I'd like to take brigde_input() & bridge_output() outside of the
KERNEL_LOCK().  My previous approach relying on the NET_LOCK() didn't
work because wireless drivers might call bridge_output() from their
interrupt handler.

So we'll need another mechanism.  The first step would be to use a
mutex.  One of the fields that will be protect by this lock is
`if_bridgeport'.  So here's a small cleanup diff to make it clear
that the field is read in ioctl path.

ok?

Index: net/bridgectl.c
===================================================================
RCS file: /cvs/src/sys/net/bridgectl.c,v
retrieving revision 1.10
diff -u -p -r1.10 bridgectl.c
--- net/bridgectl.c     22 Oct 2018 13:18:23 -0000      1.10
+++ net/bridgectl.c     24 Oct 2018 19:33:56 -0000
@@ -55,7 +55,7 @@ int   bridge_rtfind(struct bridge_softc *,
 int    bridge_rtdaddr(struct bridge_softc *, struct ether_addr *);
 u_int32_t bridge_hash(struct bridge_softc *, struct ether_addr *);
 
-int    bridge_brlconf(struct bridge_softc *, struct ifbrlconf *);
+int    bridge_brlconf(struct bridge_iflist *, struct ifbrlconf *);
 int    bridge_addrule(struct bridge_iflist *, struct ifbrlreq *, int out);
 
 int
@@ -64,6 +64,7 @@ bridgectl_ioctl(struct ifnet *ifp, u_lon
        struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;
        struct ifbreq *req = (struct ifbreq *)data;
        struct ifbrlreq *brlreq = (struct ifbrlreq *)data;
+       struct ifbrlconf *bc = (struct ifbrlconf *)data;
        struct ifbareq *bareq = (struct ifbareq *)data;
        struct ifbrparam *bparam = (struct ifbrparam *)data;
        struct bridge_iflist *bif;
@@ -160,7 +161,17 @@ bridgectl_ioctl(struct ifnet *ifp, u_lon
                bridge_flushrule(bif);
                break;
        case SIOCBRDGGRL:
-               error = bridge_brlconf(sc, (struct ifbrlconf *)data);
+               ifs = ifunit(bc->ifbrl_ifsname);
+               if (ifs == NULL) {
+                       error = ENOENT;
+                       break;
+               }
+               bif = (struct bridge_iflist *)ifs->if_bridgeport;
+               if (bif == NULL || bif->bridge_sc != sc) {
+                       error = ESRCH;
+                       break;
+               }
+               error = bridge_brlconf(bif, bc);
                break;
        default:
                break;
@@ -535,21 +546,13 @@ bridge_update(struct ifnet *ifp, struct 
  * bridge filter/matching rules
  */
 int
-bridge_brlconf(struct bridge_softc *sc, struct ifbrlconf *bc)
+bridge_brlconf(struct bridge_iflist *bif, struct ifbrlconf *bc)
 {
-       struct ifnet *ifp;
-       struct bridge_iflist *bif;
+       struct bridge_softc *sc = bif->bridge_sc;
        struct brl_node *n;
        struct ifbrlreq req;
        int error = 0;
        u_int32_t i = 0, total = 0;
-
-       ifp = ifunit(bc->ifbrl_ifsname);
-       if (ifp == NULL)
-               return (ENOENT);
-       bif = (struct bridge_iflist *)ifp->if_bridgeport;
-       if (bif == NULL || bif->bridge_sc != sc)
-               return (ESRCH);
 
        SIMPLEQ_FOREACH(n, &bif->bif_brlin, brl_next) {
                total++;

Reply via email to