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