Hi,

Mutex arp_mtx protects the llinfo_arp la_...  fields.  So kernel
lock is only needed for changing the route rt_flags.

Of course there is a race between checking and setting rt_flags.
But the other checks of the RTF_REJECT flags were without kernel
lock before.  This does not cause trouble, the worst thing that may
happen is to wait another exprire time for ARP retry.  My diff does
not make it worse, reading rt_flags and rt_expire is done without
lock anyway.

The kernel lock is needed to change rt_flags.  Testing without
KERNEL_LOCK() caused crashes.

ok?

bluhm

Index: netinet/if_ether.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/if_ether.c,v
retrieving revision 1.262
diff -u -p -r1.262 if_ether.c
--- netinet/if_ether.c  12 Apr 2023 16:14:42 -0000      1.262
+++ netinet/if_ether.c  24 Apr 2023 14:44:51 -0000
@@ -339,7 +339,7 @@ arpresolve(struct ifnet *ifp, struct rte
        struct rtentry *rt = NULL;
        char addr[INET_ADDRSTRLEN];
        time_t uptime;
-       int refresh = 0;
+       int refresh = 0, reject = 0;
 
        if (m->m_flags & M_BCAST) {     /* broadcast */
                memcpy(desten, etherbroadcastaddr, sizeof(etherbroadcastaddr));
@@ -411,16 +411,9 @@ arpresolve(struct ifnet *ifp, struct rte
        if (ifp->if_flags & (IFF_NOARP|IFF_STATICARP))
                goto bad;
 
-       KERNEL_LOCK();
-       /*
-        * Re-check since we grab the kernel lock after the first check.
-        * rtrequest_delete() can be called with shared netlock.  From
-        * there arp_rtrequest() is reached which touches RTF_LLINFO
-        * and rt_llinfo.  As this is called with kernel lock we grab the
-        * kernel lock here and are safe.  XXXSMP
-        */
+       mtx_enter(&arp_mtx);
        if (!ISSET(rt->rt_flags, RTF_LLINFO)) {
-               KERNEL_UNLOCK();
+               mtx_leave(&arp_mtx);
                goto bad;
        }
        la = (struct llinfo_arp *)rt->rt_llinfo;
@@ -451,13 +444,13 @@ arpresolve(struct ifnet *ifp, struct rte
        }
 #endif
        if (rt->rt_expire) {
-               rt->rt_flags &= ~RTF_REJECT;
+               reject = ~RTF_REJECT;
                if (la->la_asked == 0 || rt->rt_expire != uptime) {
                        rt->rt_expire = uptime;
                        if (la->la_asked++ < arp_maxtries)
                                refresh = 1;
                        else {
-                               rt->rt_flags |= RTF_REJECT;
+                               reject = RTF_REJECT;
                                rt->rt_expire += arpt_down;
                                la->la_asked = 0;
                                la->la_refreshed = 0;
@@ -466,8 +459,18 @@ arpresolve(struct ifnet *ifp, struct rte
                        }
                }
        }
+       mtx_leave(&arp_mtx);
 
-       KERNEL_UNLOCK();
+       if (reject == RTF_REJECT && !ISSET(rt->rt_flags, RTF_REJECT)) {
+               KERNEL_LOCK();
+               SET(rt->rt_flags, RTF_REJECT);
+               KERNEL_UNLOCK();
+       }
+       if (reject == ~RTF_REJECT && ISSET(rt->rt_flags, RTF_REJECT)) {
+               KERNEL_LOCK();
+               CLR(rt->rt_flags, RTF_REJECT);
+               KERNEL_UNLOCK();
+       }
        if (refresh)
                arprequest(ifp, &satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr,
                    &satosin(dst)->sin_addr.s_addr, ac->ac_enaddr);

Reply via email to