Module Name:    src
Committed By:   ozaki-r
Date:           Fri Jun 10 13:31:45 UTC 2016

Modified Files:
        src/sys/altq: altq_cdnr.c
        src/sys/dev/pci: if_lmc.c
        src/sys/dist/pf/net: if_pfsync.c
        src/sys/external/bsd/ipf/netinet: ip_compat.h
        src/sys/kern: uipc_mbuf.c
        src/sys/net: bpf.c if.c if.h if_bridge.c if_mpls.c if_pppoe.c if_stf.c
        src/sys/netatalk: ddp_input.c
        src/sys/netinet: if_arp.c igmp.c in_gif.c ip_carp.c ip_flow.c ip_icmp.c
            ip_input.c sctp_input.c sctp_output.c tcp_input.c udp_usrreq.c
        src/sys/netinet6: icmp6.c in6_gif.c ip6_forward.c ip6_input.c
            ip6_mroute.c ip6_var.h mld6.c nd6_nbr.c nd6_rtr.c raw_ip6.c
            sctp6_usrreq.c udp6_output.c udp6_usrreq.c
        src/sys/netipsec: ipsec_input.c key_debug.c xform_ipip.c
        src/sys/netmpls: mpls_ttl.c
        src/sys/netnatm: natm.c
        src/sys/sys: mbuf.h

Log Message:
Avoid storing a pointer of an interface in a mbuf

Having a pointer of an interface in a mbuf isn't safe if we remove big
kernel locks; an interface object (ifnet) can be destroyed anytime in any
packet processing and accessing such object via a pointer is racy. Instead
we have to get an object from the interface collection (ifindex2ifnet) via
an interface index (if_index) that is stored to a mbuf instead of an
pointer.

The change provides two APIs: m_{get,put}_rcvif_psref that use psref(9)
for sleep-able critical sections and m_{get,put}_rcvif that use
pserialize(9) for other critical sections. The change also adds another
API called m_get_rcvif_NOMPSAFE, that is NOT MP-safe and for transition
moratorium, i.e., it is intended to be used for places where are not
planned to be MP-ified soon.

The change adds some overhead due to psref to performance sensitive paths,
however the overhead is not serious, 2% down at worst.

Proposed on tech-kern and tech-net.


To generate a diff of this commit:
cvs rdiff -u -r1.20 -r1.21 src/sys/altq/altq_cdnr.c
cvs rdiff -u -r1.60 -r1.61 src/sys/dev/pci/if_lmc.c
cvs rdiff -u -r1.13 -r1.14 src/sys/dist/pf/net/if_pfsync.c
cvs rdiff -u -r1.9 -r1.10 src/sys/external/bsd/ipf/netinet/ip_compat.h
cvs rdiff -u -r1.166 -r1.167 src/sys/kern/uipc_mbuf.c
cvs rdiff -u -r1.197 -r1.198 src/sys/net/bpf.c
cvs rdiff -u -r1.337 -r1.338 src/sys/net/if.c
cvs rdiff -u -r1.206 -r1.207 src/sys/net/if.h
cvs rdiff -u -r1.124 -r1.125 src/sys/net/if_bridge.c
cvs rdiff -u -r1.22 -r1.23 src/sys/net/if_mpls.c
cvs rdiff -u -r1.107 -r1.108 src/sys/net/if_pppoe.c
cvs rdiff -u -r1.89 -r1.90 src/sys/net/if_stf.c
cvs rdiff -u -r1.26 -r1.27 src/sys/netatalk/ddp_input.c
cvs rdiff -u -r1.210 -r1.211 src/sys/netinet/if_arp.c
cvs rdiff -u -r1.57 -r1.58 src/sys/netinet/igmp.c
cvs rdiff -u -r1.75 -r1.76 src/sys/netinet/in_gif.c
cvs rdiff -u -r1.66 -r1.67 src/sys/netinet/ip_carp.c \
    src/sys/netinet/ip_flow.c
cvs rdiff -u -r1.146 -r1.147 src/sys/netinet/ip_icmp.c
cvs rdiff -u -r1.328 -r1.329 src/sys/netinet/ip_input.c
cvs rdiff -u -r1.2 -r1.3 src/sys/netinet/sctp_input.c
cvs rdiff -u -r1.5 -r1.6 src/sys/netinet/sctp_output.c
cvs rdiff -u -r1.346 -r1.347 src/sys/netinet/tcp_input.c
cvs rdiff -u -r1.225 -r1.226 src/sys/netinet/udp_usrreq.c
cvs rdiff -u -r1.187 -r1.188 src/sys/netinet6/icmp6.c
cvs rdiff -u -r1.73 -r1.74 src/sys/netinet6/in6_gif.c
cvs rdiff -u -r1.78 -r1.79 src/sys/netinet6/ip6_forward.c
cvs rdiff -u -r1.159 -r1.160 src/sys/netinet6/ip6_input.c
cvs rdiff -u -r1.109 -r1.110 src/sys/netinet6/ip6_mroute.c
cvs rdiff -u -r1.64 -r1.65 src/sys/netinet6/ip6_var.h
cvs rdiff -u -r1.65 -r1.66 src/sys/netinet6/mld6.c
cvs rdiff -u -r1.118 -r1.119 src/sys/netinet6/nd6_nbr.c
cvs rdiff -u -r1.110 -r1.111 src/sys/netinet6/nd6_rtr.c
cvs rdiff -u -r1.143 -r1.144 src/sys/netinet6/raw_ip6.c
cvs rdiff -u -r1.4 -r1.5 src/sys/netinet6/sctp6_usrreq.c
cvs rdiff -u -r1.50 -r1.51 src/sys/netinet6/udp6_output.c
cvs rdiff -u -r1.122 -r1.123 src/sys/netinet6/udp6_usrreq.c
cvs rdiff -u -r1.35 -r1.36 src/sys/netipsec/ipsec_input.c
cvs rdiff -u -r1.12 -r1.13 src/sys/netipsec/key_debug.c
cvs rdiff -u -r1.38 -r1.39 src/sys/netipsec/xform_ipip.c
cvs rdiff -u -r1.7 -r1.8 src/sys/netmpls/mpls_ttl.c
cvs rdiff -u -r1.51 -r1.52 src/sys/netnatm/natm.c
cvs rdiff -u -r1.163 -r1.164 src/sys/sys/mbuf.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/altq/altq_cdnr.c
diff -u src/sys/altq/altq_cdnr.c:1.20 src/sys/altq/altq_cdnr.c:1.21
--- src/sys/altq/altq_cdnr.c:1.20	Sat Nov 19 22:51:18 2011
+++ src/sys/altq/altq_cdnr.c	Fri Jun 10 13:31:43 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: altq_cdnr.c,v 1.20 2011/11/19 22:51:18 tls Exp $	*/
+/*	$NetBSD: altq_cdnr.c,v 1.21 2016/06/10 13:31:43 ozaki-r Exp $	*/
 /*	$KAME: altq_cdnr.c,v 1.15 2005/04/13 03:44:24 suz Exp $	*/
 
 /*
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: altq_cdnr.c,v 1.20 2011/11/19 22:51:18 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: altq_cdnr.c,v 1.21 2016/06/10 13:31:43 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_altq.h"
@@ -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);

Index: src/sys/dev/pci/if_lmc.c
diff -u src/sys/dev/pci/if_lmc.c:1.60 src/sys/dev/pci/if_lmc.c:1.61
--- src/sys/dev/pci/if_lmc.c:1.60	Fri Jun 10 13:27:14 2016
+++ src/sys/dev/pci/if_lmc.c	Fri Jun 10 13:31:43 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: if_lmc.c,v 1.60 2016/06/10 13:27:14 ozaki-r Exp $ */
+/* $NetBSD: if_lmc.c,v 1.61 2016/06/10 13:31:43 ozaki-r Exp $ */
 
 /*-
  * Copyright (c) 2002-2006 David Boggs. <bo...@boggs.palo-alto.ca.us>
@@ -74,7 +74,7 @@
  */
 
 # include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_lmc.c,v 1.60 2016/06/10 13:27:14 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_lmc.c,v 1.61 2016/06/10 13:31:43 ozaki-r Exp $");
 # include <sys/param.h>	/* OS version */
 # include "opt_inet.h"	/* INET6, INET */
 # include "opt_altq_enabled.h" /* ALTQ */
@@ -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,

Index: src/sys/dist/pf/net/if_pfsync.c
diff -u src/sys/dist/pf/net/if_pfsync.c:1.13 src/sys/dist/pf/net/if_pfsync.c:1.14
--- src/sys/dist/pf/net/if_pfsync.c:1.13	Fri Jun 10 13:27:15 2016
+++ src/sys/dist/pf/net/if_pfsync.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_pfsync.c,v 1.13 2016/06/10 13:27:15 ozaki-r Exp $	*/
+/*	$NetBSD: if_pfsync.c,v 1.14 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$OpenBSD: if_pfsync.c,v 1.83 2007/06/26 14:44:12 mcbride Exp $	*/
 
 /*
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_pfsync.c,v 1.13 2016/06/10 13:27:15 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_pfsync.c,v 1.14 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -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;
 	}

Index: src/sys/external/bsd/ipf/netinet/ip_compat.h
diff -u src/sys/external/bsd/ipf/netinet/ip_compat.h:1.9 src/sys/external/bsd/ipf/netinet/ip_compat.h:1.10
--- src/sys/external/bsd/ipf/netinet/ip_compat.h:1.9	Fri Jun 10 13:27:15 2016
+++ src/sys/external/bsd/ipf/netinet/ip_compat.h	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_compat.h,v 1.9 2016/06/10 13:27:15 ozaki-r Exp $	*/
+/*	$NetBSD: ip_compat.h,v 1.10 2016/06/10 13:31:44 ozaki-r Exp $	*/
 
 /*
  * Copyright (C) 2012 by Darren Reed.
@@ -1964,8 +1964,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

Index: src/sys/kern/uipc_mbuf.c
diff -u src/sys/kern/uipc_mbuf.c:1.166 src/sys/kern/uipc_mbuf.c:1.167
--- src/sys/kern/uipc_mbuf.c:1.166	Fri Jun 10 13:27:15 2016
+++ src/sys/kern/uipc_mbuf.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: uipc_mbuf.c,v 1.166 2016/06/10 13:27:15 ozaki-r Exp $	*/
+/*	$NetBSD: uipc_mbuf.c,v 1.167 2016/06/10 13:31:44 ozaki-r Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2001 The NetBSD Foundation, Inc.
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_mbuf.c,v 1.166 2016/06/10 13:27:15 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_mbuf.c,v 1.167 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_mbuftrace.h"
@@ -1171,7 +1171,7 @@ m_split0(struct mbuf *m0, int len0, int 
 		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)) {

Index: src/sys/net/bpf.c
diff -u src/sys/net/bpf.c:1.197 src/sys/net/bpf.c:1.198
--- src/sys/net/bpf.c:1.197	Fri Jun 10 13:27:15 2016
+++ src/sys/net/bpf.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: bpf.c,v 1.197 2016/06/10 13:27:15 ozaki-r Exp $	*/
+/*	$NetBSD: bpf.c,v 1.198 2016/06/10 13:31:44 ozaki-r Exp $	*/
 
 /*
  * Copyright (c) 1990, 1991, 1993
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.197 2016/06/10 13:27:15 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.198 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_bpf.h"
@@ -1469,7 +1469,7 @@ _bpf_mtap2(struct bpf_if *bp, void *data
 	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
 	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
 	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
 		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);
 }
 
 /*

Index: src/sys/net/if.c
diff -u src/sys/net/if.c:1.337 src/sys/net/if.c:1.338
--- src/sys/net/if.c:1.337	Tue May 31 04:05:01 2016
+++ src/sys/net/if.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if.c,v 1.337 2016/05/31 04:05:01 ozaki-r Exp $	*/
+/*	$NetBSD: if.c,v 1.338 2016/06/10 13:31:44 ozaki-r Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.337 2016/05/31 04:05:01 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.338 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -1245,7 +1245,7 @@ if_detach_queues(struct ifnet *ifp, stru
 		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 *
 	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)

Index: src/sys/net/if.h
diff -u src/sys/net/if.h:1.206 src/sys/net/if.h:1.207
--- src/sys/net/if.h:1.206	Mon May 16 01:16:24 2016
+++ src/sys/net/if.h	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if.h,v 1.206 2016/05/16 01:16:24 ozaki-r Exp $	*/
+/*	$NetBSD: if.h,v 1.207 2016/06/10 13:31:44 ozaki-r Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -890,17 +890,21 @@ int	ifaddrpref_ioctl(struct socket *, u_
 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 *

Index: src/sys/net/if_bridge.c
diff -u src/sys/net/if_bridge.c:1.124 src/sys/net/if_bridge.c:1.125
--- src/sys/net/if_bridge.c:1.124	Fri Jun 10 13:27:16 2016
+++ src/sys/net/if_bridge.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_bridge.c,v 1.124 2016/06/10 13:27:16 ozaki-r Exp $	*/
+/*	$NetBSD: if_bridge.c,v 1.125 2016/06/10 13:31:44 ozaki-r Exp $	*/
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -80,7 +80,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.124 2016/06/10 13:27:16 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.125 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_bridge_ipf.h"
@@ -1610,12 +1610,18 @@ bridge_forward(struct bridge_softc *sc, 
 	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, 
 		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, 
 		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, 
 	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;
         }
 

Index: src/sys/net/if_mpls.c
diff -u src/sys/net/if_mpls.c:1.22 src/sys/net/if_mpls.c:1.23
--- src/sys/net/if_mpls.c:1.22	Thu Apr 28 00:16:56 2016
+++ src/sys/net/if_mpls.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_mpls.c,v 1.22 2016/04/28 00:16:56 ozaki-r Exp $ */
+/*	$NetBSD: if_mpls.c,v 1.23 2016/06/10 13:31:44 ozaki-r Exp $ */
 
 /*
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_mpls.c,v 1.22 2016/04/28 00:16:56 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_mpls.c,v 1.23 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -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);
 	}
 }
 

Index: src/sys/net/if_pppoe.c
diff -u src/sys/net/if_pppoe.c:1.107 src/sys/net/if_pppoe.c:1.108
--- src/sys/net/if_pppoe.c:1.107	Fri Jun 10 13:27:16 2016
+++ src/sys/net/if_pppoe.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: if_pppoe.c,v 1.107 2016/06/10 13:27:16 ozaki-r Exp $ */
+/* $NetBSD: if_pppoe.c,v 1.108 2016/06/10 13:31:44 ozaki-r Exp $ */
 
 /*-
  * Copyright (c) 2002, 2008 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.107 2016/06/10 13:27:16 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.108 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #include "pppoe.h"
 
@@ -495,7 +495,9 @@ pppoe_dispatch_disc_pkt(struct mbuf *m, 
 				}
 			}
 			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, 
 			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);
 

Index: src/sys/net/if_stf.c
diff -u src/sys/net/if_stf.c:1.89 src/sys/net/if_stf.c:1.90
--- src/sys/net/if_stf.c:1.89	Fri Jun 10 13:27:16 2016
+++ src/sys/net/if_stf.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_stf.c,v 1.89 2016/06/10 13:27:16 ozaki-r Exp $	*/
+/*	$NetBSD: if_stf.c,v 1.90 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$KAME: if_stf.c,v 1.62 2001/06/07 22:32:16 itojun Exp $ */
 
 /*
@@ -75,7 +75,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_stf.c,v 1.89 2016/06/10 13:27:16 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_stf.c,v 1.90 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -584,7 +584,7 @@ in_stf_input(struct mbuf *m, int off, in
 	 * 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, in
 	 * 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;
 	}

Index: src/sys/netatalk/ddp_input.c
diff -u src/sys/netatalk/ddp_input.c:1.26 src/sys/netatalk/ddp_input.c:1.27
--- src/sys/netatalk/ddp_input.c:1.26	Wed Aug 31 18:31:03 2011
+++ src/sys/netatalk/ddp_input.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ddp_input.c,v 1.26 2011/08/31 18:31:03 plunky Exp $	 */
+/*	$NetBSD: ddp_input.c,v 1.27 2016/06/10 13:31:44 ozaki-r Exp $	 */
 
 /*
  * Copyright (c) 1990,1994 Regents of The University of Michigan.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ddp_input.c,v 1.26 2011/08/31 18:31:03 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ddp_input.c,v 1.27 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -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)

Index: src/sys/netinet/if_arp.c
diff -u src/sys/netinet/if_arp.c:1.210 src/sys/netinet/if_arp.c:1.211
--- src/sys/netinet/if_arp.c:1.210	Tue May 17 09:00:24 2016
+++ src/sys/netinet/if_arp.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_arp.c,v 1.210 2016/05/17 09:00:24 ozaki-r Exp $	*/
+/*	$NetBSD: if_arp.c,v 1.211 2016/06/10 13:31:44 ozaki-r Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.210 2016/05/17 09:00:24 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.211 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -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
 	wakeup((void *)&myip);
 
 out:
+	m_put_rcvif(rcvif, &s);
 	m_freem(m);
 }
 

Index: src/sys/netinet/igmp.c
diff -u src/sys/netinet/igmp.c:1.57 src/sys/netinet/igmp.c:1.58
--- src/sys/netinet/igmp.c:1.57	Tue Apr 26 08:44:44 2016
+++ src/sys/netinet/igmp.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: igmp.c,v 1.57 2016/04/26 08:44:44 ozaki-r Exp $	*/
+/*	$NetBSD: igmp.c,v 1.58 2016/06/10 13:31:44 ozaki-r Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -40,7 +40,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: igmp.c,v 1.57 2016/04/26 08:44:44 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: igmp.c,v 1.58 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_mrouting.h"
@@ -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

Index: src/sys/netinet/in_gif.c
diff -u src/sys/netinet/in_gif.c:1.75 src/sys/netinet/in_gif.c:1.76
--- src/sys/netinet/in_gif.c:1.75	Tue Jan 26 06:00:10 2016
+++ src/sys/netinet/in_gif.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: in_gif.c,v 1.75 2016/01/26 06:00:10 knakahara Exp $	*/
+/*	$NetBSD: in_gif.c,v 1.76 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$KAME: in_gif.c,v 1.66 2001/07/29 04:46:09 itojun Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.75 2016/01/26 06:00:10 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.76 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -199,6 +199,8 @@ in_gif_input(struct mbuf *m, int off, in
 	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, in
 		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,
 	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);
 }

Index: src/sys/netinet/ip_carp.c
diff -u src/sys/netinet/ip_carp.c:1.66 src/sys/netinet/ip_carp.c:1.67
--- src/sys/netinet/ip_carp.c:1.66	Fri Jun 10 13:27:16 2016
+++ src/sys/netinet/ip_carp.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_carp.c,v 1.66 2016/06/10 13:27:16 ozaki-r Exp $	*/
+/*	$NetBSD: ip_carp.c,v 1.67 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$OpenBSD: ip_carp.c,v 1.113 2005/11/04 08:11:54 mcbride Exp $	*/
 
 /*
@@ -33,7 +33,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.66 2016/06/10 13:27:16 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.67 2016/06/10 13:31:44 ozaki-r Exp $");
 
 /*
  * TODO:
@@ -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 
 	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 
 		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 
 	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 
 	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, struc
 	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 *sho
 		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);
 	}
Index: src/sys/netinet/ip_flow.c
diff -u src/sys/netinet/ip_flow.c:1.66 src/sys/netinet/ip_flow.c:1.67
--- src/sys/netinet/ip_flow.c:1.66	Mon Mar 23 18:33:17 2015
+++ src/sys/netinet/ip_flow.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_flow.c,v 1.66 2015/03/23 18:33:17 roy Exp $	*/
+/*	$NetBSD: ip_flow.c,v 1.67 2016/06/10 13:31:44 ozaki-r Exp $	*/
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_flow.c,v 1.66 2015/03/23 18:33:17 roy Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_flow.c,v 1.67 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -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?

Index: src/sys/netinet/ip_icmp.c
diff -u src/sys/netinet/ip_icmp.c:1.146 src/sys/netinet/ip_icmp.c:1.147
--- src/sys/netinet/ip_icmp.c:1.146	Fri Jun 10 13:27:16 2016
+++ src/sys/netinet/ip_icmp.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_icmp.c,v 1.146 2016/06/10 13:27:16 ozaki-r Exp $	*/
+/*	$NetBSD: ip_icmp.c,v 1.147 2016/06/10 13:31:44 ozaki-r Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -94,7 +94,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_icmp.c,v 1.146 2016/06/10 13:27:16 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_icmp.c,v 1.147 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ipsec.h"
@@ -339,7 +339,7 @@ icmp_error(struct mbuf *n, int type, int
 	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:

Index: src/sys/netinet/ip_input.c
diff -u src/sys/netinet/ip_input.c:1.328 src/sys/netinet/ip_input.c:1.329
--- src/sys/netinet/ip_input.c:1.328	Thu Jan 21 15:41:30 2016
+++ src/sys/netinet/ip_input.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_input.c,v 1.328 2016/01/21 15:41:30 riastradh Exp $	*/
+/*	$NetBSD: ip_input.c,v 1.329 2016/06/10 13:31:44 ozaki-r Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.328 2016/01/21 15:41:30 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.329 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -284,7 +284,7 @@ struct mowner ip_tx_mowner = MOWNER_INIT
 
 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
     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
 		if (*mp)
 			mp = &(*mp)->m_next;
 	}
+	m_put_rcvif_psref(ifp, &psref);
 }
 
 /*

Index: src/sys/netinet/sctp_input.c
diff -u src/sys/netinet/sctp_input.c:1.2 src/sys/netinet/sctp_input.c:1.3
--- src/sys/netinet/sctp_input.c:1.2	Mon Apr 25 21:21:02 2016
+++ src/sys/netinet/sctp_input.c	Fri Jun 10 13:31:44 2016
@@ -1,5 +1,5 @@
 /*	$KAME: sctp_input.c,v 1.28 2005/04/21 18:36:21 nishida Exp $	*/
-/*	$NetBSD: sctp_input.c,v 1.2 2016/04/25 21:21:02 rjs Exp $	*/
+/*	$NetBSD: sctp_input.c,v 1.3 2016/06/10 13:31:44 ozaki-r Exp $	*/
 
 /*
  * Copyright (C) 2002, 2003, 2004 Cisco Systems Inc,
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sctp_input.c,v 1.2 2016/04/25 21:21:02 rjs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sctp_input.c,v 1.3 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ipsec.h"
@@ -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.
 		 */

Index: src/sys/netinet/sctp_output.c
diff -u src/sys/netinet/sctp_output.c:1.5 src/sys/netinet/sctp_output.c:1.6
--- src/sys/netinet/sctp_output.c:1.5	Fri Jun 10 13:27:16 2016
+++ src/sys/netinet/sctp_output.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: sctp_output.c,v 1.5 2016/06/10 13:27:16 ozaki-r Exp $ */
+/*	$NetBSD: sctp_output.c,v 1.6 2016/06/10 13:31:44 ozaki-r Exp $ */
 /*	$KAME: sctp_output.c,v 1.48 2005/06/16 18:29:24 jinmei Exp $	*/
 
 /*
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sctp_output.c,v 1.5 2016/06/10 13:27:16 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sctp_output.c,v 1.6 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ipsec.h"
@@ -3470,7 +3470,7 @@ sctp_send_initiate_ack(struct sctp_inpcb
 				/* 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
 
 	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 iphl
 	}
 
 	/* 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 i
 		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);

Index: src/sys/netinet/tcp_input.c
diff -u src/sys/netinet/tcp_input.c:1.346 src/sys/netinet/tcp_input.c:1.347
--- src/sys/netinet/tcp_input.c:1.346	Fri Jun 10 13:27:16 2016
+++ src/sys/netinet/tcp_input.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: tcp_input.c,v 1.346 2016/06/10 13:27:16 ozaki-r Exp $	*/
+/*	$NetBSD: tcp_input.c,v 1.347 2016/06/10 13:31:44 ozaki-r Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -148,7 +148,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tcp_input.c,v 1.346 2016/06/10 13:27:16 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tcp_input.c,v 1.347 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -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 *
 			 * 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 *
 #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 *
 		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, stru
 	}
 	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() */

Index: src/sys/netinet/udp_usrreq.c
diff -u src/sys/netinet/udp_usrreq.c:1.225 src/sys/netinet/udp_usrreq.c:1.226
--- src/sys/netinet/udp_usrreq.c:1.225	Tue Apr 26 08:44:45 2016
+++ src/sys/netinet/udp_usrreq.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: udp_usrreq.c,v 1.225 2016/04/26 08:44:45 ozaki-r Exp $	*/
+/*	$NetBSD: udp_usrreq.c,v 1.226 2016/06/10 13:31:44 ozaki-r Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.225 2016/04/26 08:44:45 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.226 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -276,7 +276,7 @@ udp4_input_checksum(struct mbuf *m, cons
 		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, cons
 		 * 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, 
 	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

Index: src/sys/netinet6/icmp6.c
diff -u src/sys/netinet6/icmp6.c:1.187 src/sys/netinet6/icmp6.c:1.188
--- src/sys/netinet6/icmp6.c:1.187	Fri Jun 10 13:27:16 2016
+++ src/sys/netinet6/icmp6.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: icmp6.c,v 1.187 2016/06/10 13:27:16 ozaki-r Exp $	*/
+/*	$NetBSD: icmp6.c,v 1.188 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.187 2016/06/10 13:27:16 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.188 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -453,8 +453,10 @@ icmp6_input(struct mbuf **mp, int *offp,
 	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,
 	 */
 	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,
 	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,
 		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,
 	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 o
 		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 o
 		 */
 		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 
 	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 
 	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 *src
 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
 	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
 	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
 	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
 	}
 
  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);
 }

Index: src/sys/netinet6/in6_gif.c
diff -u src/sys/netinet6/in6_gif.c:1.73 src/sys/netinet6/in6_gif.c:1.74
--- src/sys/netinet6/in6_gif.c:1.73	Mon Feb 29 01:29:15 2016
+++ src/sys/netinet6/in6_gif.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_gif.c,v 1.73 2016/02/29 01:29:15 knakahara Exp $	*/
+/*	$NetBSD: in6_gif.c,v 1.74 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$KAME: in6_gif.c,v 1.62 2001/07/29 04:27:25 itojun Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_gif.c,v 1.73 2016/02/29 01:29:15 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_gif.c,v 1.74 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -229,11 +229,15 @@ in6_gif_input(struct mbuf **mp, int *off
 		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,
 	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);
 }

Index: src/sys/netinet6/ip6_forward.c
diff -u src/sys/netinet6/ip6_forward.c:1.78 src/sys/netinet6/ip6_forward.c:1.79
--- src/sys/netinet6/ip6_forward.c:1.78	Mon Aug 24 22:21:27 2015
+++ src/sys/netinet6/ip6_forward.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6_forward.c,v 1.78 2015/08/24 22:21:27 pooka Exp $	*/
+/*	$NetBSD: ip6_forward.c,v 1.79 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$KAME: ip6_forward.c,v 1.109 2002/09/11 08:10:17 sakane Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip6_forward.c,v 1.78 2015/08/24 22:21:27 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip6_forward.c,v 1.79 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_gateway.h"
@@ -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;
 }

Index: src/sys/netinet6/ip6_input.c
diff -u src/sys/netinet6/ip6_input.c:1.159 src/sys/netinet6/ip6_input.c:1.160
--- src/sys/netinet6/ip6_input.c:1.159	Thu May 19 08:53:25 2016
+++ src/sys/netinet6/ip6_input.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6_input.c,v 1.159 2016/05/19 08:53:25 ozaki-r Exp $	*/
+/*	$NetBSD: ip6_input.c,v 1.160 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.159 2016/05/19 08:53:25 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.160 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_gateway.h"
@@ -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, str
 
 		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);

Index: src/sys/netinet6/ip6_mroute.c
diff -u src/sys/netinet6/ip6_mroute.c:1.109 src/sys/netinet6/ip6_mroute.c:1.110
--- src/sys/netinet6/ip6_mroute.c:1.109	Mon Aug 24 22:21:27 2015
+++ src/sys/netinet6/ip6_mroute.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6_mroute.c,v 1.109 2015/08/24 22:21:27 pooka Exp $	*/
+/*	$NetBSD: ip6_mroute.c,v 1.110 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$KAME: ip6_mroute.c,v 1.49 2001/07/25 09:21:18 jinmei Exp $	*/
 
 /*
@@ -117,7 +117,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip6_mroute.c,v 1.109 2015/08/24 22:21:27 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip6_mroute.c,v 1.110 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -1080,8 +1080,8 @@ ip6_mforward(struct ip6_hdr *ip6, struct
 			    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 *if
 	}			/* 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 
 	 * 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;

Index: src/sys/netinet6/ip6_var.h
diff -u src/sys/netinet6/ip6_var.h:1.64 src/sys/netinet6/ip6_var.h:1.65
--- src/sys/netinet6/ip6_var.h:1.64	Tue Jan 20 21:27:36 2015
+++ src/sys/netinet6/ip6_var.h	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6_var.h,v 1.64 2015/01/20 21:27:36 roy Exp $	*/
+/*	$NetBSD: ip6_var.h,v 1.65 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $	*/
 
 /*
@@ -323,7 +323,7 @@ int	icmp6_ctloutput(int, struct socket *
 
 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 *);

Index: src/sys/netinet6/mld6.c
diff -u src/sys/netinet6/mld6.c:1.65 src/sys/netinet6/mld6.c:1.66
--- src/sys/netinet6/mld6.c:1.65	Fri Jun 10 13:27:16 2016
+++ src/sys/netinet6/mld6.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: mld6.c,v 1.65 2016/06/10 13:27:16 ozaki-r Exp $	*/
+/*	$NetBSD: mld6.c,v 1.66 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$KAME: mld6.c,v 1.25 2001/01/16 14:14:18 itojun Exp $	*/
 
 /*
@@ -102,7 +102,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.65 2016/06/10 13:27:16 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.66 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -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

Index: src/sys/netinet6/nd6_nbr.c
diff -u src/sys/netinet6/nd6_nbr.c:1.118 src/sys/netinet6/nd6_nbr.c:1.119
--- src/sys/netinet6/nd6_nbr.c:1.118	Fri Jun 10 13:27:16 2016
+++ src/sys/netinet6/nd6_nbr.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: nd6_nbr.c,v 1.118 2016/06/10 13:27:16 ozaki-r Exp $	*/
+/*	$NetBSD: nd6_nbr.c,v 1.119 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.118 2016/06/10 13:27:16 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.119 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -96,7 +96,7 @@ static int dad_maxtry = 15;	/* max # of 
 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, in
 	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, in
 	    (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, in
 	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 s
 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, in
 	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, in
 
 	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, in
 	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, in
 	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, in
 		LLE_WUNLOCK(ln);
 
 	ICMP6_STATINC(ICMP6_STAT_BADNA);
+	m_put_rcvif_psref(ifp, &psref);
 	m_freem(m);
 }
 

Index: src/sys/netinet6/nd6_rtr.c
diff -u src/sys/netinet6/nd6_rtr.c:1.110 src/sys/netinet6/nd6_rtr.c:1.111
--- src/sys/netinet6/nd6_rtr.c:1.110	Tue Apr 26 08:44:45 2016
+++ src/sys/netinet6/nd6_rtr.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: nd6_rtr.c,v 1.110 2016/04/26 08:44:45 ozaki-r Exp $	*/
+/*	$NetBSD: nd6_rtr.c,v 1.111 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$KAME: nd6_rtr.c,v 1.95 2001/02/07 08:09:47 itojun Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.110 2016/04/26 08:44:45 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.111 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -131,14 +131,21 @@ nd6_is_llinfo_probreach(struct nd_defrou
 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, in
 	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, in
 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, in
 	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, in
 	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, in
 			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, in
     }
 
  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);
 }
 

Index: src/sys/netinet6/raw_ip6.c
diff -u src/sys/netinet6/raw_ip6.c:1.143 src/sys/netinet6/raw_ip6.c:1.144
--- src/sys/netinet6/raw_ip6.c:1.143	Thu May 12 02:24:17 2016
+++ src/sys/netinet6/raw_ip6.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: raw_ip6.c,v 1.143 2016/05/12 02:24:17 ozaki-r Exp $	*/
+/*	$NetBSD: raw_ip6.c,v 1.144 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$KAME: raw_ip6.c,v 1.82 2001/07/23 18:57:56 jinmei Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.143 2016/05/12 02:24:17 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.144 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ipsec.h"
@@ -260,8 +260,11 @@ rip6_input(struct mbuf **mp, int *offp, 
 		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 socke
 	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 socke
 	 * 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 socke
 		}
 	}
 
-	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 socke
 		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 s
 	    &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;
 }
 

Index: src/sys/netinet6/sctp6_usrreq.c
diff -u src/sys/netinet6/sctp6_usrreq.c:1.4 src/sys/netinet6/sctp6_usrreq.c:1.5
--- src/sys/netinet6/sctp6_usrreq.c:1.4	Mon Apr 25 21:21:02 2016
+++ src/sys/netinet6/sctp6_usrreq.c	Fri Jun 10 13:31:44 2016
@@ -1,5 +1,5 @@
 /* $KAME: sctp6_usrreq.c,v 1.38 2005/08/24 08:08:56 suz Exp $ */
-/* $NetBSD: sctp6_usrreq.c,v 1.4 2016/04/25 21:21:02 rjs Exp $ */
+/* $NetBSD: sctp6_usrreq.c,v 1.5 2016/06/10 13:31:44 ozaki-r Exp $ */
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Cisco Systems, Inc.
@@ -33,7 +33,7 @@
  * SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sctp6_usrreq.c,v 1.4 2016/04/25 21:21:02 rjs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sctp6_usrreq.c,v 1.5 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -160,8 +160,8 @@ sctp6_input(struct mbuf **mp, int *offp,
 	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.
 		 */

Index: src/sys/netinet6/udp6_output.c
diff -u src/sys/netinet6/udp6_output.c:1.50 src/sys/netinet6/udp6_output.c:1.51
--- src/sys/netinet6/udp6_output.c:1.50	Mon Aug 24 22:21:27 2015
+++ src/sys/netinet6/udp6_output.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: udp6_output.c,v 1.50 2015/08/24 22:21:27 pooka Exp $	*/
+/*	$NetBSD: udp6_output.c,v 1.51 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$KAME: udp6_output.c,v 1.43 2001/10/15 09:19:52 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: udp6_output.c,v 1.50 2015/08/24 22:21:27 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udp6_output.c,v 1.51 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -232,9 +232,8 @@ udp6_output(struct in6pcb * const in6p, 
 			    &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

Index: src/sys/netinet6/udp6_usrreq.c
diff -u src/sys/netinet6/udp6_usrreq.c:1.122 src/sys/netinet6/udp6_usrreq.c:1.123
--- src/sys/netinet6/udp6_usrreq.c:1.122	Tue Apr 26 08:44:45 2016
+++ src/sys/netinet6/udp6_usrreq.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: udp6_usrreq.c,v 1.122 2016/04/26 08:44:45 ozaki-r Exp $	*/
+/*	$NetBSD: udp6_usrreq.c,v 1.123 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$KAME: udp6_usrreq.c,v 1.86 2001/05/27 17:33:00 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.122 2016/04/26 08:44:45 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.123 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -519,7 +519,7 @@ udp6_input_checksum(struct mbuf *m, cons
 	}
 
 	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);

Index: src/sys/netipsec/ipsec_input.c
diff -u src/sys/netipsec/ipsec_input.c:1.35 src/sys/netipsec/ipsec_input.c:1.36
--- src/sys/netipsec/ipsec_input.c:1.35	Thu Jan 21 15:41:30 2016
+++ src/sys/netipsec/ipsec_input.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipsec_input.c,v 1.35 2016/01/21 15:41:30 riastradh Exp $	*/
+/*	$NetBSD: ipsec_input.c,v 1.36 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/sys/netipsec/ipsec_input.c,v 1.2.4.2 2003/03/28 20:32:53 sam Exp $	*/
 /*	$OpenBSD: ipsec_input.c,v 1.63 2003/02/20 18:35:43 deraadt Exp $	*/
 
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipsec_input.c,v 1.35 2016/01/21 15:41:30 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipsec_input.c,v 1.36 2016/06/10 13:31:44 ozaki-r Exp $");
 
 /*
  * IPsec input processing.
@@ -769,7 +769,8 @@ ipsec6_common_input_cb(struct mbuf *m, s
 		 */
 		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;
 		}

Index: src/sys/netipsec/key_debug.c
diff -u src/sys/netipsec/key_debug.c:1.12 src/sys/netipsec/key_debug.c:1.13
--- src/sys/netipsec/key_debug.c:1.12	Mon Mar 30 03:51:50 2015
+++ src/sys/netipsec/key_debug.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: key_debug.c,v 1.12 2015/03/30 03:51:50 ozaki-r Exp $	*/
+/*	$NetBSD: key_debug.c,v 1.13 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$FreeBSD: src/sys/netipsec/key_debug.c,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $	*/
 /*	$KAME: key_debug.c,v 1.26 2001/06/27 10:46:50 sakane Exp $	*/
 
@@ -33,7 +33,7 @@
 
 #ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: key_debug.c,v 1.12 2015/03/30 03:51:50 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: key_debug.c,v 1.13 2016/06/10 13:31:44 ozaki-r Exp $");
 #endif
 
 #include "opt_inet.h"
@@ -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) {

Index: src/sys/netipsec/xform_ipip.c
diff -u src/sys/netipsec/xform_ipip.c:1.38 src/sys/netipsec/xform_ipip.c:1.39
--- src/sys/netipsec/xform_ipip.c:1.38	Thu May 12 02:24:17 2016
+++ src/sys/netipsec/xform_ipip.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: xform_ipip.c,v 1.38 2016/05/12 02:24:17 ozaki-r Exp $	*/
+/*	$NetBSD: xform_ipip.c,v 1.39 2016/06/10 13:31:44 ozaki-r Exp $	*/
 /*	$FreeBSD: src/sys/netipsec/xform_ipip.c,v 1.3.2.1 2003/01/24 05:11:36 sam Exp $	*/
 /*	$OpenBSD: ip_ipip.c,v 1.25 2002/06/10 18:04:55 itojun Exp $ */
 
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xform_ipip.c,v 1.38 2016/05/12 02:24:17 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xform_ipip.c,v 1.39 2016/06/10 13:31:44 ozaki-r Exp $");
 
 /*
  * IP-inside-IP processing
@@ -330,8 +330,8 @@ _ipip_input(struct mbuf *m, int iphlen, 
 	}
 
 	/* 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) {

Index: src/sys/netmpls/mpls_ttl.c
diff -u src/sys/netmpls/mpls_ttl.c:1.7 src/sys/netmpls/mpls_ttl.c:1.8
--- src/sys/netmpls/mpls_ttl.c:1.7	Fri Jun 10 13:27:16 2016
+++ src/sys/netmpls/mpls_ttl.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: mpls_ttl.c,v 1.7 2016/06/10 13:27:16 ozaki-r Exp $ */
+/*	$NetBSD: mpls_ttl.c,v 1.8 2016/06/10 13:31:44 ozaki-r Exp $ */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -97,7 +97,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mpls_ttl.c,v 1.7 2016/06/10 13:27:16 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mpls_ttl.c,v 1.8 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -311,7 +311,7 @@ mpls_icmp_error(struct mbuf *n, int type
 	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;

Index: src/sys/netnatm/natm.c
diff -u src/sys/netnatm/natm.c:1.51 src/sys/netnatm/natm.c:1.52
--- src/sys/netnatm/natm.c:1.51	Fri Jun 10 13:27:16 2016
+++ src/sys/netnatm/natm.c	Fri Jun 10 13:31:44 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: natm.c,v 1.51 2016/06/10 13:27:16 ozaki-r Exp $	*/
+/*	$NetBSD: natm.c,v 1.52 2016/06/10 13:31:44 ozaki-r Exp $	*/
 
 /*
  * Copyright (c) 1996 Charles D. Cranor and Washington University.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: natm.c,v 1.51 2016/06/10 13:27:16 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: natm.c,v 1.52 2016/06/10 13:31:44 ozaki-r Exp $");
 
 #include <sys/param.h>
 #include <sys/kmem.h>
@@ -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 */

Index: src/sys/sys/mbuf.h
diff -u src/sys/sys/mbuf.h:1.163 src/sys/sys/mbuf.h:1.164
--- src/sys/sys/mbuf.h:1.163	Fri Jun 10 13:27:17 2016
+++ src/sys/sys/mbuf.h	Fri Jun 10 13:31:45 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: mbuf.h,v 1.163 2016/06/10 13:27:17 ozaki-r Exp $	*/
+/*	$NetBSD: mbuf.h,v 1.164 2016/06/10 13:31:45 ozaki-r Exp $	*/
 
 /*-
  * Copyright (c) 1996, 1997, 1999, 2001, 2007 The NetBSD Foundation, Inc.
@@ -76,6 +76,7 @@
 #if defined(_KERNEL)
 #include <sys/percpu_types.h>
 #include <sys/socket.h>	/* for AF_UNSPEC */
+#include <sys/psref.h>
 #endif /* defined(_KERNEL) */
 
 /* For offsetof() */
@@ -87,6 +88,8 @@
 
 #include <uvm/uvm_param.h>	/* for MIN_PAGE_SIZE */
 
+#include <net/if.h>
+
 /*
  * 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, s
 }
 
 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_ */

Reply via email to