Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/uipc_accf.c
Show First 20 Lines • Show All 156 Lines • ▼ Show 20 Lines | default: | ||||
error = EOPNOTSUPP; | error = EOPNOTSUPP; | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
do_getopt_accept_filter(struct socket *so, struct sockopt *sopt) | accept_filt_getopt(struct socket *so, struct sockopt *sopt) | ||||
{ | { | ||||
struct accept_filter_arg *afap; | struct accept_filter_arg *afap; | ||||
int error; | int error; | ||||
error = 0; | error = 0; | ||||
afap = malloc(sizeof(*afap), M_TEMP, | afap = malloc(sizeof(*afap), M_TEMP, M_WAITOK | M_ZERO); | ||||
M_WAITOK | M_ZERO); | |||||
SOCK_LOCK(so); | SOCK_LOCK(so); | ||||
if ((so->so_options & SO_ACCEPTCONN) == 0) { | if ((so->so_options & SO_ACCEPTCONN) == 0) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
if ((so->so_options & SO_ACCEPTFILTER) == 0) { | if (so->sol_accept_filter == NULL) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
strcpy(afap->af_name, so->so_accf->so_accept_filter->accf_name); | strcpy(afap->af_name, so->sol_accept_filter->accf_name); | ||||
if (so->so_accf->so_accept_filter_str != NULL) | if (so->sol_accept_filter_str != NULL) | ||||
strcpy(afap->af_arg, so->so_accf->so_accept_filter_str); | strcpy(afap->af_arg, so->sol_accept_filter_str); | ||||
out: | out: | ||||
SOCK_UNLOCK(so); | SOCK_UNLOCK(so); | ||||
if (error == 0) | if (error == 0) | ||||
error = sooptcopyout(sopt, afap, sizeof(*afap)); | error = sooptcopyout(sopt, afap, sizeof(*afap)); | ||||
free(afap, M_TEMP); | free(afap, M_TEMP); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
do_setopt_accept_filter(struct socket *so, struct sockopt *sopt) | accept_filt_setopt(struct socket *so, struct sockopt *sopt) | ||||
{ | { | ||||
struct accept_filter_arg *afap; | struct accept_filter_arg *afap; | ||||
struct accept_filter *afp; | struct accept_filter *afp; | ||||
struct so_accf *newaf; | char *accept_filter_str = NULL; | ||||
int error = 0; | void *accept_filter_arg = NULL; | ||||
int error; | |||||
/* | /* | ||||
* Handle the simple delete case first. | * Handle the simple delete case first. | ||||
*/ | */ | ||||
if (sopt == NULL || sopt->sopt_val == NULL) { | if (sopt == NULL || sopt->sopt_val == NULL) { | ||||
SOCK_LOCK(so); | SOCK_LOCK(so); | ||||
if ((so->so_options & SO_ACCEPTCONN) == 0) { | if ((so->so_options & SO_ACCEPTCONN) == 0) { | ||||
SOCK_UNLOCK(so); | SOCK_UNLOCK(so); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
if (so->so_accf != NULL) { | if (so->sol_accept_filter != NULL) { | ||||
struct so_accf *af = so->so_accf; | if (so->sol_accept_filter->accf_destroy != NULL) | ||||
if (af->so_accept_filter != NULL && | so->sol_accept_filter->accf_destroy(so); | ||||
af->so_accept_filter->accf_destroy != NULL) { | if (so->sol_accept_filter_str != NULL) | ||||
af->so_accept_filter->accf_destroy(so); | free(so->sol_accept_filter_str, M_ACCF); | ||||
so->sol_accept_filter = NULL; | |||||
so->sol_accept_filter_arg = NULL; | |||||
so->sol_accept_filter_str = NULL; | |||||
} | } | ||||
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; | |||||
SOCK_UNLOCK(so); | SOCK_UNLOCK(so); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Pre-allocate any memory we may need later to avoid blocking at | * Pre-allocate any memory we may need later to avoid blocking at | ||||
* untimely moments. This does not optimize for invalid arguments. | * untimely moments. This does not optimize for invalid arguments. | ||||
*/ | */ | ||||
afap = malloc(sizeof(*afap), M_TEMP, | afap = malloc(sizeof(*afap), M_TEMP, M_WAITOK); | ||||
M_WAITOK); | |||||
error = sooptcopyin(sopt, afap, sizeof *afap, sizeof *afap); | error = sooptcopyin(sopt, afap, sizeof *afap, sizeof *afap); | ||||
afap->af_name[sizeof(afap->af_name)-1] = '\0'; | afap->af_name[sizeof(afap->af_name)-1] = '\0'; | ||||
afap->af_arg[sizeof(afap->af_arg)-1] = '\0'; | afap->af_arg[sizeof(afap->af_arg)-1] = '\0'; | ||||
if (error) { | if (error) { | ||||
free(afap, M_TEMP); | free(afap, M_TEMP); | ||||
return (error); | return (error); | ||||
} | } | ||||
afp = accept_filt_get(afap->af_name); | afp = accept_filt_get(afap->af_name); | ||||
if (afp == NULL) { | if (afp == NULL) { | ||||
free(afap, M_TEMP); | free(afap, M_TEMP); | ||||
return (ENOENT); | return (ENOENT); | ||||
} | } | ||||
/* | |||||
* Allocate the new accept filter instance storage. We may | |||||
* have to free it again later if we fail to attach it. If | |||||
* attached properly, 'newaf' is NULLed to avoid a free() | |||||
* while in use. | |||||
*/ | |||||
newaf = malloc(sizeof(*newaf), M_ACCF, M_WAITOK | | |||||
M_ZERO); | |||||
if (afp->accf_create != NULL && afap->af_name[0] != '\0') { | if (afp->accf_create != NULL && afap->af_name[0] != '\0') { | ||||
size_t len = strlen(afap->af_name) + 1; | size_t len = strlen(afap->af_name) + 1; | ||||
newaf->so_accept_filter_str = malloc(len, M_ACCF, | accept_filter_str = malloc(len, M_ACCF, M_WAITOK); | ||||
M_WAITOK); | strcpy(accept_filter_str, afap->af_name); | ||||
strcpy(newaf->so_accept_filter_str, afap->af_name); | |||||
} | } | ||||
/* | /* | ||||
* Require a listen socket; don't try to replace an existing filter | * Require a listen socket; don't try to replace an existing filter | ||||
* without first removing it. | * without first removing it. | ||||
*/ | */ | ||||
SOCK_LOCK(so); | SOCK_LOCK(so); | ||||
if (((so->so_options & SO_ACCEPTCONN) == 0) || | if ((so->so_options & SO_ACCEPTCONN) == 0 || | ||||
(so->so_accf != NULL)) { | so->sol_accept_filter != NULL) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
/* | /* | ||||
* Invoke the accf_create() method of the filter if required. The | * Invoke the accf_create() method of the filter if required. The | ||||
* socket mutex is held over this call, so create methods for filters | * socket mutex is held over this call, so create methods for filters | ||||
* can't block. | * can't block. | ||||
*/ | */ | ||||
if (afp->accf_create != NULL) { | if (afp->accf_create != NULL) { | ||||
newaf->so_accept_filter_arg = | accept_filter_arg = afp->accf_create(so, afap->af_arg); | ||||
afp->accf_create(so, afap->af_arg); | if (accept_filter_arg == NULL) { | ||||
if (newaf->so_accept_filter_arg == NULL) { | |||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
} | } | ||||
newaf->so_accept_filter = afp; | so->sol_accept_filter = afp; | ||||
so->so_accf = newaf; | so->sol_accept_filter_arg = accept_filter_arg; | ||||
so->so_options |= SO_ACCEPTFILTER; | so->sol_accept_filter_str = accept_filter_str; | ||||
newaf = NULL; | |||||
out: | out: | ||||
SOCK_UNLOCK(so); | SOCK_UNLOCK(so); | ||||
if (newaf != NULL) { | if (accept_filter_str != NULL) | ||||
if (newaf->so_accept_filter_str != NULL) | free(accept_filter_str, M_ACCF); | ||||
free(newaf->so_accept_filter_str, M_ACCF); | |||||
free(newaf, M_ACCF); | |||||
} | |||||
if (afap != NULL) | |||||
free(afap, M_TEMP); | free(afap, M_TEMP); | ||||
return (error); | return (error); | ||||
} | } |