diff options
author | Luiz Souza <luiz@netgate.com> | 2017-12-14 11:53:13 -0600 |
---|---|---|
committer | Luiz Souza <luiz@netgate.com> | 2017-12-14 11:53:13 -0600 |
commit | 6b18210a35860717a2745bf1fb48ac06228d67fa (patch) | |
tree | 44cf0f4cad46f34885bf164f43a429063d92adc0 /sys/netgraph | |
parent | 8f0ba7d22c8b084e6fb1a1af1ec2bca7c5e901e2 (diff) | |
parent | b943e7684ac8157a9704285d72a28eec93eb9041 (diff) | |
download | FreeBSD-src-6b18210a35860717a2745bf1fb48ac06228d67fa.zip FreeBSD-src-6b18210a35860717a2745bf1fb48ac06228d67fa.tar.gz |
Merge remote-tracking branch 'origin/stable/11' into devel-11
Diffstat (limited to 'sys/netgraph')
-rw-r--r-- | sys/netgraph/ng_iface.c | 38 |
1 files changed, 34 insertions, 4 deletions
diff --git a/sys/netgraph/ng_iface.c b/sys/netgraph/ng_iface.c index 2a342b6..8bb3379 100644 --- a/sys/netgraph/ng_iface.c +++ b/sys/netgraph/ng_iface.c @@ -60,11 +60,13 @@ #include <sys/errno.h> #include <sys/eventhandler.h> #include <sys/kernel.h> +#include <sys/lock.h> #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/errno.h> #include <sys/proc.h> #include <sys/random.h> +#include <sys/rmlock.h> #include <sys/sockio.h> #include <sys/socket.h> #include <sys/syslog.h> @@ -114,9 +116,15 @@ struct ng_iface_private { int unit; /* Interface unit number */ node_p node; /* Our netgraph node */ hook_p hooks[NUM_FAMILIES]; /* Hook for each address family */ + struct rmlock lock; /* Protect private data changes */ }; typedef struct ng_iface_private *priv_p; +#define PRIV_RLOCK(priv, t) rm_rlock(&priv->lock, t) +#define PRIV_RUNLOCK(priv, t) rm_runlock(&priv->lock, t) +#define PRIV_WLOCK(priv) rm_wlock(&priv->lock) +#define PRIV_WUNLOCK(priv) rm_wunlock(&priv->lock) + /* Interface methods */ static void ng_iface_start(struct ifnet *ifp); static int ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); @@ -440,8 +448,10 @@ ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, sa_family_t family) static int ng_iface_send(struct ifnet *ifp, struct mbuf *m, sa_family_t sa) { + struct rm_priotracker priv_tracker; const priv_p priv = (priv_p) ifp->if_softc; const iffam_p iffam = get_iffam_from_af(sa); + hook_p hook; int error; int len; @@ -455,10 +465,20 @@ ng_iface_send(struct ifnet *ifp, struct mbuf *m, sa_family_t sa) /* Copy length before the mbuf gets invalidated. */ len = m->m_pkthdr.len; - /* Send packet. If hook is not connected, mbuf will get freed. */ + PRIV_RLOCK(priv, &priv_tracker); + hook = *get_hook_from_iffam(priv, iffam); + if (hook == NULL) { + NG_FREE_M(m); + PRIV_RUNLOCK(priv, &priv_tracker); + return ENETDOWN; + } + NG_HOOK_REF(hook); + PRIV_RUNLOCK(priv, &priv_tracker); + NG_OUTBOUND_THREAD_REF(); - NG_SEND_DATA_ONLY(error, *get_hook_from_iffam(priv, iffam), m); + NG_SEND_DATA_ONLY(error, hook, m); NG_OUTBOUND_THREAD_UNREF(); + NG_HOOK_UNREF(hook); /* Update stats. */ if (error == 0) { @@ -525,6 +545,8 @@ ng_iface_constructor(node_p node) return (ENOMEM); } + rm_init(&priv->lock, "ng_iface private rmlock"); + /* Link them together */ ifp->if_softc = priv; priv->ifp = ifp; @@ -571,16 +593,21 @@ static int ng_iface_newhook(node_p node, hook_p hook, const char *name) { const iffam_p iffam = get_iffam_from_name(name); + const priv_p priv = NG_NODE_PRIVATE(node); hook_p *hookptr; if (iffam == NULL) return (EPFNOSUPPORT); - hookptr = get_hook_from_iffam(NG_NODE_PRIVATE(node), iffam); - if (*hookptr != NULL) + PRIV_WLOCK(priv); + hookptr = get_hook_from_iffam(priv, iffam); + if (*hookptr != NULL) { + PRIV_WUNLOCK(priv); return (EISCONN); + } *hookptr = hook; NG_HOOK_HI_STACK(hook); NG_HOOK_SET_TO_INBOUND(hook); + PRIV_WUNLOCK(priv); return (0); } @@ -786,6 +813,7 @@ ng_iface_shutdown(node_p node) CURVNET_RESTORE(); priv->ifp = NULL; free_unr(V_ng_iface_unit, priv->unit); + rm_destroy(&priv->lock); free(priv, M_NETGRAPH_IFACE); NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(node); @@ -804,7 +832,9 @@ ng_iface_disconnect(hook_p hook) if (iffam == NULL) panic("%s", __func__); + PRIV_WLOCK(priv); *get_hook_from_iffam(priv, iffam) = NULL; + PRIV_WUNLOCK(priv); return (0); } |