]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Change IAID to default from the last 4 bytes of the MAC address.
authorRoy Marples <roy@marples.name>
Fri, 15 Nov 2013 16:44:46 +0000 (16:44 +0000)
committerRoy Marples <roy@marples.name>
Fri, 15 Nov 2013 16:44:46 +0000 (16:44 +0000)
Rationale in the commit, but in a nutshell it allows for a stable
IAID between reboots without persistent storage and across
different OS's who name or number it differently to each other.

dhcpcd.c
dhcpcd.conf.5.in

index a01a0b4368f4e33ea5253cf0cec910950f5b8d84..6e5bc03b304a0acc54926daf0b1f1b20f3d875d4 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -321,7 +321,7 @@ configure_interface1(struct interface *ifp)
 {
        struct if_options *ifo = ifp->options;
        int ra_global, ra_iface;
-       uint32_t len;
+
        /* Do any platform specific configuration */
        if_conf(ifp);
 
@@ -368,6 +368,44 @@ configure_interface1(struct interface *ifp)
        }
 
        if (!(ifo->options & DHCPCD_IAID)) {
+               /*
+                * An IAID is for identifying a unqiue interface within
+                * the client. It is 4 bytes long. Working out a default
+                * value is problematic.
+                *
+                * Interface name and number are not stable
+                * between different OS's. Some OS's also cannot make
+                * up their mind what the interface should be called
+                * (yes, udev, I'm looking at you).
+                * Also, the name could be longer than 4 bytes.
+                * Also, with pluggable interfaces the name and index
+                * could easily get swapped per actual interface.
+                *
+                * The MAC address is 6 bytes long, the final 3
+                * being unique to the manufacturer and the initial 3
+                * being unique to the organisation which makes it.
+                * We could use the last 4 bytes of the MAC address
+                * as the IAID as it's the most stable part given the
+                * above, but equally it's not guaranteed to be
+                * unique.
+                *
+                * Given the above, and our need to reliably work
+                * between reboots without persitent storage,
+                * generating the IAID from the MAC address is the only
+                * logical default.
+                *
+                * dhclient uses the last 4 bytes of the MAC address.
+                * dibbler uses an increamenting counter.
+                * wide-dhcpv6 uses 0 or a configured value.
+                * odhcp6c uses 1.
+                * Windows 7 uses the first 3 bytes of the MAC address
+                * and an unknown byte.
+                * dhcpcd-6.1.0 and earlier used the interface name,
+                * falling back to interface index if name > 4.
+                */
+               memcpy(ifo->iaid, ifp->hwaddr + ifp->hwlen - sizeof(ifo->iaid),
+                   sizeof(ifo->iaid));
+#if 0
                len = strlen(ifp->name);
                if (len <= sizeof(ifo->iaid)) {
                        memcpy(ifo->iaid, ifp->name, len);
@@ -377,6 +415,7 @@ configure_interface1(struct interface *ifp)
                        len = htonl(ifp->index);
                        memcpy(ifo->iaid, &len, sizeof(len));
                }
+#endif
                ifo->options |= DHCPCD_IAID;
        }
 
@@ -485,6 +524,32 @@ handle_carrier(int carrier, int flags, const char *ifname)
        }
 }
 
+static void
+warn_iaid_conflict(struct interface *ifp, uint8_t *iaid)
+{
+       struct interface *ifn;
+       size_t i;
+
+       TAILQ_FOREACH(ifn, ifaces, next) {
+               if (ifn == ifp)
+                       continue;
+               if (memcmp(ifn->options->iaid, iaid,
+                   sizeof(ifn->options->iaid)) == 0)
+                       break;
+               for (i = 0; i < ifn->options->ia_len; i++) {
+                       if (memcmp(&ifn->options->ia[i].iaid, iaid,
+                           sizeof(ifn->options->ia[i].iaid)) == 0)
+                               break;
+               }
+       }
+
+       /* This is only a problem if the interfaces are on the same network. */
+       if (ifn)
+               syslog(LOG_ERR,
+                   "%s: IAID conflicts with one assigned to %s",
+                   ifp->name, ifn->name);
+}
+
 void
 start_interface(void *arg)
 {
@@ -511,12 +576,16 @@ start_interface(void *arg)
                /* Report IAIDs */
                syslog(LOG_INFO, "%s: IAID %s", ifp->name,
                    hwaddr_ntoa(ifo->iaid, sizeof(ifo->iaid)));
+               warn_iaid_conflict(ifp, ifo->iaid);
                for (i = 0; i < ifo->ia_len; i++) {
                        if (memcmp(ifo->iaid, ifo->ia[i].iaid,
                            sizeof(ifo->iaid)))
+                       {
                                syslog(LOG_INFO, "%s: IAID %s", ifp->name,
                                    hwaddr_ntoa(ifo->ia[i].iaid,
                                    sizeof(ifo->ia[i].iaid)));
+                               warn_iaid_conflict(ifp, ifo->ia[i].iaid);
+                       }
                }
        }
 
index 535f088adb590b8a7ad6525fc7fb21ac7f376f02..74f28bb98bd713cca0986491500b2c775ab7e6ee 100644 (file)
@@ -146,8 +146,13 @@ and should not be copied to other hosts.
 .It Ic iaid Ar iaid
 Set the Interface Association Identifier to
 .Ar iaid .
-This defaults to the interface name if 4 or less characters.
-If more then it defaults to the interface index.
+This defaults to 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
+warns if a conflict is detected.
+If there is a conflict, it is only a problem if the conflicted IAIDs are
+used on the same network.
 .It Ic persistent
 .Nm dhcpcd
 normally de-configures the interface and configuration when it exits.