xref: /freebsd/sys/kern/uipc_domain.c (revision 7562eaabc01a48e6b11d5b558c41e3b92dae5c2d)
1 /*
2  * Copyright (c) 1982, 1986, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *	@(#)uipc_domain.c	8.2 (Berkeley) 10/18/93
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 #include <sys/socket.h>
37 #include <sys/protosw.h>
38 #include <sys/domain.h>
39 #include <sys/mbuf.h>
40 #include <sys/kernel.h>
41 #include <sys/lock.h>
42 #include <sys/mutex.h>
43 #include <sys/socketvar.h>
44 #include <sys/systm.h>
45 #include <vm/uma.h>
46 
47 /*
48  * System initialization
49  *
50  * Note: domain initialization takes place on a per domain basis
51  * as a result of traversing a SYSINIT linker set.  Most likely,
52  * each domain would want to call DOMAIN_SET(9) itself, which
53  * would cause the domain to be added just after domaininit()
54  * is called during startup.
55  *
56  * See DOMAIN_SET(9) for details on its use.
57  */
58 
59 static void domaininit(void *);
60 SYSINIT(domain, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, domaininit, NULL)
61 
62 static struct callout pffast_callout;
63 static struct callout pfslow_callout;
64 
65 static void	pffasttimo(void *);
66 static void	pfslowtimo(void *);
67 
68 struct domain *domains;		/* registered protocol domains */
69 struct mtx dom_mtx;		/* domain list lock */
70 MTX_SYSINIT(domain, &dom_mtx, "domain list", MTX_DEF);
71 
72 /*
73  * Dummy protocol specific user requests function pointer array.
74  * All functions return EOPNOTSUPP.
75  */
76 struct pr_usrreqs nousrreqs = {
77         pru_abort_notsupp, pru_accept_notsupp, pru_attach_notsupp,
78         pru_bind_notsupp, pru_connect_notsupp, pru_connect2_notsupp,
79         pru_control_notsupp, pru_detach_notsupp, pru_disconnect_notsupp,
80         pru_listen_notsupp, pru_peeraddr_notsupp, pru_rcvd_notsupp,
81         pru_rcvoob_notsupp, pru_send_notsupp, pru_sense_null,
82         pru_shutdown_notsupp, pru_sockaddr_notsupp, pru_sosend_notsupp,
83         pru_soreceive_notsupp, pru_sopoll_notsupp, pru_sosetlabel_null
84 };
85 
86 /*
87  * Add a new protocol domain to the list of supported domains
88  * Note: you cant unload it again because a socket may be using it.
89  * XXX can't fail at this time.
90  */
91 static void
92 net_init_domain(struct domain *dp)
93 {
94 	struct protosw *pr;
95 
96 	if (dp->dom_init)
97 		(*dp->dom_init)();
98 	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++){
99 		if (pr->pr_usrreqs == 0)
100 			panic("domaininit: %ssw[%d] has no usrreqs!",
101 			      dp->dom_name,
102 			      (int)(pr - dp->dom_protosw));
103 		if (pr->pr_init)
104 			(*pr->pr_init)();
105 	}
106 	/*
107 	 * update global information about maximums
108 	 */
109 	max_hdr = max_linkhdr + max_protohdr;
110 	max_datalen = MHLEN - max_hdr;
111 }
112 
113 /*
114  * Add a new protocol domain to the list of supported domains
115  * Note: you cant unload it again because a socket may be using it.
116  * XXX can't fail at this time.
117  */
118 void
119 net_add_domain(void *data)
120 {
121 	struct domain *dp;
122 
123 	dp = (struct domain *)data;
124 	mtx_lock(&dom_mtx);
125 	dp->dom_next = domains;
126 	domains = dp;
127 	mtx_unlock(&dom_mtx);
128 	net_init_domain(dp);
129 }
130 
131 /* ARGSUSED*/
132 static void
133 domaininit(void *dummy)
134 {
135 	/*
136 	 * Before we do any setup, make sure to initialize the
137 	 * zone allocator we get struct sockets from.
138 	 */
139 
140 	socket_zone = uma_zcreate("socket", sizeof(struct socket), NULL, NULL,
141 	    NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
142 	uma_zone_set_max(socket_zone, maxsockets);
143 
144 	if (max_linkhdr < 16)		/* XXX */
145 		max_linkhdr = 16;
146 
147 	if (debug_mpsafenet) {
148 		callout_init(&pffast_callout, CALLOUT_MPSAFE);
149 		callout_init(&pfslow_callout, CALLOUT_MPSAFE);
150 	} else {
151 		callout_init(&pffast_callout, 0);
152 		callout_init(&pfslow_callout, 0);
153 	}
154 
155 	callout_reset(&pffast_callout, 1, pffasttimo, NULL);
156 	callout_reset(&pfslow_callout, 1, pfslowtimo, NULL);
157 }
158 
159 
160 struct protosw *
161 pffindtype(family, type)
162 	int family;
163 	int type;
164 {
165 	register struct domain *dp;
166 	register struct protosw *pr;
167 
168 	for (dp = domains; dp; dp = dp->dom_next)
169 		if (dp->dom_family == family)
170 			goto found;
171 	return (0);
172 found:
173 	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
174 		if (pr->pr_type && pr->pr_type == type)
175 			return (pr);
176 	return (0);
177 }
178 
179 struct protosw *
180 pffindproto(family, protocol, type)
181 	int family;
182 	int protocol;
183 	int type;
184 {
185 	register struct domain *dp;
186 	register struct protosw *pr;
187 	struct protosw *maybe = 0;
188 
189 	if (family == 0)
190 		return (0);
191 	for (dp = domains; dp; dp = dp->dom_next)
192 		if (dp->dom_family == family)
193 			goto found;
194 	return (0);
195 found:
196 	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
197 		if ((pr->pr_protocol == protocol) && (pr->pr_type == type))
198 			return (pr);
199 
200 		if (type == SOCK_RAW && pr->pr_type == SOCK_RAW &&
201 		    pr->pr_protocol == 0 && maybe == (struct protosw *)0)
202 			maybe = pr;
203 	}
204 	return (maybe);
205 }
206 
207 /*
208  * The caller must make sure that the new protocol is fully set up and ready to
209  * accept requests before it is registered.
210  */
211 int
212 pf_proto_register(family, npr)
213 	int family;
214 	struct protosw *npr;
215 {
216 	struct domain *dp;
217 	struct protosw *pr, *fpr;
218 
219 	/* Sanity checks. */
220 	if (family == 0)
221 		return (EPFNOSUPPORT);
222 	if (npr->pr_type == 0)
223 		return (EPROTOTYPE);
224 	if (npr->pr_protocol == 0)
225 		return (EPROTONOSUPPORT);
226 	if (npr->pr_usrreqs == NULL)
227 		return (ENXIO);
228 
229 	/* Try to find the specified domain based on the family. */
230 	for (dp = domains; dp; dp = dp->dom_next)
231 		if (dp->dom_family == family)
232 			goto found;
233 	return (EPFNOSUPPORT);
234 
235 found:
236 	/* Initialize backpointer to struct domain. */
237 	npr->pr_domain = dp;
238 	fpr = NULL;
239 
240 	/*
241 	 * Protect us against races when two protocol registrations for
242 	 * the same protocol happen at the same time.
243 	 */
244 	mtx_lock(&Giant);
245 
246 	/* The new protocol must not yet exist. */
247 	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
248 		if ((pr->pr_type == npr->pr_type) &&
249 		    (pr->pr_protocol == npr->pr_protocol)) {
250 			mtx_unlock(&Giant);
251 			return (EEXIST);	/* XXX: Check only protocol? */
252 		}
253 		/* While here, remember the first free spacer. */
254 		if ((fpr == NULL) && (pr->pr_protocol == PROTO_SPACER))
255 			fpr = pr;
256 	}
257 
258 	/* If no free spacer is found we can't add the new protocol. */
259 	if (fpr == NULL) {
260 		mtx_unlock(&Giant);
261 		return (ENOMEM);
262 	}
263 
264 	/* Copy the new struct protosw over the spacer. */
265 	bcopy(npr, fpr, sizeof(*fpr));
266 
267 	/* Job is done, no more protection required. */
268 	mtx_unlock(&Giant);
269 
270 	/* Initialize and activate the protocol. */
271 	if (fpr->pr_init)
272 		(fpr->pr_init)();
273 
274 	return (0);
275 }
276 
277 /*
278  * The caller must make sure the protocol and its functions correctly shut down
279  * all sockets and release all locks and memory references.
280  */
281 int
282 pf_proto_unregister(family, protocol, type)
283 	int family;
284 	int protocol;
285 	int type;
286 {
287 	struct domain *dp;
288 	struct protosw *pr, *dpr;
289 
290 	/* Sanity checks. */
291 	if (family == 0)
292 		return (EPFNOSUPPORT);
293 	if (protocol == 0)
294 		return (EPROTONOSUPPORT);
295 	if (type == 0)
296 		return (EPROTOTYPE);
297 
298 	/* Try to find the specified domain based on the family type. */
299 	for (dp = domains; dp; dp = dp->dom_next)
300 		if (dp->dom_family == family)
301 			goto found;
302 	return (EPFNOSUPPORT);
303 
304 found:
305 	dpr = NULL;
306 
307 	/* Lock out everyone else while we are manipulating the protosw. */
308 	mtx_lock(&Giant);
309 
310 	/* The protocol must exist and only once. */
311 	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
312 		if ((pr->pr_type == type) && (pr->pr_protocol == protocol)) {
313 			if (dpr != NULL) {
314 				mtx_unlock(&Giant);
315 				return (EMLINK);   /* Should not happen! */
316 			} else
317 				dpr = pr;
318 		}
319 	}
320 
321 	/* Protocol does not exist. */
322 	if (dpr == NULL) {
323 		mtx_unlock(&Giant);
324 		return (EPROTONOSUPPORT);
325 	}
326 
327 	/* De-orbit the protocol and make the slot available again. */
328 	dpr->pr_type = 0;
329 	dpr->pr_domain = dp;
330 	dpr->pr_protocol = PROTO_SPACER;
331 	dpr->pr_flags = 0;
332 	dpr->pr_input = NULL;
333 	dpr->pr_output = NULL;
334 	dpr->pr_ctlinput = NULL;
335 	dpr->pr_ctloutput = NULL;
336 	dpr->pr_ousrreq = NULL;
337 	dpr->pr_init = NULL;
338 	dpr->pr_fasttimo = NULL;
339 	dpr->pr_slowtimo = NULL;
340 	dpr->pr_drain = NULL;
341 	dpr->pr_usrreqs = &nousrreqs;
342 
343 	/* Job is done, not more protection required. */
344 	mtx_unlock(&Giant);
345 
346 	return (0);
347 }
348 
349 void
350 pfctlinput(cmd, sa)
351 	int cmd;
352 	struct sockaddr *sa;
353 {
354 	register struct domain *dp;
355 	register struct protosw *pr;
356 
357 	for (dp = domains; dp; dp = dp->dom_next)
358 		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
359 			if (pr->pr_ctlinput)
360 				(*pr->pr_ctlinput)(cmd, sa, (void *)0);
361 }
362 
363 void
364 pfctlinput2(cmd, sa, ctlparam)
365 	int cmd;
366 	struct sockaddr *sa;
367 	void *ctlparam;
368 {
369 	struct domain *dp;
370 	struct protosw *pr;
371 
372 	if (!sa)
373 		return;
374 	for (dp = domains; dp; dp = dp->dom_next) {
375 		/*
376 		 * the check must be made by xx_ctlinput() anyways, to
377 		 * make sure we use data item pointed to by ctlparam in
378 		 * correct way.  the following check is made just for safety.
379 		 */
380 		if (dp->dom_family != sa->sa_family)
381 			continue;
382 
383 		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
384 			if (pr->pr_ctlinput)
385 				(*pr->pr_ctlinput)(cmd, sa, ctlparam);
386 	}
387 }
388 
389 static void
390 pfslowtimo(arg)
391 	void *arg;
392 {
393 	register struct domain *dp;
394 	register struct protosw *pr;
395 
396 	NET_ASSERT_GIANT();
397 
398 	for (dp = domains; dp; dp = dp->dom_next)
399 		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
400 			if (pr->pr_slowtimo)
401 				(*pr->pr_slowtimo)();
402 	callout_reset(&pfslow_callout, hz/2, pfslowtimo, NULL);
403 }
404 
405 static void
406 pffasttimo(arg)
407 	void *arg;
408 {
409 	register struct domain *dp;
410 	register struct protosw *pr;
411 
412 	NET_ASSERT_GIANT();
413 
414 	for (dp = domains; dp; dp = dp->dom_next)
415 		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
416 			if (pr->pr_fasttimo)
417 				(*pr->pr_fasttimo)();
418 	callout_reset(&pffast_callout, hz/5, pffasttimo, NULL);
419 }
420