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