commit 5e0d499760de9db739647a915bdbbc8bd8a12065 Author: Ryota Ozaki Date: Thu May 26 11:27:28 2016 +0900 m_get_rcvif diff --git a/sys/altq/altq_cdnr.c b/sys/altq/altq_cdnr.c index 16db06c..f1b24f7 100644 --- a/sys/altq/altq_cdnr.c +++ b/sys/altq/altq_cdnr.c @@ -139,7 +139,7 @@ altq_cdnr_input(struct mbuf *m, int af) struct cdnr_block *cb; struct cdnr_pktinfo pktinfo; - ifp = m->m_pkthdr.rcvif; + ifp = m_get_rcvif_NOMPSAFE(m); if (!ALTQ_IS_CNDTNING(&ifp->if_snd)) /* traffic conditioner is not enabled on this interface */ return (1); diff --git a/sys/dev/pci/if_lmc.c b/sys/dev/pci/if_lmc.c index 9a4a707..89cf558 100644 --- a/sys/dev/pci/if_lmc.c +++ b/sys/dev/pci/if_lmc.c @@ -4279,7 +4279,7 @@ rxintr_cleanup(softc_t *sc) MGETHDR(new_mbuf, M_DONTWAIT, MT_DATA); if (new_mbuf) { - m_set_rcvif(new_mbuf, first_mbuf->m_pkthdr.rcvif); + m_copy_rcvif(new_mbuf, first_mbuf); new_mbuf->m_pkthdr.len = first_mbuf->m_pkthdr.len; new_mbuf->m_len = first_mbuf->m_len; memcpy(new_mbuf->m_data, first_mbuf->m_data, diff --git a/sys/dist/pf/net/if_pfsync.c b/sys/dist/pf/net/if_pfsync.c index 931624c..a32f800 100644 --- a/sys/dist/pf/net/if_pfsync.c +++ b/sys/dist/pf/net/if_pfsync.c @@ -374,7 +374,7 @@ pfsync_input(struct mbuf *m, ...) goto done; /* verify that the packet came in on the right interface */ - if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) { + if (sc->sc_sync_ifp->if_index != m->m_pkthdr.rcvif_index) { PFSYNC_STATINC(PFSYNC_STAT_BADIF); goto done; } diff --git a/sys/external/bsd/ipf/netinet/ip_compat.h b/sys/external/bsd/ipf/netinet/ip_compat.h index a983fb5..293e51e 100644 --- a/sys/external/bsd/ipf/netinet/ip_compat.h +++ b/sys/external/bsd/ipf/netinet/ip_compat.h @@ -1952,8 +1952,7 @@ MALLOC_DECLARE(M_IPFILTER); if (_o->m_flags & M_PKTHDR) { \ (m)->m_pkthdr.len += \ _o->m_pkthdr.len; \ - m_set_rcvif((m), \ - _o->m_pkthdr.rcvif); \ + m_copy_rcvif((m), _o); \ } \ } while (0) # endif diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c index 7333854..c58c2af 100644 --- a/sys/kern/uipc_mbuf.c +++ b/sys/kern/uipc_mbuf.c @@ -1171,7 +1171,7 @@ m_split0(struct mbuf *m0, int len0, int wait, int copyhdr) if (n == NULL) return NULL; MCLAIM(n, m0->m_owner); - m_set_rcvif(n, m0->m_pkthdr.rcvif); + m_copy_rcvif(n, m0); n->m_pkthdr.len = m0->m_pkthdr.len - len0; len_save = m0->m_pkthdr.len; m0->m_pkthdr.len = len0; @@ -1783,7 +1783,7 @@ nextchain: snprintb(buf, sizeof(buf), M_CSUM_BITS, m->m_pkthdr.csum_flags); (*pr)(" pktlen=%d, rcvif=%p, csum_flags=0x%s, csum_data=0x%" PRIx32 ", segsz=%u\n", - m->m_pkthdr.len, m->m_pkthdr.rcvif, + m->m_pkthdr.len, m_get_rcvif_NOMPSAFE(m), buf, m->m_pkthdr.csum_data, m->m_pkthdr.segsz); } if ((m->m_flags & M_EXT)) { diff --git a/sys/net/bpf.c b/sys/net/bpf.c index 3745713..19e8098 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -1469,7 +1469,7 @@ _bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m) struct mbuf mb; /* Skip outgoing duplicate packets. */ - if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { + if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif_index == 0) { m->m_flags &= ~M_PROMISC; return; } @@ -1486,7 +1486,7 @@ _bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m) mb.m_data = data; mb.m_len = dlen; - bpf_deliver(bp, bpf_mcpy, &mb, pktlen, 0, m->m_pkthdr.rcvif != NULL); + bpf_deliver(bp, bpf_mcpy, &mb, pktlen, 0, m->m_pkthdr.rcvif_index != 0); } /* @@ -1500,7 +1500,7 @@ _bpf_mtap(struct bpf_if *bp, struct mbuf *m) void *marg; /* Skip outgoing duplicate packets. */ - if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { + if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif_index == 0) { m->m_flags &= ~M_PROMISC; return; } @@ -1517,7 +1517,7 @@ _bpf_mtap(struct bpf_if *bp, struct mbuf *m) buflen = 0; } - bpf_deliver(bp, cpfn, marg, pktlen, buflen, m->m_pkthdr.rcvif != NULL); + bpf_deliver(bp, cpfn, marg, pktlen, buflen, m->m_pkthdr.rcvif_index != 0); } /* diff --git a/sys/net/if.c b/sys/net/if.c index 7a9b313..0fdf26f 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1245,7 +1245,7 @@ if_detach_queues(struct ifnet *ifp, struct ifqueue *q) KASSERT((m->m_flags & M_PKTHDR) != 0); next = m->m_nextpkt; - if (m->m_pkthdr.rcvif != ifp) { + if (m->m_pkthdr.rcvif_index != ifp->if_index) { prev = m; continue; } @@ -2223,6 +2223,26 @@ if_get_byindex(u_int idx, struct psref *psref) return ifp; } +/* + * XXX unsafe + */ +void +if_acquire_unsafe(struct ifnet *ifp, struct psref *psref) +{ + + KASSERT(ifp->if_index != 0); + KASSERT(if_byindex(ifp->if_index) != NULL); + psref_acquire(psref, &ifp->if_psref, ifnet_psref_class); +} + +bool +if_held(struct ifnet *ifp) +{ + + return psref_held(&ifp->if_psref, ifnet_psref_class); +} + + /* common */ int ifioctl_common(struct ifnet *ifp, u_long cmd, void *data) diff --git a/sys/net/if.h b/sys/net/if.h index d35316a..dfa3233 100644 --- a/sys/net/if.h +++ b/sys/net/if.h @@ -890,17 +890,21 @@ int ifaddrpref_ioctl(struct socket *, u_long, void *, struct ifnet *); extern int (*ifioctl)(struct socket *, u_long, void *, struct lwp *); int ifioctl_common(struct ifnet *, u_long, void *); int ifpromisc(struct ifnet *, int); -struct ifnet *ifunit(const char *); -struct ifnet *if_get(const char *, struct psref *); -ifnet_t *if_byindex(u_int); -ifnet_t *if_get_byindex(u_int, struct psref *); -void if_put(const struct ifnet *, struct psref *); int if_addr_init(ifnet_t *, struct ifaddr *, bool); int if_do_dad(struct ifnet *); int if_mcast_op(ifnet_t *, const unsigned long, const struct sockaddr *); int if_flags_set(struct ifnet *, const short); int if_clone_list(int, char *, int *); +struct ifnet *ifunit(const char *); +struct ifnet *if_get(const char *, struct psref *); +ifnet_t *if_byindex(u_int); +ifnet_t *if_get_byindex(u_int, struct psref *); +void if_put(const struct ifnet *, struct psref *); +void if_acquire_unsafe(struct ifnet *, struct psref *); + +bool if_held(struct ifnet *); + void if_input(struct ifnet *, struct mbuf *); struct if_percpuq * diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 7a621a5d..b057ade 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -1610,12 +1610,18 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m) struct ifnet *src_if, *dst_if; struct ether_header *eh; struct psref psref; + struct psref psref_src; DECLARE_LOCK_VARIABLE; if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) return; - src_if = m->m_pkthdr.rcvif; + src_if = m_get_rcvif_psref(m, &psref_src); + if (src_if == NULL) { + /* Interface is being destroyed? */ + m_freem(m); + goto out; + } sc->sc_if.if_ipackets++; sc->sc_if.if_ibytes += m->m_pkthdr.len; @@ -1690,8 +1696,7 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m) dst_if = NULL; } - if (pfil_run_hooks(sc->sc_if.if_pfil, &m, - m->m_pkthdr.rcvif, PFIL_IN) != 0) { + if (pfil_run_hooks(sc->sc_if.if_pfil, &m, src_if, PFIL_IN) != 0) { if (m != NULL) m_freem(m); goto out; @@ -1704,6 +1709,9 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m) goto out; } + m_put_rcvif_psref(src_if, &psref_src); + src_if = NULL; + /* * At this point, we're dealing with a unicast frame * going to a different interface. @@ -1736,7 +1744,8 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m) bridge_enqueue(sc, dst_if, m, 1); RELEASE_GLOBAL_LOCKS(); out: - /* XXX gcc */ + if (src_if != NULL) + m_put_rcvif_psref(src_if, &psref_src); return; } @@ -2642,7 +2651,7 @@ bridge_ip_checkbasic(struct mbuf **mp) } switch (m->m_pkthdr.csum_flags & - ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_IPv4) | + ((m_get_rcvif_NOMPSAFE(m)->if_csum_flags_rx & M_CSUM_IPv4) | M_CSUM_IPv4_BAD)) { case M_CSUM_IPv4|M_CSUM_IPv4_BAD: /* INET_CSUM_COUNTER_INCR(&ip_hwcsum_bad); */ @@ -2710,7 +2719,7 @@ bridge_ip6_checkbasic(struct mbuf **mp) * IPv6 header is in the first mbuf of the chain. */ if (IP6_HDR_ALIGNED_P(mtod(m, void *)) == 0) { - struct ifnet *inifp = m->m_pkthdr.rcvif; + struct ifnet *inifp = m_get_rcvif_NOMPSAFE(m); if ((m = m_copyup(m, sizeof(struct ip6_hdr), (max_linkhdr + 3) & ~3)) == NULL) { /* XXXJRT new stat, please */ @@ -2719,7 +2728,7 @@ bridge_ip6_checkbasic(struct mbuf **mp) goto bad; } } else if (__predict_false(m->m_len < sizeof(struct ip6_hdr))) { - struct ifnet *inifp = m->m_pkthdr.rcvif; + struct ifnet *inifp = m_get_rcvif_NOMPSAFE(m); if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { ip6_statinc(IP6_STAT_TOOSMALL); in6_ifstat_inc(inifp, ifs6_in_hdrerr); @@ -2731,7 +2740,7 @@ bridge_ip6_checkbasic(struct mbuf **mp) if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { ip6_statinc(IP6_STAT_BADVERS); - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); + in6_ifstat_inc(m_get_rcvif_NOMPSAFE(m), ifs6_in_hdrerr); goto bad; } diff --git a/sys/net/if_mpls.c b/sys/net/if_mpls.c index 47d2a1e..3d1dc75 100644 --- a/sys/net/if_mpls.c +++ b/sys/net/if_mpls.c @@ -188,13 +188,13 @@ mplsintr(void) return; if (((m->m_flags & M_PKTHDR) == 0) || - (m->m_pkthdr.rcvif == 0)) + (m->m_pkthdr.rcvif_index == 0)) panic("mplsintr(): no pkthdr or rcvif"); #ifdef MBUFTRACE m_claimm(m, &mpls_owner); #endif - mpls_input(m->m_pkthdr.rcvif, m); + mpls_input(m_get_rcvif_NOMPSAFE(m), m); } } diff --git a/sys/net/if_pppoe.c b/sys/net/if_pppoe.c index 31e943b..73a0b4c 100644 --- a/sys/net/if_pppoe.c +++ b/sys/net/if_pppoe.c @@ -495,7 +495,9 @@ pppoe_dispatch_disc_pkt(struct mbuf *m, int off) } } break; /* ignored */ - case PPPOE_TAG_HUNIQUE: + case PPPOE_TAG_HUNIQUE: { + struct ifnet *rcvif; + int s; if (sc != NULL) break; n = m_pulldown(m, off + sizeof(*pt), len, &noff); @@ -508,11 +510,14 @@ pppoe_dispatch_disc_pkt(struct mbuf *m, int off) hunique = mtod(n, uint8_t *) + noff; hunique_len = len; #endif + rcvif = m_get_rcvif(m, &s); sc = pppoe_find_softc_by_hunique(mtod(n, char *) + noff, - len, m->m_pkthdr.rcvif); + len, rcvif); + m_put_rcvif(rcvif, &s); if (sc != NULL) devname = sc->sc_sppp.pp_if.if_xname; break; + } case PPPOE_TAG_ACCOOKIE: if (ac_cookie == NULL) { n = m_pulldown(m, off + sizeof(*pt), len, @@ -623,7 +628,7 @@ breakbreak:; } sc = pppoe_find_softc_by_hunique(ac_cookie, ac_cookie_len, - m->m_pkthdr.rcvif); + m_get_rcvif_NOMPSAFE(m)); if (sc == NULL) { /* be quiet if there is not a single pppoe instance */ if (!LIST_EMPTY(&pppoe_softc_list)) @@ -718,12 +723,18 @@ breakbreak:; sc->sc_state = PPPOE_STATE_SESSION; sc->sc_sppp.pp_up(&sc->sc_sppp); /* notify upper layers */ break; - case PPPOE_CODE_PADT: - sc = pppoe_find_softc_by_session(session, m->m_pkthdr.rcvif); + case PPPOE_CODE_PADT: { + struct ifnet *rcvif; + int s; + + rcvif = m_get_rcvif(m, &s); + sc = pppoe_find_softc_by_session(session, rcvif); + m_put_rcvif(rcvif, &s); if (sc == NULL) goto done; pppoe_clear_softc(sc, "received PADT"); break; + } default: printf("%s: unknown code (0x%04x) session = 0x%04x\n", sc? sc->sc_sppp.pp_if.if_xname : "pppoe", @@ -755,6 +766,8 @@ pppoe_data_input(struct mbuf *m) uint16_t session, plen; struct pppoe_softc *sc; struct pppoehdr *ph; + struct ifnet *rcvif; + struct psref psref; #ifdef PPPOE_TERM_UNKNOWN_SESSIONS uint8_t shost[ETHER_ADDR_LEN]; #endif @@ -789,15 +802,18 @@ pppoe_data_input(struct mbuf *m) goto drop; session = ntohs(ph->session); - sc = pppoe_find_softc_by_session(session, m->m_pkthdr.rcvif); + rcvif = m_get_rcvif_psref(m, &psref); + sc = pppoe_find_softc_by_session(session, rcvif); if (sc == NULL) { #ifdef PPPOE_TERM_UNKNOWN_SESSIONS printf("pppoe: input for unknown session 0x%x, sending PADT\n", session); - pppoe_send_padt(m->m_pkthdr.rcvif, session, shost); + pppoe_send_padt(rcvif, session, shost); #endif + m_put_rcvif_psref(rcvif, &psref); goto drop; } + m_put_rcvif_psref(rcvif, &psref); plen = ntohs(ph->plen); diff --git a/sys/net/if_stf.c b/sys/net/if_stf.c index bf02eff..bc55cd5 100644 --- a/sys/net/if_stf.c +++ b/sys/net/if_stf.c @@ -584,7 +584,7 @@ in_stf_input(struct mbuf *m, int off, int proto) * for source, perform ingress filter as well. */ if (stf_checkaddr4(sc, &ip->ip_dst, NULL) < 0 || - stf_checkaddr4(sc, &ip->ip_src, m->m_pkthdr.rcvif) < 0) { + stf_checkaddr4(sc, &ip->ip_src, m_get_rcvif_NOMPSAFE(m)) < 0) { m_freem(m); return; } @@ -604,7 +604,7 @@ in_stf_input(struct mbuf *m, int off, int proto) * for source, perform ingress filter as well. */ if (stf_checkaddr6(sc, &ip6->ip6_dst, NULL) < 0 || - stf_checkaddr6(sc, &ip6->ip6_src, m->m_pkthdr.rcvif) < 0) { + stf_checkaddr6(sc, &ip6->ip6_src, m_get_rcvif_NOMPSAFE(m)) < 0) { m_freem(m); return; } diff --git a/sys/netatalk/ddp_input.c b/sys/netatalk/ddp_input.c index da6e8e7..a4e87c7 100644 --- a/sys/netatalk/ddp_input.c +++ b/sys/netatalk/ddp_input.c @@ -79,7 +79,7 @@ atintr(void) break; m_claimm(m, &atalk_rx_mowner); - ifp = m->m_pkthdr.rcvif; + ifp = m_get_rcvif_NOMPSAFE(m); for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { if (aa->aa_ifp == ifp && (aa->aa_flags & AFA_PHASE2)) break; @@ -103,7 +103,7 @@ atintr(void) break; m_claimm(m, &atalk_rx_mowner); - ifp = m->m_pkthdr.rcvif; + ifp = m_get_rcvif_NOMPSAFE(m); for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { if (aa->aa_ifp == ifp && (aa->aa_flags & AFA_PHASE2) == 0) diff --git a/sys/netinet/if_arp.c b/sys/netinet/if_arp.c index a1f1952..6d3d4b1 100644 --- a/sys/netinet/if_arp.c +++ b/sys/netinet/if_arp.c @@ -890,6 +890,8 @@ arpintr(void) mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); while (arpintrq.ifq_head) { + struct ifnet *rcvif; + s = splnet(); IF_DEQUEUE(&arpintrq, m); splx(s); @@ -906,7 +908,8 @@ arpintr(void) (ar = mtod(m, struct arphdr *)) == NULL) goto badlen; - switch (m->m_pkthdr.rcvif->if_type) { + rcvif = m_get_rcvif(m, &s); + switch (rcvif->if_type) { case IFT_IEEE1394: arplen = sizeof(struct arphdr) + ar->ar_hln + 2 * ar->ar_pln; @@ -916,6 +919,7 @@ arpintr(void) 2 * ar->ar_hln + 2 * ar->ar_pln; break; } + m_put_rcvif(rcvif, &s); if (/* XXX ntohs(ar->ar_hrd) == ARPHRD_ETHER && */ m->m_len >= arplen) @@ -955,7 +959,7 @@ static void in_arpinput(struct mbuf *m) { struct arphdr *ah; - struct ifnet *ifp = m->m_pkthdr.rcvif; + struct ifnet *ifp, *rcvif = NULL; struct llentry *la = NULL; struct in_ifaddr *ia; #if NBRIDGE > 0 @@ -969,12 +973,14 @@ in_arpinput(struct mbuf *m) int op; void *tha; uint64_t *arps; + struct psref psref; if (__predict_false(m_makewritable(&m, 0, m->m_pkthdr.len, M_DONTWAIT))) goto out; ah = mtod(m, struct arphdr *); op = ntohs(ah->ar_op); + rcvif = ifp = m_get_rcvif_psref(m, &psref); /* * Fix up ah->ar_hrd if necessary, before using ar_tha() or * ar_tpa(). @@ -1014,14 +1020,14 @@ in_arpinput(struct mbuf *m) ((ia->ia_ifp->if_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING))) { index++; - if (ia->ia_ifp == m->m_pkthdr.rcvif && + if (ia->ia_ifp == rcvif && carp_iamatch(ia, ar_sha(ah), &count, index)) { break; } } else #endif - if (ia->ia_ifp == m->m_pkthdr.rcvif) + if (ia->ia_ifp == rcvif) break; #if NBRIDGE > 0 /* @@ -1031,8 +1037,8 @@ in_arpinput(struct mbuf *m) * layer. Note we still prefer a perfect match, * but allow this weaker match if necessary. */ - if (m->m_pkthdr.rcvif->if_bridge != NULL && - m->m_pkthdr.rcvif->if_bridge == ia->ia_ifp->if_bridge) + if (rcvif->if_bridge != NULL && + rcvif->if_bridge == ia->ia_ifp->if_bridge) bridge_ia = ia; #endif /* NBRIDGE > 0 */ @@ -1042,13 +1048,16 @@ in_arpinput(struct mbuf *m) #if NBRIDGE > 0 if (ia == NULL && bridge_ia != NULL) { ia = bridge_ia; + m_put_rcvif_psref(rcvif, &psref); + rcvif = NULL; + /* FIXME */ ifp = bridge_ia->ia_ifp; } #endif if (ia == NULL) { INADDR_TO_IA(isaddr, ia); - while ((ia != NULL) && ia->ia_ifp != m->m_pkthdr.rcvif) + while ((ia != NULL) && ia->ia_ifp != rcvif) NEXT_IA_WITH_SAME_ADDR(ia); if (ia == NULL) { @@ -1272,11 +1281,12 @@ reply: /* Proxy ARP */ struct llentry *lle = NULL; struct sockaddr_in sin; - #if NCARP > 0 - if (ifp->if_type == IFT_CARP && - m->m_pkthdr.rcvif->if_type != IFT_CARP) + int s; + struct ifnet *_rcvif = m_get_rcvif(m, &s); + if (ifp->if_type == IFT_CARP && _rcvif->if_type != IFT_CARP) goto out; + m_put_rcvif(_rcvif, &s); #endif tha = ar_tha(ah); @@ -1325,12 +1335,16 @@ reply: arps[ARP_STAT_SNDREPLY]++; ARP_STAT_PUTREF(); (*ifp->if_output)(ifp, m, &sa, NULL); + if (rcvif != NULL) + m_put_rcvif_psref(rcvif, &psref); return; out: if (la != NULL) LLE_WUNLOCK(la); drop: + if (rcvif != NULL) + m_put_rcvif_psref(rcvif, &psref); m_freem(m); } @@ -1784,15 +1798,17 @@ out: void in_revarpinput(struct mbuf *m) { - struct ifnet *ifp; struct arphdr *ah; void *tha; int op; + struct ifnet *rcvif; + int s; ah = mtod(m, struct arphdr *); op = ntohs(ah->ar_op); - switch (m->m_pkthdr.rcvif->if_type) { + rcvif = m_get_rcvif(m, &s); + switch (rcvif->if_type) { case IFT_IEEE1394: /* ARP without target hardware address is not supported */ goto out; @@ -1803,6 +1819,7 @@ in_revarpinput(struct mbuf *m) switch (op) { case ARPOP_REQUEST: case ARPOP_REPLY: /* per RFC */ + m_put_rcvif(rcvif, &s); in_arpinput(m); return; case ARPOP_REVREPLY: @@ -1813,15 +1830,14 @@ in_revarpinput(struct mbuf *m) } if (!revarp_in_progress) goto out; - ifp = m->m_pkthdr.rcvif; - if (ifp != myip_ifp) /* !same interface */ + if (rcvif != myip_ifp) /* !same interface */ goto out; if (myip_initialized) goto wake; tha = ar_tha(ah); if (tha == NULL) goto out; - if (memcmp(tha, CLLADDR(ifp->if_sadl), ifp->if_sadl->sdl_alen)) + if (memcmp(tha, CLLADDR(rcvif->if_sadl), rcvif->if_sadl->sdl_alen)) goto out; memcpy(&srv_ip, ar_spa(ah), sizeof(srv_ip)); memcpy(&myip, ar_tpa(ah), sizeof(myip)); @@ -1830,6 +1846,7 @@ wake: /* Do wakeup every time in case it was missed. */ wakeup((void *)&myip); out: + m_put_rcvif(rcvif, &s); m_freem(m); } diff --git a/sys/netinet/igmp.c b/sys/netinet/igmp.c index 81ab67f..e63cae2 100644 --- a/sys/netinet/igmp.c +++ b/sys/netinet/igmp.c @@ -184,7 +184,7 @@ igmp_init(void) void igmp_input(struct mbuf *m, ...) { - ifnet_t *ifp = m->m_pkthdr.rcvif; + ifnet_t *ifp; struct ip *ip = mtod(m, struct ip *); struct igmp *igmp; u_int minlen, timer; @@ -192,6 +192,7 @@ igmp_input(struct mbuf *m, ...) struct in_ifaddr *ia; int proto, ip_len, iphlen; va_list ap; + struct psref psref; va_start(ap, m); iphlen = va_arg(ap, int); @@ -234,6 +235,7 @@ igmp_input(struct mbuf *m, ...) m->m_data -= iphlen; m->m_len += iphlen; + ifp = m_get_rcvif_psref(m, &psref); switch (igmp->igmp_type) { case IGMP_HOST_MEMBERSHIP_QUERY: @@ -248,8 +250,7 @@ igmp_input(struct mbuf *m, ...) if (ip->ip_dst.s_addr != INADDR_ALLHOSTS_GROUP) { IGMP_STATINC(IGMP_STAT_RCV_BADQUERIES); - m_freem(m); - return; + goto drop; } in_multi_lock(RW_WRITER); @@ -286,8 +287,7 @@ igmp_input(struct mbuf *m, ...) if (!IN_MULTICAST(ip->ip_dst.s_addr)) { IGMP_STATINC(IGMP_STAT_RCV_BADQUERIES); - m_freem(m); - return; + goto drop; } timer = igmp->igmp_code * PR_FASTHZ / IGMP_TIMER_SCALE; @@ -345,8 +345,7 @@ igmp_input(struct mbuf *m, ...) if (!IN_MULTICAST(igmp->igmp_group.s_addr) || !in_hosteq(igmp->igmp_group, ip->ip_dst)) { IGMP_STATINC(IGMP_STAT_RCV_BADREPORTS); - m_freem(m); - return; + goto drop; } /* @@ -412,8 +411,7 @@ igmp_input(struct mbuf *m, ...) if (!IN_MULTICAST(igmp->igmp_group.s_addr) || !in_hosteq(igmp->igmp_group, ip->ip_dst)) { IGMP_STATINC(IGMP_STAT_RCV_BADREPORTS); - m_freem(m); - return; + goto drop; } /* @@ -458,6 +456,7 @@ igmp_input(struct mbuf *m, ...) break; } + m_put_rcvif_psref(ifp, &psref); /* * Pass all valid IGMP packets up to any process(es) listening @@ -465,6 +464,11 @@ igmp_input(struct mbuf *m, ...) */ rip_input(m, iphlen, proto); return; + +drop: + m_put_rcvif_psref(ifp, &psref); + m_freem(m); + return; } int diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c index 35f6116..1e4c1a5 100644 --- a/sys/netinet/in_gif.c +++ b/sys/netinet/in_gif.c @@ -199,6 +199,8 @@ in_gif_input(struct mbuf *m, int off, int proto) const struct ip *ip; int af; u_int8_t otos; + struct ifnet *rcvif; + struct psref psref; ip = mtod(m, const struct ip *); @@ -218,11 +220,14 @@ in_gif_input(struct mbuf *m, int off, int proto) return; } - if (!gif_validate4(ip, sc, m->m_pkthdr.rcvif)) { + rcvif = m_get_rcvif_psref(m, &psref); + if (!gif_validate4(ip, sc, rcvif)) { + m_put_rcvif_psref(rcvif, &psref); m_freem(m); ip_statinc(IP_STAT_NOGIF); return; } + m_put_rcvif_psref(rcvif, &psref); #endif otos = ip->ip_tos; m_adj(m, off); @@ -349,7 +354,7 @@ gif_encapcheck4(struct mbuf *m, int off, int proto, void *arg) sc = arg; m_copydata(m, 0, sizeof(ip), &ip); - ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; + ifp = ((m->m_flags & M_PKTHDR) != 0) ? m_get_rcvif_NOMPSAFE(m) : NULL; return gif_validate4(&ip, sc, ifp); } diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index d4b9ebe..20e5034 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -475,6 +475,7 @@ carp_proto_input(struct mbuf *m, ...) struct carp_header *ch; int iplen, len; va_list ap; + struct ifnet *rcvif; va_start(ap, m); va_end(ap); @@ -487,11 +488,12 @@ carp_proto_input(struct mbuf *m, ...) return; } + rcvif = m_get_rcvif_NOMPSAFE(m); /* check if received on a valid carp interface */ - if (m->m_pkthdr.rcvif->if_type != IFT_CARP) { + if (rcvif->if_type != IFT_CARP) { CARP_STATINC(CARP_STAT_BADIF); CARP_LOG(sc, ("packet received on non-carp interface: %s", - m->m_pkthdr.rcvif->if_xname)); + rcvif->if_xname)); m_freem(m); return; } @@ -500,7 +502,7 @@ carp_proto_input(struct mbuf *m, ...) if (ip->ip_ttl != CARP_DFLTTL) { CARP_STATINC(CARP_STAT_BADTTL); CARP_LOG(sc, ("received ttl %d != %d on %s", ip->ip_ttl, - CARP_DFLTTL, m->m_pkthdr.rcvif->if_xname)); + CARP_DFLTTL, rcvif->if_xname)); m_freem(m); return; } @@ -514,7 +516,7 @@ carp_proto_input(struct mbuf *m, ...) if (len > m->m_pkthdr.len) { CARP_STATINC(CARP_STAT_BADLEN); CARP_LOG(sc, ("packet too short %d on %s", m->m_pkthdr.len, - m->m_pkthdr.rcvif->if_xname)); + rcvif->if_xname)); m_freem(m); return; } @@ -530,7 +532,7 @@ carp_proto_input(struct mbuf *m, ...) if (carp_cksum(m, len - iplen)) { CARP_STATINC(CARP_STAT_BADSUM); CARP_LOG(sc, ("checksum failed on %s", - m->m_pkthdr.rcvif->if_xname)); + rcvif->if_xname)); m_freem(m); return; } @@ -548,6 +550,7 @@ carp6_proto_input(struct mbuf **mp, int *offp, int proto) struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); struct carp_header *ch; u_int len; + struct ifnet *rcvif; CARP_STATINC(CARP_STAT_IPACKETS6); MCLAIM(m, &carp_proto6_mowner_rx); @@ -557,11 +560,13 @@ carp6_proto_input(struct mbuf **mp, int *offp, int proto) return (IPPROTO_DONE); } + rcvif = m_get_rcvif_NOMPSAFE(m); + /* check if received on a valid carp interface */ - if (m->m_pkthdr.rcvif->if_type != IFT_CARP) { + if (rcvif->if_type != IFT_CARP) { CARP_STATINC(CARP_STAT_BADIF); CARP_LOG(sc, ("packet received on non-carp interface: %s", - m->m_pkthdr.rcvif->if_xname)); + rcvif->if_xname)); m_freem(m); return (IPPROTO_DONE); } @@ -570,7 +575,7 @@ carp6_proto_input(struct mbuf **mp, int *offp, int proto) if (ip6->ip6_hlim != CARP_DFLTTL) { CARP_STATINC(CARP_STAT_BADTTL); CARP_LOG(sc, ("received ttl %d != %d on %s", ip6->ip6_hlim, - CARP_DFLTTL, m->m_pkthdr.rcvif->if_xname)); + CARP_DFLTTL, rcvif->if_xname)); m_freem(m); return (IPPROTO_DONE); } @@ -589,8 +594,7 @@ carp6_proto_input(struct mbuf **mp, int *offp, int proto) m->m_data += *offp; if (carp_cksum(m, sizeof(*ch))) { CARP_STATINC(CARP_STAT_BADSUM); - CARP_LOG(sc, ("checksum failed, on %s", - m->m_pkthdr.rcvif->if_xname)); + CARP_LOG(sc, ("checksum failed, on %s", rcvif->if_xname)); m_freem(m); return (IPPROTO_DONE); } @@ -609,7 +613,7 @@ carp_proto_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af) struct timeval sc_tv, ch_tv; TAILQ_FOREACH(sc, &((struct carp_if *) - m->m_pkthdr.rcvif->if_carpdev->if_carp)->vhif_vrs, sc_list) + m_get_rcvif_NOMPSAFE(m)->if_carpdev->if_carp)->vhif_vrs, sc_list) if (sc->sc_vhid == ch->carp_vhid) break; @@ -1387,7 +1391,7 @@ int carp_input(struct mbuf *m, u_int8_t *shost, u_int8_t *dhost, u_int16_t etype) { struct ether_header eh; - struct carp_if *cif = (struct carp_if *)m->m_pkthdr.rcvif->if_carp; + struct carp_if *cif = (struct carp_if *)m_get_rcvif_NOMPSAFE(m)->if_carp; struct ifnet *ifp; memcpy(&eh.ether_shost, shost, sizeof(eh.ether_shost)); @@ -1412,7 +1416,7 @@ carp_input(struct mbuf *m, u_int8_t *shost, u_int8_t *dhost, u_int16_t etype) return (1); } - ifp = carp_ourether(cif, &eh, m->m_pkthdr.rcvif->if_type, 0); + ifp = carp_ourether(cif, &eh, m_get_rcvif_NOMPSAFE(m)->if_type, 0); if (ifp == NULL) { return (1); } diff --git a/sys/netinet/ip_flow.c b/sys/netinet/ip_flow.c index 9d827cc..37dad52 100644 --- a/sys/netinet/ip_flow.c +++ b/sys/netinet/ip_flow.c @@ -177,6 +177,8 @@ ipflow_fastforward(struct mbuf *m) const struct sockaddr *dst; int error; int iplen; + struct ifnet *ifp; + int s; /* * Are we forwarding packets? Big enough for an IP packet? @@ -210,14 +212,16 @@ ipflow_fastforward(struct mbuf *m) if ((ipf = ipflow_lookup(ip)) == NULL) return 0; + ifp = m_get_rcvif(m, &s); /* * Verify the IP header checksum. */ switch (m->m_pkthdr.csum_flags & - ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_IPv4) | + ((ifp->if_csum_flags_rx & M_CSUM_IPv4) | M_CSUM_IPv4_BAD)) { case M_CSUM_IPv4|M_CSUM_IPv4_BAD: - return (0); + m_put_rcvif(ifp, &s); + return 0; case M_CSUM_IPv4: /* Checksum was okay. */ @@ -225,10 +229,13 @@ ipflow_fastforward(struct mbuf *m) default: /* Must compute it ourselves. */ - if (in_cksum(m, sizeof(struct ip)) != 0) - return (0); + if (in_cksum(m, sizeof(struct ip)) != 0) { + m_put_rcvif(ifp, &s); + return 0; + } break; } + m_put_rcvif(ifp, &s); /* * Route and interface still up? diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index b523aed..7604ee0 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -339,7 +339,7 @@ icmp_error(struct mbuf *n, int type, int code, n_long dest, m->m_data -= sizeof(struct ip); m->m_len += sizeof(struct ip); m->m_pkthdr.len = m->m_len; - m_set_rcvif(m, n->m_pkthdr.rcvif); + m_copy_rcvif(m, n); nip = mtod(m, struct ip *); /* ip_v set in ip_output */ nip->ip_hl = sizeof(struct ip) >> 2; @@ -560,7 +560,10 @@ icmp_input(struct mbuf *m, ...) icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ goto reflect; - case ICMP_MASKREQ: + case ICMP_MASKREQ: { + struct ifnet *rcvif; + int s; + if (icmpmaskrepl == 0) break; /* @@ -576,8 +579,10 @@ icmp_input(struct mbuf *m, ...) icmpdst.sin_addr = ip->ip_src; else icmpdst.sin_addr = ip->ip_dst; + rcvif = m_get_rcvif(m, &s); ia = ifatoia(ifaof_ifpforaddr(sintosa(&icmpdst), - m->m_pkthdr.rcvif)); + rcvif)); + m_put_rcvif(rcvif, &s); if (ia == 0) break; icp->icmp_type = ICMP_MASKREPLY; @@ -597,6 +602,7 @@ reflect: } icmp_reflect(m); return; + } case ICMP_REDIRECT: if (code > 3) @@ -686,6 +692,8 @@ icmp_reflect(struct mbuf *m) struct in_addr t; struct mbuf *opts = NULL; int optlen = (ip->ip_hl << 2) - sizeof(struct ip); + struct ifnet *rcvif; + struct psref psref; if (!in_canforward(ip->ip_src) && ((ip->ip_src.s_addr & IN_CLASSA_NET) != @@ -708,10 +716,12 @@ icmp_reflect(struct mbuf *m) if (ia && (ia->ia4_flags & IN_IFF_NOTREADY)) ia = NULL; + rcvif = m_get_rcvif_psref(m, &psref); + /* look for packet sent to broadcast address */ - if (ia == NULL && m->m_pkthdr.rcvif && - (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST)) { - IFADDR_FOREACH(ifa, m->m_pkthdr.rcvif) { + if (ia == NULL && rcvif && + (rcvif->if_flags & IFF_BROADCAST)) { + IFADDR_FOREACH(ifa, rcvif) { if (ifa->ifa_addr->sa_family != AF_INET) continue; if (in_hosteq(t,ifatoia(ifa)->ia_broadaddr.sin_addr)) { @@ -733,7 +743,7 @@ icmp_reflect(struct mbuf *m) * use that, if it's an address on the interface which * received the packet */ - if (sin == NULL && m->m_pkthdr.rcvif) { + if (sin == NULL && rcvif) { struct sockaddr_in sin_dst; struct route icmproute; int errornum; @@ -750,7 +760,7 @@ icmp_reflect(struct mbuf *m) sin = NULL; INADDR_TO_IA(t, ia); while (ia) { - if (ia->ia_ifp == m->m_pkthdr.rcvif) { + if (ia->ia_ifp == rcvif) { sin = &ia->ia_addr; break; } @@ -765,8 +775,8 @@ icmp_reflect(struct mbuf *m) * interface. This can happen when routing is asymmetric, or * when the incoming packet was encapsulated */ - if (sin == NULL && m->m_pkthdr.rcvif) { - IFADDR_FOREACH(ifa, m->m_pkthdr.rcvif) { + if (sin == NULL && rcvif) { + IFADDR_FOREACH(ifa, rcvif) { if (ifa->ifa_addr->sa_family != AF_INET) continue; sin = &(ifatoia(ifa)->ia_addr); @@ -774,6 +784,8 @@ icmp_reflect(struct mbuf *m) } } + m_put_rcvif_psref(rcvif, &psref); + /* * The following happens if the packet was not addressed to us, * and was received on an interface with no IP address: diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index dda6ef2..002cf9b 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -284,7 +284,7 @@ struct mowner ip_tx_mowner = MOWNER_INIT("internet", "tx"); static void ipintr(void *); static void ip_input(struct mbuf *); -static void ip_forward(struct mbuf *, int); +static void ip_forward(struct mbuf *, int, struct ifnet *); static bool ip_dooptions(struct mbuf *); static struct in_ifaddr *ip_rtaddr(struct in_addr); static void sysctl_net_inet_ip_setup(struct sysctllog **); @@ -374,13 +374,15 @@ ip_input(struct mbuf *m) int checkif; int srcrt = 0; ifnet_t *ifp; + struct psref psref; KASSERTMSG(cpu_softintr_p(), "ip_input: not in the software " "interrupt handler; synchronization assumptions violated"); MCLAIM(m, &ip_rx_mowner); KASSERT((m->m_flags & M_PKTHDR) != 0); - ifp = m->m_pkthdr.rcvif; + + ifp = m_get_rcvif_psref(m, &psref); /* * If no IP addresses have been set yet but the interfaces @@ -403,12 +405,12 @@ ip_input(struct mbuf *m) (max_linkhdr + 3) & ~3)) == NULL) { /* XXXJRT new stat, please */ IP_STATINC(IP_STAT_TOOSMALL); - return; + goto out; } } else if (__predict_false(m->m_len < sizeof (struct ip))) { if ((m = m_pullup(m, sizeof (struct ip))) == NULL) { IP_STATINC(IP_STAT_TOOSMALL); - return; + goto out; } } ip = mtod(m, struct ip *); @@ -424,7 +426,7 @@ ip_input(struct mbuf *m) if (hlen > m->m_len) { if ((m = m_pullup(m, hlen)) == NULL) { IP_STATINC(IP_STAT_BADHLEN); - return; + goto out; } ip = mtod(m, struct ip *); } @@ -528,7 +530,7 @@ ip_input(struct mbuf *m) freed = pfil_run_hooks(inet_pfil_hook, &m, ifp, PFIL_IN) != 0; SOFTNET_UNLOCK(); if (freed || m == NULL) { - return; + goto out; } ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; @@ -557,7 +559,7 @@ ip_input(struct mbuf *m) if ((*altq_input)(m, AF_INET) == 0) { /* Packet dropped by traffic conditioner. */ SOFTNET_UNLOCK(); - return; + goto out; } SOFTNET_UNLOCK(); } @@ -571,7 +573,7 @@ ip_input(struct mbuf *m) */ ip_nhops = 0; /* for source routed packets */ if (hlen > sizeof (struct ip) && ip_dooptions(m)) - return; + goto out; /* * Enable a consistency check between the destination address @@ -659,8 +661,7 @@ ip_input(struct mbuf *m) if (ip_mforward(m, ifp) != 0) { SOFTNET_UNLOCK(); IP_STATINC(IP_STAT_CANTFORWARD); - m_freem(m); - return; + goto bad; } SOFTNET_UNLOCK(); @@ -681,8 +682,7 @@ ip_input(struct mbuf *m) */ if (!in_multi_group(ip->ip_dst, ifp, 0)) { IP_STATINC(IP_STAT_CANTFORWARD); - m_freem(m); - return; + goto bad; } goto ours; } @@ -694,6 +694,7 @@ ip_input(struct mbuf *m) * Not for us; forward if possible and desirable. */ if (ipforwarding == 0) { + m_put_rcvif_psref(ifp, &psref); IP_STATINC(IP_STAT_CANTFORWARD); m_freem(m); } else { @@ -704,6 +705,7 @@ ip_input(struct mbuf *m) * forwarding loop till TTL goes to 0. */ if (downmatch) { + m_put_rcvif_psref(ifp, &psref); icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); IP_STATINC(IP_STAT_CANTFORWARD); return; @@ -720,11 +722,14 @@ ip_input(struct mbuf *m) SOFTNET_UNLOCK(); } #endif - ip_forward(m, srcrt); + ip_forward(m, srcrt, ifp); + m_put_rcvif_psref(ifp, &psref); } return; ours: + m_put_rcvif_psref(ifp, &psref); + /* * If offset or IP_MF are set, must reassemble. */ @@ -781,12 +786,17 @@ ours: SOFTNET_UNLOCK(); return; bad: + m_put_rcvif_psref(ifp, &psref); m_freem(m); return; badcsum: + m_put_rcvif_psref(ifp, &psref); IP_STATINC(IP_STAT_BADSUM); m_freem(m); + return; +out: + m_put_rcvif_psref(ifp, &psref); } /* @@ -988,7 +998,10 @@ ip_dooptions(struct mbuf *m) case IPOPT_TS_TSONLY: break; - case IPOPT_TS_TSANDADDR: + case IPOPT_TS_TSANDADDR: { + struct ifnet *rcvif; + int s; + if (ipt->ipt_ptr - 1 + sizeof(n_time) + sizeof(struct in_addr) > ipt->ipt_len) { code = (u_char *)&ipt->ipt_ptr - @@ -996,14 +1009,17 @@ ip_dooptions(struct mbuf *m) goto bad; } ipaddr.sin_addr = dst; + rcvif = m_get_rcvif(m, &s); ia = ifatoia(ifaof_ifpforaddr(sintosa(&ipaddr), - m->m_pkthdr.rcvif)); + rcvif)); + m_put_rcvif(rcvif, &s); if (ia == 0) continue; bcopy(&ia->ia_addr.sin_addr, cp0, sizeof(struct in_addr)); ipt->ipt_ptr += sizeof(struct in_addr); break; + } case IPOPT_TS_PRESPEC: if (ipt->ipt_ptr - 1 + sizeof(n_time) + @@ -1034,12 +1050,18 @@ ip_dooptions(struct mbuf *m) } } if (forward) { + struct ifnet *rcvif; + struct psref psref; + if (ip_forwsrcrt == 0) { type = ICMP_UNREACH; code = ICMP_UNREACH_SRCFAIL; goto bad; } - ip_forward(m, 1); + + rcvif = m_get_rcvif_psref(m, &psref); + ip_forward(m, 1, rcvif); + m_put_rcvif_psref(rcvif, &psref); return true; } return false; @@ -1186,7 +1208,7 @@ ip_drainstub(void) * via a source route. */ static void -ip_forward(struct mbuf *m, int srcrt) +ip_forward(struct mbuf *m, int srcrt, struct ifnet *rcvif) { struct ip *ip = mtod(m, struct ip *); struct rtentry *rt; @@ -1254,7 +1276,7 @@ ip_forward(struct mbuf *m, int srcrt) * Also, don't send redirect if forwarding using a default route * or a route modified by a redirect. */ - if (rt->rt_ifp == m->m_pkthdr.rcvif && + if (rt->rt_ifp == rcvif && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && !in_nullhost(satocsin(rt_getkey(rt))->sin_addr) && ipsendredirects && !srcrt) { @@ -1360,9 +1382,11 @@ ip_savecontrol(struct inpcb *inp, struct mbuf **mp, struct ip *ip, struct mbuf *m) { struct socket *so = inp->inp_socket; - ifnet_t *ifp = m->m_pkthdr.rcvif; + ifnet_t *ifp; int inpflags = inp->inp_flags; + struct psref psref; + ifp = m_get_rcvif_psref(m, &psref); if (so->so_options & SO_TIMESTAMP #ifdef SO_OTIMESTAMP || so->so_options & SO_OTIMESTAMP @@ -1423,6 +1447,7 @@ ip_savecontrol(struct inpcb *inp, struct mbuf **mp, struct ip *ip, if (*mp) mp = &(*mp)->m_next; } + m_put_rcvif_psref(ifp, &psref); } /* diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index f25294f..5c3b5d0 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -4121,7 +4121,7 @@ sctp_input(struct mbuf *m, ...) sctp_pegs[SCTP_IN_MCAST]++; goto bad; } - if (in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { + if (in_broadcast(ip->ip_dst, m_get_rcvif_NOMPSAFE(m))) { sctp_pegs[SCTP_IN_MCAST]++; goto bad; } @@ -4134,8 +4134,8 @@ sctp_input(struct mbuf *m, ...) /* validate SCTP checksum */ if ((sctp_no_csum_on_loopback == 0) || - (m->m_pkthdr.rcvif == NULL) || - (m->m_pkthdr.rcvif->if_type != IFT_LOOP)) { + (m_get_rcvif_NOMPSAFE(m) == NULL) || + (m_get_rcvif_NOMPSAFE(m)->if_type != IFT_LOOP)) { /* we do NOT validate things from the loopback if the * sysctl is set to 1. */ diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 127d378..e183349 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3470,7 +3470,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, /* pull out the scope_id from incoming pkt */ #if defined(SCTP_BASE_FREEBSD) || defined(__APPLE__) (void)in6_recoverscope(sin6, &in6_src, - init_pkt->m_pkthdr.rcvif); + m_get_rcvif_NOMPSAFE(init_pkt)); in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL); #else @@ -8104,9 +8104,8 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh) mout->m_pkthdr.len = mout->m_len; /* add checksum */ - if ((sctp_no_csum_on_loopback) && - (m->m_pkthdr.rcvif) && - (m->m_pkthdr.rcvif->if_type == IFT_LOOP)) { + if ((sctp_no_csum_on_loopback) && m_get_rcvif_NOMPSAFE(m) != NULL && + m_get_rcvif_NOMPSAFE(m)->if_type == IFT_LOOP) { comp_cp->sh.checksum = 0; } else { comp_cp->sh.checksum = sctp_calculate_sum(mout, NULL, offset_out); @@ -9046,9 +9045,8 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, } /* add checksum */ - if ((sctp_no_csum_on_loopback) && - (m->m_pkthdr.rcvif) && - (m->m_pkthdr.rcvif->if_type == IFT_LOOP)) { + if ((sctp_no_csum_on_loopback) && m_get_rcvif_NOMPSAFE(m) != NULL && + m_get_rcvif_NOMPSAFE(m)->if_type == IFT_LOOP) { abm->sh.checksum = 0; } else { abm->sh.checksum = sctp_calculate_sum(mout, NULL, iphlen_out); @@ -9130,9 +9128,8 @@ sctp_send_operr_to(struct mbuf *m, int iphlen, padlen = 4 - (scm->m_pkthdr.len % 4); m_copyback(scm, scm->m_pkthdr.len, padlen, (void *)&cpthis); } - if ((sctp_no_csum_on_loopback) && - (m->m_pkthdr.rcvif) && - (m->m_pkthdr.rcvif->if_type == IFT_LOOP)) { + if ((sctp_no_csum_on_loopback) && m_get_rcvif_NOMPSAFE(m) != NULL && + m_get_rcvif_NOMPSAFE(m)->if_type == IFT_LOOP) { val = 0; } else { val = sctp_calculate_sum(scm, NULL, 0); diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index da1635d..686b81b 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -894,17 +894,21 @@ int tcp_input_checksum(int af, struct mbuf *m, const struct tcphdr *th, int toff, int off, int tlen) { + struct ifnet *rcvif; + int s; /* * XXX it's better to record and check if this mbuf is * already checked. */ + rcvif = m_get_rcvif(m, &s); + switch (af) { #ifdef INET case AF_INET: switch (m->m_pkthdr.csum_flags & - ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_TCPv4) | + ((rcvif->if_csum_flags_rx & M_CSUM_TCPv4) | M_CSUM_TCP_UDP_BAD | M_CSUM_DATA)) { case M_CSUM_TCPv4|M_CSUM_TCP_UDP_BAD: TCP_CSUM_COUNTER_INCR(&tcp_hwcsum_bad); @@ -937,8 +941,7 @@ tcp_input_checksum(int af, struct mbuf *m, const struct tcphdr *th, * Must compute it ourselves. Maybe skip checksum * on loopback interfaces. */ - if (__predict_true(!(m->m_pkthdr.rcvif->if_flags & - IFF_LOOPBACK) || + if (__predict_true(!(rcvif->if_flags & IFF_LOOPBACK) || tcp_do_loopback_cksum)) { TCP_CSUM_COUNTER_INCR(&tcp_swcsum); if (in4_cksum(m, IPPROTO_TCP, toff, @@ -953,7 +956,7 @@ tcp_input_checksum(int af, struct mbuf *m, const struct tcphdr *th, #ifdef INET6 case AF_INET6: switch (m->m_pkthdr.csum_flags & - ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_TCPv6) | + ((rcvif->if_csum_flags_rx & M_CSUM_TCPv6) | M_CSUM_TCP_UDP_BAD | M_CSUM_DATA)) { case M_CSUM_TCPv6|M_CSUM_TCP_UDP_BAD: TCP_CSUM_COUNTER_INCR(&tcp6_hwcsum_bad); @@ -984,10 +987,12 @@ tcp_input_checksum(int af, struct mbuf *m, const struct tcphdr *th, break; #endif /* INET6 */ } + m_put_rcvif(rcvif, &s); return 0; badcsum: + m_put_rcvif(rcvif, &s); TCP_STATINC(TCP_STAT_RCVBADSUM); return -1; } @@ -1548,7 +1553,8 @@ findpcb: case AF_INET: mc = (IN_MULTICAST(ip->ip_dst.s_addr) - || in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)); + || in_broadcast(ip->ip_dst, + m_get_rcvif_NOMPSAFE(m))); break; } @@ -1747,7 +1753,8 @@ findpcb: #endif /* INET6 */ case AF_INET: if (IN_MULTICAST(ip->ip_dst.s_addr) || - in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) + in_broadcast(ip->ip_dst, + m_get_rcvif_NOMPSAFE(m))) goto drop; break; } @@ -1790,12 +1797,18 @@ findpcb: */ if (af == AF_INET6 && !ip6_use_deprecated) { struct in6_ifaddr *ia6; - if ((ia6 = in6ifa_ifpwithaddr(m->m_pkthdr.rcvif, + int s; + struct ifnet *rcvif = m_get_rcvif(m, &s); + if (rcvif == NULL) + goto dropwithreset; /* XXX */ + if ((ia6 = in6ifa_ifpwithaddr(rcvif, &ip6->ip6_dst)) && (ia6->ia6_flags & IN6_IFF_DEPRECATED)) { tp = NULL; + m_put_rcvif(rcvif, &s); goto dropwithreset; } + m_put_rcvif(rcvif, &s); } #endif @@ -3081,7 +3094,7 @@ dropwithreset: #endif /* INET6 */ case AF_INET: if (IN_MULTICAST(ip->ip_dst.s_addr) || - in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) + in_broadcast(ip->ip_dst, m_get_rcvif_NOMPSAFE(m))) goto drop; } @@ -4417,7 +4430,7 @@ syn_cache_add(struct sockaddr *src, struct sockaddr *dst, struct tcphdr *th, } sc->sc_peermaxseg = oi->maxseg; sc->sc_ourmaxseg = tcp_mss_to_advertise(m->m_flags & M_PKTHDR ? - m->m_pkthdr.rcvif : NULL, + m_get_rcvif_NOMPSAFE(m) : NULL, sc->sc_src.sa.sa_family); sc->sc_win = win; sc->sc_timebase = tcp_now - 1; /* see tcp_newtcpcb() */ diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 350f309..75baff2 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -276,7 +276,7 @@ udp4_input_checksum(struct mbuf *m, const struct udphdr *uh, return 0; switch (m->m_pkthdr.csum_flags & - ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_UDPv4) | + ((m_get_rcvif_NOMPSAFE(m)->if_csum_flags_rx & M_CSUM_UDPv4) | M_CSUM_TCP_UDP_BAD | M_CSUM_DATA)) { case M_CSUM_UDPv4|M_CSUM_TCP_UDP_BAD: UDP_CSUM_COUNTER_INCR(&udp_hwcsum_bad); @@ -309,7 +309,7 @@ udp4_input_checksum(struct mbuf *m, const struct udphdr *uh, * Need to compute it ourselves. Maybe skip checksum * on loopback interfaces. */ - if (__predict_true(!(m->m_pkthdr.rcvif->if_flags & + if (__predict_true(!(m_get_rcvif_NOMPSAFE(m)->if_flags & IFF_LOOPBACK) || udp_do_loopback_cksum)) { UDP_CSUM_COUNTER_INCR(&udp_swcsum); @@ -529,7 +529,7 @@ udp4_realinput(struct sockaddr_in *src, struct sockaddr_in *dst, dport = &dst->sin_port; if (IN_MULTICAST(dst4->s_addr) || - in_broadcast(*dst4, m->m_pkthdr.rcvif)) { + in_broadcast(*dst4, m_get_rcvif_NOMPSAFE(m))) { /* * Deliver a multicast or broadcast datagram to *all* sockets * for which the local and remote addresses and ports match diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 5cb9a2d..174cb14 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -453,8 +453,10 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) int off = *offp; int icmp6len = m->m_pkthdr.len - *offp; int code, sum, noff, i; - struct ifnet *rcvif = m->m_pkthdr.rcvif; + struct ifnet *rcvif; + struct psref psref; + rcvif = m_get_rcvif_psref(m, &psref); #define ICMP6_MAXLEN (sizeof(*nip6) + sizeof(*nicmp6) + 4) KASSERT(ICMP6_MAXLEN < MCLBYTES); icmp6_ifstat_inc(rcvif, ifs6_in_msg); @@ -484,6 +486,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) */ IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6)); if (icmp6 == NULL) { + m_put_rcvif_psref(rcvif, &psref); ICMP6_STATINC(ICMP6_STAT_TOOSHORT); /* m is invalid */ /*icmp6_ifstat_inc(rcvif, ifs6_in_error);*/ @@ -865,6 +868,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) deliver: if (icmp6_notify_error(m, off, icmp6len, code)) { /* In this case, m should've been freed. */ + m_put_rcvif_psref(rcvif, &psref); return (IPPROTO_DONE); } break; @@ -877,6 +881,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) ICMP6_STATINC(ICMP6_STAT_BADLEN); break; } + m_put_rcvif_psref(rcvif, &psref); /* deliver the packet to appropriate sockets */ icmp6_rip6_input(&m, *offp); @@ -884,6 +889,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) return IPPROTO_DONE; freeit: + m_put_rcvif_psref(rcvif, &psref); m_freem(m); return IPPROTO_DONE; } @@ -921,6 +927,8 @@ icmp6_notify_error(struct mbuf *m, int off, int icmp6len, int code) struct ip6_rthdr *rth; struct ip6_rthdr0 *rth0; int rthlen; + struct ifnet *rcvif; + int s; while (1) { /* XXX: should avoid infinite loop explicitly? */ struct ip6_ext *eh; @@ -1034,13 +1042,20 @@ icmp6_notify_error(struct mbuf *m, int off, int icmp6len, int code) */ eip6 = (struct ip6_hdr *)(icmp6 + 1); + rcvif = m_get_rcvif(m, &s); sockaddr_in6_init(&icmp6dst, (finaldst == NULL) ? &eip6->ip6_dst : finaldst, 0, 0, 0); - if (in6_setscope(&icmp6dst.sin6_addr, m->m_pkthdr.rcvif, NULL)) + if (in6_setscope(&icmp6dst.sin6_addr, rcvif, NULL)) { + m_put_rcvif(rcvif, &s); goto freeit; + } sockaddr_in6_init(&icmp6src, &eip6->ip6_src, 0, 0, 0); - if (in6_setscope(&icmp6src.sin6_addr, m->m_pkthdr.rcvif, NULL)) + if (in6_setscope(&icmp6src.sin6_addr, rcvif, NULL)) { + m_put_rcvif(rcvif, &s); goto freeit; + } + m_put_rcvif(rcvif, &s); + icmp6src.sin6_flowinfo = (eip6->ip6_flow & IPV6_FLOWLABEL_MASK); @@ -1084,6 +1099,8 @@ icmp6_mtudisc_update(struct ip6ctlparam *ip6cp, int validated) u_int mtu = ntohl(icmp6->icmp6_mtu); struct rtentry *rt = NULL; struct sockaddr_in6 sin6; + struct ifnet *rcvif; + int s; /* * The MTU should not be less than the minimal IPv6 MTU except for the @@ -1122,8 +1139,13 @@ icmp6_mtudisc_update(struct ip6ctlparam *ip6cp, int validated) sin6.sin6_family = PF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_addr = *dst; - if (in6_setscope(&sin6.sin6_addr, m->m_pkthdr.rcvif, NULL)) + s = pserialize_read_enter(); + rcvif = m_get_rcvif(m, &s); + if (in6_setscope(&sin6.sin6_addr, rcvif, NULL)) { + m_put_rcvif(rcvif, &s); return; + } + m_put_rcvif(rcvif, &s); rt = icmp6_mtudisc_clone((struct sockaddr *)&sin6); @@ -1175,6 +1197,8 @@ ni6_input(struct mbuf *m, int off) struct ip6_hdr *ip6; int oldfqdn = 0; /* if 1, return pascal string (03 draft) */ char *subj = NULL; + int s; + struct ifnet *rcvif; ip6 = mtod(m, struct ip6_hdr *); IP6_EXTHDR_GET(ni6, struct icmp6_nodeinfo *, m, off, sizeof(*ni6)); @@ -1252,8 +1276,12 @@ ni6_input(struct mbuf *m, int off) /* m_pulldown instead of copy? */ m_copydata(m, off + sizeof(struct icmp6_nodeinfo), subjlen, (void *)&in6_subj); - if (in6_setscope(&in6_subj, m->m_pkthdr.rcvif, NULL)) + rcvif = m_get_rcvif(m, &s); + if (in6_setscope(&in6_subj, rcvif, NULL)) { + m_put_rcvif(rcvif, &s); goto bad; + } + m_put_rcvif(rcvif, &s); subj = (char *)&in6_subj; if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &in6_subj)) @@ -1961,6 +1989,8 @@ icmp6_reflect(struct mbuf *m, size_t off) struct ifnet *outif = NULL; struct in6_addr origdst; const struct in6_addr *src = NULL; + struct ifnet *rcvif; + int s; /* too short to reflect */ if (off < sizeof(struct ip6_hdr)) { @@ -2077,11 +2107,13 @@ icmp6_reflect(struct mbuf *m, size_t off) ip6->ip6_vfc &= ~IPV6_VERSION_MASK; ip6->ip6_vfc |= IPV6_VERSION; ip6->ip6_nxt = IPPROTO_ICMPV6; - if (m->m_pkthdr.rcvif) { + rcvif = m_get_rcvif(m, &s); + if (rcvif) { /* XXX: This may not be the outgoing interface */ - ip6->ip6_hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim; + ip6->ip6_hlim = ND_IFINFO(rcvif)->chlim; } else ip6->ip6_hlim = ip6_defhlim; + m_put_rcvif(rcvif, &s); m->m_pkthdr.csum_flags = 0; icmp6->icmp6_cksum = 0; @@ -2100,10 +2132,9 @@ icmp6_reflect(struct mbuf *m, size_t off) * Note that only echo and node information replies are affected, * since the length of ICMP6 errors is limited to the minimum MTU. */ - if (ip6_output(m, NULL, NULL, IPV6_MINMTU, NULL, NULL, &outif) != 0 && - outif) + if (ip6_output(m, NULL, NULL, IPV6_MINMTU, NULL, NULL, &outif) + != 0 && outif) icmp6_ifstat_inc(outif, ifs6_out_error); - if (outif) icmp6_ifoutstat_inc(outif, type, code); @@ -2127,7 +2158,7 @@ icmp6_redirect_diag(struct in6_addr *src6, struct in6_addr *dst6, void icmp6_redirect_input(struct mbuf *m, int off) { - struct ifnet *ifp = m->m_pkthdr.rcvif; + struct ifnet *ifp; struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); struct nd_redirect *nd_rd; int icmp6len = ntohs(ip6->ip6_plen); @@ -2140,7 +2171,9 @@ icmp6_redirect_input(struct mbuf *m, int off) struct in6_addr redtgt6; struct in6_addr reddst6; union nd_opts ndopts; + struct psref psref; + ifp = m_get_rcvif_psref(m, &psref); if (ifp == NULL) goto freeit; @@ -2153,6 +2186,7 @@ icmp6_redirect_input(struct mbuf *m, int off) IP6_EXTHDR_GET(nd_rd, struct nd_redirect *, m, off, icmp6len); if (nd_rd == NULL) { ICMP6_STATINC(ICMP6_STAT_TOOSHORT); + m_put_rcvif_psref(ifp, &psref); return; } redtgt6 = nd_rd->nd_rd_target; @@ -2260,6 +2294,9 @@ icmp6_redirect_input(struct mbuf *m, int off) nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT, is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER); + m_put_rcvif_psref(ifp, &psref); + ifp = NULL; + if (!is_onlink) { /* better router case. perform rtredirect. */ /* perform rtredirect */ struct sockaddr_in6 sdst; @@ -2319,10 +2356,13 @@ icmp6_redirect_input(struct mbuf *m, int off) } freeit: + if (ifp != NULL) + m_put_rcvif_psref(ifp, &psref); m_freem(m); return; bad: + m_put_rcvif_psref(ifp, &psref); ICMP6_STATINC(ICMP6_STAT_BADREDIRECT); m_freem(m); } diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c index ecf6d02..6778593 100644 --- a/sys/netinet6/in6_gif.c +++ b/sys/netinet6/in6_gif.c @@ -229,11 +229,15 @@ in6_gif_input(struct mbuf **mp, int *offp, int proto) return IPPROTO_DONE; } - if (!gif_validate6(ip6, sc, m->m_pkthdr.rcvif)) { + struct psref psref; + struct ifnet *rcvif = m_get_rcvif_psref(m, &psref); + if (!gif_validate6(ip6, sc, rcvif)) { + m_put_rcvif_psref(rcvif, &psref); m_freem(m); IP6_STATINC(IP6_STAT_NOGIF); return IPPROTO_DONE; } + m_put_rcvif_psref(rcvif, &psref); #endif otos = ip6->ip6_flow; @@ -350,7 +354,7 @@ gif_encapcheck6(struct mbuf *m, int off, int proto, void *arg) sc = arg; m_copydata(m, 0, sizeof(ip6), (void *)&ip6); - ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; + ifp = ((m->m_flags & M_PKTHDR) != 0) ? m_get_rcvif_NOMPSAFE(m) : NULL; return gif_validate6(&ip6, sc, ifp); } diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index 59969cc..01d0ec8 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -133,6 +133,8 @@ ip6_forward(struct mbuf *m, int srcrt) struct ifnet *origifp; /* maybe unnecessary */ uint32_t inzone, outzone; struct in6_addr src_in6, dst_in6; + struct ifnet *rcvif = NULL; + struct psref psref; #ifdef IPSEC int needipsec = 0; struct secpolicy *sp = NULL; @@ -143,6 +145,7 @@ ip6_forward(struct mbuf *m, int srcrt) */ m->m_pkthdr.csum_flags = 0; + rcvif = m_get_rcvif_psref(m, &psref); /* * Do not forward packets to multicast destination (should be handled * by ip6_mforward(). @@ -152,19 +155,18 @@ ip6_forward(struct mbuf *m, int srcrt) if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 || IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { - ip6_cantforward(ip6, m->m_pkthdr.rcvif, NULL, + ip6_cantforward(ip6, rcvif, NULL, ((m->m_flags & (M_BCAST|M_MCAST)) != 0) ? "bcast/mcast" : IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ? "mcast/dst" : "unspec/src"); - m_freem(m); - return; + goto drop; } if (ip6->ip6_hlim <= IPV6_HLIMDEC) { /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */ icmp6_error(m, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT, 0); - return; + goto out; } ip6->ip6_hlim -= IPV6_HLIMDEC; @@ -212,8 +214,7 @@ ip6_forward(struct mbuf *m, int srcrt) icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE, 0); } - m_freem(m); - return; + goto drop; } } else if ((rt = rtcache_validate(&ip6_forward_rt)) == NULL && (rt = rtcache_update(&ip6_forward_rt, 1)) == NULL) { @@ -227,8 +228,7 @@ ip6_forward(struct mbuf *m, int srcrt) icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE, 0); } - m_freem(m); - return; + goto drop; } dst = satocsin6(rtcache_getdst(&ip6_forward_rt)); @@ -244,16 +244,15 @@ ip6_forward(struct mbuf *m, int srcrt) src_in6 = ip6->ip6_src; inzone = outzone = ~0; if (in6_setscope(&src_in6, rt->rt_ifp, &outzone) != 0 || - in6_setscope(&src_in6, m->m_pkthdr.rcvif, &inzone) != 0 || + in6_setscope(&src_in6, rcvif, &inzone) != 0 || inzone != outzone) { - ip6_cantforward(ip6, m->m_pkthdr.rcvif, rt->rt_ifp, + ip6_cantforward(ip6, rcvif, rt->rt_ifp, "src[%s] inzone %d outzone %d", in6_getscopename(&ip6->ip6_src), inzone, outzone); if (mcopy) icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE, 0); - m_freem(m); - return; + goto drop; } #ifdef IPSEC @@ -279,17 +278,16 @@ ip6_forward(struct mbuf *m, int srcrt) */ dst_in6 = ip6->ip6_dst; inzone = outzone = ~0; - if (in6_setscope(&dst_in6, m->m_pkthdr.rcvif, &inzone) != 0 || + if (in6_setscope(&dst_in6, rcvif, &inzone) != 0 || in6_setscope(&dst_in6, rt->rt_ifp, &outzone) != 0 || inzone != outzone) { - ip6_cantforward(ip6, m->m_pkthdr.rcvif, rt->rt_ifp, + ip6_cantforward(ip6, rcvif, rt->rt_ifp, "dst[%s] inzone %d outzone %d", in6_getscopename(&ip6->ip6_dst), inzone, outzone); if (mcopy) icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE, 0); - m_freem(m); - return; + goto drop; } if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) { @@ -300,8 +298,7 @@ ip6_forward(struct mbuf *m, int srcrt) mtu = IN6_LINKMTU(rt->rt_ifp); icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu); } - m_freem(m); - return; + goto drop; } if (rt->rt_flags & RTF_GATEWAY) @@ -316,7 +313,7 @@ ip6_forward(struct mbuf *m, int srcrt) * Also, don't send redirect if forwarding using a route * modified by a redirect. */ - if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt && ip6_sendredirects && + if (rt->rt_ifp == rcvif && !srcrt && ip6_sendredirects && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) { if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) && nd6_is_addr_neighbor( @@ -339,8 +336,7 @@ ip6_forward(struct mbuf *m, int srcrt) */ icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, 0); - m_freem(m); - return; + goto drop; } type = ND_REDIRECT; } @@ -373,12 +369,12 @@ ip6_forward(struct mbuf *m, int srcrt) "src %s, dst %s, nxt %d, rcvif %s, outif %s\n", ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst), - ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif), + ip6->ip6_nxt, if_name(rcvif), if_name(rt->rt_ifp)); } /* we can just use rcvif in forwarding. */ - origifp = m->m_pkthdr.rcvif; + origifp = rcvif; } else origifp = rt->rt_ifp; @@ -420,12 +416,12 @@ ip6_forward(struct mbuf *m, int srcrt) senderr: if (mcopy == NULL) - return; + goto out; switch (error) { case 0: if (type == ND_REDIRECT) { icmp6_redirect_output(mcopy, rt); - return; + goto out; } goto freecopy; @@ -447,9 +443,15 @@ ip6_forward(struct mbuf *m, int srcrt) break; } icmp6_error(mcopy, type, code, 0); - return; + goto out; freecopy: m_freem(mcopy); + goto out; + drop: + m_freem(m); + out: + if (rcvif != NULL) + m_put_rcvif_psref(rcvif, &psref); return; } diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 2db2806..6246dd2 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -217,16 +217,23 @@ ip6intr(void *arg __unused) mutex_enter(softnet_lock); while ((m = pktq_dequeue(ip6_pktq)) != NULL) { - const ifnet_t *ifp = m->m_pkthdr.rcvif; + struct psref psref; + struct ifnet *rcvif = m_get_rcvif_psref(m, &psref); + if (rcvif == NULL) { + m_freem(m); + continue; + } /* * Drop the packet if IPv6 is disabled on the interface. */ - if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { + if ((ND_IFINFO(rcvif)->flags & ND6_IFF_IFDISABLED)) { + m_put_rcvif_psref(rcvif, &psref); m_freem(m); continue; } - ip6_input(m); + ip6_input(m, rcvif); + m_put_rcvif_psref(rcvif, &psref); } mutex_exit(softnet_lock); } @@ -234,7 +241,7 @@ ip6intr(void *arg __unused) extern struct route ip6_forward_rt; void -ip6_input(struct mbuf *m) +ip6_input(struct mbuf *m, struct ifnet *rcvif) { struct ip6_hdr *ip6; int hit, off = sizeof(struct ip6_hdr), nest; @@ -248,7 +255,6 @@ ip6_input(struct mbuf *m) struct sockaddr dst; struct sockaddr_in6 dst6; } u; - struct ifnet *rcvif = m->m_pkthdr.rcvif; /* * make sure we don't have onion peering information into m_tag. @@ -1058,8 +1064,7 @@ ip6_savecontrol(struct in6pcb *in6p, struct mbuf **mp, memcpy(&pi6.ipi6_addr, &ip6->ip6_dst, sizeof(struct in6_addr)); in6_clearscope(&pi6.ipi6_addr); /* XXX */ - pi6.ipi6_ifindex = m->m_pkthdr.rcvif ? - m->m_pkthdr.rcvif->if_index : 0; + pi6.ipi6_ifindex = m->m_pkthdr.rcvif_index; *mp = sbcreatecontrol((void *) &pi6, sizeof(struct in6_pktinfo), IS2292(IPV6_2292PKTINFO, IPV6_PKTINFO), IPPROTO_IPV6); diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c index 1d1a389..5909181 100644 --- a/sys/netinet6/ip6_mroute.c +++ b/sys/netinet6/ip6_mroute.c @@ -1080,8 +1080,8 @@ ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m) ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst), ip6->ip6_nxt, - m->m_pkthdr.rcvif ? - if_name(m->m_pkthdr.rcvif) : "?"); + m->m_pkthdr.rcvif_index ? + if_name(m_get_rcvif_NOMPSAFE(m)) : "?"); } return 0; } @@ -1473,7 +1473,7 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt) } /* if wrong iif */ /* If I sourced this packet, it counts as output, else it was input. */ - if (m->m_pkthdr.rcvif == NULL) { + if (m->m_pkthdr.rcvif_index == 0) { /* XXX: is rcvif really NULL when output?? */ mif6table[mifi].m6_pkt_out++; mif6table[mifi].m6_bytes_out += plen; @@ -1561,7 +1561,7 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m) * Otherwise, we can simply send the packet to the interface * sending queue. */ - if (m->m_pkthdr.rcvif == NULL) { + if (m->m_pkthdr.rcvif_index == 0) { struct ip6_moptions im6o; im6o.im6o_multicast_ifp = ifp; diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 5221aa8..ab2bf3b 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -323,7 +323,7 @@ int icmp6_ctloutput(int, struct socket *, struct sockopt *); struct mbuf; void ip6_init(void); -void ip6_input(struct mbuf *); +void ip6_input(struct mbuf *, struct ifnet *); const struct ip6aux *ip6_getdstifaddr(struct mbuf *); void ip6_freepcbopts(struct ip6_pktopts *); void ip6_freemoptions(struct ip6_moptions *); diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c index 0109693..6ae94db 100644 --- a/sys/netinet6/mld6.c +++ b/sys/netinet6/mld6.c @@ -336,16 +336,18 @@ mld_input(struct mbuf *m, int off) { struct ip6_hdr *ip6; struct mld_hdr *mldh; - struct ifnet *ifp = m->m_pkthdr.rcvif; + struct ifnet *ifp; struct in6_multi *in6m = NULL; struct in6_addr mld_addr, all_in6; struct in6_ifaddr *ia; u_long timer = 0; /* timer value in the MLD query header */ + int s; + ifp = m_get_rcvif(m, &s); IP6_EXTHDR_GET(mldh, struct mld_hdr *, m, off, sizeof(*mldh)); if (mldh == NULL) { ICMP6_STATINC(ICMP6_STAT_TOOSHORT); - return; + goto out_nodrop; } /* source address validation */ @@ -375,8 +377,7 @@ mld_input(struct mbuf *m, int off) "mld_input: src %s is not link-local (grp=%s)\n", ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&mldh->mld_addr)); #endif - m_freem(m); - return; + goto out; } /* @@ -385,8 +386,7 @@ mld_input(struct mbuf *m, int off) mld_addr = mldh->mld_addr; if (in6_setscope(&mld_addr, ifp, NULL)) { /* XXX: this should not happen! */ - m_free(m); - return; + goto out; } /* @@ -497,7 +497,10 @@ mld_input(struct mbuf *m, int off) break; } +out: m_freem(m); +out_nodrop: + m_put_rcvif(ifp, &s); } static void diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index cead66c..2177bad 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -96,7 +96,7 @@ static int dad_maxtry = 15; /* max # of *tries* to transmit DAD packet */ void nd6_ns_input(struct mbuf *m, int off, int icmp6len) { - struct ifnet *ifp = m->m_pkthdr.rcvif; + struct ifnet *ifp; struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); struct nd_neighbor_solicit *nd_ns; struct in6_addr saddr6 = ip6->ip6_src; @@ -111,10 +111,16 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) int tlladdr; union nd_opts ndopts; const struct sockaddr_dl *proxydl = NULL; + struct psref psref; + + ifp = m_get_rcvif_psref(m, &psref); + if (ifp == NULL) + goto freeit; IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len); if (nd_ns == NULL) { ICMP6_STATINC(ICMP6_STAT_TOOSHORT); + m_put_rcvif_psref(ifp, &psref); return; } ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */ @@ -325,6 +331,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) (router ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED, tlladdr, (const struct sockaddr *)proxydl); freeit: + m_put_rcvif_psref(ifp, &psref); m_freem(m); return; @@ -333,6 +340,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) nd6log(LOG_ERR, "dst=%s\n", ip6_sprintf(&daddr6)); nd6log(LOG_ERR, "tgt=%s\n", ip6_sprintf(&taddr6)); ICMP6_STATINC(ICMP6_STAT_BADNS); + m_put_rcvif_psref(ifp, &psref); m_freem(m); } @@ -532,7 +540,7 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6, void nd6_na_input(struct mbuf *m, int off, int icmp6len) { - struct ifnet *ifp = m->m_pkthdr.rcvif; + struct ifnet *ifp; struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); struct nd_neighbor_advert *nd_na; struct in6_addr saddr6 = ip6->ip6_src; @@ -550,6 +558,11 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) struct sockaddr_in6 ssin6; int rt_announce; bool checklink = false; + struct psref psref; + + ifp = m_get_rcvif_psref(m, &psref); + if (ifp == NULL) + goto freeit; if (ip6->ip6_hlim != 255) { nd6log(LOG_ERR, @@ -561,6 +574,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, off, icmp6len); if (nd_na == NULL) { + m_put_rcvif_psref(ifp, &psref); ICMP6_STATINC(ICMP6_STAT_TOOSHORT); return; } @@ -571,8 +585,10 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0); taddr6 = nd_na->nd_na_target; - if (in6_setscope(&taddr6, ifp, NULL)) + if (in6_setscope(&taddr6, ifp, NULL)) { + m_put_rcvif_psref(ifp, &psref); return; /* XXX: impossible */ + } if (IN6_IS_ADDR_MULTICAST(&taddr6)) { nd6log(LOG_ERR, "invalid target address %s\n", @@ -815,6 +831,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) if (checklink) pfxlist_onlink_check(); + m_put_rcvif_psref(ifp, &psref); m_freem(m); return; @@ -823,6 +840,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) LLE_WUNLOCK(ln); ICMP6_STATINC(ICMP6_STAT_BADNA); + m_put_rcvif_psref(ifp, &psref); m_freem(m); } diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index b6795ba..421597a 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -131,14 +131,21 @@ nd6_is_llinfo_probreach(struct nd_defrouter *dr) void nd6_rs_input(struct mbuf *m, int off, int icmp6len) { - struct ifnet *ifp = m->m_pkthdr.rcvif; - struct nd_ifinfo *ndi = ND_IFINFO(ifp); + struct ifnet *ifp; + struct nd_ifinfo *ndi; struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); struct nd_router_solicit *nd_rs; struct in6_addr saddr6 = ip6->ip6_src; char *lladdr = NULL; int lladdrlen = 0; union nd_opts ndopts; + struct psref psref; + + ifp = m_get_rcvif_psref(m, &psref); + if (ifp == NULL) + goto freeit; + + ndi = ND_IFINFO(ifp); /* If I'm not a router, ignore it. */ if (nd6_accepts_rtadv(ndi) || !ip6_forwarding) @@ -188,11 +195,13 @@ nd6_rs_input(struct mbuf *m, int off, int icmp6len) nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); freeit: + m_put_rcvif_psref(ifp, &psref); m_freem(m); return; bad: ICMP6_STATINC(ICMP6_STAT_BADRS); + m_put_rcvif_psref(ifp, &psref); m_freem(m); } @@ -206,8 +215,8 @@ nd6_rs_input(struct mbuf *m, int off, int icmp6len) void nd6_ra_input(struct mbuf *m, int off, int icmp6len) { - struct ifnet *ifp = m->m_pkthdr.rcvif; - struct nd_ifinfo *ndi = ND_IFINFO(ifp); + struct ifnet *ifp; + struct nd_ifinfo *ndi; struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); struct nd_router_advert *nd_ra; struct in6_addr saddr6 = ip6->ip6_src; @@ -220,7 +229,13 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len) int mcast = 0; union nd_opts ndopts; struct nd_defrouter *dr; + struct psref psref; + ifp = m_get_rcvif_psref(m, &psref); + if (ifp == NULL) + goto freeit; + + ndi = ND_IFINFO(ifp); /* * We only accept RAs when * the system-wide variable allows the acceptance, and the @@ -245,6 +260,7 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len) IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len); if (nd_ra == NULL) { ICMP6_STATINC(ICMP6_STAT_TOOSHORT); + m_put_rcvif_psref(ifp, &psref); return; } @@ -335,7 +351,7 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len) memset(&prc, 0, sizeof(prc)); sockaddr_in6_init(&prc.ndprc_prefix, &pi->nd_opt_pi_prefix, 0, 0, 0); - prc.ndprc_ifp = (struct ifnet *)m->m_pkthdr.rcvif; + prc.ndprc_ifp = ifp; prc.ndprc_raf_onlink = (pi->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) ? 1 : 0; @@ -415,11 +431,13 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len) } freeit: + m_put_rcvif_psref(ifp, &psref); m_freem(m); return; bad: ICMP6_STATINC(ICMP6_STAT_BADRA); + m_put_rcvif_psref(ifp, &psref); m_freem(m); } diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index a1aa52b..6812f92 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -260,8 +260,11 @@ rip6_input(struct mbuf **mp, int *offp, int proto) if (proto == IPPROTO_NONE) m_freem(m); else { + int s; + struct ifnet *rcvif = m_get_rcvif(m, &s); u_int8_t *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */ - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_protounknown); + in6_ifstat_inc(rcvif, ifs6_in_protounknown); + m_put_rcvif(rcvif, &s); icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER, prvnxtp - mtod(m, u_int8_t *)); @@ -384,6 +387,9 @@ rip6_output(struct mbuf *m, struct socket * const so, int type, code; /* for ICMPv6 output statistics only */ int scope_ambiguous = 0; struct in6_addr *in6a; + int bound = curlwp->l_pflag & LP_BOUND; + + curlwp->l_pflag |= LP_BOUND; in6p = sotoin6pcb(so); @@ -444,8 +450,7 @@ rip6_output(struct mbuf *m, struct socket * const so, * Source address selection. */ if ((in6a = in6_selectsrc(dstsock, optp, in6p->in6p_moptions, - &in6p->in6p_route, &in6p->in6p_laddr, &oifp, - &error)) == 0) { + &in6p->in6p_route, &in6p->in6p_laddr, &oifp, &error)) == 0) { if (error == 0) error = EADDRNOTAVAIL; goto bad; @@ -507,14 +512,18 @@ rip6_output(struct mbuf *m, struct socket * const so, } } - error = ip6_output(m, optp, &in6p->in6p_route, 0, - in6p->in6p_moptions, so, &oifp); - if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { - if (oifp) - icmp6_ifoutstat_inc(oifp, type, code); - ICMP6_STATINC(ICMP6_STAT_OUTHIST + type); - } else - RIP6_STATINC(RIP6_STAT_OPACKETS); + { + struct ifnet *ret_oifp = NULL; + + error = ip6_output(m, optp, &in6p->in6p_route, 0, + in6p->in6p_moptions, so, &ret_oifp); + if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { + if (ret_oifp) + icmp6_ifoutstat_inc(ret_oifp, type, code); + ICMP6_STATINC(ICMP6_STAT_OUTHIST + type); + } else + RIP6_STATINC(RIP6_STAT_OPACKETS); + } goto freectl; @@ -527,6 +536,7 @@ rip6_output(struct mbuf *m, struct socket * const so, ip6_clearpktopts(&opt, -1); m_freem(control); } + curlwp->l_pflag ^= bound ^ LP_BOUND; return error; } @@ -736,17 +746,18 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct lwp *l) &in6p->in6p_laddr, &ifp, &error); if (in6a == NULL) { if (error == 0) - return EADDRNOTAVAIL; - return error; + error = EADDRNOTAVAIL; + goto out; } /* XXX: see above */ if (ifp && scope_ambiguous && (error = in6_setscope(&addr->sin6_addr, ifp, NULL)) != 0) { - return error; + goto out; } in6p->in6p_laddr = *in6a; in6p->in6p_faddr = addr->sin6_addr; soisconnected(so); +out: return error; } diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c index f587482..f11c4ad 100644 --- a/sys/netinet6/sctp6_usrreq.c +++ b/sys/netinet6/sctp6_usrreq.c @@ -160,8 +160,8 @@ sctp6_input(struct mbuf **mp, int *offp, int proto) if (sh->dest_port == 0) goto bad; if ((sctp_no_csum_on_loopback == 0) || - (m->m_pkthdr.rcvif == NULL) || - (m->m_pkthdr.rcvif->if_type != IFT_LOOP)) { + (m_get_rcvif_NOMPSAFE(m) == NULL) || + (m_get_rcvif_NOMPSAFE(m)->if_type != IFT_LOOP)) { /* we do NOT validate things from the loopback if the * sysctl is set to 1. */ diff --git a/sys/netinet6/udp6_output.c b/sys/netinet6/udp6_output.c index 0745e51..dea5093 100644 --- a/sys/netinet6/udp6_output.c +++ b/sys/netinet6/udp6_output.c @@ -232,9 +232,8 @@ udp6_output(struct in6pcb * const in6p, struct mbuf *m, &in6p->in6p_laddr, &oifp, &error); if (oifp && scope_ambiguous && (error = in6_setscope(&sin6->sin6_addr, - oifp, NULL))) { + oifp, NULL))) goto release; - } } else { /* * XXX: freebsd[34] does not have in_selectsrc, but diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index eab5704..5af62f4 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -519,7 +519,7 @@ udp6_input_checksum(struct mbuf *m, const struct udphdr *uh, int off, int len) } switch (m->m_pkthdr.csum_flags & - ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_UDPv6) | + ((m_get_rcvif_NOMPSAFE(m)->if_csum_flags_rx & M_CSUM_UDPv6) | M_CSUM_TCP_UDP_BAD | M_CSUM_DATA)) { case M_CSUM_UDPv6|M_CSUM_TCP_UDP_BAD: UDP_CSUM_COUNTER_INCR(&udp6_hwcsum_bad); diff --git a/sys/netipsec/ipsec_input.c b/sys/netipsec/ipsec_input.c index 1d73086..1356517 100644 --- a/sys/netipsec/ipsec_input.c +++ b/sys/netipsec/ipsec_input.c @@ -769,7 +769,8 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto */ if (m->m_pkthdr.len < skip) { IP6_STATINC(IP6_STAT_TOOSHORT); - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); + in6_ifstat_inc(m_get_rcvif_NOMPSAFE(m), + ifs6_in_truncated); error = EINVAL; goto bad; } diff --git a/sys/netipsec/key_debug.c b/sys/netipsec/key_debug.c index 14e4e16..3b6e151 100644 --- a/sys/netipsec/key_debug.c +++ b/sys/netipsec/key_debug.c @@ -620,7 +620,7 @@ kdebug_mbufhdr(const struct mbuf *m) if (m->m_flags & M_PKTHDR) { printf(" m_pkthdr{ len:%d rcvif:%p }\n", - m->m_pkthdr.len, m->m_pkthdr.rcvif); + m->m_pkthdr.len, m_get_rcvif_NOMPSAFE(m)); } if (m->m_flags & M_EXT) { diff --git a/sys/netipsec/xform_ipip.c b/sys/netipsec/xform_ipip.c index 2c2a0a4..1fca4e3 100644 --- a/sys/netipsec/xform_ipip.c +++ b/sys/netipsec/xform_ipip.c @@ -330,8 +330,8 @@ _ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp) } /* Check for local address spoofing. */ - if ((m->m_pkthdr.rcvif == NULL || - !(m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK)) && + if ((m_get_rcvif_NOMPSAFE(m) == NULL || + !(m_get_rcvif_NOMPSAFE(m)->if_flags & IFF_LOOPBACK)) && ipip_allow != 2) { int s = pserialize_read_enter(); IFNET_READER_FOREACH(ifp) { diff --git a/sys/netmpls/mpls_ttl.c b/sys/netmpls/mpls_ttl.c index 69535ec..71fc855 100644 --- a/sys/netmpls/mpls_ttl.c +++ b/sys/netmpls/mpls_ttl.c @@ -311,7 +311,7 @@ mpls_icmp_error(struct mbuf *n, int type, int code, n_long dest, m->m_data -= sizeof(struct ip); m->m_len += sizeof(struct ip); m->m_pkthdr.len = m->m_len; - m_set_rcvif(m, n->m_pkthdr.rcvif); + m_copy_rcvif(m, n); nip = mtod(m, struct ip *); /* ip_v set in ip_output */ nip->ip_hl = sizeof(struct ip) >> 2; diff --git a/sys/netnatm/natm.c b/sys/netnatm/natm.c index d2d41d1..3b95325 100644 --- a/sys/netnatm/natm.c +++ b/sys/netnatm/natm.c @@ -457,7 +457,7 @@ next: panic("natmintr no HDR"); #endif - npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */ + npcb = (struct natmpcb *) m_get_rcvif_NOMPSAFE(m); /* XXX: overloaded */ so = npcb->npcb_socket; s = splnet(); /* could have atm devs @ different levels */ diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index 5043216..b7cf880 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -76,6 +76,7 @@ #if defined(_KERNEL) #include #include /* for AF_UNSPEC */ +#include #endif /* defined(_KERNEL) */ /* For offsetof() */ @@ -87,6 +88,8 @@ #include /* for MIN_PAGE_SIZE */ +#include + /* * Mbufs are of a single size, MSIZE (machine/param.h), which * includes overhead. An mbuf may add a single "mbuf cluster" of size @@ -175,7 +178,11 @@ struct m_hdr { * LP64: 56 */ struct pkthdr { - struct ifnet *rcvif; /* rcv interface */ + union { + void *ctx; /* for M_GETCTX/M_SETCTX */ + uint16_t index; /* rcv interface index */ + } _rcvif; +#define rcvif_index _rcvif.index SLIST_HEAD(packet_tags, m_tag) tags; /* list of packet tags */ int len; /* total packet length */ int csum_flags; /* checksum flags */ @@ -710,11 +717,10 @@ do { \ #define m_copy(m, o, l) m_copym((m), (o), (l), M_DONTWAIT) /* - * Allow drivers and/or protocols to use the rcvif member of - * PKTHDR mbufs to store private context information. + * Allow drivers and/or protocols to store private context information. */ -#define M_GETCTX(m, t) ((t)(m)->m_pkthdr.rcvif) -#define M_SETCTX(m, c) ((void)((m)->m_pkthdr.rcvif = (void *)(c))) +#define M_GETCTX(m, t) ((t)(m)->m_pkthdr._rcvif.ctx) +#define M_SETCTX(m, c) ((void)((m)->m_pkthdr._rcvif.ctx = (void *)(c))) #define M_CLEARCTX(m) M_SETCTX((m), NULL) #endif /* defined(_KERNEL) */ @@ -964,17 +970,24 @@ m_hdr_init(struct mbuf *m, short type, struct mbuf *next, char *data, int len) } static __inline void -m_set_rcvif(struct mbuf *m, struct ifnet *ifp) +m_set_rcvif(struct mbuf *m, const struct ifnet *ifp) { - m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.rcvif_index = ifp->if_index; } static __inline void m_reset_rcvif(struct mbuf *m) { - m_set_rcvif(m, NULL); + m->m_pkthdr.rcvif_index = 0; +} + +static __inline void +m_copy_rcvif(struct mbuf *m, const struct mbuf *n) +{ + + m->m_pkthdr.rcvif_index = n->m_pkthdr.rcvif_index; } static __inline void @@ -1000,5 +1013,63 @@ m_pkthdr_init(struct mbuf *m) void m_print(const struct mbuf *, const char *, void (*)(const char *, ...) __printflike(1, 2)); +/* + * Get rcvif of a mbuf. + * + * The caller must call m_put_rcvif after using rcvif. The caller cannot + * block or sleep during using rcvif. Insofar as the constraint is satisfied, + * the API ensures a got rcvif isn't be freed until m_put_rcvif is called. + */ +static __inline struct ifnet * +m_get_rcvif(const struct mbuf *m, int *s) +{ + + *s = pserialize_read_enter(); + return if_byindex(m->m_pkthdr.rcvif_index); +} + +static __inline void +m_put_rcvif(struct ifnet *ifp, int *s) +{ + + if (ifp == NULL) + return; + pserialize_read_exit(*s); +} + +/* + * Get rcvif of a mbuf. + * + * The caller must call m_put_rcvif_psref after using rcvif. The API ensures + * a got rcvif isn't be freed until m_put_rcvif_psref is called. + */ +static __inline struct ifnet * +m_get_rcvif_psref(const struct mbuf *m, struct psref *psref) +{ + + return if_get_byindex(m->m_pkthdr.rcvif_index, psref); +} + +static __inline void +m_put_rcvif_psref(struct ifnet *ifp, struct psref *psref) +{ + + if (ifp == NULL) + return; + if_put(ifp, psref); +} + +/* + * Get rcvif of a mbuf. + * + * This is NOT an MP-safe API and shouldn't be used at where we want MP-safe. + */ +static __inline struct ifnet * +m_get_rcvif_NOMPSAFE(const struct mbuf *m) +{ + + return if_byindex(m->m_pkthdr.rcvif_index); +} + #endif /* _KERNEL */ #endif /* !_SYS_MBUF_H_ */