Exemplo n.º 1
0
static int
receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
{
	NMRDisc *rdisc = (NMRDisc *) user_data;
	NMRDiscConfigMap changed = 0;
	struct ndp_msgra *msgra = ndp_msgra (msg);
	NMRDiscGateway gateway;
	guint32 now = nm_utils_get_monotonic_timestamp_s ();
	int offset;
	int hop_limit;

	/* Router discovery is subject to the following RFC documents:
	 *
	 * http://tools.ietf.org/html/rfc4861
	 * http://tools.ietf.org/html/rfc4862
	 *
	 * The biggest difference from good old DHCP is that all configuration
	 * items have their own lifetimes and they are merged from various
	 * sources. Router discovery is *not* contract-based, so there is *no*
	 * single time when the configuration is finished and updates can
	 * come at any time.
	 */
	_LOGD ("received router advertisement at %u", now);

	/* DHCP level:
	 *
	 * The problem with DHCP level is what to do if subsequent
	 * router advertisements carry different flags. Currently we just
	 * rewrite the flag with every inbound RA.
	 */
	{
		NMRDiscDHCPLevel dhcp_level;

		if (ndp_msgra_flag_managed (msgra))
			dhcp_level = NM_RDISC_DHCP_LEVEL_MANAGED;
		else if (ndp_msgra_flag_other (msgra))
			dhcp_level = NM_RDISC_DHCP_LEVEL_OTHERCONF;
		else
			dhcp_level = NM_RDISC_DHCP_LEVEL_NONE;

		if (dhcp_level != rdisc->dhcp_level) {
			rdisc->dhcp_level = dhcp_level;
			changed |= NM_RDISC_CONFIG_DHCP_LEVEL;
		}
	}

	/* Default gateway:
	 *
	 * Subsequent router advertisements can represent new default gateways
	 * on the network. We should present all of them in router preference
	 * order.
	 */
	memset (&gateway, 0, sizeof (gateway));
	gateway.address = *ndp_msg_addrto (msg);
	gateway.timestamp = now;
	gateway.lifetime = ndp_msgra_router_lifetime (msgra);
	gateway.preference = translate_preference (ndp_msgra_route_preference (msgra));
	if (nm_rdisc_add_gateway (rdisc, &gateway))
		changed |= NM_RDISC_CONFIG_GATEWAYS;

	/* Addresses & Routes */
	ndp_msg_opt_for_each_offset (offset, msg, NDP_MSG_OPT_PREFIX) {
		NMRDiscRoute route;
		NMRDiscAddress address;

		/* Device route */
		memset (&route, 0, sizeof (route));
		route.plen = ndp_msg_opt_prefix_len (msg, offset);
		nm_utils_ip6_address_clear_host_address (&route.network, ndp_msg_opt_prefix (msg, offset), route.plen);
		route.timestamp = now;
		if (ndp_msg_opt_prefix_flag_on_link (msg, offset)) {
			route.lifetime = ndp_msg_opt_prefix_valid_time (msg, offset);
			if (nm_rdisc_add_route (rdisc, &route))
				changed |= NM_RDISC_CONFIG_ROUTES;
		}

		/* Address */
		if (ndp_msg_opt_prefix_flag_auto_addr_conf (msg, offset)) {
			if (route.plen == 64 && rdisc->iid.id) {
				memset (&address, 0, sizeof (address));
				address.address = route.network;
				address.timestamp = now;
				address.lifetime = ndp_msg_opt_prefix_valid_time (msg, offset);
				address.preferred = ndp_msg_opt_prefix_preferred_time (msg, offset);
				if (address.preferred > address.lifetime)
					address.preferred = address.lifetime;

				/* Add the Interface Identifier to the lower 64 bits */
				nm_utils_ipv6_addr_set_interface_identfier (&address.address, rdisc->iid);

				if (nm_rdisc_add_address (rdisc, &address))
					changed |= NM_RDISC_CONFIG_ADDRESSES;
			}
		}
	}
Exemplo n.º 2
0
static gboolean
receive_ra (gpointer user_data)
{
	NMFakeRDisc *self = user_data;
	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self);
	NMRDisc *rdisc = NM_RDISC (self);
	FakeRa *ra = priv->ras->data;
	NMRDiscConfigMap changed = 0;
	guint32 now = nm_utils_get_monotonic_timestamp_s ();
	guint i;

	priv->receive_ra_id = 0;

	if (rdisc->dhcp_level != ra->dhcp_level) {
		rdisc->dhcp_level = ra->dhcp_level;
		changed |= NM_RDISC_CONFIG_DHCP_LEVEL;
	}

	for (i = 0; i < ra->gateways->len; i++) {
		NMRDiscGateway *item = &g_array_index (ra->gateways, NMRDiscGateway, i);

		if (nm_rdisc_add_gateway (rdisc, item))
			changed |= NM_RDISC_CONFIG_GATEWAYS;
	}

	for (i = 0; i < ra->addresses->len; i++) {
		NMRDiscAddress *item = &g_array_index (ra->addresses, NMRDiscAddress, i);

		if (nm_rdisc_add_address (rdisc, item))
			changed |= NM_RDISC_CONFIG_ADDRESSES;
	}

	for (i = 0; i < ra->routes->len; i++) {
		NMRDiscRoute *item = &g_array_index (ra->routes, NMRDiscRoute, i);

		if (nm_rdisc_add_route (rdisc, item))
			changed |= NM_RDISC_CONFIG_ROUTES;
	}

	for (i = 0; i < ra->dns_servers->len; i++) {
		NMRDiscDNSServer *item = &g_array_index (ra->dns_servers, NMRDiscDNSServer, i);

		if (nm_rdisc_add_dns_server (rdisc, item))
			changed |= NM_RDISC_CONFIG_DNS_SERVERS;
	}

	for (i = 0; i < ra->dns_domains->len; i++) {
		NMRDiscDNSDomain *item = &g_array_index (ra->dns_domains, NMRDiscDNSDomain, i);

		if (nm_rdisc_add_dns_domain (rdisc, item))
			changed |= NM_RDISC_CONFIG_DNS_DOMAINS;
	}

	if (rdisc->mtu != ra->mtu) {
		rdisc->mtu = ra->mtu;
		changed |= NM_RDISC_CONFIG_MTU;
	}

	if (rdisc->hop_limit != ra->hop_limit) {
		rdisc->hop_limit = ra->hop_limit;
		changed |= NM_RDISC_CONFIG_HOP_LIMIT;
	}

	priv->ras = g_slist_remove (priv->ras, priv->ras->data);
	fake_ra_free (ra);

	nm_rdisc_ra_received (NM_RDISC (self), now, changed);

	/* Schedule next RA */
	if (priv->ras) {
		ra = priv->ras->data;
		priv->receive_ra_id = g_timeout_add_seconds (ra->when, receive_ra, self);
	}

	return G_SOURCE_REMOVE;
}