source: rtems-libbsd/freebsd/kern/uipc_accf.c @ 508e3df

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 508e3df was 508e3df, checked in by Jennifer Averett <jennifer.averett@…>, on 04/05/12 at 19:13:24

Added uipc_XXx methods.

  • Property mode set to 100644
File size: 8.0 KB
Line 
1#include <freebsd/machine/rtems-bsd-config.h>
2
3/*-
4 * Copyright (c) 2000 Paycounter, Inc.
5 * Copyright (c) 2005 Robert N. M. Watson
6 * Author: Alfred Perlstein <alfred@paycounter.com>, <alfred@FreeBSD.org>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <freebsd/sys/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34#define ACCEPT_FILTER_MOD
35
36#include <freebsd/local/opt_param.h>
37#include <freebsd/sys/param.h>
38#include <freebsd/sys/systm.h>
39#include <freebsd/sys/domain.h>
40#include <freebsd/sys/kernel.h>
41#include <freebsd/sys/lock.h>
42#include <freebsd/sys/malloc.h>
43#include <freebsd/sys/mbuf.h>
44#include <freebsd/sys/module.h>
45#include <freebsd/sys/mutex.h>
46#include <freebsd/sys/protosw.h>
47#include <freebsd/sys/sysctl.h>
48#include <freebsd/sys/socket.h>
49#include <freebsd/sys/socketvar.h>
50#include <freebsd/sys/queue.h>
51
52static struct mtx accept_filter_mtx;
53MTX_SYSINIT(accept_filter, &accept_filter_mtx, "accept_filter_mtx",
54        MTX_DEF);
55#define ACCEPT_FILTER_LOCK()    mtx_lock(&accept_filter_mtx)
56#define ACCEPT_FILTER_UNLOCK()  mtx_unlock(&accept_filter_mtx)
57
58static SLIST_HEAD(, accept_filter) accept_filtlsthd =
59        SLIST_HEAD_INITIALIZER(accept_filtlsthd);
60
61MALLOC_DEFINE(M_ACCF, "accf", "accept filter data");
62
63static int unloadable = 0;
64
65SYSCTL_DECL(_net_inet); /* XXX: some header should do this for me */
66SYSCTL_NODE(_net_inet, OID_AUTO, accf, CTLFLAG_RW, 0, "Accept filters");
67SYSCTL_INT(_net_inet_accf, OID_AUTO, unloadable, CTLFLAG_RW, &unloadable, 0,
68        "Allow unload of accept filters (not recommended)");
69
70/*
71 * Must be passed a malloc'd structure so we don't explode if the kld is
72 * unloaded, we leak the struct on deallocation to deal with this, but if a
73 * filter is loaded with the same name as a leaked one we re-use the entry.
74 */
75int
76accept_filt_add(struct accept_filter *filt)
77{
78        struct accept_filter *p;
79
80        ACCEPT_FILTER_LOCK();
81        SLIST_FOREACH(p, &accept_filtlsthd, accf_next)
82                if (strcmp(p->accf_name, filt->accf_name) == 0)  {
83                        if (p->accf_callback != NULL) {
84                                ACCEPT_FILTER_UNLOCK();
85                                return (EEXIST);
86                        } else {
87                                p->accf_callback = filt->accf_callback;
88                                ACCEPT_FILTER_UNLOCK();
89                                free(filt, M_ACCF);
90                                return (0);
91                        }
92                }
93                               
94        if (p == NULL)
95                SLIST_INSERT_HEAD(&accept_filtlsthd, filt, accf_next);
96        ACCEPT_FILTER_UNLOCK();
97        return (0);
98}
99
100int
101accept_filt_del(char *name)
102{
103        struct accept_filter *p;
104
105        p = accept_filt_get(name);
106        if (p == NULL)
107                return (ENOENT);
108
109        p->accf_callback = NULL;
110        return (0);
111}
112
113struct accept_filter *
114accept_filt_get(char *name)
115{
116        struct accept_filter *p;
117
118        ACCEPT_FILTER_LOCK();
119        SLIST_FOREACH(p, &accept_filtlsthd, accf_next)
120                if (strcmp(p->accf_name, name) == 0)
121                        break;
122        ACCEPT_FILTER_UNLOCK();
123
124        return (p);
125}
126
127int
128accept_filt_generic_mod_event(module_t mod, int event, void *data)
129{
130        struct accept_filter *p;
131        struct accept_filter *accfp = (struct accept_filter *) data;
132        int error;
133
134        switch (event) {
135        case MOD_LOAD:
136                p = malloc(sizeof(*p), M_ACCF,
137                    M_WAITOK);
138                bcopy(accfp, p, sizeof(*p));
139                error = accept_filt_add(p);
140                break;
141
142        case MOD_UNLOAD:
143                /*
144                 * Do not support unloading yet. we don't keep track of
145                 * refcounts and unloading an accept filter callback and then
146                 * having it called is a bad thing.  A simple fix would be to
147                 * track the refcount in the struct accept_filter.
148                 */
149                if (unloadable != 0) {
150                        error = accept_filt_del(accfp->accf_name);
151                } else
152                        error = EOPNOTSUPP;
153                break;
154
155        case MOD_SHUTDOWN:
156                error = 0;
157                break;
158
159        default:
160                error = EOPNOTSUPP;
161                break;
162        }
163
164        return (error);
165}
166
167int
168do_getopt_accept_filter(struct socket *so, struct sockopt *sopt)
169{
170        struct accept_filter_arg *afap;
171        int error;
172
173        error = 0;
174        afap = malloc(sizeof(*afap), M_TEMP,
175            M_WAITOK | M_ZERO);
176        SOCK_LOCK(so);
177        if ((so->so_options & SO_ACCEPTCONN) == 0) {
178                error = EINVAL;
179                goto out;
180        }
181        if ((so->so_options & SO_ACCEPTFILTER) == 0) {
182                error = EINVAL;
183                goto out;
184        }
185        strcpy(afap->af_name, so->so_accf->so_accept_filter->accf_name);
186        if (so->so_accf->so_accept_filter_str != NULL)
187                strcpy(afap->af_arg, so->so_accf->so_accept_filter_str);
188out:
189        SOCK_UNLOCK(so);
190        if (error == 0)
191                error = sooptcopyout(sopt, afap, sizeof(*afap));
192        free(afap, M_TEMP);
193        return (error);
194}
195
196int
197do_setopt_accept_filter(struct socket *so, struct sockopt *sopt)
198{
199        struct accept_filter_arg *afap;
200        struct accept_filter *afp;
201        struct so_accf *newaf;
202        int error = 0;
203
204        /*
205         * Handle the simple delete case first.
206         */
207        if (sopt == NULL || sopt->sopt_val == NULL) {
208                SOCK_LOCK(so);
209                if ((so->so_options & SO_ACCEPTCONN) == 0) {
210                        SOCK_UNLOCK(so);
211                        return (EINVAL);
212                }
213                if (so->so_accf != NULL) {
214                        struct so_accf *af = so->so_accf;
215                        if (af->so_accept_filter != NULL &&
216                                af->so_accept_filter->accf_destroy != NULL) {
217                                af->so_accept_filter->accf_destroy(so);
218                        }
219                        if (af->so_accept_filter_str != NULL)
220                                free(af->so_accept_filter_str, M_ACCF);
221                        free(af, M_ACCF);
222                        so->so_accf = NULL;
223                }
224                so->so_options &= ~SO_ACCEPTFILTER;
225                SOCK_UNLOCK(so);
226                return (0);
227        }
228
229        /*
230         * Pre-allocate any memory we may need later to avoid blocking at
231         * untimely moments.  This does not optimize for invalid arguments.
232         */
233        afap = malloc(sizeof(*afap), M_TEMP,
234            M_WAITOK);
235        error = sooptcopyin(sopt, afap, sizeof *afap, sizeof *afap);
236        afap->af_name[sizeof(afap->af_name)-1] = '\0';
237        afap->af_arg[sizeof(afap->af_arg)-1] = '\0';
238        if (error) {
239                free(afap, M_TEMP);
240                return (error);
241        }
242        afp = accept_filt_get(afap->af_name);
243        if (afp == NULL) {
244                free(afap, M_TEMP);
245                return (ENOENT);
246        }
247        /*
248         * Allocate the new accept filter instance storage.  We may
249         * have to free it again later if we fail to attach it.  If
250         * attached properly, 'newaf' is NULLed to avoid a free()
251         * while in use.
252         */
253        newaf = malloc(sizeof(*newaf), M_ACCF, M_WAITOK |
254            M_ZERO);
255        if (afp->accf_create != NULL && afap->af_name[0] != '\0') {
256                int len = strlen(afap->af_name) + 1;
257                newaf->so_accept_filter_str = malloc(len, M_ACCF,
258                    M_WAITOK);
259                strcpy(newaf->so_accept_filter_str, afap->af_name);
260        }
261
262        /*
263         * Require a listen socket; don't try to replace an existing filter
264         * without first removing it.
265         */
266        SOCK_LOCK(so);
267        if (((so->so_options & SO_ACCEPTCONN) == 0) ||
268            (so->so_accf != NULL)) {
269                error = EINVAL;
270                goto out;
271        }
272
273        /*
274         * Invoke the accf_create() method of the filter if required.  The
275         * socket mutex is held over this call, so create methods for filters
276         * can't block.
277         */
278        if (afp->accf_create != NULL) {
279                newaf->so_accept_filter_arg =
280                    afp->accf_create(so, afap->af_arg);
281                if (newaf->so_accept_filter_arg == NULL) {
282                        error = EINVAL;
283                        goto out;
284                }
285        }
286        newaf->so_accept_filter = afp;
287        so->so_accf = newaf;
288        so->so_options |= SO_ACCEPTFILTER;
289        newaf = NULL;
290out:
291        SOCK_UNLOCK(so);
292        if (newaf != NULL) {
293                if (newaf->so_accept_filter_str != NULL)
294                        free(newaf->so_accept_filter_str, M_ACCF);
295                free(newaf, M_ACCF);
296        }
297        if (afap != NULL)
298                free(afap, M_TEMP);
299        return (error);
300}
Note: See TracBrowser for help on using the repository browser.