]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Add if_nametospec helper to decode and interface name such as bge1:2 into
authorRoy Marples <roy@marples.name>
Mon, 18 Jul 2016 10:53:45 +0000 (10:53 +0000)
committerRoy Marples <roy@marples.name>
Mon, 18 Jul 2016 10:53:45 +0000 (10:53 +0000)
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.

dhcpcd.h
if-linux.c
if.c
if.h

index f286e3093f254f1d101b1c8271399236325d7366..fdb1c6d0b9aab8165775320f548dadc10f1462ef 100644 (file)
--- 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];
index f3dc5fe80740a9d0e7ceaafae77a040bd48b0c9a..687a1d38b34b89a8a835c6ca1c707bab986ede06 100644 (file)
@@ -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 1df718d07bbf5c83f33c4ff509915dffb75aac7e..65cd00a3778d0050ba94ad7606ef96ea9608584a 100644 (file)
--- 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 249dd2e43fecaccfe850c8fef1751925f594bd8f..a6a9c4fa9fe9f323a6e78984fbd028cd124cab5a 100644 (file)
--- 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 *);