| 192 | } |
| 193 | |
| 194 | int |
| 195 | accept_filt_setopt(struct socket *so, struct sockopt *sopt) |
| 196 | { |
| 197 | struct accept_filter_arg *afap; |
| 198 | struct accept_filter *afp; |
| 199 | char *accept_filter_str = NULL; |
| 200 | void *accept_filter_arg = NULL; |
| 201 | int error; |
| 202 | |
| 203 | /* |
| 204 | * Handle the simple delete case first. |
| 205 | */ |
| 206 | if (sopt == NULL || sopt->sopt_val == NULL) { |
| 207 | struct socket *sp, *sp1; |
| 208 | int wakeup; |
| 209 | |
| 210 | SOCK_LOCK(so); |
| 211 | if ((so->so_options & SO_ACCEPTCONN) == 0) { |
| 212 | SOCK_UNLOCK(so); |
| 213 | return (EINVAL); |
| 214 | } |
| 215 | if (so->sol_accept_filter == NULL) { |
| 216 | SOCK_UNLOCK(so); |
| 217 | return (0); |
| 218 | } |
| 219 | if (so->sol_accept_filter->accf_destroy != NULL) |
| 220 | so->sol_accept_filter->accf_destroy(so); |
| 221 | if (so->sol_accept_filter_str != NULL) |
| 222 | free(so->sol_accept_filter_str, M_ACCF); |
| 223 | so->sol_accept_filter = NULL; |
| 224 | so->sol_accept_filter_arg = NULL; |
| 225 | so->sol_accept_filter_str = NULL; |
| 226 | so->so_options &= ~SO_ACCEPTFILTER; |
| 227 | |
| 228 | /* |
| 229 | * Move from incomplete queue to complete only those |
| 230 | * connections, that are blocked by us. |
| 231 | */ |
| 232 | wakeup = 0; |
| 233 | TAILQ_FOREACH_SAFE(sp, &so->sol_incomp, so_list, sp1) { |
| 234 | SOCK_LOCK(sp); |
| 235 | if (sp->so_options & SO_ACCEPTFILTER) { |
| 236 | TAILQ_REMOVE(&so->sol_incomp, sp, so_list); |
| 237 | TAILQ_INSERT_TAIL(&so->sol_comp, sp, so_list); |
| 238 | sp->so_qstate = SQ_COMP; |
| 239 | sp->so_options &= ~SO_ACCEPTFILTER; |
| 240 | so->sol_incqlen--; |
| 241 | so->sol_qlen++; |
| 242 | wakeup = 1; |
| 243 | } |
| 244 | SOCK_UNLOCK(sp); |
| 245 | } |
| 246 | if (wakeup) |
| 247 | solisten_wakeup(so); /* unlocks */ |
| 248 | else |
| 249 | SOLISTEN_UNLOCK(so); |
| 250 | return (0); |
| 251 | } |
no test coverage detected