Пример #1
0
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);
	}
}
Пример #2
0
/* 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);
	}
}
Пример #3
0
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);
}