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