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