summaryrefslogtreecommitdiffstats
path: root/sys/kern/uipc_socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/uipc_socket.c')
-rw-r--r--sys/kern/uipc_socket.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index b172d46..c2d0ad7 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -58,6 +58,8 @@
#include <machine/limits.h>
+static int do_setopt_accept_filter(struct socket *so, struct sockopt *sopt);
+
static int filt_sorattach(struct knote *kn);
static void filt_sordetach(struct knote *kn);
static int filt_soread(struct knote *kn, long hint);
@@ -193,6 +195,15 @@ sodealloc(so)
if (so->so_snd.sb_hiwat)
(void)chgsbsize(so->so_cred->cr_uid,
-(rlim_t)so->so_snd.sb_hiwat);
+ if (so->so_accf != NULL) {
+ if (so->so_accf->so_accept_filter != NULL &&
+ so->so_accf->so_accept_filter->accf_destroy != NULL) {
+ so->so_accf->so_accept_filter->accf_destroy(so);
+ }
+ if (so->so_accf->so_accept_filter_str != NULL)
+ FREE(so->so_accf->so_accept_filter_str, M_ACCF);
+ FREE(so->so_accf, M_ACCF);
+ }
crfree(so->so_cred);
zfreei(so->so_zone, so);
}
@@ -977,6 +988,77 @@ sorflush(so)
sbrelease(&asb, so);
}
+static int
+do_setopt_accept_filter(so, sopt)
+ struct socket *so;
+ struct sockopt *sopt;
+{
+ struct accept_filter_arg *afap = NULL;
+ struct accept_filter *afp;
+ struct so_accf *af = so->so_accf;
+ int error = 0;
+
+ /* removing the filter */
+ if (sopt == NULL) {
+ if (af != NULL) {
+ if (af->so_accept_filter != NULL &&
+ af->so_accept_filter->accf_destroy != NULL) {
+ af->so_accept_filter->accf_destroy(so);
+ }
+ if (af->so_accept_filter_str != NULL) {
+ FREE(af->so_accept_filter_str, M_ACCF);
+ }
+ FREE(af, M_ACCF);
+ so->so_accf = NULL;
+ }
+ so->so_options &= ~SO_ACCEPTFILTER;
+ return (0);
+ }
+ /* adding a filter */
+ /* must remove previous filter first */
+ if (af != NULL) {
+ error = EINVAL;
+ goto out;
+ }
+ /* don't put large objects on the kernel stack */
+ MALLOC(afap, struct accept_filter_arg *, sizeof(*afap), M_TEMP, M_WAITOK);
+ error = sooptcopyin(sopt, afap, sizeof *afap, sizeof *afap);
+ afap->af_name[sizeof(afap->af_name)-1] = '\0';
+ afap->af_arg[sizeof(afap->af_arg)-1] = '\0';
+ if (error)
+ goto out;
+ afp = accept_filt_get(afap->af_name);
+ if (afp == NULL) {
+ error = ENOENT;
+ goto out;
+ }
+ MALLOC(af, struct so_accf *, sizeof(*af), M_ACCF, M_WAITOK);
+ bzero(af, sizeof(*af));
+ if (afp->accf_create != NULL) {
+ if (afap->af_name[0] != '\0') {
+ int len = strlen(afap->af_name) + 1;
+
+ MALLOC(af->so_accept_filter_str, char *, len, M_ACCF, M_WAITOK);
+ strcpy(af->so_accept_filter_str, afap->af_name);
+ }
+ af->so_accept_filter_arg = afp->accf_create(so, afap->af_arg);
+ if (af->so_accept_filter_arg == NULL) {
+ FREE(af->so_accept_filter_str, M_ACCF);
+ FREE(af, M_ACCF);
+ so->so_accf = NULL;
+ error = EINVAL;
+ goto out;
+ }
+ }
+ af->so_accept_filter = afp;
+ so->so_accf = af;
+ so->so_options |= SO_ACCEPTFILTER;
+out:
+ if (afap != NULL)
+ FREE(afap, M_TEMP);
+ return (error);
+}
+
/*
* Perhaps this routine, and sooptcopyout(), below, ought to come in
* an additional variant to handle the case where the option value needs
@@ -1137,6 +1219,11 @@ sosetopt(so, sopt)
}
break;
+ case SO_ACCEPTFILTER:
+ error = do_setopt_accept_filter(so, sopt);
+ if (error)
+ goto bad;
+ break;
default:
error = ENOPROTOOPT;
break;
@@ -1190,6 +1277,7 @@ sogetopt(so, sopt)
int error, optval;
struct linger l;
struct timeval tv;
+ struct accept_filter_arg *afap;
error = 0;
if (sopt->sopt_level != SOL_SOCKET) {
@@ -1200,6 +1288,19 @@ sogetopt(so, sopt)
return (ENOPROTOOPT);
} else {
switch (sopt->sopt_name) {
+ case SO_ACCEPTFILTER:
+ MALLOC(afap, struct accept_filter_arg *, sizeof(*afap),
+ M_TEMP, M_WAITOK);
+ bzero(afap, sizeof(*afap));
+ if ((so->so_options & SO_ACCEPTFILTER) != 0) {
+ strcpy(afap->af_name, so->so_accf->so_accept_filter->accf_name);
+ if (so->so_accf->so_accept_filter_str != NULL)
+ strcpy(afap->af_arg, so->so_accf->so_accept_filter_str);
+ }
+ error = sooptcopyout(sopt, afap, sizeof(*afap));
+ FREE(afap, M_TEMP);
+ break;
+
case SO_LINGER:
l.l_onoff = so->so_options & SO_LINGER;
l.l_linger = so->so_linger;
OpenPOWER on IntegriCloud