if (ifp->carrier != LINK_UP) {
syslog(LOG_INFO, "%s: carrier acquired", ifp->name);
ifp->carrier = LINK_UP;
+#if !defined(__linux__) && !defined(__NetBSD__)
+ /* BSD does not emit RTM_NEWADDR or RTM_CHGADDR when the
+ * hardware address changes so we have to go
+ * through the disovery process to work it out. */
+ handle_interface(0, ifp->name);
+#endif
if (ifp->wireless)
getifssid(ifp->name, ifp->ssid);
configure_interface(ifp, margc, margv);
TAILQ_REMOVE(ifs, ifp, next);
TAILQ_INSERT_TAIL(ifaces, ifp, next);
}
- init_state(ifp, margc, margv);
- start_interface(ifp);
+ if (action == 1) {
+ init_state(ifp, margc, margv);
+ start_interface(ifp);
+ }
}
/* Free our discovered list */
free(ifs);
}
-#ifdef RTM_CHGADDR
void
-handle_hwaddr(const char *ifname, unsigned char *hwaddr, size_t hwlen)
+handle_hwaddr(const char *ifname, const uint8_t *hwaddr, size_t hwlen)
{
struct interface *ifp;
- struct if_options *ifo;
- struct dhcp_state *state;
- TAILQ_FOREACH(ifp, ifaces, next) {
- if (strcmp(ifp->name, ifname) == 0 && ifp->hwlen <= hwlen) {
- state = D_STATE(ifp);
- if (state == NULL)
- continue;
- ifo = ifp->options;
- if (!(ifo->options &
- (DHCPCD_INFORM | DHCPCD_STATIC | DHCPCD_CLIENTID))
- && state->new != NULL &&
- state->new->cookie == htonl(MAGIC_COOKIE))
- {
- syslog(LOG_INFO,
- "%s: expiring for new hardware address",
- ifp->name);
- dhcp_drop(ifp, "EXPIRE");
- }
- memcpy(ifp->hwaddr, hwaddr, hwlen);
- ifp->hwlen = hwlen;
- if (!(ifo->options &
- (DHCPCD_INFORM | DHCPCD_STATIC | DHCPCD_CLIENTID)))
- {
- syslog(LOG_DEBUG, "%s: using hwaddr %s",
- ifp->name,
- hwaddr_ntoa(ifp->hwaddr, ifp->hwlen));
- state->interval = 0;
- state->nakoff = 0;
- start_interface(ifp);
- }
- }
+ ifp = find_interface(ifname);
+ if (ifp == NULL)
+ return;
+
+ if (hwlen > sizeof(ifp->hwaddr)) {
+ errno = ENOBUFS;
+ syslog(LOG_ERR, "%s: %s: %m", ifp->name, __func__);
+ return;
}
- free(hwaddr);
+
+ if (ifp->hwlen == hwlen && memcmp(ifp->hwaddr, hwaddr, hwlen) == 0)
+ return;
+
+ syslog(LOG_INFO, "%s: new hardware address: %s", ifp->name,
+ hwaddr_ntoa(hwaddr, hwlen));
+ ifp->hwlen = hwlen;
+ memcpy(ifp->hwaddr, hwaddr, hwlen);
}
-#endif
static void
if_reboot(struct interface *ifp, int argc, char **argv)
int handle_args(struct fd_list *, int, char **);
void handle_carrier(int, int, const char *);
void handle_interface(int, const char *);
-void handle_hwaddr(const char *, unsigned char *, size_t);
+void handle_hwaddr(const char *, const unsigned char *, size_t);
void drop_interface(struct interface *, const char *);
int select_profile(struct interface *, const char *);
sin.s6_addr = ((sa) != NULL) ? \
(((struct sockaddr_in6 *)(void *)sa)->sin6_addr).s6_addr : 0
+#ifndef CLLADDR
+# define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen))
+#endif
+
static int r_fd = -1;
static char *link_buf;
static ssize_t link_buflen;
struct ifa_msghdr *ifam;
struct sockaddr *sa, *rti_info[RTAX_MAX];
int len;
-#ifdef RTM_CHGADDR
struct sockaddr_dl sdl;
- unsigned char *hwaddr;
-#endif
#ifdef INET
struct rt rt;
#endif
if (rti_info[RTAX_IFA] == NULL)
break;
switch (rti_info[RTAX_IFA]->sa_family) {
-#ifdef RTM_CHGADDR
case AF_LINK:
+#ifdef RTM_CHGADDR
if (rtm->rtm_type != RTM_CHGADDR)
break;
+#else
+ if (rtm->rtm_type != RTM_NEWADDR)
+ break;
+#endif
memcpy(&sdl, rti_info[RTAX_IFA],
rti_info[RTAX_IFA]->sa_len);
- hwaddr = malloc(sdl.sdl_alen);
- if (hwaddr) {
- memcpy(hwaddr, LLADDR(&sdl),
- sdl.sdl_alen);
- handle_hwaddr(ifname, hwaddr,
- sdl.sdl_alen);
- } else
- syslog(LOG_ERR, "%s: %m",
- __func__);
+ handle_hwaddr(ifname,
+ (const unsigned char*)CLLADDR(&sdl),
+ sdl.sdl_alen);
break;
-#endif
#ifdef INET
case AF_INET:
case 255: /* FIXME: Why 255? */
return 1;
}
+static short l2addr_len(unsigned short if_type)
+{
+
+ switch (if_type) {
+ case ARPHRD_ETHER: /* FALLTHROUGH */
+ case ARPHRD_IEEE802: /*FALLTHROUGH */
+ case ARPHRD_IEEE80211:
+ return 6;
+ case ARPHRD_IEEE1394:
+ return 8;
+ case ARPHRD_INFINIBAND:
+ return 20;
+ default:
+ return -1;
+ }
+}
+
static int
link_netlink(struct nlmsghdr *nlm)
{
int len;
- struct rtattr *rta;
+ struct rtattr *rta, *hwaddr;
struct ifinfomsg *ifi;
char ifn[IF_NAMESIZE + 1];
rta = (struct rtattr *)(void *)((char *)ifi +NLMSG_ALIGN(sizeof(*ifi)));
len = NLMSG_PAYLOAD(nlm, sizeof(*ifi));
*ifn = '\0';
+ hwaddr = NULL;
while (RTA_OK(rta, len)) {
switch (rta->rta_type) {
case IFLA_WIRELESS:
case IFLA_IFNAME:
strlcpy(ifn, RTA_DATA(rta), sizeof(ifn));
break;
+ case IFLA_ADDRESS:
+ hwaddr = rta;
+ break;
}
rta = RTA_NEXT(rta, len);
}
return 1;
}
+ /* Re-read hardware address and friends */
+ if (!(ifi->ifi_flags & IFF_UP) && hwaddr) {
+ len = l2addr_len(ifi->ifi_type);
+ if (hwaddr->rta_len == RTA_LENGTH(len))
+ handle_hwaddr(ifn, RTA_DATA(hwaddr), len);
+ }
+
handle_carrier(ifi->ifi_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN,
ifi->ifi_flags, ifn);
return 1;