Module Name: src
Committed By: knakahara
Date: Tue Dec 13 00:35:11 UTC 2016
Modified Files:
src/sys/net: if_pppoe.c if_spppsubr.c if_spppvar.h
Log Message:
MP-safe pppoe(4).
Nearly all parts is implemented by Shoichi YAMAGUCHI<s-yamaguchi@IIJ>, thanks.
To generate a diff of this commit:
cvs rdiff -u -r1.119 -r1.120 src/sys/net/if_pppoe.c
cvs rdiff -u -r1.162 -r1.163 src/sys/net/if_spppsubr.c
cvs rdiff -u -r1.19 -r1.20 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.119 src/sys/net/if_pppoe.c:1.120
--- src/sys/net/if_pppoe.c:1.119 Fri Nov 18 08:13:02 2016
+++ src/sys/net/if_pppoe.c Tue Dec 13 00:35:11 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: if_pppoe.c,v 1.119 2016/11/18 08:13:02 knakahara Exp $ */
+/* $NetBSD: if_pppoe.c,v 1.120 2016/12/13 00:35:11 knakahara Exp $ */
/*-
* Copyright (c) 2002, 2008 The NetBSD Foundation, Inc.
@@ -30,11 +30,12 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.119 2016/11/18 08:13:02 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.120 2016/12/13 00:35:11 knakahara Exp $");
#ifdef _KERNEL_OPT
#include "pppoe.h"
#include "opt_pppoe.h"
+#include "opt_net_mpsafe.h"
#endif
#include <sys/param.h>
@@ -52,6 +53,8 @@ __KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v
#include <sys/device.h>
#include <sys/module.h>
#include <sys/sysctl.h>
+#include <sys/rwlock.h>
+#include <sys/mutex.h>
#include <net/if.h>
#include <net/if_types.h>
@@ -64,6 +67,10 @@ __KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v
#include "ioconf.h"
+#ifdef NET_MPSAFE
+#define PPPOE_MPSAFE 1
+#endif
+
struct pppoehdr {
uint8_t vertype;
uint8_t code;
@@ -125,12 +132,39 @@ struct pppoetag {
#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */
#endif
+#define PPPOE_SESSION_LOCK(_sc, _op) rw_enter(&(_sc)->sc_session_lock, (_op))
+#define PPPOE_SESSION_UNLOCK(_sc) rw_exit(&(_sc)->sc_session_lock)
+#define PPPOE_SESSION_LOCKED(_sc) rw_lock_held(&(_sc)->sc_session_lock)
+#define PPPOE_SESSION_WLOCKED(_sc) rw_write_held(&(_sc)->sc_session_lock)
+#define PPPOE_SESSION_RLOCKED(_sc) rw_read_held(&(_sc)->sc_session_lock)
+
+#define PPPOE_PARAM_LOCK(_sc) if ((_sc)->sc_lock) \
+ mutex_enter((_sc)->sc_lock)
+#define PPPOE_PARAM_UNLOCK(_sc) if ((_sc)->sc_lock) \
+ mutex_exit((_sc)->sc_lock)
+#define PPPOE_PARAM_LOCKED(_sc) (!(_sc)->sc_lock || \
+ mutex_owned((_sc)->sc_lock))
+#ifdef PPPOE_MPSAFE
+#define DECLARE_SPLNET_VARIABLE
+#define ACQUIRE_SPLNET() do { } while (0)
+#define RELEASE_SPLNET() do { } while (0)
+#else
+#define DECLARE_SPLNET_VARIABLE int __s
+#define ACQUIRE_SPLNET() do { \
+ __s = splnet(); \
+ } while (0)
+#define RELEASE_SPLNET() do { \
+ splx(__s); \
+ } while (0)
+#endif
+
struct pppoe_softc {
struct sppp sc_sppp; /* contains a struct ifnet as first element */
LIST_ENTRY(pppoe_softc) sc_list;
struct ifnet *sc_eth_if; /* ethernet interface we are using */
int sc_state; /* discovery phase or session connected */
+ bool sc_state_updating; /* state update in other components */
struct ether_addr sc_dest; /* hardware address of concentrator */
uint16_t sc_session; /* PPPoE session id */
@@ -147,6 +181,8 @@ struct pppoe_softc {
callout_t sc_timeout; /* timeout while not in session state */
int sc_padi_retried; /* number of PADI retries already done */
int sc_padr_retried; /* number of PADR retries already done */
+ krwlock_t sc_session_lock; /* lock of sc_state, sc_session, and sc_eth_if */
+ kmutex_t *sc_lock; /* lock of other parameters */
};
/* incoming traffic will be queued here */
@@ -173,6 +209,9 @@ static int pppoe_ioctl(struct ifnet *, u
static void pppoe_tls(struct sppp *);
static void pppoe_tlf(struct sppp *);
static void pppoe_start(struct ifnet *);
+#ifdef PPPOE_MPSAFE
+static int pppoe_transmit(struct ifnet *, struct mbuf *);
+#endif
static void pppoe_clear_softc(struct pppoe_softc *, const char *);
/* internal timeout handling */
@@ -191,13 +230,15 @@ static int pppoe_send_padt(struct ifnet
static int pppoe_output(struct pppoe_softc *, struct mbuf *);
/* internal helper functions */
-static struct pppoe_softc * pppoe_find_softc_by_session(u_int, struct ifnet *);
-static struct pppoe_softc * pppoe_find_softc_by_hunique(uint8_t *, size_t, struct ifnet *);
+static struct pppoe_softc * pppoe_find_softc_by_session(u_int, struct ifnet *, krw_t);
+static struct pppoe_softc * pppoe_find_softc_by_hunique(uint8_t *, size_t,
+ struct ifnet *, krw_t);
static struct mbuf *pppoe_get_mbuf(size_t len);
static int pppoe_ifattach_hook(void *, struct mbuf **, struct ifnet *, int);
static LIST_HEAD(pppoe_softc_head, pppoe_softc) pppoe_softc_list;
+static krwlock_t pppoe_softc_list_lock;
static int pppoe_clone_create(struct if_clone *, int);
static int pppoe_clone_destroy(struct ifnet *);
@@ -226,10 +267,11 @@ pppoeinit(void)
{
LIST_INIT(&pppoe_softc_list);
+ rw_init(&pppoe_softc_list_lock);
if_clone_attach(&pppoe_cloner);
- pppoe_softintr = softint_establish(SOFTINT_NET, pppoe_softintr_handler,
- NULL);
+ pppoe_softintr = softint_establish(SOFTINT_MPSAFE|SOFTINT_NET,
+ pppoe_softintr_handler, NULL);
sysctl_net_pppoe_setup(&pppoe_sysctl_clog);
IFQ_LOCK_INIT(&ppoediscinq);
@@ -265,6 +307,9 @@ pppoe_clone_create(struct if_clone *ifc,
sc->sc_sppp.pp_if.if_softc = sc;
sc->sc_sppp.pp_if.if_mtu = PPPOE_MAXMTU;
sc->sc_sppp.pp_if.if_flags = IFF_SIMPLEX|IFF_POINTOPOINT|IFF_MULTICAST;
+#ifdef PPPOE_MPSAFE
+ sc->sc_sppp.pp_if.if_extflags = IFEF_OUTPUT_MPSAFE;
+#endif
sc->sc_sppp.pp_if.if_type = IFT_PPP;
sc->sc_sppp.pp_if.if_hdrlen = sizeof(struct ether_header) + PPPOE_HEADERLEN;
sc->sc_sppp.pp_if.if_dlt = DLT_PPP_ETHER;
@@ -280,6 +325,9 @@ pppoe_clone_create(struct if_clone *ifc,
callout_init(&sc->sc_timeout, 0);
sc->sc_sppp.pp_if.if_start = pppoe_start;
+#ifdef PPPOE_MPSAFE
+ sc->sc_sppp.pp_if.if_transmit = pppoe_transmit;
+#endif
sc->sc_sppp.pp_tls = pppoe_tls;
sc->sc_sppp.pp_tlf = pppoe_tlf;
sc->sc_sppp.pp_framebytes = PPPOE_HEADERLEN; /* framing added to ppp packets */
@@ -293,7 +341,13 @@ pppoe_clone_create(struct if_clone *ifc,
if (LIST_EMPTY(&pppoe_softc_list)) {
pfil_add_hook(pppoe_ifattach_hook, NULL, PFIL_IFNET, if_pfil);
}
+
+ sc->sc_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTNET);
+ rw_init(&sc->sc_session_lock);
+
+ rw_enter(&pppoe_softc_list_lock, RW_WRITER);
LIST_INSERT_HEAD(&pppoe_softc_list, sc, sc_list);
+ rw_exit(&pppoe_softc_list_lock);
return 0;
}
@@ -302,11 +356,20 @@ pppoe_clone_destroy(struct ifnet *ifp)
{
struct pppoe_softc * sc = ifp->if_softc;
- callout_stop(&sc->sc_timeout);
+ rw_enter(&pppoe_softc_list_lock, RW_WRITER);
+
+ PPPOE_PARAM_LOCK(sc);
+ callout_halt(&sc->sc_timeout, NULL);
+
LIST_REMOVE(sc, sc_list);
+
if (LIST_EMPTY(&pppoe_softc_list)) {
pfil_remove_hook(pppoe_ifattach_hook, NULL, PFIL_IFNET, if_pfil);
}
+ rw_exit(&pppoe_softc_list_lock);
+
+ PPPOE_SESSION_LOCK(sc, RW_WRITER);
+
bpf_detach(ifp);
sppp_detach(&sc->sc_sppp.pp_if);
if_detach(ifp);
@@ -319,6 +382,13 @@ pppoe_clone_destroy(struct ifnet *ifp)
if (sc->sc_relay_sid)
free(sc->sc_relay_sid, M_DEVBUF);
callout_destroy(&sc->sc_timeout);
+
+ PPPOE_PARAM_UNLOCK(sc);
+ if (sc->sc_lock)
+ mutex_obj_free(sc->sc_lock);
+ PPPOE_SESSION_UNLOCK(sc);
+ rw_destroy(&sc->sc_session_lock);
+
free(sc, M_DEVBUF);
return (0);
@@ -331,26 +401,32 @@ pppoe_clone_destroy(struct ifnet *ifp)
* be 1.
*/
static struct pppoe_softc *
-pppoe_find_softc_by_session(u_int session, struct ifnet *rcvif)
+pppoe_find_softc_by_session(u_int session, struct ifnet *rcvif, krw_t lock)
{
- struct pppoe_softc *sc;
+ struct pppoe_softc *sc = NULL;
if (session == 0)
return NULL;
-
+ rw_enter(&pppoe_softc_list_lock, RW_READER);
LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
- if (sc->sc_state == PPPOE_STATE_SESSION
+ PPPOE_SESSION_LOCK(sc, lock);
+ if (!sc->sc_state_updating
+ && sc->sc_state == PPPOE_STATE_SESSION
&& sc->sc_session == session
&& sc->sc_eth_if == rcvif)
- return sc;
+ break;
+
+ PPPOE_SESSION_UNLOCK(sc);
}
- return NULL;
+ rw_exit(&pppoe_softc_list_lock);
+ return sc;
}
/* Check host unique token passed and return appropriate softc pointer,
* or NULL if token is bogus. */
static struct pppoe_softc *
-pppoe_find_softc_by_hunique(uint8_t *token, size_t len, struct ifnet *rcvif)
+pppoe_find_softc_by_hunique(uint8_t *token, size_t len,
+ struct ifnet *rcvif, krw_t lock)
{
struct pppoe_softc *sc, *t;
@@ -361,8 +437,14 @@ pppoe_find_softc_by_hunique(uint8_t *tok
return NULL;
memcpy(&t, token, len);
- LIST_FOREACH(sc, &pppoe_softc_list, sc_list)
- if (sc == t) break;
+ rw_enter(&pppoe_softc_list_lock, RW_READER);
+ LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
+ if (sc == t) {
+ PPPOE_SESSION_LOCK(sc, lock);
+ break;
+ }
+ }
+ rw_exit(&pppoe_softc_list_lock);
if (sc == NULL) {
#ifdef PPPOE_DEBUG
@@ -371,15 +453,26 @@ pppoe_find_softc_by_hunique(uint8_t *tok
return NULL;
}
+ if (sc->sc_state_updating) {
+#ifdef PPPOE_DEBUG
+ printf("%s: host unique tag found, but its state is updating\n",
+ sc->sc_sppp.pp_if.if_xname);
+#endif
+ PPPOE_SESSION_UNLOCK(sc);
+ return NULL;
+ }
+
/* should be safe to access *sc now */
if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) {
printf("%s: host unique tag found, but it belongs to a connection in state %d\n",
sc->sc_sppp.pp_if.if_xname, sc->sc_state);
+ PPPOE_SESSION_UNLOCK(sc);
return NULL;
}
if (sc->sc_eth_if != rcvif) {
printf("%s: wrong interface, not accepting host unique\n",
sc->sc_sppp.pp_if.if_xname);
+ PPPOE_SESSION_UNLOCK(sc);
return NULL;
}
return sc;
@@ -389,9 +482,7 @@ static void
pppoe_softintr_handler(void *dummy)
{
/* called at splsoftnet() */
- mutex_enter(softnet_lock);
pppoeintr();
- mutex_exit(softnet_lock);
}
/* called at appropriate protection level */
@@ -401,6 +492,10 @@ pppoeintr(void)
struct mbuf *m;
int disc_done, data_done;
+#ifndef PPPOE_MPSAFE
+ mutex_enter(softnet_lock);
+#endif
+
do {
disc_done = 0;
data_done = 0;
@@ -422,6 +517,9 @@ pppoeintr(void)
pppoe_data_input(m);
}
} while (disc_done || data_done);
+#ifndef PPPOE_MPSAFE
+ mutex_exit(softnet_lock);
+#endif
}
/* analyze and handle a single received packet while not in session state */
@@ -431,7 +529,8 @@ pppoe_dispatch_disc_pkt(struct mbuf *m,
uint16_t tag, len;
uint16_t session, plen;
struct pppoe_softc *sc;
- const char *err_msg, *devname;
+ const char *err_msg;
+ char devname[IF_NAMESIZE];
char *error;
uint8_t *ac_cookie;
size_t ac_cookie_len;
@@ -447,7 +546,9 @@ pppoe_dispatch_disc_pkt(struct mbuf *m,
int noff, err, errortag;
struct ether_header *eh;
- devname = "pppoe"; /* as long as we don't know which instance */
+ /* as long as we don't know which instance */
+ strlcpy(devname, "pppoe", sizeof(devname));
+
err_msg = NULL;
errortag = 0;
if (m->m_len < sizeof(*eh)) {
@@ -552,10 +653,13 @@ pppoe_dispatch_disc_pkt(struct mbuf *m,
#endif
rcvif = m_get_rcvif(m, &s);
sc = pppoe_find_softc_by_hunique(mtod(n, char *) + noff,
- len, rcvif);
+ len, rcvif, RW_READER);
m_put_rcvif(rcvif, &s);
- if (sc != NULL)
- devname = sc->sc_sppp.pp_if.if_xname;
+ if (sc != NULL) {
+ strlcpy(devname, sc->sc_sppp.pp_if.if_xname,
+ sizeof(devname));
+ PPPOE_SESSION_UNLOCK(sc);
+ }
break;
}
case PPPOE_TAG_ACCOOKIE:
@@ -629,31 +733,50 @@ breakbreak:;
*/
if (LIST_EMPTY(&pppoe_softc_list))
goto done;
+ rw_enter(&pppoe_softc_list_lock, RW_READER);
LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
- if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP))
+ PPPOE_SESSION_LOCK(sc, RW_WRITER);
+ if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP)) {
+ PPPOE_SESSION_UNLOCK(sc);
continue;
- if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE))
+ }
+ if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) {
+ PPPOE_SESSION_UNLOCK(sc);
continue;
- if (sc->sc_state == PPPOE_STATE_INITIAL)
+ }
+
+ if (!sc->sc_state_updating
+ && sc->sc_state == PPPOE_STATE_INITIAL)
break;
+
+ PPPOE_SESSION_UNLOCK(sc);
}
+ rw_exit(&pppoe_softc_list_lock);
+
if (sc == NULL) {
/* printf("pppoe: free passive interface is not found\n");*/
goto done;
}
+
+ PPPOE_PARAM_LOCK(sc);
if (hunique) {
if (sc->sc_hunique)
free(sc->sc_hunique, M_DEVBUF);
sc->sc_hunique = malloc(hunique_len, M_DEVBUF,
M_DONTWAIT);
- if (sc->sc_hunique == NULL)
+ if (sc->sc_hunique == NULL) {
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
goto done;
+ }
sc->sc_hunique_len = hunique_len;
memcpy(sc->sc_hunique, hunique, hunique_len);
}
memcpy(&sc->sc_dest, eh->ether_shost, sizeof sc->sc_dest);
sc->sc_state = PPPOE_STATE_PADO_SENT;
pppoe_send_pado(sc);
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
break;
#endif /* PPPOE_SERVER */
case PPPOE_CODE_PADR:
@@ -668,31 +791,44 @@ breakbreak:;
}
sc = pppoe_find_softc_by_hunique(ac_cookie,
ac_cookie_len,
- m_get_rcvif_NOMPSAFE(m));
+ m_get_rcvif_NOMPSAFE(m),
+ RW_WRITER);
if (sc == NULL) {
/* be quiet if there is not a single pppoe instance */
if (!LIST_EMPTY(&pppoe_softc_list))
printf("pppoe: received PADR but could not find request for it\n");
goto done;
}
- if (sc->sc_state != PPPOE_STATE_PADO_SENT) {
+
+ if (sc->sc_state_updating
+ || sc->sc_state != PPPOE_STATE_PADO_SENT) {
printf("%s: received unexpected PADR\n",
sc->sc_sppp.pp_if.if_xname);
+ PPPOE_SESSION_UNLOCK(sc);
goto done;
}
+ PPPOE_PARAM_LOCK(sc);
if (hunique) {
if (sc->sc_hunique)
free(sc->sc_hunique, M_DEVBUF);
sc->sc_hunique = malloc(hunique_len, M_DEVBUF,
M_DONTWAIT);
- if (sc->sc_hunique == NULL)
+ if (sc->sc_hunique == NULL) {
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
goto done;
+ }
sc->sc_hunique_len = hunique_len;
memcpy(sc->sc_hunique, hunique, hunique_len);
}
pppoe_send_pads(sc);
sc->sc_state = PPPOE_STATE_SESSION;
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
+
+ sppp_lock_enter(&sc->sc_sppp);
sc->sc_sppp.pp_up(&sc->sc_sppp);
+ sppp_lock_exit(&sc->sc_sppp);
break;
#else
/* ignore, we are no access concentrator */
@@ -705,11 +841,18 @@ breakbreak:;
printf("pppoe: received PADO but could not find request for it\n");
goto done;
}
- if (sc->sc_state != PPPOE_STATE_PADI_SENT) {
+
+ PPPOE_SESSION_LOCK(sc, RW_WRITER);
+
+ if (sc->sc_state_updating
+ || sc->sc_state != PPPOE_STATE_PADI_SENT) {
printf("%s: received unexpected PADO\n",
sc->sc_sppp.pp_if.if_xname);
+ PPPOE_SESSION_UNLOCK(sc);
goto done;
}
+
+ PPPOE_PARAM_LOCK(sc);
if (ac_cookie) {
if (sc->sc_ac_cookie)
free(sc->sc_ac_cookie, M_DEVBUF);
@@ -719,6 +862,8 @@ breakbreak:;
printf("%s: FATAL: could not allocate memory "
"for AC cookie\n",
sc->sc_sppp.pp_if.if_xname);
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
goto done;
}
sc->sc_ac_cookie_len = ac_cookie_len;
@@ -733,6 +878,8 @@ breakbreak:;
printf("%s: FATAL: could not allocate memory "
"for relay SID\n",
sc->sc_sppp.pp_if.if_xname);
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
goto done;
}
sc->sc_relay_sid_len = relay_sid_len;
@@ -751,34 +898,63 @@ breakbreak:;
callout_reset(&sc->sc_timeout,
PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried),
pppoe_timeout, sc);
+
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
break;
case PPPOE_CODE_PADS:
if (sc == NULL)
goto done;
+
+ PPPOE_SESSION_LOCK(sc, RW_WRITER);
+ PPPOE_PARAM_LOCK(sc);
+
+ if (sc->sc_state_updating) {
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
+ goto done;
+ }
+
sc->sc_session = session;
callout_stop(&sc->sc_timeout);
if (sc->sc_sppp.pp_if.if_flags & IFF_DEBUG)
printf("%s: session 0x%x connected\n",
sc->sc_sppp.pp_if.if_xname, session);
sc->sc_state = PPPOE_STATE_SESSION;
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_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;
int s;
rcvif = m_get_rcvif(m, &s);
- sc = pppoe_find_softc_by_session(session, rcvif);
+ sc = pppoe_find_softc_by_session(session, rcvif, RW_WRITER);
m_put_rcvif(rcvif, &s);
if (sc == NULL)
goto done;
+
+ PPPOE_PARAM_LOCK(sc);
pppoe_clear_softc(sc, "received PADT");
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
break;
}
default:
+ if (sc != NULL) {
+ PPPOE_SESSION_LOCK(sc, RW_READER);
+ strlcpy(devname, sc->sc_sppp.pp_if.if_xname,
+ sizeof(devname));
+ PPPOE_SESSION_UNLOCK(sc);
+ } else
+ strlcpy(devname, "pppoe", sizeof(devname));
+
printf("%s: unknown code (0x%04x) session = 0x%04x\n",
- sc? sc->sc_sppp.pp_if.if_xname : "pppoe",
- ph->code, session);
+ devname, ph->code, session);
break;
}
@@ -843,7 +1019,7 @@ pppoe_data_input(struct mbuf *m)
rcvif = m_get_rcvif_psref(m, &psref);
if (__predict_false(rcvif == NULL))
goto drop;
- sc = pppoe_find_softc_by_session(session, rcvif);
+ sc = pppoe_find_softc_by_session(session, rcvif, RW_READER);
if (sc == NULL) {
if (pppoe_term_unknown) {
printf("pppoe: input for unknown session %#x, "
@@ -853,6 +1029,7 @@ pppoe_data_input(struct mbuf *m)
m_put_rcvif_psref(rcvif, &psref);
goto drop;
}
+
m_put_rcvif_psref(rcvif, &psref);
plen = ntohs(ph->plen);
@@ -876,6 +1053,7 @@ pppoe_data_input(struct mbuf *m)
printf("\n");
}
#endif
+ PPPOE_SESSION_UNLOCK(sc);
if (m->m_pkthdr.len < plen)
goto drop;
@@ -899,6 +1077,9 @@ pppoe_output(struct pppoe_softc *sc, str
struct ether_header *eh;
uint16_t etype;
+ KASSERT(PPPOE_SESSION_LOCKED(sc));
+ KASSERT(PPPOE_PARAM_LOCKED(sc));
+
if (sc->sc_eth_if == NULL) {
m_freem(m);
return EIO;
@@ -942,9 +1123,11 @@ pppoe_ioctl(struct ifnet *ifp, unsigned
if (parms->eth_ifname[0] != 0) {
struct ifnet *eth_if;
+ PPPOE_SESSION_LOCK(sc, RW_WRITER);
eth_if = ifunit(parms->eth_ifname);
if (eth_if == NULL || eth_if->if_dlt != DLT_EN10MB) {
sc->sc_eth_if = NULL;
+ PPPOE_SESSION_UNLOCK(sc);
return ENXIO;
}
@@ -954,6 +1137,7 @@ pppoe_ioctl(struct ifnet *ifp, unsigned
PPPOE_OVERHEAD;
}
sc->sc_eth_if = eth_if;
+ PPPOE_SESSION_UNLOCK(sc);
}
if (parms->ac_name != NULL) {
size_t s;
@@ -971,9 +1155,12 @@ pppoe_ioctl(struct ifnet *ifp, unsigned
free(b, M_DEVBUF);
return EINVAL;
}
+
+ PPPOE_PARAM_LOCK(sc);
if (sc->sc_concentrator_name)
free(sc->sc_concentrator_name, M_DEVBUF);
sc->sc_concentrator_name = b;
+ PPPOE_PARAM_UNLOCK(sc);
}
if (parms->service_name != NULL) {
size_t s;
@@ -991,9 +1178,12 @@ pppoe_ioctl(struct ifnet *ifp, unsigned
free(b, M_DEVBUF);
return EINVAL;
}
+
+ PPPOE_PARAM_LOCK(sc);
if (sc->sc_service_name)
free(sc->sc_service_name, M_DEVBUF);
sc->sc_service_name = b;
+ PPPOE_PARAM_UNLOCK(sc);
}
return 0;
}
@@ -1002,19 +1192,25 @@ pppoe_ioctl(struct ifnet *ifp, unsigned
{
struct pppoediscparms *parms = (struct pppoediscparms*)data;
memset(parms, 0, sizeof *parms);
+ PPPOE_SESSION_LOCK(sc, RW_READER);
if (sc->sc_eth_if)
strlcpy(parms->ifname, sc->sc_eth_if->if_xname,
sizeof(parms->ifname));
+ PPPOE_SESSION_UNLOCK(sc);
return 0;
}
break;
case PPPOEGETSESSION:
{
struct pppoeconnectionstate *state = (struct pppoeconnectionstate*)data;
+ PPPOE_SESSION_LOCK(sc, RW_READER);
+ PPPOE_PARAM_LOCK(sc);
state->state = sc->sc_state;
state->session_id = sc->sc_session;
state->padi_retry_no = sc->sc_padi_retried;
state->padr_retry_no = sc->sc_padr_retried;
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
return 0;
}
break;
@@ -1023,6 +1219,9 @@ pppoe_ioctl(struct ifnet *ifp, unsigned
* Prevent running re-establishment timers overriding
* administrators choice.
*/
+ PPPOE_SESSION_LOCK(sc, RW_WRITER);
+ PPPOE_PARAM_LOCK(sc);
+
if ((ifr->ifr_flags & IFF_UP) == 0
&& sc->sc_state >= PPPOE_STATE_PADI_SENT
&& sc->sc_state < PPPOE_STATE_SESSION) {
@@ -1032,8 +1231,19 @@ pppoe_ioctl(struct ifnet *ifp, unsigned
sc->sc_padr_retried = 0;
memcpy(&sc->sc_dest, etherbroadcastaddr,
sizeof(sc->sc_dest));
+ sc->sc_state_updating = 1;
}
- return sppp_ioctl(ifp, cmd, data);
+
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
+
+ error = sppp_ioctl(ifp, cmd, data);
+
+ PPPOE_SESSION_LOCK(sc, RW_WRITER);
+ sc->sc_state_updating = 0;
+ PPPOE_SESSION_UNLOCK(sc);
+
+ return error;
case SIOCSIFMTU:
if (ifr->ifr_mtu > (sc->sc_eth_if == NULL ?
PPPOE_MAXMTU : (sc->sc_eth_if->if_mtu - PPPOE_OVERHEAD))) {
@@ -1081,6 +1291,9 @@ pppoe_send_padi(struct pppoe_softc *sc)
int len, l1 = 0, l2 = 0; /* XXX: gcc */
uint8_t *p;
+ KASSERT(PPPOE_SESSION_LOCKED(sc));
+ KASSERT(PPPOE_PARAM_LOCKED(sc));
+
if (sc->sc_state >PPPOE_STATE_PADI_SENT)
panic("pppoe_send_padi in state %d", sc->sc_state);
@@ -1145,13 +1358,16 @@ pppoe_send_padi(struct pppoe_softc *sc)
static void
pppoe_timeout(void *arg)
{
- int x, retry_wait, err;
+ int retry_wait, err;
struct pppoe_softc *sc = (struct pppoe_softc*)arg;
+ DECLARE_SPLNET_VARIABLE;
#ifdef PPPOE_DEBUG
printf("%s: timeout\n", sc->sc_sppp.pp_if.if_xname);
#endif
+ PPPOE_SESSION_LOCK(sc, RW_WRITER);
+ PPPOE_PARAM_LOCK(sc);
switch (sc->sc_state) {
case PPPOE_STATE_INITIAL:
/* delayed connect from pppoe_tls() */
@@ -1171,7 +1387,7 @@ pppoe_timeout(void *arg)
/* initialize for quick retry mode */
retry_wait = PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried);
- x = splnet();
+ ACQUIRE_SPLNET();
sc->sc_padi_retried++;
if (sc->sc_padi_retried >= PPPOE_DISC_MAXPADI) {
if ((sc->sc_sppp.pp_if.if_flags & IFF_LINK1) == 0) {
@@ -1179,7 +1395,9 @@ pppoe_timeout(void *arg)
retry_wait = PPPOE_SLOW_RETRY;
} else {
pppoe_abort_connect(sc);
- splx(x);
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
+ RELEASE_SPLNET();
return;
}
}
@@ -1192,11 +1410,11 @@ pppoe_timeout(void *arg)
}
callout_reset(&sc->sc_timeout, retry_wait,
pppoe_timeout, sc);
- splx(x);
+ RELEASE_SPLNET();
break;
case PPPOE_STATE_PADR_SENT:
- x = splnet();
+ ACQUIRE_SPLNET();
sc->sc_padr_retried++;
if (sc->sc_padr_retried >= PPPOE_DISC_MAXPADR) {
memcpy(&sc->sc_dest, etherbroadcastaddr,
@@ -1213,7 +1431,9 @@ pppoe_timeout(void *arg)
callout_reset(&sc->sc_timeout,
PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried),
pppoe_timeout, sc);
- splx(x);
+ RELEASE_SPLNET();
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
return;
}
if ((err = pppoe_send_padr(sc)) != 0) {
@@ -1226,21 +1446,29 @@ pppoe_timeout(void *arg)
callout_reset(&sc->sc_timeout,
PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried),
pppoe_timeout, sc);
- splx(x);
+ RELEASE_SPLNET();
break;
case PPPOE_STATE_CLOSING:
pppoe_disconnect(sc);
break;
default:
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
return; /* all done, work in peace */
}
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
}
/* Start a connection (i.e. initiate discovery phase) */
static int
pppoe_connect(struct pppoe_softc *sc)
{
- int x, err;
+ int err;
+ DECLARE_SPLNET_VARIABLE;
+
+ KASSERT(PPPOE_SESSION_WLOCKED(sc));
+ KASSERT(PPPOE_PARAM_LOCKED(sc));
if (sc->sc_state != PPPOE_STATE_INITIAL)
return EBUSY;
@@ -1250,7 +1478,7 @@ pppoe_connect(struct pppoe_softc *sc)
if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE))
return 0;
#endif
- x = splnet();
+ ACQUIRE_SPLNET();
/* save state, in case we fail to send PADI */
sc->sc_state = PPPOE_STATE_PADI_SENT;
sc->sc_padr_retried = 0;
@@ -1259,7 +1487,7 @@ pppoe_connect(struct pppoe_softc *sc)
printf("%s: failed to send PADI, error=%d\n",
sc->sc_sppp.pp_if.if_xname, err);
callout_reset(&sc->sc_timeout, PPPOE_DISC_TIMEOUT, pppoe_timeout, sc);
- splx(x);
+ RELEASE_SPLNET();
return err;
}
@@ -1267,9 +1495,13 @@ pppoe_connect(struct pppoe_softc *sc)
static int
pppoe_disconnect(struct pppoe_softc *sc)
{
- int err, x;
+ int err;
+ DECLARE_SPLNET_VARIABLE;
+
+ KASSERT(PPPOE_SESSION_WLOCKED(sc));
+ KASSERT(PPPOE_PARAM_LOCKED(sc));
- x = splnet();
+ ACQUIRE_SPLNET();
if (sc->sc_state < PPPOE_STATE_SESSION)
err = EBUSY;
@@ -1282,6 +1514,8 @@ pppoe_disconnect(struct pppoe_softc *sc)
/* cleanup softc */
sc->sc_state = PPPOE_STATE_INITIAL;
+ sc->sc_state_updating = 1;
+
memcpy(&sc->sc_dest, etherbroadcastaddr, sizeof(sc->sc_dest));
if (sc->sc_ac_cookie) {
free(sc->sc_ac_cookie, M_DEVBUF);
@@ -1302,11 +1536,19 @@ pppoe_disconnect(struct pppoe_softc *sc)
#endif
sc->sc_session = 0;
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_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);
- splx(x);
+ PPPOE_SESSION_LOCK(sc, RW_WRITER);
+ PPPOE_PARAM_LOCK(sc);
+ sc->sc_state_updating = 0;
+ RELEASE_SPLNET();
return err;
}
@@ -1314,12 +1556,26 @@ pppoe_disconnect(struct pppoe_softc *sc)
static void
pppoe_abort_connect(struct pppoe_softc *sc)
{
+ KASSERT(PPPOE_SESSION_WLOCKED(sc));
+ KASSERT(PPPOE_PARAM_LOCKED(sc));
+
printf("%s: could not establish connection\n",
sc->sc_sppp.pp_if.if_xname);
sc->sc_state = PPPOE_STATE_CLOSING;
+ sc->sc_state_updating = 1;
+
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_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_SESSION_LOCK(sc, RW_WRITER);
+ PPPOE_PARAM_LOCK(sc);
+
+ sc->sc_state_updating = 0;
/* clear connection state */
memcpy(&sc->sc_dest, etherbroadcastaddr, sizeof(sc->sc_dest));
@@ -1334,6 +1590,9 @@ pppoe_send_padr(struct pppoe_softc *sc)
uint8_t *p;
size_t len, l1 = 0; /* XXX: gcc */
+ KASSERT(PPPOE_SESSION_LOCKED(sc));
+ KASSERT(PPPOE_PARAM_LOCKED(sc));
+
if (sc->sc_state != PPPOE_STATE_PADR_SENT)
return EIO;
@@ -1428,6 +1687,9 @@ pppoe_send_pado(struct pppoe_softc *sc)
uint8_t *p;
size_t len;
+ KASSERT(PPPOE_SESSION_LOCKED(sc)); /* required by pppoe_output(). */
+ KASSERT(PPPOE_PARAM_LOCKED(sc));
+
if (sc->sc_state != PPPOE_STATE_PADO_SENT)
return EIO;
@@ -1460,6 +1722,9 @@ pppoe_send_pads(struct pppoe_softc *sc)
uint8_t *p;
size_t len, l1 = 0; /* XXX: gcc */
+ KASSERT(PPPOE_SESSION_WLOCKED(sc));
+ KASSERT(PPPOE_PARAM_LOCKED(sc));
+
if (sc->sc_state != PPPOE_STATE_PADO_SENT)
return EIO;
@@ -1499,8 +1764,17 @@ pppoe_tls(struct sppp *sp)
struct pppoe_softc *sc = (void *)sp;
int wtime;
- if (sc->sc_state != PPPOE_STATE_INITIAL)
+ KASSERT(!PPPOE_SESSION_LOCKED(sc));
+ KASSERT(!PPPOE_PARAM_LOCKED(sc));
+
+ PPPOE_SESSION_LOCK(sc, RW_READER);
+
+ if (sc->sc_state != PPPOE_STATE_INITIAL) {
+ PPPOE_SESSION_UNLOCK(sc);
return;
+ }
+
+ PPPOE_PARAM_LOCK(sc);
if (sc->sc_sppp.pp_phase == SPPP_PHASE_ESTABLISH &&
sc->sc_sppp.pp_auth_failures > 0) {
@@ -1515,21 +1789,37 @@ pppoe_tls(struct sppp *sp)
wtime = PPPOE_RECON_IMMEDIATE;
}
callout_reset(&sc->sc_timeout, wtime, pppoe_timeout, sc);
+
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
}
static void
pppoe_tlf(struct sppp *sp)
{
struct pppoe_softc *sc = (void *)sp;
- if (sc->sc_state < PPPOE_STATE_SESSION)
+
+ KASSERT(!PPPOE_SESSION_LOCKED(sc));
+ KASSERT(!PPPOE_PARAM_LOCKED(sc));
+
+ PPPOE_SESSION_LOCK(sc, RW_WRITER);
+
+ if (sc->sc_state < PPPOE_STATE_SESSION) {
+ PPPOE_SESSION_UNLOCK(sc);
return;
+ }
/*
* Do not call pppoe_disconnect here, the upper layer state
* machine gets confused by this. We must return from this
* function and defer disconnecting to the timeout handler.
*/
sc->sc_state = PPPOE_STATE_CLOSING;
+ PPPOE_PARAM_LOCK(sc);
+
callout_reset(&sc->sc_timeout, hz/50, pppoe_timeout, sc);
+
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
}
static void
@@ -1557,37 +1847,89 @@ pppoe_start(struct ifnet *ifp)
continue;
}
p = mtod(m, uint8_t *);
+ PPPOE_SESSION_LOCK(sc, RW_READER);
PPPOE_ADD_HEADER(p, 0, sc->sc_session, len);
bpf_mtap(&sc->sc_sppp.pp_if, m);
+ PPPOE_PARAM_LOCK(sc);
pppoe_output(sc, m);
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
}
}
+#ifdef PPPOE_MPSAFE
+static int
+pppoe_transmit(struct ifnet *ifp, struct mbuf *m)
+{
+ struct pppoe_softc *sc = (void *)ifp;
+ uint8_t *p;
+ size_t len;
+
+ if (m == NULL)
+ return EINVAL;
+
+ /* are we ready to process data yet? */
+ PPPOE_SESSION_LOCK(sc, RW_READER);
+ if (sc->sc_state < PPPOE_STATE_SESSION) {
+ PPPOE_SESSION_UNLOCK(sc);
+ m_free(m);
+ return ENOBUFS;
+ }
+
+ len = m->m_pkthdr.len;
+ M_PREPEND(m, PPPOE_HEADERLEN, M_DONTWAIT);
+ if (m == NULL) {
+ PPPOE_SESSION_UNLOCK(sc);
+ ifp->if_oerrors++;
+ return ENETDOWN;
+ }
+ p = mtod(m, uint8_t *);
+ PPPOE_ADD_HEADER(p, 0, sc->sc_session, len);
+
+ bpf_mtap(&sc->sc_sppp.pp_if, m);
+
+ PPPOE_PARAM_LOCK(sc);
+ pppoe_output(sc, m);
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
+ return 0;
+}
+#endif /* PPPOE_MPSAFE */
static int
pppoe_ifattach_hook(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
{
struct pppoe_softc *sc;
- int s;
+ DECLARE_SPLNET_VARIABLE;
if (mp != (struct mbuf **)PFIL_IFNET_DETACH)
return 0;
- s = splnet();
+ ACQUIRE_SPLNET();
+ rw_enter(&pppoe_softc_list_lock, RW_READER);
LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
- if (sc->sc_eth_if != ifp)
+ PPPOE_SESSION_LOCK(sc, RW_WRITER);
+ if (sc->sc_eth_if != ifp) {
+ PPPOE_SESSION_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_PARAM_LOCK(sc);
pppoe_clear_softc(sc, "ethernet interface detached");
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_UNLOCK(sc);
}
- splx(s);
+ rw_exit(&pppoe_softc_list_lock);
+ RELEASE_SPLNET();
return 0;
}
@@ -1595,6 +1937,9 @@ pppoe_ifattach_hook(void *arg, struct mb
static void
pppoe_clear_softc(struct pppoe_softc *sc, const char *message)
{
+ KASSERT(PPPOE_SESSION_WLOCKED(sc));
+ KASSERT(PPPOE_PARAM_LOCKED(sc));
+
/* stop timer */
callout_stop(&sc->sc_timeout);
if (sc->sc_sppp.pp_if.if_flags & IFF_DEBUG)
@@ -1603,9 +1948,20 @@ pppoe_clear_softc(struct pppoe_softc *sc
/* fix our state */
sc->sc_state = PPPOE_STATE_INITIAL;
+ sc->sc_state_updating = 1;
+
+ PPPOE_PARAM_UNLOCK(sc);
+ PPPOE_SESSION_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_SESSION_LOCK(sc, RW_WRITER);
+ PPPOE_PARAM_LOCK(sc);
+
+ sc->sc_state_updating = 0;
/* clean up softc */
memcpy(&sc->sc_dest, etherbroadcastaddr, sizeof(sc->sc_dest));
Index: src/sys/net/if_spppsubr.c
diff -u src/sys/net/if_spppsubr.c:1.162 src/sys/net/if_spppsubr.c:1.163
--- src/sys/net/if_spppsubr.c:1.162 Tue Dec 6 07:01:47 2016
+++ src/sys/net/if_spppsubr.c Tue Dec 13 00:35:11 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: if_spppsubr.c,v 1.162 2016/12/06 07:01:47 knakahara Exp $ */
+/* $NetBSD: if_spppsubr.c,v 1.163 2016/12/13 00:35:11 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.162 2016/12/06 07:01:47 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_spppsubr.c,v 1.163 2016/12/13 00:35:11 knakahara Exp $");
#if defined(_KERNEL_OPT)
#include "opt_inet.h"
@@ -91,6 +91,10 @@ __KERNEL_RCSID(0, "$NetBSD: if_spppsubr.
#include <net/if_sppp.h>
#include <net/if_spppvar.h>
+#ifdef NET_MPSAFE
+#define SPPPSUBR_MPSAFE 1
+#endif
+
#define LCP_KEEPALIVE_INTERVAL 10 /* seconds between checks */
#define LOOPALIVECNT 3 /* loopback detection tries */
#define DEFAULT_MAXALIVECNT 3 /* max. missed alive packets */
@@ -242,9 +246,16 @@ struct cp {
};
static struct sppp *spppq;
+static kmutex_t *spppq_lock = NULL;
static callout_t keepalive_ch;
+#define SPPPQ_LOCK() if (spppq_lock) \
+ mutex_enter(spppq_lock);
+#define SPPPQ_UNLOCK() if (spppq_lock) \
+ mutex_exit(spppq_lock);
+
#ifdef INET
+#ifndef SPPPSUBR_MPSAFE
/*
* The following disgusting hack gets around the problem that IP TOS
* can't be set yet. We want to put "interactive" traffic on a high
@@ -258,6 +269,7 @@ static u_short interactive_ports[8] = {
0, 21, 0, 23,
};
#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
+#endif /* SPPPSUBR_MPSAFE */
#endif
/* almost every function needs these */
@@ -457,6 +469,8 @@ sppp_change_phase(struct sppp *sp, int p
{
STDDCL;
+ KASSERT(sppp_locked(sp));
+
if (sp->pp_phase == phase)
return;
@@ -492,6 +506,10 @@ 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);
+
if (ifp->if_flags & IFF_UP) {
/* Count received bytes, add hardware framing */
ifp->if_ibytes += m->m_pkthdr.len + sp->pp_framebytes;
@@ -509,6 +527,7 @@ sppp_input(struct ifnet *ifp, struct mbu
++ifp->if_ierrors;
++ifp->if_iqdrops;
m_freem(m);
+ sppp_lock_exit(sp);
return;
}
@@ -553,6 +572,7 @@ sppp_input(struct ifnet *ifp, struct mbu
++ifp->if_noproto;
goto invalid;
case CISCO_KEEPALIVE:
+ sppp_lock_exit(sp);
sppp_cisco_input((struct sppp *) ifp, m);
m_freem(m);
return;
@@ -596,23 +616,33 @@ sppp_input(struct ifnet *ifp, struct mbu
++ifp->if_noproto;
goto drop;
case PPP_LCP:
+ sppp_lock_exit(sp);
sppp_cp_input(&lcp, sp, m);
m_freem(m);
return;
case PPP_PAP:
- if (sp->pp_phase >= SPPP_PHASE_AUTHENTICATE)
+ 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:
- if (sp->pp_phase >= SPPP_PHASE_AUTHENTICATE)
+ 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:
- if (sp->pp_phase == SPPP_PHASE_NETWORK)
+ 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:
@@ -624,8 +654,11 @@ sppp_input(struct ifnet *ifp, struct mbu
#endif
#ifdef INET6
case PPP_IPV6CP:
- if (sp->pp_phase == SPPP_PHASE_NETWORK)
+ 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;
@@ -643,9 +676,11 @@ 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;
}
return;
@@ -659,6 +694,7 @@ queue_pkt:
if (debug)
log(LOG_DEBUG, "%s: protocol queue overflow\n",
ifp->if_xname);
+ sppp_lock_enter(sp);
goto drop;
}
IF_ENQUEUE(inq, m);
@@ -675,16 +711,20 @@ sppp_output(struct ifnet *ifp, struct mb
{
struct sppp *sp = (struct sppp *) ifp;
struct ppp_header *h = NULL;
+#ifndef SPPPSUBR_MPSAFE
struct ifqueue *ifq = NULL; /* XXX */
+#endif
int s, error = 0;
uint16_t protocol;
s = splnet();
+ 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);
splx(s);
return (ENETDOWN);
@@ -710,16 +750,20 @@ sppp_output(struct ifnet *ifp, struct mb
#ifdef INET
if (dst->sa_family == AF_INET) {
struct ip *ip = NULL;
+#ifndef SPPPSUBR_MPSAFE
struct tcphdr *th = NULL;
+#endif
if (m->m_len >= sizeof(struct ip)) {
ip = mtod(m, struct ip *);
+#ifndef SPPPSUBR_MPSAFE
if (ip->ip_p == IPPROTO_TCP &&
m->m_len >= sizeof(struct ip) + (ip->ip_hl << 2) +
sizeof(struct tcphdr)) {
th = (struct tcphdr *)
((char *)ip + (ip->ip_hl << 2));
}
+#endif
} else
ip = NULL;
@@ -736,6 +780,7 @@ 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);
splx(s);
if (proto == IPPROTO_TCP)
@@ -744,16 +789,17 @@ sppp_output(struct ifnet *ifp, struct mb
return (0);
}
+#ifndef SPPPSUBR_MPSAFE
/*
* Put low delay, telnet, rlogin and ftp control packets
* in front of the queue.
*/
-
if (!IF_QFULL(&sp->pp_fastq) &&
((ip && (ip->ip_tos & IPTOS_LOWDELAY)) ||
(th && (INTERACTIVE(ntohs(th->th_sport)) ||
INTERACTIVE(ntohs(th->th_dport))))))
ifq = &sp->pp_fastq;
+#endif /* !SPPPSUBR_MPSAFE */
}
#endif
@@ -773,6 +819,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);
splx(s);
return (ENOBUFS);
}
@@ -834,6 +881,7 @@ sppp_output(struct ifnet *ifp, struct mb
default:
m_freem(m);
++ifp->if_oerrors;
+ sppp_lock_exit(sp);
splx(s);
return (EAFNOSUPPORT);
}
@@ -845,6 +893,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);
splx(s);
return (ENOBUFS);
}
@@ -854,6 +903,11 @@ sppp_output(struct ifnet *ifp, struct mb
}
+#ifdef SPPPSUBR_MPSAFE
+ error = if_transmit_lock(ifp, m);
+ if (error == 0)
+ ifp->if_obytes += m->m_pkthdr.len + sp->pp_framebytes;
+#else /* !SPPPSUBR_MPSAFE */
error = ifq_enqueue2(ifp, ifq, m);
if (error == 0) {
@@ -862,10 +916,15 @@ sppp_output(struct ifnet *ifp, struct mb
* The packet length includes header + additional hardware
* framing according to RFC 1333.
*/
- if (!(ifp->if_flags & IFF_OACTIVE))
+ if (!(ifp->if_flags & IFF_OACTIVE)) {
+ sppp_lock_exit(sp);
if_start_lock(ifp);
+ sppp_lock_enter(sp);
+ }
ifp->if_obytes += m->m_pkthdr.len + sp->pp_framebytes;
}
+#endif /* !SPPPSUBR_MPSAFE */
+ sppp_lock_exit(sp);
splx(s);
return error;
}
@@ -880,7 +939,10 @@ sppp_mediachange(struct ifnet *ifp)
static void
sppp_mediastatus(struct ifnet *ifp, struct ifmediareq *imr)
{
+ struct sppp *sp = (struct sppp *)ifp;
+ KASSERT(!sppp_locked(sp));
+ sppp_lock_enter(sp);
switch (ifp->if_link_state) {
case LINK_STATE_UP:
imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
@@ -893,6 +955,7 @@ sppp_mediastatus(struct ifnet *ifp, stru
imr->ifm_status = 0;
break;
}
+ sppp_lock_exit(sp);
}
void
@@ -906,6 +969,9 @@ sppp_attach(struct ifnet *ifp)
callout_reset(&keepalive_ch, hz * LCP_KEEPALIVE_INTERVAL, sppp_keepalive, NULL);
}
+ if (! spppq_lock)
+ spppq_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTNET);
+
/* Insert new entry into the keepalive list. */
sp->pp_next = spppq;
spppq = sp;
@@ -928,6 +994,7 @@ sppp_attach(struct ifnet *ifp)
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);
if_alloc_sadl(ifp);
@@ -950,7 +1017,9 @@ 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)
if (p == sp) {
*q = p->pp_next;
@@ -966,6 +1035,7 @@ sppp_detach(struct ifnet *ifp)
if (! spppq) {
callout_stop(&keepalive_ch);
}
+ SPPPQ_UNLOCK();
callout_stop(&sp->ch[IDX_LCP]);
callout_stop(&sp->ch[IDX_IPCP]);
@@ -984,6 +1054,11 @@ sppp_detach(struct ifnet *ifp)
/* 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);
+
}
/*
@@ -1008,9 +1083,13 @@ sppp_isempty(struct ifnet *ifp)
struct sppp *sp = (struct sppp *) ifp;
int empty, s;
+ KASSERT(!sppp_locked(sp));
+
s = splnet();
+ sppp_lock_enter(sp);
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);
splx(s);
return (empty);
}
@@ -1026,6 +1105,7 @@ sppp_dequeue(struct ifnet *ifp)
int s;
s = splnet();
+ sppp_lock_enter(sp);
/*
* Process only the control protocol queue until we have at
* least one NCP open.
@@ -1039,6 +1119,7 @@ sppp_dequeue(struct ifnet *ifp)
if (m == NULL)
IFQ_DEQUEUE(&sp->pp_if.if_snd, m);
}
+ sppp_lock_exit(sp);
splx(s);
return m;
}
@@ -1064,6 +1145,8 @@ sppp_ioctl(struct ifnet *ifp, u_long cmd
case SIOCSIFFLAGS:
if ((error = ifioctl_common(ifp, cmd, data)) != 0)
break;
+
+ sppp_lock_enter(sp);
going_up = ifp->if_flags & IFF_UP &&
(ifp->if_flags & IFF_RUNNING) == 0;
going_down = (ifp->if_flags & IFF_UP) == 0 &&
@@ -1075,8 +1158,9 @@ sppp_ioctl(struct ifnet *ifp, u_long cmd
ifp->if_flags &= ~IFF_AUTO;
}
- if (going_up || going_down)
+ if (going_up || going_down) {
lcp.Close(sp);
+ }
if (going_up && newmode == 0) {
/* neither auto-dial nor passive */
ifp->if_flags |= IFF_RUNNING;
@@ -1086,7 +1170,7 @@ sppp_ioctl(struct ifnet *ifp, u_long cmd
sppp_flush(ifp);
ifp->if_flags &= ~IFF_RUNNING;
}
-
+ sppp_lock_exit(sp);
break;
case SIOCSIFMTU:
@@ -1177,11 +1261,16 @@ sppp_cisco_input(struct sppp *sp, struct
uint32_t me, mymask = 0; /* XXX: GCC */
#endif
+ KASSERT(!sppp_locked(sp));
+
+ sppp_lock_enter(sp);
+
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);
return;
}
h = mtod(m, struct cisco_packet *);
@@ -1212,7 +1301,9 @@ sppp_cisco_input(struct sppp *sp, struct
ifp->if_xname);
sp->pp_loopcnt = 0;
if (ifp->if_flags & IFF_UP) {
+ sppp_lock_exit(sp);
if_down(ifp);
+ sppp_lock_enter(sp);
IF_PURGE(&sp->pp_cpq);
}
}
@@ -1225,17 +1316,22 @@ 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);
if_up(ifp);
+ sppp_lock_enter(sp);
}
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);
}
/*
@@ -1250,6 +1346,8 @@ sppp_cisco_send(struct sppp *sp, int typ
struct mbuf *m;
uint32_t t;
+ KASSERT(sppp_locked(sp));
+
t = time_uptime * 1000;
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (! m)
@@ -1286,8 +1384,11 @@ sppp_cisco_send(struct sppp *sp, int typ
return;
} else
IF_ENQUEUE(&sp->pp_cpq, m);
- if (! (ifp->if_flags & IFF_OACTIVE))
+ if (! (ifp->if_flags & IFF_OACTIVE)) {
+ sppp_lock_exit(sp);
if_start_lock(ifp);
+ sppp_lock_enter(sp);
+ }
ifp->if_obytes += m->m_pkthdr.len + sp->pp_framebytes;
}
@@ -1307,6 +1408,8 @@ sppp_cp_send(struct sppp *sp, u_short pr
struct mbuf *m;
size_t pkthdrlen;
+ KASSERT(sppp_locked(sp));
+
pkthdrlen = (sp->pp_flags & PP_NOFRAMING) ? 2 : PPP_HEADER_LEN;
if (len > MHLEN - pkthdrlen - LCP_HEADER_LEN)
@@ -1351,8 +1454,13 @@ sppp_cp_send(struct sppp *sp, u_short pr
return;
} else
IF_ENQUEUE(&sp->pp_cpq, m);
- if (! (ifp->if_flags & IFF_OACTIVE))
+
+ if (! (ifp->if_flags & IFF_OACTIVE)) {
+ sppp_lock_exit(sp);
if_start_lock(ifp);
+ sppp_lock_enter(sp);
+ }
+
ifp->if_obytes += m->m_pkthdr.len + sp->pp_framebytes;
}
@@ -1369,6 +1477,7 @@ sppp_cp_input(const struct cp *cp, struc
u_char *p;
uint32_t u32;
+ KASSERT(!sppp_locked(sp));
if (len < 4) {
if (debug)
log(LOG_DEBUG,
@@ -1400,17 +1509,22 @@ 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);
return;
case STATE_CLOSED:
sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident,
0, 0);
+ sppp_lock_exit(sp);
return;
}
rv = (cp->RCR)(sp, h, len);
@@ -1418,6 +1532,7 @@ sppp_cp_input(const struct cp *cp, struc
/* fatal error, shut down */
(cp->tld)(sp);
sppp_lcp_tlf(sp);
+ sppp_lock_exit(sp);
return;
}
switch (sp->state[cp->protoidx]) {
@@ -1448,20 +1563,24 @@ 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]) {
@@ -1498,15 +1617,18 @@ 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)
@@ -1541,9 +1663,11 @@ 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:
@@ -1573,8 +1697,10 @@ 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:
@@ -1606,9 +1732,11 @@ 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",
@@ -1633,6 +1761,7 @@ 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:
{
@@ -1653,6 +1782,8 @@ 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",
@@ -1668,6 +1799,7 @@ 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;
}
}
@@ -1692,6 +1824,7 @@ 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:
@@ -1702,11 +1835,13 @@ 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) {
@@ -1714,6 +1849,7 @@ 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);
@@ -1727,6 +1863,7 @@ sppp_cp_input(const struct cp *cp, struc
/* XXX */
lcp.Down(sp);
lcp.Up(sp);
+ sppp_lock_exit(sp);
break;
}
u32 = htonl(sp->lcp.magic);
@@ -1736,12 +1873,15 @@ 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) {
@@ -1749,6 +1889,7 @@ 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)
@@ -1757,16 +1898,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);
}
}
@@ -1780,6 +1924,8 @@ sppp_up_event(const struct cp *cp, struc
{
STDDCL;
+ KASSERT(sppp_locked(sp));
+
if (debug)
log(LOG_DEBUG, "%s: %s up(%s)\n",
ifp->if_xname, cp->name,
@@ -1806,6 +1952,8 @@ sppp_down_event(const struct cp *cp, str
{
STDDCL;
+ KASSERT(sppp_locked(sp));
+
if (debug)
log(LOG_DEBUG, "%s: %s down(%s)\n",
ifp->if_xname, cp->name,
@@ -1842,6 +1990,8 @@ sppp_open_event(const struct cp *cp, str
{
STDDCL;
+ KASSERT(sppp_locked(sp));
+
if (debug)
log(LOG_DEBUG, "%s: %s open(%s)\n",
ifp->if_xname, cp->name,
@@ -1878,6 +2028,8 @@ sppp_close_event(const struct cp *cp, st
{
STDDCL;
+ KASSERT(sppp_locked(sp));
+
if (debug)
log(LOG_DEBUG, "%s: %s close(%s)\n",
ifp->if_xname, cp->name,
@@ -1918,7 +2070,10 @@ sppp_to_event(const struct cp *cp, struc
STDDCL;
int s;
+ KASSERT(sppp_locked(sp));
+
s = splnet();
+
if (debug)
log(LOG_DEBUG, "%s: %s TO(%s) rst_counter = %d\n",
ifp->if_xname, cp->name,
@@ -1979,6 +2134,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));
+
sp->state[cp->protoidx] = newstate;
callout_stop(&sp->ch[cp->protoidx]);
switch (newstate) {
@@ -2009,6 +2166,7 @@ sppp_cp_change_state(const struct cp *cp
static void
sppp_lcp_init(struct sppp *sp)
{
+ sppp_lock_enter(sp);
sp->lcp.opts = (1 << LCP_OPT_MAGIC);
sp->lcp.magic = 0;
sp->state[IDX_LCP] = STATE_INITIAL;
@@ -2029,6 +2187,7 @@ 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
@@ -2036,6 +2195,8 @@ sppp_lcp_up(struct sppp *sp)
{
STDDCL;
+ KASSERT(sppp_locked(sp));
+
/* Initialize activity timestamp: opening a connection is an activity */
sp->pp_last_receive = sp->pp_last_activity = time_uptime;
@@ -2070,6 +2231,8 @@ sppp_lcp_down(struct sppp *sp)
{
STDDCL;
+ KASSERT(sppp_locked(sp));
+
sppp_down_event(&lcp, sp);
/*
@@ -2084,7 +2247,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);
if_down(ifp);
+ sppp_lock_enter(sp);
} else {
if (debug)
log(LOG_DEBUG,
@@ -2100,6 +2265,8 @@ sppp_lcp_down(struct sppp *sp)
static void
sppp_lcp_open(struct sppp *sp)
{
+ KASSERT(sppp_locked(sp));
+
if (sp->pp_if.if_mtu < PP_MTU) {
sp->lcp.mru = sp->pp_if.if_mtu;
sp->lcp.opts |= (1 << LCP_OPT_MRU);
@@ -2121,13 +2288,19 @@ sppp_lcp_open(struct sppp *sp)
static void
sppp_lcp_close(struct sppp *sp)
{
+ KASSERT(sppp_locked(sp));
sppp_close_event(&lcp, sp);
}
static void
sppp_lcp_TO(void *cookie)
{
- sppp_to_event(&lcp, (struct sppp *)cookie);
+ struct sppp *sp = (struct sppp*)cookie;
+ KASSERT(!sppp_locked(sp));
+
+ sppp_lock_enter(sp);
+ sppp_to_event(&lcp, sp);
+ sppp_lock_exit(sp);
}
/*
@@ -2145,6 +2318,8 @@ sppp_lcp_RCR(struct sppp *sp, struct lcp
uint32_t nmagic;
u_short authproto;
+ KASSERT(sppp_locked(sp));
+
len -= 4;
origlen = len;
buf = r = malloc (blen = len, M_TEMP, M_NOWAIT);
@@ -2269,7 +2444,9 @@ 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);
if_down(ifp);
+ sppp_lock_enter(sp);
IF_PURGE(&sp->pp_cpq);
/* XXX ? */
lcp.Down(sp);
@@ -2388,6 +2565,8 @@ sppp_lcp_RCN_rej(struct sppp *sp, struct
STDDCL;
u_char *buf, *p, l;
+ KASSERT(sppp_locked(sp));
+
len -= 4;
buf = malloc (len, M_TEMP, M_NOWAIT);
if (!buf)
@@ -2470,6 +2649,8 @@ sppp_lcp_RCN_nak(struct sppp *sp, struct
u_char *buf, *p, l, blen;
uint32_t magic;
+ KASSERT(sppp_locked(sp));
+
len -= 4;
buf = malloc (blen = len, M_TEMP, M_NOWAIT);
if (!buf)
@@ -2557,11 +2738,15 @@ sppp_lcp_tlu(struct sppp *sp)
int i;
uint32_t mask;
+ KASSERT(sppp_locked(sp));
+
/* XXX ? */
if (! (ifp->if_flags & IFF_UP) &&
(ifp->if_flags & IFF_RUNNING)) {
/* Coming out of loopback mode. */
+ sppp_lock_exit(sp);
if_up(ifp);
+ sppp_lock_enter(sp);
}
for (i = 0; i < IDX_COUNT; i++)
@@ -2593,9 +2778,11 @@ sppp_lcp_tlu(struct sppp *sp)
}
/* Send Up events to all started protos. */
- for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
- if ((sp->lcp.protos & mask) && ((cps[i])->flags & CP_LCP) == 0)
+ for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) {
+ if ((sp->lcp.protos & mask) && ((cps[i])->flags & CP_LCP) == 0) {
(cps[i])->Up(sp);
+ }
+ }
/* notify low-level driver of state change */
if (sp->pp_chg)
@@ -2612,6 +2799,8 @@ sppp_lcp_tld(struct sppp *sp)
int i;
uint32_t mask;
+ KASSERT(sppp_locked(sp));
+
sppp_change_phase(sp, SPPP_PHASE_TERMINATE);
/*
@@ -2620,22 +2809,27 @@ sppp_lcp_tld(struct sppp *sp)
* ``a flurry of terminate-request packets'', as the RFC
* describes it.
*/
- for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
+ for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1) {
if ((sp->lcp.protos & mask) && ((cps[i])->flags & CP_LCP) == 0) {
(cps[i])->Down(sp);
(cps[i])->Close(sp);
}
+ }
}
static void
sppp_lcp_tls(struct sppp *sp)
{
+ KASSERT(sppp_locked(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",
+ printf("%s: authentication failed %d times, not retrying again\n",
sp->pp_if.if_xname, sp->pp_auth_failures);
- if_down(&sp->pp_if);
- return;
+ sppp_lock_exit(sp);
+ if_down(&sp->pp_if);
+ sppp_lock_enter(sp);
+ return;
}
sppp_change_phase(sp, SPPP_PHASE_ESTABLISH);
@@ -2648,6 +2842,7 @@ sppp_lcp_tls(struct sppp *sp)
static void
sppp_lcp_tlf(struct sppp *sp)
{
+ KASSERT(sppp_locked(sp));
sppp_change_phase(sp, SPPP_PHASE_DEAD);
@@ -2663,6 +2858,8 @@ sppp_lcp_scr(struct sppp *sp)
int i = 0;
u_short authproto;
+ KASSERT(sppp_locked(sp));
+
if (sp->lcp.opts & (1 << LCP_OPT_MAGIC)) {
if (! sp->lcp.magic)
sp->lcp.magic = cprng_fast32();
@@ -2716,6 +2913,7 @@ sppp_ncp_check(struct sppp *sp)
static void
sppp_lcp_check_and_close(struct sppp *sp)
{
+ KASSERT(sppp_locked(sp));
if (sp->pp_phase < SPPP_PHASE_NETWORK)
/* don't bother, we are already going down */
@@ -2723,7 +2921,6 @@ sppp_lcp_check_and_close(struct sppp *sp
if (sppp_ncp_check(sp))
return;
-
lcp.Close(sp);
}
@@ -2741,6 +2938,7 @@ sppp_ipcp_init(struct sppp *sp)
{
int error;
+ sppp_lock_enter(sp);
sp->ipcp.opts = 0;
sp->ipcp.flags = 0;
sp->state[IDX_IPCP] = STATE_INITIAL;
@@ -2757,17 +2955,20 @@ 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));
sppp_up_event(&ipcp, sp);
}
static void
sppp_ipcp_down(struct sppp *sp)
{
+ KASSERT(sppp_locked(sp));
sppp_down_event(&ipcp, sp);
}
@@ -2777,6 +2978,8 @@ sppp_ipcp_open(struct sppp *sp)
STDDCL;
uint32_t myaddr, hisaddr;
+ KASSERT(sppp_locked(sp));
+
sp->ipcp.flags &= ~(IPCP_HISADDR_SEEN|IPCP_MYADDR_SEEN|IPCP_MYADDR_DYN|IPCP_HISADDR_DYN);
sp->ipcp.req_myaddr = 0;
sp->ipcp.req_hisaddr = 0;
@@ -2823,7 +3026,9 @@ static void
sppp_ipcp_close(struct sppp *sp)
{
+ KASSERT(sppp_locked(sp));
sppp_close_event(&ipcp, sp);
+
#ifdef INET
if (sp->ipcp.flags & (IPCP_MYADDR_DYN|IPCP_HISADDR_DYN))
/*
@@ -2836,7 +3041,13 @@ sppp_ipcp_close(struct sppp *sp)
static void
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);
}
/*
@@ -2853,6 +3064,7 @@ 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));
len -= 4;
origlen = len;
/*
@@ -3047,6 +3259,8 @@ 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));
+
len -= 4;
buf = malloc (blen = len, M_TEMP, M_NOWAIT);
if (!buf)
@@ -3101,6 +3315,8 @@ sppp_ipcp_RCN_nak(struct sppp *sp, struc
int debug = ifp->if_flags & IFF_DEBUG;
uint32_t wantaddr;
+ KASSERT(sppp_locked(sp));
+
len -= 4;
if (debug)
@@ -3177,6 +3393,7 @@ static void
sppp_ipcp_tlu(struct sppp *sp)
{
#ifdef INET
+ KASSERT(sppp_locked(sp));
/* we are up. Set addresses and notify anyone interested */
sppp_set_ip_addrs(sp);
#endif
@@ -3190,6 +3407,7 @@ sppp_ipcp_tld(struct sppp *sp)
static void
sppp_ipcp_tls(struct sppp *sp)
{
+ KASSERT(sppp_locked(sp));
/* indicate to LCP that it must stay alive */
sp->lcp.protos |= (1 << IDX_IPCP);
}
@@ -3197,6 +3415,7 @@ sppp_ipcp_tls(struct sppp *sp)
static void
sppp_ipcp_tlf(struct sppp *sp)
{
+ KASSERT(sppp_locked(sp));
/* we no longer need LCP */
sp->lcp.protos &= ~(1 << IDX_IPCP);
}
@@ -3210,6 +3429,8 @@ sppp_ipcp_scr(struct sppp *sp)
#endif
int i = 0;
+ KASSERT(sppp_locked(sp));
+
#ifdef notyet
if (sp->ipcp.opts & (1 << IPCP_OPT_COMPRESSION)) {
opt[i++] = IPCP_OPT_COMPRESSION;
@@ -3270,6 +3491,7 @@ sppp_ipcp_scr(struct sppp *sp)
static void
sppp_ipv6cp_init(struct sppp *sp)
{
+ sppp_lock_enter(sp);
sp->ipv6cp.opts = 0;
sp->ipv6cp.flags = 0;
sp->state[IDX_IPV6CP] = STATE_INITIAL;
@@ -3277,17 +3499,20 @@ 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));
sppp_up_event(&ipv6cp, sp);
}
static void
sppp_ipv6cp_down(struct sppp *sp)
{
+ KASSERT(sppp_locked(sp));
sppp_down_event(&ipv6cp, sp);
}
@@ -3297,6 +3522,8 @@ sppp_ipv6cp_open(struct sppp *sp)
STDDCL;
struct in6_addr myaddr, hisaddr;
+ KASSERT(sppp_locked(sp));
+
#ifdef IPV6CP_MYIFID_DYN
sp->ipv6cp.flags &= ~(IPV6CP_MYIFID_SEEN|IPV6CP_MYIFID_DYN);
#else
@@ -3326,13 +3553,19 @@ sppp_ipv6cp_open(struct sppp *sp)
static void
sppp_ipv6cp_close(struct sppp *sp)
{
+ KASSERT(sppp_locked(sp));
sppp_close_event(&ipv6cp, sp);
}
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);
}
/*
@@ -3352,6 +3585,8 @@ sppp_ipv6cp_RCR(struct sppp *sp, struct
int type;
int collision, nohisaddr;
+ KASSERT(sppp_locked(sp));
+
len -= 4;
origlen = len;
/*
@@ -3529,6 +3764,8 @@ 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));
+
len -= 4;
buf = malloc (blen = len, M_TEMP, M_NOWAIT);
if (!buf)
@@ -3582,6 +3819,8 @@ sppp_ipv6cp_RCN_nak(struct sppp *sp, str
int debug = ifp->if_flags & IFF_DEBUG;
struct in6_addr suggestaddr;
+ KASSERT(sppp_locked(sp));
+
len -= 4;
buf = malloc (blen = len, M_TEMP, M_NOWAIT);
if (!buf)
@@ -3677,6 +3916,7 @@ drop:
static void
sppp_ipv6cp_tlu(struct sppp *sp)
{
+ KASSERT(sppp_locked(sp));
/* we are up - notify isdn daemon */
if (sp->pp_con)
sp->pp_con(sp);
@@ -3690,6 +3930,7 @@ sppp_ipv6cp_tld(struct sppp *sp)
static void
sppp_ipv6cp_tls(struct sppp *sp)
{
+ KASSERT(sppp_locked(sp));
/* indicate to LCP that it must stay alive */
sp->lcp.protos |= (1 << IDX_IPV6CP);
}
@@ -3697,6 +3938,7 @@ sppp_ipv6cp_tls(struct sppp *sp)
static void
sppp_ipv6cp_tlf(struct sppp *sp)
{
+ KASSERT(sppp_locked(sp));
/* we no longer need LCP */
sp->lcp.protos &= ~(1 << IDX_IPV6CP);
}
@@ -3708,6 +3950,8 @@ sppp_ipv6cp_scr(struct sppp *sp)
struct in6_addr ouraddr;
int i = 0;
+ KASSERT(sppp_locked(sp));
+
if (sp->ipv6cp.opts & (1 << IPV6CP_OPT_IFID)) {
sppp_get_ip6_addrs(sp, &ouraddr, 0, 0);
opt[i++] = IPV6CP_OPT_IFID;
@@ -3904,6 +4148,8 @@ 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)
@@ -3919,12 +4165,14 @@ sppp_chap_input(struct sppp *sp, struct
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);
- break;
+ /* 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);
value_len = value[-1];
@@ -3943,6 +4191,7 @@ sppp_chap_input(struct sppp *sp, struct
len - 4);
addlog(">\n");
}
+ sppp_lock_exit(sp);
break;
}
@@ -3972,9 +4221,11 @@ 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);
@@ -3996,14 +4247,17 @@ 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) {
@@ -4017,15 +4271,18 @@ 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);
+ /* 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);
@@ -4045,6 +4302,7 @@ sppp_chap_input(struct sppp *sp, struct
len - 4);
addlog(">\n");
}
+ sppp_lock_exit(sp);
break;
}
if (h->ident != sp->confid[IDX_CHAP]) {
@@ -4054,6 +4312,7 @@ 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 &&
@@ -4102,6 +4361,7 @@ sppp_chap_input(struct sppp *sp, struct
if (value_len != sizeof digest ||
memcmp(digest, value, value_len) != 0) {
chap_failure:
+ KASSERT(sppp_locked(sp));
/* action scn, tld */
x = splnet();
sp->pp_auth_failures++;
@@ -4110,6 +4370,7 @@ chap_failure:
sizeof(FAILMSG) - 1, (const u_char *)FAILMSG,
0);
chap.tld(sp);
+ sppp_lock_exit(sp);
break;
}
sp->pp_auth_failures = 0;
@@ -4123,10 +4384,12 @@ 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",
@@ -4137,25 +4400,49 @@ 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));
+}
+
static void
sppp_chap_init(struct sppp *sp)
{
+ sppp_lock_enter(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));
if (sp->hisauth.proto == PPP_CHAP &&
(sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) {
/* we are authenticator for CHAP, start it */
@@ -4169,6 +4456,8 @@ sppp_chap_open(struct sppp *sp)
static void
sppp_chap_close(struct sppp *sp)
{
+ KASSERT(sppp_locked(sp));
+
if (sp->state[IDX_CHAP] != STATE_CLOSED)
sppp_cp_change_state(&chap, sp, STATE_CLOSED);
}
@@ -4180,7 +4469,11 @@ sppp_chap_TO(void *cookie)
STDDCL;
int s;
+ KASSERT(!sppp_locked(sp));
+
s = splnet();
+ sppp_lock_enter(sp);
+
if (debug)
log(LOG_DEBUG, "%s: chap TO(%s) rst_counter = %d\n",
ifp->if_xname,
@@ -4209,6 +4502,7 @@ sppp_chap_TO(void *cookie)
break;
}
+ sppp_lock_exit(sp);
splx(s);
}
@@ -4218,6 +4512,7 @@ sppp_chap_tlu(struct sppp *sp)
STDDCL;
int i, x;
+ KASSERT(sppp_locked(sp));
i = 0;
sp->rst_counter[IDX_CHAP] = sp->lcp.max_configure;
@@ -4277,6 +4572,8 @@ sppp_chap_tld(struct sppp *sp)
{
STDDCL;
+ KASSERT(sppp_locked(sp));
+
if (debug)
log(LOG_DEBUG, "%s: chap tld\n", ifp->if_xname);
callout_stop(&sp->ch[IDX_CHAP]);
@@ -4291,6 +4588,8 @@ sppp_chap_scr(struct sppp *sp)
uint32_t *ch;
u_char clen = 4 * sizeof(uint32_t);
+ KASSERT(sppp_locked(sp));
+
if (sp->hisauth.name == NULL) {
/* can't do anything useful */
printf("%s: chap starting without his name being set\n",
@@ -4336,6 +4635,8 @@ 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.
@@ -4356,11 +4657,14 @@ sppp_pap_input(struct sppp *sp, struct m
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);
- break;
+ /* 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);
name_len = name[-1];
@@ -4378,6 +4682,7 @@ sppp_pap_input(struct sppp *sp, struct m
len - 4);
addlog(">\n");
}
+ sppp_lock_exit(sp);
break;
}
if (debug) {
@@ -4404,6 +4709,7 @@ 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 */
@@ -4419,10 +4725,12 @@ 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",
@@ -4447,13 +4755,16 @@ 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) {
@@ -4470,10 +4781,12 @@ 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",
@@ -4483,6 +4796,7 @@ sppp_pap_input(struct sppp *sp, struct m
sppp_print_bytes((u_char *)(h + 1), len - 4);
addlog(">\n");
}
+ sppp_lock_exit(sp);
break;
}
@@ -4492,17 +4806,21 @@ static void
sppp_pap_init(struct sppp *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));
+
if (sp->hisauth.proto == PPP_PAP &&
(sp->lcp.opts & (1 << LCP_OPT_AUTH_PROTO)) != 0) {
/* we are authenticator for PAP, start our timer */
@@ -4520,6 +4838,7 @@ sppp_pap_open(struct sppp *sp)
static void
sppp_pap_close(struct sppp *sp)
{
+ KASSERT(sppp_locked(sp));
if (sp->state[IDX_PAP] != STATE_CLOSED)
sppp_cp_change_state(&pap, sp, STATE_CLOSED);
}
@@ -4535,7 +4854,10 @@ sppp_pap_TO(void *cookie)
STDDCL;
int s;
+ KASSERT(!sppp_locked(sp));
+
s = splnet();
+ sppp_lock_enter(sp);
if (debug)
log(LOG_DEBUG, "%s: pap TO(%s) rst_counter = %d\n",
ifp->if_xname,
@@ -4559,6 +4881,7 @@ sppp_pap_TO(void *cookie)
break;
}
+ sppp_lock_exit(sp);
splx(s);
}
@@ -4573,11 +4896,15 @@ sppp_pap_my_TO(void *cookie)
struct sppp *sp = (struct sppp *)cookie;
STDDCL;
+ KASSERT(!sppp_locked(sp));
+
+ sppp_lock_enter(sp);
if (debug)
log(LOG_DEBUG, "%s: pap peer TO\n",
ifp->if_xname);
pap.scr(sp);
+ sppp_lock_exit(sp);
}
static void
@@ -4586,6 +4913,7 @@ sppp_pap_tlu(struct sppp *sp)
STDDCL;
int x;
+ KASSERT(sppp_locked(sp));
sp->rst_counter[IDX_PAP] = sp->lcp.max_configure;
if (debug)
@@ -4615,6 +4943,8 @@ sppp_pap_tld(struct sppp *sp)
{
STDDCL;
+ KASSERT(sppp_locked(sp));
+
if (debug)
log(LOG_DEBUG, "%s: pap tld\n", ifp->if_xname);
callout_stop(&sp->ch[IDX_PAP]);
@@ -4629,6 +4959,8 @@ sppp_pap_scr(struct sppp *sp)
{
u_char idlen, pwdlen;
+ KASSERT(sppp_locked(sp));
+
if (sp->myauth.secret == NULL || sp->myauth.name == NULL) {
/* can't do anything useful */
printf("%s: pap starting without my name and secret being set\n",
@@ -4678,6 +5010,8 @@ sppp_auth_send(const struct cp *cp, stru
const char *msg;
va_list ap;
+ KASSERT(sppp_locked(sp));
+
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (! m)
return;
@@ -4739,8 +5073,11 @@ sppp_auth_send(const struct cp *cp, stru
return;
} else
IF_ENQUEUE(&sp->pp_cpq, m);
- if (! (ifp->if_flags & IFF_OACTIVE))
+ if (! (ifp->if_flags & IFF_OACTIVE)) {
+ sppp_lock_exit(sp);
if_start_lock(ifp);
+ sppp_lock_enter(sp);
+ }
ifp->if_obytes += m->m_pkthdr.len + 3;
}
@@ -4754,10 +5091,15 @@ sppp_keepalive(void *dummy)
int s;
time_t now;
+ SPPPQ_LOCK();
+
s = splnet();
now = time_uptime;
for (sp=spppq; sp; sp=sp->pp_next) {
- struct ifnet *ifp = &sp->pp_if;
+ struct ifnet *ifp = NULL;
+
+ sppp_lock_enter(sp);
+ ifp = &sp->pp_if;
/* check idle timeout */
if ((sp->pp_idle_timeout != 0) && (ifp->if_flags & IFF_RUNNING)
@@ -4769,29 +5111,38 @@ sppp_keepalive(void *dummy)
sp->pp_if.if_xname,
(unsigned long)(now-sp->pp_last_activity));
lcp.Close(sp);
+ sppp_lock_exit(sp);
continue;
}
}
/* Keepalive mode disabled or channel down? */
if (! (sp->pp_flags & PP_KEEPALIVE) ||
- ! (ifp->if_flags & IFF_RUNNING))
+ ! (ifp->if_flags & IFF_RUNNING)) {
+ sppp_lock_exit(sp);
continue;
+ }
+
/* No keepalive in PPP mode if LCP not opened yet. */
if (! (sp->pp_flags & PP_CISCO) &&
- sp->pp_phase < SPPP_PHASE_AUTHENTICATE)
+ sp->pp_phase < SPPP_PHASE_AUTHENTICATE) {
+ sppp_lock_exit(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);
continue;
}
if (sp->pp_alivecnt >= sp->pp_maxalive) {
/* No keepalive packets got. Stop the interface. */
+ sppp_lock_exit(sp);
if_down (ifp);
+ sppp_lock_enter(sp);
IF_PURGE(&sp->pp_cpq);
if (! (sp->pp_flags & PP_CISCO)) {
printf("%s: LCP keepalive timed out, going to restart the connection\n",
@@ -4808,6 +5159,8 @@ sppp_keepalive(void *dummy)
* will summon the magic needed to reestablish it. */
if (sp->pp_tlf)
sp->pp_tlf(sp);
+
+ sppp_lock_exit(sp);
continue;
}
}
@@ -4822,9 +5175,13 @@ sppp_keepalive(void *dummy)
sppp_cp_send(sp, PPP_LCP, ECHO_REQ,
sp->lcp.echoid, 4, &nmagic);
}
+
+ sppp_lock_exit(sp);
}
splx(s);
callout_reset(&keepalive_ch, hz * LCP_KEEPALIVE_INTERVAL, sppp_keepalive, NULL);
+
+ SPPPQ_UNLOCK();
}
#ifdef INET
@@ -5210,6 +5567,8 @@ sppp_params(struct sppp *sp, u_long cmd,
int error;
size_t len;
+ sppp_lock_enter(sp);
+
cfg->myauthflags = sp->myauth.flags;
cfg->hisauthflags = sp->hisauth.flags;
strlcpy(cfg->ifname, sp->pp_if.if_xname, sizeof(cfg->ifname));
@@ -5227,10 +5586,15 @@ sppp_params(struct sppp *sp, u_long cmd,
cfg->myname_length = 0;
} else {
len = sp->myauth.name_len + 1;
+
+ sppp_lock_exit(sp);
+
if (cfg->myname_length < len)
return (ENAMETOOLONG);
error = copyout(sp->myauth.name, cfg->myname, len);
if (error) return error;
+
+ sppp_lock_enter(sp);
}
}
if (cfg->hisname_length == 0) {
@@ -5241,12 +5605,16 @@ sppp_params(struct sppp *sp, u_long cmd,
cfg->hisname_length = 0;
} else {
len = sp->hisauth.name_len + 1;
+
+ sppp_lock_exit(sp);
if (cfg->hisname_length < len)
return (ENAMETOOLONG);
error = copyout(sp->hisauth.name, cfg->hisname, len);
if (error) return error;
+ sppp_lock_enter(sp);
}
}
+ sppp_lock_exit(sp);
}
break;
case SPPPSETAUTHCFG:
@@ -5254,6 +5622,8 @@ sppp_params(struct sppp *sp, u_long cmd,
struct spppauthcfg *cfg = (struct spppauthcfg *)data;
int error;
+ sppp_lock_enter(sp);
+
if (sp->myauth.name) {
free(sp->myauth.name, M_DEVBUF);
sp->myauth.name = NULL;
@@ -5272,56 +5642,72 @@ sppp_params(struct sppp *sp, u_long cmd,
}
if (cfg->hisname != NULL && cfg->hisname_length > 0) {
- if (cfg->hisname_length >= MCLBYTES)
- return (ENAMETOOLONG);
- sp->hisauth.name = malloc(cfg->hisname_length, M_DEVBUF, M_WAITOK);
- error = copyin(cfg->hisname, sp->hisauth.name, cfg->hisname_length);
- if (error) {
- free(sp->hisauth.name, M_DEVBUF);
- sp->hisauth.name = NULL;
- return error;
- }
- sp->hisauth.name_len = cfg->hisname_length - 1;
- sp->hisauth.name[sp->hisauth.name_len] = 0;
+ if (cfg->hisname_length >= MCLBYTES) {
+ sppp_lock_exit(sp);
+ return (ENAMETOOLONG);
+ }
+ sp->hisauth.name = malloc(cfg->hisname_length, M_DEVBUF, M_WAITOK);
+ error = copyin(cfg->hisname, sp->hisauth.name, cfg->hisname_length);
+ if (error) {
+ free(sp->hisauth.name, M_DEVBUF);
+ sp->hisauth.name = NULL;
+ sppp_lock_exit(sp);
+ return error;
+ }
+ sp->hisauth.name_len = cfg->hisname_length - 1;
+ sp->hisauth.name[sp->hisauth.name_len] = 0;
}
if (cfg->hissecret != NULL && cfg->hissecret_length > 0) {
- if (cfg->hissecret_length >= MCLBYTES)
- return (ENAMETOOLONG);
- sp->hisauth.secret = malloc(cfg->hissecret_length, M_DEVBUF, M_WAITOK);
- error = copyin(cfg->hissecret, sp->hisauth.secret, cfg->hissecret_length);
- if (error) {
- free(sp->hisauth.secret, M_DEVBUF);
- sp->hisauth.secret = NULL;
- return error;
- }
- sp->hisauth.secret_len = cfg->hissecret_length - 1;
- sp->hisauth.secret[sp->hisauth.secret_len] = 0;
+ if (cfg->hissecret_length >= MCLBYTES) {
+ sppp_lock_exit(sp);
+ return (ENAMETOOLONG);
+ }
+ sp->hisauth.secret = malloc(cfg->hissecret_length,
+ M_DEVBUF, M_WAITOK);
+ error = copyin(cfg->hissecret, sp->hisauth.secret,
+ cfg->hissecret_length);
+ if (error) {
+ free(sp->hisauth.secret, M_DEVBUF);
+ sp->hisauth.secret = NULL;
+ sppp_lock_exit(sp);
+ return error;
+ }
+ sp->hisauth.secret_len = cfg->hissecret_length - 1;
+ sp->hisauth.secret[sp->hisauth.secret_len] = 0;
}
if (cfg->myname != NULL && cfg->myname_length > 0) {
- if (cfg->myname_length >= MCLBYTES)
- return (ENAMETOOLONG);
- sp->myauth.name = malloc(cfg->myname_length, M_DEVBUF, M_WAITOK);
- error = copyin(cfg->myname, sp->myauth.name, cfg->myname_length);
- if (error) {
- free(sp->myauth.name, M_DEVBUF);
- sp->myauth.name = NULL;
- return error;
- }
- sp->myauth.name_len = cfg->myname_length - 1;
- sp->myauth.name[sp->myauth.name_len] = 0;
+ if (cfg->myname_length >= MCLBYTES) {
+ sppp_lock_exit(sp);
+ return (ENAMETOOLONG);
+ }
+ sp->myauth.name = malloc(cfg->myname_length, M_DEVBUF, M_WAITOK);
+ error = copyin(cfg->myname, sp->myauth.name, cfg->myname_length);
+ if (error) {
+ free(sp->myauth.name, M_DEVBUF);
+ sp->myauth.name = NULL;
+ sppp_lock_exit(sp);
+ return error;
+ }
+ sp->myauth.name_len = cfg->myname_length - 1;
+ sp->myauth.name[sp->myauth.name_len] = 0;
}
if (cfg->mysecret != NULL && cfg->mysecret_length > 0) {
- if (cfg->mysecret_length >= MCLBYTES)
- return (ENAMETOOLONG);
- sp->myauth.secret = malloc(cfg->mysecret_length, M_DEVBUF, M_WAITOK);
- error = copyin(cfg->mysecret, sp->myauth.secret, cfg->mysecret_length);
- if (error) {
- free(sp->myauth.secret, M_DEVBUF);
- sp->myauth.secret = NULL;
- return error;
- }
- sp->myauth.secret_len = cfg->mysecret_length - 1;
- sp->myauth.secret[sp->myauth.secret_len] = 0;
+ if (cfg->mysecret_length >= MCLBYTES) {
+ sppp_lock_exit(sp);
+ return (ENAMETOOLONG);
+ }
+ sp->myauth.secret = malloc(cfg->mysecret_length,
+ M_DEVBUF, M_WAITOK);
+ error = copyin(cfg->mysecret, sp->myauth.secret,
+ cfg->mysecret_length);
+ if (error) {
+ free(sp->myauth.secret, M_DEVBUF);
+ sp->myauth.secret = NULL;
+ sppp_lock_exit(sp);
+ return error;
+ }
+ sp->myauth.secret_len = cfg->mysecret_length - 1;
+ sp->myauth.secret[sp->myauth.secret_len] = 0;
}
sp->myauth.flags = cfg->myauthflags;
if (cfg->myauth)
@@ -5334,120 +5720,156 @@ sppp_params(struct sppp *sp, u_long cmd,
sp->lcp.opts |= (1 << LCP_OPT_AUTH_PROTO);
else
sp->lcp.opts &= ~(1 << LCP_OPT_AUTH_PROTO);
+
+ sppp_lock_exit(sp);
}
break;
case SPPPGETLCPCFG:
{
- struct sppplcpcfg *lcpp = (struct sppplcpcfg *)data;
- lcpp->lcp_timeout = sp->lcp.timeout;
+ struct sppplcpcfg *lcpp = (struct sppplcpcfg *)data;
+ sppp_lock_enter(sp);
+ lcpp->lcp_timeout = sp->lcp.timeout;
+ sppp_lock_exit(sp);
}
break;
case SPPPSETLCPCFG:
{
- struct sppplcpcfg *lcpp = (struct sppplcpcfg *)data;
- sp->lcp.timeout = lcpp->lcp_timeout;
+ struct sppplcpcfg *lcpp = (struct sppplcpcfg *)data;
+ sppp_lock_enter(sp);
+ sp->lcp.timeout = lcpp->lcp_timeout;
+ sppp_lock_exit(sp);
}
break;
case SPPPGETSTATUS:
{
struct spppstatus *status = (struct spppstatus *)data;
+ sppp_lock_enter(sp);
status->phase = sp->pp_phase;
+ sppp_lock_exit(sp);
}
break;
case SPPPGETSTATUSNCP:
{
struct spppstatusncp *status = (struct spppstatusncp *)data;
+ sppp_lock_enter(sp);
status->phase = sp->pp_phase;
+ sppp_lock_exit(sp);
status->ncpup = sppp_ncp_check(sp);
}
break;
case SPPPGETIDLETO:
{
struct spppidletimeout *to = (struct spppidletimeout *)data;
+ sppp_lock_enter(sp);
to->idle_seconds = sp->pp_idle_timeout;
+ sppp_lock_exit(sp);
}
break;
case SPPPSETIDLETO:
{
struct spppidletimeout *to = (struct spppidletimeout *)data;
- sp->pp_idle_timeout = to->idle_seconds;
+ sppp_lock_enter(sp);
+ sp->pp_idle_timeout = to->idle_seconds;
+ sppp_lock_exit(sp);
}
break;
case SPPPSETAUTHFAILURE:
{
struct spppauthfailuresettings *afsettings = (struct spppauthfailuresettings *)data;
- sp->pp_max_auth_fail = afsettings->max_failures;
- sp->pp_auth_failures = 0;
+ sppp_lock_enter(sp);
+ sp->pp_max_auth_fail = afsettings->max_failures;
+ sp->pp_auth_failures = 0;
+ sppp_lock_exit(sp);
}
break;
case SPPPGETAUTHFAILURES:
{
struct spppauthfailurestats *stats = (struct spppauthfailurestats *)data;
- stats->auth_failures = sp->pp_auth_failures;
- stats->max_failures = sp->pp_max_auth_fail;
+ sppp_lock_enter(sp);
+ stats->auth_failures = sp->pp_auth_failures;
+ stats->max_failures = sp->pp_max_auth_fail;
+ sppp_lock_exit(sp);
}
break;
case SPPPSETDNSOPTS:
{
struct spppdnssettings *req = (struct spppdnssettings *)data;
+ sppp_lock_enter(sp);
sp->query_dns = req->query_dns & 3;
+ sppp_lock_exit(sp);
}
break;
case SPPPGETDNSOPTS:
{
struct spppdnssettings *req = (struct spppdnssettings *)data;
+ sppp_lock_enter(sp);
req->query_dns = sp->query_dns;
+ sppp_lock_exit(sp);
}
break;
case SPPPGETDNSADDRS:
{
- struct spppdnsaddrs *addrs = (struct spppdnsaddrs *)data;
- memcpy(&addrs->dns, &sp->dns_addrs, sizeof addrs->dns);
+ struct spppdnsaddrs *addrs = (struct spppdnsaddrs *)data;
+ sppp_lock_enter(sp);
+ memcpy(&addrs->dns, &sp->dns_addrs, sizeof addrs->dns);
+ sppp_lock_exit(sp);
}
break;
case SPPPGETKEEPALIVE:
{
struct spppkeepalivesettings *settings =
(struct spppkeepalivesettings*)data;
+ sppp_lock_enter(sp);
settings->maxalive = sp->pp_maxalive;
settings->max_noreceive = sp->pp_max_noreceive;
+ sppp_lock_exit(sp);
}
break;
case SPPPSETKEEPALIVE:
{
struct spppkeepalivesettings *settings =
(struct spppkeepalivesettings*)data;
+ sppp_lock_enter(sp);
sp->pp_maxalive = settings->maxalive;
sp->pp_max_noreceive = settings->max_noreceive;
+ sppp_lock_exit(sp);
}
break;
#if defined(COMPAT_50) || defined(MODULAR)
case __SPPPGETIDLETO50:
{
struct spppidletimeout50 *to = (struct spppidletimeout50 *)data;
+ sppp_lock_enter(sp);
to->idle_seconds = (uint32_t)sp->pp_idle_timeout;
+ sppp_lock_exit(sp);
}
break;
case __SPPPSETIDLETO50:
{
- struct spppidletimeout50 *to = (struct spppidletimeout50 *)data;
- sp->pp_idle_timeout = (time_t)to->idle_seconds;
+ struct spppidletimeout50 *to = (struct spppidletimeout50 *)data;
+ sppp_lock_enter(sp);
+ sp->pp_idle_timeout = (time_t)to->idle_seconds;
+ sppp_lock_exit(sp);
}
break;
case __SPPPGETKEEPALIVE50:
{
struct spppkeepalivesettings50 *settings =
(struct spppkeepalivesettings50*)data;
+ sppp_lock_enter(sp);
settings->maxalive = sp->pp_maxalive;
settings->max_noreceive = (uint32_t)sp->pp_max_noreceive;
+ sppp_lock_exit(sp);
}
break;
case __SPPPSETKEEPALIVE50:
{
struct spppkeepalivesettings50 *settings =
(struct spppkeepalivesettings50*)data;
+ sppp_lock_enter(sp);
sp->pp_maxalive = settings->maxalive;
sp->pp_max_noreceive = (time_t)settings->max_noreceive;
+ sppp_lock_exit(sp);
}
break;
#endif /* COMPAT_50 || MODULAR */
@@ -5464,6 +5886,8 @@ sppp_phase_network(struct sppp *sp)
int i;
uint32_t mask;
+ KASSERT(sppp_locked(sp));
+
sppp_change_phase(sp, SPPP_PHASE_NETWORK);
/* Notify NCPs now. */
@@ -5473,8 +5897,9 @@ sppp_phase_network(struct sppp *sp)
/* Send Up events to all NCPs. */
for (i = 0, mask = 1; i < IDX_COUNT; i++, mask <<= 1)
- if ((sp->lcp.protos & mask) && ((cps[i])->flags & CP_NCP))
+ if ((sp->lcp.protos & mask) && ((cps[i])->flags & CP_NCP)) {
(cps[i])->Up(sp);
+ }
/* if no NCP is starting, all this was in vain, close down */
sppp_lcp_check_and_close(sp);
Index: src/sys/net/if_spppvar.h
diff -u src/sys/net/if_spppvar.h:1.19 src/sys/net/if_spppvar.h:1.20
--- src/sys/net/if_spppvar.h:1.19 Thu Dec 1 02:30:54 2016
+++ src/sys/net/if_spppvar.h Tue Dec 13 00:35:11 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: if_spppvar.h,v 1.19 2016/12/01 02:30:54 knakahara Exp $ */
+/* $NetBSD: if_spppvar.h,v 1.20 2016/12/13 00:35:11 knakahara Exp $ */
#ifndef _NET_IF_SPPPVAR_H_
#define _NET_IF_SPPPVAR_H_
@@ -111,6 +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 */
int query_dns; /* 1 if we want to know the dns addresses */
uint32_t dns_addrs[2];
int state[IDX_COUNT]; /* state machine */
@@ -180,5 +181,8 @@ 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_ */