uboot/cmd/ethsw.c
<<
>>
Prefs
   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
  15static 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
  20static 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
  31static 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
  43static 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
  54static 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
  65static 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
  76static 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
  88static 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
  99static 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
 110static 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
 121static 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
 128static 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
 582struct 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
 608static 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);
 611static 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);
 614static 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);
 617static 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);
 620static 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);
 623static 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 */
 631struct 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 */
 721int 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 */
 750static 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 */
 763static 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 */
 786static 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 */
 829static 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 */
 851static 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 */
 880static 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 */
 902static 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 */
 956static 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 */
1002static 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
1050static 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 " */
1067static 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
1088U_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