On Fri, Nov 15, 2013 at 03:20:48PM +0100, Mike Belopuhov wrote: > On 15 November 2013 15:13, Stefan Sperling <s...@openbsd.org> wrote: > > Is this done right? > > > > Works here with pppoe(4) for both IPv4 and IPv6. > > > > i think this diff might lack task_del's in the detach code.
Ooops, good catch. > have you tried destroying your pppoe interface? Yes, but evidently not while a task was scheduled. Same diff with task_del calls added. Index: if_sppp.h =================================================================== RCS file: /cvs/src/sys/net/if_sppp.h,v retrieving revision 1.19 diff -u -p -r1.19 if_sppp.h --- if_sppp.h 14 Nov 2013 16:52:33 -0000 1.19 +++ if_sppp.h 15 Nov 2013 13:48:47 -0000 @@ -93,6 +93,12 @@ struct spppreq { #ifdef _KERNEL #include <sys/timeout.h> +#include <sys/task.h> + +#ifdef INET6 +#include <netinet/in.h> +#include <netinet6/in6_var.h> +#endif #define IDX_LCP 0 /* idx into state table */ @@ -124,8 +130,13 @@ struct sipcp { #define IPV6CP_MYIFID_SEEN 2 /* have seen my suggested ifid */ u_int32_t saved_hisaddr; /* if hisaddr (IPv4) is dynamic, save * original one here, in network byte order */ - u_int32_t req_hisaddr; /* remote address requested */ - u_int32_t req_myaddr; /* local address requested */ + u_int32_t req_hisaddr; /* remote address requested (IPv4) */ + u_int32_t req_myaddr; /* local address requested (IPv4) */ +#ifdef INET6 + struct in6_aliasreq req_ifid; /* local ifid requested (IPv6) */ +#endif + struct task set_addr_task; /* set address from process context */ + struct task clear_addr_task; /* clear address from process context */ }; struct sauth { Index: if_spppsubr.c =================================================================== RCS file: /cvs/src/sys/net/if_spppsubr.c,v retrieving revision 1.112 diff -u -p -r1.112 if_spppsubr.c --- if_spppsubr.c 14 Nov 2013 16:52:33 -0000 1.112 +++ if_spppsubr.c 15 Nov 2013 14:37:24 -0000 @@ -46,7 +46,6 @@ #include <sys/syslog.h> #include <sys/malloc.h> #include <sys/mbuf.h> -#include <sys/workq.h> #include <sys/timeout.h> #include <crypto/md5.h> @@ -72,10 +71,6 @@ #include <net/if_sppp.h> -#ifdef INET6 -#include <netinet6/in6_var.h> -#endif - # define UNTIMEOUT(fun, arg, handle) \ timeout_del(&(handle)) @@ -291,6 +286,7 @@ HIDE void sppp_lcp_check_and_close(struc HIDE int sppp_ncp_check(struct sppp *sp); HIDE void sppp_ipcp_init(struct sppp *sp); +HIDE void sppp_ipcp_destroy(struct sppp *sp); HIDE void sppp_ipcp_up(struct sppp *sp); HIDE void sppp_ipcp_down(struct sppp *sp); HIDE void sppp_ipcp_open(struct sppp *sp); @@ -306,6 +302,7 @@ HIDE void sppp_ipcp_tlf(struct sppp *sp) HIDE void sppp_ipcp_scr(struct sppp *sp); HIDE void sppp_ipv6cp_init(struct sppp *sp); +HIDE void sppp_ipv6cp_destroy(struct sppp *sp); HIDE void sppp_ipv6cp_up(struct sppp *sp); HIDE void sppp_ipv6cp_down(struct sppp *sp); HIDE void sppp_ipv6cp_open(struct sppp *sp); @@ -902,6 +899,9 @@ sppp_detach(struct ifnet *ifp) struct sppp **q, *p, *sp = (struct sppp*) ifp; int i; + sppp_ipcp_destroy(sp); + sppp_ipv6cp_destroy(sp); + /* Remove the entry from the keepalive list. */ for (q = &spppq; (p = *q); q = &p->pp_next) if (p == sp) { @@ -2637,6 +2637,15 @@ sppp_ipcp_init(struct sppp *sp) sp->ipcp.flags = 0; sp->state[IDX_IPCP] = STATE_INITIAL; sp->fail_counter[IDX_IPCP] = 0; + task_set(&sp->ipcp.set_addr_task, sppp_set_ip_addrs, sp, NULL); + task_set(&sp->ipcp.clear_addr_task, sppp_clear_ip_addrs, sp, NULL); +} + +HIDE void +sppp_ipcp_destroy(struct sppp *sp) +{ + task_del(systq, &sp->ipcp.set_addr_task); + task_del(systq, &sp->ipcp.clear_addr_task); } HIDE void @@ -2955,38 +2964,11 @@ sppp_ipcp_RCN_nak(struct sppp *sp, struc addlog("\n"); } -struct sppp_set_ip_addrs_args { - struct sppp *sp; - u_int32_t myaddr; - u_int32_t hisaddr; -}; - HIDE void sppp_ipcp_tlu(struct sppp *sp) { - struct ifnet *ifp = &sp->pp_if; - struct sppp_set_ip_addrs_args *args; - - args = malloc(sizeof(*args), M_TEMP, M_NOWAIT); - if (args == NULL) - return; - - args->sp = sp; - - /* we are up. Set addresses and notify anyone interested */ - sppp_get_ip_addrs(sp, &args->myaddr, &args->hisaddr, 0); - if ((sp->ipcp.flags & IPCP_MYADDR_DYN) && - (sp->ipcp.flags & IPCP_MYADDR_SEEN)) - args->myaddr = sp->ipcp.req_myaddr; - if ((sp->ipcp.flags & IPCP_HISADDR_DYN) && - (sp->ipcp.flags & IPCP_HISADDR_SEEN)) - args->hisaddr = sp->ipcp.req_hisaddr; - - if (workq_add_task(NULL, 0, sppp_set_ip_addrs, args, NULL)) { - free(args, M_TEMP); - printf("%s: workq_add_task failed, cannot set " - "addresses\n", ifp->if_xname); - } + if (sp->ipcp.req_myaddr != 0 || sp->ipcp.req_hisaddr != 0) + task_add(systq, &sp->ipcp.set_addr_task); } HIDE void @@ -3043,15 +3025,9 @@ sppp_ipcp_tls(struct sppp *sp) HIDE void sppp_ipcp_tlf(struct sppp *sp) { - struct ifnet *ifp = &sp->pp_if; - if (sp->ipcp.flags & (IPCP_MYADDR_DYN|IPCP_HISADDR_DYN)) /* Some address was dynamic, clear it again. */ - if (workq_add_task(NULL, 0, - sppp_clear_ip_addrs, (void *)sp, NULL)) { - printf("%s: workq_add_task failed, cannot clear " - "addresses\n", ifp->if_xname); - } + task_add(systq, &sp->ipcp.clear_addr_task); /* we no longer need LCP */ sp->lcp.protos &= ~(1 << IDX_IPCP); @@ -3110,6 +3086,14 @@ sppp_ipv6cp_init(struct sppp *sp) sp->ipv6cp.flags = 0; sp->state[IDX_IPV6CP] = STATE_INITIAL; sp->fail_counter[IDX_IPV6CP] = 0; + task_set(&sp->ipv6cp.set_addr_task, sppp_update_ip6_addr, sp, + &sp->ipv6cp.req_ifid); +} + +HIDE void +sppp_ipv6cp_destroy(struct sppp *sp) +{ + task_del(systq, &sp->ipv6cp.set_addr_task); } HIDE void @@ -3498,6 +3482,11 @@ sppp_ipv6cp_init(struct sppp *sp) } HIDE void +sppp_ipv6cp_destroy(struct sppp *sp) +{ +} + +HIDE void sppp_ipv6cp_up(struct sppp *sp) { } @@ -4587,16 +4576,15 @@ sppp_update_gw(struct ifnet *ifp) } /* - * Work queue task adding addresses from process context. + * Task adding addresses from process context. * If an address is 0, leave it the way it is. */ HIDE void sppp_set_ip_addrs(void *arg1, void *arg2) { - struct sppp_set_ip_addrs_args *args = arg1; - struct sppp *sp = args->sp; - u_int32_t myaddr = args->myaddr; - u_int32_t hisaddr = args->hisaddr; + struct sppp *sp = arg1; + u_int32_t myaddr; + u_int32_t hisaddr; struct ifnet *ifp = &sp->pp_if; int debug = ifp->if_flags & IFF_DEBUG; struct ifaddr *ifa; @@ -4604,8 +4592,13 @@ sppp_set_ip_addrs(void *arg1, void *arg2 struct sockaddr_in *dest; int s; - /* Arguments are now on local stack so free temporary storage. */ - free(args, M_TEMP); + sppp_get_ip_addrs(sp, &myaddr, &hisaddr, NULL); + if ((sp->ipcp.flags & IPCP_MYADDR_DYN) && + (sp->ipcp.flags & IPCP_MYADDR_SEEN)) + myaddr = sp->ipcp.req_myaddr; + if ((sp->ipcp.flags & IPCP_HISADDR_DYN) && + (sp->ipcp.flags & IPCP_HISADDR_SEEN)) + hisaddr = sp->ipcp.req_hisaddr; s = splsoftnet(); @@ -4656,7 +4649,7 @@ sppp_set_ip_addrs(void *arg1, void *arg2 } /* - * Work queue task clearing addresses from process context. + * Task clearing addresses from process context. * Clear IP addresses. */ HIDE void @@ -4772,7 +4765,6 @@ sppp_update_ip6_addr(void *arg1, void *a if (ia == NULL) { /* IPv6 disabled? */ splx(s); - free(ifra, M_TEMP); return; } @@ -4791,7 +4783,6 @@ sppp_update_ip6_addr(void *arg1, void *a SPP_ARGS(ifp), error); } splx(s); - free(ifra, M_TEMP); } /* @@ -4802,12 +4793,9 @@ sppp_set_ip6_addr(struct sppp *sp, const const struct in6_addr *dst) { struct ifnet *ifp = &sp->pp_if; - struct in6_aliasreq *ifra; - - ifra = malloc(sizeof(*ifra), M_TEMP, M_NOWAIT|M_ZERO); - if (ifra == NULL) - return; + struct in6_aliasreq *ifra = &sp->ipv6cp.req_ifid; + bzero(ifra, sizeof(*ifra)); bcopy(ifp->if_xname, ifra->ifra_name, sizeof(ifra->ifra_name)); ifra->ifra_addr.sin6_len = sizeof(struct sockaddr_in6); @@ -4831,11 +4819,7 @@ sppp_set_ip6_addr(struct sppp *sp, const /* DAD is redundant after an IPv6CP exchange. */ ifra->ifra_flags |= IN6_IFF_NODAD; - if (workq_add_task(NULL, 0, sppp_update_ip6_addr, sp, ifra)) { - free(ifra, M_TEMP); - printf("%s: workq_add_task failed, cannot set IPv6 " - "addresses\n", ifp->if_xname); - } + task_add(systq, &sp->ipv6cp.set_addr_task); } /*