On 07/12/15(Mon) 12:29, Martin Pieuchot wrote:
> On 06/12/15(Sun) 13:52, aaron.mille...@gmail.com wrote:
> > >Synopsis:  Unplugging my urtwn device causes an assertion failure in the 
> > >driver code (see trace)
> > >Category:  system kernel amd64
> > >Environment:
> >     System      : OpenBSD 5.8
> >     Details     : OpenBSD 5.8-current (GENERIC.MP) #1706: Fri Dec  4 
> > 01:49:55 MST 2015
> >                      
> > dera...@amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC.MP
> > 
> >     Architecture: OpenBSD.amd64
> >     Machine     : amd64
> > >Description:
> > 
> > In the past, my urtwn(4) device (RTL8192CU chipset, I think) would stop
> > working after a while, and would start working again after unplugging and
> > plugging back in. I suspect it stopped working due to overheating, because 
> > it's
> > really hot when I pull it out. Occasionally, this would crash the system.
> > 
> > I upgraded from the Nov 25 snapshot to yesterday's snapshot, and now it
> > seems to fail every time with an assertion that drops me to the ddb prompt.
> > Here's the traceback I typed from a picture of the screen:
> > 
> > panic: kernel diagnostic assertion "ifp != NULL" failed: file 
> > "../../../../net/route.c", line 863
> > Stopped at        Debugger+0x9:    leave
> > TID PID UID PRFLAGS PFLAGS CPU COMMAND
> > 18228 18228 77 0x10 0x80 3 dhclient
> > *26266 26266 0 0x14000 0x200 6 usbtask
> > Debugger() at Debugger+0x9
> > panic() at panic+0xfe
> > __assert() at __assert+0x25
> > rtrequest_delete() at rtrequest_delete+0x20a
> > rtdeletemsg() at rtdeletemsg+0xae
> > rtflushclone1() at rtflushclone1+0x98
> > rn_walktree() at rn_walktree+0x83
> > rtrequest_delete() at rtrequest_delete+0x18a
> > rtdeletemsg() at rtdeletemsg+0xae
> > rt_if_remove_rtdelete() at rt_if_remove_rtdelete+0x2b
> > rn_walktree() at rn_walktree+0x83
> > rt_if_remove() at rt_if_remove+0x58
> > if_detach() at if_detach+0x9e
> > urtwn_detach() at urtwn_detach+0x81
> > end trace frame 0xffff800032cdddc0, count: 0
> 
> Could you show me the output of "route -n show" before unplugging your
> device?  Are you using dhclient(8) on multiple interfaces?

Ok I found the bug, can you tell me if the diff below helps?

Index: net/route.c
===================================================================
RCS file: /cvs/src/sys/net/route.c,v
retrieving revision 1.289
diff -u -p -r1.289 route.c
--- net/route.c 5 Dec 2015 10:07:55 -0000       1.289
+++ net/route.c 7 Dec 2015 15:10:15 -0000
@@ -159,8 +159,7 @@ struct sockaddr *rt_plentosa(sa_family_t
 
 struct ifaddr *ifa_ifwithroute(int, struct sockaddr *, struct sockaddr *,
                    u_int);
-int    rtrequest_delete(struct rt_addrinfo *, u_int8_t, struct ifnet *,
-           struct rtentry **, u_int);
+int    rt_delete(struct rtentry *, struct ifnet *, unsigned int);
 
 #ifdef DDB
 void   db_print_sa(struct sockaddr *);
@@ -613,38 +612,29 @@ out:
 }
 
 /*
- * Delete a route and generate a message
+ * Delete a route and generate a message.  The caller must hold a reference
+ * on ``rt''.
  */
 int
-rtdeletemsg(struct rtentry *rt, struct ifnet *ifp, u_int tableid)
+rtdeletemsg(struct rtentry *rt, struct ifnet *ifp, unsigned int rtableid)
 {
        int                     error;
-       struct rt_addrinfo      info;
-       unsigned int            ifidx;
-       struct sockaddr_in6     sa_mask;
 
-       /*
-        * Request the new route so that the entry is not actually
-        * deleted.  That will allow the information being reported to
-        * be accurate (and consistent with route_output()).
-        */
-       bzero((caddr_t)&info, sizeof(info));
-       info.rti_info[RTAX_DST] = rt_key(rt);
-       if (!ISSET(rt->rt_flags, RTF_HOST))
-               info.rti_info[RTAX_NETMASK] = rt_plen2mask(rt, &sa_mask);
-       info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
-       info.rti_flags = rt->rt_flags;
-       ifidx = rt->rt_ifidx;
-       error = rtrequest_delete(&info, rt->rt_priority, ifp, &rt, tableid);
-       rt_missmsg(RTM_DELETE, &info, info.rti_flags, ifidx, error, tableid);
+       KASSERT(rt->rt_ifidx == ifp->if_index);
+
+       error = rt_delete(rt, ifp, rtableid);
        if (error == 0)
-               rtfree(rt);
+               rt_sendmsg(rt, RTM_DELETE, rtableid);
+
        return (error);
 }
 
 static inline int
 rtequal(struct rtentry *a, struct rtentry *b)
 {
+       if (a == b)
+               return 1;
+
        if (memcmp(rt_key(a), rt_key(b), rt_key(a)->sa_len) == 0 &&
            rt_plen(a) == rt_plen(b))
                return 1;
@@ -656,10 +646,25 @@ int
 rtflushclone1(struct rtentry *rt, void *arg, u_int id)
 {
        struct rtentry *parent = arg;
+       struct ifnet *ifp;
+
+       ifp = if_get(rt->rt_ifidx);
+
+       /*
+        * This happens when an interface with a RTF_CLONING route is
+        * being detached.  In this case it's safe to bail because all
+        * the routes are being purged by rt_if_remove().
+        */
+       if (ifp == NULL)
+               return 0;
 
-       if ((rt->rt_flags & RTF_CLONED) != 0 && (rt->rt_parent == parent ||
-           rtequal(rt->rt_parent, parent)))
-               rtdeletemsg(rt, NULL, id);
+       if (ISSET(rt->rt_flags, RTF_CLONED) && rtequal(rt->rt_parent, parent)) {
+               rtref(rt);
+               rtdeletemsg(rt, ifp, id);
+               rtfree(rt);
+       }
+
+       if_put(ifp);
        return 0;
 }
 
@@ -801,53 +806,20 @@ rt_getifa(struct rt_addrinfo *info, u_in
 }
 
 int
-rtrequest_delete(struct rt_addrinfo *info, u_int8_t prio, struct ifnet *ifp,
-    struct rtentry **ret_nrt, u_int tableid)
+rt_delete(struct rtentry *rt, struct ifnet *ifp, unsigned int rtableid)
 {
-       struct rtentry  *rt;
-       int              error;
+       struct sockaddr_in6      sa_mask;
 
-       splsoftassert(IPL_SOFTNET);
+       KASSERT(ifp->if_index == rt->rt_ifidx);
 
-       if (!rtable_exists(tableid))
-               return (EAFNOSUPPORT);
-       rt = rtable_lookup(tableid, info->rti_info[RTAX_DST],
-           info->rti_info[RTAX_NETMASK], info->rti_info[RTAX_GATEWAY], prio);
-       if (rt == NULL)
-               return (ESRCH);
-#ifndef SMALL_KERNEL
-       /*
-        * If we got multipath routes, we require users to specify
-        * a matching gateway.
-        */
-       if ((rt->rt_flags & RTF_MPATH) &&
-           info->rti_info[RTAX_GATEWAY] == NULL) {
-               rtfree(rt);
-               return (ESRCH);
-       }
-#endif
-
-       /*
-        * Since RTP_LOCAL cannot be set by userland, make
-        * sure that local routes are only modified by the
-        * kernel.
-        */
-       if ((rt->rt_flags & (RTF_LOCAL|RTF_BROADCAST)) &&
-           prio != RTP_LOCAL) {
-               rtfree(rt);
-               return (EINVAL);
-       }
+       splsoftassert(IPL_SOFTNET);
 
-       error = rtable_delete(tableid, info->rti_info[RTAX_DST],
-           info->rti_info[RTAX_NETMASK], rt);
-       if (error != 0) {
-               rtfree(rt);
+       if (rtable_delete(rtableid, rt_key(rt), rt_plen2mask(rt, &sa_mask), rt))
                return (ESRCH);
-       }
 
        /* clean up any cloned children */
        if ((rt->rt_flags & RTF_CLONING) != 0)
-               rtflushclone(tableid, rt);
+               rtflushclone(rtableid, rt);
 
        rtfree(rt->rt_gwroute);
        rt->rt_gwroute = NULL;
@@ -857,23 +829,10 @@ rtrequest_delete(struct rt_addrinfo *inf
 
        rt->rt_flags &= ~RTF_UP;
 
-       if (ifp == NULL) {
-               ifp = if_get(rt->rt_ifidx);
-               KASSERT(ifp != NULL);
-               ifp->if_rtrequest(ifp, RTM_DELETE, rt);
-               if_put(ifp);
-       } else {
-               KASSERT(ifp->if_index == rt->rt_ifidx);
-               ifp->if_rtrequest(ifp, RTM_DELETE, rt);
-       }
+       ifp->if_rtrequest(ifp, RTM_DELETE, rt);
 
        atomic_inc_int(&rttrash);
 
-       if (ret_nrt != NULL)
-               *ret_nrt = rt;
-       else
-               rtfree(rt);
-
        return (0);
 }
 
@@ -900,9 +859,50 @@ rtrequest(int req, struct rt_addrinfo *i
                info->rti_info[RTAX_NETMASK] = NULL;
        switch (req) {
        case RTM_DELETE:
-               error = rtrequest_delete(info, prio, NULL, ret_nrt, tableid);
-               if (error)
+               rt = rtable_lookup(tableid, info->rti_info[RTAX_DST],
+                   info->rti_info[RTAX_NETMASK],
+                   info->rti_info[RTAX_GATEWAY], prio);
+               if (rt == NULL)
+                       return (ESRCH);
+
+#ifndef SMALL_KERNEL
+               /*
+                * If we got multipath routes, we require users to specify
+                * a matching gateway.
+                */
+               if (ISSET(rt->rt_flags, RTF_MPATH) &&
+                   info->rti_info[RTAX_GATEWAY] == NULL) {
+                       rtfree(rt);
+                       return (ESRCH);
+               }
+#endif
+
+               /*
+                * Since RTP_LOCAL cannot be set by userland, make
+                * sure that local routes are only modified by the
+                * kernel.
+                */
+               if (ISSET(rt->rt_flags, RTF_LOCAL|RTF_BROADCAST) &&
+                   prio != RTP_LOCAL) {
+                       rtfree(rt);
+                       return (EINVAL);
+               }
+
+               ifp = if_get(rt->rt_ifidx);
+               KASSERT(ifp != NULL);
+               error = rt_delete(rt, ifp, tableid);
+               if_put(ifp);
+
+               if (error) {
+                       rtfree(rt);
                        return (error);
+               }
+
+               if (ret_nrt != NULL)
+                       *ret_nrt = rt;
+               else
+                       rtfree(rt);
+
                break;
 
        case RTM_RESOLVE:
@@ -1067,7 +1067,7 @@ rtrequest(int req, struct rt_addrinfo *i
                if (error != 0 && (crt = rtalloc(ndst, 0, tableid)) != NULL) {
                        /* overwrite cloned route */
                        if ((crt->rt_flags & RTF_CLONED) != 0) {
-                               rtdeletemsg(crt, NULL, tableid);
+                               rtdeletemsg(crt, ifp, tableid);
                                error = rtable_insert(tableid, ndst,
                                    info->rti_info[RTAX_NETMASK],
                                    info->rti_info[RTAX_GATEWAY],
@@ -1235,8 +1235,8 @@ rt_ifa_del(struct ifaddr *ifa, int flags
        struct rtentry          *rt;
        struct mbuf             *m = NULL;
        struct sockaddr         *deldst;
-       struct rt_addrinfo       info;
-       struct sockaddr_rtlabel  sa_rl;
+       struct sockaddr         *mask = NULL;
+       struct sockaddr         *gateway = NULL;
        unsigned int             rtableid = ifp->if_rdomain;
        uint8_t                  prio = ifp->if_priority + RTP_STATIC;
        int                      error;
@@ -1256,16 +1256,10 @@ rt_ifa_del(struct ifaddr *ifa, int flags
                dst = deldst;
        }
 
-       memset(&info, 0, sizeof(info));
-       info.rti_ifa = ifa;
-       info.rti_flags = flags;
-       info.rti_info[RTAX_DST] = dst;
        if ((flags & RTF_LLINFO) == 0)
-               info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
-       info.rti_info[RTAX_LABEL] = rtlabel_id2sa(ifp->if_rtlabelid, &sa_rl);
-
+               gateway = ifa->ifa_addr;
        if ((flags & RTF_HOST) == 0)
-               info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
+               mask = ifa->ifa_netmask;
 
        if (flags & (RTF_LOCAL|RTF_BROADCAST))
                prio = RTP_LOCAL;
@@ -1273,13 +1267,32 @@ rt_ifa_del(struct ifaddr *ifa, int flags
        if (flags & RTF_CONNECTED)
                prio = RTP_CONNECTED;
 
-       error = rtrequest_delete(&info, prio, ifp, &rt, rtableid);
-       if (error == 0) {
-               rt_sendmsg(rt, RTM_DELETE, rtableid);
-               if (flags & RTF_LOCAL)
-                       rt_sendaddrmsg(rt, RTM_DELADDR);
+       rt = rtable_lookup(rtableid, dst, mask, gateway, prio);
+       if (rt == NULL)
+               return (ESRCH);
+
+#ifndef SMALL_KERNEL
+       /*
+        * If we got multipath routes, we require users to specify
+        * a matching gateway.
+        */
+       if (ISSET(rt->rt_flags, RTF_MPATH) && gateway == NULL) {
                rtfree(rt);
+               return (ESRCH);
        }
+#endif
+
+       /* Make sure that's the route the caller want to delete. */
+       if (rt->rt_ifidx != ifp->if_index) {
+               rtfree(rt);
+               return (ESRCH);
+       }
+
+       error = rtdeletemsg(rt, ifp, rtableid);
+       if (error == 0 && (flags & RTF_LOCAL))
+               rt_sendaddrmsg(rt, RTM_DELADDR);
+       rtfree(rt);
+
        if (m != NULL)
                m_free(m);
 
@@ -1691,9 +1704,12 @@ rt_if_remove_rtdelete(struct rtentry *rt
        struct ifnet    *ifp = vifp;
 
        if (rt->rt_ifidx == ifp->if_index) {
-               int     cloning = (rt->rt_flags & RTF_CLONING);
+               int     error, cloning = ISSET(rt->rt_flags, RTF_CLONING);
 
-               if (rtdeletemsg(rt, ifp, id) == 0 && cloning)
+               rtref(rt);
+               error = rtdeletemsg(rt, ifp, id);
+               rtfree(rt);
+               if (error == 0 && cloning)
                        return (EAGAIN);
        }
 
@@ -1751,7 +1767,9 @@ rt_if_linkstate_change(struct rtentry *r
                         * clone a new route from a better source.
                         */
                        if (rt->rt_flags & RTF_CLONED) {
+                               rtref(rt);
                                rtdeletemsg(rt, ifp, id);
+                               rtfree(rt);
                                return (0);
                        }
                        /* take route down */
Index: netinet/ip_icmp.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_icmp.c,v
retrieving revision 1.150
diff -u -p -r1.150 ip_icmp.c
--- netinet/ip_icmp.c   3 Dec 2015 21:11:53 -0000       1.150
+++ netinet/ip_icmp.c   7 Dec 2015 12:40:06 -0000
@@ -1042,19 +1042,21 @@ icmp_mtudisc(struct icmp *icp, u_int rta
 void
 icmp_mtudisc_timeout(struct rtentry *rt, struct rttimer *r)
 {
-       if (rt == NULL)
-               panic("icmp_mtudisc_timeout:  bad route to timeout");
+       struct ifnet *ifp;
+       int s;
 
-       if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) ==
-           (RTF_DYNAMIC | RTF_HOST)) {
+       ifp = if_get(rt->rt_ifidx);
+       if (ifp == NULL)
+               return;
+
+       if ((rt->rt_flags & (RTF_DYNAMIC|RTF_HOST)) == (RTF_DYNAMIC|RTF_HOST)) {
                void *(*ctlfunc)(int, struct sockaddr *, u_int, void *);
                struct sockaddr_in sin;
-               int s;
 
                sin = *satosin(rt_key(rt));
 
                s = splsoftnet();
-               rtdeletemsg(rt, NULL, r->rtt_tableid);
+               rtdeletemsg(rt, ifp, r->rtt_tableid);
 
                /* Notify TCP layer of increased Path MTU estimate */
                ctlfunc = inetsw[ip_protox[IPPROTO_TCP]].pr_ctlinput;
@@ -1062,9 +1064,12 @@ icmp_mtudisc_timeout(struct rtentry *rt,
                        (*ctlfunc)(PRC_MTUINC, sintosa(&sin),
                            r->rtt_tableid, NULL);
                splx(s);
-       } else
+       } else {
                if ((rt->rt_rmx.rmx_locks & RTV_MTU) == 0)
                        rt->rt_rmx.rmx_mtu = 0;
+       }
+
+       if_put(ifp);
 }
 
 /*
@@ -1088,17 +1093,20 @@ icmp_ratelimit(const struct in_addr *dst
 void
 icmp_redirect_timeout(struct rtentry *rt, struct rttimer *r)
 {
-       if (rt == NULL)
-               panic("icmp_redirect_timeout:  bad route to timeout");
+       struct ifnet *ifp;
+       int s;
 
-       if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) ==
-           (RTF_DYNAMIC | RTF_HOST)) {
-               int s;
+       ifp = if_get(rt->rt_ifidx);
+       if (ifp == NULL)
+               return;
 
+       if ((rt->rt_flags & (RTF_DYNAMIC|RTF_HOST)) == (RTF_DYNAMIC|RTF_HOST)) {
                s = splsoftnet();
-               rtdeletemsg(rt, NULL, r->rtt_tableid);
+               rtdeletemsg(rt, ifp, r->rtt_tableid);
                splx(s);
        }
+
+       if_put(ifp);
 }
 
 int
Index: netinet6/icmp6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/icmp6.c,v
retrieving revision 1.182
diff -u -p -r1.182 icmp6.c
--- netinet6/icmp6.c    3 Dec 2015 21:11:53 -0000       1.182
+++ netinet6/icmp6.c    7 Dec 2015 12:39:28 -0000
@@ -1952,34 +1952,42 @@ icmp6_mtudisc_clone(struct sockaddr *dst
 void
 icmp6_mtudisc_timeout(struct rtentry *rt, struct rttimer *r)
 {
-       if (rt == NULL)
-               panic("icmp6_mtudisc_timeout: bad route to timeout");
-       if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) ==
-           (RTF_DYNAMIC | RTF_HOST)) {
-               int s;
+       struct ifnet *ifp;
+       int s;
 
+       ifp = if_get(rt->rt_ifidx);
+       if (ifp == NULL)
+               return;
+
+       if ((rt->rt_flags & (RTF_DYNAMIC|RTF_HOST)) == (RTF_DYNAMIC|RTF_HOST)) {
                s = splsoftnet();
-               rtdeletemsg(rt, NULL, r->rtt_tableid);
+               rtdeletemsg(rt, ifp, r->rtt_tableid);
                splx(s);
        } else {
                if (!(rt->rt_rmx.rmx_locks & RTV_MTU))
                        rt->rt_rmx.rmx_mtu = 0;
        }
+
+       if_put(ifp);
 }
 
 void
 icmp6_redirect_timeout(struct rtentry *rt, struct rttimer *r)
 {
-       if (rt == NULL)
-               panic("icmp6_redirect_timeout: bad route to timeout");
-       if ((rt->rt_flags & (RTF_GATEWAY | RTF_DYNAMIC | RTF_HOST)) ==
-           (RTF_GATEWAY | RTF_DYNAMIC | RTF_HOST)) {
-               int s;
+       struct ifnet *ifp;
+       int s;
 
+       ifp = if_get(rt->rt_ifidx);
+       if (ifp == NULL)
+               return;
+
+       if ((rt->rt_flags & (RTF_DYNAMIC|RTF_HOST)) == (RTF_DYNAMIC|RTF_HOST)) {
                s = splsoftnet();
-               rtdeletemsg(rt, NULL, r->rtt_tableid);
+               rtdeletemsg(rt, ifp, r->rtt_tableid);
                splx(s);
        }
+
+       if_put(ifp);
 }
 
 int *icmpv6ctl_vars[ICMPV6CTL_MAXID] = ICMPV6CTL_VARS;

Reply via email to