Module Name:    src
Committed By:   knakahara
Date:           Thu Oct 12 09:49:43 UTC 2017

Modified Files:
        src/sys/net: if_pppoe.c if_spppsubr.c if_spppvar.h

Log Message:
sppp_lock is changed from mutex to rwlock now. Contributed by s-yamaguchi@IIJ.

Add locking notes later.


To generate a diff of this commit:
cvs rdiff -u -r1.127 -r1.128 src/sys/net/if_pppoe.c
cvs rdiff -u -r1.169 -r1.170 src/sys/net/if_spppsubr.c
cvs rdiff -u -r1.20 -r1.21 src/sys/net/if_spppvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/if_pppoe.c
diff -u src/sys/net/if_pppoe.c:1.127 src/sys/net/if_pppoe.c:1.128
--- src/sys/net/if_pppoe.c:1.127	Thu Oct 12 09:47:21 2017
+++ src/sys/net/if_pppoe.c	Thu Oct 12 09:49:43 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: if_pppoe.c,v 1.127 2017/10/12 09:47:21 knakahara Exp $ */
+/* $NetBSD: if_pppoe.c,v 1.128 2017/10/12 09:49:43 knakahara Exp $ */
 
 /*-
  * Copyright (c) 2002, 2008 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.127 2017/10/12 09:47:21 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.128 2017/10/12 09:49:43 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "pppoe.h"
@@ -813,9 +813,7 @@ breakbreak:;
 		sc->sc_state = PPPOE_STATE_SESSION;
 		PPPOE_UNLOCK(sc);
 
-		sppp_lock_enter(&sc->sc_sppp);
 		sc->sc_sppp.pp_up(&sc->sc_sppp);
-		sppp_lock_exit(&sc->sc_sppp);
 		break;
 	    }
 #else
@@ -899,9 +897,7 @@ breakbreak:;
 		sc->sc_state = PPPOE_STATE_SESSION;
 		PPPOE_UNLOCK(sc);
 
-		sppp_lock_enter(&sc->sc_sppp);
 		sc->sc_sppp.pp_up(&sc->sc_sppp);	/* notify upper layers */
-		sppp_lock_exit(&sc->sc_sppp);
 		break;
 	case PPPOE_CODE_PADT: {
 		struct ifnet *rcvif;
@@ -1495,9 +1491,7 @@ pppoe_disconnect(struct pppoe_softc *sc)
 	PPPOE_UNLOCK(sc);
 
 	/* notify upper layer */
-	sppp_lock_enter(&sc->sc_sppp);
 	sc->sc_sppp.pp_down(&sc->sc_sppp);
-	sppp_lock_exit(&sc->sc_sppp);
 
 	PPPOE_LOCK(sc, RW_WRITER);
 
@@ -1518,9 +1512,7 @@ pppoe_abort_connect(struct pppoe_softc *
 	PPPOE_UNLOCK(sc);
 
 	/* notify upper layer */
-	sppp_lock_enter(&sc->sc_sppp);
 	sc->sc_sppp.pp_down(&sc->sc_sppp);
-	sppp_lock_exit(&sc->sc_sppp);
 
 	PPPOE_LOCK(sc, RW_WRITER);
 
@@ -1849,13 +1841,11 @@ pppoe_ifattach_hook(void *arg, unsigned 
 			PPPOE_UNLOCK(sc);
 			continue;
 		}
-		sppp_lock_enter(&sc->sc_sppp);
 		if (sc->sc_sppp.pp_if.if_flags & IFF_UP) {
 			sc->sc_sppp.pp_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
 			printf("%s: ethernet interface detached, going down\n",
 			    sc->sc_sppp.pp_if.if_xname);
 		}
-		sppp_lock_exit(&sc->sc_sppp);
 		sc->sc_eth_if = NULL;
 		pppoe_clear_softc(sc, "ethernet interface detached");
 		PPPOE_UNLOCK(sc);
@@ -1881,9 +1871,7 @@ pppoe_clear_softc(struct pppoe_softc *sc
 	PPPOE_UNLOCK(sc);
 
 	/* signal upper layer */
-	sppp_lock_enter(&sc->sc_sppp);
 	sc->sc_sppp.pp_down(&sc->sc_sppp);
-	sppp_lock_exit(&sc->sc_sppp);
 
 	PPPOE_LOCK(sc, RW_WRITER);
 

Index: src/sys/net/if_spppsubr.c
diff -u src/sys/net/if_spppsubr.c:1.169 src/sys/net/if_spppsubr.c:1.170
--- src/sys/net/if_spppsubr.c:1.169	Tue Mar 28 08:47:19 2017
+++ src/sys/net/if_spppsubr.c	Thu Oct 12 09:49:43 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_spppsubr.c,v 1.169 2017/03/28 08:47:19 ozaki-r Exp $	 */
+/*	$NetBSD: if_spppsubr.c,v 1.170 2017/10/12 09:49:43 knakahara Exp $	 */
 
 /*
  * Synchronous PPP/Cisco link level subroutines.
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_spppsubr.c,v 1.169 2017/03/28 08:47:19 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_spppsubr.c,v 1.170 2017/10/12 09:49:43 knakahara Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -254,6 +254,15 @@ static callout_t keepalive_ch;
 #define SPPPQ_UNLOCK()	if (spppq_lock) \
 				mutex_exit(spppq_lock);
 
+#define SPPP_LOCK(_sp, _op)	rw_enter(&(_sp)->pp_lock, (_op))
+#define SPPP_UNLOCK(_sp)	rw_exit(&(_sp)->pp_lock)
+#define SPPP_WLOCKED(_sp)	rw_write_held(&(_sp)->pp_lock)
+#define SPPP_UPGRADE(_sp)	do{	\
+	SPPP_UNLOCK(_sp);		\
+	SPPP_LOCK(_sp, RW_WRITER);	\
+}while (0)
+#define SPPP_DOWNGRADE(_sp)	rw_downgrade(&(_sp)->pp_lock)
+
 #ifdef INET
 #ifndef SPPPSUBR_MPSAFE
 /*
@@ -403,6 +412,16 @@ static void sppp_gen_ip6_addr(struct spp
 static void sppp_suggest_ip6_addr(struct sppp *sp, struct in6_addr *src);
 #endif
 
+static void sppp_notify_up(struct sppp *);
+static void sppp_notify_down(struct sppp *);
+static void sppp_notify_tls_wlocked(struct sppp *);
+static void sppp_notify_tlf_wlocked(struct sppp *);
+static void sppp_notify_con_wlocked(struct sppp *);
+static void sppp_notify_con(struct sppp *);
+
+static void sppp_notify_chg_wlocked(struct sppp *);
+
+
 /* our control protocol descriptors */
 static const struct cp lcp = {
 	PPP_LCP, IDX_LCP, CP_LCP, "lcp",
@@ -469,7 +488,7 @@ sppp_change_phase(struct sppp *sp, int p
 {
 	STDDCL;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	if (sp->pp_phase == phase)
 		return;
@@ -506,9 +525,7 @@ sppp_input(struct ifnet *ifp, struct mbu
 	int debug = ifp->if_flags & IFF_DEBUG;
 	int isr = 0;
 
-	KASSERT(!sppp_locked(sp));
-
-	sppp_lock_enter(sp);
+	SPPP_LOCK(sp, RW_READER);
 
 	if (ifp->if_flags & IFF_UP) {
 		/* Count received bytes, add hardware framing */
@@ -527,7 +544,7 @@ sppp_input(struct ifnet *ifp, struct mbu
 		++ifp->if_ierrors;
 		++ifp->if_iqdrops;
 		m_freem(m);
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 		return;
 	}
 
@@ -572,7 +589,7 @@ sppp_input(struct ifnet *ifp, struct mbu
 				++ifp->if_noproto;
 				goto invalid;
 			case CISCO_KEEPALIVE:
-				sppp_lock_exit(sp);
+				SPPP_UNLOCK(sp);
 				sppp_cisco_input((struct sppp *) ifp, m);
 				m_freem(m);
 				return;
@@ -605,9 +622,12 @@ sppp_input(struct ifnet *ifp, struct mbu
 	default:
 		if (sp->state[IDX_LCP] == STATE_OPENED) {
 			uint16_t prot = htons(protocol);
+
+			SPPP_UPGRADE(sp);
 			sppp_cp_send(sp, PPP_LCP, PROTO_REJ,
 			    ++sp->pp_seq[IDX_LCP], m->m_pkthdr.len + 2,
 			    &prot);
+			SPPP_DOWNGRADE(sp);
 		}
 		if (debug)
 			log(LOG_DEBUG,
@@ -616,33 +636,30 @@ sppp_input(struct ifnet *ifp, struct mbu
 		++ifp->if_noproto;
 		goto drop;
 	case PPP_LCP:
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 		sppp_cp_input(&lcp, sp, m);
 		m_freem(m);
 		return;
 	case PPP_PAP:
+		SPPP_UNLOCK(sp);
 		if (sp->pp_phase >= SPPP_PHASE_AUTHENTICATE) {
-			sppp_lock_exit(sp);
 			sppp_pap_input(sp, m);
-		} else
-			sppp_lock_exit(sp);
+		}
 		m_freem(m);
 		return;
 	case PPP_CHAP:
+		SPPP_UNLOCK(sp);
 		if (sp->pp_phase >= SPPP_PHASE_AUTHENTICATE) {
-			sppp_lock_exit(sp);
 			sppp_chap_input(sp, m);
-		} else
-			sppp_lock_exit(sp);
+		}
 		m_freem(m);
 		return;
 #ifdef INET
 	case PPP_IPCP:
+		SPPP_UNLOCK(sp);
 		if (sp->pp_phase == SPPP_PHASE_NETWORK) {
-			sppp_lock_exit(sp);
 			sppp_cp_input(&ipcp, sp, m);
-		} else
-			sppp_lock_exit(sp);
+		}
 		m_freem(m);
 		return;
 	case PPP_IP:
@@ -654,11 +671,10 @@ sppp_input(struct ifnet *ifp, struct mbu
 #endif
 #ifdef INET6
 	case PPP_IPV6CP:
+		SPPP_UNLOCK(sp);
 		if (sp->pp_phase == SPPP_PHASE_NETWORK) {
-			sppp_lock_exit(sp);
 			sppp_cp_input(&ipv6cp, sp, m);
-		} else
-			sppp_lock_exit(sp);
+		}
 		m_freem(m);
 		return;
 
@@ -676,16 +692,17 @@ queue_pkt:
 		goto drop;
 	}
 
-	sppp_lock_exit(sp);
 	/* Check queue. */
 	if (__predict_true(pktq)) {
 		if (__predict_false(!pktq_enqueue(pktq, m, 0))) {
-			sppp_lock_enter(sp);
 			goto drop;
 		}
+		SPPP_UNLOCK(sp);
 		return;
 	}
 
+	SPPP_UNLOCK(sp);
+
 	IFQ_LOCK(inq);
 	if (IF_QFULL(inq)) {
 		/* Queue overflow. */
@@ -694,7 +711,8 @@ queue_pkt:
 		if (debug)
 			log(LOG_DEBUG, "%s: protocol queue overflow\n",
 				ifp->if_xname);
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_READER);
 		goto drop;
 	}
 	IF_ENQUEUE(inq, m);
@@ -719,15 +737,17 @@ sppp_output(struct ifnet *ifp, struct mb
 	size_t pktlen;
 
 	s = splnet();
+	SPPP_LOCK(sp, RW_READER);
 
-	sppp_lock_enter(sp);
 	sp->pp_last_activity = time_uptime;
 
 	if ((ifp->if_flags & IFF_UP) == 0 ||
 	    (ifp->if_flags & (IFF_RUNNING | IFF_AUTO)) == 0) {
-		sppp_lock_exit(sp);
-		m_freem(m);
+		SPPP_UNLOCK(sp);
 		splx(s);
+
+		m_freem(m);
+
 		return (ENETDOWN);
 	}
 
@@ -737,9 +757,16 @@ sppp_output(struct ifnet *ifp, struct mb
 		 * to start LCP for it.
 		 */
 		ifp->if_flags |= IFF_RUNNING;
+
+		SPPP_UNLOCK(sp);
 		splx(s);
+
+		SPPP_LOCK(sp, RW_WRITER);
 		lcp.Open(sp);
+		SPPP_UNLOCK(sp);
+
 		s = splnet();
+		SPPP_LOCK(sp, RW_READER);
 	}
 
 	/*
@@ -781,9 +808,10 @@ sppp_output(struct ifnet *ifp, struct mb
 		if (ip && ip->ip_src.s_addr == INADDR_ANY) {
 			uint8_t proto = ip->ip_p;
 
-			sppp_lock_exit(sp);
-			m_freem(m);
+			SPPP_UNLOCK(sp);
 			splx(s);
+
+			m_freem(m);
 			if (proto == IPPROTO_TCP)
 				return (EADDRNOTAVAIL);
 			else
@@ -820,7 +848,7 @@ sppp_output(struct ifnet *ifp, struct mb
 				log(LOG_DEBUG, "%s: no memory for transmit header\n",
 					ifp->if_xname);
 			++ifp->if_oerrors;
-			sppp_lock_exit(sp);
+			SPPP_UNLOCK(sp);
 			splx(s);
 			return (ENOBUFS);
 		}
@@ -882,7 +910,7 @@ sppp_output(struct ifnet *ifp, struct mb
 	default:
 		m_freem(m);
 		++ifp->if_oerrors;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 		splx(s);
 		return (EAFNOSUPPORT);
 	}
@@ -894,7 +922,7 @@ sppp_output(struct ifnet *ifp, struct mb
 				log(LOG_DEBUG, "%s: no memory for transmit header\n",
 					ifp->if_xname);
 			++ifp->if_oerrors;
-			sppp_lock_exit(sp);
+			SPPP_UNLOCK(sp);
 			splx(s);
 			return (ENOBUFS);
 		}
@@ -905,7 +933,9 @@ sppp_output(struct ifnet *ifp, struct mb
 
 	pktlen = m->m_pkthdr.len;
 #ifdef SPPPSUBR_MPSAFE
+	SPPP_UNLOCK(sp);
 	error = if_transmit_lock(ifp, m);
+	SPPP_LOCK(sp, RW_READER);
 	if (error == 0)
 		ifp->if_obytes += pktlen + sp->pp_framebytes;
 #else /* !SPPPSUBR_MPSAFE */
@@ -918,14 +948,14 @@ sppp_output(struct ifnet *ifp, struct mb
 		 * framing according to RFC 1333.
 		 */
 		if (!(ifp->if_flags & IFF_OACTIVE)) {
-			sppp_lock_exit(sp);
+			SPPP_UNLOCK(sp);
 			if_start_lock(ifp);
-			sppp_lock_enter(sp);
+			SPPP_LOCK(sp, RW_READER);
 		}
 		ifp->if_obytes += pktlen + sp->pp_framebytes;
 	}
 #endif /* !SPPPSUBR_MPSAFE */
-	sppp_lock_exit(sp);
+	SPPP_UNLOCK(sp);
 	splx(s);
 	return error;
 }
@@ -941,9 +971,9 @@ static void
 sppp_mediastatus(struct ifnet *ifp, struct ifmediareq *imr)
 {
 	struct sppp *sp = (struct sppp *)ifp;
-	KASSERT(!sppp_locked(sp));
 
-	sppp_lock_enter(sp);
+	SPPP_LOCK(sp, RW_WRITER);
+
 	switch (ifp->if_link_state) {
 	case LINK_STATE_UP:
 		imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
@@ -956,7 +986,8 @@ sppp_mediastatus(struct ifnet *ifp, stru
 		imr->ifm_status = 0;
 		break;
 	}
-	sppp_lock_exit(sp);
+
+	SPPP_UNLOCK(sp);
 }
 
 void
@@ -993,9 +1024,9 @@ sppp_attach(struct ifnet *ifp)
 	sp->pp_auth_failures = 0;
 	sp->pp_max_auth_fail = DEFAULT_MAX_AUTH_FAILURES;
 	sp->pp_phase = SPPP_PHASE_DEAD;
-	sp->pp_up = lcp.Up;
-	sp->pp_down = lcp.Down;
-	sp->pp_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTNET);
+	sp->pp_up = sppp_notify_up;
+	sp->pp_down = sppp_notify_down;
+	rw_init(&sp->pp_lock);
 
 	if_alloc_sadl(ifp);
 
@@ -1006,11 +1037,13 @@ sppp_attach(struct ifnet *ifp)
 
 	memset(&sp->myauth, 0, sizeof sp->myauth);
 	memset(&sp->hisauth, 0, sizeof sp->hisauth);
+	SPPP_LOCK(sp, RW_WRITER);
 	sppp_lcp_init(sp);
 	sppp_ipcp_init(sp);
 	sppp_ipv6cp_init(sp);
 	sppp_pap_init(sp);
 	sppp_chap_init(sp);
+	SPPP_UNLOCK(sp);
 }
 
 void
@@ -1018,7 +1051,6 @@ sppp_detach(struct ifnet *ifp)
 {
 	struct sppp **q, *p, *sp = (struct sppp *) ifp;
 
-	sppp_lock_enter(sp);
 	/* Remove the entry from the keepalive list. */
 	SPPPQ_LOCK();
 	for (q = &spppq; (p = *q); q = &p->pp_next)
@@ -1026,18 +1058,22 @@ sppp_detach(struct ifnet *ifp)
 			*q = p->pp_next;
 			break;
 		}
+	SPPPQ_UNLOCK();
+
+	if (! spppq) {
+		/* Stop keepalive handler. */
+		callout_stop(&keepalive_ch);
+		mutex_obj_free(spppq_lock);
+		spppq_lock = NULL;
+	}
+
+	SPPP_LOCK(sp, RW_WRITER);
 
 	/* to avoid workqueue enqueued */
 	atomic_swap_uint(&sp->ipcp.update_addrs_enqueued, 1);
 	workqueue_destroy(sp->ipcp.update_addrs_wq);
 	pcq_destroy(sp->ipcp.update_addrs_q);
 
-	/* Stop keepalive handler. */
-	if (! spppq) {
-		callout_stop(&keepalive_ch);
-	}
-	SPPPQ_UNLOCK();
-
 	callout_stop(&sp->ch[IDX_LCP]);
 	callout_stop(&sp->ch[IDX_IPCP]);
 	callout_stop(&sp->ch[IDX_PAP]);
@@ -1052,14 +1088,11 @@ sppp_detach(struct ifnet *ifp)
 	if (sp->myauth.secret) free(sp->myauth.secret, M_DEVBUF);
 	if (sp->hisauth.name) free(sp->hisauth.name, M_DEVBUF);
 	if (sp->hisauth.secret) free(sp->hisauth.secret, M_DEVBUF);
+	SPPP_UNLOCK(sp);
+	rw_destroy(&sp->pp_lock);
 
 	/* Safety - shouldn't be needed as there is no media to set. */
 	ifmedia_delete_instance(&sp->pp_im, IFM_INST_ANY);
-
-	sppp_lock_exit(sp);
-	if (sp->pp_lock)
-		mutex_obj_free(sp->pp_lock);
-
 }
 
 /*
@@ -1070,9 +1103,11 @@ sppp_flush(struct ifnet *ifp)
 {
 	struct sppp *sp = (struct sppp *) ifp;
 
+	SPPP_LOCK(sp, RW_WRITER);
 	IFQ_PURGE(&sp->pp_if.if_snd);
 	IF_PURGE(&sp->pp_fastq);
 	IF_PURGE(&sp->pp_cpq);
+	SPPP_UNLOCK(sp);
 }
 
 /*
@@ -1084,13 +1119,11 @@ sppp_isempty(struct ifnet *ifp)
 	struct sppp *sp = (struct sppp *) ifp;
 	int empty, s;
 
-	KASSERT(!sppp_locked(sp));
-
 	s = splnet();
-	sppp_lock_enter(sp);
+	SPPP_LOCK(sp, RW_READER);
 	empty = IF_IS_EMPTY(&sp->pp_fastq) && IF_IS_EMPTY(&sp->pp_cpq) &&
 		IFQ_IS_EMPTY(&sp->pp_if.if_snd);
-	sppp_lock_exit(sp);
+	SPPP_UNLOCK(sp);
 	splx(s);
 	return (empty);
 }
@@ -1106,7 +1139,7 @@ sppp_dequeue(struct ifnet *ifp)
 	int s;
 
 	s = splnet();
-	sppp_lock_enter(sp);
+	SPPP_LOCK(sp, RW_WRITER);
 	/*
 	 * Process only the control protocol queue until we have at
 	 * least one NCP open.
@@ -1120,7 +1153,7 @@ sppp_dequeue(struct ifnet *ifp)
 		if (m == NULL)
 			IFQ_DEQUEUE(&sp->pp_if.if_snd, m);
 	}
-	sppp_lock_exit(sp);
+	SPPP_UNLOCK(sp);
 	splx(s);
 	return m;
 }
@@ -1147,7 +1180,7 @@ sppp_ioctl(struct ifnet *ifp, u_long cmd
 		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
 			break;
 
-		sppp_lock_enter(sp);
+		SPPP_LOCK(sp, RW_WRITER);
 		going_up = ifp->if_flags & IFF_UP &&
 			(ifp->if_flags & IFF_RUNNING) == 0;
 		going_down = (ifp->if_flags & IFF_UP) == 0 &&
@@ -1168,10 +1201,13 @@ sppp_ioctl(struct ifnet *ifp, u_long cmd
 			if (!(sp->pp_flags & PP_CISCO))
 				lcp.Open(sp);
 		} else if (going_down) {
+			SPPP_UNLOCK(sp);
 			sppp_flush(ifp);
+			SPPP_LOCK(sp, RW_WRITER);
+
 			ifp->if_flags &= ~IFF_RUNNING;
 		}
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 		break;
 
 	case SIOCSIFMTU:
@@ -1262,16 +1298,14 @@ sppp_cisco_input(struct sppp *sp, struct
 	uint32_t me, mymask = 0;	/* XXX: GCC */
 #endif
 
-	KASSERT(!sppp_locked(sp));
-
-	sppp_lock_enter(sp);
+	SPPP_LOCK(sp, RW_WRITER);
 
 	if (m->m_pkthdr.len < CISCO_PACKET_LEN) {
 		if (debug)
 			log(LOG_DEBUG,
 			    "%s: cisco invalid packet length: %d bytes\n",
 			    ifp->if_xname, m->m_pkthdr.len);
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 		return;
 	}
 	h = mtod(m, struct cisco_packet *);
@@ -1302,9 +1336,10 @@ sppp_cisco_input(struct sppp *sp, struct
 					ifp->if_xname);
 				sp->pp_loopcnt = 0;
 				if (ifp->if_flags & IFF_UP) {
-					sppp_lock_exit(sp);
+					SPPP_UNLOCK(sp);
 					if_down(ifp);
-					sppp_lock_enter(sp);
+					SPPP_LOCK(sp, RW_WRITER);
+
 					IF_PURGE(&sp->pp_cpq);
 				}
 			}
@@ -1317,22 +1352,20 @@ sppp_cisco_input(struct sppp *sp, struct
 		sp->pp_loopcnt = 0;
 		if (! (ifp->if_flags & IFF_UP) &&
 		    (ifp->if_flags & IFF_RUNNING)) {
-			sppp_lock_exit(sp);
+			SPPP_UNLOCK(sp);
 			if_up(ifp);
-			sppp_lock_enter(sp);
+			SPPP_LOCK(sp, RW_WRITER);
 		}
 		break;
 	case CISCO_ADDR_REQ:
 #ifdef INET
-		sppp_lock_exit(sp);
 		sppp_get_ip_addrs(sp, &me, 0, &mymask);
 		if (me != 0L)
 			sppp_cisco_send(sp, CISCO_ADDR_REPLY, me, mymask);
 #endif
-		sppp_lock_enter(sp);
 		break;
 	}
-	sppp_lock_exit(sp);
+	SPPP_UNLOCK(sp);
 }
 
 /*
@@ -1347,7 +1380,7 @@ sppp_cisco_send(struct sppp *sp, int typ
 	struct mbuf *m;
 	uint32_t t;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	t = time_uptime * 1000;
 	MGETHDR(m, M_DONTWAIT, MT_DATA);
@@ -1389,9 +1422,9 @@ sppp_cisco_send(struct sppp *sp, int typ
 	IF_ENQUEUE(&sp->pp_cpq, m);
 
 	if (! (ifp->if_flags & IFF_OACTIVE)) {
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 		if_start_lock(ifp);
-		sppp_lock_enter(sp);
+		SPPP_LOCK(sp, RW_WRITER);
 	}
 }
 
@@ -1411,15 +1444,16 @@ sppp_cp_send(struct sppp *sp, u_short pr
 	struct mbuf *m;
 	size_t pkthdrlen;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	pkthdrlen = (sp->pp_flags & PP_NOFRAMING) ? 2 : PPP_HEADER_LEN;
 
 	if (len > MHLEN - pkthdrlen - LCP_HEADER_LEN)
 		len = MHLEN - pkthdrlen - LCP_HEADER_LEN;
 	MGETHDR(m, M_DONTWAIT, MT_DATA);
-	if (! m)
+	if (! m) {
 		return;
+	}
 	m->m_pkthdr.len = m->m_len = pkthdrlen + LCP_HEADER_LEN + len;
 	m_reset_rcvif(m);
 
@@ -1460,10 +1494,11 @@ sppp_cp_send(struct sppp *sp, u_short pr
 	ifp->if_obytes += m->m_pkthdr.len + sp->pp_framebytes;
 	IF_ENQUEUE(&sp->pp_cpq, m);
 
+
 	if (! (ifp->if_flags & IFF_OACTIVE)) {
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 		if_start_lock(ifp);
-		sppp_lock_enter(sp);
+		SPPP_LOCK(sp, RW_WRITER);
 	}
 }
 
@@ -1480,12 +1515,14 @@ sppp_cp_input(const struct cp *cp, struc
 	u_char *p;
 	uint32_t u32;
 
-	KASSERT(!sppp_locked(sp));
+	SPPP_LOCK(sp, RW_WRITER);
+
 	if (len < 4) {
 		if (debug)
 			log(LOG_DEBUG,
 			    "%s: %s invalid packet length: %d bytes\n",
 			    ifp->if_xname, cp->name, len);
+		SPPP_UNLOCK(sp);
 		return;
 	}
 	h = mtod(m, struct lcp_header *);
@@ -1512,22 +1549,19 @@ sppp_cp_input(const struct cp *cp, struc
 				addlog("%s: %s invalid conf-req length %d\n",
 				       ifp->if_xname, cp->name,
 				       len);
-			sppp_lock_enter(sp);
 			++ifp->if_ierrors;
-			sppp_lock_exit(sp);
 			break;
 		}
 		/* handle states where RCR doesn't get a SCA/SCN */
-		sppp_lock_enter(sp);
 		switch (sp->state[cp->protoidx]) {
 		case STATE_CLOSING:
 		case STATE_STOPPING:
-			sppp_lock_exit(sp);
+			SPPP_UNLOCK(sp);
 			return;
 		case STATE_CLOSED:
 			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident,
 				     0, 0);
-			sppp_lock_exit(sp);
+			SPPP_UNLOCK(sp);
 			return;
 		}
 		rv = (cp->RCR)(sp, h, len);
@@ -1535,7 +1569,7 @@ sppp_cp_input(const struct cp *cp, struc
 			/* fatal error, shut down */
 			(cp->tld)(sp);
 			sppp_lcp_tlf(sp);
-			sppp_lock_exit(sp);
+			SPPP_UNLOCK(sp);
 			return;
 		}
 		switch (sp->state[cp->protoidx]) {
@@ -1566,24 +1600,20 @@ sppp_cp_input(const struct cp *cp, struc
 				sppp_cp_change_state(cp, sp, STATE_ACK_RCVD);
 			break;
 		default:
-			sppp_lock_enter(sp);
 			printf("%s: %s illegal %s in state %s\n",
 			       ifp->if_xname, cp->name,
 			       sppp_cp_type_name(h->type),
 			       sppp_state_name(sp->state[cp->protoidx]));
 			++ifp->if_ierrors;
 		}
-		sppp_lock_exit(sp);
 		break;
 	case CONF_ACK:
-		sppp_lock_enter(sp);
 		if (h->ident != sp->confid[cp->protoidx]) {
 			if (debug)
 				addlog("%s: %s id mismatch 0x%x != 0x%x\n",
 				       ifp->if_xname, cp->name,
 				       h->ident, sp->confid[cp->protoidx]);
 			++ifp->if_ierrors;
-			sppp_lock_exit(sp);
 			break;
 		}
 		switch (sp->state[cp->protoidx]) {
@@ -1620,18 +1650,15 @@ sppp_cp_input(const struct cp *cp, struc
 			       sppp_state_name(sp->state[cp->protoidx]));
 			++ifp->if_ierrors;
 		}
-		sppp_lock_exit(sp);
 		break;
 	case CONF_NAK:
 	case CONF_REJ:
-		sppp_lock_enter(sp);
 		if (h->ident != sp->confid[cp->protoidx]) {
 			if (debug)
 				addlog("%s: %s id mismatch 0x%x != 0x%x\n",
 				       ifp->if_xname, cp->name,
 				       h->ident, sp->confid[cp->protoidx]);
 			++ifp->if_ierrors;
-			sppp_lock_exit(sp);
 			break;
 		}
 		if (h->type == CONF_NAK)
@@ -1666,11 +1693,9 @@ sppp_cp_input(const struct cp *cp, struc
 			       sppp_state_name(sp->state[cp->protoidx]));
 			++ifp->if_ierrors;
 		}
-		sppp_lock_exit(sp);
 		break;
 
 	case TERM_REQ:
-		sppp_lock_enter(sp);
 		switch (sp->state[cp->protoidx]) {
 		case STATE_ACK_RCVD:
 		case STATE_ACK_SENT:
@@ -1700,10 +1725,8 @@ sppp_cp_input(const struct cp *cp, struc
 			       sppp_state_name(sp->state[cp->protoidx]));
 			++ifp->if_ierrors;
 		}
-		sppp_lock_exit(sp);
 		break;
 	case TERM_ACK:
-		sppp_lock_enter(sp);
 		switch (sp->state[cp->protoidx]) {
 		case STATE_CLOSED:
 		case STATE_STOPPED:
@@ -1735,11 +1758,9 @@ sppp_cp_input(const struct cp *cp, struc
 			       sppp_state_name(sp->state[cp->protoidx]));
 			++ifp->if_ierrors;
 		}
-		sppp_lock_exit(sp);
 		break;
 	case CODE_REJ:
 		/* XXX catastrophic rejects (RXJ-) aren't handled yet. */
-		sppp_lock_enter(sp);
 		log(LOG_INFO,
 		    "%s: %s: ignoring RXJ (%s) for code ?, "
 		    "danger will robinson\n",
@@ -1764,7 +1785,6 @@ sppp_cp_input(const struct cp *cp, struc
 			       sppp_state_name(sp->state[cp->protoidx]));
 			++ifp->if_ierrors;
 		}
-		sppp_lock_exit(sp);
 		break;
 	case PROTO_REJ:
 	    {
@@ -1785,8 +1805,6 @@ sppp_cp_input(const struct cp *cp, struc
 		if (upper == NULL)
 			catastrophic++;
 
-		sppp_lock_enter(sp);
-
 		if (debug)
 			log(LOG_INFO,
 			    "%s: %s: RXJ%c (%s) for proto 0x%x (%s/%s)\n",
@@ -1802,7 +1820,6 @@ sppp_cp_input(const struct cp *cp, struc
 		if (upper && !catastrophic) {
 			if (sp->state[upper->protoidx] == STATE_REQ_SENT) {
 				upper->Close(sp);
-				sppp_lock_exit(sp);
 				break;
 			}
 		}
@@ -1827,7 +1844,6 @@ sppp_cp_input(const struct cp *cp, struc
 			       sppp_state_name(sp->state[cp->protoidx]));
 			++ifp->if_ierrors;
 		}
-		sppp_lock_exit(sp);
 		break;
 	    }
 	case DISC_REQ:
@@ -1838,13 +1854,11 @@ sppp_cp_input(const struct cp *cp, struc
 	case ECHO_REQ:
 		if (cp->proto != PPP_LCP)
 			goto illegal;
-		sppp_lock_enter(sp);
 		if (sp->state[cp->protoidx] != STATE_OPENED) {
 			if (debug)
 				addlog("%s: lcp echo req but lcp closed\n",
 				       ifp->if_xname);
 			++ifp->if_ierrors;
-			sppp_lock_exit(sp);
 			break;
 		}
 		if (len < 8) {
@@ -1852,21 +1866,22 @@ sppp_cp_input(const struct cp *cp, struc
 				addlog("%s: invalid lcp echo request "
 				       "packet length: %d bytes\n",
 				       ifp->if_xname, len);
-			sppp_lock_exit(sp);
 			break;
 		}
 		memcpy(&u32, h + 1, sizeof u32);
 		if (ntohl(u32) == sp->lcp.magic) {
 			/* Line loopback mode detected. */
 			printf("%s: loopback\n", ifp->if_xname);
+			SPPP_UNLOCK(sp);
 			if_down(ifp);
+			SPPP_LOCK(sp, RW_WRITER);
+
 			IF_PURGE(&sp->pp_cpq);
 
 			/* Shut down the PPP link. */
 			/* XXX */
 			lcp.Down(sp);
 			lcp.Up(sp);
-			sppp_lock_exit(sp);
 			break;
 		}
 		u32 = htonl(sp->lcp.magic);
@@ -1876,15 +1891,12 @@ sppp_cp_input(const struct cp *cp, struc
 			       ifp->if_xname);
 		sppp_cp_send(sp, PPP_LCP, ECHO_REPLY, h->ident, len - 4,
 		    h + 1);
-		sppp_lock_exit(sp);
 		break;
 	case ECHO_REPLY:
 		if (cp->proto != PPP_LCP)
 			goto illegal;
-		sppp_lock_enter(sp);
 		if (h->ident != sp->lcp.echoid) {
 			++ifp->if_ierrors;
-			sppp_lock_exit(sp);
 			break;
 		}
 		if (len < 8) {
@@ -1892,7 +1904,6 @@ sppp_cp_input(const struct cp *cp, struc
 				addlog("%s: lcp invalid echo reply "
 				       "packet length: %d bytes\n",
 				       ifp->if_xname, len);
-			sppp_lock_exit(sp);
 			break;
 		}
 		if (debug)
@@ -1901,20 +1912,19 @@ sppp_cp_input(const struct cp *cp, struc
 		memcpy(&u32, h + 1, sizeof u32);
 		if (ntohl(u32) != sp->lcp.magic)
 			sp->pp_alivecnt = 0;
-		sppp_lock_exit(sp);
 		break;
 	default:
 		/* Unknown packet type -- send Code-Reject packet. */
 	  illegal:
-		sppp_lock_enter(sp);
 		if (debug)
 			addlog("%s: %s send code-rej for 0x%x\n",
 			       ifp->if_xname, cp->name, h->type);
 		sppp_cp_send(sp, cp->proto, CODE_REJ,
 		    ++sp->pp_seq[cp->protoidx], m->m_pkthdr.len, h);
 		++ifp->if_ierrors;
-		sppp_lock_exit(sp);
 	}
+
+	SPPP_UNLOCK(sp);
 }
 
 
@@ -1927,7 +1937,7 @@ sppp_up_event(const struct cp *cp, struc
 {
 	STDDCL;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	if (debug)
 		log(LOG_DEBUG, "%s: %s up(%s)\n",
@@ -1955,7 +1965,7 @@ sppp_down_event(const struct cp *cp, str
 {
 	STDDCL;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	if (debug)
 		log(LOG_DEBUG, "%s: %s down(%s)\n",
@@ -1993,7 +2003,7 @@ sppp_open_event(const struct cp *cp, str
 {
 	STDDCL;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	if (debug)
 		log(LOG_DEBUG, "%s: %s open(%s)\n",
@@ -2031,7 +2041,7 @@ sppp_close_event(const struct cp *cp, st
 {
 	STDDCL;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	if (debug)
 		log(LOG_DEBUG, "%s: %s close(%s)\n",
@@ -2073,7 +2083,7 @@ sppp_to_event(const struct cp *cp, struc
 	STDDCL;
 	int s;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	s = splnet();
 
@@ -2137,7 +2147,8 @@ sppp_to_event(const struct cp *cp, struc
 void
 sppp_cp_change_state(const struct cp *cp, struct sppp *sp, int newstate)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
 
 	sp->state[cp->protoidx] = newstate;
 	callout_stop(&sp->ch[cp->protoidx]);
@@ -2169,7 +2180,9 @@ sppp_cp_change_state(const struct cp *cp
 static void
 sppp_lcp_init(struct sppp *sp)
 {
-	sppp_lock_enter(sp);
+
+	KASSERT(SPPP_WLOCKED(sp));
+
 	sp->lcp.opts = (1 << LCP_OPT_MAGIC);
 	sp->lcp.magic = 0;
 	sp->state[IDX_LCP] = STATE_INITIAL;
@@ -2190,7 +2203,6 @@ sppp_lcp_init(struct sppp *sp)
 	sp->lcp.max_configure = 10;
 	sp->lcp.max_failure = 10;
 	callout_init(&sp->ch[IDX_LCP], 0);
-	sppp_lock_exit(sp);
 }
 
 static void
@@ -2198,7 +2210,7 @@ sppp_lcp_up(struct sppp *sp)
 {
 	STDDCL;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	/* Initialize activity timestamp: opening a connection is an activity */
 	sp->pp_last_receive = sp->pp_last_activity = time_uptime;
@@ -2234,7 +2246,7 @@ sppp_lcp_down(struct sppp *sp)
 {
 	STDDCL;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	sppp_down_event(&lcp, sp);
 
@@ -2250,9 +2262,9 @@ sppp_lcp_down(struct sppp *sp)
 			log(LOG_INFO,
 			    "%s: Down event (carrier loss), taking interface down.\n",
 			    ifp->if_xname);
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 		if_down(ifp);
-		sppp_lock_enter(sp);
+		SPPP_LOCK(sp, RW_WRITER);
 	} else {
 		if (debug)
 			log(LOG_DEBUG,
@@ -2268,7 +2280,8 @@ sppp_lcp_down(struct sppp *sp)
 static void
 sppp_lcp_open(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
 
 	if (sp->pp_if.if_mtu < PP_MTU) {
 		sp->lcp.mru = sp->pp_if.if_mtu;
@@ -2291,7 +2304,8 @@ sppp_lcp_open(struct sppp *sp)
 static void
 sppp_lcp_close(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
 	sppp_close_event(&lcp, sp);
 }
 
@@ -2299,11 +2313,10 @@ static void
 sppp_lcp_TO(void *cookie)
 {
 	struct sppp *sp = (struct sppp*)cookie;
-	KASSERT(!sppp_locked(sp));
 
-	sppp_lock_enter(sp);
+	SPPP_LOCK(sp, RW_WRITER);
 	sppp_to_event(&lcp, sp);
-	sppp_lock_exit(sp);
+	SPPP_UNLOCK(sp);
 }
 
 /*
@@ -2321,7 +2334,7 @@ sppp_lcp_RCR(struct sppp *sp, struct lcp
 	uint32_t nmagic;
 	u_short authproto;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	len -= 4;
 	origlen = len;
@@ -2447,9 +2460,10 @@ sppp_lcp_RCR(struct sppp *sp, struct lcp
 					ifp->if_xname);
 				sp->pp_loopcnt = 0;
 				if (ifp->if_flags & IFF_UP) {
-					sppp_lock_exit(sp);
+					SPPP_UNLOCK(sp);
 					if_down(ifp);
-					sppp_lock_enter(sp);
+					SPPP_LOCK(sp, RW_WRITER);
+
 					IF_PURGE(&sp->pp_cpq);
 					/* XXX ? */
 					lcp.Down(sp);
@@ -2568,7 +2582,7 @@ sppp_lcp_RCN_rej(struct sppp *sp, struct
 	STDDCL;
 	u_char *buf, *p, l;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	len -= 4;
 	buf = malloc (len, M_TEMP, M_NOWAIT);
@@ -2652,7 +2666,7 @@ sppp_lcp_RCN_nak(struct sppp *sp, struct
 	u_char *buf, *p, l, blen;
 	uint32_t magic;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	len -= 4;
 	buf = malloc (blen = len, M_TEMP, M_NOWAIT);
@@ -2741,15 +2755,15 @@ sppp_lcp_tlu(struct sppp *sp)
 	int i;
 	uint32_t mask;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	/* XXX ? */
 	if (! (ifp->if_flags & IFF_UP) &&
 	    (ifp->if_flags & IFF_RUNNING)) {
 		/* Coming out of loopback mode. */
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 		if_up(ifp);
-		sppp_lock_enter(sp);
+		SPPP_LOCK(sp, RW_WRITER);
 	}
 
 	for (i = 0; i < IDX_COUNT; i++)
@@ -2788,8 +2802,7 @@ sppp_lcp_tlu(struct sppp *sp)
 	}
 
 	/* notify low-level driver of state change */
-	if (sp->pp_chg)
-		sp->pp_chg(sp, (int)sp->pp_phase);
+	sppp_notify_chg_wlocked(sp);
 
 	if (sp->pp_phase == SPPP_PHASE_NETWORK)
 		/* if no NCP is starting, close down */
@@ -2802,7 +2815,7 @@ sppp_lcp_tld(struct sppp *sp)
 	int i;
 	uint32_t mask;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	sppp_change_phase(sp, SPPP_PHASE_TERMINATE);
 
@@ -2824,34 +2837,35 @@ static void
 sppp_lcp_tls(struct sppp *sp)
 {
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
+
 
 	if (sp->pp_max_auth_fail != 0 && sp->pp_auth_failures >= sp->pp_max_auth_fail) {
 		printf("%s: authentication failed %d times, not retrying again\n",
 		sp->pp_if.if_xname, sp->pp_auth_failures);
-		sppp_lock_exit(sp);
+
+		SPPP_UNLOCK(sp);
 		if_down(&sp->pp_if);
-		sppp_lock_enter(sp);
+		SPPP_LOCK(sp, RW_WRITER);
 		return;
 	}
 
 	sppp_change_phase(sp, SPPP_PHASE_ESTABLISH);
 
 	/* Notify lower layer if desired. */
-	if (sp->pp_tls)
-		(sp->pp_tls)(sp);
+	sppp_notify_tls_wlocked(sp);
 }
 
 static void
 sppp_lcp_tlf(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
 
 	sppp_change_phase(sp, SPPP_PHASE_DEAD);
 
 	/* Notify lower layer if desired. */
-	if (sp->pp_tlf)
-		(sp->pp_tlf)(sp);
+	sppp_notify_tlf_wlocked(sp);
 }
 
 static void
@@ -2861,7 +2875,7 @@ sppp_lcp_scr(struct sppp *sp)
 	int i = 0;
 	u_short authproto;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	if (sp->lcp.opts & (1 << LCP_OPT_MAGIC)) {
 		if (! sp->lcp.magic)
@@ -2916,7 +2930,8 @@ sppp_ncp_check(struct sppp *sp)
 static void
 sppp_lcp_check_and_close(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
 
 	if (sp->pp_phase < SPPP_PHASE_NETWORK)
 		/* don't bother, we are already going down */
@@ -2941,7 +2956,8 @@ sppp_ipcp_init(struct sppp *sp)
 {
 	int error;
 
-	sppp_lock_enter(sp);
+	KASSERT(SPPP_WLOCKED(sp));
+
 	sp->ipcp.opts = 0;
 	sp->ipcp.flags = 0;
 	sp->state[IDX_IPCP] = STATE_INITIAL;
@@ -2958,20 +2974,19 @@ sppp_ipcp_init(struct sppp *sp)
 	sp->ipcp.update_addrs_q = pcq_create(IPCP_UPDATE_LIMIT, KM_SLEEP);
 
 	sp->ipcp.update_addrs_enqueued = 0;
-	sppp_lock_exit(sp);
 }
 
 static void
 sppp_ipcp_up(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 	sppp_up_event(&ipcp, sp);
 }
 
 static void
 sppp_ipcp_down(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 	sppp_down_event(&ipcp, sp);
 }
 
@@ -2981,7 +2996,7 @@ sppp_ipcp_open(struct sppp *sp)
 	STDDCL;
 	uint32_t myaddr, hisaddr;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	sp->ipcp.flags &= ~(IPCP_HISADDR_SEEN|IPCP_MYADDR_SEEN|IPCP_MYADDR_DYN|IPCP_HISADDR_DYN);
 	sp->ipcp.req_myaddr = 0;
@@ -3029,7 +3044,8 @@ static void
 sppp_ipcp_close(struct sppp *sp)
 {
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
+
 	sppp_close_event(&ipcp, sp);
 
 #ifdef INET
@@ -3046,11 +3062,9 @@ sppp_ipcp_TO(void *cookie)
 {
 	struct sppp *sp = cookie;
 
-	KASSERT(!sppp_locked(sp));
-
-	sppp_lock_enter(sp);
-	sppp_to_event(&ipcp, (struct sppp *)cookie);
-	sppp_lock_exit(sp);
+	SPPP_LOCK(sp, RW_WRITER);
+	sppp_to_event(&ipcp, sp);
+	SPPP_UNLOCK(sp);
 }
 
 /*
@@ -3067,7 +3081,8 @@ sppp_ipcp_RCR(struct sppp *sp, struct lc
 	int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG;
 	uint32_t hisaddr, desiredaddr;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
+
 	len -= 4;
 	origlen = len;
 	/*
@@ -3262,7 +3277,7 @@ sppp_ipcp_RCN_rej(struct sppp *sp, struc
 	struct ifnet *ifp = &sp->pp_if;
 	int debug = ifp->if_flags & IFF_DEBUG;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	len -= 4;
 	buf = malloc (blen = len, M_TEMP, M_NOWAIT);
@@ -3318,7 +3333,7 @@ sppp_ipcp_RCN_nak(struct sppp *sp, struc
 	int debug = ifp->if_flags & IFF_DEBUG;
 	uint32_t wantaddr;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	len -= 4;
 
@@ -3396,7 +3411,7 @@ static void
 sppp_ipcp_tlu(struct sppp *sp)
 {
 #ifdef INET
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 	/* we are up. Set addresses and notify anyone interested */
 	sppp_set_ip_addrs(sp);
 #endif
@@ -3405,12 +3420,15 @@ sppp_ipcp_tlu(struct sppp *sp)
 static void
 sppp_ipcp_tld(struct sppp *sp)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
 }
 
 static void
 sppp_ipcp_tls(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
 	/* indicate to LCP that it must stay alive */
 	sp->lcp.protos |= (1 << IDX_IPCP);
 }
@@ -3418,7 +3436,9 @@ sppp_ipcp_tls(struct sppp *sp)
 static void
 sppp_ipcp_tlf(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
+
 	/* we no longer need LCP */
 	sp->lcp.protos &= ~(1 << IDX_IPCP);
 }
@@ -3432,7 +3452,7 @@ sppp_ipcp_scr(struct sppp *sp)
 #endif
 	int i = 0;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 #ifdef notyet
 	if (sp->ipcp.opts & (1 << IPCP_OPT_COMPRESSION)) {
@@ -3494,7 +3514,9 @@ sppp_ipcp_scr(struct sppp *sp)
 static void
 sppp_ipv6cp_init(struct sppp *sp)
 {
-	sppp_lock_enter(sp);
+
+	KASSERT(SPPP_WLOCKED(sp));
+
 	sp->ipv6cp.opts = 0;
 	sp->ipv6cp.flags = 0;
 	sp->state[IDX_IPV6CP] = STATE_INITIAL;
@@ -3502,20 +3524,21 @@ sppp_ipv6cp_init(struct sppp *sp)
 	sp->pp_seq[IDX_IPV6CP] = 0;
 	sp->pp_rseq[IDX_IPV6CP] = 0;
 	callout_init(&sp->ch[IDX_IPV6CP], 0);
-	sppp_lock_exit(sp);
 }
 
 static void
 sppp_ipv6cp_up(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
 	sppp_up_event(&ipv6cp, sp);
 }
 
 static void
 sppp_ipv6cp_down(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
 	sppp_down_event(&ipv6cp, sp);
 }
 
@@ -3525,7 +3548,7 @@ sppp_ipv6cp_open(struct sppp *sp)
 	STDDCL;
 	struct in6_addr myaddr, hisaddr;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 #ifdef IPV6CP_MYIFID_DYN
 	sp->ipv6cp.flags &= ~(IPV6CP_MYIFID_SEEN|IPV6CP_MYIFID_DYN);
@@ -3556,7 +3579,8 @@ sppp_ipv6cp_open(struct sppp *sp)
 static void
 sppp_ipv6cp_close(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
 	sppp_close_event(&ipv6cp, sp);
 }
 
@@ -3564,11 +3588,10 @@ static void
 sppp_ipv6cp_TO(void *cookie)
 {
 	struct sppp *sp = cookie;
-	KASSERT(!sppp_locked(sp));
 
-	sppp_lock_enter(sp);
-	sppp_to_event(&ipv6cp, (struct sppp *)cookie);
-	sppp_lock_exit(sp);
+	SPPP_LOCK(sp, RW_WRITER);
+	sppp_to_event(&ipv6cp, sp);
+	SPPP_UNLOCK(sp);
 }
 
 /*
@@ -3589,7 +3612,7 @@ sppp_ipv6cp_RCR(struct sppp *sp, struct 
 	int collision, nohisaddr;
 	char ip6buf[INET6_ADDRSTRLEN];
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	len -= 4;
 	origlen = len;
@@ -3768,7 +3791,7 @@ sppp_ipv6cp_RCN_rej(struct sppp *sp, str
 	struct ifnet *ifp = &sp->pp_if;
 	int debug = ifp->if_flags & IFF_DEBUG;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	len -= 4;
 	buf = malloc (blen = len, M_TEMP, M_NOWAIT);
@@ -3824,7 +3847,7 @@ sppp_ipv6cp_RCN_nak(struct sppp *sp, str
 	struct in6_addr suggestaddr;
 	char ip6buf[INET6_ADDRSTRLEN];
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	len -= 4;
 	buf = malloc (blen = len, M_TEMP, M_NOWAIT);
@@ -3921,21 +3944,24 @@ drop:
 static void
 sppp_ipv6cp_tlu(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
 	/* we are up - notify isdn daemon */
-	if (sp->pp_con)
-		sp->pp_con(sp);
+	sppp_notify_con_wlocked(sp);
 }
 
 static void
 sppp_ipv6cp_tld(struct sppp *sp)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
 }
 
 static void
 sppp_ipv6cp_tls(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
 	/* indicate to LCP that it must stay alive */
 	sp->lcp.protos |= (1 << IDX_IPV6CP);
 }
@@ -3943,7 +3969,8 @@ sppp_ipv6cp_tls(struct sppp *sp)
 static void
 sppp_ipv6cp_tlf(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
 	/* we no longer need LCP */
 	sp->lcp.protos &= ~(1 << IDX_IPV6CP);
 }
@@ -3955,7 +3982,7 @@ sppp_ipv6cp_scr(struct sppp *sp)
 	struct in6_addr ouraddr;
 	int i = 0;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	if (sp->ipv6cp.opts & (1 << IPV6CP_OPT_IFID)) {
 		sppp_get_ip6_addrs(sp, &ouraddr, 0, 0);
@@ -3982,37 +4009,51 @@ sppp_ipv6cp_scr(struct sppp *sp)
 static void
 sppp_ipv6cp_init(struct sppp *sp)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
 }
 
 static void
 sppp_ipv6cp_up(struct sppp *sp)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
 }
 
 static void
 sppp_ipv6cp_down(struct sppp *sp)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
 }
 
 static void
 sppp_ipv6cp_open(struct sppp *sp)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
 }
 
 static void
 sppp_ipv6cp_close(struct sppp *sp)
 {
+
+	KASSERT(SPPPP_WLOKED(sp));
 }
 
 static void
 sppp_ipv6cp_TO(void *sp)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
 }
 
 static int
 sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h,
 		int len)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
 	return 0;
 }
 
@@ -4020,37 +4061,51 @@ static void
 sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h,
 		    int len)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
 }
 
 static void
 sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h,
 		    int len)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
 }
 
 static void
 sppp_ipv6cp_tlu(struct sppp *sp)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
 }
 
 static void
 sppp_ipv6cp_tld(struct sppp *sp)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
 }
 
 static void
 sppp_ipv6cp_tls(struct sppp *sp)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
 }
 
 static void
 sppp_ipv6cp_tlf(struct sppp *sp)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
 }
 
 static void
 sppp_ipv6cp_scr(struct sppp *sp)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
 }
 #endif /*INET6*/
 
@@ -4153,8 +4208,6 @@ sppp_chap_input(struct sppp *sp, struct 
 	int value_len, name_len;
 	MD5_CTX ctx;
 
-	KASSERT(!sppp_locked(sp));
-
 	len = m->m_pkthdr.len;
 	if (len < 4) {
 		if (debug)
@@ -4167,16 +4220,16 @@ sppp_chap_input(struct sppp *sp, struct 
 	if (len > ntohs(h->len))
 		len = ntohs(h->len);
 
+	SPPP_LOCK(sp, RW_WRITER);
+
 	switch (h->type) {
 	/* challenge, failure and success are his authproto */
 	case CHAP_CHALLENGE:
-		sppp_lock_enter(sp);
 		if (sp->myauth.secret == NULL || sp->myauth.name == NULL) {
 			/* can't do anything useful */
 			sp->pp_auth_failures++;
 			printf("%s: chap input without my name and my secret being set\n",
 				ifp->if_xname);
-			sppp_lock_exit(sp);
 			break;
 		}
 		value = 1 + (u_char *)(h + 1);
@@ -4196,7 +4249,6 @@ sppp_chap_input(struct sppp *sp, struct 
 					    len - 4);
 				addlog(">\n");
 			}
-			sppp_lock_exit(sp);
 			break;
 		}
 
@@ -4226,11 +4278,9 @@ sppp_chap_input(struct sppp *sp, struct 
 			       sp->myauth.name_len,
 			       sp->myauth.name,
 			       0);
-		sppp_lock_exit(sp);
 		break;
 
 	case CHAP_SUCCESS:
-		sppp_lock_enter(sp);
 		if (debug) {
 			log(LOG_DEBUG, "%s: chap success",
 			    ifp->if_xname);
@@ -4252,17 +4302,14 @@ sppp_chap_input(struct sppp *sp, struct 
 			 * to network phase.
 			 */
 			splx(x);
-			sppp_lock_exit(sp);
 			break;
 		}
 		splx(x);
 		sppp_phase_network(sp);
-		sppp_lock_exit(sp);
 		break;
 
 	case CHAP_FAILURE:
 		x = splnet();
-		sppp_lock_enter(sp);
 		sp->pp_auth_failures++;
 		splx(x);
 		if (debug) {
@@ -4276,18 +4323,15 @@ sppp_chap_input(struct sppp *sp, struct 
 		} else
 			log(LOG_INFO, "%s: chap failure\n",
 			    ifp->if_xname);
-		sppp_lock_exit(sp);
 		/* await LCP shutdown by authenticator */
 		break;
 
 	/* response is my authproto */
 	case CHAP_RESPONSE:
-		sppp_lock_enter(sp);
 		if (sp->hisauth.secret == NULL) {
 			/* can't do anything useful */
 			printf("%s: chap input without his secret being set\n",
 			    ifp->if_xname);
-			sppp_lock_exit(sp);
 		    break;
 		}
 		value = 1 + (u_char *)(h + 1);
@@ -4307,7 +4351,6 @@ sppp_chap_input(struct sppp *sp, struct 
 					    len - 4);
 				addlog(">\n");
 			}
-			sppp_lock_exit(sp);
 			break;
 		}
 		if (h->ident != sp->confid[IDX_CHAP]) {
@@ -4317,7 +4360,6 @@ sppp_chap_input(struct sppp *sp, struct 
 				    "(got %d, expected %d)\n",
 				    ifp->if_xname,
 				    h->ident, sp->confid[IDX_CHAP]);
-			sppp_lock_exit(sp);
 			break;
 		}
 		if (sp->hisauth.name != NULL &&
@@ -4366,16 +4408,13 @@ sppp_chap_input(struct sppp *sp, struct 
 		if (value_len != sizeof digest ||
 		    memcmp(digest, value, value_len) != 0) {
 chap_failure:
-			KASSERT(sppp_locked(sp));
+			KASSERT(SPPP_WLOCKED(sp));
 			/* action scn, tld */
-			x = splnet();
 			sp->pp_auth_failures++;
-			splx(x);
 			sppp_auth_send(&chap, sp, CHAP_FAILURE, h->ident,
 				       sizeof(FAILMSG) - 1, (const u_char *)FAILMSG,
 				       0);
 			chap.tld(sp);
-			sppp_lock_exit(sp);
 			break;
 		}
 		sp->pp_auth_failures = 0;
@@ -4389,12 +4428,10 @@ chap_failure:
 			sppp_cp_change_state(&chap, sp, STATE_OPENED);
 			chap.tlu(sp);
 		}
-		sppp_lock_exit(sp);
 		break;
 
 	default:
 		/* Unknown CHAP packet type -- ignore. */
-		sppp_lock_enter(sp);
 		if (debug) {
 			log(LOG_DEBUG, "%s: chap unknown input(%s) "
 			    "<0x%x id=0x%xh len=%d",
@@ -4405,49 +4442,32 @@ chap_failure:
 				sppp_print_bytes((u_char *)(h + 1), len - 4);
 			addlog(">\n");
 		}
-		sppp_lock_exit(sp);
 		break;
 
 	}
-}
 
-void
-sppp_lock_enter(struct sppp *sp)
-{
-	if (sp->pp_lock)
-		mutex_enter(sp->pp_lock);
-}
-
-void
-sppp_lock_exit(struct sppp *sp)
-{
-	if (sp->pp_lock)
-		mutex_exit(sp->pp_lock);
-}
-
-int
-sppp_locked(struct sppp *sp)
-{
-	return (!(sp->pp_lock) || mutex_owned(sp->pp_lock));
+	SPPP_UNLOCK(sp);
 }
 
 static void
 sppp_chap_init(struct sppp *sp)
 {
-	sppp_lock_enter(sp);
+
+	KASSERT(SPPP_WLOCKED(sp));
+
 	/* Chap doesn't have STATE_INITIAL at all. */
 	sp->state[IDX_CHAP] = STATE_CLOSED;
 	sp->fail_counter[IDX_CHAP] = 0;
 	sp->pp_seq[IDX_CHAP] = 0;
 	sp->pp_rseq[IDX_CHAP] = 0;
 	callout_init(&sp->ch[IDX_CHAP], 0);
-	sppp_lock_exit(sp);
 }
 
 static void
 sppp_chap_open(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
 	if (sp->hisauth.proto == PPP_CHAP &&
 	    (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) {
 		/* we are authenticator for CHAP, start it */
@@ -4461,8 +4481,8 @@ sppp_chap_open(struct sppp *sp)
 static void
 sppp_chap_close(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
 
+	KASSERT(SPPP_WLOCKED(sp));
 	if (sp->state[IDX_CHAP] != STATE_CLOSED)
 		sppp_cp_change_state(&chap, sp, STATE_CLOSED);
 }
@@ -4474,10 +4494,9 @@ sppp_chap_TO(void *cookie)
 	STDDCL;
 	int s;
 
-	KASSERT(!sppp_locked(sp));
-
 	s = splnet();
-	sppp_lock_enter(sp);
+
+	SPPP_LOCK(sp, RW_WRITER);
 
 	if (debug)
 		log(LOG_DEBUG, "%s: chap TO(%s) rst_counter = %d\n",
@@ -4507,7 +4526,7 @@ sppp_chap_TO(void *cookie)
 			break;
 		}
 
-	sppp_lock_exit(sp);
+	SPPP_UNLOCK(sp);
 	splx(s);
 }
 
@@ -4517,7 +4536,8 @@ sppp_chap_tlu(struct sppp *sp)
 	STDDCL;
 	int i, x;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
+
 	i = 0;
 	sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure;
 
@@ -4577,7 +4597,7 @@ sppp_chap_tld(struct sppp *sp)
 {
 	STDDCL;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	if (debug)
 		log(LOG_DEBUG, "%s: chap tld\n", ifp->if_xname);
@@ -4593,7 +4613,7 @@ sppp_chap_scr(struct sppp *sp)
 	uint32_t *ch;
 	u_char clen = 4 * sizeof(uint32_t);
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	if (sp->hisauth.name == NULL) {
 	    /* can't do anything useful */
@@ -4640,8 +4660,6 @@ sppp_pap_input(struct sppp *sp, struct m
 	char *name, *secret;
 	int name_len, secret_len;
 
-	KASSERT(!sppp_locked(sp));
-
 	/*
 	 * Malicious input might leave this uninitialized, so
 	 * init to an impossible value.
@@ -4659,16 +4677,17 @@ sppp_pap_input(struct sppp *sp, struct m
 	h = mtod(m, struct lcp_header *);
 	if (len > ntohs(h->len))
 		len = ntohs(h->len);
+
+	SPPP_LOCK(sp, RW_WRITER);
+
 	switch (h->type) {
 	/* PAP request is my authproto */
 	case PAP_REQ:
-		sppp_lock_enter(sp);
 		if (sp->hisauth.name == NULL || sp->hisauth.secret == NULL) {
 			/* can't do anything useful */
 			printf("%s: "
 			    "pap request without his name and his secret being set\n",
 			    ifp->if_xname);
-			sppp_lock_exit(sp);
 			break;
 		}
 		name = 1 + (u_char *)(h + 1);
@@ -4687,7 +4706,6 @@ sppp_pap_input(struct sppp *sp, struct m
 					    len - 4);
 				addlog(">\n");
 			}
-			sppp_lock_exit(sp);
 			break;
 		}
 		if (debug) {
@@ -4714,7 +4732,6 @@ sppp_pap_input(struct sppp *sp, struct m
 				       sizeof(FAILMSG) - 1, (const u_char *)FAILMSG,
 				       0);
 			pap.tld(sp);
-			sppp_lock_exit(sp);
 			break;
 		}
 		/* action sca, perhaps tlu */
@@ -4730,12 +4747,10 @@ sppp_pap_input(struct sppp *sp, struct m
 			sppp_cp_change_state(&pap, sp, STATE_OPENED);
 			pap.tlu(sp);
 		}
-		sppp_lock_exit(sp);
 		break;
 
 	/* ack and nak are his authproto */
 	case PAP_ACK:
-		sppp_lock_enter(sp);
 		callout_stop(&sp->pap_my_to_ch);
 		if (debug) {
 			log(LOG_DEBUG, "%s: pap success",
@@ -4760,16 +4775,13 @@ sppp_pap_input(struct sppp *sp, struct m
 			 * to network phase.
 			 */
 			splx(x);
-			sppp_lock_exit(sp);
 			break;
 		}
 		splx(x);
 		sppp_phase_network(sp);
-		sppp_lock_exit(sp);
 		break;
 
 	case PAP_NAK:
-		sppp_lock_enter(sp);
 		callout_stop(&sp->pap_my_to_ch);
 		sp->pp_auth_failures++;
 		if (debug) {
@@ -4786,12 +4798,10 @@ sppp_pap_input(struct sppp *sp, struct m
 			log(LOG_INFO, "%s: pap failure\n",
 			    ifp->if_xname);
 		/* await LCP shutdown by authenticator */
-		sppp_lock_exit(sp);
 		break;
 
 	default:
 		/* Unknown PAP packet type -- ignore. */
-		sppp_lock_enter(sp);
 		if (debug) {
 			log(LOG_DEBUG, "%s: pap corrupted input "
 			    "<0x%x id=0x%x len=%d",
@@ -4801,30 +4811,32 @@ sppp_pap_input(struct sppp *sp, struct m
 				sppp_print_bytes((u_char *)(h + 1), len - 4);
 			addlog(">\n");
 		}
-		sppp_lock_exit(sp);
 		break;
-
 	}
+
+	SPPP_UNLOCK(sp);
 }
 
 static void
 sppp_pap_init(struct sppp *sp)
 {
+
+	KASSERT(SPPP_WLOCKED(sp));
+
 	/* PAP doesn't have STATE_INITIAL at all. */
-	sppp_lock_enter(sp);
 	sp->state[IDX_PAP] = STATE_CLOSED;
 	sp->fail_counter[IDX_PAP] = 0;
 	sp->pp_seq[IDX_PAP] = 0;
 	sp->pp_rseq[IDX_PAP] = 0;
 	callout_init(&sp->ch[IDX_PAP], 0);
 	callout_init(&sp->pap_my_to_ch, 0);
-	sppp_lock_exit(sp);
 }
 
 static void
 sppp_pap_open(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
 
 	if (sp->hisauth.proto == PPP_PAP &&
 	    (sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) {
@@ -4843,7 +4855,9 @@ sppp_pap_open(struct sppp *sp)
 static void
 sppp_pap_close(struct sppp *sp)
 {
-	KASSERT(sppp_locked(sp));
+
+	KASSERT(SPPP_WLOCKED(sp));
+
 	if (sp->state[IDX_PAP] != STATE_CLOSED)
 		sppp_cp_change_state(&pap, sp, STATE_CLOSED);
 }
@@ -4859,10 +4873,9 @@ sppp_pap_TO(void *cookie)
 	STDDCL;
 	int s;
 
-	KASSERT(!sppp_locked(sp));
-
 	s = splnet();
-	sppp_lock_enter(sp);
+	SPPP_LOCK(sp, RW_WRITER);
+
 	if (debug)
 		log(LOG_DEBUG, "%s: pap TO(%s) rst_counter = %d\n",
 		    ifp->if_xname,
@@ -4886,7 +4899,7 @@ sppp_pap_TO(void *cookie)
 			break;
 		}
 
-	sppp_lock_exit(sp);
+	SPPP_UNLOCK(sp);
 	splx(s);
 }
 
@@ -4901,15 +4914,14 @@ sppp_pap_my_TO(void *cookie)
 	struct sppp *sp = (struct sppp *)cookie;
 	STDDCL;
 
-	KASSERT(!sppp_locked(sp));
-
-	sppp_lock_enter(sp);
+	SPPP_LOCK(sp, RW_WRITER);
 	if (debug)
 		log(LOG_DEBUG, "%s: pap peer TO\n",
 		    ifp->if_xname);
 
 	pap.scr(sp);
-	sppp_lock_exit(sp);
+
+	SPPP_UNLOCK(sp);
 }
 
 static void
@@ -4918,7 +4930,8 @@ sppp_pap_tlu(struct sppp *sp)
 	STDDCL;
 	int x;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
+
 	sp->rst_counter[IDX_PAP] = sp->lcp.max_configure;
 
 	if (debug)
@@ -4948,7 +4961,7 @@ sppp_pap_tld(struct sppp *sp)
 {
 	STDDCL;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	if (debug)
 		log(LOG_DEBUG, "%s: pap tld\n", ifp->if_xname);
@@ -4964,7 +4977,7 @@ sppp_pap_scr(struct sppp *sp)
 {
 	u_char idlen, pwdlen;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	if (sp->myauth.secret == NULL || sp->myauth.name == NULL) {
 	    /* can't do anything useful */
@@ -5015,7 +5028,7 @@ sppp_auth_send(const struct cp *cp, stru
 	const char *msg;
 	va_list ap;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	MGETHDR(m, M_DONTWAIT, MT_DATA);
 	if (! m)
@@ -5082,9 +5095,9 @@ sppp_auth_send(const struct cp *cp, stru
 	IF_ENQUEUE(&sp->pp_cpq, m);
 
 	if (! (ifp->if_flags & IFF_OACTIVE)) {
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 		if_start_lock(ifp);
-		sppp_lock_enter(sp);
+		SPPP_LOCK(sp, RW_WRITER);
 	}
 }
 
@@ -5105,7 +5118,7 @@ sppp_keepalive(void *dummy)
 	for (sp=spppq; sp; sp=sp->pp_next) {
 		struct ifnet *ifp = NULL;
 
-		sppp_lock_enter(sp);
+		SPPP_LOCK(sp, RW_WRITER);
 		ifp = &sp->pp_if;
 
 		/* check idle timeout */
@@ -5118,7 +5131,7 @@ sppp_keepalive(void *dummy)
 				sp->pp_if.if_xname,
 				(unsigned long)(now-sp->pp_last_activity));
 			lcp.Close(sp);
-			sppp_lock_exit(sp);
+			SPPP_UNLOCK(sp);
 			continue;
 		    }
 		}
@@ -5126,7 +5139,7 @@ sppp_keepalive(void *dummy)
 		/* Keepalive mode disabled or channel down? */
 		if (! (sp->pp_flags & PP_KEEPALIVE) ||
 		    ! (ifp->if_flags & IFF_RUNNING)) {
-			sppp_lock_exit(sp);
+			SPPP_UNLOCK(sp);
 			continue;
 		}
 
@@ -5134,23 +5147,25 @@ sppp_keepalive(void *dummy)
 		/* No keepalive in PPP mode if LCP not opened yet. */
 		if (! (sp->pp_flags & PP_CISCO) &&
 		    sp->pp_phase < SPPP_PHASE_AUTHENTICATE) {
-			sppp_lock_exit(sp);
+			SPPP_UNLOCK(sp);
 			continue;
 		}
 
 		/* No echo reply, but maybe user data passed through? */
 		if ((now - sp->pp_last_receive) < sp->pp_max_noreceive) {
 			sp->pp_alivecnt = 0;
-			sppp_lock_exit(sp);
+			SPPP_UNLOCK(sp);
 			continue;
 		}
 
 		if (sp->pp_alivecnt >= sp->pp_maxalive) {
 			/* No keepalive packets got.  Stop the interface. */
-			sppp_lock_exit(sp);
+			SPPP_UNLOCK(sp);
 			if_down (ifp);
-			sppp_lock_enter(sp);
+			SPPP_LOCK(sp, RW_WRITER);
+
 			IF_PURGE(&sp->pp_cpq);
+
 			if (! (sp->pp_flags & PP_CISCO)) {
 				printf("%s: LCP keepalive timed out, going to restart the connection\n",
 					ifp->if_xname);
@@ -5164,10 +5179,9 @@ sppp_keepalive(void *dummy)
 
 				/* Close connection immediately, completition of this
 				 * will summon the magic needed to reestablish it. */
-				if (sp->pp_tlf)
-					sp->pp_tlf(sp);
+				sppp_notify_tlf_wlocked(sp);
 
-				sppp_lock_exit(sp);
+				SPPP_UNLOCK(sp);
 				continue;
 			}
 		}
@@ -5183,7 +5197,7 @@ sppp_keepalive(void *dummy)
 				sp->lcp.echoid, 4, &nmagic);
 		}
 
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	}
 	splx(s);
 	callout_reset(&keepalive_ch, hz * LCP_KEEPALIVE_INTERVAL, sppp_keepalive, NULL);
@@ -5310,8 +5324,7 @@ sppp_set_ip_addrs_work(struct work *wk, 
 			    ifp->if_xname, ifp->if_mtu);
 	}
 
-	if (sp->pp_con)
-		sp->pp_con(sp);
+	sppp_notify_con(sp);
 }
 
 static void
@@ -5571,7 +5584,7 @@ sppp_params(struct sppp *sp, u_long cmd,
 		int error;
 		size_t len;
 
-		sppp_lock_enter(sp);
+		SPPP_LOCK(sp, RW_READER);
 
 		cfg->myauthflags = sp->myauth.flags;
 		cfg->hisauthflags = sp->hisauth.flags;
@@ -5591,14 +5604,16 @@ sppp_params(struct sppp *sp, u_long cmd,
 		    } else {
 			len = sp->myauth.name_len + 1;
 
-			sppp_lock_exit(sp);
 
-			if (cfg->myname_length < len)
-			    return (ENAMETOOLONG);
+			if (cfg->myname_length < len) {
+				SPPP_UNLOCK(sp);
+				return (ENAMETOOLONG);
+			}
 			error = copyout(sp->myauth.name, cfg->myname, len);
-			if (error) return error;
-
-			sppp_lock_enter(sp);
+			if (error) {
+				SPPP_UNLOCK(sp);
+				return error;
+			}
 		    }
 		}
 		if (cfg->hisname_length == 0) {
@@ -5610,15 +5625,18 @@ sppp_params(struct sppp *sp, u_long cmd,
 		    } else {
 			len = sp->hisauth.name_len + 1;
 
-			sppp_lock_exit(sp);
-			if (cfg->hisname_length < len)
-			    return (ENAMETOOLONG);
+			if (cfg->hisname_length < len) {
+				SPPP_UNLOCK(sp);
+				return (ENAMETOOLONG);
+			}
 			error = copyout(sp->hisauth.name, cfg->hisname, len);
-			if (error) return error;
-			sppp_lock_enter(sp);
+			if (error) {
+				SPPP_UNLOCK(sp);
+				return error;
+			}
 		    }
 		}
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case SPPPSETAUTHCFG:
@@ -5626,7 +5644,7 @@ sppp_params(struct sppp *sp, u_long cmd,
 		struct spppauthcfg *cfg = (struct spppauthcfg *)data;
 		int error;
 
-		sppp_lock_enter(sp);
+		SPPP_LOCK(sp, RW_WRITER);
 
 		if (sp->myauth.name) {
 			free(sp->myauth.name, M_DEVBUF);
@@ -5647,7 +5665,7 @@ sppp_params(struct sppp *sp, u_long cmd,
 
 		if (cfg->hisname != NULL && cfg->hisname_length > 0) {
 			if (cfg->hisname_length >= MCLBYTES) {
-				sppp_lock_exit(sp);
+				SPPP_UNLOCK(sp);
 				return (ENAMETOOLONG);
 			}
 			sp->hisauth.name = malloc(cfg->hisname_length, M_DEVBUF, M_WAITOK);
@@ -5655,7 +5673,7 @@ sppp_params(struct sppp *sp, u_long cmd,
 			if (error) {
 				free(sp->hisauth.name, M_DEVBUF);
 				sp->hisauth.name = NULL;
-				sppp_lock_exit(sp);
+				SPPP_UNLOCK(sp);
 				return error;
 			}
 			sp->hisauth.name_len = cfg->hisname_length - 1;
@@ -5663,7 +5681,7 @@ sppp_params(struct sppp *sp, u_long cmd,
 		}
 		if (cfg->hissecret != NULL && cfg->hissecret_length > 0) {
 			if (cfg->hissecret_length >= MCLBYTES) {
-				sppp_lock_exit(sp);
+				SPPP_UNLOCK(sp);
 				return (ENAMETOOLONG);
 			}
 			sp->hisauth.secret = malloc(cfg->hissecret_length,
@@ -5673,7 +5691,7 @@ sppp_params(struct sppp *sp, u_long cmd,
 			if (error) {
 				free(sp->hisauth.secret, M_DEVBUF);
 				sp->hisauth.secret = NULL;
-				sppp_lock_exit(sp);
+				SPPP_UNLOCK(sp);
 				return error;
 			}
 			sp->hisauth.secret_len = cfg->hissecret_length - 1;
@@ -5681,7 +5699,7 @@ sppp_params(struct sppp *sp, u_long cmd,
 		}
 		if (cfg->myname != NULL && cfg->myname_length > 0) {
 			if (cfg->myname_length >= MCLBYTES) {
-				sppp_lock_exit(sp);
+				SPPP_UNLOCK(sp);
 				return (ENAMETOOLONG);
 			}
 			sp->myauth.name = malloc(cfg->myname_length, M_DEVBUF, M_WAITOK);
@@ -5689,7 +5707,7 @@ sppp_params(struct sppp *sp, u_long cmd,
 			if (error) {
 				free(sp->myauth.name, M_DEVBUF);
 				sp->myauth.name = NULL;
-				sppp_lock_exit(sp);
+				SPPP_UNLOCK(sp);
 				return error;
 			}
 			sp->myauth.name_len = cfg->myname_length - 1;
@@ -5697,7 +5715,7 @@ sppp_params(struct sppp *sp, u_long cmd,
 		}
 		if (cfg->mysecret != NULL && cfg->mysecret_length > 0) {
 			if (cfg->mysecret_length >= MCLBYTES) {
-				sppp_lock_exit(sp);
+				SPPP_UNLOCK(sp);
 				return (ENAMETOOLONG);
 			}
 			sp->myauth.secret = malloc(cfg->mysecret_length,
@@ -5707,7 +5725,7 @@ sppp_params(struct sppp *sp, u_long cmd,
 			if (error) {
 				free(sp->myauth.secret, M_DEVBUF);
 				sp->myauth.secret = NULL;
-				sppp_lock_exit(sp);
+				SPPP_UNLOCK(sp);
 				return error;
 			}
 			sp->myauth.secret_len = cfg->mysecret_length - 1;
@@ -5725,155 +5743,173 @@ sppp_params(struct sppp *sp, u_long cmd,
 		else
 		    sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO);
 
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case SPPPGETLCPCFG:
 	    {
 		struct sppplcpcfg *lcpp = (struct sppplcpcfg *)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_READER);
 		lcpp->lcp_timeout = sp->lcp.timeout;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case SPPPSETLCPCFG:
 	    {
 		struct sppplcpcfg *lcpp = (struct sppplcpcfg *)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_WRITER);
 		sp->lcp.timeout = lcpp->lcp_timeout;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case SPPPGETSTATUS:
 	    {
 		struct spppstatus *status = (struct spppstatus *)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_READER);
 		status->phase = sp->pp_phase;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case SPPPGETSTATUSNCP:
 	    {
 		struct spppstatusncp *status = (struct spppstatusncp *)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_READER);
 		status->phase = sp->pp_phase;
-		sppp_lock_exit(sp);
 		status->ncpup = sppp_ncp_check(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case SPPPGETIDLETO:
 	    {
 	    	struct spppidletimeout *to = (struct spppidletimeout *)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_READER);
 		to->idle_seconds = sp->pp_idle_timeout;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case SPPPSETIDLETO:
 	    {
 	    	struct spppidletimeout *to = (struct spppidletimeout *)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_WRITER);
 		sp->pp_idle_timeout = to->idle_seconds;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case SPPPSETAUTHFAILURE:
 	    {
-	    	struct spppauthfailuresettings *afsettings = (struct spppauthfailuresettings *)data;
-		sppp_lock_enter(sp);
+	    	struct spppauthfailuresettings *afsettings =
+		    (struct spppauthfailuresettings *)data;
+
+		SPPP_LOCK(sp, RW_WRITER);
 		sp->pp_max_auth_fail = afsettings->max_failures;
 		sp->pp_auth_failures = 0;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case SPPPGETAUTHFAILURES:
 	    {
 	    	struct spppauthfailurestats *stats = (struct spppauthfailurestats *)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_READER);
 		stats->auth_failures = sp->pp_auth_failures;
 		stats->max_failures = sp->pp_max_auth_fail;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case SPPPSETDNSOPTS:
 	    {
 		struct spppdnssettings *req = (struct spppdnssettings *)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_WRITER);
 		sp->query_dns = req->query_dns & 3;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case SPPPGETDNSOPTS:
 	    {
 		struct spppdnssettings *req = (struct spppdnssettings *)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_READER);
 		req->query_dns = sp->query_dns;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case SPPPGETDNSADDRS:
 	    {
 		struct spppdnsaddrs *addrs = (struct spppdnsaddrs *)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_READER);
 		memcpy(&addrs->dns, &sp->dns_addrs, sizeof addrs->dns);
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case SPPPGETKEEPALIVE:
 	    {
 	    	struct spppkeepalivesettings *settings =
 		     (struct spppkeepalivesettings*)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_READER);
 		settings->maxalive = sp->pp_maxalive;
 		settings->max_noreceive = sp->pp_max_noreceive;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case SPPPSETKEEPALIVE:
 	    {
 	    	struct spppkeepalivesettings *settings =
 		     (struct spppkeepalivesettings*)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_WRITER);
 		sp->pp_maxalive = settings->maxalive;
 		sp->pp_max_noreceive = settings->max_noreceive;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 #if defined(COMPAT_50) || defined(MODULAR)
 	case __SPPPGETIDLETO50:
 	    {
 	    	struct spppidletimeout50 *to = (struct spppidletimeout50 *)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_READER);
 		to->idle_seconds = (uint32_t)sp->pp_idle_timeout;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case __SPPPSETIDLETO50:
 	    {
 		struct spppidletimeout50 *to = (struct spppidletimeout50 *)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_WRITER);
 		sp->pp_idle_timeout = (time_t)to->idle_seconds;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case __SPPPGETKEEPALIVE50:
 	    {
 	    	struct spppkeepalivesettings50 *settings =
 		     (struct spppkeepalivesettings50*)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_READER);
 		settings->maxalive = sp->pp_maxalive;
 		settings->max_noreceive = (uint32_t)sp->pp_max_noreceive;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 	case __SPPPSETKEEPALIVE50:
 	    {
 	    	struct spppkeepalivesettings50 *settings =
 		     (struct spppkeepalivesettings50*)data;
-		sppp_lock_enter(sp);
+
+		SPPP_LOCK(sp, RW_WRITER);
 		sp->pp_maxalive = settings->maxalive;
 		sp->pp_max_noreceive = (time_t)settings->max_noreceive;
-		sppp_lock_exit(sp);
+		SPPP_UNLOCK(sp);
 	    }
 	    break;
 #endif /* COMPAT_50 || MODULAR */
@@ -5890,7 +5926,7 @@ sppp_phase_network(struct sppp *sp)
 	int i;
 	uint32_t mask;
 
-	KASSERT(sppp_locked(sp));
+	KASSERT(SPPP_WLOCKED(sp));
 
 	sppp_change_phase(sp, SPPP_PHASE_NETWORK);
 
@@ -6126,3 +6162,84 @@ sppp_subr_modcmd(modcmd_t cmd, void *arg
         }
 }
 
+static void
+sppp_notify_up(struct sppp *sp)
+{
+
+	SPPP_LOCK(sp, RW_WRITER);
+	lcp.Up(sp);
+	SPPP_UNLOCK(sp);
+}
+
+static void
+sppp_notify_down(struct sppp *sp)
+{
+
+	SPPP_LOCK(sp, RW_WRITER);
+	lcp.Down(sp);
+	SPPP_UNLOCK(sp);
+}
+
+static void
+sppp_notify_tls_wlocked(struct sppp *sp)
+{
+
+	KASSERT(SPPP_WLOCKED(sp));
+
+	if (!sp->pp_tls)
+		return;
+
+	SPPP_UNLOCK(sp);
+	sp->pp_tls(sp);
+	SPPP_LOCK(sp, RW_WRITER);
+}
+
+static void
+sppp_notify_tlf_wlocked(struct sppp *sp)
+{
+
+	KASSERT(SPPP_WLOCKED(sp));
+
+	if (!sp->pp_tlf)
+		return;
+
+	SPPP_UNLOCK(sp);
+	sp->pp_tlf(sp);
+	SPPP_LOCK(sp, RW_WRITER);
+}
+
+static void
+sppp_notify_con(struct sppp *sp)
+{
+
+	if (!sp->pp_con)
+		return;
+
+	sp->pp_con(sp);
+}
+
+static void
+sppp_notify_con_wlocked(struct sppp *sp)
+{
+
+	KASSERT(SPPP_WLOCKED(sp));
+
+	SPPP_UNLOCK(sp);
+	sppp_notify_con(sp);
+	SPPP_LOCK(sp, RW_WRITER);
+
+}
+
+static void
+sppp_notify_chg_wlocked(struct sppp *sp)
+{
+
+	KASSERT(SPPP_WLOCKED(sp));
+
+	if (!sp->pp_chg)
+		return;
+
+	SPPP_UNLOCK(sp);
+	sp->pp_chg(sp, sp->pp_phase);
+	SPPP_LOCK(sp, RW_WRITER);
+}

Index: src/sys/net/if_spppvar.h
diff -u src/sys/net/if_spppvar.h:1.20 src/sys/net/if_spppvar.h:1.21
--- src/sys/net/if_spppvar.h:1.20	Tue Dec 13 00:35:11 2016
+++ src/sys/net/if_spppvar.h	Thu Oct 12 09:49:43 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_spppvar.h,v 1.20 2016/12/13 00:35:11 knakahara Exp $	*/
+/*	$NetBSD: if_spppvar.h,v 1.21 2017/10/12 09:49:43 knakahara Exp $	*/
 
 #ifndef _NET_IF_SPPPVAR_H_
 #define _NET_IF_SPPPVAR_H_
@@ -111,7 +111,7 @@ struct sppp {
 	int	pp_auth_failures;	/* authorization failures */
 	int	pp_max_auth_fail;	/* max. allowed authorization failures */
 	int	pp_phase;	/* phase we're currently in */
-	kmutex_t	*pp_lock;	/* lock for sppp structure */
+	krwlock_t	pp_lock;	/* lock for sppp structure */
 	int	query_dns;	/* 1 if we want to know the dns addresses */
 	uint32_t	dns_addrs[2];
 	int	state[IDX_COUNT];	/* state machine */
@@ -181,8 +181,5 @@ int sppp_ioctl(struct ifnet *, u_long, v
 struct mbuf *sppp_dequeue (struct ifnet *);
 int sppp_isempty (struct ifnet *);
 void sppp_flush (struct ifnet *);
-void sppp_lock_enter(struct sppp *);
-void sppp_lock_exit(struct sppp *);
-int sppp_locked(struct sppp *);
 #endif
 #endif /* !_NET_IF_SPPPVAR_H_ */

Reply via email to