]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/uipc_domain.c
e01929374f3e85db53d38f4f6a869f7d22e607ef
[apple/xnu.git] / bsd / kern / uipc_domain.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /* Copyright (c) 1998, 1999 Apple Computer, Inc. All Rights Reserved */
29 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
30 /*
31 * Copyright (c) 1982, 1986, 1993
32 * The Regents of the University of California. All rights reserved.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 * 3. All advertising materials mentioning features or use of this software
43 * must display the following acknowledgement:
44 * This product includes software developed by the University of
45 * California, Berkeley and its contributors.
46 * 4. Neither the name of the University nor the names of its contributors
47 * may be used to endorse or promote products derived from this software
48 * without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 *
62 * @(#)uipc_domain.c 8.3 (Berkeley) 2/14/95
63 */
64
65 #include <sys/param.h>
66 #include <sys/socket.h>
67 #include <sys/protosw.h>
68 #include <sys/domain.h>
69 #include <sys/mbuf.h>
70 #include <sys/time.h>
71 #include <sys/kernel.h>
72 #include <sys/systm.h>
73 #include <sys/proc_internal.h>
74 #include <sys/sysctl.h>
75 #include <sys/syslog.h>
76 #include <sys/queue.h>
77
78 void pffasttimo(void *);
79 void pfslowtimo(void *);
80
81 /*
82 * Add/delete 'domain': Link structure into system list,
83 * invoke the domain init, and then the proto inits.
84 * To delete, just remove from the list (dom_refs must be zero)
85 */
86
87 lck_grp_t *domain_proto_mtx_grp;
88 lck_attr_t *domain_proto_mtx_attr;
89 static lck_grp_attr_t *domain_proto_mtx_grp_attr;
90 lck_mtx_t *domain_proto_mtx;
91 extern int do_reclaim;
92
93 void init_domain(register struct domain *dp)
94 {
95 struct protosw *pr;
96
97 if ((dp->dom_mtx = lck_mtx_alloc_init(domain_proto_mtx_grp, domain_proto_mtx_attr)) == NULL) {
98 printf("init_domain: can't init domain mtx for domain=%s\n", dp->dom_name);
99 return; /* we have a problem... */
100 }
101
102 if (dp->dom_init)
103 (*dp->dom_init)();
104
105 /* and then init the currently installed protos in this domain */
106
107 for (pr = dp->dom_protosw; pr; pr = pr->pr_next) {
108 if (pr->pr_usrreqs == 0)
109 panic("domaininit: %ssw[%d] has no usrreqs!",
110 dp->dom_name,
111 (int)(pr - dp->dom_protosw));
112
113 if (pr->pr_init)
114 (*pr->pr_init)();
115 }
116
117 /* Recompute for new protocol */
118 if (max_linkhdr < 16) /* XXX - Sheesh; everything's ether? */
119 max_linkhdr = 16;
120 if (dp->dom_protohdrlen > max_protohdr)
121 max_protohdr = dp->dom_protohdrlen;
122 max_hdr = max_linkhdr + max_protohdr;
123 max_datalen = MHLEN - max_hdr;
124 }
125
126 void concat_domain(struct domain *dp)
127 {
128 lck_mtx_assert(domain_proto_mtx, LCK_MTX_ASSERT_OWNED);
129 dp->dom_next = domains;
130 domains = dp;
131 }
132
133 void
134 net_add_domain(register struct domain *dp)
135 { register struct protosw *pr;
136
137 kprintf("Adding domain %s (family %d)\n", dp->dom_name,
138 dp->dom_family);
139 /* First, link in the domain */
140
141 lck_mtx_lock(domain_proto_mtx);
142 concat_domain(dp);
143
144 init_domain(dp);
145 lck_mtx_unlock(domain_proto_mtx);
146
147 }
148
149 int
150 net_del_domain(register struct domain *dp)
151 { register struct domain *dp1, *dp2;
152 register int retval = 0;
153
154 lck_mtx_lock(domain_proto_mtx);
155
156 if (dp->dom_refs) {
157 lck_mtx_unlock(domain_proto_mtx);
158 return(EBUSY);
159 }
160
161 for (dp2 = NULL, dp1 = domains; dp1; dp2 = dp1, dp1 = dp1->dom_next)
162 { if (dp == dp1)
163 break;
164 }
165 if (dp1)
166 { if (dp2)
167 dp2->dom_next = dp1->dom_next;
168 else
169 domains = dp1->dom_next;
170 } else
171 retval = EPFNOSUPPORT;
172 lck_mtx_unlock(domain_proto_mtx);
173
174 return(retval);
175 }
176
177 /*
178 * net_add_proto - link a protosw into a domain's protosw chain
179 *
180 * note: protocols must use their own domain lock before calling net_add_proto
181 */
182 int
183 net_add_proto(register struct protosw *pp,
184 register struct domain *dp)
185 { register struct protosw *pp1, *pp2;
186
187 for (pp2 = NULL, pp1 = dp->dom_protosw; pp1; pp1 = pp1->pr_next)
188 { if (pp1->pr_type == pp->pr_type &&
189 pp1->pr_protocol == pp->pr_protocol) {
190 return(EEXIST);
191 }
192 pp2 = pp1;
193 }
194 if (pp2 == NULL)
195 dp->dom_protosw = pp;
196 else
197 pp2->pr_next = pp;
198 pp->pr_next = NULL;
199 TAILQ_INIT(&pp->pr_filter_head);
200 if (pp->pr_init)
201 (*pp->pr_init)();
202
203 /* Make sure pr_init isn't called again!! */
204 pp->pr_init = 0;
205 return(0);
206 }
207
208 /*
209 * net_del_proto - remove a protosw from a domain's protosw chain.
210 * Search the protosw chain for the element with matching data.
211 * Then unlink and return.
212 *
213 * note: protocols must use their own domain lock before calling net_del_proto
214 */
215 int
216 net_del_proto(register int type,
217 register int protocol,
218 register struct domain *dp)
219 { register struct protosw *pp1, *pp2;
220
221 for (pp2 = NULL, pp1 = dp->dom_protosw; pp1; pp1 = pp1->pr_next)
222 { if (pp1->pr_type == type &&
223 pp1->pr_protocol == protocol)
224 break;
225 pp2 = pp1;
226 }
227 if (pp1 == NULL) {
228 return(ENXIO);
229 }
230 if (pp2)
231 pp2->pr_next = pp1->pr_next;
232 else
233 dp->dom_protosw = pp1->pr_next;
234 return(0);
235 }
236
237
238 void
239 domaininit()
240 { register struct domain *dp;
241 register struct protosw *pr;
242 extern struct domain localdomain, routedomain, ndrvdomain, inetdomain;
243 extern struct domain systemdomain;
244 #if NS
245 extern struct domain nsdomain;
246 #endif
247 #if ISO
248 extern struct domain isodomain;
249 #endif
250 #if CCITT
251 extern struct domain ccittdomain;
252 #endif
253
254 #if NETAT
255 extern struct domain atalkdomain;
256 #endif
257 #if INET6
258 extern struct domain inet6domain;
259 #endif
260 #if IPSEC
261 extern struct domain keydomain;
262 #endif
263
264 /*
265 * allocate lock group attribute and group for domain mutexes
266 */
267 domain_proto_mtx_grp_attr = lck_grp_attr_alloc_init();
268 lck_grp_attr_setdefault(domain_proto_mtx_grp_attr);
269
270 domain_proto_mtx_grp = lck_grp_alloc_init("domain", domain_proto_mtx_grp_attr);
271
272 /*
273 * allocate the lock attribute for per domain mutexes
274 */
275 domain_proto_mtx_attr = lck_attr_alloc_init();
276 lck_attr_setdefault(domain_proto_mtx_attr);
277
278 if ((domain_proto_mtx = lck_mtx_alloc_init(domain_proto_mtx_grp, domain_proto_mtx_attr)) == NULL) {
279 printf("domaininit: can't init domain mtx for domain list\n");
280 return; /* we have a problem... */
281 }
282 /*
283 * Add all the static domains to the domains list
284 */
285
286 lck_mtx_lock(domain_proto_mtx);
287
288 concat_domain(&localdomain);
289 concat_domain(&routedomain);
290 concat_domain(&inetdomain);
291 #if NETAT
292 concat_domain(&atalkdomain);
293 #endif
294 #if INET6
295 concat_domain(&inet6domain);
296 #endif
297 #if IPSEC
298 concat_domain(&keydomain);
299 #endif
300
301 #if NS
302 concat_domain(&nsdomain);
303 #endif
304 #if ISO
305 concat_domain(&isodomain);
306 #endif
307 #if CCITT
308 concat_domain(&ccittdomain);
309 #endif
310 concat_domain(&ndrvdomain);
311
312 concat_domain(&systemdomain);
313
314 /*
315 * Now ask them all to init (XXX including the routing domain,
316 * see above)
317 */
318 for (dp = domains; dp; dp = dp->dom_next)
319 init_domain(dp);
320
321 lck_mtx_unlock(domain_proto_mtx);
322 timeout(pffasttimo, NULL, 1);
323 timeout(pfslowtimo, NULL, 1);
324 }
325
326 struct protosw *
327 pffindtype(family, type)
328 int family, type;
329 {
330 register struct domain *dp;
331 register struct protosw *pr;
332
333 lck_mtx_assert(domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
334 lck_mtx_lock(domain_proto_mtx);
335 for (dp = domains; dp; dp = dp->dom_next)
336 if (dp->dom_family == family)
337 goto found;
338 lck_mtx_unlock(domain_proto_mtx);
339 return (0);
340 found:
341 for (pr = dp->dom_protosw; pr; pr = pr->pr_next)
342 if (pr->pr_type && pr->pr_type == type) {
343 lck_mtx_unlock(domain_proto_mtx);
344 return (pr);
345 }
346 lck_mtx_unlock(domain_proto_mtx);
347 return (0);
348 }
349
350 struct domain *
351 pffinddomain(int pf)
352 { struct domain *dp;
353
354 lck_mtx_assert(domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
355 lck_mtx_lock(domain_proto_mtx);
356 dp = domains;
357 while (dp)
358 { if (dp->dom_family == pf) {
359 lck_mtx_unlock(domain_proto_mtx);
360 return(dp);
361 }
362 dp = dp->dom_next;
363 }
364 lck_mtx_unlock(domain_proto_mtx);
365 return(NULL);
366 }
367
368 struct protosw *
369 pffindproto(family, protocol, type)
370 int family, protocol, type;
371 {
372 register struct protosw *pr;
373 lck_mtx_assert(domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
374 lck_mtx_lock(domain_proto_mtx);
375 pr = pffindproto_locked(family, protocol, type);
376 lck_mtx_unlock(domain_proto_mtx);
377 return (pr);
378 }
379
380 struct protosw *
381 pffindproto_locked(family, protocol, type)
382 int family, protocol, type;
383 {
384 register struct domain *dp;
385 register struct protosw *pr;
386 struct protosw *maybe = 0;
387
388 if (family == 0)
389 return (0);
390 for (dp = domains; dp; dp = dp->dom_next)
391 if (dp->dom_family == family)
392 goto found;
393 return (0);
394 found:
395 for (pr = dp->dom_protosw; pr; pr = pr->pr_next) {
396 if ((pr->pr_protocol == protocol) && (pr->pr_type == type))
397 return (pr);
398
399 if (type == SOCK_RAW && pr->pr_type == SOCK_RAW &&
400 pr->pr_protocol == 0 && maybe == (struct protosw *)0)
401 maybe = pr;
402 }
403 return (maybe);
404 }
405
406 int
407 net_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
408 user_addr_t newp, size_t newlen, struct proc *p)
409 {
410 register struct domain *dp;
411 register struct protosw *pr;
412 int family, protocol, error;
413
414 /*
415 * All sysctl names at this level are nonterminal;
416 * next two components are protocol family and protocol number,
417 * then at least one addition component.
418 */
419 if (namelen < 3)
420 return (EISDIR); /* overloaded */
421 family = name[0];
422 protocol = name[1];
423
424 if (family == 0)
425 return (0);
426 lck_mtx_lock(domain_proto_mtx);
427 for (dp = domains; dp; dp = dp->dom_next)
428 if (dp->dom_family == family)
429 goto found;
430 lck_mtx_unlock(domain_proto_mtx);
431 return (ENOPROTOOPT);
432 found:
433 for (pr = dp->dom_protosw; pr; pr = pr->pr_next)
434 if (pr->pr_protocol == protocol && pr->pr_sysctl) {
435 error = (*pr->pr_sysctl)(name + 2, namelen - 2,
436 oldp, oldlenp, newp, newlen);
437 lck_mtx_unlock(domain_proto_mtx);
438 return (error);
439 }
440 lck_mtx_unlock(domain_proto_mtx);
441 return (ENOPROTOOPT);
442 }
443
444 void
445 pfctlinput(cmd, sa)
446 int cmd;
447 struct sockaddr *sa;
448 {
449 pfctlinput2(cmd, sa, (void*)0);
450 }
451
452 void
453 pfctlinput2(cmd, sa, ctlparam)
454 int cmd;
455 struct sockaddr *sa;
456 void *ctlparam;
457 {
458 struct domain *dp;
459 struct protosw *pr;
460
461 if (!sa)
462 return;
463
464 lck_mtx_lock(domain_proto_mtx);
465 for (dp = domains; dp; dp = dp->dom_next)
466 for (pr = dp->dom_protosw; pr; pr = pr->pr_next)
467 if (pr->pr_ctlinput)
468 (*pr->pr_ctlinput)(cmd, sa, ctlparam);
469 lck_mtx_unlock(domain_proto_mtx);
470 }
471
472 void
473 pfslowtimo(arg)
474 void *arg;
475 {
476 register struct domain *dp;
477 register struct protosw *pr;
478
479 lck_mtx_lock(domain_proto_mtx);
480 for (dp = domains; dp; dp = dp->dom_next)
481 for (pr = dp->dom_protosw; pr; pr = pr->pr_next) {
482 if (pr->pr_slowtimo)
483 (*pr->pr_slowtimo)();
484 if (do_reclaim && pr->pr_drain)
485 (*pr->pr_drain)();
486 }
487 do_reclaim = 0;
488 lck_mtx_unlock(domain_proto_mtx);
489 timeout(pfslowtimo, NULL, hz/2);
490
491 }
492
493 void
494 pffasttimo(arg)
495 void *arg;
496 {
497 register struct domain *dp;
498 register struct protosw *pr;
499
500 lck_mtx_lock(domain_proto_mtx);
501 for (dp = domains; dp; dp = dp->dom_next)
502 for (pr = dp->dom_protosw; pr; pr = pr->pr_next)
503 if (pr->pr_fasttimo)
504 (*pr->pr_fasttimo)();
505 lck_mtx_unlock(domain_proto_mtx);
506 timeout(pffasttimo, NULL, hz/5);
507 }