this diff is about fixing some semantic issues with the current
interface input handler list processing. i was a bit worried it would
cause a small performance hit, but it seems it has the opposite effect
and is actually slightly faster. so in my opinion it is more correct,
but also improves performance.

originially the network stack only really dealt with layer 3 protocols
like ipv4, arp, ipv6, and so on. this meant ethernet drivers (ie, 90% of
network drivers) had to pull the ethernet header apart in their hardware
interrupt handlers before they could throw IP packets over the wall
(read queue packets for softnet to process).

etherent got complicated though. there's a whole bunch of pseudo/virtual
interfaces that do interesting things at the ethernet level, and when we
were doing the intiial mpsafe network stack work, none of them were
mpsafe. this meant that we couldn't pull ethernet headers apart without
taking the big lock, which meant that mpsafe hardware interrupt handlers
for nics wouldn't be able to run completely big lock free in moderately
interesting network configs.

so to help out in the initial mpsafe work, we decided to throw ethernet
packets straight off the ring over to softnet and pull ethernet apart
there. this let the interrupts run without biglock, but the virtual
ethernet interface drivers weren't mpsafe yet. to mitigate against that,
we made processing for them optional. since then we have made pretty
much all the pseudo interfaces mpsafe though.

so the currently situation is that by default, the softnet interface
input handler for ethernet interfaces simply looks at the protocol and
splits it up into ip/arp/etc. when you enable somethiing like vlan(4) on
an interface, it prepends an input handler to normal ethernet one. this
handler acts like a filter, so the vlan one takes vlan encapsulated
packets away and lets the rest fall through to the normal ethernet one.

the bridge input handler looks at the mac address on the packet forwards
it based on the address.

the semantic problems referred to above kick in if you enable bridge and
vlan at the same time. depending on the order in which you attach them
to the physical interface, they will filter in different orders. if you
enable bridge after vlan, packets will be sent to other ports regardless
of the vlan tags on the packet. this sucks if you want to land a vlan on
the current box, but bridge everythign else.

im arguing that the interaction between vlan interfaces and bridges
should be deterministic. and all the virtual interfaces actually.

the semantics im suggested are documented as comments in ether_input in
the diff below, but i'll list them here too:

 * Ethernet input has several "phases" of filtering packets to
 * support virtual/pseudo interfaces before actual layer 3 protocol
 * handling.
 *
 * First phase:
 *
 * The first phase supports drivers that aggregate multiple Ethernet
 * ports into a single logical interface, ie, aggr(4) and trunk(4).
 * These drivers intercept packets by swapping out the if_input handler
 * on the "port" interfaces to steal the packets before they get here
 * to ether_input().

 * Second phase: service delimited packet filtering.
 *
 * Let vlan(4) and svlan(4) look at "service delimited"
 * packets. If a virtual interface does not exist to take
 * those packets, they're returned to ether_input() so a
 * bridge can have a go at forwarding them.

 * Third phase: bridge processing.
 *
 * Give the packet to a bridge interface, ie, bridge(4),
 * switch(4), or tpmr(4), if it is configured. A bridge
 * may take the packet and forward it to another port, or it
 * may return it here to ether_input() to support local
 * delivery to this port.

 * Fourth phase: drop service delimited packets.
 *
 * If the packet has a tag, and a bridge didn't want it,
 * it's not for this port.

 * Fifth phase: destination address check.
 *
 * Is the packet specifically addressed to this port?
         * If it's not for this port, it could be for carp(4).
         * If not, it must be multicast or broadcast to go further.

 * Sixth phase: protocol demux.
 *
 * At this point it is known that the packet is destined
 * for layer 3 protocol handling on the local port.

another motivation for doing this is that jmatthew@ tried to convert the
srpl holding the interface input handlers to an smrl, and it blew up cos
it's possible to do a context switch in the network stack. you're not
supposed to do that with srps either, but they're a bit more forgiving.
getting rid of the list means another step closer to deprecating srps.

Index: net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.611
diff -u -p -r1.611 if.c
--- net/if.c    30 Jun 2020 09:31:38 -0000      1.611
+++ net/if.c    9 Jul 2020 10:15:36 -0000
@@ -631,8 +631,6 @@ if_attach_common(struct ifnet *ifp)
        if (ifp->if_enqueue == NULL)
                ifp->if_enqueue = if_enqueue_ifq;
        ifp->if_llprio = IFQ_DEFPRIO;
-
-       SRPL_INIT(&ifp->if_inputs);
 }
 
 void
@@ -805,109 +803,6 @@ if_output_local(struct ifnet *ifp, struc
        return (ifiq_enqueue(ifiq, m) == 0 ? 0 : ENOBUFS);
 }
 
-struct ifih {
-       SRPL_ENTRY(ifih)          ifih_next;
-       int                     (*ifih_input)(struct ifnet *, struct mbuf *,
-                                     void *);
-       void                     *ifih_cookie;
-       int                       ifih_refcnt;
-       struct refcnt             ifih_srpcnt;
-};
-
-void   if_ih_ref(void *, void *);
-void   if_ih_unref(void *, void *);
-
-struct srpl_rc ifih_rc = SRPL_RC_INITIALIZER(if_ih_ref, if_ih_unref, NULL);
-
-void
-if_ih_insert(struct ifnet *ifp, int (*input)(struct ifnet *, struct mbuf *,
-    void *), void *cookie)
-{
-       struct ifih *ifih;
-
-       /* the kernel lock guarantees serialised modifications to if_inputs */
-       KERNEL_ASSERT_LOCKED();
-
-       SRPL_FOREACH_LOCKED(ifih, &ifp->if_inputs, ifih_next) {
-               if (ifih->ifih_input == input && ifih->ifih_cookie == cookie) {
-                       ifih->ifih_refcnt++;
-                       break;
-               }
-       }
-
-       if (ifih == NULL) {
-               ifih = malloc(sizeof(*ifih), M_DEVBUF, M_WAITOK);
-
-               ifih->ifih_input = input;
-               ifih->ifih_cookie = cookie;
-               ifih->ifih_refcnt = 1;
-               refcnt_init(&ifih->ifih_srpcnt);
-               SRPL_INSERT_HEAD_LOCKED(&ifih_rc, &ifp->if_inputs,
-                   ifih, ifih_next);
-       }
-}
-
-void
-if_ih_ref(void *null, void *i)
-{
-       struct ifih *ifih = i;
-
-       refcnt_take(&ifih->ifih_srpcnt);
-}
-
-void
-if_ih_unref(void *null, void *i)
-{
-       struct ifih *ifih = i;
-
-       refcnt_rele_wake(&ifih->ifih_srpcnt);
-}
-
-void
-if_ih_remove(struct ifnet *ifp, int (*input)(struct ifnet *, struct mbuf *,
-    void *), void *cookie)
-{
-       struct ifih *ifih;
-
-       /* the kernel lock guarantees serialised modifications to if_inputs */
-       KERNEL_ASSERT_LOCKED();
-
-       SRPL_FOREACH_LOCKED(ifih, &ifp->if_inputs, ifih_next) {
-               if (ifih->ifih_input == input && ifih->ifih_cookie == cookie)
-                       break;
-       }
-
-       KASSERT(ifih != NULL);
-
-       if (--ifih->ifih_refcnt == 0) {
-               SRPL_REMOVE_LOCKED(&ifih_rc, &ifp->if_inputs, ifih,
-                   ifih, ifih_next);
-
-               refcnt_finalize(&ifih->ifih_srpcnt, "ifihrm");
-               free(ifih, M_DEVBUF, sizeof(*ifih));
-       }
-}
-
-static void
-if_ih_input(struct ifnet *ifp, struct mbuf *m)
-{
-       struct ifih *ifih;
-       struct srp_ref sr;
-
-       /*
-        * Pass this mbuf to all input handlers of its
-        * interface until it is consumed.
-        */
-       SRPL_FOREACH(ifih, &sr, &ifp->if_inputs, ifih_next) {
-               if ((*ifih->ifih_input)(ifp, m, ifih->ifih_cookie))
-                       break;
-       }
-       SRPL_LEAVE(&sr);
-
-       if (ifih == NULL)
-               m_freem(m);
-}
-
 void
 if_input_process(struct ifnet *ifp, struct mbuf_list *ml)
 {
@@ -933,7 +828,7 @@ if_input_process(struct ifnet *ifp, stru
         */
        NET_LOCK();
        while ((m = ml_dequeue(ml)) != NULL)
-               if_ih_input(ifp, m);
+               (*ifp->if_input)(ifp, m);
        NET_UNLOCK();
 }
 
@@ -960,7 +855,7 @@ if_vinput(struct ifnet *ifp, struct mbuf
        }
 #endif
 
-       if_ih_input(ifp, m);
+       (*ifp->if_input)(ifp, m);
 }
 
 void
Index: net/if_aggr.c
===================================================================
RCS file: /cvs/src/sys/net/if_aggr.c,v
retrieving revision 1.31
diff -u -p -r1.31 if_aggr.c
--- net/if_aggr.c       17 Jun 2020 06:45:22 -0000      1.31
+++ net/if_aggr.c       9 Jul 2020 10:15:36 -0000
@@ -332,6 +332,7 @@ struct aggr_port {
        uint32_t                 p_mtu;
 
        int (*p_ioctl)(struct ifnet *, u_long, caddr_t);
+       void (*p_input)(struct ifnet *, struct mbuf *);
        int (*p_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
            struct rtentry *);
 
@@ -723,13 +724,14 @@ aggr_eh_is_slow(const struct ether_heade
            eh->ether_type == htons(ETHERTYPE_SLOW));
 }
 
-static int
-aggr_input(struct ifnet *ifp0, struct mbuf *m, void *cookie)
+static void
+aggr_input(struct ifnet *ifp0, struct mbuf *m)
 {
-       struct ether_header *eh;
-       struct aggr_port *p = cookie;
+       struct arpcom *ac0 = (struct arpcom *)ifp0;
+       struct aggr_port *p = ac0->ac_trunkport;
        struct aggr_softc *sc = p->p_aggr;
        struct ifnet *ifp = &sc->sc_if;
+       struct ether_header *eh;
        int hlen = sizeof(*eh);
 
        if (!ISSET(ifp->if_flags, IFF_RUNNING))
@@ -745,7 +747,7 @@ aggr_input(struct ifnet *ifp0, struct mb
                        m = m_pullup(m, hlen);
                        if (m == NULL) {
                                /* short++ */
-                               return (1);
+                               return;
                        }
                        eh = mtod(m, struct ether_header *);
                }
@@ -756,7 +758,7 @@ aggr_input(struct ifnet *ifp0, struct mb
                case SLOWPROTOCOLS_SUBTYPE_LACP_MARKER:
                        if (mq_enqueue(&p->p_rxm_mq, m) == 0)
                                task_add(systq, &p->p_rxm_task);
-                       return (1);
+                       return;
                default:
                        break;
                }
@@ -770,11 +772,10 @@ aggr_input(struct ifnet *ifp0, struct mb
 
        if_vinput(ifp, m);
 
-       return (1);
+       return;
 
 drop:
        m_freem(m);
-       return (1);
 }
 
 static int
@@ -1072,6 +1073,10 @@ aggr_add_port(struct aggr_softc *sc, con
        if (ifp0->if_type != IFT_ETHER)
                return (EPROTONOSUPPORT);
 
+       error = ether_is_brport(ifp0);
+       if (error != 0)
+               return (error);
+
        if (ifp0->if_hardmtu < ifp->if_mtu)
                return (ENOBUFS);
 
@@ -1103,6 +1108,7 @@ aggr_add_port(struct aggr_softc *sc, con
        CTASSERT(sizeof(p->p_lladdr) == sizeof(ac0->ac_enaddr));
        memcpy(p->p_lladdr, ac0->ac_enaddr, sizeof(p->p_lladdr));
        p->p_ioctl = ifp0->if_ioctl;
+       p->p_input = ifp0->if_input;
        p->p_output = ifp0->if_output;
 
        error = aggr_group(sc, p, SIOCADDMULTI);
@@ -1161,12 +1167,18 @@ aggr_add_port(struct aggr_softc *sc, con
 
        aggr_update_capabilities(sc);
 
+       /*
+         * use (and modification) of ifp->if_input and ac->ac_trunkport
+         * is protected by NET_LOCK.
+        */
+
        ac0->ac_trunkport = p;
+
        /* make sure p is visible before handlers can run */
        membar_producer();
        ifp0->if_ioctl = aggr_p_ioctl;
+       ifp0->if_input = aggr_input;
        ifp0->if_output = aggr_p_output;
-       if_ih_insert(ifp0, aggr_input, p);
 
        aggr_mux(sc, p, LACP_MUX_E_BEGIN);
        aggr_rxm(sc, p, LACP_RXM_E_BEGIN);
@@ -1385,10 +1397,13 @@ aggr_p_dtor(struct aggr_softc *sc, struc
        timeout_del(&p->p_current_while_timer);
        timeout_del(&p->p_wait_while_timer);
 
-       if_ih_remove(ifp0, aggr_input, p);
+       /*
+         * use (and modification) of ifp->if_input and ac->ac_trunkport
+         * is protected by NET_LOCK.
+        */
 
        ac0->ac_trunkport = NULL;
-
+       ifp0->if_input = p->p_input;
        ifp0->if_ioctl = p->p_ioctl;
        ifp0->if_output = p->p_output;
 
Index: net/if_bridge.c
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.340
diff -u -p -r1.340 if_bridge.c
--- net/if_bridge.c     24 Jun 2020 22:03:42 -0000      1.340
+++ net/if_bridge.c     9 Jul 2020 10:15:36 -0000
@@ -109,7 +109,8 @@ void        bridge_ifdetach(void *);
 void   bridge_spandetach(void *);
 int    bridge_ifremove(struct bridge_iflist *);
 void   bridge_spanremove(struct bridge_iflist *);
-int    bridge_input(struct ifnet *, struct mbuf *, void *);
+struct mbuf *
+       bridge_input(struct ifnet *, struct mbuf *, void *);
 void   bridge_process(struct ifnet *, struct mbuf *);
 void   bridgeintr_frame(struct ifnet *, struct ifnet *, struct mbuf *);
 void   bridge_bifgetstp(struct bridge_softc *, struct bridge_iflist *,
@@ -149,6 +150,11 @@ struct niqueue bridgeintrq = NIQUEUE_INI
 struct if_clone bridge_cloner =
     IF_CLONE_INITIALIZER("bridge", bridge_clone_create, bridge_clone_destroy);
 
+const struct ether_brport bridge_brport = {
+       bridge_input,
+       NULL,
+};
+
 void
 bridgeattach(int n)
 {
@@ -198,8 +204,6 @@ bridge_clone_create(struct if_clone *ifc
            DLT_EN10MB, ETHER_HDR_LEN);
 #endif
 
-       if_ih_insert(ifp, ether_input, NULL);
-
        return (0);
 }
 
@@ -236,10 +240,6 @@ bridge_clone_destroy(struct ifnet *ifp)
        /* Undo pseudo-driver changes. */
        if_deactivate(ifp);
 
-       if_ih_remove(ifp, ether_input, NULL);
-
-       KASSERT(SRPL_EMPTY_LOCKED(&ifp->if_inputs));
-
        if_detach(ifp);
 
        free(sc, M_DEVBUF, sizeof *sc);
@@ -273,14 +273,6 @@ bridge_ioctl(struct ifnet *ifp, u_long c
                        break;
 
                ifs = ifunit(req->ifbr_ifsname);
-
-               /* try to create the interface if it does't exist */
-               if (ifs == NULL) {
-                       error = if_clone_create(req->ifbr_ifsname, 0);
-                       if (error == 0)
-                               ifs = ifunit(req->ifbr_ifsname);
-               }
-
                if (ifs == NULL) {                      /* no such interface */
                        error = ENOENT;
                        break;
@@ -297,6 +289,10 @@ bridge_ioctl(struct ifnet *ifp, u_long c
                        break;
                }
 
+               error = ether_is_brport(ifp);
+               if (error != 0)
+                       break;
+
                /* If it's in the span list, it can't be a member. */
                SMR_SLIST_FOREACH_LOCKED(bif, &sc->sc_spanlist, bif_next) {
                        if (bif->ifp == ifs)
@@ -321,6 +317,14 @@ bridge_ioctl(struct ifnet *ifp, u_long c
                        break;
                }
 
+               /*
+                * XXX If the NET_LOCK() or ifpromisc() calls above
+                * had to sleep, then something else could have come
+                * along and taken over ifs while the kernel lock was
+                * released. Or worse, ifs could have been destroyed
+                * cos ifunit() is... optimistic.
+                */
+
                bif->bridge_sc = sc;
                bif->ifp = ifs;
                bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
@@ -329,7 +333,7 @@ bridge_ioctl(struct ifnet *ifp, u_long c
                ifs->if_bridgeidx = ifp->if_index;
                task_set(&bif->bif_dtask, bridge_ifdetach, bif);
                if_detachhook_add(ifs, &bif->bif_dtask);
-               if_ih_insert(bif->ifp, bridge_input, NULL);
+               ether_set_brport(bif->ifp, &bridge_brport);
                SMR_SLIST_INSERT_HEAD_LOCKED(&sc->sc_iflist, bif, bif_next);
                break;
        case SIOCBRDGDEL:
@@ -550,7 +554,7 @@ bridge_ifremove(struct bridge_iflist *bi
 
        SMR_SLIST_REMOVE_LOCKED(&sc->sc_iflist, bif, bridge_iflist, bif_next);
        if_detachhook_del(bif->ifp, &bif->bif_dtask);
-       if_ih_remove(bif->ifp, bridge_input, NULL);
+       ether_clr_brport(bif->ifp);
 
        smr_barrier();
 
@@ -1095,19 +1099,19 @@ bridge_ourether(struct ifnet *ifp, uint8
  * Receive input from an interface.  Queue the packet for bridging if its
  * not for us, and schedule an interrupt.
  */
-int
-bridge_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
+struct mbuf *
+bridge_input(struct ifnet *ifp, struct mbuf *m, void *null)
 {
        KASSERT(m->m_flags & M_PKTHDR);
 
        if (m->m_flags & M_PROTO1) {
                m->m_flags &= ~M_PROTO1;
-               return (0);
+               return (m);
        }
 
        niq_enqueue(&bridgeintrq, m);
 
-       return (1);
+       return (NULL);
 }
 
 void
Index: net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.261
diff -u -p -r1.261 if_ethersubr.c
--- net/if_ethersubr.c  24 Nov 2019 07:50:55 -0000      1.261
+++ net/if_ethersubr.c  9 Jul 2020 10:15:36 -0000
@@ -86,6 +86,7 @@ didn't get a copy, you may request one f
 #include <sys/errno.h>
 #include <sys/syslog.h>
 #include <sys/timeout.h>
+#include <sys/smr.h>
 
 #include <net/if.h>
 #include <net/netisr.h>
@@ -103,6 +104,16 @@ didn't get a copy, you may request one f
 #include <net/bpf.h>
 #endif
 
+#include "vlan.h"
+#if NVLAN > 0
+#include <net/if_vlan_var.h>
+#endif
+
+#include "carp.h"
+#if NCARP > 0
+#include <netinet/ip_carp.h>
+#endif
+
 #include "pppoe.h"
 #if NPPPOE > 0
 #include <net/if_pppoe.h>
@@ -343,30 +354,175 @@ ether_output(struct ifnet *ifp, struct m
        return (if_enqueue(ifp, m));
 }
 
+int
+ether_is_brport(struct ifnet *ifp)
+{
+       struct arpcom *ac = (struct arpcom *)ifp;
+
+       KERNEL_ASSERT_LOCKED();
+       if (SMR_PTR_GET_LOCKED(&ac->ac_brport) != NULL)
+               return (EBUSY);
+
+       return (0);
+}
+
+void
+ether_set_brport(struct ifnet *ifp, const struct ether_brport *eb)
+{
+       struct arpcom *ac = (struct arpcom *)ifp;
+
+       KERNEL_ASSERT_LOCKED();
+       KASSERTMSG(SMR_PTR_GET_LOCKED(&ac->ac_brport) == NULL,
+           "%s setting an already set brport", ifp->if_xname);
+
+       SMR_PTR_SET_LOCKED(&ac->ac_brport, eb);
+}
+
+void
+ether_clr_brport(struct ifnet *ifp)
+{
+       struct arpcom *ac = (struct arpcom *)ifp;
+
+       KERNEL_ASSERT_LOCKED();
+       KASSERTMSG(SMR_PTR_GET_LOCKED(&ac->ac_brport) != NULL,
+           "%s clearing an already clear brport", ifp->if_xname);
+
+       SMR_PTR_SET_LOCKED(&ac->ac_brport, NULL);
+}
+
+const struct ether_brport *
+ether_get_brport(struct ifnet *ifp)
+{
+       struct arpcom *ac = (struct arpcom *)ifp;
+       SMR_ASSERT_CRITICAL();
+       return (SMR_PTR_GET(&ac->ac_brport));
+}
+
+const struct ether_brport *
+ether_get_brport_locked(struct ifnet *ifp)
+{
+       struct arpcom *ac = (struct arpcom *)ifp;
+       KERNEL_ASSERT_LOCKED();
+       return (SMR_PTR_GET_LOCKED(&ac->ac_brport));
+}
+
 /*
- * Process a received Ethernet packet;
- * the packet is in the mbuf chain m without
- * the ether header, which is provided separately.
+ * Process a received Ethernet packet.
+ *
+ * Ethernet input has several "phases" of filtering packets to
+ * support virtual/pseudo interfaces before actual layer 3 protocol
+ * handling.
+ *
+ * First phase:
+ *
+ * The first phase supports drivers that aggregate multiple Ethernet
+ * ports into a single logical interface, ie, aggr(4) and trunk(4).
+ * These drivers intercept packets by swapping out the if_input handler
+ * on the "port" interfaces to steal the packets before they get here
+ * to ether_input().
  */
-int
-ether_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
+
+void
+ether_input(struct ifnet *ifp, struct mbuf *m)
 {
-       struct ether_header *eh;
        void (*input)(struct ifnet *, struct mbuf *);
+       struct ether_header *eh;
        u_int16_t etype;
        struct arpcom *ac;
+       const struct ether_brport *eb;
+       unsigned int sdelim = 0;
 
        /* Drop short frames */
-       if (m->m_len < ETHER_HDR_LEN)
+       if (m->m_len < sizeof(*eh))
                goto dropanyway;
 
-       ac = (struct arpcom *)ifp;
+       /*
+        * Second phase: service delimited packet filtering.
+        *
+        * Let vlan(4) and svlan(4) look at "service delimited"
+        * packets. If a virtual interface does not exist to take
+        * those packets, they're returned to ether_input() so a
+        * bridge can have a go at forwarding them.
+        */
+
        eh = mtod(m, struct ether_header *);
+       etype = ntohs(eh->ether_type);
+
+#if NVLAN > 0
+       if (ISSET(m->m_flags, M_VLANTAG)) {
+               m = vlan_input(ifp, m);
+               if (m == NULL)
+                       return;
+
+               sdelim = 1;
+       } else /* <-- avoid calling vlan_input again */
+#endif /* NVLAN > 0 */
+       if (etype == ETHERTYPE_VLAN || etype == ETHERTYPE_QINQ) {
+#if NVLAN > 0
+               m = vlan_input(ifp, m);
+               if (m == NULL)
+                       return;
+#endif /* NVLAN > 0 */
+
+               sdelim = 1;
+       }
+
+       /*
+        * Third phase: bridge processing.
+        *
+        * Give the packet to a bridge interface, ie, bridge(4),
+        * switch(4), or tpmr(4), if it is configured. A bridge
+        * may take the packet and forward it to another port, or it
+        * may return it here to ether_input() to support local
+        * delivery to this port.
+        */
+
+       ac = (struct arpcom *)ifp;
+
+       smr_read_enter();
+       eb = SMR_PTR_GET(&ac->ac_brport);
+       if (eb != NULL) {
+               m = (*eb->eb_input)(ifp, m, eb->eb_port);
+               if (m == NULL) {
+                       smr_read_leave();
+                       return;
+               }
+       }
+       smr_read_leave();
 
-       /* Is the packet for us? */
+       /*
+        * Fourth phase: drop service delimited packets.
+        *
+        * If the packet has a tag, and a bridge didn't want it,
+        * it's not for this port.
+        */
+
+       if (sdelim)
+               goto dropanyway;
+
+       /*
+        * Fifth phase: destination address check.
+        *
+        * Is the packet specifically addressed to this port?
+        */
+
+       eh = mtod(m, struct ether_header *);
        if (memcmp(ac->ac_enaddr, eh->ether_dhost, ETHER_ADDR_LEN) != 0) {
+#if NCARP > 0
+               /*
+                * If it's not for this port, it could be for carp(4).
+                */
+               if (ifp->if_type != IFT_CARP &&
+                   !SRPL_EMPTY_LOCKED(&ifp->if_carp)) {
+                       m = carp_input(ifp, m);
+                       if (m == NULL)
+                               return;
+               }
+#endif
 
-               /* If not, it must be multicast or broadcast to go further */
+               /*
+                * If not, it must be multicast or broadcast to go further.
+                */
                if (!ETHER_IS_MULTICAST(eh->ether_dhost))
                        goto dropanyway;
 
@@ -384,17 +540,14 @@ ether_input(struct ifnet *ifp, struct mb
                        m->m_flags |= M_BCAST;
                else
                        m->m_flags |= M_MCAST;
-               ifp->if_imcasts++;
        }
 
        /*
-        * HW vlan tagged packets that were not collected by vlan(4) must
-        * be dropped now.
+        * Sixth phase: protocol demux.
+        *
+        * At this point it is known that the packet is destined
+        * for layer 3 protocol handling on the local port.
         */
-       if (m->m_flags & M_VLANTAG)
-               goto dropanyway;
-
-       etype = ntohs(eh->ether_type);
 
        switch (etype) {
        case ETHERTYPE_IP:
@@ -432,7 +585,7 @@ ether_input(struct ifnet *ifp, struct mb
 
                        if ((session = pipex_pppoe_lookup_session(m)) != NULL) {
                                pipex_pppoe_input(m, session);
-                               return (1);
+                               return;
                        }
                }
 #endif
@@ -440,7 +593,7 @@ ether_input(struct ifnet *ifp, struct mb
                        niq_enqueue(&pppoediscinq, m);
                else
                        niq_enqueue(&pppoeinq, m);
-               return (1);
+               return;
 #endif
 #ifdef MPLS
        case ETHERTYPE_MPLS:
@@ -451,7 +604,7 @@ ether_input(struct ifnet *ifp, struct mb
 #if NBPE > 0
        case ETHERTYPE_PBB:
                bpe_input(ifp, m);
-               return (1);
+               return;
 #endif
        default:
                goto dropanyway;
@@ -459,10 +612,9 @@ ether_input(struct ifnet *ifp, struct mb
 
        m_adj(m, sizeof(*eh));
        (*input)(ifp, m);
-       return (1);
+       return;
 dropanyway:
        m_freem(m);
-       return (1);
 }
 
 /*
@@ -522,12 +674,11 @@ ether_ifattach(struct ifnet *ifp)
        ifp->if_addrlen = ETHER_ADDR_LEN;
        ifp->if_hdrlen = ETHER_HDR_LEN;
        ifp->if_mtu = ETHERMTU;
+       ifp->if_input = ether_input;
        if (ifp->if_output == NULL)
                ifp->if_output = ether_output;
        ifp->if_rtrequest = ether_rtrequest;
 
-       if_ih_insert(ifp, ether_input, NULL);
-
        if (ifp->if_hardmtu == 0)
                ifp->if_hardmtu = ETHERMTU;
 
@@ -547,10 +698,6 @@ ether_ifdetach(struct ifnet *ifp)
 
        /* Undo pseudo-driver changes. */
        if_deactivate(ifp);
-
-       if_ih_remove(ifp, ether_input, NULL);
-
-       KASSERT(SRPL_EMPTY_LOCKED(&ifp->if_inputs));
 
        for (enm = LIST_FIRST(&ac->ac_multiaddrs);
            enm != NULL;
Index: net/if_loop.c
===================================================================
RCS file: /cvs/src/sys/net/if_loop.c,v
retrieving revision 1.90
diff -u -p -r1.90 if_loop.c
--- net/if_loop.c       8 Jan 2020 09:09:10 -0000       1.90
+++ net/if_loop.c       9 Jul 2020 10:15:36 -0000
@@ -143,7 +143,7 @@
 int    loioctl(struct ifnet *, u_long, caddr_t);
 void   loopattach(int);
 void   lortrequest(struct ifnet *, int, struct rtentry *);
-int    loinput(struct ifnet *, struct mbuf *, void *);
+void   loinput(struct ifnet *, struct mbuf *);
 int    looutput(struct ifnet *,
            struct mbuf *, struct sockaddr *, struct rtentry *);
 
@@ -175,6 +175,7 @@ loop_clone_create(struct if_clone *ifc, 
        ifp->if_xflags = IFXF_CLONED;
        ifp->if_rtrequest = lortrequest;
        ifp->if_ioctl = loioctl;
+       ifp->if_input = loinput;
        ifp->if_output = looutput;
        ifp->if_type = IFT_LOOP;
        ifp->if_hdrlen = sizeof(u_int32_t);
@@ -188,7 +189,6 @@ loop_clone_create(struct if_clone *ifc, 
 #if NBPFILTER > 0
        bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
 #endif
-       if_ih_insert(ifp, loinput, NULL);
        return (0);
 }
 
@@ -218,7 +218,6 @@ loop_clone_destroy(struct ifnet *ifp)
                rdomain = ifp->if_rdomain;
        }
 
-       if_ih_remove(ifp, loinput, NULL);
        if_detach(ifp);
 
        free(ifp, M_DEVBUF, sizeof(*ifp));
@@ -228,8 +227,8 @@ loop_clone_destroy(struct ifnet *ifp)
        return (0);
 }
 
-int
-loinput(struct ifnet *ifp, struct mbuf *m, void *cookie)
+void
+loinput(struct ifnet *ifp, struct mbuf *m)
 {
        int error;
 
@@ -239,8 +238,6 @@ loinput(struct ifnet *ifp, struct mbuf *
        error = if_input_local(ifp, m, m->m_pkthdr.ph_family);
        if (error)
                ifp->if_ierrors++;
-
-       return (1);
 }
 
 int
Index: net/if_switch.c
===================================================================
RCS file: /cvs/src/sys/net/if_switch.c,v
retrieving revision 1.30
diff -u -p -r1.30 if_switch.c
--- net/if_switch.c     6 Nov 2019 03:51:26 -0000       1.30
+++ net/if_switch.c     9 Jul 2020 10:15:36 -0000
@@ -68,7 +68,8 @@ int    switch_port_add(struct switch_softc
 void    switch_port_detach(void *);
 int     switch_port_del(struct switch_softc *, struct ifbreq *);
 int     switch_port_list(struct switch_softc *, struct ifbifconf *);
-int     switch_input(struct ifnet *, struct mbuf *, void *);
+struct mbuf *
+        switch_input(struct ifnet *, struct mbuf *, void *);
 struct mbuf
        *switch_port_ingress(struct switch_softc *, struct ifnet *,
            struct mbuf *);
@@ -119,6 +120,11 @@ struct rwlock switch_ifs_lk = RWLOCK_INI
 
 struct pool swfcl_pool;
 
+const struct ether_brport switch_brport = {
+       switch_input,
+       NULL,
+};
+
 void
 switchattach(int n)
 {
@@ -506,8 +512,8 @@ switch_port_add(struct switch_softc *sc,
        if ((ifs = ifunit(req->ifbr_ifsname)) == NULL)
                return (ENOENT);
 
-       if (ifs->if_bridgeidx != 0)
-               return (EBUSY);
+       if (ifs->if_type != IFT_ETHER)
+               return (EPROTONOSUPPORT);
 
        if (ifs->if_switchport != NULL) {
                swpo = (struct switch_port *)ifs->if_switchport;
@@ -517,21 +523,25 @@ switch_port_add(struct switch_softc *sc,
                        return (EBUSY);
        }
 
-       if (ifs->if_type == IFT_ETHER) {
-               if ((error = ifpromisc(ifs, 1)) != 0)
-                       return (error);
+       if ((error = ifpromisc(ifs, 1)) != 0)
+               return (error);
+
+       error = ether_is_brport(ifs);
+       if (error != 0) {
+               ifpromisc(ifs, 0);
+               return (error);
        }
 
        swpo = malloc(sizeof(*swpo), M_DEVBUF, M_NOWAIT|M_ZERO);
        if (swpo == NULL) {
-               if (ifs->if_type == IFT_ETHER)
-                       ifpromisc(ifs, 0);
+               ifpromisc(ifs, 0);
                return (ENOMEM);
        }
+
        swpo->swpo_switch = sc;
        swpo->swpo_ifindex = ifs->if_index;
        ifs->if_switchport = (caddr_t)swpo;
-       if_ih_insert(ifs, switch_input, NULL);
+       ether_set_brport(ifs, &switch_brport);
        swpo->swpo_port_no = swofp_assign_portno(sc, ifs->if_index);
        task_set(&swpo->swpo_dtask, switch_port_detach, ifs);
        if_detachhook_add(ifs, &swpo->swpo_dtask);
@@ -603,7 +613,7 @@ switch_port_detach(void *arg)
        ifp->if_switchport = NULL;
        if_detachhook_del(ifp, &swpo->swpo_dtask);
        ifpromisc(ifp, 0);
-       if_ih_remove(ifp, switch_input, NULL);
+       ether_clr_brport(ifp);
        TAILQ_REMOVE(&sc->sc_swpo_list, swpo, swpo_list_next);
        free(swpo, M_DEVBUF, sizeof(*swpo));
 }
@@ -633,19 +643,19 @@ switch_port_del(struct switch_softc *sc,
        return (error);
 }
 
-int
-switch_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
+struct mbuf *
+switch_input(struct ifnet *ifp, struct mbuf *m, void *null)
 {
        KASSERT(m->m_flags & M_PKTHDR);
 
        if (m->m_flags & M_PROTO1) {
                m->m_flags &= ~M_PROTO1;
-               return (0);
+               return (m);
        }
 
        niq_enqueue(&switchintrq, m);
 
-       return (1);
+       return (NULL);
 }
 
 
Index: net/if_tpmr.c
===================================================================
RCS file: /cvs/src/sys/net/if_tpmr.c,v
retrieving revision 1.10
diff -u -p -r1.10 if_tpmr.c
--- net/if_tpmr.c       12 Apr 2020 06:56:37 -0000      1.10
+++ net/if_tpmr.c       9 Jul 2020 10:15:36 -0000
@@ -91,6 +91,8 @@ struct tpmr_port {
 
        struct tpmr_softc       *p_tpmr;
        unsigned int             p_slot;
+
+       struct ether_brport      p_brport;
 };
 
 struct tpmr_softc {
@@ -281,10 +283,10 @@ tpmr_pf(struct ifnet *ifp0, int dir, str
 }
 #endif /* NPF > 0 */
 
-static int
-tpmr_input(struct ifnet *ifp0, struct mbuf *m, void *cookie)
+static struct mbuf *
+tpmr_input(struct ifnet *ifp0, struct mbuf *m, void *brport)
 {
-       struct tpmr_port *p = cookie;
+       struct tpmr_port *p = brport;
        struct tpmr_softc *sc = p->p_tpmr;
        struct ifnet *ifp = &sc->sc_if;
        struct tpmr_port *pn;
@@ -317,7 +319,7 @@ tpmr_input(struct ifnet *ifp0, struct mb
 #if NPF > 0
        if (!ISSET(ifp->if_flags, IFF_LINK1) &&
            (m = tpmr_pf(ifp0, PF_IN, m)) == NULL)
-               return (1);
+               return (NULL);
 #endif
 
        len = m->m_pkthdr.len;
@@ -353,11 +355,11 @@ tpmr_input(struct ifnet *ifp0, struct mb
        }
        smr_read_leave();
 
-       return (1);
+       return (NULL);
 
 drop:
        m_freem(m);
-       return (1);
+       return (NULL);
 }
 
 static int
@@ -520,7 +522,6 @@ tpmr_add_port(struct tpmr_softc *sc, con
 {
        struct ifnet *ifp = &sc->sc_if;
        struct ifnet *ifp0;
-       struct arpcom *ac0;
        struct tpmr_port **pp;
        struct tpmr_port *p;
        int i;
@@ -537,9 +538,9 @@ tpmr_add_port(struct tpmr_softc *sc, con
        if (ifp0->if_type != IFT_ETHER)
                return (EPROTONOSUPPORT);
 
-       ac0 = (struct arpcom *)ifp0;
-       if (ac0->ac_trunkport != NULL)
-               return (EBUSY);
+       error = ether_is_brport(ifp0);
+       if (error != 0)
+               return (error);
 
        /* let's try */
 
@@ -565,12 +566,20 @@ tpmr_add_port(struct tpmr_softc *sc, con
        if (error != 0)
                goto free;
 
+       /* this might have changed if we slept for malloc or ifpromisc */
+       error = ether_is_brport(ifp0);
+       if (error != 0)
+               goto unpromisc;
+
        task_set(&p->p_ltask, tpmr_p_linkch, p);
        if_linkstatehook_add(ifp0, &p->p_ltask);
 
        task_set(&p->p_dtask, tpmr_p_detach, p);
        if_detachhook_add(ifp0, &p->p_dtask);
 
+       p->p_brport.eb_input = tpmr_input;
+       p->p_brport.eb_port = p;
+
        /* commit */
        DPRINTF(sc, "%s %s trunkport: creating port\n",
            ifp->if_xname, ifp0->if_xname);
@@ -584,12 +593,9 @@ tpmr_add_port(struct tpmr_softc *sc, con
 
        p->p_slot = i;
 
-       ac0->ac_trunkport = p;
-       /* make sure p is visible before handlers can run */
-       membar_producer();
+       ether_set_brport(ifp0, &p->p_brport);
        ifp0->if_ioctl = tpmr_p_ioctl;
        ifp0->if_output = tpmr_p_output;
-       if_ih_insert(ifp0, tpmr_input, p);
 
        SMR_PTR_SET_LOCKED(pp, p);
 
@@ -597,6 +603,8 @@ tpmr_add_port(struct tpmr_softc *sc, con
 
        return (0);
 
+unpromisc:
+       ifpromisc(ifp0, 0);
 free:
        free(p, M_DEVBUF, sizeof(*p));
 put:
@@ -654,10 +662,19 @@ tpmr_del_port(struct tpmr_softc *sc, con
 static int
 tpmr_p_ioctl(struct ifnet *ifp0, u_long cmd, caddr_t data)
 {
-       struct arpcom *ac0 = (struct arpcom *)ifp0;
-       struct tpmr_port *p = ac0->ac_trunkport;
+       const struct ether_brport *eb = ether_get_brport_locked(ifp0);
+       struct tpmr_port *p;
        int error = 0;
 
+       KASSERTMSG(eb != NULL,
+           "%s: %s called without an ether_brport set",
+           ifp0->if_xname, __func__);
+       KASSERTMSG(eb->eb_input == tpmr_input,
+           "%s: %s called, but eb_input seems wrong (%p != tpmr_input())",
+           ifp0->if_xname, __func__, eb->eb_input);
+
+       p = eb->eb_port;
+
        switch (cmd) {
        case SIOCSIFADDR:
                error = EBUSY;
@@ -674,6 +691,7 @@ tpmr_p_ioctl(struct ifnet *ifp0, u_long 
 
                CTASSERT(sizeof(rp->rp_ifname) == sizeof(ifp->if_xname));
                memcpy(rp->rp_ifname, ifp->if_xname, sizeof(rp->rp_ifname));
+
                break;
        }
 
@@ -689,8 +707,9 @@ static int
 tpmr_p_output(struct ifnet *ifp0, struct mbuf *m, struct sockaddr *dst,
     struct rtentry *rt)
 {
-       struct arpcom *ac0 = (struct arpcom *)ifp0;
-       struct tpmr_port *p = ac0->ac_trunkport;
+       int (*p_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
+           struct rtentry *) = NULL;
+       const struct ether_brport *eb;
 
        /* restrict transmission to bpf only */
        if ((m_tag_find(m, PACKET_TAG_DLT, NULL) == NULL)) {
@@ -698,7 +717,20 @@ tpmr_p_output(struct ifnet *ifp0, struct
                return (EBUSY);
        }
 
-       return ((*p->p_output)(ifp0, m, dst, rt));
+       smr_read_enter();
+       eb = ether_get_brport(ifp0);
+       if (eb != NULL && eb->eb_input == tpmr_input) {
+               struct tpmr_port *p = eb->eb_port;
+               p_output = p->p_output; /* code doesn't go away */
+       }
+       smr_read_leave();
+
+       if (p_output == NULL) {
+               m_freem(m);
+               return (ENXIO);
+       }
+
+       return ((*p_output)(ifp0, m, dst, rt));
 }
 
 static void
@@ -706,18 +738,14 @@ tpmr_p_dtor(struct tpmr_softc *sc, struc
 {
        struct ifnet *ifp = &sc->sc_if;
        struct ifnet *ifp0 = p->p_ifp0;
-       struct arpcom *ac0 = (struct arpcom *)ifp0;
 
        DPRINTF(sc, "%s %s: destroying port\n",
            ifp->if_xname, ifp0->if_xname);
 
-       if_ih_remove(ifp0, tpmr_input, p);
-
        ifp0->if_ioctl = p->p_ioctl;
        ifp0->if_output = p->p_output;
-       membar_producer();
 
-       ac0->ac_trunkport = NULL;
+       ether_clr_brport(ifp0);
 
        sc->sc_nports--;
        SMR_PTR_SET_LOCKED(&sc->sc_ports[p->p_slot], NULL);
Index: net/if_trunk.c
===================================================================
RCS file: /cvs/src/sys/net/if_trunk.c,v
retrieving revision 1.146
diff -u -p -r1.146 if_trunk.c
--- net/if_trunk.c      17 Jun 2020 06:45:22 -0000      1.146
+++ net/if_trunk.c      9 Jul 2020 10:15:36 -0000
@@ -76,7 +76,7 @@ int    trunk_ether_delmulti(struct trunk_s
 void    trunk_ether_purgemulti(struct trunk_softc *);
 int     trunk_ether_cmdmulti(struct trunk_port *, u_long);
 int     trunk_ioctl_allports(struct trunk_softc *, u_long, caddr_t);
-int     trunk_input(struct ifnet *, struct mbuf *, void *);
+void    trunk_input(struct ifnet *, struct mbuf *);
 void    trunk_start(struct ifnet *);
 void    trunk_init(struct ifnet *);
 void    trunk_stop(struct ifnet *);
@@ -380,9 +380,11 @@ trunk_port_create(struct trunk_softc *tr
        if (tr->tr_port_create != NULL)
                error = (*tr->tr_port_create)(tp);
 
-       ac0->ac_trunkport = tp;
        /* Change input handler of the physical interface. */
-       if_ih_insert(ifp, trunk_input, tp);
+       tp->tp_input = ifp->if_input;
+       NET_ASSERT_LOCKED();
+       ac0->ac_trunkport = tp;
+       ifp->if_input = trunk_input;
 
        return (error);
 }
@@ -413,7 +415,8 @@ trunk_port_destroy(struct trunk_port *tp
        struct arpcom *ac0 = (struct arpcom *)ifp;
 
        /* Restore previous input handler. */
-       if_ih_remove(ifp, trunk_input, tp);
+       NET_ASSERT_LOCKED();
+       ifp->if_input = tp->tp_input;
        ac0->ac_trunkport = NULL;
 
        /* Remove multicast addresses from this port */
@@ -649,15 +652,24 @@ trunk_ioctl(struct ifnet *ifp, u_long cm
                        error = EPROTONOSUPPORT;
                        break;
                }
+
                /*
+                 * Use of ifp->if_input and ac->ac_trunkport is
+                 * protected by NET_LOCK, but that may not be true
+                 * in the future. The below comment and code flow is
+                 * maintained to help in that future.
+                *
                 * Serialize modifications to the trunk and trunk
                 * ports via the ifih SRP: detaching trunk_input
                 * from the trunk port will require all currently
                 * running trunk_input's on this port to finish
                 * granting us an exclusive access to it.
                 */
-               SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
-                       if_ih_remove(tp->tp_if, trunk_input, tp);
+               NET_ASSERT_LOCKED();
+               SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
+                       /* if_ih_remove(tp->tp_if, trunk_input, tp); */
+                       tp->tp_if->if_input = tp->tp_input;
+               }
                if (tr->tr_proto != TRUNK_PROTO_NONE)
                        error = tr->tr_detach(tr);
                if (error != 0)
@@ -671,9 +683,11 @@ trunk_ioctl(struct ifnet *ifp, u_long cm
                                tr->tr_proto = trunk_protos[i].ti_proto;
                                if (tr->tr_proto != TRUNK_PROTO_NONE)
                                        error = trunk_protos[i].ti_attach(tr);
-                               SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
-                                       if_ih_insert(tp->tp_if,
-                                           trunk_input, tp);
+                               SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
+                                       /* if_ih_insert(tp->tp_if,
+                                           trunk_input, tp); */
+                                       tp->tp_if->if_input = trunk_input;
+                               }
                                /* Update trunk capabilities */
                                tr->tr_capabilities = trunk_capabilities(tr);
                                goto out;
@@ -1118,14 +1132,18 @@ trunk_stop(struct ifnet *ifp)
                (*tr->tr_stop)(tr);
 }
 
-int
-trunk_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
+void
+trunk_input(struct ifnet *ifp, struct mbuf *m)
 {
-       struct trunk_softc *tr;
+       struct arpcom *ac0 = (struct arpcom *)ifp;
        struct trunk_port *tp;
+       struct trunk_softc *tr;
        struct ifnet *trifp = NULL;
        struct ether_header *eh;
 
+       if (m->m_len < sizeof(*eh))
+               goto bad;
+
        eh = mtod(m, struct ether_header *);
        if (ETHER_IS_MULTICAST(eh->ether_dhost))
                ifp->if_imcasts++;
@@ -1134,7 +1152,7 @@ trunk_input(struct ifnet *ifp, struct mb
        if (ifp->if_type != IFT_IEEE8023ADLAG)
                goto bad;
 
-       tp = (struct trunk_port *)cookie;
+       tp = (struct trunk_port *)ac0->ac_trunkport;
        if ((tr = (struct trunk_softc *)tp->tp_trunk) == NULL)
                goto bad;
 
@@ -1147,7 +1165,7 @@ trunk_input(struct ifnet *ifp, struct mb
                 * We stop here if the packet has been consumed
                 * by the protocol routine.
                 */
-               return (1);
+               return;
        }
 
        if ((trifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
@@ -1163,19 +1181,18 @@ trunk_input(struct ifnet *ifp, struct mb
                if (bcmp(&tr->tr_ac.ac_enaddr, eh->ether_dhost,
                    ETHER_ADDR_LEN)) {
                        m_freem(m);
-                       return (1);
+                       return;
                }
        }
 
 
        if_vinput(trifp, m);
-       return (1);
+       return;
 
  bad:
        if (trifp != NULL)
                trifp->if_ierrors++;
        m_freem(m);
-       return (1);
 }
 
 int
Index: net/if_trunk.h
===================================================================
RCS file: /cvs/src/sys/net/if_trunk.h,v
retrieving revision 1.29
diff -u -p -r1.29 if_trunk.h
--- net/if_trunk.h      7 Nov 2019 07:36:32 -0000       1.29
+++ net/if_trunk.h      9 Jul 2020 10:15:36 -0000
@@ -172,6 +172,7 @@ struct trunk_port {
        int     (*tp_ioctl)(struct ifnet *, u_long, caddr_t);
        int     (*tp_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
                    struct rtentry *);
+       void    (*tp_input)(struct ifnet *, struct mbuf *);
 
        SLIST_ENTRY(trunk_port)         tp_entries;
 };
Index: net/if_tun.c
===================================================================
RCS file: /cvs/src/sys/net/if_tun.c,v
retrieving revision 1.222
diff -u -p -r1.222 if_tun.c
--- net/if_tun.c        13 May 2020 00:48:06 -0000      1.222
+++ net/if_tun.c        9 Jul 2020 10:15:36 -0000
@@ -115,7 +115,7 @@ int tun_dev_poll(dev_t, int, struct proc
 int    tun_dev_kqfilter(dev_t, struct knote *);
 
 int    tun_ioctl(struct ifnet *, u_long, caddr_t);
-int    tun_input(struct ifnet *, struct mbuf *, void *);
+void   tun_input(struct ifnet *, struct mbuf *);
 int    tun_output(struct ifnet *, struct mbuf *, struct sockaddr *,
            struct rtentry *);
 int    tun_enqueue(struct ifnet *, struct mbuf *);
@@ -240,6 +240,7 @@ tun_create(struct if_clone *ifc, int uni
        if_counters_alloc(ifp);
 
        if ((flags & TUN_LAYER2) == 0) {
+               ifp->if_input = tun_input;
                ifp->if_output = tun_output;
                ifp->if_mtu = ETHERMTU;
                ifp->if_flags = (IFF_POINTOPOINT|IFF_MULTICAST);
@@ -253,8 +254,6 @@ tun_create(struct if_clone *ifc, int uni
 #if NBPFILTER > 0
                bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
 #endif
-
-               if_ih_insert(ifp, tun_input, NULL);
        } else {
                sc->sc_flags |= TUN_LAYER2;
                ether_fakeaddr(ifp);
@@ -320,9 +319,7 @@ tun_clone_destroy(struct ifnet *ifp)
        klist_invalidate(&sc->sc_wsel.si_note);
        splx(s);
 
-       if (!ISSET(sc->sc_flags, TUN_LAYER2))
-               if_ih_remove(ifp, tun_input, NULL);
-       else
+       if (ISSET(sc->sc_flags, TUN_LAYER2))
                ether_ifdetach(ifp);
 
        if_detach(ifp);
@@ -880,8 +877,8 @@ put:
        return (error);
 }
 
-int
-tun_input(struct ifnet *ifp, struct mbuf *m0, void *cookie)
+void
+tun_input(struct ifnet *ifp, struct mbuf *m0)
 {
        uint32_t                af;
 
@@ -909,8 +906,6 @@ tun_input(struct ifnet *ifp, struct mbuf
                m_freem(m0);
                break;
        }
-
-       return (1);
 }
 
 /*
Index: net/if_var.h
===================================================================
RCS file: /cvs/src/sys/net/if_var.h,v
retrieving revision 1.106
diff -u -p -r1.106 if_var.h
--- net/if_var.h        4 Jul 2020 08:06:08 -0000       1.106
+++ net/if_var.h        9 Jul 2020 10:15:36 -0000
@@ -159,7 +159,7 @@ struct ifnet {                              /* and the 
entries */
        struct  task if_linkstatetask;  /* [I] task to do route updates */
 
        /* procedure handles */
-       SRPL_HEAD(, ifih) if_inputs;    /* [K] input routines (dequeue) */
+       void    (*if_input)(struct ifnet *, struct mbuf *);
        int     (*if_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
                     struct rtentry *); /* output routine (enqueue) */
                                        /* link level output function */
@@ -368,11 +368,6 @@ void       ifa_add(struct ifnet *, struct ifad
 void   ifa_del(struct ifnet *, struct ifaddr *);
 void   ifa_update_broadaddr(struct ifnet *, struct ifaddr *,
            struct sockaddr *);
-
-void   if_ih_insert(struct ifnet *, int (*)(struct ifnet *, struct mbuf *,
-           void *), void *);
-void   if_ih_remove(struct ifnet *, int (*)(struct ifnet *, struct mbuf *,
-           void *), void *);
 
 void   if_addrhook_add(struct ifnet *, struct task *);
 void   if_addrhook_del(struct ifnet *, struct task *);
Index: net/if_vlan.c
===================================================================
RCS file: /cvs/src/sys/net/if_vlan.c,v
retrieving revision 1.203
diff -u -p -r1.203 if_vlan.c
--- net/if_vlan.c       1 Feb 2020 10:27:40 -0000       1.203
+++ net/if_vlan.c       9 Jul 2020 10:15:36 -0000
@@ -119,7 +119,6 @@ void        vlanattach(int count);
 int    vlan_clone_create(struct if_clone *, int);
 int    vlan_clone_destroy(struct ifnet *);
 
-int    vlan_input(struct ifnet *, struct mbuf *, void *);
 int    vlan_enqueue(struct ifnet *, struct mbuf *);
 void   vlan_start(struct ifqueue *ifq);
 int    vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
@@ -358,44 +357,45 @@ vlan_inject(struct mbuf *m, uint16_t typ
        return (m);
  }
 
-/*
- * vlan_input() returns 1 if it has consumed the packet, 0 otherwise.
- */
-int
-vlan_input(struct ifnet *ifp0, struct mbuf *m, void *cookie)
+struct mbuf *
+vlan_input(struct ifnet *ifp0, struct mbuf *m)
 {
        struct vlan_softc *sc;
+       struct ifnet *ifp;
        struct ether_vlan_header *evl;
-       struct ether_header *eh;
        struct vlan_list *tagh, *list;
-       uint16_t tag;
+       uint16_t vtag, tag;
        uint16_t etype;
        int rxprio;
 
-       eh = mtod(m, struct ether_header *);
-       etype = ntohs(eh->ether_type);
-
        if (m->m_flags & M_VLANTAG) {
+               vtag = m->m_pkthdr.ether_vtag;
                etype = ETHERTYPE_VLAN;
                tagh = vlan_tagh;
-       } else if ((etype == ETHERTYPE_VLAN) || (etype == ETHERTYPE_QINQ)) {
-               if (m->m_len < sizeof(*evl) &&
-                   (m = m_pullup(m, sizeof(*evl))) == NULL) {
-                       ifp0->if_ierrors++;
-                       return (1);
+       } else {
+               if (m->m_len < sizeof(*evl)) {
+                       m = m_pullup(m, sizeof(*evl));
+                       if (m == NULL)
+                               return (NULL);
                }
 
                evl = mtod(m, struct ether_vlan_header *);
-               m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag);
-               tagh = etype == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
-       } else {
-               /* Skip non-VLAN packets. */
-               return (0);
+               vtag = bemtoh16(&evl->evl_tag);
+               etype = bemtoh16(&evl->evl_encap_proto);
+               switch (etype) {
+               case ETHERTYPE_VLAN:
+                       tagh = vlan_tagh;
+                       break;
+               case ETHERTYPE_QINQ:
+                       tagh = svlan_tagh;
+                       break;
+               default:
+                       panic("%s: unexpected etype 0x%04x", __func__, etype);
+                       /* NOTREACHED */
+               }
        }
 
-       /* From now on ether_vtag is fine */
-       tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
-
+       tag = EVL_VLANOFTAG(vtag);
        list = &tagh[TAG_HASH(tag)];
        smr_read_enter();
        SMR_SLIST_FOREACH(sc, list, sc_list) {
@@ -407,7 +407,11 @@ vlan_input(struct ifnet *ifp0, struct mb
        }
        smr_read_leave();
 
-       if (sc == NULL || !ISSET(sc->sc_if.if_flags, IFF_RUNNING)) {
+       if (sc == NULL)
+               return (m); /* decline, let bridge have a go */
+
+       ifp = &sc->sc_if;
+       if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
                m_freem(m);
                goto leave;
        }
@@ -417,11 +421,11 @@ vlan_input(struct ifnet *ifp0, struct mb
         * the given source interface and vlan tag, remove the
         * encapsulation.
         */
-       if (m->m_flags & M_VLANTAG) {
-               m->m_flags &= ~M_VLANTAG;
+       if (ISSET(m->m_flags, M_VLANTAG)) {
+               CLR(m->m_flags, M_VLANTAG);
        } else {
-               eh->ether_type = evl->evl_proto;
-               memmove((char *)eh + EVL_ENCAPLEN, eh, sizeof(*eh));
+               memmove((caddr_t)evl + EVL_ENCAPLEN, evl,
+                   offsetof(struct ether_vlan_header, evl_encap_proto));
                m_adj(m, EVL_ENCAPLEN);
        }
 
@@ -440,11 +444,10 @@ vlan_input(struct ifnet *ifp0, struct mb
                break;
        }
 
-       if_vinput(&sc->sc_if, m);
+       if_vinput(ifp, m);
 leave:
-       if (sc != NULL)
-               refcnt_rele_wake(&sc->sc_refcnt);
-       return (1);
+       refcnt_rele_wake(&sc->sc_refcnt);
+       return (NULL);
 }
 
 int
@@ -530,8 +533,6 @@ vlan_up(struct vlan_softc *sc)
        /* configure the parent to handle packets for this vlan */
        vlan_multi_apply(sc, ifp0, SIOCADDMULTI);
 
-       if_ih_insert(ifp0, vlan_input, NULL);
-
        /* we're running now */
        SET(ifp->if_flags, IFF_RUNNING);
        vlan_link_state(sc, ifp0->if_link_state, ifp0->if_baudrate);
@@ -574,7 +575,6 @@ vlan_down(struct vlan_softc *sc)
 
        ifp0 = if_get(sc->sc_ifidx0);
        if (ifp0 != NULL) {
-               if_ih_remove(ifp0, vlan_input, NULL);
                if (ISSET(sc->sc_flags, IFVF_PROMISC))
                        ifpromisc(ifp0, 0);
                vlan_multi_apply(sc, ifp0, SIOCDELMULTI);
Index: net/if_vlan_var.h
===================================================================
RCS file: /cvs/src/sys/net/if_vlan_var.h,v
retrieving revision 1.41
diff -u -p -r1.41 if_vlan_var.h
--- net/if_vlan_var.h   27 Apr 2019 04:46:03 -0000      1.41
+++ net/if_vlan_var.h   9 Jul 2020 10:15:36 -0000
@@ -47,6 +47,7 @@ struct        vlanreq {
 };
 
 #ifdef _KERNEL
+struct mbuf    *vlan_input(struct ifnet *, struct mbuf *);
 struct mbuf    *vlan_inject(struct mbuf *, uint16_t, uint16_t);
 #endif /* _KERNEL */
 
Index: netinet/if_ether.h
===================================================================
RCS file: /cvs/src/sys/netinet/if_ether.h,v
retrieving revision 1.76
diff -u -p -r1.76 if_ether.h
--- netinet/if_ether.h  17 Jul 2019 16:46:18 -0000      1.76
+++ netinet/if_ether.h  9 Jul 2020 10:15:36 -0000
@@ -199,6 +199,11 @@ do {                                                       
                \
 
 #include <net/if_var.h>        /* for "struct ifnet" */
 
+struct ether_brport {
+       struct mbuf     *(*eb_input)(struct ifnet *, struct mbuf *, void *);
+       void              *eb_port;
+};
+
 /*
  * Structure shared between the ethernet driver modules and
  * the address resolution code.  For example, each ec_softc or il_softc
@@ -213,6 +218,7 @@ struct      arpcom {
        int      ac_multirangecnt;              /* number of mcast ranges */
 
        void    *ac_trunkport;
+       const struct ether_brport *ac_brport;
 };
 
 extern int arpt_keep;                          /* arp resolved cache expire */
@@ -247,7 +253,7 @@ int ether_multiaddr(struct sockaddr *, u
 void   ether_ifattach(struct ifnet *);
 void   ether_ifdetach(struct ifnet *);
 int    ether_ioctl(struct ifnet *, struct arpcom *, u_long, caddr_t);
-int    ether_input(struct ifnet *, struct mbuf *, void *);
+void   ether_input(struct ifnet *, struct mbuf *);
 int    ether_resolve(struct ifnet *, struct mbuf *, struct sockaddr *,
            struct rtentry *, struct ether_header *);
 struct mbuf *
@@ -258,6 +264,13 @@ int        ether_output(struct ifnet *, struct 
 void   ether_rtrequest(struct ifnet *, int, struct rtentry *);
 char   *ether_sprintf(u_char *);
 
+int    ether_is_brport(struct ifnet *);
+void   ether_set_brport(struct ifnet *, const struct ether_brport *);
+void   ether_clr_brport(struct ifnet *);
+const struct ether_brport *
+       ether_get_brport(struct ifnet *);
+const struct ether_brport *
+       ether_get_brport_locked(struct ifnet *);
 
 /*
  * Ethernet multicast address structure.  There is one of these for each
Index: netinet/ip_carp.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_carp.c,v
retrieving revision 1.345
diff -u -p -r1.345 ip_carp.c
--- netinet/ip_carp.c   21 May 2020 05:24:59 -0000      1.345
+++ netinet/ip_carp.c   9 Jul 2020 10:15:36 -0000
@@ -208,7 +208,6 @@ void        carp_hmac_generate(struct carp_vhos
            unsigned char *, u_int8_t);
 int    carp_hmac_verify(struct carp_vhost_entry *, u_int32_t *,
            unsigned char *);
-int    carp_input(struct ifnet *, struct mbuf *, void *);
 void   carp_proto_input_c(struct ifnet *, struct mbuf *,
            struct carp_header *, int, sa_family_t);
 int    carp_proto_input_if(struct ifnet *, struct mbuf **, int *, int);
@@ -949,9 +948,6 @@ carpdetach(void *arg)
 
        cif = &ifp0->if_carp;
 
-       /* Restore previous input handler. */
-       if_ih_remove(ifp0, carp_input, NULL);
-
        SRPL_REMOVE_LOCKED(&carp_sc_rc, cif, sc, carp_softc, sc_list);
        sc->sc_carpdev = NULL;
 
@@ -1376,23 +1372,14 @@ carp_vhe_match(struct carp_softc *sc, ui
        return (match);
 }
 
-int
-carp_input(struct ifnet *ifp0, struct mbuf *m, void *cookie)
+struct mbuf *
+carp_input(struct ifnet *ifp0, struct mbuf *m)
 {
        struct ether_header *eh;
        struct srpl *cif;
        struct carp_softc *sc;
        struct srp_ref sr;
 
-#if NVLAN > 0
-       /*
-        * If the underlying interface removed the VLAN header itself,
-        * it's not for us.
-        */
-       if (ISSET(m->m_flags, M_VLANTAG))
-               return (0);
-#endif
-
        eh = mtod(m, struct ether_header *);
        cif = &ifp0->if_carp;
 
@@ -1426,7 +1413,7 @@ carp_input(struct ifnet *ifp0, struct mb
                SRPL_LEAVE(&sr);
 
                if (!ETHER_IS_MULTICAST(eh->ether_dhost))
-                       return (0);
+                       return (m);
 
                /*
                 * XXX Should really check the list of multicast addresses
@@ -1446,14 +1433,14 @@ carp_input(struct ifnet *ifp0, struct mb
                }
                SRPL_LEAVE(&sr);
 
-               return (0);
+               return (m);
        }
 
        if_vinput(&sc->sc_if, m);
 out:
        SRPL_LEAVE(&sr);
 
-       return (1);
+       return (NULL);
 }
 
 int
@@ -1731,9 +1718,6 @@ carp_set_ifp(struct carp_softc *sc, stru
        if (sc->sc_naddrs || sc->sc_naddrs6)
                sc->sc_if.if_flags |= IFF_UP;
        carp_set_enaddr(sc);
-
-       /* Change input handler of the physical interface. */
-       if_ih_insert(ifp0, carp_input, NULL);
 
        carp_carpdev_state(sc);
 
Index: netinet/ip_carp.h
===================================================================
RCS file: /cvs/src/sys/netinet/ip_carp.h,v
retrieving revision 1.48
diff -u -p -r1.48 ip_carp.h
--- netinet/ip_carp.h   8 Dec 2019 11:08:22 -0000       1.48
+++ netinet/ip_carp.h   9 Jul 2020 10:15:36 -0000
@@ -207,6 +207,8 @@ carp_strict_addr_chk(struct ifnet *ifp_a
            ifp_a->if_carpdev == ifp_b->if_carpdev));
 }
 
+struct mbuf    *carp_input(struct ifnet *, struct mbuf *);
+
 int             carp_proto_input(struct mbuf **, int *, int, int);
 void            carp_carpdev_state(void *);
 void            carp_group_demote_adj(struct ifnet *, int, char *);
Index: dev/usb/if_umb.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_umb.c,v
retrieving revision 1.34
diff -u -p -r1.34 if_umb.c
--- dev/usb/if_umb.c    4 May 2020 14:41:03 -0000       1.34
+++ dev/usb/if_umb.c    9 Jul 2020 10:15:36 -0000
@@ -137,7 +137,7 @@ void                 umb_close_bulkpipes(struct umb_so
 int             umb_ioctl(struct ifnet *, u_long, caddr_t);
 int             umb_output(struct ifnet *, struct mbuf *, struct sockaddr *,
                    struct rtentry *);
-int             umb_input(struct ifnet *, struct mbuf *, void *);
+void            umb_input(struct ifnet *, struct mbuf *);
 void            umb_start(struct ifnet *);
 void            umb_rtrequest(struct ifnet *, int, struct rtentry *);
 void            umb_watchdog(struct ifnet *);
@@ -522,9 +522,9 @@ umb_attach(struct device *parent, struct
            sizeof (struct ncm_pointer16);
        ifp->if_mtu = 1500;             /* use a common default */
        ifp->if_hardmtu = sc->sc_maxpktlen;
+       ifp->if_input = umb_input;
        ifp->if_output = umb_output;
        if_attach(ifp);
-       if_ih_insert(ifp, umb_input, NULL);
        if_alloc_sadl(ifp);
        ifp->if_softc = sc;
 #if NBPFILTER > 0
@@ -575,7 +575,6 @@ umb_detach(struct device *self, int flag
                sc->sc_resp_buf = NULL;
        }
        if (ifp->if_softc != NULL) {
-               if_ih_remove(ifp, umb_input, NULL);
                if_detach(ifp);
        }
 
@@ -775,21 +774,21 @@ umb_output(struct ifnet *ifp, struct mbu
        return if_enqueue(ifp, m);
 }
 
-int
-umb_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
+void
+umb_input(struct ifnet *ifp, struct mbuf *m)
 {
        uint32_t af;
 
        if ((ifp->if_flags & IFF_UP) == 0) {
                m_freem(m);
-               return 1;
+               return;
        }
        if (m->m_pkthdr.len < sizeof (struct ip) + sizeof(af)) {
                ifp->if_ierrors++;
                DPRINTFN(4, "%s: dropping short packet (len %d)\n", __func__,
                    m->m_pkthdr.len);
                m_freem(m);
-               return 1;
+               return;
        }
        m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
 
@@ -802,20 +801,19 @@ umb_input(struct ifnet *ifp, struct mbuf
        switch (af) {
        case AF_INET:
                ipv4_input(ifp, m);
-               return 1;
+               return;
 #ifdef INET6
        case AF_INET6:
                ipv6_input(ifp, m);
-               return 1;
+               return;
 #endif /* INET6 */
        default:
                ifp->if_ierrors++;
                DPRINTFN(4, "%s: dropping packet with bad IP version (af %d)\n",
                    __func__, af);
                m_freem(m);
-               return 1;
+               return;
        }
-       return 1;
 }
 
 static inline int

Reply via email to