From: Roy Marples Date: Sat, 22 Apr 2017 21:09:08 +0000 (+0100) Subject: Detect VLANID to use in IAID. X-Git-Tag: v7.0.0-rc1~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9db242be39938c7a588d733dc15cc3f63d54315d;p=thirdparty%2Fdhcpcd.git Detect VLANID to use in IAID. Summary: This only works if the VLAN interface has already been setup prior to starting dhcpcd. Initial fix for T115. Test Plan: Configure a vlan interface. Don't set any iaid in /etc/dhcpcd.conf. Start dhcpcd, check VLANID is used for IAID. Reviewers: sthen Reviewed By: sthen Tags: #dhcpcd Differential Revision: https://dev.marples.name/D107 --- diff --git a/src/dhcpcd.c b/src/dhcpcd.c index bc79610e..ac6c6ba9 100644 --- a/src/dhcpcd.c +++ b/src/dhcpcd.c @@ -477,6 +477,10 @@ configure_interface1(struct interface *ifp) * between reboots without persitent storage, * generating the IAID from the MAC address is the only * logical default. + * Saying that, if a VLANID has been specified then we + * can use that. It's possible that different interfaces + * can have the same VLANID, but this is no worse than + * generating the IAID from the duplicate MAC address. * * dhclient uses the last 4 bytes of the MAC address. * dibbler uses an increamenting counter. @@ -487,11 +491,18 @@ configure_interface1(struct interface *ifp) * dhcpcd-6.1.0 and earlier used the interface name, * falling back to interface index if name > 4. */ - if (ifp->hwlen >= sizeof(ifo->iaid)) + if (ifp->vlanid != 0) { + uint32_t vlanid; + + /* Maximal VLANID is 4095, so prefix with 0xff + * so we don't conflict with an interface index. */ + vlanid = htonl(ifp->vlanid | 0xff000000); + memcpy(ifo->iaid, &vlanid, sizeof(vlanid)); + } else if (ifp->hwlen >= sizeof(ifo->iaid)) { memcpy(ifo->iaid, ifp->hwaddr + ifp->hwlen - sizeof(ifo->iaid), sizeof(ifo->iaid)); - else { + } else { uint32_t len; len = (uint32_t)strlen(ifp->name); @@ -503,7 +514,7 @@ configure_interface1(struct interface *ifp) } else { /* IAID is the same size as a uint32_t */ len = htonl(ifp->index); - memcpy(ifo->iaid, &len, sizeof(len)); + memcpy(ifo->iaid, &len, sizeof(ifo->iaid)); } } ifo->options |= DHCPCD_IAID; diff --git a/src/dhcpcd.conf.5.in b/src/dhcpcd.conf.5.in index fbb7290e..2600f2fb 100644 --- a/src/dhcpcd.conf.5.in +++ b/src/dhcpcd.conf.5.in @@ -199,7 +199,8 @@ Set the Interface Association Identifier to This option must be used in an .Ic interface block. -This defaults to the last 4 bytes of the hardware address assigned to the +This defaults to the VLANID (prefixed with 0xff) for the interface if set, +otherwise the last 4 bytes of the hardware address assigned to the interface. Each instance of this should be unique within the scope of the client and .Nm dhcpcd diff --git a/src/dhcpcd.h b/src/dhcpcd.h index 55235e64..ac647038 100644 --- a/src/dhcpcd.h +++ b/src/dhcpcd.h @@ -81,6 +81,7 @@ struct interface { sa_family_t family; unsigned char hwaddr[HWADDR_LEN]; uint8_t hwlen; + unsigned short vlanid; unsigned int metric; int carrier; int wireless; diff --git a/src/if-bsd.c b/src/if-bsd.c index 40152cae..b0987d1a 100644 --- a/src/if-bsd.c +++ b/src/if-bsd.c @@ -48,6 +48,11 @@ #include #include #include +#ifdef __NetBSD__ +#include /* Needs netinet/if_ether.h */ +#else +#include +#endif #ifdef __DragonFly__ # include #elif __APPLE__ @@ -196,12 +201,31 @@ if_linkaddr(struct sockaddr_dl *sdl, const struct interface *ifp) } #endif +#if defined(SIOCG80211NWID) || defined(SIOCGETVLAN) +static int if_direct_ioctl(int s, const char *ifname, + unsigned long cmd, void *data) +{ + + strlcpy(data, ifname, IFNAMSIZ); + return ioctl(s, cmd, data); +} + +static int if_indirect_ioctl(int s, const char *ifname, + unsigned long cmd, void *data) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_data = data; + return if_direct_ioctl(s, ifname, cmd, &ifr); +} +#endif + static int if_getssid1(int s, const char *ifname, void *ssid) { int retval = -1; #if defined(SIOCG80211NWID) - struct ifreq ifr; struct ieee80211_nwid nwid; #elif defined(IEEE80211_IOC_SSID) struct ieee80211req ireq; @@ -209,11 +233,8 @@ if_getssid1(int s, const char *ifname, void *ssid) #endif #if defined(SIOCG80211NWID) /* NetBSD */ - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); memset(&nwid, 0, sizeof(nwid)); - ifr.ifr_data = (void *)&nwid; - if (ioctl(s, SIOCG80211NWID, &ifr) == 0) { + if (if_indirect_ioctl(s, ifname, SIOCG80211NWID, &nwid) == 0) { if (ssid == NULL) retval = nwid.i_len; else if (nwid.i_len > IF_SSIDLEN) @@ -288,6 +309,31 @@ if_vimaster(const struct dhcpcd_ctx *ctx, const char *ifname) return 0; } +unsigned short +if_vlanid(const struct interface *ifp) +{ +#ifdef SIOCGETVLAN + struct vlanreq vlr; + + memset(&vlr, 0, sizeof(vlr)); + if (if_indirect_ioctl(ifp->ctx->pf_inet_fd, + ifp->name, SIOCGETVLAN, &vlr) != 0) + return 0; /* 0 means no VLANID */ + return vlr.vlr_tag; +#elif defined(SIOCGVNETID) + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); + if (ioctl(ifp->ctx->pf_inet_fd, SIOCGVNETID, &ifr) != 0) + return 0; /* 0 means no VLANID */ + return ifr.ifr_vnetid; +#else + UNUSED(ifp); + return 0; /* 0 means no VLANID */ +#endif +} + static void get_addrs(int type, const void *data, const struct sockaddr **sa) { diff --git a/src/if-linux.c b/src/if-linux.c index 480c06da..1716dc38 100644 --- a/src/if-linux.c +++ b/src/if-linux.c @@ -28,15 +28,17 @@ #include /* Needed for 2.4 kernels */ #include -#include #include +#include #include #include #include #include +#include #include #include +#include #include #include @@ -253,6 +255,19 @@ if_vimaster(__unused const struct dhcpcd_ctx *ctx, __unused const char *ifname) return 0; } +unsigned short +if_vlanid(const struct interface *ifp) +{ + struct vlan_ioctl_args v; + + memset(&v, 0, sizeof(v)); + strlcpy(v.device1, ifp->name, sizeof(v.device1)); + v.cmd = GET_VLAN_VID_CMD; + if (ioctl(ifp->ctx->pf_inet_fd, SIOCSIFVLAN, &v) != 0) + return 0; /* 0 means no VLANID */ + return (unsigned short)v.u.VID; +} + static int _open_link_socket(struct sockaddr_nl *nl, int protocol) { diff --git a/src/if-sun.c b/src/if-sun.c index 5def7b0e..8d212eb2 100644 --- a/src/if-sun.c +++ b/src/if-sun.c @@ -159,6 +159,13 @@ if_getssid(struct interface *ifp) return -1; } +unsigned short +if_vlanid(__unused const struct interface *ifp) +{ + + return 0; +} + int if_vimaster(__unused const struct dhcpcd_ctx *ctx, __unused const char *ifname) { diff --git a/src/if.c b/src/if.c index 71385eef..bcf14f2d 100644 --- a/src/if.c +++ b/src/if.c @@ -516,6 +516,8 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv) } } + ifp->vlanid = if_vlanid(ifp); + #ifdef SIOCGIFPRIORITY /* Respect the interface priority */ memset(&ifr, 0, sizeof(ifr)); diff --git a/src/if.h b/src/if.h index 97a944f9..fd5f3101 100644 --- a/src/if.h +++ b/src/if.h @@ -141,6 +141,7 @@ int if_conf(struct interface *); int if_init(struct interface *); int if_getssid(struct interface *); int if_vimaster(const struct dhcpcd_ctx *ctx, const char *); +unsigned short if_vlanid(const struct interface *); int if_opensockets(struct dhcpcd_ctx *); int if_opensockets_os(struct dhcpcd_ctx *); void if_closesockets(struct dhcpcd_ctx *);