| @@ -137,6 +137,23 @@ static void parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) |
| { |
| int count = 0; |
| char medium[IFNAMSIZ]; |
| + | static const char * const keywords[] = { |
| + | "mode", "ipip", "ip/ip", "gre", "gre/ip", "sit", "ipv6/ip", |
| + | "key", "ikey", "okey", "seq", "iseq", "oseq", |
| + | "csum", "icsum", "ocsum", "nopmtudisc", "pmtudisc", |
| + | "remote", "any", "local", "dev", |
| + | "ttl", "inherit", "tos", "dsfield", |
| + | "name", NULL |
| + | }; |
| + | enum { |
| + | ARG_mode, ARG_ipip, ARG_ip_ip, ARG_gre, ARG_gre_ip, ARG_sit, ARG_ip6_ip, |
| + | ARG_key, ARG_ikey, ARG_okey, ARG_seq, ARG_iseq, ARG_oseq, |
| + | ARG_csum, ARG_icsum, ARG_ocsum, ARG_nopmtudisc, ARG_pmtudisc, |
| + | ARG_remote, ARG_any, ARG_local, ARG_dev, |
| + | ARG_ttl, ARG_inherit, ARG_tos, ARG_dsfield, |
| + | ARG_name |
| + | }; |
| + | int key; |
| memset(p, 0, sizeof(*p)); |
| memset(&medium, 0, sizeof(medium)); |
| |
| @@ -148,22 +165,24 @@ static void parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) |
| p->iph.frag_off = htons(IP_DF); |
| |
| while (argc > 0) { |
| - | if (strcmp(*argv, "mode") == 0) { |
| + | key = index_in_str_array(keywords, *argv); |
| + | if (key == ARG_mode) { |
| NEXT_ARG(); |
| - | if (strcmp(*argv, "ipip") == 0 || |
| - | strcmp(*argv, "ip/ip") == 0) { |
| + | key = index_in_str_array(keywords, *argv); |
| + | if (key == ARG_ipip || |
| + | key == ARG_ip_ip) { |
| if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) { |
| bb_error_msg_and_die("you managed to ask for more than one tunnel mode"); |
| } |
| p->iph.protocol = IPPROTO_IPIP; |
| - | } else if (strcmp(*argv, "gre") == 0 || |
| - | strcmp(*argv, "gre/ip") == 0) { |
| + | } else if (key == ARG_gre || |
| + | key == ARG_gre_ip) { |
| if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) { |
| bb_error_msg_and_die("you managed to ask for more than one tunnel mode"); |
| } |
| p->iph.protocol = IPPROTO_GRE; |
| - | } else if (strcmp(*argv, "sit") == 0 || |
| - | strcmp(*argv, "ipv6/ip") == 0) { |
| + | } else if (key == ARG_sit || |
| + | key == ARG_ip6_ip) { |
| if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) { |
| bb_error_msg_and_die("you managed to ask for more than one tunnel mode"); |
| } |
| @@ -171,7 +190,7 @@ static void parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) |
| } else { |
| bb_error_msg_and_die("cannot guess tunnel mode"); |
| } |
| - | } else if (strcmp(*argv, "key") == 0) { |
| + | } else if (key == ARG_key) { |
| unsigned uval; |
| NEXT_ARG(); |
| p->i_flags |= GRE_KEY; |
| @@ -184,7 +203,7 @@ static void parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) |
| } |
| p->i_key = p->o_key = htonl(uval); |
| } |
| - | } else if (strcmp(*argv, "ikey") == 0) { |
| + | } else if (key == ARG_ikey) { |
| unsigned uval; |
| NEXT_ARG(); |
| p->i_flags |= GRE_KEY; |
| @@ -196,7 +215,7 @@ static void parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) |
| } |
| p->i_key = htonl(uval); |
| } |
| - | } else if (strcmp(*argv, "okey") == 0) { |
| + | } else if (key == ARG_okey) { |
| unsigned uval; |
| NEXT_ARG(); |
| p->o_flags |= GRE_KEY; |
| @@ -208,57 +227,61 @@ static void parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) |
| } |
| p->o_key = htonl(uval); |
| } |
| - | } else if (strcmp(*argv, "seq") == 0) { |
| + | } else if (key == ARG_seq) { |
| p->i_flags |= GRE_SEQ; |
| p->o_flags |= GRE_SEQ; |
| - | } else if (strcmp(*argv, "iseq") == 0) { |
| + | } else if (key == ARG_iseq) { |
| p->i_flags |= GRE_SEQ; |
| - | } else if (strcmp(*argv, "oseq") == 0) { |
| + | } else if (key == ARG_oseq) { |
| p->o_flags |= GRE_SEQ; |
| - | } else if (strcmp(*argv, "csum") == 0) { |
| + | } else if (key == ARG_csum) { |
| p->i_flags |= GRE_CSUM; |
| p->o_flags |= GRE_CSUM; |
| - | } else if (strcmp(*argv, "icsum") == 0) { |
| + | } else if (key == ARG_icsum) { |
| p->i_flags |= GRE_CSUM; |
| - | } else if (strcmp(*argv, "ocsum") == 0) { |
| + | } else if (key == ARG_ocsum) { |
| p->o_flags |= GRE_CSUM; |
| - | } else if (strcmp(*argv, "nopmtudisc") == 0) { |
| + | } else if (key == ARG_nopmtudisc) { |
| p->iph.frag_off = 0; |
| - | } else if (strcmp(*argv, "pmtudisc") == 0) { |
| + | } else if (key == ARG_pmtudisc) { |
| p->iph.frag_off = htons(IP_DF); |
| - | } else if (strcmp(*argv, "remote") == 0) { |
| + | } else if (key == ARG_remote) { |
| NEXT_ARG(); |
| - | if (strcmp(*argv, "any")) |
| + | key = index_in_str_array(keywords, *argv); |
| + | if (key == ARG_any) |
| p->iph.daddr = get_addr32(*argv); |
| - | } else if (strcmp(*argv, "local") == 0) { |
| + | } else if (key == ARG_local) { |
| NEXT_ARG(); |
| - | if (strcmp(*argv, "any")) |
| + | key = index_in_str_array(keywords, *argv); |
| + | if (key == ARG_any) |
| p->iph.saddr = get_addr32(*argv); |
| - | } else if (strcmp(*argv, "dev") == 0) { |
| + | } else if (key == ARG_dev) { |
| NEXT_ARG(); |
| strncpy(medium, *argv, IFNAMSIZ-1); |
| - | } else if (strcmp(*argv, "ttl") == 0) { |
| + | } else if (key == ARG_ttl) { |
| unsigned uval; |
| NEXT_ARG(); |
| - | if (strcmp(*argv, "inherit") != 0) { |
| + | key = index_in_str_array(keywords, *argv); |
| + | if (key != ARG_inherit) { |
| if (get_unsigned(&uval, *argv, 0)) |
| invarg(*argv, "TTL"); |
| if (uval > 255) |
| invarg(*argv, "TTL must be <=255"); |
| p->iph.ttl = uval; |
| } |
| - | } else if (strcmp(*argv, "tos") == 0 || |
| - | matches(*argv, "dsfield") == 0) { |
| + | } else if (key == ARG_tos || |
| + | key == ARG_dsfield) { |
| uint32_t uval; |
| NEXT_ARG(); |
| - | if (strcmp(*argv, "inherit") != 0) { |
| + | key = index_in_str_array(keywords, *argv); |
| + | if (key != ARG_inherit) { |
| if (rtnl_dsfield_a2n(&uval, *argv)) |
| invarg(*argv, "TOS"); |
| p->iph.tos = uval; |
| } else |
| p->iph.tos = 1; |
| } else { |
| - | if (strcmp(*argv, "name") == 0) { |
| + | if (key == ARG_name) { |
| NEXT_ARG(); |
| } |
| if (p->name[0]) |
| @@ -438,7 +461,7 @@ static void do_tunnels_list(struct ip_tunnel_parm *p) |
| ptr = strchr(buf, ':'); |
| if (ptr == NULL || |
| (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) { |
| - | bb_error_msg("wrong format of /proc/net/dev. Sorry"); |
| + | bb_error_msg("wrong format of /proc/net/dev"); |
| return; |
| } |
| if (sscanf(ptr, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu", |
| @@ -503,19 +526,29 @@ static int do_show(int argc, char **argv) |
| /* Return value becomes exitcode. It's okay to not return at all */ |
| int do_iptunnel(int argc, char **argv) |
| { |
| + | static const char * const keywords[] = { |
| + | "add", "change", "delete", "show", "list", "lst", NULL |
| + | }; |
| + | enum {ARG_add = 1, ARG_change, ARG_del, ARG_show, ARG_list, ARG_lst}; |
| + | smalluint key = 4; /* show */ |
| if (argc > 0) { |
| - | if (matches(*argv, "add") == 0) |
| - | return do_add(SIOCADDTUNNEL, argc-1, argv+1); |
| - | if (matches(*argv, "change") == 0) |
| - | return do_add(SIOCCHGTUNNEL, argc-1, argv+1); |
| - | if (matches(*argv, "del") == 0) |
| - | return do_del(argc-1, argv+1); |
| - | if (matches(*argv, "show") == 0 || |
| - | matches(*argv, "lst") == 0 || |
| - | matches(*argv, "list") == 0) |
| - | return do_show(argc-1, argv+1); |
| + | key = index_in_substr_array(keywords, *argv) +1; |
| + | --argc; |
| + | ++argv; |
| } else |
| return do_show(0, NULL); |
| - | |
| - | bb_error_msg_and_die("command \"%s\" is unknown", *argv); |
| + | if (key < ARG_add) |
| + | bail: |
| + | bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); |
| + | |
| + | if (key == ARG_add) |
| + | return do_add(SIOCADDTUNNEL, argc, argv); |
| + | if (key == ARG_change) |
| + | return do_add(SIOCCHGTUNNEL, argc, argv); |
| + | if (key == ARG_del) |
| + | return do_del(argc, argv); |
| + | if (key == ARG_show || key == ARG_list || key == ARG_lst) |
| + | return do_show(argc, argv); |
| + | /* be gentle to gcc; avoid warning about non returning */ |
| + | goto bail; /* never reached */ |
| } |