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