/* * Copyright 2015 Freescale Semiconductor, Inc. * * SPDX-License-Identifier: GPL-2.0+ * * Ethernet Switch commands */ #include #include #include #include #include static const char *ethsw_name; #define ETHSW_PORT_STATS_HELP "ethsw [port ] statistics " \ "{ [help] | [clear] } - show an l2 switch port's statistics" static int ethsw_port_stats_help_key_func(struct ethsw_command_def *parsed_cmd) { printf(ETHSW_PORT_STATS_HELP"\n"); return CMD_RET_SUCCESS; } #define ETHSW_LEARN_HELP "ethsw [port ] learning " \ "{ [help] | show | auto | disable } " \ "- enable/disable/show learning configuration on a port" static int ethsw_learn_help_key_func(struct ethsw_command_def *parsed_cmd) { printf(ETHSW_LEARN_HELP"\n"); return CMD_RET_SUCCESS; } #define ETHSW_FDB_HELP "ethsw [port ] [vlan ] fdb " \ "{ [help] | show | flush | { add | del } } " \ "- Add/delete a mac entry in FDB; use show to see FDB entries; " \ "if vlan is missing, VID 1 will be used" static int ethsw_fdb_help_key_func(struct ethsw_command_def *parsed_cmd) { printf(ETHSW_FDB_HELP"\n"); return CMD_RET_SUCCESS; } #define ETHSW_PVID_HELP "ethsw [port ] " \ "pvid { [help] | show | } " \ "- set/show PVID (ingress and egress VLAN tagging) for a port" static int ethsw_pvid_help_key_func(struct ethsw_command_def *parsed_cmd) { printf(ETHSW_PVID_HELP"\n"); return CMD_RET_SUCCESS; } #define ETHSW_VLAN_HELP "ethsw [port ] vlan " \ "{ [help] | show | add | del } " \ "- add a VLAN to a port (VLAN members)" static int ethsw_vlan_help_key_func(struct ethsw_command_def *parsed_cmd) { printf(ETHSW_VLAN_HELP"\n"); return CMD_RET_SUCCESS; } #define ETHSW_PORT_UNTAG_HELP "ethsw [port ] untagged " \ "{ [help] | show | all | none | pvid } " \ " - set egress tagging mode for a port" static int ethsw_port_untag_help_key_func(struct ethsw_command_def *parsed_cmd) { printf(ETHSW_PORT_UNTAG_HELP"\n"); return CMD_RET_SUCCESS; } #define ETHSW_EGR_VLAN_TAG_HELP "ethsw [port ] egress tag " \ "{ [help] | show | pvid | classified } " \ "- Configure VID source for egress tag. " \ "Tag's VID could be the frame's classified VID or the PVID of the port" static int ethsw_egr_tag_help_key_func(struct ethsw_command_def *parsed_cmd) { printf(ETHSW_EGR_VLAN_TAG_HELP"\n"); return CMD_RET_SUCCESS; } #define ETHSW_VLAN_FDB_HELP "ethsw vlan fdb " \ "{ [help] | show | shared | private } " \ "- make VLAN learning shared or private" static int ethsw_vlan_learn_help_key_func(struct ethsw_command_def *parsed_cmd) { printf(ETHSW_VLAN_FDB_HELP"\n"); return CMD_RET_SUCCESS; } #define ETHSW_PORT_INGR_FLTR_HELP "ethsw [port ] ingress filtering" \ " { [help] | show | enable | disable } " \ "- enable/disable VLAN ingress filtering on port" static int ethsw_ingr_fltr_help_key_func(struct ethsw_command_def *parsed_cmd) { printf(ETHSW_PORT_INGR_FLTR_HELP"\n"); return CMD_RET_SUCCESS; } #define ETHSW_PORT_AGGR_HELP "ethsw [port ] aggr" \ " { [help] | show | } " \ "- get/set LAG group for a port" static int ethsw_port_aggr_help_key_func(struct ethsw_command_def *parsed_cmd) { printf(ETHSW_PORT_AGGR_HELP"\n"); return CMD_RET_SUCCESS; } static struct keywords_to_function { enum ethsw_keyword_id cmd_keyword[ETHSW_MAX_CMD_PARAMS]; int cmd_func_offset; int (*keyword_function)(struct ethsw_command_def *parsed_cmd); } ethsw_cmd_def[] = { { .cmd_keyword = { ethsw_id_enable, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_enable), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_disable, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_disable), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_show, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_show), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_statistics, ethsw_id_help, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_port_stats_help_key_func, }, { .cmd_keyword = { ethsw_id_statistics, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_stats), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_statistics, ethsw_id_clear, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_stats_clear), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_learning, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_learn_help_key_func, }, { .cmd_keyword = { ethsw_id_learning, ethsw_id_help, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_learn_help_key_func, }, { .cmd_keyword = { ethsw_id_learning, ethsw_id_show, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_learn_show), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_learning, ethsw_id_auto, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_learn), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_learning, ethsw_id_disable, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_learn), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_fdb, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_fdb_help_key_func, }, { .cmd_keyword = { ethsw_id_fdb, ethsw_id_help, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_fdb_help_key_func, }, { .cmd_keyword = { ethsw_id_fdb, ethsw_id_show, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, fdb_show), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_fdb, ethsw_id_flush, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, fdb_flush), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_fdb, ethsw_id_add, ethsw_id_add_del_mac, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, fdb_entry_add), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_fdb, ethsw_id_del, ethsw_id_add_del_mac, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, fdb_entry_del), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_pvid, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_pvid_help_key_func, }, { .cmd_keyword = { ethsw_id_pvid, ethsw_id_help, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_pvid_help_key_func, }, { .cmd_keyword = { ethsw_id_pvid, ethsw_id_show, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, pvid_show), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_pvid, ethsw_id_pvid_no, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, pvid_set), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_vlan, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_vlan_help_key_func, }, { .cmd_keyword = { ethsw_id_vlan, ethsw_id_help, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_vlan_help_key_func, }, { .cmd_keyword = { ethsw_id_vlan, ethsw_id_show, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, vlan_show), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_vlan, ethsw_id_add, ethsw_id_add_del_no, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, vlan_set), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_vlan, ethsw_id_del, ethsw_id_add_del_no, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, vlan_set), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_untagged, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_port_untag_help_key_func, }, { .cmd_keyword = { ethsw_id_untagged, ethsw_id_help, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_port_untag_help_key_func, }, { .cmd_keyword = { ethsw_id_untagged, ethsw_id_show, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_untag_show), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_untagged, ethsw_id_all, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_untag_set), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_untagged, ethsw_id_none, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_untag_set), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_untagged, ethsw_id_pvid, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_untag_set), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_egress, ethsw_id_tag, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_egr_tag_help_key_func, }, { .cmd_keyword = { ethsw_id_egress, ethsw_id_tag, ethsw_id_help, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_egr_tag_help_key_func, }, { .cmd_keyword = { ethsw_id_egress, ethsw_id_tag, ethsw_id_show, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_egr_vlan_show), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_egress, ethsw_id_tag, ethsw_id_pvid, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_egr_vlan_set), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_egress, ethsw_id_tag, ethsw_id_classified, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_egr_vlan_set), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_vlan, ethsw_id_fdb, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_vlan_learn_help_key_func, }, { .cmd_keyword = { ethsw_id_vlan, ethsw_id_fdb, ethsw_id_help, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_vlan_learn_help_key_func, }, { .cmd_keyword = { ethsw_id_vlan, ethsw_id_fdb, ethsw_id_show, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, vlan_learn_show), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_vlan, ethsw_id_fdb, ethsw_id_shared, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, vlan_learn_set), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_vlan, ethsw_id_fdb, ethsw_id_private, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, vlan_learn_set), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_ingress, ethsw_id_filtering, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_ingr_fltr_help_key_func, }, { .cmd_keyword = { ethsw_id_ingress, ethsw_id_filtering, ethsw_id_help, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_ingr_fltr_help_key_func, }, { .cmd_keyword = { ethsw_id_ingress, ethsw_id_filtering, ethsw_id_show, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_ingr_filt_show), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_ingress, ethsw_id_filtering, ethsw_id_enable, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_ingr_filt_set), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_ingress, ethsw_id_filtering, ethsw_id_disable, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_ingr_filt_set), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_aggr, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_port_aggr_help_key_func, }, { .cmd_keyword = { ethsw_id_aggr, ethsw_id_help, ethsw_id_key_end, }, .cmd_func_offset = -1, .keyword_function = ðsw_port_aggr_help_key_func, }, { .cmd_keyword = { ethsw_id_aggr, ethsw_id_show, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_aggr_show), .keyword_function = NULL, }, { .cmd_keyword = { ethsw_id_aggr, ethsw_id_aggr_no, ethsw_id_key_end, }, .cmd_func_offset = offsetof(struct ethsw_command_func, port_aggr_set), .keyword_function = NULL, }, }; struct keywords_optional { int cmd_keyword[ETHSW_MAX_CMD_PARAMS]; } cmd_opt_def[] = { { .cmd_keyword = { ethsw_id_port, ethsw_id_port_no, ethsw_id_key_end, }, }, { .cmd_keyword = { ethsw_id_vlan, ethsw_id_vlan_no, ethsw_id_key_end, }, }, { .cmd_keyword = { ethsw_id_port, ethsw_id_port_no, ethsw_id_vlan, ethsw_id_vlan_no, ethsw_id_key_end, }, }, }; static int keyword_match_gen(enum ethsw_keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct ethsw_command_def *parsed_cmd); static int keyword_match_port(enum ethsw_keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct ethsw_command_def *parsed_cmd); static int keyword_match_vlan(enum ethsw_keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct ethsw_command_def *parsed_cmd); static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct ethsw_command_def *parsed_cmd); static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct ethsw_command_def *parsed_cmd); static int keyword_match_aggr(enum ethsw_keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct ethsw_command_def *parsed_cmd); /* * Define properties for each keyword; * keep the order synced with enum ethsw_keyword_id */ struct keyword_def { const char *keyword_name; int (*match)(enum ethsw_keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct ethsw_command_def *parsed_cmd); } keyword[] = { { .keyword_name = "help", .match = &keyword_match_gen, }, { .keyword_name = "show", .match = &keyword_match_gen, }, { .keyword_name = "port", .match = &keyword_match_port }, { .keyword_name = "enable", .match = &keyword_match_gen, }, { .keyword_name = "disable", .match = &keyword_match_gen, }, { .keyword_name = "statistics", .match = &keyword_match_gen, }, { .keyword_name = "clear", .match = &keyword_match_gen, }, { .keyword_name = "learning", .match = &keyword_match_gen, }, { .keyword_name = "auto", .match = &keyword_match_gen, }, { .keyword_name = "vlan", .match = &keyword_match_vlan, }, { .keyword_name = "fdb", .match = &keyword_match_gen, }, { .keyword_name = "add", .match = &keyword_match_mac_addr, }, { .keyword_name = "del", .match = &keyword_match_mac_addr, }, { .keyword_name = "flush", .match = &keyword_match_gen, }, { .keyword_name = "pvid", .match = &keyword_match_pvid, }, { .keyword_name = "untagged", .match = &keyword_match_gen, }, { .keyword_name = "all", .match = &keyword_match_gen, }, { .keyword_name = "none", .match = &keyword_match_gen, }, { .keyword_name = "egress", .match = &keyword_match_gen, }, { .keyword_name = "tag", .match = &keyword_match_gen, }, { .keyword_name = "classified", .match = &keyword_match_gen, }, { .keyword_name = "shared", .match = &keyword_match_gen, }, { .keyword_name = "private", .match = &keyword_match_gen, }, { .keyword_name = "ingress", .match = &keyword_match_gen, }, { .keyword_name = "filtering", .match = &keyword_match_gen, }, { .keyword_name = "aggr", .match = &keyword_match_aggr, }, }; /* * Function used by an Ethernet Switch driver to set the functions * that must be called by the parser when an ethsw command is given */ int ethsw_define_functions(const struct ethsw_command_func *cmd_func) { int i; void **aux_p; int (*cmd_func_aux)(struct ethsw_command_def *); if (!cmd_func->ethsw_name) return -EINVAL; ethsw_name = cmd_func->ethsw_name; for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) { /* * get the pointer to the function send by the Ethernet Switch * driver that corresponds to the proper ethsw command */ if (ethsw_cmd_def[i].keyword_function) continue; aux_p = (void *)cmd_func + ethsw_cmd_def[i].cmd_func_offset; cmd_func_aux = (int (*)(struct ethsw_command_def *)) *aux_p; ethsw_cmd_def[i].keyword_function = cmd_func_aux; } return 0; } /* Generic function used to match a keyword only by a string */ static int keyword_match_gen(enum ethsw_keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct ethsw_command_def *parsed_cmd) { if (strcmp(argv[*argc_nr], keyword[key_id].keyword_name) == 0) { parsed_cmd->cmd_to_keywords[*argc_nr] = key_id; return 1; } return 0; } /* Function used to match the command's port */ static int keyword_match_port(enum ethsw_keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct ethsw_command_def *parsed_cmd) { unsigned long val; if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd)) return 0; if (*argc_nr + 1 >= argc) return 0; if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) { parsed_cmd->port = val; (*argc_nr)++; parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_port_no; return 1; } return 0; } /* Function used to match the command's vlan */ static int keyword_match_vlan(enum ethsw_keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct ethsw_command_def *parsed_cmd) { unsigned long val; int aux; if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd)) return 0; if (*argc_nr + 1 >= argc) return 0; if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) { parsed_cmd->vid = val; (*argc_nr)++; parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_vlan_no; return 1; } aux = *argc_nr + 1; if (keyword_match_gen(ethsw_id_add, argc, argv, &aux, parsed_cmd)) parsed_cmd->cmd_to_keywords[*argc_nr + 1] = ethsw_id_add; else if (keyword_match_gen(ethsw_id_del, argc, argv, &aux, parsed_cmd)) parsed_cmd->cmd_to_keywords[*argc_nr + 1] = ethsw_id_del; else return 0; if (*argc_nr + 2 >= argc) return 0; if (strict_strtoul(argv[*argc_nr + 2], 10, &val) != -EINVAL) { parsed_cmd->vid = val; (*argc_nr) += 2; parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_add_del_no; return 1; } return 0; } /* Function used to match the command's pvid */ static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct ethsw_command_def *parsed_cmd) { unsigned long val; if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd)) return 0; if (*argc_nr + 1 >= argc) return 1; if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) { parsed_cmd->vid = val; (*argc_nr)++; parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_pvid_no; } return 1; } /* Function used to match the command's MAC address */ static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct ethsw_command_def *parsed_cmd) { if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd)) return 0; if ((*argc_nr + 1 >= argc) || !is_broadcast_ethaddr(parsed_cmd->ethaddr)) return 1; if (eth_validate_ethaddr_str(argv[*argc_nr + 1])) { printf("Invalid MAC address: %s\n", argv[*argc_nr + 1]); return 0; } eth_parse_enetaddr(argv[*argc_nr + 1], parsed_cmd->ethaddr); if (is_broadcast_ethaddr(parsed_cmd->ethaddr)) { memset(parsed_cmd->ethaddr, 0xFF, sizeof(parsed_cmd->ethaddr)); return 0; } parsed_cmd->cmd_to_keywords[*argc_nr + 1] = ethsw_id_add_del_mac; return 1; } /* Function used to match the command's aggregation number */ static int keyword_match_aggr(enum ethsw_keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct ethsw_command_def *parsed_cmd) { unsigned long val; if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd)) return 0; if (*argc_nr + 1 >= argc) return 1; if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) { parsed_cmd->aggr_grp = val; (*argc_nr)++; parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_aggr_no; } return 1; } /* Finds optional keywords and modifies *argc_va to skip them */ static void cmd_keywords_opt_check(const struct ethsw_command_def *parsed_cmd, int *argc_val) { int i; int keyw_opt_matched; int argc_val_max; int const *cmd_keyw_p; int const *cmd_keyw_opt_p; /* remember the best match */ argc_val_max = *argc_val; /* * check if our command's optional keywords match the optional * keywords of an available command */ for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) { keyw_opt_matched = 0; cmd_keyw_p = &parsed_cmd->cmd_to_keywords[keyw_opt_matched]; cmd_keyw_opt_p = &cmd_opt_def[i].cmd_keyword[keyw_opt_matched]; /* * increase the number of keywords that * matched with a command */ while (keyw_opt_matched + *argc_val < parsed_cmd->cmd_keywords_nr && *cmd_keyw_opt_p != ethsw_id_key_end && *(cmd_keyw_p + *argc_val) == *cmd_keyw_opt_p) { keyw_opt_matched++; cmd_keyw_p++; cmd_keyw_opt_p++; } /* * if all our optional command's keywords perfectly match an * optional pattern, then we can move to the next defined * keywords in our command; remember the one that matched the * greatest number of keywords */ if (keyw_opt_matched + *argc_val <= parsed_cmd->cmd_keywords_nr && *cmd_keyw_opt_p == ethsw_id_key_end && *argc_val + keyw_opt_matched > argc_val_max) argc_val_max = *argc_val + keyw_opt_matched; } *argc_val = argc_val_max; } /* * Finds the function to call based on keywords and * modifies *argc_va to skip them */ static void cmd_keywords_check(struct ethsw_command_def *parsed_cmd, int *argc_val) { int i; int keyw_matched; int *cmd_keyw_p; int *cmd_keyw_def_p; /* * check if our command's keywords match the * keywords of an available command */ for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) { keyw_matched = 0; cmd_keyw_p = &parsed_cmd->cmd_to_keywords[keyw_matched]; cmd_keyw_def_p = ðsw_cmd_def[i].cmd_keyword[keyw_matched]; /* * increase the number of keywords that * matched with a command */ while (keyw_matched + *argc_val < parsed_cmd->cmd_keywords_nr && *cmd_keyw_def_p != ethsw_id_key_end && *(cmd_keyw_p + *argc_val) == *cmd_keyw_def_p) { keyw_matched++; cmd_keyw_p++; cmd_keyw_def_p++; } /* * if all our command's keywords perfectly match an * available command, then we get the function we need to call * to configure the Ethernet Switch */ if (keyw_matched && keyw_matched + *argc_val == parsed_cmd->cmd_keywords_nr && *cmd_keyw_def_p == ethsw_id_key_end) { *argc_val += keyw_matched; parsed_cmd->cmd_function = ethsw_cmd_def[i].keyword_function; return; } } } /* find all the keywords in the command */ static int keywords_find(int argc, char * const argv[], struct ethsw_command_def *parsed_cmd) { int i; int j; int argc_val; int rc = CMD_RET_SUCCESS; for (i = 1; i < argc; i++) { for (j = 0; j < ethsw_id_count; j++) { if (keyword[j].match(j, argc, argv, &i, parsed_cmd)) break; } } /* if there is no keyword match for a word, the command is invalid */ for (i = 1; i < argc; i++) if (parsed_cmd->cmd_to_keywords[i] == ethsw_id_key_end) rc = CMD_RET_USAGE; parsed_cmd->cmd_keywords_nr = argc; argc_val = 1; /* get optional parameters first */ cmd_keywords_opt_check(parsed_cmd, &argc_val); if (argc_val == parsed_cmd->cmd_keywords_nr) return CMD_RET_USAGE; /* * check the keywords and if a match is found, * get the function to call */ cmd_keywords_check(parsed_cmd, &argc_val); /* error if not all commands' parameters were matched */ if (argc_val == parsed_cmd->cmd_keywords_nr) { if (!parsed_cmd->cmd_function) { printf("Command not available for: %s\n", ethsw_name); rc = CMD_RET_FAILURE; } } else { rc = CMD_RET_USAGE; } return rc; } static void command_def_init(struct ethsw_command_def *parsed_cmd) { int i; for (i = 0; i < ETHSW_MAX_CMD_PARAMS; i++) parsed_cmd->cmd_to_keywords[i] = ethsw_id_key_end; parsed_cmd->port = ETHSW_CMD_PORT_ALL; parsed_cmd->vid = ETHSW_CMD_VLAN_ALL; parsed_cmd->aggr_grp = ETHSW_CMD_AGGR_GRP_NONE; parsed_cmd->cmd_function = NULL; /* We initialize the MAC address with the Broadcast address */ memset(parsed_cmd->ethaddr, 0xff, sizeof(parsed_cmd->ethaddr)); } /* function to interpret commands starting with "ethsw " */ static int do_ethsw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct ethsw_command_def parsed_cmd; int rc = CMD_RET_SUCCESS; if (argc == 1 || argc >= ETHSW_MAX_CMD_PARAMS) return CMD_RET_USAGE; command_def_init(&parsed_cmd); rc = keywords_find(argc, argv, &parsed_cmd); if (rc == CMD_RET_SUCCESS) rc = parsed_cmd.cmd_function(&parsed_cmd); return rc; } #define ETHSW_PORT_CONF_HELP "[port ] { enable | disable | show } " \ "- enable/disable a port; show a port's configuration" U_BOOT_CMD(ethsw, ETHSW_MAX_CMD_PARAMS, 0, do_ethsw, "Ethernet l2 switch commands", ETHSW_PORT_CONF_HELP"\n" ETHSW_PORT_STATS_HELP"\n" ETHSW_LEARN_HELP"\n" ETHSW_FDB_HELP"\n" ETHSW_PVID_HELP"\n" ETHSW_VLAN_HELP"\n" ETHSW_PORT_UNTAG_HELP"\n" ETHSW_EGR_VLAN_TAG_HELP"\n" ETHSW_VLAN_FDB_HELP"\n" ETHSW_PORT_INGR_FLTR_HELP"\n" ETHSW_PORT_AGGR_HELP"\n" );