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