xref: /openbsd/sys/kern/uipc_domain.c (revision 6fb93e47)
1 /*	$OpenBSD: uipc_domain.c,v 1.69 2024/12/15 11:00:05 dlg Exp $	*/
2 /*	$NetBSD: uipc_domain.c,v 1.14 1996/02/09 19:00:44 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1982, 1986, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *	@(#)uipc_domain.c	8.2 (Berkeley) 10/18/93
33  */
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/systm.h>
41 #include <sys/sysctl.h>
42 #include <sys/timeout.h>
43 
44 #include "af_frame.h"
45 #include "bpfilter.h"
46 #include "pflow.h"
47 
48 #if NAF_FRAME > 0
49 extern const struct domain framedomain;
50 #endif
51 
52 const struct domain *const domains[] = {
53 #ifdef MPLS
54 	&mplsdomain,
55 #endif
56 #if defined (IPSEC) || defined (TCP_SIGNATURE)
57 	&pfkeydomain,
58 #endif
59 #ifdef INET6
60 	&inet6domain,
61 #endif /* INET6 */
62 	&inetdomain,
63 	&unixdomain,
64 	&routedomain,
65 #if NAF_FRAME > 0
66 	&framedomain,
67 #endif
68 	NULL
69 };
70 
71 void		pffasttimo(void *);
72 void		pfslowtimo(void *);
73 
74 void
domaininit(void)75 domaininit(void)
76 {
77 	const struct domain *dp;
78 	const struct protosw *pr;
79 	static struct timeout pffast_timeout;
80 	static struct timeout pfslow_timeout;
81 	int i;
82 
83 	for (i = 0; (dp = domains[i]) != NULL; i++) {
84 		if (dp->dom_init)
85 			(*dp->dom_init)();
86 		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
87 			if (pr->pr_init)
88 				(*pr->pr_init)();
89 	}
90 
91 	/*
92 	 * max_linkhdr of 64 was chosen to encompass tunnelling
93 	 * traffic in IP payloads, eg, by etherip(4) or gif(4),
94 	 * without needing to prepend an mbuf to fit those
95 	 * headers.
96 	 */
97 	if (max_linkhdr < 64)
98 		max_linkhdr = 64;
99 
100 	max_hdr = max_linkhdr + max_protohdr;
101 	timeout_set_flags(&pffast_timeout, pffasttimo, &pffast_timeout,
102 	    KCLOCK_NONE, TIMEOUT_PROC | TIMEOUT_MPSAFE);
103 	timeout_set_flags(&pfslow_timeout, pfslowtimo, &pfslow_timeout,
104 	    KCLOCK_NONE, TIMEOUT_PROC | TIMEOUT_MPSAFE);
105 	timeout_add(&pffast_timeout, 1);
106 	timeout_add(&pfslow_timeout, 1);
107 }
108 
109 const struct domain *
pffinddomain(int family)110 pffinddomain(int family)
111 {
112 	const struct domain *dp;
113 	int i;
114 
115 	for (i = 0; (dp = domains[i]) != NULL; i++) {
116 		if (dp->dom_family == family)
117 			return (dp);
118 	}
119 	return (NULL);
120 }
121 
122 const struct protosw *
pffindtype(int family,int type)123 pffindtype(int family, int type)
124 {
125 	const struct domain *dp;
126 	const struct protosw *pr;
127 
128 	dp = pffinddomain(family);
129 	if (dp == NULL)
130 		return (NULL);
131 
132 	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
133 		if (pr->pr_type && pr->pr_type == type)
134 			return (pr);
135 	return (NULL);
136 }
137 
138 const struct protosw *
pffindproto(int family,int protocol,int type)139 pffindproto(int family, int protocol, int type)
140 {
141 	const struct domain *dp;
142 	const struct protosw *pr;
143 	const struct protosw *maybe = NULL;
144 
145 	if (family == PF_UNSPEC)
146 		return (NULL);
147 
148 	dp = pffinddomain(family);
149 	if (dp == NULL)
150 		return (NULL);
151 
152 	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
153 		if ((pr->pr_protocol == protocol) && (pr->pr_type == type))
154 			return (pr);
155 
156 		if (type == SOCK_RAW && pr->pr_type == SOCK_RAW &&
157 		    pr->pr_protocol == 0 && maybe == NULL)
158 			maybe = pr;
159 	}
160 	return (maybe);
161 }
162 
163 static int
net_link_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen)164 net_link_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
165     void *newp, size_t newlen)
166 {
167 	int node;
168 	int error;
169 
170 	/*
171 	 * All sysctl names at this level are nonterminal.
172 	 */
173 	if (namelen < 2)
174 		return (EISDIR);		/* overloaded */
175 	node = name[0];
176 
177 	namelen--;
178 	name++;
179 
180 	switch (node) {
181 	case NET_LINK_IFRXQ:
182 		error = net_ifiq_sysctl(name, namelen, oldp, oldlenp,
183 		    newp, newlen);
184 		break;
185 
186 	default:
187 		error = ENOPROTOOPT;
188 		break;
189 	}
190 
191 	return (error);
192 }
193 
194 int
net_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen,struct proc * p)195 net_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
196     size_t newlen, struct proc *p)
197 {
198 	const struct domain *dp;
199 	const struct protosw *pr;
200 	int family, protocol;
201 
202 	/*
203 	 * All sysctl names at this level are nonterminal.
204 	 * Usually: next two components are protocol family and protocol
205 	 *	number, then at least one addition component.
206 	 */
207 	if (namelen < 2)
208 		return (EISDIR);		/* overloaded */
209 	family = name[0];
210 
211 	if (family == PF_UNSPEC)
212 		return (0);
213 	if (family == PF_LINK)
214 		return (net_link_sysctl(name + 1, namelen - 1, oldp, oldlenp,
215 		    newp, newlen));
216 	if (family == PF_UNIX)
217 		return (uipc_sysctl(name + 1, namelen - 1, oldp, oldlenp,
218 		    newp, newlen));
219 #if NBPFILTER > 0
220 	if (family == PF_BPF)
221 		return (bpf_sysctl(name + 1, namelen - 1, oldp, oldlenp,
222 		    newp, newlen));
223 #endif
224 #if NPFLOW > 0
225 	if (family == PF_PFLOW)
226 		return (pflow_sysctl(name + 1, namelen - 1, oldp, oldlenp,
227 		    newp, newlen));
228 #endif
229 #ifdef PIPEX
230 	if (family == PF_PIPEX)
231 		return (pipex_sysctl(name + 1, namelen - 1, oldp, oldlenp,
232 		    newp, newlen));
233 #endif
234 #ifdef MPLS
235 	if (family == PF_MPLS)
236 		return (mpls_sysctl(name + 1, namelen - 1, oldp, oldlenp,
237 		    newp, newlen));
238 #endif
239 	dp = pffinddomain(family);
240 	if (dp == NULL)
241 		return (ENOPROTOOPT);
242 
243 	if (namelen < 3)
244 		return (EISDIR);		/* overloaded */
245 	protocol = name[1];
246 	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
247 		if (pr->pr_protocol == protocol && pr->pr_sysctl) {
248 			size_t savelen;
249 			int error;
250 
251 			if ((pr->pr_flags & PR_MPSYSCTL) == 0) {
252 				savelen = *oldlenp;
253 				if ((error = sysctl_vslock(oldp, savelen)))
254 					return (error);
255 			}
256 			error = (*pr->pr_sysctl)(name + 2, namelen - 2,
257 			    oldp, oldlenp, newp, newlen);
258 			if ((pr->pr_flags & PR_MPSYSCTL) == 0)
259 				sysctl_vsunlock(oldp, savelen);
260 
261 			return (error);
262 		}
263 	return (ENOPROTOOPT);
264 }
265 
266 void
pfctlinput(int cmd,struct sockaddr * sa)267 pfctlinput(int cmd, struct sockaddr *sa)
268 {
269 	const struct domain *dp;
270 	const struct protosw *pr;
271 	int i;
272 
273 	NET_ASSERT_LOCKED();
274 
275 	for (i = 0; (dp = domains[i]) != NULL; i++) {
276 		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
277 			if (pr->pr_ctlinput)
278 				(*pr->pr_ctlinput)(cmd, sa, 0, NULL);
279 	}
280 }
281 
282 void
pfslowtimo(void * arg)283 pfslowtimo(void *arg)
284 {
285 	struct timeout *to = (struct timeout *)arg;
286 	const struct domain *dp;
287 	const struct protosw *pr;
288 	int i;
289 
290 	for (i = 0; (dp = domains[i]) != NULL; i++) {
291 		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
292 			if (pr->pr_slowtimo)
293 				(*pr->pr_slowtimo)();
294 	}
295 	timeout_add_msec(to, 500);
296 }
297 
298 void
pffasttimo(void * arg)299 pffasttimo(void *arg)
300 {
301 	struct timeout *to = (struct timeout *)arg;
302 	const struct domain *dp;
303 	const struct protosw *pr;
304 	int i;
305 
306 	for (i = 0; (dp = domains[i]) != NULL; i++) {
307 		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
308 			if (pr->pr_fasttimo)
309 				(*pr->pr_fasttimo)();
310 	}
311 	timeout_add_msec(to, 200);
312 }
313