uipc_domain.c revision 177253
122347Spst/*-
222347Spst * Copyright (c) 1982, 1986, 1993
329964Sache *	The Regents of the University of California.  All rights reserved.
492906Smarkm *
592906Smarkm * Redistribution and use in source and binary forms, with or without
622347Spst * modification, are permitted provided that the following conditions
722347Spst * are met:
822347Spst * 1. Redistributions of source code must retain the above copyright
922347Spst *    notice, this list of conditions and the following disclaimer.
1022347Spst * 2. Redistributions in binary form must reproduce the above copyright
1159118Skris *    notice, this list of conditions and the following disclaimer in the
1259118Skris *    documentation and/or other materials provided with the distribution.
1329964Sache * 4. Neither the name of the University nor the names of its contributors
1429964Sache *    may be used to endorse or promote products derived from this software
1529964Sache *    without specific prior written permission.
1622347Spst *
1722347Spst * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1822347Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1922347Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2022347Spst * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2122347Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2222347Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2322347Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2422347Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2522347Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2629964Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2729964Sache * SUCH DAMAGE.
2829964Sache *
2929964Sache *	@(#)uipc_domain.c	8.2 (Berkeley) 10/18/93
3029964Sache */
3129964Sache
3229964Sache#include <sys/cdefs.h>
3329964Sache__FBSDID("$FreeBSD: head/sys/kern/uipc_domain.c 177253 2008-03-16 10:58:09Z rwatson $");
3422347Spst
3522347Spst#include <sys/param.h>
3622347Spst#include <sys/socket.h>
3722347Spst#include <sys/protosw.h>
3822347Spst#include <sys/domain.h>
3922347Spst#include <sys/eventhandler.h>
4022347Spst#include <sys/mbuf.h>
4122347Spst#include <sys/kernel.h>
4222347Spst#include <sys/lock.h>
4322347Spst#include <sys/mutex.h>
4422347Spst#include <sys/socketvar.h>
4522347Spst#include <sys/systm.h>
4659118Skris#include <vm/uma.h>
4722347Spst
4822347Spst/*
4922347Spst * System initialization
5022347Spst *
5122347Spst * Note: domain initialization takes place on a per domain basis
5222347Spst * as a result of traversing a SYSINIT linker set.  Most likely,
5359118Skris * each domain would want to call DOMAIN_SET(9) itself, which
5422347Spst * would cause the domain to be added just after domaininit()
5522347Spst * is called during startup.
5622347Spst *
5722347Spst * See DOMAIN_SET(9) for details on its use.
5822347Spst */
5922347Spst
6022347Spststatic void domaininit(void *);
6122347SpstSYSINIT(domain, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, domaininit, NULL);
6222347Spst
6322347Spststatic void domainfinalize(void *);
64SYSINIT(domainfin, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST, domainfinalize,
65    NULL);
66
67static struct callout pffast_callout;
68static struct callout pfslow_callout;
69
70static void	pffasttimo(void *);
71static void	pfslowtimo(void *);
72
73struct domain *domains;		/* registered protocol domains */
74int domain_init_status = 0;
75struct mtx dom_mtx;		/* domain list lock */
76MTX_SYSINIT(domain, &dom_mtx, "domain list", MTX_DEF);
77
78/*
79 * Dummy protocol specific user requests function pointer array.
80 * All functions return EOPNOTSUPP.
81 */
82struct pr_usrreqs nousrreqs = {
83	.pru_accept =		pru_accept_notsupp,
84	.pru_attach =		pru_attach_notsupp,
85	.pru_bind =		pru_bind_notsupp,
86	.pru_connect =		pru_connect_notsupp,
87	.pru_connect2 =		pru_connect2_notsupp,
88	.pru_control =		pru_control_notsupp,
89	.pru_disconnect	=	pru_disconnect_notsupp,
90	.pru_listen =		pru_listen_notsupp,
91	.pru_peeraddr =		pru_peeraddr_notsupp,
92	.pru_rcvd =		pru_rcvd_notsupp,
93	.pru_rcvoob =		pru_rcvoob_notsupp,
94	.pru_send =		pru_send_notsupp,
95	.pru_sense =		pru_sense_null,
96	.pru_shutdown =		pru_shutdown_notsupp,
97	.pru_sockaddr =		pru_sockaddr_notsupp,
98	.pru_sosend =		pru_sosend_notsupp,
99	.pru_soreceive =	pru_soreceive_notsupp,
100	.pru_sopoll =		pru_sopoll_notsupp,
101};
102
103static void
104protosw_init(struct protosw *pr)
105{
106	struct pr_usrreqs *pu;
107
108	pu = pr->pr_usrreqs;
109	KASSERT(pu != NULL, ("protosw_init: %ssw[%d] has no usrreqs!",
110	    pr->pr_domain->dom_name,
111	    (int)(pr - pr->pr_domain->dom_protosw)));
112
113#define DEFAULT(foo, bar)	if ((foo) == NULL)  (foo) = (bar)
114	DEFAULT(pu->pru_accept, pru_accept_notsupp);
115	DEFAULT(pu->pru_connect, pru_connect_notsupp);
116	DEFAULT(pu->pru_connect2, pru_connect2_notsupp);
117	DEFAULT(pu->pru_control, pru_control_notsupp);
118	DEFAULT(pu->pru_listen, pru_listen_notsupp);
119	DEFAULT(pu->pru_rcvd, pru_rcvd_notsupp);
120	DEFAULT(pu->pru_rcvoob, pru_rcvoob_notsupp);
121	DEFAULT(pu->pru_sense, pru_sense_null);
122	DEFAULT(pu->pru_sosend, sosend_generic);
123	DEFAULT(pu->pru_soreceive, soreceive_generic);
124	DEFAULT(pu->pru_sopoll, sopoll_generic);
125#undef DEFAULT
126	if (pr->pr_init)
127		(*pr->pr_init)();
128}
129
130/*
131 * Add a new protocol domain to the list of supported domains
132 * Note: you cant unload it again because a socket may be using it.
133 * XXX can't fail at this time.
134 */
135static void
136net_init_domain(struct domain *dp)
137{
138	struct protosw *pr;
139
140	if (dp->dom_init)
141		(*dp->dom_init)();
142	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
143		protosw_init(pr);
144	/*
145	 * update global information about maximums
146	 */
147	max_hdr = max_linkhdr + max_protohdr;
148	max_datalen = MHLEN - max_hdr;
149	if (max_datalen < 1)
150		panic("%s: max_datalen < 1", __func__);
151}
152
153/*
154 * Add a new protocol domain to the list of supported domains
155 * Note: you cant unload it again because a socket may be using it.
156 * XXX can't fail at this time.
157 */
158void
159net_add_domain(void *data)
160{
161	struct domain *dp;
162
163	dp = (struct domain *)data;
164	mtx_lock(&dom_mtx);
165	dp->dom_next = domains;
166	domains = dp;
167
168	KASSERT(domain_init_status >= 1,
169	    ("attempt to net_add_domain(%s) before domaininit()",
170	    dp->dom_name));
171#ifndef INVARIANTS
172	if (domain_init_status < 1)
173		printf("WARNING: attempt to net_add_domain(%s) before "
174		    "domaininit()\n", dp->dom_name);
175#endif
176#ifdef notyet
177	KASSERT(domain_init_status < 2,
178	    ("attempt to net_add_domain(%s) after domainfinalize()",
179	    dp->dom_name));
180#else
181	if (domain_init_status >= 2)
182		printf("WARNING: attempt to net_add_domain(%s) after "
183		    "domainfinalize()\n", dp->dom_name);
184#endif
185	mtx_unlock(&dom_mtx);
186	net_init_domain(dp);
187}
188
189static void
190socket_zone_change(void *tag)
191{
192
193	uma_zone_set_max(socket_zone, maxsockets);
194}
195
196/* ARGSUSED*/
197static void
198domaininit(void *dummy)
199{
200
201	/*
202	 * Before we do any setup, make sure to initialize the
203	 * zone allocator we get struct sockets from.
204	 */
205	socket_zone = uma_zcreate("socket", sizeof(struct socket), NULL, NULL,
206	    NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
207	uma_zone_set_max(socket_zone, maxsockets);
208	EVENTHANDLER_REGISTER(maxsockets_change, socket_zone_change, NULL,
209		EVENTHANDLER_PRI_FIRST);
210
211	if (max_linkhdr < 16)		/* XXX */
212		max_linkhdr = 16;
213
214	callout_init(&pffast_callout, CALLOUT_MPSAFE);
215	callout_init(&pfslow_callout, CALLOUT_MPSAFE);
216
217	mtx_lock(&dom_mtx);
218	KASSERT(domain_init_status == 0, ("domaininit called too late!"));
219	domain_init_status = 1;
220	mtx_unlock(&dom_mtx);
221}
222
223/* ARGSUSED*/
224static void
225domainfinalize(void *dummy)
226{
227
228	mtx_lock(&dom_mtx);
229	KASSERT(domain_init_status == 1, ("domainfinalize called too late!"));
230	domain_init_status = 2;
231	mtx_unlock(&dom_mtx);
232
233	callout_reset(&pffast_callout, 1, pffasttimo, NULL);
234	callout_reset(&pfslow_callout, 1, pfslowtimo, NULL);
235}
236
237struct protosw *
238pffindtype(int family, int type)
239{
240	struct domain *dp;
241	struct protosw *pr;
242
243	for (dp = domains; dp; dp = dp->dom_next)
244		if (dp->dom_family == family)
245			goto found;
246	return (0);
247found:
248	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
249		if (pr->pr_type && pr->pr_type == type)
250			return (pr);
251	return (0);
252}
253
254struct protosw *
255pffindproto(int family, int protocol, int type)
256{
257	struct domain *dp;
258	struct protosw *pr;
259	struct protosw *maybe = 0;
260
261	if (family == 0)
262		return (0);
263	for (dp = domains; dp; dp = dp->dom_next)
264		if (dp->dom_family == family)
265			goto found;
266	return (0);
267found:
268	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
269		if ((pr->pr_protocol == protocol) && (pr->pr_type == type))
270			return (pr);
271
272		if (type == SOCK_RAW && pr->pr_type == SOCK_RAW &&
273		    pr->pr_protocol == 0 && maybe == (struct protosw *)0)
274			maybe = pr;
275	}
276	return (maybe);
277}
278
279/*
280 * The caller must make sure that the new protocol is fully set up and ready to
281 * accept requests before it is registered.
282 */
283int
284pf_proto_register(int family, struct protosw *npr)
285{
286	struct domain *dp;
287	struct protosw *pr, *fpr;
288
289	/* Sanity checks. */
290	if (family == 0)
291		return (EPFNOSUPPORT);
292	if (npr->pr_type == 0)
293		return (EPROTOTYPE);
294	if (npr->pr_protocol == 0)
295		return (EPROTONOSUPPORT);
296	if (npr->pr_usrreqs == NULL)
297		return (ENXIO);
298
299	/* Try to find the specified domain based on the family. */
300	for (dp = domains; dp; dp = dp->dom_next)
301		if (dp->dom_family == family)
302			goto found;
303	return (EPFNOSUPPORT);
304
305found:
306	/* Initialize backpointer to struct domain. */
307	npr->pr_domain = dp;
308	fpr = NULL;
309
310	/*
311	 * Protect us against races when two protocol registrations for
312	 * the same protocol happen at the same time.
313	 */
314	mtx_lock(&Giant);
315
316	/* The new protocol must not yet exist. */
317	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
318		if ((pr->pr_type == npr->pr_type) &&
319		    (pr->pr_protocol == npr->pr_protocol)) {
320			mtx_unlock(&Giant);
321			return (EEXIST);	/* XXX: Check only protocol? */
322		}
323		/* While here, remember the first free spacer. */
324		if ((fpr == NULL) && (pr->pr_protocol == PROTO_SPACER))
325			fpr = pr;
326	}
327
328	/* If no free spacer is found we can't add the new protocol. */
329	if (fpr == NULL) {
330		mtx_unlock(&Giant);
331		return (ENOMEM);
332	}
333
334	/* Copy the new struct protosw over the spacer. */
335	bcopy(npr, fpr, sizeof(*fpr));
336
337	/* Job is done, no more protection required. */
338	mtx_unlock(&Giant);
339
340	/* Initialize and activate the protocol. */
341	protosw_init(fpr);
342
343	return (0);
344}
345
346/*
347 * The caller must make sure the protocol and its functions correctly shut down
348 * all sockets and release all locks and memory references.
349 */
350int
351pf_proto_unregister(int family, int protocol, int type)
352{
353	struct domain *dp;
354	struct protosw *pr, *dpr;
355
356	/* Sanity checks. */
357	if (family == 0)
358		return (EPFNOSUPPORT);
359	if (protocol == 0)
360		return (EPROTONOSUPPORT);
361	if (type == 0)
362		return (EPROTOTYPE);
363
364	/* Try to find the specified domain based on the family type. */
365	for (dp = domains; dp; dp = dp->dom_next)
366		if (dp->dom_family == family)
367			goto found;
368	return (EPFNOSUPPORT);
369
370found:
371	dpr = NULL;
372
373	/* Lock out everyone else while we are manipulating the protosw. */
374	mtx_lock(&Giant);
375
376	/* The protocol must exist and only once. */
377	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
378		if ((pr->pr_type == type) && (pr->pr_protocol == protocol)) {
379			if (dpr != NULL) {
380				mtx_unlock(&Giant);
381				return (EMLINK);   /* Should not happen! */
382			} else
383				dpr = pr;
384		}
385	}
386
387	/* Protocol does not exist. */
388	if (dpr == NULL) {
389		mtx_unlock(&Giant);
390		return (EPROTONOSUPPORT);
391	}
392
393	/* De-orbit the protocol and make the slot available again. */
394	dpr->pr_type = 0;
395	dpr->pr_domain = dp;
396	dpr->pr_protocol = PROTO_SPACER;
397	dpr->pr_flags = 0;
398	dpr->pr_input = NULL;
399	dpr->pr_output = NULL;
400	dpr->pr_ctlinput = NULL;
401	dpr->pr_ctloutput = NULL;
402	dpr->pr_ousrreq = NULL;
403	dpr->pr_init = NULL;
404	dpr->pr_fasttimo = NULL;
405	dpr->pr_slowtimo = NULL;
406	dpr->pr_drain = NULL;
407	dpr->pr_usrreqs = &nousrreqs;
408
409	/* Job is done, not more protection required. */
410	mtx_unlock(&Giant);
411
412	return (0);
413}
414
415void
416pfctlinput(int cmd, struct sockaddr *sa)
417{
418	struct domain *dp;
419	struct protosw *pr;
420
421	for (dp = domains; dp; dp = dp->dom_next)
422		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
423			if (pr->pr_ctlinput)
424				(*pr->pr_ctlinput)(cmd, sa, (void *)0);
425}
426
427void
428pfctlinput2(int cmd, struct sockaddr *sa, void *ctlparam)
429{
430	struct domain *dp;
431	struct protosw *pr;
432
433	if (!sa)
434		return;
435	for (dp = domains; dp; dp = dp->dom_next) {
436		/*
437		 * the check must be made by xx_ctlinput() anyways, to
438		 * make sure we use data item pointed to by ctlparam in
439		 * correct way.  the following check is made just for safety.
440		 */
441		if (dp->dom_family != sa->sa_family)
442			continue;
443
444		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
445			if (pr->pr_ctlinput)
446				(*pr->pr_ctlinput)(cmd, sa, ctlparam);
447	}
448}
449
450static void
451pfslowtimo(void *arg)
452{
453	struct domain *dp;
454	struct protosw *pr;
455
456	for (dp = domains; dp; dp = dp->dom_next)
457		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
458			if (pr->pr_slowtimo)
459				(*pr->pr_slowtimo)();
460	callout_reset(&pfslow_callout, hz/2, pfslowtimo, NULL);
461}
462
463static void
464pffasttimo(void *arg)
465{
466	struct domain *dp;
467	struct protosw *pr;
468
469	for (dp = domains; dp; dp = dp->dom_next)
470		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
471			if (pr->pr_fasttimo)
472				(*pr->pr_fasttimo)();
473	callout_reset(&pffast_callout, hz/5, pffasttimo, NULL);
474}
475