xref: /dragonfly/sys/net/raw_usrreq.c (revision 6e278935)
1 /*
2  * Copyright (c) 1980, 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  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	@(#)raw_usrreq.c	8.1 (Berkeley) 6/10/93
34  * $FreeBSD: src/sys/net/raw_usrreq.c,v 1.18 1999/08/28 00:48:28 peter Exp $
35  * $DragonFly: src/sys/net/raw_usrreq.c,v 1.14 2007/06/24 20:00:00 dillon Exp $
36  */
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/mbuf.h>
41 #include <sys/proc.h>
42 #include <sys/priv.h>
43 #include <sys/protosw.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 
47 #include <sys/socketvar2.h>
48 #include <sys/msgport2.h>
49 
50 #include <net/raw_cb.h>
51 
52 
53 static struct lwkt_token raw_token = LWKT_TOKEN_INITIALIZER(raw_token);
54 
55 /*
56  * Initialize raw connection block q.
57  */
58 void
59 raw_init(void)
60 {
61 	LIST_INIT(&rawcb_list);
62 }
63 
64 /************************************************************************
65  *			 RAW PROTOCOL INTERFACE				*
66  ************************************************************************/
67 
68 /*
69  * Raw protocol input routine.  Find the socket associated with the packet(s)
70  * and move them over.  If nothing exists for this packet, drop it.  This
71  * routine is indirect called via rts_input() and will be serialized on
72  * cpu 0.
73  *
74  * Most other raw protocol interface functions are also serialized XXX.
75  */
76 void
77 raw_input(struct mbuf *m0, const struct sockproto *proto,
78 	  const struct sockaddr *src, const struct sockaddr *dst,
79 	  const struct rawcb *skip)
80 {
81 	struct rawcb *rp;
82 	struct mbuf *m = m0;
83 	struct socket *last;
84 
85 	lwkt_gettoken(&raw_token);
86 
87 	last = NULL;
88 	LIST_FOREACH(rp, &rawcb_list, list) {
89 		if (rp == skip)
90 			continue;
91 		if (rp->rcb_proto.sp_family != proto->sp_family)
92 			continue;
93 		if (rp->rcb_proto.sp_protocol  &&
94 		    rp->rcb_proto.sp_protocol != proto->sp_protocol)
95 			continue;
96 		/*
97 		 * We assume the lower level routines have
98 		 * placed the address in a canonical format
99 		 * suitable for a structure comparison.
100 		 *
101 		 * Note that if the lengths are not the same
102 		 * the comparison will fail at the first byte.
103 		 */
104 		if (rp->rcb_laddr && !sa_equal(rp->rcb_laddr, dst))
105 			continue;
106 		if (rp->rcb_faddr && !sa_equal(rp->rcb_faddr, src))
107 			continue;
108 		if (last) {
109 			struct mbuf *n;
110 
111 			n = m_copypacket(m, MB_DONTWAIT);
112 			if (n != NULL) {
113 				lwkt_gettoken(&last->so_rcv.ssb_token);
114 				if (ssb_appendaddr(&last->so_rcv, src, n,
115 						 NULL) == 0) {
116 					/* should notify about lost packet */
117 					m_freem(n);
118 				} else {
119 					sorwakeup(last);
120 				}
121 				lwkt_reltoken(&last->so_rcv.ssb_token);
122 			}
123 		}
124 		last = rp->rcb_socket;
125 	}
126 	if (last) {
127 		lwkt_gettoken(&last->so_rcv.ssb_token);
128 		if (ssb_appendaddr(&last->so_rcv, src, m, NULL) == 0)
129 			m_freem(m);
130 		else
131 			sorwakeup(last);
132 		lwkt_reltoken(&last->so_rcv.ssb_token);
133 	} else {
134 		m_freem(m);
135 	}
136 	lwkt_reltoken(&raw_token);
137 }
138 
139 /*
140  * nm_cmd, nm_arg, nm_extra
141  */
142 void
143 raw_ctlinput(netmsg_t msg)
144 {
145 	int error = 0;
146 
147 	if (msg->ctlinput.nm_cmd < 0 || msg->ctlinput.nm_cmd > PRC_NCMDS)
148 		;
149 	lwkt_replymsg(&msg->lmsg, error);
150 }
151 
152 /*
153  * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
154  *	 will sofree() it when we return.
155  */
156 static void
157 raw_uabort(netmsg_t msg)
158 {
159 	struct rawcb *rp = sotorawcb(msg->base.nm_so);
160 	int error;
161 
162 	if (rp) {
163 		raw_disconnect(rp);
164 		soisdisconnected(msg->base.nm_so);
165 		error = 0;
166 	} else {
167 		error = EINVAL;
168 	}
169 	lwkt_replymsg(&msg->lmsg, error);
170 }
171 
172 /* pru_accept is EOPNOTSUPP */
173 
174 static void
175 raw_uattach(netmsg_t msg)
176 {
177 	struct socket *so = msg->base.nm_so;
178 	int proto = msg->attach.nm_proto;
179 	struct pru_attach_info *ai = msg->attach.nm_ai;
180 	struct rawcb *rp;
181 	int error;
182 
183 	rp = sotorawcb(so);
184 	if (rp) {
185 		error = priv_check_cred(ai->p_ucred, PRIV_ROOT, NULL_CRED_OKAY);
186 		if (error == 0)
187 			error = raw_attach(so, proto, ai->sb_rlimit);
188 	} else {
189 		error = EINVAL;
190 	}
191 	lwkt_replymsg(&msg->lmsg, error);
192 }
193 
194 static void
195 raw_ubind(netmsg_t msg)
196 {
197 	lwkt_replymsg(&msg->lmsg, EINVAL);
198 }
199 
200 static void
201 raw_uconnect(netmsg_t msg)
202 {
203 	lwkt_replymsg(&msg->lmsg, EINVAL);
204 }
205 
206 /* pru_connect2 is EOPNOTSUPP */
207 /* pru_control is EOPNOTSUPP */
208 
209 static void
210 raw_udetach(netmsg_t msg)
211 {
212 	struct rawcb *rp = sotorawcb(msg->base.nm_so);
213 	int error;
214 
215 	if (rp) {
216 		raw_detach(rp);
217 		error = 0;
218 	} else {
219 		error = EINVAL;
220 	}
221 	lwkt_replymsg(&msg->lmsg, error);
222 }
223 
224 static void
225 raw_udisconnect(netmsg_t msg)
226 {
227 	struct socket *so = msg->base.nm_so;
228 	struct rawcb *rp;
229 	int error;
230 
231 	rp = sotorawcb(so);
232 	if (rp == NULL) {
233 		error = EINVAL;
234 	} else if (rp->rcb_faddr == NULL) {
235 		error = ENOTCONN;
236 	} else {
237 		soreference(so);
238 		raw_disconnect(rp);
239 		soisdisconnected(so);
240 		sofree(so);
241 		error = 0;
242 	}
243 	lwkt_replymsg(&msg->lmsg, error);
244 }
245 
246 /* pru_listen is EOPNOTSUPP */
247 
248 static void
249 raw_upeeraddr(netmsg_t msg)
250 {
251 	struct rawcb *rp = sotorawcb(msg->base.nm_so);
252 	int error;
253 
254 	if (rp == NULL) {
255 		error = EINVAL;
256 	} else if (rp->rcb_faddr == NULL) {
257 		error = ENOTCONN;
258 	} else {
259 		*msg->peeraddr.nm_nam = dup_sockaddr(rp->rcb_faddr);
260 		error = 0;
261 	}
262 	lwkt_replymsg(&msg->lmsg, error);
263 }
264 
265 /* pru_rcvd is EOPNOTSUPP */
266 /* pru_rcvoob is EOPNOTSUPP */
267 
268 static void
269 raw_usend(netmsg_t msg)
270 {
271 	struct socket *so = msg->base.nm_so;
272 	struct mbuf *m = msg->send.nm_m;
273 	struct mbuf *control = msg->send.nm_control;
274 	struct rawcb *rp = sotorawcb(so);
275 	struct pr_output_info oi;
276 	int flags = msg->send.nm_flags;
277 	int error;
278 
279 	if (rp == NULL) {
280 		error = EINVAL;
281 		goto release;
282 	}
283 
284 	if (flags & PRUS_OOB) {
285 		error = EOPNOTSUPP;
286 		goto release;
287 	}
288 
289 	if (control && control->m_len) {
290 		error = EOPNOTSUPP;
291 		goto release;
292 	}
293 	if (msg->send.nm_addr) {
294 		if (rp->rcb_faddr) {
295 			error = EISCONN;
296 			goto release;
297 		}
298 		rp->rcb_faddr = msg->send.nm_addr;
299 	} else if (rp->rcb_faddr == NULL) {
300 		error = ENOTCONN;
301 		goto release;
302 	}
303 	oi.p_pid = msg->send.nm_td->td_proc->p_pid;
304 	error = (*so->so_proto->pr_output)(m, so, &oi);
305 	m = NULL;
306 	if (msg->send.nm_addr)
307 		rp->rcb_faddr = NULL;
308 release:
309 	if (m != NULL)
310 		m_freem(m);
311 	lwkt_replymsg(&msg->lmsg, error);
312 }
313 
314 /* pru_sense is null */
315 
316 static void
317 raw_ushutdown(netmsg_t msg)
318 {
319 	struct rawcb *rp = sotorawcb(msg->base.nm_so);
320 	int error;
321 
322 	if (rp) {
323 		socantsendmore(msg->base.nm_so);
324 		error = 0;
325 	} else {
326 		error = EINVAL;
327 	}
328 	lwkt_replymsg(&msg->lmsg, error);
329 }
330 
331 static void
332 raw_usockaddr(netmsg_t msg)
333 {
334 	struct rawcb *rp = sotorawcb(msg->base.nm_so);
335 	int error;
336 
337 	if (rp == NULL) {
338 		error = EINVAL;
339 	} else if (rp->rcb_laddr == NULL) {
340 		error = EINVAL;
341 	} else {
342 		*msg->sockaddr.nm_nam = dup_sockaddr(rp->rcb_laddr);
343 		error = 0;
344 	}
345 	lwkt_replymsg(&msg->lmsg, error);
346 }
347 
348 struct pr_usrreqs raw_usrreqs = {
349 	.pru_abort = raw_uabort,
350 	.pru_accept = pr_generic_notsupp,
351 	.pru_attach = raw_uattach,
352 	.pru_bind = raw_ubind,
353 	.pru_connect = raw_uconnect,
354 	.pru_connect2 = pr_generic_notsupp,
355 	.pru_control = pr_generic_notsupp,
356 	.pru_detach = raw_udetach,
357 	.pru_disconnect = raw_udisconnect,
358 	.pru_listen = pr_generic_notsupp,
359 	.pru_peeraddr = raw_upeeraddr,
360 	.pru_rcvd = pr_generic_notsupp,
361 	.pru_rcvoob = pr_generic_notsupp,
362 	.pru_send = raw_usend,
363 	.pru_sense = pru_sense_null,
364 	.pru_shutdown = raw_ushutdown,
365 	.pru_sockaddr = raw_usockaddr,
366 	.pru_sosend = sosend,
367 	.pru_soreceive = soreceive
368 };
369