]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Detect VLANID to use in IAID.
authorRoy Marples <roy@marples.name>
Sat, 22 Apr 2017 21:09:08 +0000 (22:09 +0100)
committerRoy Marples <roy@marples.name>
Sat, 22 Apr 2017 23:34:29 +0000 (00:34 +0100)
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

src/dhcpcd.c
src/dhcpcd.conf.5.in
src/dhcpcd.h
src/if-bsd.c
src/if-linux.c
src/if-sun.c
src/if.c
src/if.h

index bc79610e14e2e856224089f63a87ab7d4e8af49e..ac6c6ba9611fff4f652d7170329030753f4c3879 100644 (file)
@@ -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;
index fbb7290ed9619bb7a6ba7ed70cf0b53435c29bac..2600f2fb32da4a61d5edb65866a67edccdc4cbdc 100644 (file)
@@ -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
index 55235e641b58603d46c193f77172540f8ee09389..ac6470386d88c01bacc08fd7acfd8d733cd1b5e0 100644 (file)
@@ -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;
index 40152cae44a46e4d4e8bd1860f5852eaca394c04..b0987d1a5ab42c943a4a2119f22a099e5a8e4277 100644 (file)
 #include <netinet/in_var.h>
 #include <netinet6/in6_var.h>
 #include <netinet6/nd6.h>
+#ifdef __NetBSD__
+#include <net/if_vlanvar.h> /* Needs netinet/if_ether.h */
+#else
+#include <net/if_vlan_var.h>
+#endif
 #ifdef __DragonFly__
 #  include <netproto/802_11/ieee80211_ioctl.h>
 #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)
 {
index 480c06dadc4a5c0cb441303f83f807dadd7d12e1..1716dc386951ef57338f18bf7a796ad135690690 100644 (file)
 #include <asm/types.h> /* Needed for 2.4 kernels */
 
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <sys/ioctl.h>
+#include <sys/socket.h>
 #include <sys/param.h>
 
 #include <linux/if_addr.h>
 #include <linux/if_link.h>
 #include <linux/if_packet.h>
+#include <linux/if_vlan.h>
 #include <linux/filter.h>
 #include <linux/netlink.h>
+#include <linux/sockios.h>
 #include <linux/rtnetlink.h>
 
 #include <arpa/inet.h>
@@ -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)
 {
index 5def7b0e13b733ebf4a31cd32817fb9b82e77376..8d212eb2c2153823543939cdac08bf21be7271b1 100644 (file)
@@ -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)
 {
index 71385eef7691ccf0fab79ddf5f94c9d372465c3b..bcf14f2dee55e6ece2af47ef5d228887c735a2f8 100644 (file)
--- 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));
index 97a944f9465cacab47dc328e368e08be3f1b0d10..fd5f3101c297078799fde83ddb941966ce7d1840 100644 (file)
--- 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 *);