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); } }
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; }
/* * 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; }
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); } }
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); }
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); }
/* * 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); }
/* * 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; }