raw_usrreq.c revision 1.33 1 /* $NetBSD: raw_usrreq.c,v 1.33 2007/05/06 06:21:26 dyoung 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.33 2007/05/06 06:21:26 dyoung 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 #include <machine/stdarg.h>
54 /*
55 * Initialize raw connection block q.
56 */
57 void
58 raw_init(void)
59 {
60
61 LIST_INIT(&rawcb);
62 }
63
64 static inline int
65 equal(const struct sockaddr *a1, const struct sockaddr *a2)
66 {
67 return memcmp(a1, a2, a1->sa_len) == 0;
68 }
69
70 /*
71 * Raw protocol input routine. Find the socket
72 * associated with the packet(s) and move them over. If
73 * nothing exists for this packet, drop it.
74 */
75 /*
76 * Raw protocol interface.
77 */
78 void
79 raw_input(struct mbuf *m0, ...)
80 {
81 struct rawcb *rp;
82 struct mbuf *m = m0;
83 int sockets = 0;
84 struct socket *last;
85 va_list ap;
86 struct sockproto *proto;
87 struct sockaddr *src, *dst;
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 sockets++;
124 }
125 }
126 last = rp->rcb_socket;
127 }
128 if (last == NULL || sbappendaddr(&last->so_rcv, src, m, NULL) == 0)
129 m_freem(m);
130 else {
131 sorwakeup(last);
132 sockets++;
133 }
134 }
135
136 /*ARGSUSED*/
137 void *
138 raw_ctlinput(int cmd, const struct sockaddr *arg, void *d)
139 {
140
141 if ((unsigned)cmd >= PRC_NCMDS)
142 return NULL;
143 return NULL;
144 /* INCOMPLETE */
145 }
146
147 void
148 raw_setsockaddr(struct rawcb *rp, struct mbuf *nam)
149 {
150
151 nam->m_len = rp->rcb_laddr->sa_len;
152 memcpy(mtod(nam, void *), rp->rcb_laddr, (size_t)nam->m_len);
153 }
154
155 void
156 raw_setpeeraddr(struct rawcb *rp, struct mbuf *nam)
157 {
158
159 nam->m_len = rp->rcb_faddr->sa_len;
160 memcpy(mtod(nam, void *), rp->rcb_faddr, (size_t)nam->m_len);
161 }
162
163 /*ARGSUSED*/
164 int
165 raw_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
166 struct mbuf *control, struct lwp *l)
167 {
168 struct rawcb *rp;
169 int s;
170 int error = 0;
171
172 if (req == PRU_CONTROL)
173 return (EOPNOTSUPP);
174
175 s = splsoftnet();
176 rp = sotorawcb(so);
177 #ifdef DIAGNOSTIC
178 if (req != PRU_SEND && req != PRU_SENDOOB && control)
179 panic("raw_usrreq: unexpected control mbuf");
180 #endif
181 if (rp == NULL && req != PRU_ATTACH) {
182 error = EINVAL;
183 goto release;
184 }
185
186 switch (req) {
187
188 /*
189 * Allocate a raw control block and fill in the
190 * necessary info to allow packets to be routed to
191 * the appropriate raw interface routine.
192 */
193 case PRU_ATTACH:
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 return (0);
278
279 /*
280 * Not supported.
281 */
282 case PRU_RCVOOB:
283 error = EOPNOTSUPP;
284 break;
285
286 case PRU_SENDOOB:
287 m_freem(control);
288 m_freem(m);
289 error = EOPNOTSUPP;
290 break;
291
292 case PRU_SOCKADDR:
293 if (rp->rcb_laddr == NULL) {
294 error = EINVAL;
295 break;
296 }
297 raw_setsockaddr(rp, nam);
298 break;
299
300 case PRU_PEERADDR:
301 if (rp->rcb_faddr == NULL) {
302 error = ENOTCONN;
303 break;
304 }
305 raw_setpeeraddr(rp, nam);
306 break;
307
308 default:
309 panic("raw_usrreq");
310 }
311
312 release:
313 splx(s);
314 return (error);
315 }
316