X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/9bccf70c0258c7cac2dcb80011b2a964d884c552..4452a7af2eac33dbad800bcc91f2399d62c18f53:/bsd/net/if_stf.c diff --git a/bsd/net/if_stf.c b/bsd/net/if_stf.c index 7bdf6faa5..c9d646ea1 100644 --- a/bsd/net/if_stf.c +++ b/bsd/net/if_stf.c @@ -83,15 +83,12 @@ #include #include #include -#include #include #include #include -#include #include -#include #include #include @@ -118,7 +115,7 @@ struct stf_softc { struct ifnet sc_if; /* common area */ #ifdef __APPLE__ - struct if_proto *stf_proto; /* dlil protocol attached */ + u_long sc_protocol_family; /* dlil protocol attached */ #endif union { struct route __sc_ro4; @@ -131,10 +128,7 @@ struct stf_softc { static struct stf_softc *stf; #ifdef __APPLE__ -void stfattach __P((void)); -int stf_pre_output __P((struct ifnet *, register struct mbuf **, struct sockaddr *, - caddr_t, char *, char *, u_long)); -static u_long stf_dl_tag=0; +void stfattach (void); #endif #ifndef __APPLE__ @@ -142,141 +136,96 @@ static MALLOC_DEFINE(M_STF, "stf", "6to4 Tunnel Interface"); #endif static int ip_stf_ttl = 40; +static void in_stf_input(struct mbuf *, int); extern struct domain inetdomain; struct protosw in_stf_protosw = { SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR, - in_stf_input, rip_output, 0, rip_ctloutput, + in_stf_input, 0, 0, rip_ctloutput, 0, - 0, 0, 0, 0, 0, - &rip_usrreqs + &rip_usrreqs, + 0, rip_unlock, 0 }; -static int stf_encapcheck __P((const struct mbuf *, int, int, void *)); -static struct in6_ifaddr *stf_getsrcifa6 __P((struct ifnet *)); -int stf_pre_output __P((struct ifnet *, register struct mbuf **, struct sockaddr *, - caddr_t, char *, char *, u_long)); -static int stf_checkaddr4 __P((struct stf_softc *, struct in_addr *, - struct ifnet *)); -static int stf_checkaddr6 __P((struct stf_softc *, struct in6_addr *, - struct ifnet *)); -static void stf_rtrequest __P((int, struct rtentry *, struct sockaddr *)); -int stf_ioctl __P((struct ifnet *, u_long, void *)); - +static int stf_encapcheck(const struct mbuf *, int, int, void *); +static struct in6_ifaddr *stf_getsrcifa6(struct ifnet *); +int stf_pre_output(struct ifnet *, u_long, register struct mbuf **, + const struct sockaddr *, caddr_t, char *, char *); +static int stf_checkaddr4(struct stf_softc *, struct in_addr *, + struct ifnet *); +static int stf_checkaddr6(struct stf_softc *, struct in6_addr *, + struct ifnet *); +static void stf_rtrequest(int, struct rtentry *, struct sockaddr *); +int stf_ioctl(struct ifnet *, u_long, void *); static -int stf_add_if(struct ifnet *ifp) -{ - ifp->if_demux = 0; - ifp->if_framer = 0; - return 0; -} - -static -int stf_del_if(struct ifnet *ifp) -{ - return 0; -} - -static -int stf_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long dl_tag) +int stf_add_proto( + struct ifnet *ifp, + u_long protocol_family, + struct ddesc_head_str *desc_head) { /* Only one protocol may be attached at a time */ - struct stf_softc* stf = (struct stf_softc*)proto->ifp; - if (stf->stf_proto == NULL) - stf->stf_proto = proto; + struct stf_softc* stf = (struct stf_softc*)ifp; + if (stf->sc_protocol_family == 0) + stf->sc_protocol_family = protocol_family; else { printf("stf_add_proto: stf already has a proto\n"); - return (EBUSY); + return EBUSY; } - - return (0); + + return 0; } static -int stf_del_proto(struct if_proto *proto, u_long dl_tag) +int stf_del_proto( + struct ifnet *ifp, + u_long protocol_family) { - if (((struct stf_softc*)proto->ifp)->stf_proto == proto) - ((struct stf_softc*)proto->ifp)->stf_proto = NULL; + if (((struct stf_softc*)ifp)->sc_protocol_family == protocol_family) + ((struct stf_softc*)ifp)->sc_protocol_family = 0; else return ENOENT; return 0; } -int stf_shutdown() -{ - return 0; -} - -void stf_reg_if_mods() -{ - struct dlil_ifmod_reg_str stf_ifmod; - - bzero(&stf_ifmod, sizeof(stf_ifmod)); - stf_ifmod.add_if = stf_add_if; - stf_ifmod.del_if = stf_del_if; - stf_ifmod.add_proto = stf_add_proto; - stf_ifmod.del_proto = stf_del_proto; - stf_ifmod.ifmod_ioctl = 0; - stf_ifmod.shutdown = stf_shutdown; - - - if (dlil_reg_if_modules(APPLE_IF_FAM_STF, &stf_ifmod)) - panic("Couldn't register stf modules\n"); - -} - -u_long stf_attach_inet6(struct ifnet *ifp) +static int +stf_attach_inet6(struct ifnet *ifp, u_long protocol_family) { struct dlil_proto_reg_str reg; - struct dlil_demux_desc desc; - short native=0; int stat, i; - if (stf_dl_tag != 0) - return stf_dl_tag; - + bzero(®, sizeof(reg)); TAILQ_INIT(®.demux_desc_head); - desc.type = DLIL_DESC_RAW; - desc.variants.bitmask.proto_id_length = 0; - desc.variants.bitmask.proto_id = 0; - desc.variants.bitmask.proto_id_mask = 0; - desc.native_type = (char *) &native; - TAILQ_INSERT_TAIL(®.demux_desc_head, &desc, next); reg.interface_family = ifp->if_family; reg.unit_number = ifp->if_unit; - reg.input = 0; reg.pre_output = stf_pre_output; - reg.event = 0; - reg.offer = 0; - reg.ioctl = 0; - reg.default_proto = 0; reg.protocol_family = PF_INET6; - stat = dlil_attach_protocol(®, &stf_dl_tag); - if (stat) { - panic("stf_attach_inet6 can't attach interface\n"); - } + stat = dlil_attach_protocol(®); - return stf_dl_tag; + return stat; } -u_long stf_detach_inet6(struct ifnet *ifp) +static int +stf_demux( + struct ifnet *ifp, + struct mbuf *m, + char *frame_ptr, + u_long *protocol_family) { - u_long ip_dl_tag = 0; - int stat; - - stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, AF_INET6, &ip_dl_tag); - if (stat == 0) { - stat = dlil_detach_protocol(ip_dl_tag); - if (stat) { - printf("WARNING: stf_detach can't detach IP AF_INET6 from interface\n"); - } - } - return (stat); + *protocol_family = PF_INET6; + return 0; } +void stf_reg_if_mods() +{ + int error; + + /* Register protocol registration functions */ + if ( error = dlil_reg_proto_module(AF_INET6, APPLE_IF_FAM_STF, stf_attach_inet6, NULL) != 0) + kprintf("dlil_reg_proto_module failed for AF_INET6 error=%d\n", error); +} void stfattach(void) @@ -284,8 +233,6 @@ stfattach(void) struct ifnet *ifp; struct stf_softc *sc; int i, error; - - int err; const struct encaptab *p; @@ -315,6 +262,9 @@ stfattach(void) sc->sc_if.if_output = NULL; /* processing done in pre_output */ sc->sc_if.if_type = IFT_STF; sc->sc_if.if_family= APPLE_IF_FAM_STF; + sc->sc_if.if_add_proto = stf_add_proto; + sc->sc_if.if_del_proto = stf_del_proto; + sc->sc_if.if_demux = stf_demux; #if 0 /* turn off ingress filter */ sc->sc_if.if_flags |= IFF_LINK2; @@ -401,6 +351,7 @@ stf_getsrcifa6(ifp) struct sockaddr_in6 *sin6; struct in_addr in; + ifnet_lock_shared(ifp); for (ia = ifp->if_addrlist.tqh_first; ia; ia = ia->ifa_list.tqe_next) @@ -414,6 +365,7 @@ stf_getsrcifa6(ifp) continue; bcopy(GET_V4(&sin6->sin6_addr), &in, sizeof(in)); + lck_mtx_lock(rt_mtx); for (ia4 = TAILQ_FIRST(&in_ifaddrhead); ia4; ia4 = TAILQ_NEXT(ia4, ia_link)) @@ -421,24 +373,27 @@ stf_getsrcifa6(ifp) if (ia4->ia_addr.sin_addr.s_addr == in.s_addr) break; } + lck_mtx_unlock(rt_mtx); if (ia4 == NULL) continue; + ifnet_lock_done(ifp); return (struct in6_ifaddr *)ia; } + ifnet_lock_done(ifp); return NULL; } int -stf_pre_output(ifp, m0, dst, rt, frame_type, address, dl_tag) - struct ifnet *ifp; - register struct mbuf **m0; - struct sockaddr *dst; - caddr_t rt; - char *frame_type; - char *address; - u_long dl_tag; +stf_pre_output( + struct ifnet *ifp, + u_long protocol_family, + register struct mbuf **m0, + const struct sockaddr *dst, + caddr_t rt, + char *frame_type, + char *address) { register struct mbuf *m = *m0; struct stf_softc *sc; @@ -472,8 +427,10 @@ stf_pre_output(ifp, m0, dst, rt, frame_type, address, dl_tag) if (m->m_len < sizeof(*ip6)) { m = m_pullup(m, sizeof(*ip6)); - if (!m) + if (!m) { + *m0 = NULL; /* makes sure this won't be double freed */ return ENOBUFS; + } } ip6 = mtod(m, struct ip6_hdr *); tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; @@ -498,21 +455,23 @@ stf_pre_output(ifp, m0, dst, rt, frame_type, address, dl_tag) * will only read from the mbuf (i.e., it won't * try to free it or keep a pointer a to it). */ - struct mbuf m0; + struct mbuf m1; u_int32_t af = AF_INET6; - m0.m_next = m; - m0.m_len = 4; - m0.m_data = (char *)⁡ + m1.m_next = m; + m1.m_len = 4; + m1.m_data = (char *)⁡ - bpf_mtap(ifp, &m0); + bpf_mtap(ifp, &m1); } M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); if (m && m->m_len < sizeof(struct ip)) m = m_pullup(m, sizeof(struct ip)); - if (m == NULL) + if (m == NULL) { + *m0 = NULL; return ENOBUFS; + } ip = mtod(m, struct ip *); bzero(ip, sizeof(*ip)); @@ -536,7 +495,7 @@ stf_pre_output(ifp, m0, dst, rt, frame_type, address, dl_tag) dst4->sin_len = sizeof(struct sockaddr_in); bcopy(&ip->ip_dst, &dst4->sin_addr, sizeof(dst4->sin_addr)); if (sc->sc_ro.ro_rt) { - RTFREE(sc->sc_ro.ro_rt); + rtfree(sc->sc_ro.ro_rt); sc->sc_ro.ro_rt = NULL; } } @@ -551,6 +510,9 @@ stf_pre_output(ifp, m0, dst, rt, frame_type, address, dl_tag) error = ip_output(m, NULL, &sc->sc_ro, 0, NULL); if (error == 0) return EJUSTRETURN; + + *m0 = NULL; + return error; } static int @@ -575,15 +537,19 @@ stf_checkaddr4(sc, in, inifp) /* * reject packets with broadcast */ + lck_mtx_lock(rt_mtx); for (ia4 = TAILQ_FIRST(&in_ifaddrhead); ia4; ia4 = TAILQ_NEXT(ia4, ia_link)) { if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) continue; - if (in->s_addr == ia4->ia_broadaddr.sin_addr.s_addr) + if (in->s_addr == ia4->ia_broadaddr.sin_addr.s_addr) { + lck_mtx_unlock(rt_mtx); return -1; + } } + lck_mtx_unlock(rt_mtx); /* * perform ingress filter @@ -637,7 +603,7 @@ stf_checkaddr6(sc, in6, inifp) return 0; } -void +static void in_stf_input(m, off) struct mbuf *m; int off; @@ -646,8 +612,7 @@ in_stf_input(m, off) struct ip *ip; struct ip6_hdr *ip6; u_int8_t otos, itos; - int s, isr, proto; - struct ifqueue *ifq = NULL; + int proto; struct ifnet *ifp; ip = mtod(m, struct ip *); @@ -738,21 +703,11 @@ in_stf_input(m, off) * See net/if_gif.c for possible issues with packet processing * reorder due to extra queueing. */ - ifq = &ip6intrq; - isr = NETISR_IPV6; - - s = splimp(); - if (IF_QFULL(ifq)) { - IF_DROP(ifq); /* update statistics */ - m_freem(m); - splx(s); - return; - } - IF_ENQUEUE(ifq, m); - schednetisr(isr); + proto_input(PF_INET6, m); ifp->if_ipackets++; ifp->if_ibytes += m->m_pkthdr.len; - splx(s); + + return; } /* ARGSUSED */ @@ -788,8 +743,11 @@ stf_ioctl(ifp, cmd, data) } sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; if (IN6_IS_ADDR_6TO4(&sin6->sin6_addr)) { - ifa->ifa_rtrequest = stf_rtrequest; - ifp->if_flags |= IFF_UP; + if ( !(ifnet_flags( ifp ) & IFF_UP) ) { + /* do this only if the interface is not already up */ + ifa->ifa_rtrequest = stf_rtrequest; + ifnet_set_flags(ifp, IFF_UP, IFF_UP); + } } else error = EINVAL; break;