]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/uipc_domain.c
This commit was generated by cvs2svn to compensate for changes in r147021,
[FreeBSD/FreeBSD.git] / sys / kern / uipc_domain.c
1 /*-
2  * Copyright (c) 1982, 1986, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *      @(#)uipc_domain.c       8.2 (Berkeley) 10/18/93
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/socket.h>
37 #include <sys/protosw.h>
38 #include <sys/domain.h>
39 #include <sys/mbuf.h>
40 #include <sys/kernel.h>
41 #include <sys/lock.h>
42 #include <sys/mutex.h>
43 #include <sys/socketvar.h>
44 #include <sys/systm.h>
45 #include <vm/uma.h>
46
47 /*
48  * System initialization
49  *
50  * Note: domain initialization takes place on a per domain basis
51  * as a result of traversing a SYSINIT linker set.  Most likely,
52  * each domain would want to call DOMAIN_SET(9) itself, which
53  * would cause the domain to be added just after domaininit()
54  * is called during startup.
55  *
56  * See DOMAIN_SET(9) for details on its use.
57  */
58
59 static void domaininit(void *);
60 SYSINIT(domain, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, domaininit, NULL)
61
62 static void domainfinalize(void *);
63 SYSINIT(domainfin, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST, domainfinalize,
64     NULL)
65
66 static struct callout pffast_callout;
67 static struct callout pfslow_callout;
68
69 static void     pffasttimo(void *);
70 static void     pfslowtimo(void *);
71
72 struct domain *domains;         /* registered protocol domains */
73 int domain_init_status = 0;
74 struct mtx dom_mtx;             /* domain list lock */
75 MTX_SYSINIT(domain, &dom_mtx, "domain list", MTX_DEF);
76
77 /*
78  * Dummy protocol specific user requests function pointer array.
79  * All functions return EOPNOTSUPP.
80  */
81 struct pr_usrreqs nousrreqs = {
82         .pru_abort =            pru_abort_notsupp,
83         .pru_accept =           pru_accept_notsupp,
84         .pru_attach =           pru_attach_notsupp,
85         .pru_bind =             pru_bind_notsupp,
86         .pru_connect =          pru_connect_notsupp,
87         .pru_connect2 =         pru_connect2_notsupp,
88         .pru_control =          pru_control_notsupp,
89         .pru_detach =           pru_detach_notsupp,
90         .pru_disconnect =       pru_disconnect_notsupp,
91         .pru_listen =           pru_listen_notsupp,
92         .pru_peeraddr =         pru_peeraddr_notsupp,
93         .pru_rcvd =             pru_rcvd_notsupp,
94         .pru_rcvoob =           pru_rcvoob_notsupp,
95         .pru_send =             pru_send_notsupp,
96         .pru_sense =            pru_sense_null,
97         .pru_shutdown =         pru_shutdown_notsupp,
98         .pru_sockaddr =         pru_sockaddr_notsupp,
99         .pru_sosend =           pru_sosend_notsupp,
100         .pru_soreceive =        pru_soreceive_notsupp,
101         .pru_sopoll =           pru_sopoll_notsupp,
102         .pru_sosetlabel =       pru_sosetlabel_null
103 };
104
105 static void
106 protosw_init(struct protosw *pr)
107 {
108         struct pr_usrreqs *pu;
109
110         pu = pr->pr_usrreqs;
111         KASSERT(pu != NULL, ("protosw_init: %ssw[%d] has no usrreqs!",
112             pr->pr_domain->dom_name,
113             (int)(pr - pr->pr_domain->dom_protosw)));
114
115 #define DEFAULT(foo, bar)       if ((foo) == NULL)  (foo) = (bar)
116         DEFAULT(pu->pru_accept, pru_accept_notsupp);
117         DEFAULT(pu->pru_connect, pru_connect_notsupp);
118         DEFAULT(pu->pru_connect2, pru_connect2_notsupp);
119         DEFAULT(pu->pru_control, pru_control_notsupp);
120         DEFAULT(pu->pru_listen, pru_listen_notsupp);
121         DEFAULT(pu->pru_rcvd, pru_rcvd_notsupp);
122         DEFAULT(pu->pru_rcvoob, pru_rcvoob_notsupp);
123         DEFAULT(pu->pru_sense, pru_sense_null);
124         DEFAULT(pu->pru_sosend, sosend);
125         DEFAULT(pu->pru_soreceive, soreceive);
126         DEFAULT(pu->pru_sopoll, sopoll);
127         DEFAULT(pu->pru_sosetlabel, pru_sosetlabel_null);
128 #undef DEFAULT
129         if (pr->pr_init)
130                 (*pr->pr_init)();
131 }
132
133 /*
134  * Add a new protocol domain to the list of supported domains
135  * Note: you cant unload it again because a socket may be using it.
136  * XXX can't fail at this time.
137  */
138 static void
139 net_init_domain(struct domain *dp)
140 {
141         struct protosw *pr;
142
143         if (dp->dom_init)
144                 (*dp->dom_init)();
145         for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
146                 protosw_init(pr);
147         /*
148          * update global information about maximums
149          */
150         max_hdr = max_linkhdr + max_protohdr;
151         max_datalen = MHLEN - max_hdr;
152 }
153
154 /*
155  * Add a new protocol domain to the list of supported domains
156  * Note: you cant unload it again because a socket may be using it.
157  * XXX can't fail at this time.
158  */
159 void
160 net_add_domain(void *data)
161 {
162         struct domain *dp;
163
164         dp = (struct domain *)data;
165         mtx_lock(&dom_mtx);
166         dp->dom_next = domains;
167         domains = dp;
168
169         KASSERT(domain_init_status >= 1,
170             ("attempt to net_add_domain(%s) before domaininit()",
171             dp->dom_name));
172 #ifndef INVARIANTS
173         if (domain_init_status < 1)
174                 printf("WARNING: attempt to net_add_domain(%s) before "
175                     "domaininit()\n", dp->dom_name);
176 #endif
177 #ifdef notyet
178         KASSERT(domain_init_status < 2,
179             ("attempt to net_add_domain(%s) after domainfinalize()",
180             dp->dom_name));
181 #else
182         if (domain_init_status >= 2)
183                 printf("WARNING: attempt to net_add_domain(%s) after "
184                     "domainfinalize()\n", dp->dom_name);
185 #endif
186         mtx_unlock(&dom_mtx);
187         net_init_domain(dp);
188 }
189
190 /* ARGSUSED*/
191 static void
192 domaininit(void *dummy)
193 {
194         /*
195          * Before we do any setup, make sure to initialize the
196          * zone allocator we get struct sockets from.
197          */
198
199         socket_zone = uma_zcreate("socket", sizeof(struct socket), NULL, NULL,
200             NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
201         uma_zone_set_max(socket_zone, maxsockets);
202
203         if (max_linkhdr < 16)           /* XXX */
204                 max_linkhdr = 16;
205
206         if (debug_mpsafenet) {
207                 callout_init(&pffast_callout, CALLOUT_MPSAFE);
208                 callout_init(&pfslow_callout, CALLOUT_MPSAFE);
209         } else {
210                 callout_init(&pffast_callout, 0);
211                 callout_init(&pfslow_callout, 0);
212         }
213
214         mtx_lock(&dom_mtx);
215         KASSERT(domain_init_status == 0, ("domaininit called too late!"));
216         domain_init_status = 1;
217         mtx_unlock(&dom_mtx);
218 }
219
220 /* ARGSUSED*/
221 static void
222 domainfinalize(void *dummy)
223 {
224         mtx_lock(&dom_mtx);
225         KASSERT(domain_init_status == 1, ("domainfinalize called too late!"));
226         domain_init_status = 2;
227         mtx_unlock(&dom_mtx);   
228
229         callout_reset(&pffast_callout, 1, pffasttimo, NULL);
230         callout_reset(&pfslow_callout, 1, pfslowtimo, NULL);
231 }
232
233 struct protosw *
234 pffindtype(family, type)
235         int family;
236         int type;
237 {
238         register struct domain *dp;
239         register struct protosw *pr;
240
241         for (dp = domains; dp; dp = dp->dom_next)
242                 if (dp->dom_family == family)
243                         goto found;
244         return (0);
245 found:
246         for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
247                 if (pr->pr_type && pr->pr_type == type)
248                         return (pr);
249         return (0);
250 }
251
252 struct protosw *
253 pffindproto(family, protocol, type)
254         int family;
255         int protocol;
256         int type;
257 {
258         register struct domain *dp;
259         register struct protosw *pr;
260         struct protosw *maybe = 0;
261
262         if (family == 0)
263                 return (0);
264         for (dp = domains; dp; dp = dp->dom_next)
265                 if (dp->dom_family == family)
266                         goto found;
267         return (0);
268 found:
269         for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
270                 if ((pr->pr_protocol == protocol) && (pr->pr_type == type))
271                         return (pr);
272
273                 if (type == SOCK_RAW && pr->pr_type == SOCK_RAW &&
274                     pr->pr_protocol == 0 && maybe == (struct protosw *)0)
275                         maybe = pr;
276         }
277         return (maybe);
278 }
279
280 /*
281  * The caller must make sure that the new protocol is fully set up and ready to
282  * accept requests before it is registered.
283  */
284 int
285 pf_proto_register(family, npr)
286         int family;
287         struct protosw *npr;
288 {
289         struct domain *dp;
290         struct protosw *pr, *fpr;
291
292         /* Sanity checks. */
293         if (family == 0)
294                 return (EPFNOSUPPORT);
295         if (npr->pr_type == 0)
296                 return (EPROTOTYPE);
297         if (npr->pr_protocol == 0)
298                 return (EPROTONOSUPPORT);
299         if (npr->pr_usrreqs == NULL)
300                 return (ENXIO);
301
302         /* Try to find the specified domain based on the family. */
303         for (dp = domains; dp; dp = dp->dom_next)
304                 if (dp->dom_family == family)
305                         goto found;
306         return (EPFNOSUPPORT);
307
308 found:
309         /* Initialize backpointer to struct domain. */
310         npr->pr_domain = dp;
311         fpr = NULL;
312
313         /*
314          * Protect us against races when two protocol registrations for
315          * the same protocol happen at the same time.
316          */
317         mtx_lock(&Giant);
318
319         /* The new protocol must not yet exist. */
320         for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
321                 if ((pr->pr_type == npr->pr_type) &&
322                     (pr->pr_protocol == npr->pr_protocol)) {
323                         mtx_unlock(&Giant);
324                         return (EEXIST);        /* XXX: Check only protocol? */
325                 }
326                 /* While here, remember the first free spacer. */
327                 if ((fpr == NULL) && (pr->pr_protocol == PROTO_SPACER))
328                         fpr = pr;
329         }
330
331         /* If no free spacer is found we can't add the new protocol. */
332         if (fpr == NULL) {
333                 mtx_unlock(&Giant);
334                 return (ENOMEM);
335         }
336
337         /* Copy the new struct protosw over the spacer. */
338         bcopy(npr, fpr, sizeof(*fpr));
339
340         /* Job is done, no more protection required. */
341         mtx_unlock(&Giant);
342
343         /* Initialize and activate the protocol. */
344         protosw_init(fpr);
345
346         return (0);
347 }
348
349 /*
350  * The caller must make sure the protocol and its functions correctly shut down
351  * all sockets and release all locks and memory references.
352  */
353 int
354 pf_proto_unregister(family, protocol, type)
355         int family;
356         int protocol;
357         int type;
358 {
359         struct domain *dp;
360         struct protosw *pr, *dpr;
361
362         /* Sanity checks. */
363         if (family == 0)
364                 return (EPFNOSUPPORT);
365         if (protocol == 0)
366                 return (EPROTONOSUPPORT);
367         if (type == 0)
368                 return (EPROTOTYPE);
369
370         /* Try to find the specified domain based on the family type. */
371         for (dp = domains; dp; dp = dp->dom_next)
372                 if (dp->dom_family == family)
373                         goto found;
374         return (EPFNOSUPPORT);
375
376 found:
377         dpr = NULL;
378
379         /* Lock out everyone else while we are manipulating the protosw. */
380         mtx_lock(&Giant);
381
382         /* The protocol must exist and only once. */
383         for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
384                 if ((pr->pr_type == type) && (pr->pr_protocol == protocol)) {
385                         if (dpr != NULL) {
386                                 mtx_unlock(&Giant);
387                                 return (EMLINK);   /* Should not happen! */
388                         } else
389                                 dpr = pr;
390                 }
391         }
392
393         /* Protocol does not exist. */
394         if (dpr == NULL) {
395                 mtx_unlock(&Giant);
396                 return (EPROTONOSUPPORT);
397         }
398
399         /* De-orbit the protocol and make the slot available again. */
400         dpr->pr_type = 0;
401         dpr->pr_domain = dp;
402         dpr->pr_protocol = PROTO_SPACER;
403         dpr->pr_flags = 0;
404         dpr->pr_input = NULL;
405         dpr->pr_output = NULL;
406         dpr->pr_ctlinput = NULL;
407         dpr->pr_ctloutput = NULL;
408         dpr->pr_ousrreq = NULL;
409         dpr->pr_init = NULL;
410         dpr->pr_fasttimo = NULL;
411         dpr->pr_slowtimo = NULL;
412         dpr->pr_drain = NULL;
413         dpr->pr_usrreqs = &nousrreqs;
414
415         /* Job is done, not more protection required. */
416         mtx_unlock(&Giant);
417
418         return (0);
419 }
420
421 void
422 pfctlinput(cmd, sa)
423         int cmd;
424         struct sockaddr *sa;
425 {
426         register struct domain *dp;
427         register struct protosw *pr;
428
429         for (dp = domains; dp; dp = dp->dom_next)
430                 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
431                         if (pr->pr_ctlinput)
432                                 (*pr->pr_ctlinput)(cmd, sa, (void *)0);
433 }
434
435 void
436 pfctlinput2(cmd, sa, ctlparam)
437         int cmd;
438         struct sockaddr *sa;
439         void *ctlparam;
440 {
441         struct domain *dp;
442         struct protosw *pr;
443
444         if (!sa)
445                 return;
446         for (dp = domains; dp; dp = dp->dom_next) {
447                 /*
448                  * the check must be made by xx_ctlinput() anyways, to
449                  * make sure we use data item pointed to by ctlparam in
450                  * correct way.  the following check is made just for safety.
451                  */
452                 if (dp->dom_family != sa->sa_family)
453                         continue;
454
455                 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
456                         if (pr->pr_ctlinput)
457                                 (*pr->pr_ctlinput)(cmd, sa, ctlparam);
458         }
459 }
460
461 static void
462 pfslowtimo(arg)
463         void *arg;
464 {
465         register struct domain *dp;
466         register struct protosw *pr;
467
468         NET_ASSERT_GIANT();
469
470         for (dp = domains; dp; dp = dp->dom_next)
471                 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
472                         if (pr->pr_slowtimo)
473                                 (*pr->pr_slowtimo)();
474         callout_reset(&pfslow_callout, hz/2, pfslowtimo, NULL);
475 }
476
477 static void
478 pffasttimo(arg)
479         void *arg;
480 {
481         register struct domain *dp;
482         register struct protosw *pr;
483
484         NET_ASSERT_GIANT();
485
486         for (dp = domains; dp; dp = dp->dom_next)
487                 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
488                         if (pr->pr_fasttimo)
489                                 (*pr->pr_fasttimo)();
490         callout_reset(&pffast_callout, hz/5, pffasttimo, NULL);
491 }