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