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