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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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 = ðsw_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