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