diff options
author | ru <ru@FreeBSD.org> | 2000-08-03 14:09:52 +0000 |
---|---|---|
committer | ru <ru@FreeBSD.org> | 2000-08-03 14:09:52 +0000 |
commit | 50604c76216a391b193b037e68ab1f66c4e41dde (patch) | |
tree | 0789cd450bc977ea22e47d9bb2ae9b9823ac14c0 /sys/netinet/ip_divert.c | |
parent | cdd996ee9c582b6081c73f4e0beffb19da81534a (diff) | |
download | FreeBSD-src-50604c76216a391b193b037e68ab1f66c4e41dde.zip FreeBSD-src-50604c76216a391b193b037e68ab1f66c4e41dde.tar.gz |
Make netstat(1) to be aware of divert(4) sockets.
Diffstat (limited to 'sys/netinet/ip_divert.c')
-rw-r--r-- | sys/netinet/ip_divert.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index bbe5036..77ab70f 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -43,11 +43,13 @@ #endif #include <sys/param.h> +#include <sys/kernel.h> #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/protosw.h> #include <sys/socketvar.h> +#include <sys/sysctl.h> #include <sys/systm.h> #include <sys/proc.h> @@ -356,6 +358,7 @@ div_attach(struct socket *so, int proto, struct proc *p) return error; inp = (struct inpcb *)so->so_pcb; inp->inp_ip_p = proto; + inp->inp_vflag |= INP_IPV4; inp->inp_flags |= INP_HDRINCL; /* The socket is always "connected" because we always know "where" to send the packet */ @@ -446,6 +449,93 @@ div_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, return div_output(so, m, nam, control); } +static int +div_pcblist(SYSCTL_HANDLER_ARGS) +{ + int error, i, n, s; + struct inpcb *inp, **inp_list; + inp_gen_t gencnt; + struct xinpgen xig; + + /* + * The process of preparing the TCB list is too time-consuming and + * resource-intensive to repeat twice on every request. + */ + if (req->oldptr == 0) { + n = divcbinfo.ipi_count; + req->oldidx = 2 * (sizeof xig) + + (n + n/8) * sizeof(struct xinpcb); + return 0; + } + + if (req->newptr != 0) + return EPERM; + + /* + * OK, now we're committed to doing something. + */ + s = splnet(); + gencnt = divcbinfo.ipi_gencnt; + n = divcbinfo.ipi_count; + splx(s); + + xig.xig_len = sizeof xig; + xig.xig_count = n; + xig.xig_gen = 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); + if (inp_list == 0) + return ENOMEM; + + s = splnet(); + for (inp = divcbinfo.listhead->lh_first, i = 0; inp && i < n; + inp = inp->inp_list.le_next) { + if (inp->inp_gencnt <= gencnt && !prison_xinpcb(req->p, inp)) + inp_list[i++] = inp; + } + splx(s); + n = i; + + error = 0; + for (i = 0; i < n; i++) { + inp = inp_list[i]; + if (inp->inp_gencnt <= gencnt) { + struct xinpcb xi; + xi.xi_len = sizeof xi; + /* XXX should avoid extra copy */ + bcopy(inp, &xi.xi_inp, sizeof *inp); + if (inp->inp_socket) + sotoxsocket(inp->inp_socket, &xi.xi_socket); + error = SYSCTL_OUT(req, &xi, sizeof xi); + } + } + if (!error) { + /* + * 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. + */ + s = splnet(); + xig.xig_gen = divcbinfo.ipi_gencnt; + xig.xig_sogen = so_gencnt; + xig.xig_count = divcbinfo.ipi_count; + splx(s); + error = SYSCTL_OUT(req, &xig, sizeof xig); + } + free(inp_list, M_TEMP); + return error; +} + +SYSCTL_DECL(_net_inet_divert); +SYSCTL_PROC(_net_inet_divert, OID_AUTO, pcblist, CTLFLAG_RD, 0, 0, + div_pcblist, "S,xinpcb", "List of active divert sockets"); + struct pr_usrreqs div_usrreqs = { div_abort, pru_accept_notsupp, div_attach, div_bind, pru_connect_notsupp, pru_connect2_notsupp, in_control, div_detach, |