xref: /openbsd/sys/kern/uipc_domain.c (revision 60728a2f)
1 /*	$OpenBSD: uipc_domain.c,v 1.68 2024/08/16 09:20:34 mvs 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 "bpfilter.h"
45 #include "pflow.h"
46 
47 const struct domain *const domains[] = {
48 #ifdef MPLS
49 	&mplsdomain,
50 #endif
51 #if defined (IPSEC) || defined (TCP_SIGNATURE)
52 	&pfkeydomain,
53 #endif
54 #ifdef INET6
55 	&inet6domain,
56 #endif /* INET6 */
57 	&inetdomain,
58 	&unixdomain,
59 	&routedomain,
60 	NULL
61 };
62 
63 void		pffasttimo(void *);
64 void		pfslowtimo(void *);
65 
66 void
domaininit(void)67 domaininit(void)
68 {
69 	const struct domain *dp;
70 	const struct protosw *pr;
71 	static struct timeout pffast_timeout;
72 	static struct timeout pfslow_timeout;
73 	int i;
74 
75 	for (i = 0; (dp = domains[i]) != NULL; i++) {
76 		if (dp->dom_init)
77 			(*dp->dom_init)();
78 		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
79 			if (pr->pr_init)
80 				(*pr->pr_init)();
81 	}
82 
83 	/*
84 	 * max_linkhdr of 64 was chosen to encompass tunnelling
85 	 * traffic in IP payloads, eg, by etherip(4) or gif(4),
86 	 * without needing to prepend an mbuf to fit those
87 	 * headers.
88 	 */
89 	if (max_linkhdr < 64)
90 		max_linkhdr = 64;
91 
92 	max_hdr = max_linkhdr + max_protohdr;
93 	timeout_set_flags(&pffast_timeout, pffasttimo, &pffast_timeout,
94 	    KCLOCK_NONE, TIMEOUT_PROC | TIMEOUT_MPSAFE);
95 	timeout_set_flags(&pfslow_timeout, pfslowtimo, &pfslow_timeout,
96 	    KCLOCK_NONE, TIMEOUT_PROC | TIMEOUT_MPSAFE);
97 	timeout_add(&pffast_timeout, 1);
98 	timeout_add(&pfslow_timeout, 1);
99 }
100 
101 const struct domain *
pffinddomain(int family)102 pffinddomain(int family)
103 {
104 	const struct domain *dp;
105 	int i;
106 
107 	for (i = 0; (dp = domains[i]) != NULL; i++) {
108 		if (dp->dom_family == family)
109 			return (dp);
110 	}
111 	return (NULL);
112 }
113 
114 const struct protosw *
pffindtype(int family,int type)115 pffindtype(int family, int type)
116 {
117 	const struct domain *dp;
118 	const struct protosw *pr;
119 
120 	dp = pffinddomain(family);
121 	if (dp == NULL)
122 		return (NULL);
123 
124 	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
125 		if (pr->pr_type && pr->pr_type == type)
126 			return (pr);
127 	return (NULL);
128 }
129 
130 const struct protosw *
pffindproto(int family,int protocol,int type)131 pffindproto(int family, int protocol, int type)
132 {
133 	const struct domain *dp;
134 	const struct protosw *pr;
135 	const struct protosw *maybe = NULL;
136 
137 	if (family == PF_UNSPEC)
138 		return (NULL);
139 
140 	dp = pffinddomain(family);
141 	if (dp == NULL)
142 		return (NULL);
143 
144 	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
145 		if ((pr->pr_protocol == protocol) && (pr->pr_type == type))
146 			return (pr);
147 
148 		if (type == SOCK_RAW && pr->pr_type == SOCK_RAW &&
149 		    pr->pr_protocol == 0 && maybe == NULL)
150 			maybe = pr;
151 	}
152 	return (maybe);
153 }
154 
155 static int
net_link_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen)156 net_link_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
157     void *newp, size_t newlen)
158 {
159 	int node;
160 	int error;
161 
162 	/*
163 	 * All sysctl names at this level are nonterminal.
164 	 */
165 	if (namelen < 2)
166 		return (EISDIR);		/* overloaded */
167 	node = name[0];
168 
169 	namelen--;
170 	name++;
171 
172 	switch (node) {
173 	case NET_LINK_IFRXQ:
174 		error = net_ifiq_sysctl(name, namelen, oldp, oldlenp,
175 		    newp, newlen);
176 		break;
177 
178 	default:
179 		error = ENOPROTOOPT;
180 		break;
181 	}
182 
183 	return (error);
184 }
185 
186 int
net_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen,struct proc * p)187 net_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
188     size_t newlen, struct proc *p)
189 {
190 	const struct domain *dp;
191 	const struct protosw *pr;
192 	int family, protocol;
193 
194 	/*
195 	 * All sysctl names at this level are nonterminal.
196 	 * Usually: next two components are protocol family and protocol
197 	 *	number, then at least one addition component.
198 	 */
199 	if (namelen < 2)
200 		return (EISDIR);		/* overloaded */
201 	family = name[0];
202 
203 	if (family == PF_UNSPEC)
204 		return (0);
205 	if (family == PF_LINK)
206 		return (net_link_sysctl(name + 1, namelen - 1, oldp, oldlenp,
207 		    newp, newlen));
208 	if (family == PF_UNIX)
209 		return (uipc_sysctl(name + 1, namelen - 1, oldp, oldlenp,
210 		    newp, newlen));
211 #if NBPFILTER > 0
212 	if (family == PF_BPF)
213 		return (bpf_sysctl(name + 1, namelen - 1, oldp, oldlenp,
214 		    newp, newlen));
215 #endif
216 #if NPFLOW > 0
217 	if (family == PF_PFLOW)
218 		return (pflow_sysctl(name + 1, namelen - 1, oldp, oldlenp,
219 		    newp, newlen));
220 #endif
221 #ifdef PIPEX
222 	if (family == PF_PIPEX)
223 		return (pipex_sysctl(name + 1, namelen - 1, oldp, oldlenp,
224 		    newp, newlen));
225 #endif
226 #ifdef MPLS
227 	if (family == PF_MPLS)
228 		return (mpls_sysctl(name + 1, namelen - 1, oldp, oldlenp,
229 		    newp, newlen));
230 #endif
231 	dp = pffinddomain(family);
232 	if (dp == NULL)
233 		return (ENOPROTOOPT);
234 
235 	if (namelen < 3)
236 		return (EISDIR);		/* overloaded */
237 	protocol = name[1];
238 	for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
239 		if (pr->pr_protocol == protocol && pr->pr_sysctl) {
240 			size_t savelen;
241 			int error;
242 
243 			if ((pr->pr_flags & PR_MPSYSCTL) == 0) {
244 				savelen = *oldlenp;
245 				if ((error = sysctl_vslock(oldp, savelen)))
246 					return (error);
247 			}
248 			error = (*pr->pr_sysctl)(name + 2, namelen - 2,
249 			    oldp, oldlenp, newp, newlen);
250 			if ((pr->pr_flags & PR_MPSYSCTL) == 0)
251 				sysctl_vsunlock(oldp, savelen);
252 
253 			return (error);
254 		}
255 	return (ENOPROTOOPT);
256 }
257 
258 void
pfctlinput(int cmd,struct sockaddr * sa)259 pfctlinput(int cmd, struct sockaddr *sa)
260 {
261 	const struct domain *dp;
262 	const struct protosw *pr;
263 	int i;
264 
265 	NET_ASSERT_LOCKED();
266 
267 	for (i = 0; (dp = domains[i]) != NULL; i++) {
268 		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
269 			if (pr->pr_ctlinput)
270 				(*pr->pr_ctlinput)(cmd, sa, 0, NULL);
271 	}
272 }
273 
274 void
pfslowtimo(void * arg)275 pfslowtimo(void *arg)
276 {
277 	struct timeout *to = (struct timeout *)arg;
278 	const struct domain *dp;
279 	const struct protosw *pr;
280 	int i;
281 
282 	for (i = 0; (dp = domains[i]) != NULL; i++) {
283 		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
284 			if (pr->pr_slowtimo)
285 				(*pr->pr_slowtimo)();
286 	}
287 	timeout_add_msec(to, 500);
288 }
289 
290 void
pffasttimo(void * arg)291 pffasttimo(void *arg)
292 {
293 	struct timeout *to = (struct timeout *)arg;
294 	const struct domain *dp;
295 	const struct protosw *pr;
296 	int i;
297 
298 	for (i = 0; (dp = domains[i]) != NULL; i++) {
299 		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
300 			if (pr->pr_fasttimo)
301 				(*pr->pr_fasttimo)();
302 	}
303 	timeout_add_msec(to, 200);
304 }
305