static boolean_t check_main_lif(dhcp_smach_t *dsmp, const struct ifa_msghdr *ifam, int msglen) { dhcp_lif_t *lif = dsmp->dsm_lif; struct lifreq lifr; /* * Get the real (64 bit) logical interface flags. Note that the * routing socket message has flags, but these are just the lower 32 * bits. */ (void) memset(&lifr, 0, sizeof (lifr)); (void) strlcpy(lifr.lifr_name, lif->lif_name, sizeof (lifr.lifr_name)); if (ioctl(v6_sock_fd, SIOCGLIFFLAGS, &lifr) == -1) { /* * Failing to retrieve flags means that the interface is gone. * Our state machine is now trash. */ if (errno == ENXIO) { dhcpmsg(MSG_INFO, "%s has been removed; abandoning", lif->lif_name); } else { dhcpmsg(MSG_ERR, "unable to retrieve interface flags on %s", lif->lif_name); } return (B_FALSE); } else if (!check_rtm_addr(ifam, msglen, B_TRUE, &lif->lif_v6addr)) { /* * If the message is not about this logical interface, * then just ignore it. */ return (B_TRUE); } else if (lifr.lifr_flags & IFF_DUPLICATE) { dhcpmsg(MSG_ERROR, "interface %s has duplicate address", lif->lif_name); return (B_FALSE); } else { return (B_TRUE); } }
/* ARGSUSED */ static void rtsock_event(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, void *arg) { struct ifslist *ifs; union { struct ifa_msghdr ifam; char buf[1024]; } msg; uint16_t ifindex; struct lifreq lifr; char *fail; int msglen; DHCPSTATE oldstate; if ((msglen = read(fd, &msg, sizeof (msg))) <= 0) return; /* * These are the messages that can identify a particular logical * interface by local IP address. */ if (msg.ifam.ifam_type != RTM_DELADDR && msg.ifam.ifam_type != RTM_NEWADDR) return; /* Note that ifam_index is just 16 bits */ ifindex = msg.ifam.ifam_index; for (ifs = lookup_ifs_by_uindex(ifindex, NULL); ifs != NULL; ifs = lookup_ifs_by_uindex(ifindex, ifs)) { /* * The if_sock_ip_fd is set to a non-negative integer by * configure_bound(). If it's negative, then DHCP doesn't * think we're bound. * * For pre-bound interfaces, we want to check to see if the * IFF_UP bit has been reported. This means that DAD is * complete. */ oldstate = ifs->if_state; if (ifs->if_sock_ip_fd == -1 && (oldstate != PRE_BOUND && oldstate != ADOPTING)) continue; /* * Since we cannot trust the flags reported by the routing * socket (they're just 32 bits -- and thus never include * IFF_DUPLICATE), and we can't trust the ifindex (it's only 16 * bits and also doesn't reflect the alias in use), we get * flags on all matching interfaces, and go by that. */ (void) strlcpy(lifr.lifr_name, ifs->if_name, sizeof (lifr.lifr_name)); if (ioctl(ifs->if_sock_fd, SIOCGLIFFLAGS, &lifr) == -1) { fail = "unable to retrieve interface flags on %s"; lifr.lifr_flags = 0; } else if (!check_rtm_addr(&msg.ifam, msglen, ifs->if_addr)) { /* * If the message is not about this logical interface, * then just ignore it. */ continue; } else if (lifr.lifr_flags & IFF_DUPLICATE) { fail = "interface %s has duplicate address"; } else { /* * If we're now up and we were waiting for that, then * kick off this interface. DAD is done. */ if (lifr.lifr_flags & IFF_UP) { if (oldstate == PRE_BOUND || oldstate == ADOPTING) dhcp_bound_complete(ifs); if (oldstate == ADOPTING) dhcp_adopt_complete(ifs); } continue; } if (ifs->if_sock_ip_fd != -1) { (void) close(ifs->if_sock_ip_fd); ifs->if_sock_ip_fd = -1; } dhcpmsg(MSG_ERROR, fail, ifs->if_name); /* * The binding has evidently failed, so it's as though it never * happened. We need to do switch back to PRE_BOUND state so * that send_pkt_internal() uses DLPI instead of sockets. Our * logical interface has already been torn down by the kernel, * and thus we can't send DHCPDECLINE by way of regular IP. * (Unless we're adopting -- allow the grandparent to be * handled as expected.) */ if (oldstate != ADOPTING) ifs->if_state = PRE_BOUND; if (ifs->if_ack->opts[CD_DHCP_TYPE] != NULL && (lifr.lifr_flags & IFF_DUPLICATE)) send_decline(ifs, fail, &ifs->if_addr); ifs->if_bad_offers++; dhcp_restart(ifs); } }
static boolean_t check_lif(dhcp_lif_t *lif, const struct ifa_msghdr *ifam, int msglen) { boolean_t isv6, dad_wait, unplumb; int fd; struct lifreq lifr; isv6 = lif->lif_pif->pif_isv6; fd = isv6 ? v6_sock_fd : v4_sock_fd; /* * Get the real (64 bit) logical interface flags. Note that the * routing socket message has flags, but these are just the lower 32 * bits. */ unplumb = B_FALSE; (void) memset(&lifr, 0, sizeof (lifr)); (void) strlcpy(lifr.lifr_name, lif->lif_name, sizeof (lifr.lifr_name)); if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { /* * Failing to retrieve flags means that the interface is gone. * It hasn't failed to verify with DAD, but we still have to * give up on it. */ lifr.lifr_flags = 0; if (errno == ENXIO) { lif->lif_plumbed = B_FALSE; dhcpmsg(MSG_INFO, "%s has been removed; abandoning", lif->lif_name); if (!isv6) discard_default_routes(lif->lif_smachs); } else { dhcpmsg(MSG_ERR, "unable to retrieve interface flags on %s", lif->lif_name); } unplumb = B_TRUE; } else if (!check_rtm_addr(ifam, msglen, isv6, &lif->lif_v6addr)) { /* * If the message is not about this logical interface, * then just ignore it. */ return (B_FALSE); } else if (lifr.lifr_flags & IFF_DUPLICATE) { dhcpmsg(MSG_ERROR, "interface %s has duplicate address", lif->lif_name); lif_mark_decline(lif, "duplicate address"); close_ip_lif(lif); (void) open_ip_lif(lif, INADDR_ANY, B_TRUE); } dad_wait = lif->lif_dad_wait; if (dad_wait) { dhcpmsg(MSG_VERBOSE, "check_lif: %s has finished DAD", lif->lif_name); lif->lif_dad_wait = B_FALSE; } if (unplumb) unplumb_lif(lif); return (dad_wait); }