]> Git Repo - J-u-boot.git/blame - common/cmd_ethsw.c
drivers/net/vsc9953: Add command for shared/private VLAN learning
[J-u-boot.git] / common / cmd_ethsw.c
CommitLineData
4ea54e3f
CC
1/*
2 * Copyright 2015 Freescale Semiconductor, Inc.
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 *
6 * Ethernet Switch commands
7 */
8
9#include <common.h>
10#include <command.h>
11#include <errno.h>
22449858 12#include <env_flags.h>
4ea54e3f
CC
13#include <ethsw.h>
14
15static const char *ethsw_name;
16
86719f0c
CC
17#define ETHSW_PORT_STATS_HELP "ethsw [port <port_no>] statistics " \
18"{ [help] | [clear] } - show an l2 switch port's statistics"
19
20static int ethsw_port_stats_help_key_func(struct ethsw_command_def *parsed_cmd)
21{
22 printf(ETHSW_PORT_STATS_HELP"\n");
23
24 return CMD_RET_SUCCESS;
25}
26
68c929da
CC
27#define ETHSW_LEARN_HELP "ethsw [port <port_no>] learning " \
28"{ [help] | show | auto | disable } " \
29"- enable/disable/show learning configuration on a port"
30
31static int ethsw_learn_help_key_func(struct ethsw_command_def *parsed_cmd)
32{
33 printf(ETHSW_LEARN_HELP"\n");
34
35 return CMD_RET_SUCCESS;
36}
37
22449858
CC
38#define ETHSW_FDB_HELP "ethsw [port <port_no>] [vlan <vid>] fdb " \
39"{ [help] | show | flush | { add | del } <mac> } " \
40"- Add/delete a mac entry in FDB; use show to see FDB entries; " \
41"if vlan <vid> is missing, VID 1 will be used"
42
43static int ethsw_fdb_help_key_func(struct ethsw_command_def *parsed_cmd)
44{
45 printf(ETHSW_FDB_HELP"\n");
46
47 return CMD_RET_SUCCESS;
48}
49
a2477924
CC
50#define ETHSW_PVID_HELP "ethsw [port <port_no>] " \
51"pvid { [help] | show | <pvid> } " \
52"- set/show PVID (ingress and egress VLAN tagging) for a port"
53
54static int ethsw_pvid_help_key_func(struct ethsw_command_def *parsed_cmd)
55{
56 printf(ETHSW_PVID_HELP"\n");
57
58 return CMD_RET_SUCCESS;
59}
60
61#define ETHSW_VLAN_HELP "ethsw [port <port_no>] vlan " \
62"{ [help] | show | add <vid> | del <vid> } " \
63"- add a VLAN to a port (VLAN members)"
64
65static int ethsw_vlan_help_key_func(struct ethsw_command_def *parsed_cmd)
66{
67 printf(ETHSW_VLAN_HELP"\n");
68
69 return CMD_RET_SUCCESS;
70}
71
72#define ETHSW_PORT_UNTAG_HELP "ethsw [port <port_no>] untagged " \
73"{ [help] | show | all | none | pvid } " \
74" - set egress tagging mod for a port"
75
76static int ethsw_port_untag_help_key_func(struct ethsw_command_def *parsed_cmd)
77{
78 printf(ETHSW_PORT_UNTAG_HELP"\n");
79
80 return CMD_RET_SUCCESS;
81}
82
83#define ETHSW_EGR_VLAN_TAG_HELP "ethsw [port <port_no>] egress tag " \
84"{ [help] | show | pvid | classified } " \
85"- Configure VID source for egress tag. " \
86"Tag's VID could be the frame's classified VID or the PVID of the port"
87
88static int ethsw_egr_tag_help_key_func(struct ethsw_command_def *parsed_cmd)
89{
90 printf(ETHSW_EGR_VLAN_TAG_HELP"\n");
91
92 return CMD_RET_SUCCESS;
93}
94
21d214fc
CC
95#define ETHSW_VLAN_FDB_HELP "ethsw vlan fdb " \
96"{ [help] | show | shared | private } " \
97"- make VLAN learning shared or private"
98
99static int ethsw_vlan_learn_help_key_func(struct ethsw_command_def *parsed_cmd)
100{
101 printf(ETHSW_VLAN_FDB_HELP"\n");
102
103 return CMD_RET_SUCCESS;
104}
105
4ea54e3f
CC
106static struct keywords_to_function {
107 enum ethsw_keyword_id cmd_keyword[ETHSW_MAX_CMD_PARAMS];
108 int cmd_func_offset;
109 int (*keyword_function)(struct ethsw_command_def *parsed_cmd);
110} ethsw_cmd_def[] = {
111 {
112 .cmd_keyword = {
113 ethsw_id_enable,
114 ethsw_id_key_end,
115 },
116 .cmd_func_offset = offsetof(struct ethsw_command_func,
117 port_enable),
118 .keyword_function = NULL,
119 }, {
120 .cmd_keyword = {
121 ethsw_id_disable,
122 ethsw_id_key_end,
123 },
124 .cmd_func_offset = offsetof(struct ethsw_command_func,
125 port_disable),
126 .keyword_function = NULL,
127 }, {
128 .cmd_keyword = {
129 ethsw_id_show,
130 ethsw_id_key_end,
131 },
132 .cmd_func_offset = offsetof(struct ethsw_command_func,
133 port_show),
134 .keyword_function = NULL,
86719f0c
CC
135 }, {
136 .cmd_keyword = {
137 ethsw_id_statistics,
138 ethsw_id_help,
139 ethsw_id_key_end,
140 },
141 .cmd_func_offset = -1,
142 .keyword_function = &ethsw_port_stats_help_key_func,
143 }, {
144 .cmd_keyword = {
145 ethsw_id_statistics,
146 ethsw_id_key_end,
147 },
148 .cmd_func_offset = offsetof(struct ethsw_command_func,
149 port_stats),
150 .keyword_function = NULL,
151 }, {
152 .cmd_keyword = {
153 ethsw_id_statistics,
154 ethsw_id_clear,
155 ethsw_id_key_end,
156 },
157 .cmd_func_offset = offsetof(struct ethsw_command_func,
158 port_stats_clear),
159 .keyword_function = NULL,
68c929da
CC
160 }, {
161 .cmd_keyword = {
162 ethsw_id_learning,
163 ethsw_id_key_end,
164 },
165 .cmd_func_offset = -1,
166 .keyword_function = &ethsw_learn_help_key_func,
167 }, {
168 .cmd_keyword = {
169 ethsw_id_learning,
170 ethsw_id_help,
171 ethsw_id_key_end,
172 },
173 .cmd_func_offset = -1,
174 .keyword_function = &ethsw_learn_help_key_func,
175 }, {
176 .cmd_keyword = {
177 ethsw_id_learning,
178 ethsw_id_show,
179 ethsw_id_key_end,
180 },
181 .cmd_func_offset = offsetof(struct ethsw_command_func,
182 port_learn_show),
183 .keyword_function = NULL,
184 }, {
185 .cmd_keyword = {
186 ethsw_id_learning,
187 ethsw_id_auto,
188 ethsw_id_key_end,
189 },
190 .cmd_func_offset = offsetof(struct ethsw_command_func,
191 port_learn),
192 .keyword_function = NULL,
193 }, {
194 .cmd_keyword = {
195 ethsw_id_learning,
196 ethsw_id_disable,
197 ethsw_id_key_end,
198 },
199 .cmd_func_offset = offsetof(struct ethsw_command_func,
200 port_learn),
201 .keyword_function = NULL,
22449858
CC
202 }, {
203 .cmd_keyword = {
204 ethsw_id_fdb,
205 ethsw_id_key_end,
206 },
207 .cmd_func_offset = -1,
208 .keyword_function = &ethsw_fdb_help_key_func,
209 }, {
210 .cmd_keyword = {
211 ethsw_id_fdb,
212 ethsw_id_help,
213 ethsw_id_key_end,
214 },
215 .cmd_func_offset = -1,
216 .keyword_function = &ethsw_fdb_help_key_func,
217 }, {
218 .cmd_keyword = {
219 ethsw_id_fdb,
220 ethsw_id_show,
221 ethsw_id_key_end,
222 },
223 .cmd_func_offset = offsetof(struct ethsw_command_func,
224 fdb_show),
225 .keyword_function = NULL,
226 }, {
227 .cmd_keyword = {
228 ethsw_id_fdb,
229 ethsw_id_flush,
230 ethsw_id_key_end,
231 },
232 .cmd_func_offset = offsetof(struct ethsw_command_func,
233 fdb_flush),
234 .keyword_function = NULL,
235 }, {
236 .cmd_keyword = {
237 ethsw_id_fdb,
238 ethsw_id_add,
239 ethsw_id_add_del_mac,
240 ethsw_id_key_end,
241 },
242 .cmd_func_offset = offsetof(struct ethsw_command_func,
243 fdb_entry_add),
244 .keyword_function = NULL,
245 }, {
246 .cmd_keyword = {
247 ethsw_id_fdb,
248 ethsw_id_del,
249 ethsw_id_add_del_mac,
250 ethsw_id_key_end,
251 },
252 .cmd_func_offset = offsetof(struct ethsw_command_func,
253 fdb_entry_del),
254 .keyword_function = NULL,
a2477924
CC
255 }, {
256 .cmd_keyword = {
257 ethsw_id_pvid,
258 ethsw_id_key_end,
259 },
260 .cmd_func_offset = -1,
261 .keyword_function = &ethsw_pvid_help_key_func,
262 }, {
263 .cmd_keyword = {
264 ethsw_id_pvid,
265 ethsw_id_help,
266 ethsw_id_key_end,
267 },
268 .cmd_func_offset = -1,
269 .keyword_function = &ethsw_pvid_help_key_func,
270 }, {
271 .cmd_keyword = {
272 ethsw_id_pvid,
273 ethsw_id_show,
274 ethsw_id_key_end,
275 },
276 .cmd_func_offset = offsetof(struct ethsw_command_func,
277 pvid_show),
278 .keyword_function = NULL,
279 }, {
280 .cmd_keyword = {
281 ethsw_id_pvid,
282 ethsw_id_pvid_no,
283 ethsw_id_key_end,
284 },
285 .cmd_func_offset = offsetof(struct ethsw_command_func,
286 pvid_set),
287 .keyword_function = NULL,
288 }, {
289 .cmd_keyword = {
290 ethsw_id_vlan,
291 ethsw_id_key_end,
292 },
293 .cmd_func_offset = -1,
294 .keyword_function = &ethsw_vlan_help_key_func,
295 }, {
296 .cmd_keyword = {
297 ethsw_id_vlan,
298 ethsw_id_help,
299 ethsw_id_key_end,
300 },
301 .cmd_func_offset = -1,
302 .keyword_function = &ethsw_vlan_help_key_func,
303 }, {
304 .cmd_keyword = {
305 ethsw_id_vlan,
306 ethsw_id_show,
307 ethsw_id_key_end,
308 },
309 .cmd_func_offset = offsetof(struct ethsw_command_func,
310 vlan_show),
311 .keyword_function = NULL,
312 }, {
313 .cmd_keyword = {
314 ethsw_id_vlan,
315 ethsw_id_add,
316 ethsw_id_add_del_no,
317 ethsw_id_key_end,
318 },
319 .cmd_func_offset = offsetof(struct ethsw_command_func,
320 vlan_set),
321 .keyword_function = NULL,
322 }, {
323 .cmd_keyword = {
324 ethsw_id_vlan,
325 ethsw_id_del,
326 ethsw_id_add_del_no,
327 ethsw_id_key_end,
328 },
329 .cmd_func_offset = offsetof(struct ethsw_command_func,
330 vlan_set),
331 .keyword_function = NULL,
332 }, {
333 .cmd_keyword = {
334 ethsw_id_untagged,
335 ethsw_id_key_end,
336 },
337 .cmd_func_offset = -1,
338 .keyword_function = &ethsw_port_untag_help_key_func,
339 }, {
340 .cmd_keyword = {
341 ethsw_id_untagged,
342 ethsw_id_help,
343 ethsw_id_key_end,
344 },
345 .cmd_func_offset = -1,
346 .keyword_function = &ethsw_port_untag_help_key_func,
347 }, {
348 .cmd_keyword = {
349 ethsw_id_untagged,
350 ethsw_id_show,
351 ethsw_id_key_end,
352 },
353 .cmd_func_offset = offsetof(struct ethsw_command_func,
354 port_untag_show),
355 .keyword_function = NULL,
356 }, {
357 .cmd_keyword = {
358 ethsw_id_untagged,
359 ethsw_id_all,
360 ethsw_id_key_end,
361 },
362 .cmd_func_offset = offsetof(struct ethsw_command_func,
363 port_untag_set),
364 .keyword_function = NULL,
365 }, {
366 .cmd_keyword = {
367 ethsw_id_untagged,
368 ethsw_id_none,
369 ethsw_id_key_end,
370 },
371 .cmd_func_offset = offsetof(struct ethsw_command_func,
372 port_untag_set),
373 .keyword_function = NULL,
374 }, {
375 .cmd_keyword = {
376 ethsw_id_untagged,
377 ethsw_id_pvid,
378 ethsw_id_key_end,
379 },
380 .cmd_func_offset = offsetof(struct ethsw_command_func,
381 port_untag_set),
382 .keyword_function = NULL,
383 }, {
384 .cmd_keyword = {
385 ethsw_id_egress,
386 ethsw_id_tag,
387 ethsw_id_key_end,
388 },
389 .cmd_func_offset = -1,
390 .keyword_function = &ethsw_egr_tag_help_key_func,
391 }, {
392 .cmd_keyword = {
393 ethsw_id_egress,
394 ethsw_id_tag,
395 ethsw_id_help,
396 ethsw_id_key_end,
397 },
398 .cmd_func_offset = -1,
399 .keyword_function = &ethsw_egr_tag_help_key_func,
400 }, {
401 .cmd_keyword = {
402 ethsw_id_egress,
403 ethsw_id_tag,
404 ethsw_id_show,
405 ethsw_id_key_end,
406 },
407 .cmd_func_offset = offsetof(struct ethsw_command_func,
408 port_egr_vlan_show),
409 .keyword_function = NULL,
410 }, {
411 .cmd_keyword = {
412 ethsw_id_egress,
413 ethsw_id_tag,
414 ethsw_id_pvid,
415 ethsw_id_key_end,
416 },
417 .cmd_func_offset = offsetof(struct ethsw_command_func,
418 port_egr_vlan_set),
419 .keyword_function = NULL,
420 }, {
421 .cmd_keyword = {
422 ethsw_id_egress,
423 ethsw_id_tag,
424 ethsw_id_classified,
425 ethsw_id_key_end,
426 },
427 .cmd_func_offset = offsetof(struct ethsw_command_func,
428 port_egr_vlan_set),
429 .keyword_function = NULL,
21d214fc
CC
430 }, {
431 .cmd_keyword = {
432 ethsw_id_vlan,
433 ethsw_id_fdb,
434 ethsw_id_key_end,
435 },
436 .cmd_func_offset = -1,
437 .keyword_function = &ethsw_vlan_learn_help_key_func,
438 }, {
439 .cmd_keyword = {
440 ethsw_id_vlan,
441 ethsw_id_fdb,
442 ethsw_id_help,
443 ethsw_id_key_end,
444 },
445 .cmd_func_offset = -1,
446 .keyword_function = &ethsw_vlan_learn_help_key_func,
447 }, {
448 .cmd_keyword = {
449 ethsw_id_vlan,
450 ethsw_id_fdb,
451 ethsw_id_show,
452 ethsw_id_key_end,
453 },
454 .cmd_func_offset = offsetof(struct ethsw_command_func,
455 vlan_learn_show),
456 .keyword_function = NULL,
457 }, {
458 .cmd_keyword = {
459 ethsw_id_vlan,
460 ethsw_id_fdb,
461 ethsw_id_shared,
462 ethsw_id_key_end,
463 },
464 .cmd_func_offset = offsetof(struct ethsw_command_func,
465 vlan_learn_set),
466 .keyword_function = NULL,
467 }, {
468 .cmd_keyword = {
469 ethsw_id_vlan,
470 ethsw_id_fdb,
471 ethsw_id_private,
472 ethsw_id_key_end,
473 },
474 .cmd_func_offset = offsetof(struct ethsw_command_func,
475 vlan_learn_set),
476 .keyword_function = NULL,
4ea54e3f
CC
477 },
478};
479
480struct keywords_optional {
481 int cmd_keyword[ETHSW_MAX_CMD_PARAMS];
482} cmd_opt_def[] = {
483 {
484 .cmd_keyword = {
485 ethsw_id_port,
486 ethsw_id_port_no,
487 ethsw_id_key_end,
488 },
22449858
CC
489 }, {
490 .cmd_keyword = {
491 ethsw_id_vlan,
492 ethsw_id_vlan_no,
493 ethsw_id_key_end,
494 },
495 }, {
496 .cmd_keyword = {
497 ethsw_id_port,
498 ethsw_id_port_no,
499 ethsw_id_vlan,
500 ethsw_id_vlan_no,
501 ethsw_id_key_end,
502 },
4ea54e3f
CC
503 },
504};
505
506static int keyword_match_gen(enum ethsw_keyword_id key_id, int argc, char
507 *const argv[], int *argc_nr,
508 struct ethsw_command_def *parsed_cmd);
509static int keyword_match_port(enum ethsw_keyword_id key_id, int argc,
510 char *const argv[], int *argc_nr,
511 struct ethsw_command_def *parsed_cmd);
22449858
CC
512static int keyword_match_vlan(enum ethsw_keyword_id key_id, int argc,
513 char *const argv[], int *argc_nr,
514 struct ethsw_command_def *parsed_cmd);
a2477924
CC
515static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc,
516 char *const argv[], int *argc_nr,
517 struct ethsw_command_def *parsed_cmd);
22449858
CC
518static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
519 char *const argv[], int *argc_nr,
520 struct ethsw_command_def *parsed_cmd);
4ea54e3f
CC
521
522/*
523 * Define properties for each keyword;
524 * keep the order synced with enum ethsw_keyword_id
525 */
526struct keyword_def {
527 const char *keyword_name;
528 int (*match)(enum ethsw_keyword_id key_id, int argc, char *const argv[],
529 int *argc_nr, struct ethsw_command_def *parsed_cmd);
530} keyword[] = {
531 {
532 .keyword_name = "help",
533 .match = &keyword_match_gen,
534 }, {
535 .keyword_name = "show",
536 .match = &keyword_match_gen,
537 }, {
538 .keyword_name = "port",
539 .match = &keyword_match_port
540 }, {
541 .keyword_name = "enable",
542 .match = &keyword_match_gen,
543 }, {
544 .keyword_name = "disable",
545 .match = &keyword_match_gen,
86719f0c
CC
546 }, {
547 .keyword_name = "statistics",
548 .match = &keyword_match_gen,
549 }, {
550 .keyword_name = "clear",
551 .match = &keyword_match_gen,
68c929da
CC
552 }, {
553 .keyword_name = "learning",
554 .match = &keyword_match_gen,
555 }, {
556 .keyword_name = "auto",
557 .match = &keyword_match_gen,
22449858
CC
558 }, {
559 .keyword_name = "vlan",
560 .match = &keyword_match_vlan,
561 }, {
562 .keyword_name = "fdb",
563 .match = &keyword_match_gen,
564 }, {
565 .keyword_name = "add",
566 .match = &keyword_match_mac_addr,
567 }, {
568 .keyword_name = "del",
569 .match = &keyword_match_mac_addr,
570 }, {
571 .keyword_name = "flush",
572 .match = &keyword_match_gen,
a2477924
CC
573 }, {
574 .keyword_name = "pvid",
575 .match = &keyword_match_pvid,
576 }, {
577 .keyword_name = "untagged",
578 .match = &keyword_match_gen,
579 }, {
580 .keyword_name = "all",
581 .match = &keyword_match_gen,
582 }, {
583 .keyword_name = "none",
584 .match = &keyword_match_gen,
585 }, {
586 .keyword_name = "egress",
587 .match = &keyword_match_gen,
588 }, {
589 .keyword_name = "tag",
590 .match = &keyword_match_gen,
591 }, {
592 .keyword_name = "classified",
593 .match = &keyword_match_gen,
21d214fc
CC
594 }, {
595 .keyword_name = "shared",
596 .match = &keyword_match_gen,
597 }, {
598 .keyword_name = "private",
599 .match = &keyword_match_gen,
4ea54e3f
CC
600 },
601};
602
603/*
604 * Function used by an Ethernet Switch driver to set the functions
605 * that must be called by the parser when an ethsw command is given
606 */
607int ethsw_define_functions(const struct ethsw_command_func *cmd_func)
608{
609 int i;
610 void **aux_p;
611 int (*cmd_func_aux)(struct ethsw_command_def *);
612
613 if (!cmd_func->ethsw_name)
614 return -EINVAL;
615
616 ethsw_name = cmd_func->ethsw_name;
617
618 for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) {
619 /*
620 * get the pointer to the function send by the Ethernet Switch
621 * driver that corresponds to the proper ethsw command
622 */
623 if (ethsw_cmd_def[i].keyword_function)
624 continue;
625
626 aux_p = (void *)cmd_func + ethsw_cmd_def[i].cmd_func_offset;
627
628 cmd_func_aux = (int (*)(struct ethsw_command_def *)) *aux_p;
629 ethsw_cmd_def[i].keyword_function = cmd_func_aux;
630 }
631
632 return 0;
633}
634
635/* Generic function used to match a keyword only by a string */
636static int keyword_match_gen(enum ethsw_keyword_id key_id, int argc,
637 char *const argv[], int *argc_nr,
638 struct ethsw_command_def *parsed_cmd)
639{
640 if (strcmp(argv[*argc_nr], keyword[key_id].keyword_name) == 0) {
641 parsed_cmd->cmd_to_keywords[*argc_nr] = key_id;
642
643 return 1;
644 }
645 return 0;
646}
647
648/* Function used to match the command's port */
649static int keyword_match_port(enum ethsw_keyword_id key_id, int argc,
650 char *const argv[], int *argc_nr,
651 struct ethsw_command_def *parsed_cmd)
652{
653 unsigned long val;
654
655 if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
656 return 0;
657
658 if (*argc_nr + 1 >= argc)
659 return 0;
660
661 if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
662 parsed_cmd->port = val;
663 (*argc_nr)++;
664 parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_port_no;
665 return 1;
666 }
667
668 return 0;
669}
670
22449858
CC
671/* Function used to match the command's vlan */
672static int keyword_match_vlan(enum ethsw_keyword_id key_id, int argc,
673 char *const argv[], int *argc_nr,
674 struct ethsw_command_def *parsed_cmd)
675{
676 unsigned long val;
677 int aux;
678
679 if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
680 return 0;
681
682 if (*argc_nr + 1 >= argc)
683 return 0;
684
685 if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
686 parsed_cmd->vid = val;
687 (*argc_nr)++;
688 parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_vlan_no;
689 return 1;
690 }
691
692 aux = *argc_nr + 1;
693
694 if (keyword_match_gen(ethsw_id_add, argc, argv, &aux, parsed_cmd))
695 parsed_cmd->cmd_to_keywords[*argc_nr + 1] = ethsw_id_add;
696 else if (keyword_match_gen(ethsw_id_del, argc, argv, &aux, parsed_cmd))
697 parsed_cmd->cmd_to_keywords[*argc_nr + 1] = ethsw_id_del;
698 else
699 return 0;
700
701 if (*argc_nr + 2 >= argc)
702 return 0;
703
704 if (strict_strtoul(argv[*argc_nr + 2], 10, &val) != -EINVAL) {
705 parsed_cmd->vid = val;
706 (*argc_nr) += 2;
707 parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_add_del_no;
708 return 1;
709 }
710
711 return 0;
712}
713
a2477924
CC
714/* Function used to match the command's pvid */
715static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc,
716 char *const argv[], int *argc_nr,
717 struct ethsw_command_def *parsed_cmd)
718{
719 unsigned long val;
720
721 if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
722 return 0;
723
724 if (*argc_nr + 1 >= argc)
725 return 1;
726
727 if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
728 parsed_cmd->vid = val;
729 (*argc_nr)++;
730 parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_pvid_no;
731 }
732
733 return 1;
734}
735
22449858
CC
736/* Function used to match the command's MAC address */
737static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
738 char *const argv[], int *argc_nr,
739 struct ethsw_command_def *parsed_cmd)
740{
741 if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
742 return 0;
743
744 if ((*argc_nr + 1 >= argc) ||
745 !is_broadcast_ethaddr(parsed_cmd->ethaddr))
746 return 1;
747
748 if (eth_validate_ethaddr_str(argv[*argc_nr + 1])) {
749 printf("Invalid MAC address: %s\n", argv[*argc_nr + 1]);
750 return 0;
751 }
752
753 eth_parse_enetaddr(argv[*argc_nr + 1], parsed_cmd->ethaddr);
754
755 if (is_broadcast_ethaddr(parsed_cmd->ethaddr)) {
756 memset(parsed_cmd->ethaddr, 0xFF, sizeof(parsed_cmd->ethaddr));
757 return 0;
758 }
759
760 parsed_cmd->cmd_to_keywords[*argc_nr + 1] = ethsw_id_add_del_mac;
761
762 return 1;
763}
764
4ea54e3f
CC
765/* Finds optional keywords and modifies *argc_va to skip them */
766static void cmd_keywords_opt_check(const struct ethsw_command_def *parsed_cmd,
767 int *argc_val)
768{
769 int i;
770 int keyw_opt_matched;
771 int argc_val_max;
772 int const *cmd_keyw_p;
773 int const *cmd_keyw_opt_p;
774
775 /* remember the best match */
776 argc_val_max = *argc_val;
777
778 /*
779 * check if our command's optional keywords match the optional
780 * keywords of an available command
781 */
782 for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) {
783 keyw_opt_matched = 0;
784 cmd_keyw_p = &parsed_cmd->cmd_to_keywords[keyw_opt_matched];
785 cmd_keyw_opt_p = &cmd_opt_def[i].cmd_keyword[keyw_opt_matched];
786
787 /*
788 * increase the number of keywords that
789 * matched with a command
790 */
791 while (keyw_opt_matched + *argc_val <
792 parsed_cmd->cmd_keywords_nr &&
793 *cmd_keyw_opt_p != ethsw_id_key_end &&
794 *(cmd_keyw_p + *argc_val) == *cmd_keyw_opt_p) {
795 keyw_opt_matched++;
796 cmd_keyw_p++;
797 cmd_keyw_opt_p++;
798 }
799
800 /*
801 * if all our optional command's keywords perfectly match an
802 * optional pattern, then we can move to the next defined
803 * keywords in our command; remember the one that matched the
804 * greatest number of keywords
805 */
806 if (keyw_opt_matched + *argc_val <=
807 parsed_cmd->cmd_keywords_nr &&
808 *cmd_keyw_opt_p == ethsw_id_key_end &&
809 *argc_val + keyw_opt_matched > argc_val_max)
810 argc_val_max = *argc_val + keyw_opt_matched;
811 }
812
813 *argc_val = argc_val_max;
814}
815
816/*
817 * Finds the function to call based on keywords and
818 * modifies *argc_va to skip them
819 */
820static void cmd_keywords_check(struct ethsw_command_def *parsed_cmd,
821 int *argc_val)
822{
823 int i;
824 int keyw_matched;
825 int *cmd_keyw_p;
826 int *cmd_keyw_def_p;
827
828 /*
829 * check if our command's keywords match the
830 * keywords of an available command
831 */
832 for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) {
833 keyw_matched = 0;
834 cmd_keyw_p = &parsed_cmd->cmd_to_keywords[keyw_matched];
835 cmd_keyw_def_p = &ethsw_cmd_def[i].cmd_keyword[keyw_matched];
836
837 /*
838 * increase the number of keywords that
839 * matched with a command
840 */
841 while (keyw_matched + *argc_val < parsed_cmd->cmd_keywords_nr &&
842 *cmd_keyw_def_p != ethsw_id_key_end &&
843 *(cmd_keyw_p + *argc_val) == *cmd_keyw_def_p) {
844 keyw_matched++;
845 cmd_keyw_p++;
846 cmd_keyw_def_p++;
847 }
848
849 /*
850 * if all our command's keywords perfectly match an
851 * available command, then we get the function we need to call
852 * to configure the Ethernet Switch
853 */
854 if (keyw_matched && keyw_matched + *argc_val ==
855 parsed_cmd->cmd_keywords_nr &&
856 *cmd_keyw_def_p == ethsw_id_key_end) {
857 *argc_val += keyw_matched;
858 parsed_cmd->cmd_function =
859 ethsw_cmd_def[i].keyword_function;
860 return;
861 }
862 }
863}
864
865/* find all the keywords in the command */
866static int keywords_find(int argc, char * const argv[],
867 struct ethsw_command_def *parsed_cmd)
868{
869 int i;
870 int j;
871 int argc_val;
872 int rc = CMD_RET_SUCCESS;
873
874 for (i = 1; i < argc; i++) {
875 for (j = 0; j < ethsw_id_count; j++) {
876 if (keyword[j].match(j, argc, argv, &i, parsed_cmd))
877 break;
878 }
879 }
880
881 /* if there is no keyword match for a word, the command is invalid */
882 for (i = 1; i < argc; i++)
883 if (parsed_cmd->cmd_to_keywords[i] == ethsw_id_key_end)
884 rc = CMD_RET_USAGE;
885
886 parsed_cmd->cmd_keywords_nr = argc;
887 argc_val = 1;
888
889 /* get optional parameters first */
890 cmd_keywords_opt_check(parsed_cmd, &argc_val);
891
892 if (argc_val == parsed_cmd->cmd_keywords_nr)
893 return CMD_RET_USAGE;
894
895 /*
896 * check the keywords and if a match is found,
897 * get the function to call
898 */
899 cmd_keywords_check(parsed_cmd, &argc_val);
900
901 /* error if not all commands' parameters were matched */
902 if (argc_val == parsed_cmd->cmd_keywords_nr) {
903 if (!parsed_cmd->cmd_function) {
904 printf("Command not available for: %s\n", ethsw_name);
905 rc = CMD_RET_FAILURE;
906 }
907 } else {
908 rc = CMD_RET_USAGE;
909 }
910
911 return rc;
912}
913
914static void command_def_init(struct ethsw_command_def *parsed_cmd)
915{
916 int i;
917
918 for (i = 0; i < ETHSW_MAX_CMD_PARAMS; i++)
919 parsed_cmd->cmd_to_keywords[i] = ethsw_id_key_end;
920
921 parsed_cmd->port = ETHSW_CMD_PORT_ALL;
22449858 922 parsed_cmd->vid = ETHSW_CMD_VLAN_ALL;
4ea54e3f 923 parsed_cmd->cmd_function = NULL;
22449858
CC
924
925 /* We initialize the MAC address with the Broadcast address */
926 memset(parsed_cmd->ethaddr, 0xff, sizeof(parsed_cmd->ethaddr));
4ea54e3f
CC
927}
928
929/* function to interpret commands starting with "ethsw " */
930static int do_ethsw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
931{
932 struct ethsw_command_def parsed_cmd;
933 int rc = CMD_RET_SUCCESS;
934
935 if (argc == 1 || argc >= ETHSW_MAX_CMD_PARAMS)
936 return CMD_RET_USAGE;
937
938 command_def_init(&parsed_cmd);
939
940 rc = keywords_find(argc, argv, &parsed_cmd);
941
942 if (rc == CMD_RET_SUCCESS)
943 rc = parsed_cmd.cmd_function(&parsed_cmd);
944
945 return rc;
946}
947
948#define ETHSW_PORT_CONF_HELP "[port <port_no>] { enable | disable | show } " \
949"- enable/disable a port; show shows a port's configuration"
950
951U_BOOT_CMD(ethsw, ETHSW_MAX_CMD_PARAMS, 0, do_ethsw,
952 "Ethernet l2 switch commands",
953 ETHSW_PORT_CONF_HELP"\n"
86719f0c 954 ETHSW_PORT_STATS_HELP"\n"
68c929da 955 ETHSW_LEARN_HELP"\n"
22449858 956 ETHSW_FDB_HELP"\n"
a2477924
CC
957 ETHSW_PVID_HELP"\n"
958 ETHSW_VLAN_HELP"\n"
959 ETHSW_PORT_UNTAG_HELP"\n"
960 ETHSW_EGR_VLAN_TAG_HELP"\n"
21d214fc 961 ETHSW_VLAN_FDB_HELP"\n"
4ea54e3f 962);
This page took 0.128645 seconds and 4 git commands to generate.