static int link_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp, struct nlmsghdr *nlm) { int r; size_t len; struct rtattr *rta, *hwaddr; struct ifinfomsg *ifi; char ifn[IF_NAMESIZE + 1]; r = link_route(ctx, ifp, nlm); if (r != 0) return r; r = link_addr(ctx, ifp, nlm); if (r != 0) return r; #ifdef INET6 r = link_neigh(ctx, ifp, nlm); if (r != 0) return r; #endif if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK) return 0; len = nlm->nlmsg_len - sizeof(*nlm); if ((size_t)len < sizeof(*ifi)) { errno = EBADMSG; return -1; } ifi = NLMSG_DATA(nlm); if (ifi->ifi_flags & IFF_LOOPBACK) return 0; rta = (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: /* Ignore wireless messages */ if (nlm->nlmsg_type == RTM_NEWLINK && ifi->ifi_change == 0) return 0; break; case IFLA_IFNAME: strlcpy(ifn, (char *)RTA_DATA(rta), sizeof(ifn)); break; case IFLA_ADDRESS: hwaddr = rta; break; } rta = RTA_NEXT(rta, len); } if (nlm->nlmsg_type == RTM_DELLINK) { /* If are listening to a dev manager, let that remove * the interface rather than the kernel. */ if (dev_listening(ctx) < 1) dhcpcd_handleinterface(ctx, -1, ifn); return 0; } /* Virtual interfaces may not get a valid hardware address * at this point. * To trigger a valid hardware address pickup we need to pretend * that that don't exist until they have one. */ if (ifi->ifi_flags & IFF_MASTER && !hwaddr) { dhcpcd_handleinterface(ctx, -1, ifn); return 0; } /* Check for a new interface */ ifp = if_findindex(ctx->ifaces, (unsigned int)ifi->ifi_index); if (ifp == NULL) { /* If are listening to a dev manager, let that announce * the interface rather than the kernel. */ if (dev_listening(ctx) < 1) dhcpcd_handleinterface(ctx, 1, ifn); return 0; } /* Handle interface being renamed */ if (strcmp(ifp->name, ifn) != 0) { dhcpcd_handleinterface(ctx, -1, ifn); dhcpcd_handleinterface(ctx, 1, ifn); return 0; } /* Re-read hardware address and friends */ if (!(ifi->ifi_flags & IFF_UP) && hwaddr) { uint8_t l; l = l2addr_len(ifi->ifi_type); if (hwaddr->rta_len == RTA_LENGTH(l)) dhcpcd_handlehwaddr(ctx, ifn, RTA_DATA(hwaddr), l); } dhcpcd_handlecarrier(ctx, ifi->ifi_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN, ifi->ifi_flags, ifn); return 0; }
static int link_netlink(struct nlmsghdr *nlm) { int len; struct rtattr *rta, *hwaddr; struct ifinfomsg *ifi; char ifn[IF_NAMESIZE + 1]; struct interface *ifp; len = link_route(nlm); if (len != 0) return len; len = link_addr(nlm); if (len != 0) return len; if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK) return 0; len = nlm->nlmsg_len - sizeof(*nlm); if ((size_t)len < sizeof(*ifi)) { errno = EBADMSG; return -1; } ifi = NLMSG_DATA(nlm); if (ifi->ifi_flags & IFF_LOOPBACK) return 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: /* Ignore wireless messages */ if (nlm->nlmsg_type == RTM_NEWLINK && ifi->ifi_change == 0) return 1; break; case IFLA_IFNAME: strlcpy(ifn, RTA_DATA(rta), sizeof(ifn)); break; case IFLA_ADDRESS: hwaddr = rta; break; } rta = RTA_NEXT(rta, len); } if (nlm->nlmsg_type == RTM_DELLINK) { handle_interface(-1, ifn); return 1; } /* Virtual interfaces may not get a valid hardware address * at this point. * To trigger a valid hardware address pickup we need to pretend * that that don't exist until they have one. */ if (ifi->ifi_flags & IFF_MASTER && !hwaddr) { handle_interface(-1, ifn); return 1; } /* Check for interface name change */ if (handle_rename(ifi->ifi_index, ifn)) return 1; /* Check for a new interface */ ifp = find_interface(ifn); if (ifp == NULL) { /* If are listening to a dev manager, let that announce * the interface rather than the kernel. */ if (dev_listening() < 1) handle_interface(1, ifn); 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; }