diff --git a/include/utils.h b/include/utils.h index 9ee55fdc..7223a10d 100644 --- a/include/utils.h +++ b/include/utils.h @@ -147,4 +147,7 @@ extern int cmdlineno; extern ssize_t getcmdline(char **line, size_t *len, FILE *in); extern int makeargs(char *line, char *argv[], int maxargs); +struct iplink_req; +int iplink_parse(int argc, char **argv, struct iplink_req *req, + char **name, char **type, char **link, char **dev); #endif /* __UTILS_H__ */ diff --git a/ip/iplink.c b/ip/iplink.c index f28f91c3..95801a6c 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -143,22 +143,145 @@ static int iplink_have_newlink(void) } #endif /* ! IPLINK_IOCTL_COMPAT */ -static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) +struct iplink_req { + struct nlmsghdr n; + struct ifinfomsg i; + char buf[1024]; +}; + +int iplink_parse(int argc, char **argv, struct iplink_req *req, + char **name, char **type, char **link, char **dev) { + int ret, len; + char abuf[32]; int qlen = -1; int mtu = -1; + + ret = argc; + + while (argc > 0) { + if (strcmp(*argv, "up") == 0) { + req->i.ifi_change |= IFF_UP; + req->i.ifi_flags |= IFF_UP; + } else if (strcmp(*argv, "down") == 0) { + req->i.ifi_change |= IFF_UP; + req->i.ifi_flags &= ~IFF_UP; + } else if (strcmp(*argv, "name") == 0) { + NEXT_ARG(); + *name = *argv; + } else if (matches(*argv, "link") == 0) { + NEXT_ARG(); + *link = *argv; + } else if (matches(*argv, "address") == 0) { + NEXT_ARG(); + len = ll_addr_a2n(abuf, sizeof(abuf), *argv); + addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len); + } else if (matches(*argv, "broadcast") == 0 || + strcmp(*argv, "brd") == 0) { + NEXT_ARG(); + len = ll_addr_a2n(abuf, sizeof(abuf), *argv); + addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len); + } else if (matches(*argv, "txqueuelen") == 0 || + strcmp(*argv, "qlen") == 0 || + matches(*argv, "txqlen") == 0) { + NEXT_ARG(); + if (qlen != -1) + duparg("txqueuelen", *argv); + if (get_integer(&qlen, *argv, 0)) + invarg("Invalid \"txqueuelen\" value\n", *argv); + addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4); + } else if (strcmp(*argv, "mtu") == 0) { + NEXT_ARG(); + if (mtu != -1) + duparg("mtu", *argv); + if (get_integer(&mtu, *argv, 0)) + invarg("Invalid \"mtu\" value\n", *argv); + addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4); + } else if (strcmp(*argv, "multicast") == 0) { + NEXT_ARG(); + req->i.ifi_change |= IFF_MULTICAST; + if (strcmp(*argv, "on") == 0) { + req->i.ifi_flags |= IFF_MULTICAST; + } else if (strcmp(*argv, "off") == 0) { + req->i.ifi_flags &= ~IFF_MULTICAST; + } else + return on_off("multicast"); + } else if (strcmp(*argv, "allmulticast") == 0) { + NEXT_ARG(); + req->i.ifi_change |= IFF_ALLMULTI; + if (strcmp(*argv, "on") == 0) { + req->i.ifi_flags |= IFF_ALLMULTI; + } else if (strcmp(*argv, "off") == 0) { + req->i.ifi_flags &= ~IFF_ALLMULTI; + } else + return on_off("allmulticast"); + } else if (strcmp(*argv, "promisc") == 0) { + NEXT_ARG(); + req->i.ifi_change |= IFF_PROMISC; + if (strcmp(*argv, "on") == 0) { + req->i.ifi_flags |= IFF_PROMISC; + } else if (strcmp(*argv, "off") == 0) { + req->i.ifi_flags &= ~IFF_PROMISC; + } else + return on_off("promisc"); + } else if (strcmp(*argv, "trailers") == 0) { + NEXT_ARG(); + req->i.ifi_change |= IFF_NOTRAILERS; + if (strcmp(*argv, "off") == 0) { + req->i.ifi_flags |= IFF_NOTRAILERS; + } else if (strcmp(*argv, "on") == 0) { + req->i.ifi_flags &= ~IFF_NOTRAILERS; + } else + return on_off("trailers"); + } else if (strcmp(*argv, "arp") == 0) { + NEXT_ARG(); + req->i.ifi_change |= IFF_NOARP; + if (strcmp(*argv, "on") == 0) { + req->i.ifi_flags &= ~IFF_NOARP; + } else if (strcmp(*argv, "off") == 0) { + req->i.ifi_flags |= IFF_NOARP; + } else + return on_off("noarp"); +#ifdef IFF_DYNAMIC + } else if (matches(*argv, "dynamic") == 0) { + NEXT_ARG(); + req->i.ifi_change |= IFF_DYNAMIC; + if (strcmp(*argv, "on") == 0) { + req->i.ifi_flags |= IFF_DYNAMIC; + } else if (strcmp(*argv, "off") == 0) { + req->i.ifi_flags &= ~IFF_DYNAMIC; + } else + return on_off("dynamic"); +#endif + } else if (matches(*argv, "type") == 0) { + NEXT_ARG(); + *type = *argv; + argc--; argv++; + break; + } else { + if (strcmp(*argv, "dev") == 0) { + NEXT_ARG(); + } + if (*dev) + duparg2("dev", *argv); + *dev = *argv; + } + argc--; argv++; + } + + return ret - argc; +} + +static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) +{ int len; - char abuf[32]; char *dev = NULL; char *name = NULL; char *link = NULL; char *type = NULL; struct link_util *lu = NULL; - struct { - struct nlmsghdr n; - struct ifinfomsg i; - char buf[1024]; - } req; + struct iplink_req req; + int ret; memset(&req, 0, sizeof(req)); @@ -167,116 +290,12 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) req.n.nlmsg_type = cmd; req.i.ifi_family = preferred_family; - while (argc > 0) { - if (strcmp(*argv, "up") == 0) { - req.i.ifi_change |= IFF_UP; - req.i.ifi_flags |= IFF_UP; - } else if (strcmp(*argv, "down") == 0) { - req.i.ifi_change |= IFF_UP; - req.i.ifi_flags &= ~IFF_UP; - } else if (strcmp(*argv, "name") == 0) { - NEXT_ARG(); - name = *argv; - } else if (matches(*argv, "link") == 0) { - NEXT_ARG(); - link = *argv; - } else if (matches(*argv, "address") == 0) { - NEXT_ARG(); - len = ll_addr_a2n(abuf, sizeof(abuf), *argv); - addattr_l(&req.n, sizeof(req), IFLA_ADDRESS, abuf, len); - } else if (matches(*argv, "broadcast") == 0 || - strcmp(*argv, "brd") == 0) { - NEXT_ARG(); - len = ll_addr_a2n(abuf, sizeof(abuf), *argv); - addattr_l(&req.n, sizeof(req), IFLA_BROADCAST, abuf, len); - } else if (matches(*argv, "txqueuelen") == 0 || - strcmp(*argv, "qlen") == 0 || - matches(*argv, "txqlen") == 0) { - NEXT_ARG(); - if (qlen != -1) - duparg("txqueuelen", *argv); - if (get_integer(&qlen, *argv, 0)) - invarg("Invalid \"txqueuelen\" value\n", *argv); - addattr_l(&req.n, sizeof(req), IFLA_TXQLEN, &qlen, 4); - } else if (strcmp(*argv, "mtu") == 0) { - NEXT_ARG(); - if (mtu != -1) - duparg("mtu", *argv); - if (get_integer(&mtu, *argv, 0)) - invarg("Invalid \"mtu\" value\n", *argv); - addattr_l(&req.n, sizeof(req), IFLA_MTU, &mtu, 4); - } else if (strcmp(*argv, "multicast") == 0) { - NEXT_ARG(); - req.i.ifi_change |= IFF_MULTICAST; - if (strcmp(*argv, "on") == 0) { - req.i.ifi_flags |= IFF_MULTICAST; - } else if (strcmp(*argv, "off") == 0) { - req.i.ifi_flags &= ~IFF_MULTICAST; - } else - return on_off("multicast"); - } else if (strcmp(*argv, "allmulticast") == 0) { - NEXT_ARG(); - req.i.ifi_change |= IFF_ALLMULTI; - if (strcmp(*argv, "on") == 0) { - req.i.ifi_flags |= IFF_ALLMULTI; - } else if (strcmp(*argv, "off") == 0) { - req.i.ifi_flags &= ~IFF_ALLMULTI; - } else - return on_off("allmulticast"); - } else if (strcmp(*argv, "promisc") == 0) { - NEXT_ARG(); - req.i.ifi_change |= IFF_PROMISC; - if (strcmp(*argv, "on") == 0) { - req.i.ifi_flags |= IFF_PROMISC; - } else if (strcmp(*argv, "off") == 0) { - req.i.ifi_flags &= ~IFF_PROMISC; - } else - return on_off("promisc"); - } else if (strcmp(*argv, "trailers") == 0) { - NEXT_ARG(); - req.i.ifi_change |= IFF_NOTRAILERS; - if (strcmp(*argv, "off") == 0) { - req.i.ifi_flags |= IFF_NOTRAILERS; - } else if (strcmp(*argv, "on") == 0) { - req.i.ifi_flags &= ~IFF_NOTRAILERS; - } else - return on_off("trailers"); - } else if (strcmp(*argv, "arp") == 0) { - NEXT_ARG(); - req.i.ifi_change |= IFF_NOARP; - if (strcmp(*argv, "on") == 0) { - req.i.ifi_flags &= ~IFF_NOARP; - } else if (strcmp(*argv, "off") == 0) { - req.i.ifi_flags |= IFF_NOARP; - } else - return on_off("noarp"); -#ifdef IFF_DYNAMIC - } else if (matches(*argv, "dynamic") == 0) { - NEXT_ARG(); - req.i.ifi_change |= IFF_DYNAMIC; - if (strcmp(*argv, "on") == 0) { - req.i.ifi_flags |= IFF_DYNAMIC; - } else if (strcmp(*argv, "off") == 0) { - req.i.ifi_flags &= ~IFF_DYNAMIC; - } else - return on_off("dynamic"); -#endif - } else if (matches(*argv, "type") == 0) { - NEXT_ARG(); - type = *argv; - argc--; argv++; - break; - } else { - if (strcmp(*argv, "dev") == 0) { - NEXT_ARG(); - } - if (dev) - duparg2("dev", *argv); - dev = *argv; - } - argc--; argv++; - } + ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev); + if (ret < 0) + return ret; + argc -= ret; + argv += ret; ll_init_map(&rth); if (type) {