@@ -203,6 +203,7 @@ struct ng_ppp_private { frags; int qlen; /* fraq queue length */ struct callout fragTimer; /* fraq queue check */ + struct lwkt_token token; /* serialize priv (SMP) */ }; typedef struct ng_ppp_private *priv_p; @@ -212,6 +213,10 @@ static ng_rcvmsg_t ng_ppp_rcvmsg; static ng_shutdown_t ng_ppp_rmnode; static ng_newhook_t ng_ppp_newhook; static ng_rcvdata_t ng_ppp_rcvdata; +static int ng_ppp_rcvdata_unlocked(hook_p hook, + struct mbuf *m, meta_p meta); +static int ng_ppp_newhook_unlocked(node_p node, hook_p hook, + const char *name); static ng_disconnect_t ng_ppp_disconnect; /* Helper functions */ @@ -400,6 +405,7 @@ ng_ppp_constructor(node_p *nodep) for (i = 0; i < NG_PPP_MAX_LINKS; i++) priv->links[i].seq = MP_NOSEQ; callout_init(&priv->fragTimer); + lwkt_token_init(&priv->token, "ng_ppp"); /* Done */ return (0); @@ -410,6 +416,18 @@ ng_ppp_constructor(node_p *nodep) */ static int ng_ppp_newhook(node_p node, hook_p hook, const char *name) +{ + const priv_p priv = node->private; + int ret; + + lwkt_gettoken(&priv->token); + ret = ng_ppp_newhook_unlocked(node, hook, name); + lwkt_reltoken(&priv->token); + return (ret); +} + +static int +ng_ppp_newhook_unlocked(node_p node, hook_p hook, const char *name) { const priv_p priv = node->private; int linkNum = -1; @@ -471,6 +489,7 @@ ng_ppp_rcvmsg(node_p node, struct ng_mesg *msg, struct ng_mesg *resp = NULL; int error = 0; + lwkt_gettoken(&priv->token); switch (msg->header.typecookie) { case NGM_PPP_COOKIE: switch (msg->header.cmd) { @@ -565,6 +584,7 @@ ng_ppp_rcvmsg(node_p node, struct ng_mesg *msg, ERROUT(error); ksnprintf(path, sizeof(path), "[%lx]:%s", (long)node, NG_PPP_HOOK_VJC_IP); + lwkt_reltoken(&priv->token); return ng_send_msg(origNode, msg, path, rptr); } default: @@ -578,6 +598,7 @@ ng_ppp_rcvmsg(node_p node, struct ng_mesg *msg, done: kfree(msg, M_NETGRAPH); + lwkt_reltoken(&priv->token); return (error); } @@ -586,6 +607,19 @@ ng_ppp_rcvmsg(node_p node, struct ng_mesg *msg, */ static int ng_ppp_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) +{ + const node_p node = hook->node; + const priv_p priv = node->private; + int ret; + + lwkt_gettoken(&priv->token); + ret = ng_ppp_rcvdata_unlocked(hook, m, meta); + lwkt_reltoken(&priv->token); + return (ret); +} + +static int +ng_ppp_rcvdata_unlocked(hook_p hook, struct mbuf *m, meta_p meta) { const node_p node = hook->node; const priv_p priv = node->private; @@ -793,6 +827,8 @@ ng_ppp_rmnode(node_p node) { const priv_p priv = node->private; + lwkt_gettoken(&priv->token); + /* Stop fragment queue timer */ ng_ppp_stop_frag_timer(node); @@ -801,6 +837,14 @@ ng_ppp_rmnode(node_p node) ng_cutlinks(node); ng_unname(node); ng_ppp_frag_reset(node); + /* + * All hooks are gone now, so no new rcvdata/rcvmsg can be + * dispatched. Drop the token before the private structure is + * freed so we never touch freed memory; any synchronous caller + * still spinning on the token sees valid (zeroed-by-bzero + * below) memory or an invalid hook and bails. + */ + lwkt_reltoken(&priv->token); bzero(priv, sizeof(*priv)); kfree(priv, M_NETGRAPH); node->private = NULL; @@ -818,6 +862,8 @@ ng_ppp_disconnect(hook_p hook) const priv_p priv = node->private; const int index = HOOK_INDEX(hook); + lwkt_gettoken(&priv->token); + /* Zero out hook pointer */ if (index < 0) priv->links[~index].hook = NULL; @@ -829,6 +875,7 @@ ng_ppp_disconnect(hook_p hook) ng_ppp_update(node, 0); else ng_rmnode(node); + lwkt_reltoken(&priv->token); return (0); } @@ -1457,6 +1504,7 @@ ng_ppp_frag_timeout(void *arg) crit_exit(); return; } + lwkt_gettoken(&priv->token); /* Reset timer state after timeout */ KASSERT(priv->timerActive, ("%s: !timerActive", __func__)); @@ -1469,6 +1517,7 @@ ng_ppp_frag_timeout(void *arg) /* Scan the fragment queue */ ng_ppp_frag_checkstale(node); + lwkt_reltoken(&priv->token); crit_exit(); }