summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet/ip_divert.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet/ip_divert.c')
-rw-r--r--freebsd/sys/netinet/ip_divert.c49
1 files changed, 28 insertions, 21 deletions
diff --git a/freebsd/sys/netinet/ip_divert.c b/freebsd/sys/netinet/ip_divert.c
index 84f39023..fbf74ca1 100644
--- a/freebsd/sys/netinet/ip_divert.c
+++ b/freebsd/sys/netinet/ip_divert.c
@@ -113,8 +113,8 @@ __FBSDID("$FreeBSD$");
*/
/* Internal variables. */
-static VNET_DEFINE(struct inpcbhead, divcb);
-static VNET_DEFINE(struct inpcbinfo, divcbinfo);
+VNET_DEFINE_STATIC(struct inpcbhead, divcb);
+VNET_DEFINE_STATIC(struct inpcbinfo, divcbinfo);
#define V_divcb VNET(divcb)
#define V_divcbinfo VNET(divcbinfo)
@@ -194,6 +194,7 @@ divert_packet(struct mbuf *m, int incoming)
u_int16_t nport;
struct sockaddr_in divsrc;
struct m_tag *mtag;
+ struct epoch_tracker et;
mtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL);
if (mtag == NULL) {
@@ -274,8 +275,8 @@ divert_packet(struct mbuf *m, int incoming)
/* Put packet on socket queue, if any */
sa = NULL;
nport = htons((u_int16_t)(((struct ipfw_rule_ref *)(mtag+1))->info));
- INP_INFO_RLOCK(&V_divcbinfo);
- LIST_FOREACH(inp, &V_divcb, inp_list) {
+ INP_INFO_RLOCK_ET(&V_divcbinfo, et);
+ CK_LIST_FOREACH(inp, &V_divcb, inp_list) {
/* XXX why does only one socket match? */
if (inp->inp_lport == nport) {
INP_RLOCK(inp);
@@ -292,7 +293,7 @@ divert_packet(struct mbuf *m, int incoming)
break;
}
}
- INP_INFO_RUNLOCK(&V_divcbinfo);
+ INP_INFO_RUNLOCK_ET(&V_divcbinfo, et);
if (sa == NULL) {
m_freem(m);
KMOD_IPSTAT_INC(ips_noproto);
@@ -554,7 +555,6 @@ div_detach(struct socket *so)
KASSERT(inp != NULL, ("div_detach: inp == NULL"));
INP_INFO_WLOCK(&V_divcbinfo);
INP_WLOCK(inp);
- /* XXX defer destruction to epoch_call */
in_pcbdetach(inp);
in_pcbfree(inp);
INP_INFO_WUNLOCK(&V_divcbinfo);
@@ -634,10 +634,10 @@ static int
div_pcblist(SYSCTL_HANDLER_ARGS)
{
int error, i, n;
- struct in_pcblist *il;
struct inpcb *inp, **inp_list;
inp_gen_t gencnt;
struct xinpgen xig;
+ struct epoch_tracker et;
/*
* The process of preparing the TCB list is too time-consuming and
@@ -656,10 +656,10 @@ div_pcblist(SYSCTL_HANDLER_ARGS)
/*
* OK, now we're committed to doing something.
*/
- INP_INFO_RLOCK(&V_divcbinfo);
+ INP_INFO_WLOCK(&V_divcbinfo);
gencnt = V_divcbinfo.ipi_gencnt;
n = V_divcbinfo.ipi_count;
- INP_INFO_RUNLOCK(&V_divcbinfo);
+ INP_INFO_WUNLOCK(&V_divcbinfo);
error = sysctl_wire_old_buffer(req,
2 * sizeof(xig) + n*sizeof(struct xinpcb));
@@ -674,12 +674,13 @@ div_pcblist(SYSCTL_HANDLER_ARGS)
if (error)
return error;
- il = malloc(sizeof(struct in_pcblist) + n * sizeof(struct inpcb *), M_TEMP, M_WAITOK|M_ZERO_INVARIANTS);
- inp_list = il->il_inp_list;
+ inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
+ if (inp_list == NULL)
+ return ENOMEM;
- INP_INFO_RLOCK(&V_divcbinfo);
- for (inp = LIST_FIRST(V_divcbinfo.ipi_listhead), i = 0; inp && i < n;
- inp = LIST_NEXT(inp, inp_list)) {
+ INP_INFO_RLOCK_ET(&V_divcbinfo, et);
+ for (inp = CK_LIST_FIRST(V_divcbinfo.ipi_listhead), i = 0; inp && i < n;
+ inp = CK_LIST_NEXT(inp, inp_list)) {
INP_WLOCK(inp);
if (inp->inp_gencnt <= gencnt &&
cr_canseeinpcb(req->td->td_ucred, inp) == 0) {
@@ -688,7 +689,7 @@ div_pcblist(SYSCTL_HANDLER_ARGS)
}
INP_WUNLOCK(inp);
}
- INP_INFO_RUNLOCK(&V_divcbinfo);
+ INP_INFO_RUNLOCK_ET(&V_divcbinfo, et);
n = i;
error = 0;
@@ -704,11 +705,17 @@ div_pcblist(SYSCTL_HANDLER_ARGS)
} else
INP_RUNLOCK(inp);
}
- il->il_count = n;
- il->il_pcbinfo = &V_divcbinfo;
- epoch_call(net_epoch_preempt, &il->il_epoch_ctx, in_pcblist_rele_rlocked);
+ INP_INFO_WLOCK(&V_divcbinfo);
+ for (i = 0; i < n; i++) {
+ inp = inp_list[i];
+ INP_RLOCK(inp);
+ if (!in_pcbrele_rlocked(inp))
+ INP_RUNLOCK(inp);
+ }
+ INP_INFO_WUNLOCK(&V_divcbinfo);
if (!error) {
+ struct epoch_tracker et;
/*
* Give the user an updated idea of our state.
* If the generation differs from what we told
@@ -716,13 +723,14 @@ div_pcblist(SYSCTL_HANDLER_ARGS)
* while we were processing this request, and it
* might be necessary to retry.
*/
- INP_INFO_RLOCK(&V_divcbinfo);
+ INP_INFO_RLOCK_ET(&V_divcbinfo, et);
xig.xig_gen = V_divcbinfo.ipi_gencnt;
xig.xig_sogen = so_gencnt;
xig.xig_count = V_divcbinfo.ipi_count;
- INP_INFO_RUNLOCK(&V_divcbinfo);
+ INP_INFO_RUNLOCK_ET(&V_divcbinfo, et);
error = SYSCTL_OUT(req, &xig, sizeof xig);
}
+ free(inp_list, M_TEMP);
return error;
}
@@ -802,7 +810,6 @@ div_modevent(module_t mod, int type, void *unused)
break;
}
ip_divert_ptr = NULL;
- /* XXX defer to epoch_call ? */
err = pf_proto_unregister(PF_INET, IPPROTO_DIVERT, SOCK_RAW);
INP_INFO_WUNLOCK(&V_divcbinfo);
#ifndef VIMAGE