Beispiel #1
0
/*
 * Validate the specified scope zone ID in the sin6_scope_id field.  If the ID
 * is unspecified (=0), needs to be specified, and the default zone ID can be
 * used, the default value will be used.
 * This routine then generates the kernel-internal form: if the address scope
 * of is interface-local or link-local, embed the interface index in the
 * address.
 */
int
sa6_embedscope(struct sockaddr_in6 *sin6, int defaultok)
{
	struct ifnet *ifp;
	u_int32_t zoneid;

	if ((zoneid = sin6->sin6_scope_id) == 0 && defaultok)
		zoneid = scope6_addr2default(&sin6->sin6_addr);

	if (zoneid != 0 &&
	    (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr))) {
		/*
		 * At this moment, we only check interface-local and
		 * link-local scope IDs, and use interface indices as the
		 * zone IDs assuming a one-to-one mapping between interfaces
		 * and links.
		 */
		if (V_if_index < zoneid)
			return (ENXIO);
		ifp = ifnet_byindex(zoneid);
		if (ifp == NULL) /* XXX: this can happen for some OS */
			return (ENXIO);

		/* XXX assignment to 16bit from 32bit variable */
		sin6->sin6_addr.s6_addr16[1] = htons(zoneid & 0xffff);

		sin6->sin6_scope_id = 0;
	}

	return 0;
}
Beispiel #2
0
/*
 * generate standard sockaddr_in6 from embedded form.
 */
int
sa6_recoverscope(struct sockaddr_in6 *sin6)
{
	u_int32_t zoneid;

	if (sin6->sin6_scope_id != 0) {
		log(LOG_NOTICE,
		    "sa6_recoverscope: assumption failure (non 0 ID): %s%%%d\n",
		    ip6_sprintf(&sin6->sin6_addr), sin6->sin6_scope_id);
		/* XXX: proceed anyway... */
	}
	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
		/*
		 * KAME assumption: link id == interface id
		 */
		zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
		if (zoneid) {
			/* sanity check */
			if (zoneid < 0 || if_indexlim <= zoneid)
				return (ENXIO);
#ifdef __FreeBSD__
			if (ifnet_byindex(zoneid) == NULL)
#else
			if (ifindex2ifnet[zoneid] == NULL)
#endif
				return (ENXIO);
			sin6->sin6_addr.s6_addr16[1] = 0;
			sin6->sin6_scope_id = zoneid;
		}
	}

	return 0;
}
Beispiel #3
0
/*
 * generate standard sockaddr_in6 from embedded form.
 */
int
sa6_recoverscope(struct sockaddr_in6 *sin6)
{
	char ip6buf[INET6_ADDRSTRLEN];
	u_int32_t zoneid;

	if (sin6->sin6_scope_id != 0) {
		log(LOG_NOTICE,
		    "sa6_recoverscope: assumption failure (non 0 ID): %s%%%d\n",
		    ip6_sprintf(ip6buf, &sin6->sin6_addr), sin6->sin6_scope_id);
		/* XXX: proceed anyway... */
	}
	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
		/*
		 * KAME assumption: link id == interface id
		 */
		zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
		if (zoneid) {
			/* sanity check */
			if (zoneid < 0 || V_if_index < zoneid)
				return (ENXIO);
			if (!ifnet_byindex(zoneid))
				return (ENXIO);
			sin6->sin6_addr.s6_addr16[1] = 0;
			sin6->sin6_scope_id = zoneid;
		}
	}

	return 0;
}
Beispiel #4
0
static int
netkqfilter(struct cdev *dev, struct knote *kn)
{
	struct knlist *klist;
	struct ifnet *ifp;
	int idx;

	switch (kn->kn_filter) {
	case EVFILT_NETDEV:
		kn->kn_fop = &netdev_filtops;
		break;
	default:
		return (1);
	}

	idx = minor(dev);
	if (idx == 0) {
		klist = &ifklist;
	} else {
		ifp = ifnet_byindex(idx);
		if (ifp == NULL)
			return (1);
		klist = &ifp->if_klist;
	}

	kn->kn_hook = (caddr_t)klist;

	knlist_add(klist, kn, 0);

	return (0);
}
Beispiel #5
0
static int
netioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
{
	struct ifnet *ifp;
	int error, idx;

	/* only support interface specific ioctls */
	if (IOCGROUP(cmd) != 'i')
		return (EOPNOTSUPP);
	idx = minor(dev);
	if (idx == 0) {
		/*
		 * special network device, not interface.
		 */
		if (cmd == SIOCGIFCONF)
			return (ifconf(cmd, data));	/* XXX remove cmd */
		return (EOPNOTSUPP);
	}

	ifp = ifnet_byindex(idx);
	if (ifp == NULL)
		return (ENXIO);

	error = ifhwioctl(cmd, ifp, data, td);
	if (error == ENOIOCTL)
		error = EOPNOTSUPP;
	return (error);
}
Beispiel #6
0
/*
 * Gets real interface for the @rte.
 * Returns rt_ifp for !IFF_LOOPBACK routers.
 * Extracts "real" address interface from interface address
 * loopback routes.
 */
static struct ifnet *
fib6_get_ifaifp(struct rtentry *rte)
{
	struct ifnet *ifp;
	struct sockaddr_dl *sdl;

	ifp = rte->rt_ifp;
	if ((ifp->if_flags & IFF_LOOPBACK) &&
	    rte->rt_gateway->sa_family == AF_LINK) {
		sdl = (struct sockaddr_dl *)rte->rt_gateway;
		return (ifnet_byindex(sdl->sdl_index));
	}

	return (ifp);
}
Beispiel #7
0
/*
 * generate standard sockaddr_in6 from embedded form.
 */
int
sa6_recoverscope(struct sockaddr_in6 *sin6)
{
	char ip6buf[INET6_ADDRSTRLEN];
	u_int32_t zoneid;

	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
		/*
		 * KAME assumption: link id == interface id
		 */
		zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
		if (zoneid) {
			/* sanity check */
			if (V_if_index < zoneid)
				return (ENXIO);
#if 0
			/* XXX: Disabled due to possible deadlock. */
			if (!ifnet_byindex(zoneid))
				return (ENXIO);
#endif
			if (sin6->sin6_scope_id != 0 &&
			    zoneid != sin6->sin6_scope_id) {
				log(LOG_NOTICE,
				    "%s: embedded scope mismatch: %s%%%d. "
				    "sin6_scope_id was overridden.", __func__,
				    ip6_sprintf(ip6buf, &sin6->sin6_addr),
				    sin6->sin6_scope_id);
			}
			sin6->sin6_addr.s6_addr16[1] = 0;
			sin6->sin6_scope_id = zoneid;
		}
	}

	return 0;
}
Beispiel #8
0
int
scope6_set(struct ifnet *ifp, struct scope6_id *idlist)
{
	int i, s;
	int error = 0;
	struct scope6_id *sid = SID(ifp);

	if (sid == NULL)	/* paranoid? */
		return (EINVAL);

	/*
	 * XXX: We need more consistency checks of the relationship among
	 * scopes (e.g. an organization should be larger than a site).
	 */

	/*
	 * TODO(XXX): after setting, we should reflect the changes to
	 * interface addresses, routing table entries, PCB entries...
	 */

#if defined(__NetBSD__) || defined(__OpenBSD__)
	s = splsoftnet();
#else
	s = splnet();
#endif

	for (i = 0; i < 16; i++) {
		if (idlist->s6id_list[i] &&
		    idlist->s6id_list[i] != sid->s6id_list[i]) {
			/*
			 * An interface zone ID must be the corresponding
			 * interface index by definition.
			 */
			if (i == IPV6_ADDR_SCOPE_INTFACELOCAL &&
			    idlist->s6id_list[i] != ifp->if_index) {
				splx(s);
				return (EINVAL);
			}

			if (i == IPV6_ADDR_SCOPE_LINKLOCAL) {
				if (idlist->s6id_list[i] >= if_indexlim ||
#ifdef __FreeBSD__
				    ifnet_byindex(idlist->s6id_list[i]) == NULL
#else
				    ifindex2ifnet[idlist->s6id_list[i]] == NULL
#endif
				    ) {
					/*
					 * XXX: theoretically, there should be
					 * no relationship between link IDs and
					 * interface IDs, but we check the
					 * consistency for safety in later use.
					 */
					splx(s);
					return (EINVAL);
				}
			}

			/*
			 * XXX: we must need lots of work in this case,
			 * but we simply set the new value in this initial
			 * implementation.
			 */
			sid->s6id_list[i] = idlist->s6id_list[i];
		}
	}
	splx(s);

	return (error);
}
Beispiel #9
0
/*
 * Add a mif to the mif table
 */
static int
add_m6if(struct mif6ctl *mifcp)
{
	struct mif6 *mifp;
	struct ifnet *ifp;
	int error;

	MIF6_LOCK();

	if (mifcp->mif6c_mifi >= MAXMIFS) {
		MIF6_UNLOCK();
		return (EINVAL);
	}
	mifp = mif6table + mifcp->mif6c_mifi;
	if (mifp->m6_ifp != NULL) {
		MIF6_UNLOCK();
		return (EADDRINUSE); /* XXX: is it appropriate? */
	}
	if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi > V_if_index) {
		MIF6_UNLOCK();
		return (ENXIO);
	}

	ifp = ifnet_byindex(mifcp->mif6c_pifi);

	if (mifcp->mif6c_flags & MIFF_REGISTER) {
		if (reg_mif_num == (mifi_t)-1) {
			ifp = if_alloc(IFT_OTHER);

			if_initname(ifp, "register_mif", 0);
			ifp->if_flags |= IFF_LOOPBACK;
			if_attach(ifp);
			multicast_register_if6 = ifp;
			reg_mif_num = mifcp->mif6c_mifi;
			/*
			 * it is impossible to guess the ifindex of the
			 * register interface.  So mif6c_pifi is automatically
			 * calculated.
			 */
			mifcp->mif6c_pifi = ifp->if_index;
		} else {
			ifp = multicast_register_if6;
		}
	} else {
		/* Make sure the interface supports multicast */
		if ((ifp->if_flags & IFF_MULTICAST) == 0) {
			MIF6_UNLOCK();
			return (EOPNOTSUPP);
		}

		error = if_allmulti(ifp, 1);
		if (error) {
			MIF6_UNLOCK();
			return (error);
		}
	}

	mifp->m6_flags     = mifcp->mif6c_flags;
	mifp->m6_ifp       = ifp;

	/* initialize per mif pkt counters */
	mifp->m6_pkt_in    = 0;
	mifp->m6_pkt_out   = 0;
	mifp->m6_bytes_in  = 0;
	mifp->m6_bytes_out = 0;

	/* Adjust nummifs up if the mifi is higher than nummifs */
	if (nummifs <= mifcp->mif6c_mifi)
		nummifs = mifcp->mif6c_mifi + 1;

	MIF6_UNLOCK();
	MRT6_DLOG(DEBUG_ANY, "mif #%d, phyint %s", mifcp->mif6c_mifi,
	    if_name(ifp));

	return (0);
}