From: Roy Marples Date: Mon, 18 Jul 2016 10:53:45 +0000 (+0000) Subject: Add if_nametospec helper to decode and interface name such as bge1:2 into X-Git-Tag: v6.11.2~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b277b424d0daa25cb3a75cd14131754635004603;p=thirdparty%2Fdhcpcd.git Add if_nametospec helper to decode and interface name such as bge1:2 into device name, lun, ppa and driver name. Use this function when discovering addresesses and when they arrive via the kernel listening socket so they can be assigned to the correct physical interface. This change does also stop `dhcpcd eth0:1` working on Linux, but is needed for basic Solaris support. --- diff --git a/dhcpcd.h b/dhcpcd.h index f286e309..fdb1c6d0 100644 --- a/dhcpcd.h +++ b/dhcpcd.h @@ -75,11 +75,8 @@ struct interface { struct dhcpcd_ctx *ctx; TAILQ_ENTRY(interface) next; char name[IF_NAMESIZE]; -#ifdef __linux__ - char alias[IF_NAMESIZE]; -#endif unsigned int index; - int active; + unsigned int active; unsigned int flags; sa_family_t family; unsigned char hwaddr[HWADDR_LEN]; diff --git a/if-linux.c b/if-linux.c index f3dc5fe8..687a1d38 100644 --- a/if-linux.c +++ b/if-linux.c @@ -1368,10 +1368,12 @@ if_address(unsigned char cmd, const struct ipv4_addr *addr) nlm.ifa.ifa_index = addr->iface->index; nlm.ifa.ifa_family = AF_INET; nlm.ifa.ifa_prefixlen = inet_ntocidr(addr->mask); +#if 0 /* This creates the aliased interface */ add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LABEL, addr->iface->alias, (unsigned short)(strlen(addr->iface->alias) + 1)); +#endif add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LOCAL, &addr->addr.s_addr, sizeof(addr->addr.s_addr)); if (cmd == RTM_NEWADDR) @@ -1540,9 +1542,11 @@ if_address6(unsigned char cmd, const struct ipv6_addr *ia) /* Add as /128 if no IFA_F_NOPREFIXROUTE ? */ nlm.ifa.ifa_prefixlen = ia->prefix_len; +#if 0 /* This creates the aliased interface */ add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LABEL, ia->iface->alias, (unsigned short)(strlen(ia->iface->alias) + 1)); +#endif add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LOCAL, &ia->addr.s6_addr, sizeof(ia->addr.s6_addr)); diff --git a/if.c b/if.c index 1df718d0..65cd00a3 100644 --- a/if.c +++ b/if.c @@ -247,13 +247,11 @@ struct if_head * if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv) { struct ifaddrs *ifaddrs, *ifa; - char *p; - int i, active; + int i; + unsigned int active; struct if_head *ifs; struct interface *ifp; -#ifdef __linux__ - char ifn[IF_NAMESIZE]; -#endif + struct if_spec spec; #ifdef AF_LINK const struct sockaddr_dl *sdl; #ifdef SIOCGIFPRIORITY @@ -287,11 +285,13 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv) continue; #endif } + if (if_nametospec(ifa->ifa_name, &spec) != 0) + continue; /* It's possible for an interface to have >1 AF_LINK. * For our purposes, we use the first one. */ TAILQ_FOREACH(ifp, ifs, next) { - if (strcmp(ifp->name, ifa->ifa_name) == 0) + if (strcmp(ifp->name, spec.devname) == 0) break; } if (ifp) @@ -300,66 +300,47 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv) active = IF_ACTIVE_USER; if (argc > 0) { for (i = 0; i < argc; i++) { -#ifdef __linux__ - /* Check the real interface name */ - strlcpy(ifn, argv[i], sizeof(ifn)); - p = strchr(ifn, ':'); - if (p) - *p = '\0'; - if (strcmp(ifn, ifa->ifa_name) == 0) - break; -#else - if (strcmp(argv[i], ifa->ifa_name) == 0) + if (strcmp(argv[i], spec.devname) == 0) break; -#endif } - if (i == argc) { + if (i == argc) active = IF_INACTIVE; - p = ifa->ifa_name; -#ifdef __linux__ - strlcpy(ifn, ifa->ifa_name, sizeof(ifn)); -#endif - } else - p = argv[i]; } else { - p = ifa->ifa_name; -#ifdef __linux__ - strlcpy(ifn, ifa->ifa_name, sizeof(ifn)); -#endif /* -1 means we're discovering against a specific * interface, but we still need the below rules * to apply. */ - if (argc == -1 && strcmp(argv[0], ifa->ifa_name) != 0) + if (argc == -1 && strcmp(argv[0], spec.devname) != 0) continue; } for (i = 0; i < ctx->ifdc; i++) - if (!fnmatch(ctx->ifdv[i], p, 0)) + if (!fnmatch(ctx->ifdv[i], spec.devname, 0)) break; if (i < ctx->ifdc) active = IF_INACTIVE; for (i = 0; i < ctx->ifac; i++) - if (!fnmatch(ctx->ifav[i], p, 0)) + if (!fnmatch(ctx->ifav[i], spec.devname, 0)) break; if (ctx->ifac && i == ctx->ifac) active = IF_INACTIVE; #ifdef PLUGIN_DEV /* Ensure that the interface name has settled */ - if (!dev_initialized(ctx, p)) + if (!dev_initialized(ctx, spec.devname)) continue; #endif /* Don't allow loopback or pointopoint unless explicit */ if (ifa->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) { if ((argc == 0 || argc == -1) && - ctx->ifac == 0 && !if_hasconf(ctx, p)) + ctx->ifac == 0 && !if_hasconf(ctx, spec.devname)) active = IF_INACTIVE; } - if (if_vimaster(ctx, p) == 1) { + if (if_vimaster(ctx, spec.devname) == 1) { logger(ctx, argc ? LOG_ERR : LOG_DEBUG, - "%s: is a Virtual Interface Master, skipping", p); + "%s: is a Virtual Interface Master, skipping", + spec.devname); continue; } @@ -369,12 +350,7 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv) break; } ifp->ctx = ctx; -#ifdef __linux__ - strlcpy(ifp->name, ifn, sizeof(ifp->name)); - strlcpy(ifp->alias, p, sizeof(ifp->alias)); -#else - strlcpy(ifp->name, p, sizeof(ifp->name)); -#endif + strlcpy(ifp->name, spec.devname, sizeof(ifp->name)); ifp->flags = ifa->ifa_flags; ifp->carrier = if_carrier(ifp); @@ -510,8 +486,9 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv) if (!(ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST))) { /* Handle any platform init for the interface */ - if (active && if_init(ifp) == -1) { - logger(ifp->ctx, LOG_ERR, "%s: if_init: %m", p); + if (active != IF_INACTIVE && if_init(ifp) == -1) { + logger(ifp->ctx, LOG_ERR, "%s: if_init: %m", + ifp->name); if_free(ifp); continue; } @@ -521,7 +498,7 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv) if_setmtu(ifp, MTU_MIN) == -1) { logger(ifp->ctx, LOG_ERR, - "%s: if_setmtu: %m", p); + "%s: if_setmtu: %m", ifp->name); if_free(ifp); continue; } @@ -554,18 +531,62 @@ failed: return ifs; } +/* Decode bge0:1 as dev = bge, ppa = 0 and lun = 1 */ +int +if_nametospec(const char *ifname, struct if_spec *spec) +{ + char *ep; + int e; + + if (ifname == NULL || *ifname == '\0' || + strlcpy(spec->ifname, ifname, sizeof(spec->ifname)) >= + sizeof(spec->ifname) || + strlcpy(spec->drvname, ifname, sizeof(spec->drvname)) >= + sizeof(spec->drvname)) + { + errno = EINVAL; + return -1; + } + ep = strchr(spec->drvname, ':'); + if (ep) { + spec->lun = (int)strtoi(ep + 1, NULL, 10, 0, INT_MAX, &e); + if (e != 0) { + errno = e; + return -1; + } + *ep-- = '\0'; + } else { + spec->lun = -1; + ep = spec->drvname + strlen(spec->drvname) - 1; + } + strlcpy(spec->devname, spec->drvname, sizeof(spec->devname)); + while (ep > spec->drvname && isdigit((int)*ep)) + ep--; + if (*ep++ == ':') { + errno = EINVAL; + return -1; + } + spec->ppa = (int)strtoi(ep, NULL, 10, 0, INT_MAX, &e); + if (e != 0) + spec->ppa = -1; + *ep = '\0'; + + return 0; +} + static struct interface * if_findindexname(struct if_head *ifaces, unsigned int idx, const char *name) { if (ifaces != NULL) { + struct if_spec spec; struct interface *ifp; + if (name && if_nametospec(name, &spec) == -1) + return NULL; + TAILQ_FOREACH(ifp, ifaces, next) { - if ((name && strcmp(ifp->name, name) == 0) || -#ifdef __linux__ - (name && strcmp(ifp->alias, name) == 0) || -#endif + if ((name && strcmp(ifp->name, spec.devname) == 0) || (!name && ifp->index == idx)) return ifp; } diff --git a/if.h b/if.h index 249dd2e4..a6a9c4fa 100644 --- a/if.h +++ b/if.h @@ -105,6 +105,20 @@ int if_domtu(const struct interface *, short int); #define if_setmtu(ifp, mtu) if_domtu((ifp), (mtu)) int if_carrier(struct interface *); +/* + * Helper to decode an interface name of bge0:1 to + * devname = bge0, drvname = bge0, ppa = 0, lun = 1. + * If ppa or lun are invalid they are set to -1. + */ +struct if_spec { + char ifname[IF_NAMESIZE]; + char devname[IF_NAMESIZE]; + char drvname[IF_NAMESIZE]; + int ppa; + int lun; +}; +int if_nametospec(const char *, struct if_spec *); + /* The below functions are provided by if-KERNEL.c */ int if_conf(struct interface *); int if_init(struct interface *);