aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet/raw_ip.c
diff options
context:
space:
mode:
authorGleb Smirnoff <glebius@FreeBSD.org>2019-11-07 21:27:32 +0000
committerGleb Smirnoff <glebius@FreeBSD.org>2019-11-07 21:27:32 +0000
commit032677ceb535e53dcd041eff471a6fee631afe9b (patch)
treeffee1673969d517e554519465eae3ab04e83028e /sys/netinet/raw_ip.c
parentd40c0d47cd2a8100b8b9719bea092dde0512937a (diff)
downloadsrc-032677ceb535e53dcd041eff471a6fee631afe9b.tar.gz
src-032677ceb535e53dcd041eff471a6fee631afe9b.zip
Notes
Diffstat (limited to 'sys/netinet/raw_ip.c')
-rw-r--r--sys/netinet/raw_ip.c72
1 files changed, 21 insertions, 51 deletions
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index 1dd7a9de3f56..95f1a7c04b93 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -1067,97 +1067,67 @@ rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
static int
rip_pcblist(SYSCTL_HANDLER_ARGS)
{
- int error, i, n;
- struct inpcb *inp, **inp_list;
- inp_gen_t gencnt;
struct xinpgen xig;
struct epoch_tracker et;
+ struct inpcb *inp;
+ int error;
+
+ if (req->newptr != 0)
+ return (EPERM);
- /*
- * The process of preparing the TCB list is too time-consuming and
- * resource-intensive to repeat twice on every request.
- */
if (req->oldptr == 0) {
+ int n;
+
n = V_ripcbinfo.ipi_count;
n += imax(n / 8, 10);
req->oldidx = 2 * (sizeof xig) + n * sizeof(struct xinpcb);
return (0);
}
- if (req->newptr != 0)
- return (EPERM);
-
- /*
- * OK, now we're committed to doing something.
- */
- INP_INFO_WLOCK(&V_ripcbinfo);
- gencnt = V_ripcbinfo.ipi_gencnt;
- n = V_ripcbinfo.ipi_count;
- INP_INFO_WUNLOCK(&V_ripcbinfo);
+ if ((error = sysctl_wire_old_buffer(req, 0)) != 0)
+ return (error);
bzero(&xig, sizeof(xig));
xig.xig_len = sizeof xig;
- xig.xig_count = n;
- xig.xig_gen = gencnt;
+ xig.xig_count = V_ripcbinfo.ipi_count;
+ xig.xig_gen = V_ripcbinfo.ipi_gencnt;
xig.xig_sogen = so_gencnt;
error = SYSCTL_OUT(req, &xig, sizeof xig);
if (error)
return (error);
- inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
-
- INP_INFO_RLOCK_ET(&V_ripcbinfo, et);
- for (inp = CK_LIST_FIRST(V_ripcbinfo.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) {
- in_pcbref(inp);
- inp_list[i++] = inp;
- }
- INP_WUNLOCK(inp);
- }
- INP_INFO_RUNLOCK_ET(&V_ripcbinfo, et);
- n = i;
-
- error = 0;
- for (i = 0; i < n; i++) {
- inp = inp_list[i];
+ NET_EPOCH_ENTER(et);
+ for (inp = CK_LIST_FIRST(V_ripcbinfo.ipi_listhead);
+ inp != NULL;
+ inp = CK_LIST_NEXT(inp, inp_list)) {
INP_RLOCK(inp);
- if (inp->inp_gencnt <= gencnt) {
+ if (inp->inp_gencnt <= xig.xig_gen &&
+ cr_canseeinpcb(req->td->td_ucred, inp) == 0) {
struct xinpcb xi;
in_pcbtoxinpcb(inp, &xi);
INP_RUNLOCK(inp);
error = SYSCTL_OUT(req, &xi, sizeof xi);
+ if (error)
+ break;
} else
INP_RUNLOCK(inp);
}
- INP_INFO_WLOCK(&V_ripcbinfo);
- 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_ripcbinfo);
+ NET_EPOCH_EXIT(et);
if (!error) {
- struct epoch_tracker et;
/*
* Give the user an updated idea of our state. If the
* generation differs from what we told her before, she knows
* that something happened while we were processing this
* request, and it might be necessary to retry.
*/
- INP_INFO_RLOCK_ET(&V_ripcbinfo, et);
xig.xig_gen = V_ripcbinfo.ipi_gencnt;
xig.xig_sogen = so_gencnt;
xig.xig_count = V_ripcbinfo.ipi_count;
- INP_INFO_RUNLOCK_ET(&V_ripcbinfo, et);
error = SYSCTL_OUT(req, &xig, sizeof xig);
}
- free(inp_list, M_TEMP);
+
return (error);
}