diff options
author | melifaro <melifaro@FreeBSD.org> | 2014-08-23 14:58:31 +0000 |
---|---|---|
committer | melifaro <melifaro@FreeBSD.org> | 2014-08-23 14:58:31 +0000 |
commit | cf94663e69b2c927e4a44dcb922c93483f11bc29 (patch) | |
tree | f43a461c97f3db054606f6367939a61652f0db97 /sys/kern/uipc_socket.c | |
parent | 2e65f120c886a9d09b274b1953783df2b995e799 (diff) | |
parent | 19be009a4f8eb0d239ec3e465b0a9b2a2947dcf8 (diff) | |
download | FreeBSD-src-cf94663e69b2c927e4a44dcb922c93483f11bc29.zip FreeBSD-src-cf94663e69b2c927e4a44dcb922c93483f11bc29.tar.gz |
Sync to HEAD@r270409.
Diffstat (limited to 'sys/kern/uipc_socket.c')
-rw-r--r-- | sys/kern/uipc_socket.c | 121 |
1 files changed, 115 insertions, 6 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index ddf52b0..eb769a1 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -118,7 +118,9 @@ __FBSDID("$FreeBSD$"); #include <sys/mutex.h> #include <sys/domain.h> #include <sys/file.h> /* for struct knote */ +#include <sys/hhook.h> #include <sys/kernel.h> +#include <sys/khelp.h> #include <sys/event.h> #include <sys/eventhandler.h> #include <sys/poll.h> @@ -157,6 +159,7 @@ static int filt_soread(struct knote *kn, long hint); static void filt_sowdetach(struct knote *kn); static int filt_sowrite(struct knote *kn, long hint); static int filt_solisten(struct knote *kn, long hint); +static int inline hhook_run_socket(struct socket *so, void *hctx, int32_t h_id); static struct filterops solisten_filtops = { .f_isfd = 1, @@ -183,6 +186,9 @@ MALLOC_DEFINE(M_PCB, "pcb", "protocol control block"); VNET_ASSERT(curvnet != NULL, \ ("%s:%d curvnet is NULL, so=%p", __func__, __LINE__, (so))); +VNET_DEFINE(struct hhook_head *, socket_hhh[HHOOK_SOCKET_LAST + 1]); +#define V_socket_hhh VNET(socket_hhh) + /* * Limit on the number of connections in the listen queue waiting * for accept(2). @@ -255,6 +261,24 @@ socket_zone_change(void *tag) } static void +socket_hhook_register(int subtype) +{ + + if (hhook_head_register(HHOOK_TYPE_SOCKET, subtype, + &V_socket_hhh[subtype], + HHOOK_NOWAIT|HHOOK_HEADISINVNET) != 0) + printf("%s: WARNING: unable to register hook\n", __func__); +} + +static void +socket_hhook_deregister(int subtype) +{ + + if (hhook_head_deregister(V_socket_hhh[subtype]) != 0) + printf("%s: WARNING: unable to deregister hook\n", __func__); +} + +static void socket_init(void *tag) { @@ -267,6 +291,29 @@ socket_init(void *tag) } SYSINIT(socket, SI_SUB_PROTO_DOMAININIT, SI_ORDER_ANY, socket_init, NULL); +static void +socket_vnet_init(const void *unused __unused) +{ + int i; + + /* We expect a contiguous range */ + for (i = 0; i <= HHOOK_SOCKET_LAST; i++) + socket_hhook_register(i); +} +VNET_SYSINIT(socket_vnet_init, SI_SUB_PROTO_DOMAININIT, SI_ORDER_ANY, + socket_vnet_init, NULL); + +static void +socket_vnet_uninit(const void *unused __unused) +{ + int i; + + for (i = 0; i <= HHOOK_SOCKET_LAST; i++) + socket_hhook_deregister(i); +} +VNET_SYSUNINIT(socket_vnet_uninit, SI_SUB_PROTO_DOMAININIT, SI_ORDER_ANY, + socket_vnet_uninit, NULL); + /* * Initialise maxsockets. This SYSINIT must be run after * tunable_mbinit(). @@ -333,6 +380,11 @@ soalloc(struct vnet *vnet) return (NULL); } #endif + if (khelp_init_osd(HELPER_CLASS_SOCKET, &so->osd)) { + uma_zfree(socket_zone, so); + return (NULL); + } + SOCKBUF_LOCK_INIT(&so->so_snd, "so_snd"); SOCKBUF_LOCK_INIT(&so->so_rcv, "so_rcv"); sx_init(&so->so_snd.sb_sx, "so_snd_sx"); @@ -348,6 +400,16 @@ soalloc(struct vnet *vnet) so->so_vnet = vnet; #endif mtx_unlock(&so_global_mtx); + + CURVNET_SET(vnet); + /* We shouldn't need the so_global_mtx */ + if (V_socket_hhh[HHOOK_SOCKET_CREATE]->hhh_nhooks > 0) { + if (hhook_run_socket(so, NULL, HHOOK_SOCKET_CREATE)) + /* Do we need more comprehensive error returns? */ + so = NULL; + } + CURVNET_RESTORE(); + return (so); } @@ -384,7 +446,13 @@ sodealloc(struct socket *so) #ifdef MAC mac_socket_destroy(so); #endif + CURVNET_SET(so->so_vnet); + if (V_socket_hhh[HHOOK_SOCKET_CLOSE]->hhh_nhooks > 0) + hhook_run_socket(so, NULL, HHOOK_SOCKET_CLOSE); + CURVNET_RESTORE(); + crfree(so->so_cred); + khelp_destroy_osd(&so->osd); sx_destroy(&so->so_snd.sb_sx); sx_destroy(&so->so_rcv.sb_sx); SOCKBUF_LOCK_DESTROY(&so->so_snd); @@ -2328,6 +2396,25 @@ sorflush(struct socket *so) } /* + * Wrapper for Socket established helper hook. + * Parameters: socket, context of the hook point, hook id. + */ +static int inline +hhook_run_socket(struct socket *so, void *hctx, int32_t h_id) +{ + struct socket_hhook_data hhook_data = { + .so = so, + .hctx = hctx, + .m = NULL + }; + + hhook_run_hooks(V_socket_hhh[h_id], &hhook_data, &so->osd); + + /* Ugly but needed, since hhooks return void for now */ + return (hhook_data.status); +} + +/* * Perhaps this routine, and sooptcopyout(), below, ought to come in an * additional variant to handle the case where the option value needs to be * some kind of integer, but not a specific size. In addition to their use @@ -2572,7 +2659,11 @@ sosetopt(struct socket *so, struct sockopt *sopt) break; default: - error = ENOPROTOOPT; + if (V_socket_hhh[HHOOK_SOCKET_OPT]->hhh_nhooks > 0) + error = hhook_run_socket(so, sopt, + HHOOK_SOCKET_OPT); + else + error = ENOPROTOOPT; break; } if (error == 0 && so->so_proto->pr_ctloutput != NULL) @@ -2755,7 +2846,11 @@ integer: goto integer; default: - error = ENOPROTOOPT; + if (V_socket_hhh[HHOOK_SOCKET_OPT]->hhh_nhooks > 0) + error = hhook_run_socket(so, sopt, + HHOOK_SOCKET_OPT); + else + error = ENOPROTOOPT; break; } } @@ -3160,10 +3255,20 @@ filt_soread(struct knote *kn, long hint) return (1); } else if (so->so_error) /* temporary udp error */ return (1); - else if (kn->kn_sfflags & NOTE_LOWAT) - return (kn->kn_data >= kn->kn_sdata); - else - return (so->so_rcv.sb_cc >= so->so_rcv.sb_lowat); + + if (kn->kn_sfflags & NOTE_LOWAT) { + if (kn->kn_data >= kn->kn_sdata) + return 1; + } else { + if (so->so_rcv.sb_cc >= so->so_rcv.sb_lowat) + return 1; + } + + if (V_socket_hhh[HHOOK_FILT_SOREAD]->hhh_nhooks > 0) + /* This hook returning non-zero indicates an event, not error */ + return (hhook_run_socket(so, NULL, HHOOK_FILT_SOREAD)); + + return (0); } static void @@ -3187,6 +3292,10 @@ filt_sowrite(struct knote *kn, long hint) so = kn->kn_fp->f_data; SOCKBUF_LOCK_ASSERT(&so->so_snd); kn->kn_data = sbspace(&so->so_snd); + + if (V_socket_hhh[HHOOK_FILT_SOWRITE]->hhh_nhooks > 0) + hhook_run_socket(so, kn, HHOOK_FILT_SOWRITE); + if (so->so_snd.sb_state & SBS_CANTSENDMORE) { kn->kn_flags |= EV_EOF; kn->kn_fflags = so->so_error; |