示例#1
0
int
in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
    struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp,
    u_int rtableid)
{
	struct rtentry *rt = NULL;
	struct in6_pktinfo *pi = NULL;

	/* If the caller specify the outgoing interface explicitly, use it. */
	if (opts && (pi = opts->ip6po_pktinfo) != NULL && pi->ipi6_ifindex) {
		*retifp = if_get(pi->ipi6_ifindex);
		if (*retifp != NULL)
			return (0);
	}

	/*
	 * If the destination address is a multicast address and the outgoing
	 * interface for the address is specified by the caller, use it.
	 */
	if (IN6_IS_ADDR_MULTICAST(&dstsock->sin6_addr) &&
	    mopts != NULL && (*retifp = if_get(mopts->im6o_ifidx)) != NULL)
	    	return (0);

	rt = in6_selectroute(dstsock, opts, ro, rtableid);
	if (rt == NULL)
		return (EHOSTUNREACH);

	/*
	 * do not use a rejected or black hole route.
	 * XXX: this check should be done in the L2 output routine.
	 * However, if we skipped this check here, we'd see the following
	 * scenario:
	 * - install a rejected route for a scoped address prefix
	 *   (like fe80::/10)
	 * - send a packet to a destination that matches the scoped prefix,
	 *   with ambiguity about the scope zone.
	 * - pick the outgoing interface from the route, and disambiguate the
	 *   scope zone with the interface.
	 * - ip6_output() would try to get another route with the "new"
	 *   destination, which may be valid.
	 * - we'd see no error on output.
	 * Although this may not be very harmful, it should still be confusing.
	 * We thus reject the case here.
	 */
	if (rt && (rt->rt_flags & (RTF_REJECT | RTF_BLACKHOLE)))
		return (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);

	if (rt != NULL)
		*retifp = if_get(rt->rt_ifidx);

	return (0);
}
示例#2
0
void
pairstart(struct ifnet *ifp)
{
	struct pair_softc	*sc = (struct pair_softc *)ifp->if_softc;
	struct mbuf_list	 ml = MBUF_LIST_INITIALIZER();
	struct ifnet		*pairedifp;
	struct mbuf		*m;

	pairedifp = if_get(sc->sc_pairedif);

	for (;;) {
		IFQ_DEQUEUE(&ifp->if_snd, m);
		if (m == NULL)
			break;

#if NBPFILTER > 0
		if (ifp->if_bpf)
			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
#endif /* NBPFILTER > 0 */

		ifp->if_opackets++;
		if (pairedifp != NULL) {
			if (m->m_flags & M_PKTHDR)
				m_resethdr(m);
			ml_enqueue(&ml, m);
		} else
			m_freem(m);
	}

	if (pairedifp != NULL) {
		if_input(pairedifp, &ml);
		if_put(pairedifp);
	}
}
示例#3
0
/*
 * generate kernel-internal form (scopeid embedded into s6_addr16[1]).
 * If the address scope of is link-local, embed the interface index in the
 * address.  The routine determines our precedence
 * between advanced API scope/interface specification and basic API
 * specification.
 *
 * this function should be nuked in the future, when we get rid of
 * embedded scopeid thing.
 *
 * XXX actually, it is over-specification to return ifp against sin6_scope_id.
 * there can be multiple interfaces that belong to a particular scope zone
 * (in specification, we have 1:N mapping between a scope zone and interfaces).
 * we may want to change the function to return something other than ifp.
 */
int
in6_embedscope(struct in6_addr *in6, const struct sockaddr_in6 *sin6,
    struct inpcb *in6p)
{
	struct ifnet *ifp = NULL;
	u_int32_t scopeid;

	*in6 = sin6->sin6_addr;
	scopeid = sin6->sin6_scope_id;

	/*
	 * don't try to read sin6->sin6_addr beyond here, since the caller may
	 * ask us to overwrite existing sockaddr_in6
	 */

	if (IN6_IS_SCOPE_EMBED(in6)) {
		struct in6_pktinfo *pi;

		/*
		 * KAME assumption: link id == interface id
		 */

		if (in6p && in6p->inp_outputopts6 &&
		    (pi = in6p->inp_outputopts6->ip6po_pktinfo) &&
		    pi->ipi6_ifindex) {
			ifp = if_get(pi->ipi6_ifindex);
			if (ifp == NULL)
				return ENXIO;  /* XXX EINVAL? */
			in6->s6_addr16[1] = htons(pi->ipi6_ifindex);
		} else if (in6p && IN6_IS_ADDR_MULTICAST(in6) &&
		    in6p->inp_moptions6 &&
		    (ifp = if_get(in6p->inp_moptions6->im6o_ifidx))) {
			in6->s6_addr16[1] = htons(ifp->if_index);
		} else if (scopeid) {
			ifp = if_get(scopeid);
			if (ifp == NULL)
				return ENXIO;  /* XXX EINVAL? */
			/*XXX assignment to 16bit from 32bit variable */
			in6->s6_addr16[1] = htons(scopeid & 0xffff);
		}
		if_put(ifp);
	}

	return 0;
}
示例#4
0
void
pair_media_status(struct ifnet *ifp, struct ifmediareq *imr)
{
	struct pair_softc	*sc = ifp->if_softc;
	struct ifnet		*pairedifp;

	imr->ifm_active = IFM_ETHER | IFM_AUTO;

	if ((pairedifp = if_get(sc->sc_pairedif)) == NULL) {
		imr->ifm_status = 0;
		return;
	}
	if_put(pairedifp);

	imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
}
示例#5
0
void
pair_link_state(struct ifnet *ifp)
{
	struct pair_softc	*sc = ifp->if_softc;
	struct ifnet		*pairedifp;
	unsigned int		 link_state;

	/* The pair state is determined by the paired interface */
	if ((pairedifp = if_get(sc->sc_pairedif)) != NULL) {
		link_state = LINK_STATE_UP;
		if_put(pairedifp);
	} else
		link_state = LINK_STATE_DOWN;

	if (ifp->if_link_state != link_state) {
		ifp->if_link_state = link_state;
		if_link_state_change(ifp);
	}
}
示例#6
0
int
pair_clone_destroy(struct ifnet *ifp)
{
	struct pair_softc	*sc = ifp->if_softc;
	struct ifnet		*pairedifp;
	struct pair_softc	*dstsc = ifp->if_softc;

	if ((pairedifp = if_get(sc->sc_pairedif)) != NULL) {
		dstsc = pairedifp->if_softc;
		dstsc->sc_pairedif = 0;
		pair_link_state(pairedifp);
		if_put(pairedifp);
	}

	ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
	ether_ifdetach(ifp);
	if_detach(ifp);
	free(sc, M_DEVBUF, sizeof(*sc));

	return (0);
}
示例#7
0
int
pairioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
	struct pair_softc	*sc = (struct pair_softc *)ifp->if_softc;
	struct ifreq		*ifr = (struct ifreq *)data;
	struct if_clone		*ifc;
	struct pair_softc	*pairedsc = ifp->if_softc;
	struct ifnet		*oldifp = NULL, *newifp = NULL;
	int			 error = 0, unit;

	switch (cmd) {
	case SIOCSIFADDR:
		ifp->if_flags |= IFF_UP;
		/* FALLTHROUGH */

	case SIOCSIFFLAGS:
		if (ifp->if_flags & IFF_UP)
			ifp->if_flags |= IFF_RUNNING;
		else
			ifp->if_flags &= ~IFF_RUNNING;
		break;

	case SIOCADDMULTI:
	case SIOCDELMULTI:
		break;

	case SIOCGIFMEDIA:
	case SIOCSIFMEDIA:
		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
		break;

	case SIOCSIFPAIR:
		if (sc->sc_pairedif == ifr->ifr_index)
			break;

		/* Cannot link to myself */
		if (ifr->ifr_index == ifp->if_index) {
			error = EINVAL;
			break;
		}

		oldifp = if_get(sc->sc_pairedif);
		newifp = if_get(ifr->ifr_index);

		if (newifp != NULL) {
			pairedsc = newifp->if_softc;

			if (pairedsc->sc_pairedif != 0) {
				error = EBUSY;
				break;
			}

			/* Only allow pair(4) interfaces for the pair */
			if ((ifc = if_clone_lookup(newifp->if_xname,
			    &unit)) == NULL || strcmp("pair",
			    ifc->ifc_name) != 0) {
				error = ENODEV;
				break;
			}

			pairedsc->sc_pairedif = ifp->if_index;
			sc->sc_pairedif = ifr->ifr_index;
		} else
			sc->sc_pairedif = 0;

		if (oldifp != NULL) {
			pairedsc = oldifp->if_softc;
			pairedsc->sc_pairedif = 0;
		}
		break;

	case SIOCGIFPAIR:
		ifr->ifr_index = sc->sc_pairedif;
		break;

	default:
		error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
	}

	if (newifp != NULL || oldifp != NULL)
		pair_link_state(ifp);
	if (oldifp != NULL) {
		pair_link_state(oldifp);
		if_put(oldifp);
	}
	if (newifp != NULL) {
		pair_link_state(newifp);
		if_put(newifp);
	}

	return (error);
}
示例#8
0
/*
 * Return an IPv6 address, which is the most appropriate for a given
 * destination and user specified options.
 * If necessary, this function lookups the routing table and returns
 * an entry to the caller for later use.
 */
int
in6_selectsrc(struct in6_addr **in6src, struct sockaddr_in6 *dstsock,
    struct ip6_pktopts *opts, struct ip6_moptions *mopts,
    struct route_in6 *ro, struct in6_addr *laddr, u_int rtableid)
{
	struct ifnet *ifp = NULL;
	struct in6_addr *dst;
	struct in6_ifaddr *ia6 = NULL;
	struct in6_pktinfo *pi = NULL;
	int	error;

	dst = &dstsock->sin6_addr;

	/*
	 * If the source address is explicitly specified by the caller,
	 * check if the requested source address is indeed a unicast address
	 * assigned to the node, and can be used as the packet's source
	 * address.  If everything is okay, use the address as source.
	 */
	if (opts && (pi = opts->ip6po_pktinfo) &&
	    !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
		struct sockaddr_in6 sa6;

		/* get the outgoing interface */
		error = in6_selectif(dstsock, opts, mopts, ro, &ifp, rtableid);
		if (error)
			return (error);

		bzero(&sa6, sizeof(sa6));
		sa6.sin6_family = AF_INET6;
		sa6.sin6_len = sizeof(sa6);
		sa6.sin6_addr = pi->ipi6_addr;

		if (ifp && IN6_IS_SCOPE_EMBED(&sa6.sin6_addr))
			sa6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
		if_put(ifp); /* put reference from in6_selectif */

		ia6 = ifatoia6(ifa_ifwithaddr(sin6tosa(&sa6), rtableid));
		if (ia6 == NULL ||
		    (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY)))
			return (EADDRNOTAVAIL);

		pi->ipi6_addr = sa6.sin6_addr; /* XXX: this overrides pi */

		*in6src = &pi->ipi6_addr;
		return (0);
	}

	/*
	 * If the source address is not specified but the socket(if any)
	 * is already bound, use the bound address.
	 */
	if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr)) {
		*in6src = laddr;
		return (0);
	}

	/*
	 * If the caller doesn't specify the source address but
	 * the outgoing interface, use an address associated with
	 * the interface.
	 */
	if (pi && pi->ipi6_ifindex) {
		ifp = if_get(pi->ipi6_ifindex);
		if (ifp == NULL)
			return (ENXIO); /* XXX: better error? */

		ia6 = in6_ifawithscope(ifp, dst, rtableid);
		if_put(ifp);

		if (ia6 == NULL)
			return (EADDRNOTAVAIL);

		*in6src = &ia6->ia_addr.sin6_addr;
		return (0);
	}

	/*
	 * If the destination address is a link-local unicast address or
	 * a link/interface-local multicast address, and if the outgoing
	 * interface is specified by the sin6_scope_id filed, use an address
	 * associated with the interface.
	 * XXX: We're now trying to define more specific semantics of
	 *      sin6_scope_id field, so this part will be rewritten in
	 *      the near future.
	 */
	if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MC_LINKLOCAL(dst) ||
	     IN6_IS_ADDR_MC_INTFACELOCAL(dst)) && dstsock->sin6_scope_id) {
		ifp = if_get(dstsock->sin6_scope_id);
		if (ifp == NULL)
			return (ENXIO); /* XXX: better error? */

		ia6 = in6_ifawithscope(ifp, dst, rtableid);
		if_put(ifp);

		if (ia6 == NULL)
			return (EADDRNOTAVAIL);

		*in6src = &ia6->ia_addr.sin6_addr;
		return (0);
	}

	/*
	 * If the destination address is a multicast address and
	 * the outgoing interface for the address is specified
	 * by the caller, use an address associated with the interface.
	 * Even if the outgoing interface is not specified, we also
	 * choose a loopback interface as the outgoing interface.
	 */
	if (IN6_IS_ADDR_MULTICAST(dst)) {
		ifp = mopts ? if_get(mopts->im6o_ifidx) : NULL;

		if (!ifp && dstsock->sin6_scope_id)
			ifp = if_get(htons(dstsock->sin6_scope_id));

		if (ifp) {
			ia6 = in6_ifawithscope(ifp, dst, rtableid);
			if_put(ifp);

			if (ia6 == NULL)
				return (EADDRNOTAVAIL);

			*in6src = &ia6->ia_addr.sin6_addr;
			return (0);
		}
	}

	/*
	 * If route is known or can be allocated now,
	 * our src addr is taken from the i/f, else punt.
	 */
	if (ro) {
		if (!rtisvalid(ro->ro_rt) || (ro->ro_tableid != rtableid) ||
		    !IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, dst)) {
			rtfree(ro->ro_rt);
			ro->ro_rt = NULL;
		}
		if (ro->ro_rt == NULL) {
			struct sockaddr_in6 *sa6;

			/* No route yet, so try to acquire one */
			bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
			ro->ro_tableid = rtableid;
			sa6 = &ro->ro_dst;
			sa6->sin6_family = AF_INET6;
			sa6->sin6_len = sizeof(struct sockaddr_in6);
			sa6->sin6_addr = *dst;
			sa6->sin6_scope_id = dstsock->sin6_scope_id;
			ro->ro_rt = rtalloc(sin6tosa(&ro->ro_dst),
			    RT_RESOLVE, ro->ro_tableid);
		}

		/*
		 * in_pcbconnect() checks out IFF_LOOPBACK to skip using
		 * the address. But we don't know why it does so.
		 * It is necessary to ensure the scope even for lo0
		 * so doesn't check out IFF_LOOPBACK.
		 */

		if (ro->ro_rt) {
			ifp = if_get(ro->ro_rt->rt_ifidx);
			if (ifp != NULL) {
				ia6 = in6_ifawithscope(ifp, dst, rtableid);
				if_put(ifp);
			}
			if (ia6 == NULL) /* xxx scope error ?*/
				ia6 = ifatoia6(ro->ro_rt->rt_ifa);
		}
		if (ia6 == NULL)
			return (EHOSTUNREACH);	/* no route */

		*in6src = &ia6->ia_addr.sin6_addr;
		return (0);
	}

	return (EADDRNOTAVAIL);
}
示例#9
0
static usbh_baseclassdriver_t *_ftdi_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) {
    int i;
    USBHFTDIDriver *ftdip;

    if (dev->devDesc.idVendor != 0x0403) {
        uerr("FTDI: Unrecognized VID");
        return NULL;
    }

    switch (dev->devDesc.idProduct) {
    case 0x6001:
    case 0x6010:
    case 0x6011:
    case 0x6014:
    case 0x6015:
        break;
    default:
        uerr("FTDI: Unrecognized PID");
        return NULL;
    }

    if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_INTERFACE))
        return NULL;

    const usbh_interface_descriptor_t * const ifdesc = (const usbh_interface_descriptor_t * const)descriptor;
    if (ifdesc->bInterfaceNumber != 0) {
        uwarn("FTDI: Will allocate driver along with IF #0");
    }

    /* alloc driver */
    for (i = 0; i < HAL_USBHFTDI_MAX_INSTANCES; i++) {
        if (USBHFTDID[i].dev == NULL) {
            ftdip = &USBHFTDID[i];
            goto alloc_ok;
        }
    }

    uwarn("FTDI: Can't alloc driver");

    /* can't alloc */
    return NULL;

alloc_ok:
    /* initialize the driver's variables */
    ftdip->ports = 0;
    switch (dev->devDesc.bcdDevice) {
    case 0x200:		//AM
        uinfo("FTDI: Type A chip");
        ftdip->type = USBHFTDI_TYPE_A;
        break;
    case 0x400:		//BM
    case 0x500:		//2232C
    case 0x600:		//R
    case 0x1000:	//230X
        uinfo("FTDI: Type B chip");
        ftdip->type = USBHFTDI_TYPE_B;
        break;
    case 0x700:		//2232H;
    case 0x800:		//4232H;
    case 0x900:		//232H;
        uinfo("FTDI: Type H chip");
        ftdip->type = USBHFTDI_TYPE_H;
    default:
        uerr("FTDI: Unrecognized chip type");
        return NULL;
    }
    usbhEPSetName(&dev->ctrl, "FTD[CTRL]");

    /* parse the configuration descriptor */
    generic_iterator_t iep, icfg;
    if_iterator_t iif;
    cfg_iter_init(&icfg, dev->fullConfigurationDescriptor, dev->basicConfigDesc.wTotalLength);
    for (if_iter_init(&iif, &icfg); iif.valid; if_iter_next(&iif)) {
        const usbh_interface_descriptor_t *const ifdesc = if_get(&iif);
        uinfof("FTDI: Interface #%d", ifdesc->bInterfaceNumber);

        USBHFTDIPortDriver *const prt = _find_port();
        if (prt == NULL) {
            uwarn("\tCan't alloc port for this interface");
            break;
        }

        prt->ifnum = ifdesc->bInterfaceNumber;
        prt->epin.status = USBH_EPSTATUS_UNINITIALIZED;
        prt->epout.status = USBH_EPSTATUS_UNINITIALIZED;

        for (ep_iter_init(&iep, &iif); iep.valid; ep_iter_next(&iep)) {
            const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep);
            if ((epdesc->bEndpointAddress & 0x80) && (epdesc->bmAttributes == USBH_EPTYPE_BULK)) {
                uinfof("BULK IN endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress);
                usbhEPObjectInit(&prt->epin, dev, epdesc);
                usbhEPSetName(&prt->epin, "FTD[BIN ]");
            } else if (((epdesc->bEndpointAddress & 0x80) == 0)
                       && (epdesc->bmAttributes == USBH_EPTYPE_BULK)) {
                uinfof("BULK OUT endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress);
                usbhEPObjectInit(&prt->epout, dev, epdesc);
                usbhEPSetName(&prt->epout, "FTD[BOUT]");
            } else {
                uinfof("unsupported endpoint found: bEndpointAddress=%02x, bmAttributes=%02x",
                       epdesc->bEndpointAddress, epdesc->bmAttributes);
            }
        }

        if ((prt->epin.status != USBH_EPSTATUS_CLOSED)
                || (prt->epout.status != USBH_EPSTATUS_CLOSED)) {
            uwarn("\tCouldn't find endpoints; can't alloc port for this interface");
            continue;
        }

        /* link the new block driver to the list */
        prt->next = ftdip->ports;
        ftdip->ports = prt;
        prt->ftdip = ftdip;

        prt->state = USBHFTDIP_STATE_ACTIVE;
    }

    return (usbh_baseclassdriver_t *)ftdip;

}
示例#10
0
/*
 * Add a mif to the mif table
 */
int
add_m6if(struct mif6ctl *mifcp)
{
	struct mif6 *mifp;
	struct ifnet *ifp;
	struct in6_ifreq ifr;
	int error, s;
#ifdef notyet
	struct tbf *m_tbf = tbftable + mifcp->mif6c_mifi;
#endif

	if (mifcp->mif6c_mifi >= MAXMIFS)
		return EINVAL;
	mifp = mif6table + mifcp->mif6c_mifi;
	if (mifp->m6_ifp)
		return EADDRINUSE; /* XXX: is it appropriate? */
	ifp = if_get(mifcp->mif6c_pifi);
	if (!ifp)
		return ENXIO;

	if (mifcp->mif6c_flags & MIFF_REGISTER) {
		if (reg_mif_num == (mifi_t)-1) {
			strlcpy(multicast_register_if.if_xname,
			    "register_mif",
			    sizeof multicast_register_if.if_xname); /* XXX */
			multicast_register_if.if_flags |= IFF_LOOPBACK;
			multicast_register_if.if_index = mifcp->mif6c_mifi;
			reg_mif_num = mifcp->mif6c_mifi;
		}

		if_put(ifp);
		ifp = if_ref(&multicast_register_if);

	} /* if REGISTER */
	else {
		/* Make sure the interface supports multicast */
		if ((ifp->if_flags & IFF_MULTICAST) == 0) {
			if_put(ifp);
			return EOPNOTSUPP;
		}

		s = splsoftnet();

		/*
		 * Enable promiscuous reception of all IPv6 multicasts
		 * from the interface.
		 */
		memset(&ifr, 0, sizeof(ifr));
		ifr.ifr_addr.sin6_family = AF_INET6;
		ifr.ifr_addr.sin6_addr = in6addr_any;
		error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);

		splx(s);
		if (error) {
			if_put(ifp);
			return error;
		}
	}

	s = splsoftnet();

	mifp->m6_flags     = mifcp->mif6c_flags;
	mifp->m6_ifp       = ifp;
#ifdef notyet
	/* scaling up here allows division by 1024 in critical code */
	mifp->m6_rate_limit = mifcp->mif6c_rate_limit * 1024 / 1000;
#endif
	/* 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;
	splx(s);

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

#ifdef MRT6DEBUG
	if (mrt6debug)
		log(LOG_DEBUG,
		    "add_mif #%d, phyint %s\n",
		    mifcp->mif6c_mifi,
		    ifp->if_xname);
#endif

	if_put(ifp);

	return 0;
}