raw_usrreq.c revision 1.37 1 /* $NetBSD: raw_usrreq.c,v 1.37 2011/07/17 20:54:52 joerg Exp $ */
2
3 /*
4 * Copyright (c) 1980, 1986, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * @(#)raw_usrreq.c 8.1 (Berkeley) 6/10/93
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: raw_usrreq.c,v 1.37 2011/07/17 20:54:52 joerg Exp $");
36
37 #include <sys/param.h>
38 #include <sys/mbuf.h>
39 #include <sys/domain.h>
40 #include <sys/protosw.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/errno.h>
44 #include <sys/systm.h>
45 #include <sys/proc.h>
46 #include <sys/kauth.h>
47
48 #include <net/if.h>
49 #include <net/route.h>
50 #include <net/netisr.h>
51 #include <net/raw_cb.h>
52
53 /*
54 * Initialize raw connection block q.
55 */
56 void
57 raw_init(void)
58 {
59
60 LIST_INIT(&rawcb);
61 }
62
63 static inline int
64 equal(const struct sockaddr *a1, const struct sockaddr *a2)
65 {
66 return memcmp(a1, a2, a1->sa_len) == 0;
67 }
68
69 /*
70 * Raw protocol input routine. Find the socket
71 * associated with the packet(s) and move them over. If
72 * nothing exists for this packet, drop it.
73 */
74 /*
75 * Raw protocol interface.
76 */
77 void
78 raw_input(struct mbuf *m0, ...)
79 {
80 struct rawcb *rp;
81 struct mbuf *m = m0;
82 struct socket *last;
83 va_list ap;
84 struct sockproto *proto;
85 struct sockaddr *src, *dst;
86
87 KASSERT(mutex_owned(softnet_lock));
88
89 va_start(ap, m0);
90 proto = va_arg(ap, struct sockproto *);
91 src = va_arg(ap, struct sockaddr *);
92 dst = va_arg(ap, struct sockaddr *);
93 va_end(ap);
94
95 last = NULL;
96 LIST_FOREACH(rp, &rawcb, rcb_list) {
97 if (rp->rcb_proto.sp_family != proto->sp_family)
98 continue;
99 if (rp->rcb_proto.sp_protocol &&
100 rp->rcb_proto.sp_protocol != proto->sp_protocol)
101 continue;
102 /*
103 * We assume the lower level routines have
104 * placed the address in a canonical format
105 * suitable for a structure comparison.
106 *
107 * Note that if the lengths are not the same
108 * the comparison will fail at the first byte.
109 */
110 if (rp->rcb_laddr && !equal(rp->rcb_laddr, dst))
111 continue;
112 if (rp->rcb_faddr && !equal(rp->rcb_faddr, src))
113 continue;
114 if (last != NULL) {
115 struct mbuf *n;
116 if ((n = m_copy(m, 0, M_COPYALL)) == NULL)
117 ;
118 else if (sbappendaddr(&last->so_rcv, src, n, NULL) == 0)
119 /* should notify about lost packet */
120 m_freem(n);
121 else {
122 sorwakeup(last);
123 }
124 }
125 last = rp->rcb_socket;
126 }
127 if (last == NULL || sbappendaddr(&last->so_rcv, src, m, NULL) == 0)
128 m_freem(m);
129 else {
130 sorwakeup(last);
131 }
132 }
133
134 /*ARGSUSED*/
135 void *
136 raw_ctlinput(int cmd, const struct sockaddr *arg, void *d)
137 {
138
139 if ((unsigned)cmd >= PRC_NCMDS)
140 return NULL;
141 return NULL;
142 /* INCOMPLETE */
143 }
144
145 void
146 raw_setsockaddr(struct rawcb *rp, struct mbuf *nam)
147 {
148
149 nam->m_len = rp->rcb_laddr->sa_len;
150 memcpy(mtod(nam, void *), rp->rcb_laddr, (size_t)nam->m_len);
151 }
152
153 void
154 raw_setpeeraddr(struct rawcb *rp, struct mbuf *nam)
155 {
156
157 nam->m_len = rp->rcb_faddr->sa_len;
158 memcpy(mtod(nam, void *), rp->rcb_faddr, (size_t)nam->m_len);
159 }
160
161 /*ARGSUSED*/
162 int
163 raw_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
164 struct mbuf *control, struct lwp *l)
165 {
166 struct rawcb *rp;
167 int s;
168 int error = 0;
169
170 if (req == PRU_CONTROL)
171 return (EOPNOTSUPP);
172
173 s = splsoftnet();
174 KERNEL_LOCK(1, NULL);
175 rp = sotorawcb(so);
176 #ifdef DIAGNOSTIC
177 if (req != PRU_SEND && req != PRU_SENDOOB && control)
178 panic("raw_usrreq: unexpected control mbuf");
179 #endif
180 if (rp == NULL && req != PRU_ATTACH) {
181 error = EINVAL;
182 goto release;
183 }
184
185 switch (req) {
186
187 /*
188 * Allocate a raw control block and fill in the
189 * necessary info to allow packets to be routed to
190 * the appropriate raw interface routine.
191 */
192 case PRU_ATTACH:
193 sosetlock(so);
194 if (l == NULL)
195 break;
196
197 /* XXX: raw socket permissions are checked in socreate() */
198
199 error = raw_attach(so, (int)(long)nam);
200 break;
201
202 /*
203 * Destroy state just before socket deallocation.
204 * Flush data or not depending on the options.
205 */
206 case PRU_DETACH:
207 raw_detach(rp);
208 break;
209
210 /*
211 * If a socket isn't bound to a single address,
212 * the raw input routine will hand it anything
213 * within that protocol family (assuming there's
214 * nothing else around it should go to).
215 */
216 case PRU_BIND:
217 case PRU_LISTEN:
218 case PRU_CONNECT:
219 case PRU_CONNECT2:
220 error = EOPNOTSUPP;
221 break;
222
223 case PRU_DISCONNECT:
224 soisdisconnected(so);
225 raw_disconnect(rp);
226 break;
227
228 /*
229 * Mark the connection as being incapable of further input.
230 */
231 case PRU_SHUTDOWN:
232 socantsendmore(so);
233 break;
234
235 case PRU_RCVD:
236 error = EOPNOTSUPP;
237 break;
238
239 /*
240 * Ship a packet out. The appropriate raw output
241 * routine handles any massaging necessary.
242 */
243 case PRU_SEND:
244 if (control && control->m_len) {
245 m_freem(control);
246 m_freem(m);
247 error = EINVAL;
248 break;
249 }
250 if (nam) {
251 if ((so->so_state & SS_ISCONNECTED) != 0) {
252 error = EISCONN;
253 goto die;
254 }
255 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
256 NULL, nam, NULL, l);
257 if (error) {
258 die:
259 m_freem(m);
260 break;
261 }
262 } else {
263 if ((so->so_state & SS_ISCONNECTED) == 0) {
264 error = ENOTCONN;
265 goto die;
266 }
267 }
268 error = (*so->so_proto->pr_output)(m, so);
269 if (nam)
270 raw_disconnect(rp);
271 break;
272
273 case PRU_SENSE:
274 /*
275 * stat: don't bother with a blocksize.
276 */
277 error = 0;
278 break;
279
280 /*
281 * Not supported.
282 */
283 case PRU_RCVOOB:
284 error = EOPNOTSUPP;
285 break;
286
287 case PRU_SENDOOB:
288 m_freem(control);
289 m_freem(m);
290 error = EOPNOTSUPP;
291 break;
292
293 case PRU_SOCKADDR:
294 if (rp->rcb_laddr == NULL) {
295 error = EINVAL;
296 break;
297 }
298 raw_setsockaddr(rp, nam);
299 break;
300
301 case PRU_PEERADDR:
302 if (rp->rcb_faddr == NULL) {
303 error = ENOTCONN;
304 break;
305 }
306 raw_setpeeraddr(rp, nam);
307 break;
308
309 default:
310 panic("raw_usrreq");
311 }
312
313 release:
314 KERNEL_UNLOCK_ONE(NULL);
315 splx(s);
316 return (error);
317 }
318