summaryrefslogtreecommitdiffstats
path: root/sys/netinet/ip_divert.c
diff options
context:
space:
mode:
authorru <ru@FreeBSD.org>2000-08-03 14:09:52 +0000
committerru <ru@FreeBSD.org>2000-08-03 14:09:52 +0000
commit50604c76216a391b193b037e68ab1f66c4e41dde (patch)
tree0789cd450bc977ea22e47d9bb2ae9b9823ac14c0 /sys/netinet/ip_divert.c
parentcdd996ee9c582b6081c73f4e0beffb19da81534a (diff)
downloadFreeBSD-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.c90
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,
OpenPOWER on IntegriCloud