示例#1
0
文件: agent.c 项目: andreiw/polaris
/* 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);
	}
}
示例#2
0
/* ARGSUSED */
static void
rtsock_event(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, void *arg)
{
	dhcp_smach_t *dsmp, *dsmnext;
	union {
		struct ifa_msghdr ifam;
		struct if_msghdr ifm;
		char buf[1024];
	} msg;
	uint16_t ifindex;
	int msglen;
	boolean_t isv6;

	if ((msglen = read(fd, &msg, sizeof (msg))) <= 0)
		return;

	/* Note that the routing socket interface index is just 16 bits */
	if (msg.ifm.ifm_type == RTM_IFINFO) {
		ifindex = msg.ifm.ifm_index;
		isv6 = (msg.ifm.ifm_flags & IFF_IPV6) ? B_TRUE : B_FALSE;
	} else if (msg.ifam.ifam_type == RTM_DELADDR ||
	    msg.ifam.ifam_type == RTM_NEWADDR) {
		ifindex = msg.ifam.ifam_index;
		isv6 = is_rtm_v6(&msg.ifam, msglen);
	} else {
		return;
	}

	for (dsmp = lookup_smach_by_uindex(ifindex, NULL, isv6);
	    dsmp != NULL; dsmp = dsmnext) {
		DHCPSTATE oldstate;
		boolean_t lif_finished;
		boolean_t lease_removed;
		dhcp_lease_t *dlp, *dlnext;

		/*
		 * Note that script_start can call dhcp_drop directly, and
		 * that will do release_smach.
		 */
		dsmnext = lookup_smach_by_uindex(ifindex, dsmp, isv6);
		oldstate = dsmp->dsm_state;

		/*
		 * Ignore state machines that are currently processing drop or
		 * release; there is nothing more we can do for them.
		 */
		if (dsmp->dsm_droprelease)
			continue;

		/*
		 * Look for link up/down notifications.  These occur on a
		 * physical interface basis.
		 */
		if (msg.ifm.ifm_type == RTM_IFINFO) {
			process_link_up_down(dsmp->dsm_lif->lif_pif, &msg.ifm);
			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.
		 */
		lif_finished = B_FALSE;
		lease_removed = B_FALSE;
		for (dlp = dsmp->dsm_leases; dlp != NULL; dlp = dlnext) {
			dhcp_lif_t *lif, *lifnext;
			uint_t nlifs = dlp->dl_nlifs;

			dlnext = dlp->dl_next;
			for (lif = dlp->dl_lifs; lif != NULL && nlifs > 0;
			    lif = lifnext, nlifs--) {
				lifnext = lif->lif_next;
				if (check_lif(lif, &msg.ifam, msglen)) {
					dsmp->dsm_lif_wait--;
					lif_finished = B_TRUE;
				}
			}
			if (dlp->dl_nlifs == 0) {
				remove_lease(dlp);
				lease_removed = B_TRUE;
			}
		}

		if ((isv6 && !check_main_lif(dsmp, &msg.ifam, msglen)) ||
		    (!isv6 && !verify_lif(dsmp->dsm_lif))) {
			finished_smach(dsmp, DHCP_IPC_E_INVIF);
			continue;
		}

		/*
		 * Ignore this state machine if nothing interesting has
		 * happened.
		 */
		if (!lif_finished && dsmp->dsm_lif_down == 0 &&
		    (dsmp->dsm_leases != NULL || !lease_removed))
			continue;

		/*
		 * If we're still waiting for DAD to complete on some of the
		 * configured LIFs, then don't send a response.
		 */
		if (dsmp->dsm_lif_wait != 0) {
			dhcpmsg(MSG_VERBOSE, "rtsock_event: %s still has %d "
			    "LIFs waiting on DAD", dsmp->dsm_name,
			    dsmp->dsm_lif_wait);
			continue;
		}

		/*
		 * If we have some failed LIFs, then handle them now.  We'll
		 * remove them from the list.  Any leases that become empty are
		 * also removed as part of the decline-generation process.
		 */
		if (dsmp->dsm_lif_down != 0)
			send_declines(dsmp);

		if (dsmp->dsm_leases == NULL) {
			dsmp->dsm_bad_offers++;
			/*
			 * For DHCPv6, we'll process the restart once we're
			 * done sending Decline messages, because these are
			 * supposed to be acknowledged.  With DHCPv4, there's
			 * no acknowledgment for a DECLINE, so after sending
			 * it, we just restart right away.
			 */
			if (!dsmp->dsm_isv6) {
				dhcpmsg(MSG_VERBOSE, "rtsock_event: %s has no "
				    "LIFs left", dsmp->dsm_name);
				dhcp_restart(dsmp);
			}
		} else {
			/*
			 * If we're now up on at least some of the leases and
			 * we were waiting for that, then kick off the rest of
			 * configuration.  Lease validation and DAD are done.
			 */
			dhcpmsg(MSG_VERBOSE, "rtsock_event: all LIFs verified "
			    "on %s in %s state", dsmp->dsm_name,
			    dhcp_state_to_string(oldstate));
			if (oldstate == PRE_BOUND ||
			    oldstate == ADOPTING)
				dhcp_bound_complete(dsmp);
			if (oldstate == ADOPTING)
				dhcp_adopt_complete(dsmp);
		}
	}
}