summaryrefslogtreecommitdiffstats
path: root/dhcpcd.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2013-11-15 16:44:46 +0000
committerRoy Marples <roy@marples.name>2013-11-15 16:44:46 +0000
commit6f66c6c93f43bf8ae45d468bc23c43b851b6290c (patch)
tree33f8cb1c97a8800ee61a964661b54622735176a5 /dhcpcd.c
parentebc9d360fab092318d9ce64a70b9693b33a87d0b (diff)
downloaddhcpcd-6f66c6c93f43bf8ae45d468bc23c43b851b6290c.tar.xz
Change IAID to default from the last 4 bytes of the MAC address.
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.
Diffstat (limited to 'dhcpcd.c')
-rw-r--r--dhcpcd.c71
1 files changed, 70 insertions, 1 deletions
diff --git a/dhcpcd.c b/dhcpcd.c
index a01a0b43..6e5bc03b 100644
--- 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);
+ }
}
}