]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/kern/uipc_domain.c
xnu-2422.90.20.tar.gz
[apple/xnu.git] / bsd / kern / uipc_domain.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1998-2013 Apple 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) 1995 NeXT Computer, Inc. All Rights Reserved */
29/*
30 * Copyright (c) 1982, 1986, 1993
31 * The Regents of the University of California. All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 *
61 * @(#)uipc_domain.c 8.3 (Berkeley) 2/14/95
62 */
63
64#include <sys/param.h>
65#include <sys/socket.h>
66#include <sys/protosw.h>
67#include <sys/domain.h>
68#include <sys/mcache.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#include <net/dlil.h>
79
80#include <mach/boolean.h>
81#include <pexpert/pexpert.h>
82
83static void pr_init_old(struct protosw *, struct domain *);
84static void init_proto(struct protosw *, struct domain *);
85static void attach_proto(struct protosw *, struct domain *);
86static void detach_proto(struct protosw *, struct domain *);
87static void dom_init_old(struct domain *);
88static void init_domain(struct domain *);
89static void attach_domain(struct domain *);
90static void detach_domain(struct domain *);
91static struct protosw *pffindprotonotype_locked(int, int, int);
92static struct domain *pffinddomain_locked(int);
93
94static boolean_t domain_timeout_run; /* domain timer is scheduled to run */
95static boolean_t domain_draining;
96static void domain_sched_timeout(void);
97static void domain_timeout(void *);
98
99lck_grp_t *domain_proto_mtx_grp;
100lck_attr_t *domain_proto_mtx_attr;
101static lck_grp_attr_t *domain_proto_mtx_grp_attr;
102decl_lck_mtx_data(static, domain_proto_mtx);
103decl_lck_mtx_data(static, domain_timeout_mtx);
104
105extern sysctlfn net_sysctl;
106
107static u_int64_t _net_uptime;
108
109static void
110pr_init_old(struct protosw *pp, struct domain *dp)
111{
112#pragma unused(dp)
113 VERIFY(pp->pr_flags & PR_OLD);
114 VERIFY(pp->pr_old != NULL);
115
116 if (pp->pr_old->pr_init != NULL)
117 pp->pr_old->pr_init();
118}
119
120static void
121init_proto(struct protosw *pp, struct domain *dp)
122{
123 VERIFY(pp->pr_flags & PR_ATTACHED);
124
125 if (!(pp->pr_flags & PR_INITIALIZED)) {
126 TAILQ_INIT(&pp->pr_filter_head);
127 if (pp->pr_init != NULL)
128 pp->pr_init(pp, dp);
129 pp->pr_flags |= PR_INITIALIZED;
130 }
131}
132
133static void
134attach_proto(struct protosw *pp, struct domain *dp)
135{
136 domain_proto_mtx_lock_assert_held();
137 VERIFY(!(pp->pr_flags & PR_ATTACHED));
138 VERIFY(pp->pr_domain == NULL);
139 VERIFY(pp->pr_protosw == NULL);
140
141 TAILQ_INSERT_TAIL(&dp->dom_protosw, pp, pr_entry);
142 pp->pr_flags |= PR_ATTACHED;
143 pp->pr_domain = dp;
144 pp->pr_protosw = pp;
145
146 /* do some cleaning up on user request callbacks */
147 pru_sanitize(pp->pr_usrreqs);
148}
149
150static void
151detach_proto(struct protosw *pp, struct domain *dp)
152{
153 domain_proto_mtx_lock_assert_held();
154 VERIFY(pp->pr_flags & PR_ATTACHED);
155 VERIFY(pp->pr_domain == dp);
156 VERIFY(pp->pr_protosw == pp);
157
158 TAILQ_REMOVE(&dp->dom_protosw, pp, pr_entry);
159 pp->pr_flags &= ~PR_ATTACHED;
160 pp->pr_domain = NULL;
161 pp->pr_protosw = NULL;
162}
163
164static void
165dom_init_old(struct domain *dp)
166{
167 VERIFY(dp->dom_flags & DOM_OLD);
168 VERIFY(dp->dom_old != NULL);
169
170 if (dp->dom_old->dom_init != NULL)
171 dp->dom_old->dom_init();
172}
173
174static void
175init_domain(struct domain *dp)
176{
177 VERIFY(dp->dom_flags & DOM_ATTACHED);
178
179 if (!(dp->dom_flags & DOM_INITIALIZED)) {
180 lck_mtx_init(&dp->dom_mtx_s, domain_proto_mtx_grp,
181 domain_proto_mtx_attr);
182 dp->dom_mtx = &dp->dom_mtx_s;
183 TAILQ_INIT(&dp->dom_protosw);
184 if (dp->dom_init != NULL)
185 dp->dom_init(dp);
186 dp->dom_flags |= DOM_INITIALIZED;
187 }
188
189 /* Recompute for new protocol */
190 if (_max_linkhdr < 16) /* XXX - Sheesh; everything's ether? */
191 _max_linkhdr = 16;
192 _max_linkhdr = max_linkhdr; /* round it up */
193
194 if (dp->dom_protohdrlen > _max_protohdr)
195 _max_protohdr = dp->dom_protohdrlen;
196 _max_protohdr = max_protohdr; /* round it up */
197
198 max_hdr = max_linkhdr + max_protohdr;
199 max_datalen = MHLEN - max_hdr;
200}
201
202static void
203attach_domain(struct domain *dp)
204{
205 domain_proto_mtx_lock_assert_held();
206 VERIFY(!(dp->dom_flags & DOM_ATTACHED));
207
208 TAILQ_INSERT_TAIL(&domains, dp, dom_entry);
209 dp->dom_flags |= DOM_ATTACHED;
210}
211
212static void
213detach_domain(struct domain *dp)
214{
215 domain_proto_mtx_lock_assert_held();
216 VERIFY(dp->dom_flags & DOM_ATTACHED);
217
218 TAILQ_REMOVE(&domains, dp, dom_entry);
219 dp->dom_flags &= ~DOM_ATTACHED;
220
221 if (dp->dom_flags & DOM_OLD) {
222 struct domain_old *odp = dp->dom_old;
223
224 VERIFY(odp != NULL);
225 odp->dom_next = NULL;
226 odp->dom_mtx = NULL;
227 }
228}
229
230/*
231 * Exported (private) routine, indirection of net_add_domain.
232 */
233void
234net_add_domain_old(struct domain_old *odp)
235{
236 struct domain *dp;
237 domain_guard_t guard;
238
239 VERIFY(odp != NULL);
240
241 guard = domain_guard_deploy();
242 if ((dp = pffinddomain_locked(odp->dom_family)) != NULL) {
243 /*
244 * There is really nothing better than to panic here,
245 * as the caller would not have been able to handle
246 * any failures otherwise.
247 */
248 panic("%s: domain (%d,%s) already exists for %s\n", __func__,
249 dp->dom_family, dp->dom_name, odp->dom_name);
250 /* NOTREACHED */
251 }
252
253 /* Make sure nothing is currently pointing to the odp. */
254 TAILQ_FOREACH(dp, &domains, dom_entry) {
255 if (dp->dom_old == odp) {
256 panic("%s: domain %p (%d,%s) is already "
257 "associated with %p (%d,%s)\n", __func__,
258 odp, odp->dom_family, odp->dom_name, dp,
259 dp->dom_family, dp->dom_name);
260 /* NOTREACHED */
261 }
262 }
263
264 if (odp->dom_protosw != NULL) {
265 panic("%s: domain (%d,%s) protocols need to added "
266 "via net_add_proto\n", __func__, odp->dom_family,
267 odp->dom_name);
268 /* NOTREACHED */
269 }
270
271 dp = _MALLOC(sizeof (*dp), M_TEMP, M_WAITOK | M_ZERO);
272 if (dp == NULL) {
273 /*
274 * There is really nothing better than to panic here,
275 * as the caller would not have been able to handle
276 * any failures otherwise.
277 */
278 panic("%s: unable to allocate memory for domain family "
279 "%d (%s)\n", __func__, odp->dom_family, odp->dom_name);
280 /* NOTREACHED */
281 }
282
283 /* Copy everything but dom_init, dom_mtx, dom_next and dom_refs */
284 dp->dom_family = odp->dom_family;
285 dp->dom_flags = (odp->dom_flags & DOMF_USERFLAGS) | DOM_OLD;
286 dp->dom_name = odp->dom_name;
287 dp->dom_init = dom_init_old;
288 dp->dom_externalize = odp->dom_externalize;
289 dp->dom_dispose = odp->dom_dispose;
290 dp->dom_rtattach = odp->dom_rtattach;
291 dp->dom_rtoffset = odp->dom_rtoffset;
292 dp->dom_maxrtkey = odp->dom_maxrtkey;
293 dp->dom_protohdrlen = odp->dom_protohdrlen;
294 dp->dom_old = odp;
295
296 attach_domain(dp);
297 init_domain(dp);
298
299 /* Point the mutex back to the internal structure's */
300 odp->dom_mtx = dp->dom_mtx;
301 domain_guard_release(guard);
302}
303
304/*
305 * Exported (private) routine, indirection of net_del_domain.
306 */
307int
308net_del_domain_old(struct domain_old *odp)
309{
310 struct domain *dp1, *dp2;
311 int error = 0;
312 domain_guard_t guard;
313
314 VERIFY(odp != NULL);
315
316 guard = domain_guard_deploy();
317 if (odp->dom_refs != 0) {
318 error = EBUSY;
319 goto done;
320 }
321
322 TAILQ_FOREACH_SAFE(dp1, &domains, dom_entry, dp2) {
323 if (!(dp1->dom_flags & DOM_OLD))
324 continue;
325 VERIFY(dp1->dom_old != NULL);
326 if (odp == dp1->dom_old)
327 break;
328 }
329 if (dp1 != NULL) {
330 struct protosw *pp1, *pp2;
331
332 VERIFY(dp1->dom_flags & DOM_OLD);
333 VERIFY(dp1->dom_old == odp);
334
335 /* Remove all protocols attached to this domain */
336 TAILQ_FOREACH_SAFE(pp1, &dp1->dom_protosw, pr_entry, pp2) {
337 detach_proto(pp1, dp1);
338 if (pp1->pr_usrreqs->pru_flags & PRUF_OLD)
339 FREE(pp1->pr_usrreqs, M_TEMP);
340 if (pp1->pr_flags & PR_OLD)
341 FREE(pp1, M_TEMP);
342 }
343
344 detach_domain(dp1);
345 FREE(dp1, M_TEMP);
346 } else {
347 error = EPFNOSUPPORT;
348 }
349done:
350 domain_guard_release(guard);
351 return (error);
352}
353
354/*
355 * Internal routine, not exported.
356 *
357 * net_add_proto - link a protosw into a domain's protosw chain
358 *
359 * NOTE: Caller must have acquired domain_proto_mtx
360 */
361int
362net_add_proto(struct protosw *pp, struct domain *dp, int doinit)
363{
364 struct protosw *pp1;
365
366 /*
367 * This could be called as part of initializing the domain,
368 * and thus DOM_INITIALIZED may not be set (yet).
369 */
370 domain_proto_mtx_lock_assert_held();
371 VERIFY(!(pp->pr_flags & PR_ATTACHED));
372
373 /* pr_domain is set only after the protocol is attached */
374 if (pp->pr_domain != NULL) {
375 panic("%s: domain (%d,%s), proto %d has non-NULL pr_domain!\n",
376 __func__, dp->dom_family, dp->dom_name, pp->pr_protocol);
377 /* NOTREACHED */
378 }
379
380 if (pp->pr_usrreqs == NULL) {
381 panic("%s: domain (%d,%s), proto %d has no usrreqs!\n",
382 __func__, dp->dom_family, dp->dom_name, pp->pr_protocol);
383 /* NOTREACHED */
384 }
385
386 TAILQ_FOREACH(pp1, &dp->dom_protosw, pr_entry) {
387 if (pp1->pr_type == pp->pr_type &&
388 pp1->pr_protocol == pp->pr_protocol)
389 return (EEXIST);
390 }
391
392 attach_proto(pp, dp);
393 if (doinit)
394 net_init_proto(pp, dp);
395
396 return (0);
397}
398
399void
400net_init_proto(struct protosw *pp, struct domain *dp)
401{
402 /*
403 * This could be called as part of initializing the domain,
404 * and thus DOM_INITIALIZED may not be set (yet). The protocol
405 * must have been attached via net_addr_protosw() by now.
406 */
407 domain_proto_mtx_lock_assert_held();
408 VERIFY(pp->pr_flags & PR_ATTACHED);
409
410 init_proto(pp, dp);
411}
412
413/*
414 * Exported (private) routine, indirection of net_add_proto.
415 */
416int
417net_add_proto_old(struct protosw_old *opp, struct domain_old *odp)
418{
419 struct pr_usrreqs_old *opru;
420 struct pr_usrreqs *pru = NULL;
421 struct protosw *pp = NULL, *pp1;
422 int error = 0;
423 struct domain *dp;
424 domain_guard_t guard;
425
426 /*
427 * This could be called as part of initializing the domain,
428 * and thus DOM_INITIALIZED may not be set (yet).
429 */
430 guard = domain_guard_deploy();
431
432 /* Make sure the domain has been added via net_add_domain */
433 TAILQ_FOREACH(dp, &domains, dom_entry) {
434 if (!(dp->dom_flags & DOM_OLD))
435 continue;
436 if (dp->dom_old == odp)
437 break;
438 }
439 if (dp == NULL) {
440 error = EINVAL;
441 goto done;
442 }
443
444 TAILQ_FOREACH(pp1, &dp->dom_protosw, pr_entry) {
445 if (pp1->pr_type == opp->pr_type &&
446 pp1->pr_protocol == opp->pr_protocol) {
447 error = EEXIST;
448 goto done;
449 }
450 }
451
452 if ((opru = opp->pr_usrreqs) == NULL) {
453 panic("%s: domain (%d,%s), proto %d has no usrreqs!\n",
454 __func__, odp->dom_family, odp->dom_name, opp->pr_protocol);
455 /* NOTREACHED */
456 }
457
458 pru = _MALLOC(sizeof (*pru), M_TEMP, M_WAITOK | M_ZERO);
459 if (pru == NULL) {
460 error = ENOMEM;
461 goto done;
462 }
463
464 pru->pru_flags = PRUF_OLD;
465 pru->pru_abort = opru->pru_abort;
466 pru->pru_accept = opru->pru_accept;
467 pru->pru_attach = opru->pru_attach;
468 pru->pru_bind = opru->pru_bind;
469 pru->pru_connect = opru->pru_connect;
470 pru->pru_connect2 = opru->pru_connect2;
471 pru->pru_control = opru->pru_control;
472 pru->pru_detach = opru->pru_detach;
473 pru->pru_disconnect = opru->pru_disconnect;
474 pru->pru_listen = opru->pru_listen;
475 pru->pru_peeraddr = opru->pru_peeraddr;
476 pru->pru_rcvd = opru->pru_rcvd;
477 pru->pru_rcvoob = opru->pru_rcvoob;
478 pru->pru_send = opru->pru_send;
479 pru->pru_sense = opru->pru_sense;
480 pru->pru_shutdown = opru->pru_shutdown;
481 pru->pru_sockaddr = opru->pru_sockaddr;
482 pru->pru_sosend = opru->pru_sosend;
483 pru->pru_soreceive = opru->pru_soreceive;
484 pru->pru_sopoll = opru->pru_sopoll;
485
486 pp = _MALLOC(sizeof (*pp), M_TEMP, M_WAITOK | M_ZERO);
487 if (pp == NULL) {
488 error = ENOMEM;
489 goto done;
490 }
491
492 /*
493 * Protocol fast and slow timers are now deprecated.
494 */
495 if (opp->pr_unused != NULL) {
496 printf("%s: domain (%d,%s), proto %d: pr_fasttimo is "
497 "deprecated and won't be called\n", __func__,
498 odp->dom_family, odp->dom_name, opp->pr_protocol);
499 }
500 if (opp->pr_unused2 != NULL) {
501 printf("%s: domain (%d,%s), proto %d: pr_slowtimo is "
502 "deprecated and won't be called\n", __func__,
503 odp->dom_family, odp->dom_name, opp->pr_protocol);
504 }
505
506 /* Copy everything but pr_init, pr_next, pr_domain, pr_protosw */
507 pp->pr_type = opp->pr_type;
508 pp->pr_protocol = opp->pr_protocol;
509 pp->pr_flags = (opp->pr_flags & PRF_USERFLAGS) | PR_OLD;
510 pp->pr_input = opp->pr_input;
511 pp->pr_output = opp->pr_output;
512 pp->pr_ctlinput = opp->pr_ctlinput;
513 pp->pr_ctloutput = opp->pr_ctloutput;
514 pp->pr_usrreqs = pru;
515 pp->pr_init = pr_init_old;
516 pp->pr_drain = opp->pr_drain;
517 pp->pr_sysctl = opp->pr_sysctl;
518 pp->pr_lock = opp->pr_lock;
519 pp->pr_unlock = opp->pr_unlock;
520 pp->pr_getlock = opp->pr_getlock;
521 pp->pr_old = opp;
522
523 /* attach as well as initialize */
524 attach_proto(pp, dp);
525 net_init_proto(pp, dp);
526done:
527 if (error != 0) {
528 printf("%s: domain (%d,%s), proto %d: failed to attach, "
529 "error %d\n", __func__, odp->dom_family,
530 odp->dom_name, opp->pr_protocol, error);
531
532 if (pru != NULL)
533 FREE(pru, M_TEMP);
534 if (pp != NULL)
535 FREE(pp, M_TEMP);
536 }
537
538 domain_guard_release(guard);
539 return (error);
540}
541
542/*
543 * Internal routine, not exported.
544 *
545 * net_del_proto - remove a protosw from a domain's protosw chain.
546 * Search the protosw chain for the element with matching data.
547 * Then unlink and return.
548 *
549 * NOTE: Caller must have acquired domain_proto_mtx
550 */
551int
552net_del_proto(int type, int protocol, struct domain *dp)
553{
554 struct protosw *pp;
555
556 /*
557 * This could be called as part of initializing the domain,
558 * and thus DOM_INITIALIZED may not be set (yet).
559 */
560 domain_proto_mtx_lock_assert_held();
561
562 TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) {
563 if (pp->pr_type == type && pp->pr_protocol == protocol)
564 break;
565 }
566 if (pp == NULL)
567 return (ENXIO);
568
569 detach_proto(pp, dp);
570 if (pp->pr_usrreqs->pru_flags & PRUF_OLD)
571 FREE(pp->pr_usrreqs, M_TEMP);
572 if (pp->pr_flags & PR_OLD)
573 FREE(pp, M_TEMP);
574
575 return (0);
576}
577
578/*
579 * Exported (private) routine, indirection of net_del_proto.
580 */
581int
582net_del_proto_old(int type, int protocol, struct domain_old *odp)
583{
584 int error = 0;
585 struct protosw *pp;
586 struct domain *dp;
587 domain_guard_t guard;
588
589 /*
590 * This could be called as part of initializing the domain,
591 * and thus DOM_INITIALIZED may not be set (yet).
592 */
593 guard = domain_guard_deploy();
594
595 /* Make sure the domain has been added via net_add_domain */
596 TAILQ_FOREACH(dp, &domains, dom_entry) {
597 if (!(dp->dom_flags & DOM_OLD))
598 continue;
599 if (dp->dom_old == odp)
600 break;
601 }
602 if (dp == NULL) {
603 error = ENXIO;
604 goto done;
605 }
606
607 TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) {
608 if (pp->pr_type == type && pp->pr_protocol == protocol)
609 break;
610 }
611 if (pp == NULL) {
612 error = ENXIO;
613 goto done;
614 }
615 detach_proto(pp, dp);
616 if (pp->pr_usrreqs->pru_flags & PRUF_OLD)
617 FREE(pp->pr_usrreqs, M_TEMP);
618 if (pp->pr_flags & PR_OLD)
619 FREE(pp, M_TEMP);
620
621done:
622 domain_guard_release(guard);
623 return (error);
624}
625
626static void
627domain_sched_timeout(void)
628{
629 lck_mtx_assert(&domain_timeout_mtx, LCK_MTX_ASSERT_OWNED);
630
631 if (!domain_timeout_run && domain_draining) {
632 domain_timeout_run = TRUE;
633 timeout(domain_timeout, NULL, hz);
634 }
635}
636
637void
638net_drain_domains(void)
639{
640 lck_mtx_lock(&domain_timeout_mtx);
641 domain_draining = TRUE;
642 domain_sched_timeout();
643 lck_mtx_unlock(&domain_timeout_mtx);
644}
645
646#if INET6
647extern struct domain inet6domain_s;
648#endif
649#if IPSEC
650extern struct domain keydomain_s;
651#endif
652
653extern struct domain routedomain_s, ndrvdomain_s, inetdomain_s;
654extern struct domain systemdomain_s, localdomain_s;
655
656#if MULTIPATH
657extern struct domain mpdomain_s;
658#endif /* MULTIPATH */
659
660static void
661domain_timeout(void *arg)
662{
663#pragma unused(arg)
664 struct protosw *pp;
665 struct domain *dp;
666 domain_guard_t guard;
667
668 lck_mtx_lock(&domain_timeout_mtx);
669 if (domain_draining) {
670 domain_draining = FALSE;
671 lck_mtx_unlock(&domain_timeout_mtx);
672
673 guard = domain_guard_deploy();
674 TAILQ_FOREACH(dp, &domains, dom_entry) {
675 TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) {
676 if (pp->pr_drain != NULL)
677 (*pp->pr_drain)();
678 }
679 }
680 domain_guard_release(guard);
681
682 lck_mtx_lock(&domain_timeout_mtx);
683 }
684
685 /* re-arm the timer if there's work to do */
686 domain_timeout_run = FALSE;
687 domain_sched_timeout();
688 lck_mtx_unlock(&domain_timeout_mtx);
689}
690
691void
692domaininit(void)
693{
694 struct domain *dp;
695 domain_guard_t guard;
696
697 /*
698 * allocate lock group attribute and group for domain mutexes
699 */
700 domain_proto_mtx_grp_attr = lck_grp_attr_alloc_init();
701
702 domain_proto_mtx_grp = lck_grp_alloc_init("domain",
703 domain_proto_mtx_grp_attr);
704
705 /*
706 * allocate the lock attribute for per domain mutexes
707 */
708 domain_proto_mtx_attr = lck_attr_alloc_init();
709
710 lck_mtx_init(&domain_proto_mtx, domain_proto_mtx_grp,
711 domain_proto_mtx_attr);
712 lck_mtx_init(&domain_timeout_mtx, domain_proto_mtx_grp,
713 domain_proto_mtx_attr);
714
715 guard = domain_guard_deploy();
716 /*
717 * Add all the static domains to the domains list. route domain
718 * gets added and initialized last, since we need it to attach
719 * rt_tables[] to everything that's already there. This also
720 * means that domains added after this point won't get their
721 * dom_rtattach() called on rt_tables[].
722 */
723 attach_domain(&inetdomain_s);
724#if INET6
725 attach_domain(&inet6domain_s);
726#endif /* INET6 */
727#if MULTIPATH
728 attach_domain(&mpdomain_s);
729#endif /* MULTIPATH */
730 attach_domain(&systemdomain_s);
731 attach_domain(&localdomain_s);
732#if IPSEC
733 attach_domain(&keydomain_s);
734#endif /* IPSEC */
735 attach_domain(&ndrvdomain_s);
736 attach_domain(&routedomain_s); /* must be last domain */
737
738 /*
739 * Now ask them all to init (XXX including the routing domain,
740 * see above)
741 */
742 TAILQ_FOREACH(dp, &domains, dom_entry)
743 init_domain(dp);
744
745 domain_guard_release(guard);
746}
747
748static __inline__ struct domain *
749pffinddomain_locked(int pf)
750{
751 struct domain *dp;
752
753 domain_proto_mtx_lock_assert_held();
754
755 TAILQ_FOREACH(dp, &domains, dom_entry) {
756 if (dp->dom_family == pf)
757 break;
758 }
759 return (dp);
760}
761
762struct protosw *
763pffindtype(int family, int type)
764{
765 struct protosw *pp = NULL;
766 struct domain *dp;
767 domain_guard_t guard;
768
769 guard = domain_guard_deploy();
770 if ((dp = pffinddomain_locked(family)) == NULL)
771 goto done;
772
773 TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) {
774 if (pp->pr_type != 0 && pp->pr_type == type)
775 goto done;
776 }
777done:
778 domain_guard_release(guard);
779 return (pp);
780}
781
782/*
783 * Internal routine, not exported.
784 */
785struct domain *
786pffinddomain(int pf)
787{
788 struct domain *dp;
789 domain_guard_t guard;
790
791 guard = domain_guard_deploy();
792 dp = pffinddomain_locked(pf);
793 domain_guard_release(guard);
794 return (dp);
795}
796
797/*
798 * Exported (private) routine, indirection of pffinddomain.
799 */
800struct domain_old *
801pffinddomain_old(int pf)
802{
803 struct domain_old *odp = NULL;
804 struct domain *dp;
805 domain_guard_t guard;
806
807 guard = domain_guard_deploy();
808 if ((dp = pffinddomain_locked(pf)) != NULL && (dp->dom_flags & DOM_OLD))
809 odp = dp->dom_old;
810 domain_guard_release(guard);
811 return (odp);
812}
813
814/*
815 * Internal routine, not exported.
816 */
817struct protosw *
818pffindproto(int family, int protocol, int type)
819{
820 struct protosw *pp;
821 domain_guard_t guard;
822
823 guard = domain_guard_deploy();
824 pp = pffindproto_locked(family, protocol, type);
825 domain_guard_release(guard);
826 return (pp);
827}
828
829struct protosw *
830pffindproto_locked(int family, int protocol, int type)
831{
832 struct protosw *maybe = NULL;
833 struct protosw *pp;
834 struct domain *dp;
835
836 domain_proto_mtx_lock_assert_held();
837
838 if (family == 0)
839 return (0);
840
841 dp = pffinddomain_locked(family);
842 if (dp == NULL)
843 return (NULL);
844
845 TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) {
846 if ((pp->pr_protocol == protocol) && (pp->pr_type == type))
847 return (pp);
848
849 if (type == SOCK_RAW && pp->pr_type == SOCK_RAW &&
850 pp->pr_protocol == 0 && maybe == NULL)
851 maybe = pp;
852 }
853 return (maybe);
854}
855
856/*
857 * Exported (private) routine, indirection of pffindproto.
858 */
859struct protosw_old *
860pffindproto_old(int family, int protocol, int type)
861{
862 struct protosw_old *opr = NULL;
863 struct protosw *pp;
864 domain_guard_t guard;
865
866 guard = domain_guard_deploy();
867 if ((pp = pffindproto_locked(family, protocol, type)) != NULL &&
868 (pp->pr_flags & PR_OLD))
869 opr = pp->pr_old;
870 domain_guard_release(guard);
871 return (opr);
872}
873
874static struct protosw *
875pffindprotonotype_locked(int family, int protocol, int type)
876{
877#pragma unused(type)
878 struct domain *dp;
879 struct protosw *pp;
880
881 domain_proto_mtx_lock_assert_held();
882
883 if (family == 0)
884 return (0);
885
886 dp = pffinddomain_locked(family);
887 if (dp == NULL)
888 return (NULL);
889
890 TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) {
891 if (pp->pr_protocol == protocol)
892 return (pp);
893 }
894 return (NULL);
895}
896
897struct protosw *
898pffindprotonotype(int family, int protocol)
899{
900 struct protosw *pp;
901 domain_guard_t guard;
902
903 if (protocol == 0)
904 return (NULL);
905
906 guard = domain_guard_deploy();
907 pp = pffindprotonotype_locked(family, protocol, 0);
908 domain_guard_release(guard);
909 return (pp);
910}
911
912int
913net_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
914 user_addr_t newp, size_t newlen, struct proc *p)
915{
916#pragma unused(p)
917 int family, protocol, error = 0;
918 struct domain *dp;
919 struct protosw *pp;
920 domain_guard_t guard;
921
922 /*
923 * All sysctl names at this level are nonterminal;
924 * next two components are protocol family and protocol number,
925 * then at least one addition component.
926 */
927 if (namelen < 3)
928 return (EISDIR); /* overloaded */
929 family = name[0];
930 protocol = name[1];
931
932 if (family == 0)
933 return (0);
934
935 guard = domain_guard_deploy();
936 TAILQ_FOREACH(dp, &domains, dom_entry) {
937 if (dp->dom_family == family)
938 break;
939 }
940 if (dp == NULL) {
941 error = ENOPROTOOPT;
942 goto done;
943 }
944
945 TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) {
946 if (pp->pr_protocol == protocol && pp->pr_sysctl != NULL) {
947 error = (*pp->pr_sysctl)(name + 2, namelen - 2,
948 (void *)(uintptr_t)oldp, oldlenp,
949 (void *)(uintptr_t)newp, newlen);
950 goto done;
951 }
952 }
953 error = ENOPROTOOPT;
954done:
955 domain_guard_release(guard);
956 return (error);
957}
958
959void
960pfctlinput(int cmd, struct sockaddr *sa)
961{
962 pfctlinput2(cmd, sa, NULL);
963}
964
965void
966pfctlinput2(int cmd, struct sockaddr *sa, void *ctlparam)
967{
968 struct domain *dp;
969 struct protosw *pp;
970 domain_guard_t guard;
971
972 if (sa == NULL)
973 return;
974
975 guard = domain_guard_deploy();
976 TAILQ_FOREACH(dp, &domains, dom_entry) {
977 TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) {
978 if (pp->pr_ctlinput != NULL)
979 (*pp->pr_ctlinput)(cmd, sa, ctlparam);
980 }
981 }
982 domain_guard_release(guard);
983}
984
985void
986net_update_uptime(void)
987{
988 struct timeval tv;
989
990 microuptime(&tv);
991 _net_uptime = tv.tv_sec;
992 /*
993 * Round up the timer to the nearest integer value because otherwise
994 * we might setup networking timers that are off by almost 1 second.
995 */
996 if (tv.tv_usec > 500000)
997 _net_uptime++;
998}
999
1000void
1001net_update_uptime_secs(uint64_t secs)
1002{
1003 _net_uptime = secs;
1004}
1005
1006/*
1007 * Convert our uin64_t net_uptime to a struct timeval.
1008 */
1009void
1010net_uptime2timeval(struct timeval *tv)
1011{
1012 if (tv == NULL)
1013 return;
1014
1015 tv->tv_usec = 0;
1016 tv->tv_sec = net_uptime();
1017}
1018
1019/*
1020 * An alternative way to obtain the coarse-grained uptime (in seconds)
1021 * for networking code which do not require high-precision timestamp,
1022 * as this is significantly cheaper than microuptime().
1023 */
1024u_int64_t
1025net_uptime(void)
1026{
1027 if (_net_uptime == 0)
1028 net_update_uptime();
1029
1030 return (_net_uptime);
1031}
1032
1033void
1034domain_proto_mtx_lock_assert_held(void)
1035{
1036 lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED);
1037}
1038
1039void
1040domain_proto_mtx_lock_assert_notheld(void)
1041{
1042 lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
1043}
1044
1045domain_guard_t
1046domain_guard_deploy(void)
1047{
1048 net_thread_marks_t marks;
1049
1050 marks = net_thread_marks_push(NET_THREAD_HELD_DOMAIN);
1051 if (marks != net_thread_marks_none) {
1052 lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
1053 lck_mtx_lock(&domain_proto_mtx);
1054 }
1055 else
1056 lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED);
1057
1058 return ((domain_guard_t)(const void*)marks);
1059}
1060
1061void
1062domain_guard_release(domain_guard_t guard)
1063{
1064 net_thread_marks_t marks = (net_thread_marks_t)(const void*)guard;
1065
1066 if (marks != net_thread_marks_none) {
1067 lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED);
1068 lck_mtx_unlock(&domain_proto_mtx);
1069 net_thread_marks_pop(marks);
1070 }
1071 else
1072 lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
1073}
1074
1075domain_unguard_t
1076domain_unguard_deploy(void)
1077{
1078 net_thread_marks_t marks;
1079
1080 marks = net_thread_unmarks_push(NET_THREAD_HELD_DOMAIN);
1081 if (marks != net_thread_marks_none) {
1082 lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED);
1083 lck_mtx_unlock(&domain_proto_mtx);
1084 }
1085 else
1086 lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
1087
1088 return ((domain_unguard_t)(const void*)marks);
1089}
1090
1091void
1092domain_unguard_release(domain_unguard_t unguard)
1093{
1094 net_thread_marks_t marks = (net_thread_marks_t)(const void*)unguard;
1095
1096 if (marks != net_thread_marks_none) {
1097 lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
1098 lck_mtx_lock(&domain_proto_mtx);
1099 net_thread_unmarks_pop(marks);
1100 }
1101 else
1102 lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED);
1103}