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