]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/uipc_domain.c
9bf1001f4549ba1915abb3d6947822e980079fe5
[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
269 domain_proto_mtx_grp = lck_grp_alloc_init("domain", domain_proto_mtx_grp_attr);
270
271 /*
272 * allocate the lock attribute for per domain mutexes
273 */
274 domain_proto_mtx_attr = lck_attr_alloc_init();
275
276 if ((domain_proto_mtx = lck_mtx_alloc_init(domain_proto_mtx_grp, domain_proto_mtx_attr)) == NULL) {
277 printf("domaininit: can't init domain mtx for domain list\n");
278 return; /* we have a problem... */
279 }
280 /*
281 * Add all the static domains to the domains list
282 */
283
284 lck_mtx_lock(domain_proto_mtx);
285
286 concat_domain(&localdomain);
287 concat_domain(&routedomain);
288 concat_domain(&inetdomain);
289 #if NETAT
290 concat_domain(&atalkdomain);
291 #endif
292 #if INET6
293 concat_domain(&inet6domain);
294 #endif
295 #if IPSEC
296 concat_domain(&keydomain);
297 #endif
298
299 #if NS
300 concat_domain(&nsdomain);
301 #endif
302 #if ISO
303 concat_domain(&isodomain);
304 #endif
305 #if CCITT
306 concat_domain(&ccittdomain);
307 #endif
308 concat_domain(&ndrvdomain);
309
310 concat_domain(&systemdomain);
311
312 /*
313 * Now ask them all to init (XXX including the routing domain,
314 * see above)
315 */
316 for (dp = domains; dp; dp = dp->dom_next)
317 init_domain(dp);
318
319 lck_mtx_unlock(domain_proto_mtx);
320 timeout(pffasttimo, NULL, 1);
321 timeout(pfslowtimo, NULL, 1);
322 }
323
324 struct protosw *
325 pffindtype(family, type)
326 int family, type;
327 {
328 register struct domain *dp;
329 register struct protosw *pr;
330
331 lck_mtx_assert(domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
332 lck_mtx_lock(domain_proto_mtx);
333 for (dp = domains; dp; dp = dp->dom_next)
334 if (dp->dom_family == family)
335 goto found;
336 lck_mtx_unlock(domain_proto_mtx);
337 return (0);
338 found:
339 for (pr = dp->dom_protosw; pr; pr = pr->pr_next)
340 if (pr->pr_type && pr->pr_type == type) {
341 lck_mtx_unlock(domain_proto_mtx);
342 return (pr);
343 }
344 lck_mtx_unlock(domain_proto_mtx);
345 return (0);
346 }
347
348 struct domain *
349 pffinddomain(int pf)
350 { struct domain *dp;
351
352 lck_mtx_assert(domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
353 lck_mtx_lock(domain_proto_mtx);
354 dp = domains;
355 while (dp)
356 { if (dp->dom_family == pf) {
357 lck_mtx_unlock(domain_proto_mtx);
358 return(dp);
359 }
360 dp = dp->dom_next;
361 }
362 lck_mtx_unlock(domain_proto_mtx);
363 return(NULL);
364 }
365
366 struct protosw *
367 pffindproto(family, protocol, type)
368 int family, protocol, type;
369 {
370 register struct protosw *pr;
371 lck_mtx_assert(domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
372 lck_mtx_lock(domain_proto_mtx);
373 pr = pffindproto_locked(family, protocol, type);
374 lck_mtx_unlock(domain_proto_mtx);
375 return (pr);
376 }
377
378 struct protosw *
379 pffindproto_locked(family, protocol, type)
380 int family, protocol, type;
381 {
382 register struct domain *dp;
383 register struct protosw *pr;
384 struct protosw *maybe = 0;
385
386 if (family == 0)
387 return (0);
388 for (dp = domains; dp; dp = dp->dom_next)
389 if (dp->dom_family == family)
390 goto found;
391 return (0);
392 found:
393 for (pr = dp->dom_protosw; pr; pr = pr->pr_next) {
394 if ((pr->pr_protocol == protocol) && (pr->pr_type == type))
395 return (pr);
396
397 if (type == SOCK_RAW && pr->pr_type == SOCK_RAW &&
398 pr->pr_protocol == 0 && maybe == (struct protosw *)0)
399 maybe = pr;
400 }
401 return (maybe);
402 }
403
404 int
405 net_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
406 user_addr_t newp, size_t newlen, struct proc *p)
407 {
408 register struct domain *dp;
409 register struct protosw *pr;
410 int family, protocol, error;
411
412 /*
413 * All sysctl names at this level are nonterminal;
414 * next two components are protocol family and protocol number,
415 * then at least one addition component.
416 */
417 if (namelen < 3)
418 return (EISDIR); /* overloaded */
419 family = name[0];
420 protocol = name[1];
421
422 if (family == 0)
423 return (0);
424 lck_mtx_lock(domain_proto_mtx);
425 for (dp = domains; dp; dp = dp->dom_next)
426 if (dp->dom_family == family)
427 goto found;
428 lck_mtx_unlock(domain_proto_mtx);
429 return (ENOPROTOOPT);
430 found:
431 for (pr = dp->dom_protosw; pr; pr = pr->pr_next)
432 if (pr->pr_protocol == protocol && pr->pr_sysctl) {
433 error = (*pr->pr_sysctl)(name + 2, namelen - 2,
434 oldp, oldlenp, newp, newlen);
435 lck_mtx_unlock(domain_proto_mtx);
436 return (error);
437 }
438 lck_mtx_unlock(domain_proto_mtx);
439 return (ENOPROTOOPT);
440 }
441
442 void
443 pfctlinput(cmd, sa)
444 int cmd;
445 struct sockaddr *sa;
446 {
447 pfctlinput2(cmd, sa, (void*)0);
448 }
449
450 void
451 pfctlinput2(cmd, sa, ctlparam)
452 int cmd;
453 struct sockaddr *sa;
454 void *ctlparam;
455 {
456 struct domain *dp;
457 struct protosw *pr;
458
459 if (!sa)
460 return;
461
462 lck_mtx_lock(domain_proto_mtx);
463 for (dp = domains; dp; dp = dp->dom_next)
464 for (pr = dp->dom_protosw; pr; pr = pr->pr_next)
465 if (pr->pr_ctlinput)
466 (*pr->pr_ctlinput)(cmd, sa, ctlparam);
467 lck_mtx_unlock(domain_proto_mtx);
468 }
469
470 void
471 pfslowtimo(arg)
472 void *arg;
473 {
474 register struct domain *dp;
475 register struct protosw *pr;
476
477 lck_mtx_lock(domain_proto_mtx);
478 for (dp = domains; dp; dp = dp->dom_next)
479 for (pr = dp->dom_protosw; pr; pr = pr->pr_next) {
480 if (pr->pr_slowtimo)
481 (*pr->pr_slowtimo)();
482 if (do_reclaim && pr->pr_drain)
483 (*pr->pr_drain)();
484 }
485 do_reclaim = 0;
486 lck_mtx_unlock(domain_proto_mtx);
487 timeout(pfslowtimo, NULL, hz/2);
488
489 }
490
491 void
492 pffasttimo(arg)
493 void *arg;
494 {
495 register struct domain *dp;
496 register struct protosw *pr;
497
498 lck_mtx_lock(domain_proto_mtx);
499 for (dp = domains; dp; dp = dp->dom_next)
500 for (pr = dp->dom_protosw; pr; pr = pr->pr_next)
501 if (pr->pr_fasttimo)
502 (*pr->pr_fasttimo)();
503 lck_mtx_unlock(domain_proto_mtx);
504 timeout(pffasttimo, NULL, hz/5);
505 }