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