On 06/27/12 10:59, RD Thrush wrote:
> On 06/26/12 12:36, Matthew Dempsky wrote:
>> This looks similar to the pppoe(4) bug that stsp fixed last year:
>> http://marc.info/?l=openbsd-tech&m=130288210121749&w=2
>>
>> Seems to me like sppp_clear_ip_addresses() needs the same workq
>> treatment that sppp_set_ip_addresses() received.
> 
> Thanks for the heads up.  I made the attached patch and have been running with
> it for the past 3 hours.  So far, it has successfully gone through 7 
> disconnects
> without the stack trace diagnostic.  I'll report more later unless breakage 
> occurs.

Status update:

While running the patch, my DSL continued to fail in the same way for another 
day or so until full service was regained.  During that time, it handled 30+ 
disconnections without triggering the stack trace diagnostic.  I'm confident 
the patch fixed my problem and may be considered for the tree.

Thanks, Bob

I've appended the patch inline or [1] if tbird mangles it.
[1]<http://arp.thrush.com/openbsd/pppoe/sys_net_if_spppsubr_c.diff>


Give sppp_clear_ip_addresses() the same workq treatment
that sppp_set_ip_addresses() received in cvs r1.85 by stsp.

Index: sys/net/if_spppsubr.c
===================================================================
RCS file: /a8v/pub2/cvsroot/OpenBSD/src/sys/net/if_spppsubr.c,v
retrieving revision 1.96
diff -u -p -u -p -r1.96 if_spppsubr.c
--- sys/net/if_spppsubr.c       28 Jan 2012 12:14:45 -0000      1.96
+++ sys/net/if_spppsubr.c       27 Jun 2012 11:35:01 -0000
@@ -398,7 +398,7 @@ HIDE void sppp_qflush(struct ifqueue *if
 int sppp_update_gw_walker(struct radix_node *rn, void *arg, u_int);
 void sppp_update_gw(struct ifnet *ifp);
 HIDE void sppp_set_ip_addrs(void *, void *);
-HIDE void sppp_clear_ip_addrs(struct sppp *sp);
+HIDE void sppp_clear_ip_addrs(void *, void *);
 HIDE void sppp_set_phase(struct sppp *sp);
 
 /* our control protocol descriptors */
@@ -3014,6 +3014,10 @@ struct sppp_set_ip_addrs_args {
        u_int32_t hisaddr;
 };
 
+struct sppp_clear_ip_addrs_args {
+       struct sppp *sp;
+};
+
 HIDE void
 sppp_ipcp_tlu(struct sppp *sp)
 {
@@ -3035,6 +3039,7 @@ sppp_ipcp_tlu(struct sppp *sp)
            (sp->ipcp.flags & IPCP_HISADDR_SEEN))
                args->hisaddr = sp->ipcp.req_hisaddr;
 
+       printf("%s: workq_add_task(sppp_set_ip_addrs)\n", ifp->if_xname); /* 
XXX */
        if (workq_add_task(NULL, 0, sppp_set_ip_addrs, args, NULL)) {
                free(args, M_TEMP);
                printf("%s: workq_add_task failed, cannot set "
@@ -3096,9 +3101,23 @@ sppp_ipcp_tls(struct sppp *sp)
 HIDE void
 sppp_ipcp_tlf(struct sppp *sp)
 {
+       struct ifnet *ifp = &sp->pp_if;
+       struct sppp_clear_ip_addrs_args *args;
+
+       args = malloc(sizeof(*args), M_TEMP, M_NOWAIT);
+       if (args == NULL)
+               return;
+
+       args->sp = sp;
+
        if (sp->ipcp.flags & (IPCP_MYADDR_DYN|IPCP_HISADDR_DYN))
                /* Some address was dynamic, clear it again. */
-               sppp_clear_ip_addrs(sp);
+               printf("%s: workq_add_task(sppp_clear_ip_addrs)\n", 
ifp->if_xname); /* XXX */
+               if (workq_add_task(NULL, 0, sppp_clear_ip_addrs, args, NULL)) {
+                       free(args, M_TEMP);
+                       printf("%s: workq_add_task failed, cannot clear "
+                           "addresses\n", ifp->if_xname);
+               }
 
        /* we no longer need LCP */
        sp->lcp.protos &= ~(1 << IDX_IPCP);
@@ -4755,21 +4774,33 @@ sppp_set_ip_addrs(void *arg1, void *arg2
                        return;
                }
                sppp_update_gw(ifp);
+               log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addrs succeeded\n", 
SPP_ARGS(ifp)); /* XXX */
        }
        splx(s);
 }
 
 /*
- * Clear IP addresses.  Must be called at splnet.
+ * Work queue task clearing addresses from process context.
+ * Clear IP addresses.
  */
 HIDE void
-sppp_clear_ip_addrs(struct sppp *sp)
+sppp_clear_ip_addrs(void *arg1, void *arg2)
 {
+       struct sppp_clear_ip_addrs_args *args = arg1;
+       struct sppp *sp = args->sp;
        struct ifnet *ifp = &sp->pp_if;
+       int debug = ifp->if_flags & IFF_DEBUG;
        struct ifaddr *ifa;
        struct sockaddr_in *si;
        struct sockaddr_in *dest;
 
+       int s;
+       
+       /* Arguments are now on local stack so free temporary storage. */
+       free(args, M_TEMP);
+
+       s = splsoftnet();
+
        u_int32_t remote;
        if (sp->ipcp.flags & IPCP_HISADDR_DYN)
                remote = sp->ipcp.saved_hisaddr;
@@ -4792,6 +4823,7 @@ sppp_clear_ip_addrs(struct sppp *sp)
        }
 
        if (ifa && si) {
+               int error;
                struct sockaddr_in new_sin = *si;
 
                in_ifscrub(ifp, ifatoia(ifa));
@@ -4800,10 +4832,18 @@ sppp_clear_ip_addrs(struct sppp *sp)
                if (sp->ipcp.flags & IPCP_HISADDR_DYN)
                        /* replace peer addr in place */
                        dest->sin_addr.s_addr = sp->ipcp.saved_hisaddr;
-               if (!in_ifinit(ifp, ifatoia(ifa), &new_sin, 0, 0))
+               if (!(error = in_ifinit(ifp, ifatoia(ifa), &new_sin, 0, 0)))
                        dohooks(ifp->if_addrhooks, 0);
+               if (debug && error) {
+                       log(LOG_DEBUG, SPP_FMT "sppp_clear_ip_addrs: in_ifinit "
+                       " failed, error=%d\n", SPP_ARGS(ifp), error);
+                       splx(s);
+                       return;
+               }
                sppp_update_gw(ifp);
+               log(LOG_DEBUG, SPP_FMT "sppp_clear_ip_addrs succeeded\n", 
SPP_ARGS(ifp)); /* XXX */
        }
+       splx(s);
 }

Reply via email to