xref: /openbmc/u-boot/cmd/ethsw.c (revision 407b5b956a2e0facf6668fc8b295f4be9205c83e)
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 <environment.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(cmd_opt_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  );
1102