raw_ip.c revision 1.31 1 /* $NetBSD: raw_ip.c,v 1.31 1996/06/23 12:12:49 mycroft Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1988, 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. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94
36 */
37
38 #include <sys/param.h>
39 #include <sys/malloc.h>
40 #include <sys/mbuf.h>
41 #include <sys/socket.h>
42 #include <sys/protosw.h>
43 #include <sys/socketvar.h>
44 #include <sys/errno.h>
45 #include <sys/systm.h>
46 #include <sys/proc.h>
47
48 #include <net/if.h>
49 #include <net/route.h>
50
51 #include <netinet/in.h>
52 #include <netinet/in_systm.h>
53 #include <netinet/ip.h>
54 #include <netinet/ip_var.h>
55 #include <netinet/ip_mroute.h>
56 #include <netinet/in_pcb.h>
57 #include <netinet/in_var.h>
58
59 #include <machine/stdarg.h>
60
61 struct inpcbtable rawcbtable;
62
63 int rip_bind __P((struct inpcb *, struct mbuf *));
64 int rip_connect __P((struct inpcb *, struct mbuf *));
65 void rip_disconnect __P((struct inpcb *));
66
67 /*
68 * Nominal space allocated to a raw ip socket.
69 */
70 #define RIPSNDQ 8192
71 #define RIPRCVQ 8192
72
73 /*
74 * Raw interface to IP protocol.
75 */
76
77 /*
78 * Initialize raw connection block q.
79 */
80 void
81 rip_init()
82 {
83
84 in_pcbinit(&rawcbtable, 1);
85 }
86
87 struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
88 /*
89 * Setup generic address and protocol structures
90 * for raw_input routine, then pass them along with
91 * mbuf chain.
92 */
93 void
94 #if __STDC__
95 rip_input(struct mbuf *m, ...)
96 #else
97 rip_input(m, va_alist)
98 struct mbuf *m;
99 va_dcl
100 #endif
101 {
102 register struct ip *ip = mtod(m, struct ip *);
103 register struct inpcb *inp;
104 struct socket *last = 0;
105
106 ripsrc.sin_addr = ip->ip_src;
107 for (inp = rawcbtable.inpt_queue.cqh_first;
108 inp != (struct inpcb *)&rawcbtable.inpt_queue;
109 inp = inp->inp_queue.cqe_next) {
110 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
111 continue;
112 if (inp->inp_laddr.s_addr != INADDR_ANY &&
113 inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
114 continue;
115 if (inp->inp_faddr.s_addr != INADDR_ANY &&
116 inp->inp_faddr.s_addr != ip->ip_src.s_addr)
117 continue;
118 if (last) {
119 struct mbuf *n;
120 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
121 if (sbappendaddr(&last->so_rcv,
122 sintosa(&ripsrc), n,
123 (struct mbuf *)0) == 0)
124 /* should notify about lost packet */
125 m_freem(n);
126 else
127 sorwakeup(last);
128 }
129 }
130 last = inp->inp_socket;
131 }
132 if (last) {
133 if (sbappendaddr(&last->so_rcv, sintosa(&ripsrc), m,
134 (struct mbuf *)0) == 0)
135 m_freem(m);
136 else
137 sorwakeup(last);
138 } else {
139 m_freem(m);
140 ipstat.ips_noproto++;
141 ipstat.ips_delivered--;
142 }
143 }
144
145 /*
146 * Generate IP header and pass packet to ip_output.
147 * Tack on options user may have setup with control call.
148 */
149 int
150 #if __STDC__
151 rip_output(struct mbuf *m, ...)
152 #else
153 rip_output(m, va_alist)
154 struct mbuf *m;
155 va_dcl
156 #endif
157 {
158 register struct inpcb *inp;
159 register struct ip *ip;
160 struct mbuf *opts;
161 int flags;
162 va_list ap;
163
164 va_start(ap, m);
165 inp = va_arg(ap, struct inpcb *);
166 va_end(ap);
167
168 flags =
169 (inp->inp_socket->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
170
171 /*
172 * If the user handed us a complete IP packet, use it.
173 * Otherwise, allocate an mbuf for a header and fill it in.
174 */
175 if ((inp->inp_flags & INP_HDRINCL) == 0) {
176 M_PREPEND(m, sizeof(struct ip), M_WAIT);
177 ip = mtod(m, struct ip *);
178 ip->ip_tos = 0;
179 ip->ip_off = 0;
180 ip->ip_p = inp->inp_ip.ip_p;
181 ip->ip_len = m->m_pkthdr.len;
182 ip->ip_src = inp->inp_laddr;
183 ip->ip_dst = inp->inp_faddr;
184 ip->ip_ttl = MAXTTL;
185 opts = inp->inp_options;
186 } else {
187 ip = mtod(m, struct ip *);
188 if (ip->ip_id == 0)
189 ip->ip_id = htons(ip_id++);
190 opts = NULL;
191 /* XXX prevent ip_output from overwriting header fields */
192 flags |= IP_RAWOUTPUT;
193 ipstat.ips_rawout++;
194 }
195 return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions));
196 }
197
198 /*
199 * Raw IP socket option processing.
200 */
201 int
202 rip_ctloutput(op, so, level, optname, m)
203 int op;
204 struct socket *so;
205 int level, optname;
206 struct mbuf **m;
207 {
208 register struct inpcb *inp = sotoinpcb(so);
209 int error = 0;
210
211 if (level != IPPROTO_IP) {
212 error = ENOPROTOOPT;
213 if (op == PRCO_SETOPT && *m != 0)
214 (void) m_free(*m);
215 } else switch (op) {
216
217 case PRCO_SETOPT:
218 switch (optname) {
219 case IP_HDRINCL:
220 if (*m == 0 || (*m)->m_len < sizeof (int))
221 error = EINVAL;
222 else {
223 if (*mtod(*m, int *))
224 inp->inp_flags |= INP_HDRINCL;
225 else
226 inp->inp_flags &= ~INP_HDRINCL;
227 }
228 if (*m != 0)
229 (void) m_free(*m);
230 break;
231
232 #ifdef MROUTING
233 case MRT_INIT:
234 case MRT_DONE:
235 case MRT_ADD_VIF:
236 case MRT_DEL_VIF:
237 case MRT_ADD_MFC:
238 case MRT_DEL_MFC:
239 case MRT_ASSERT:
240 error = ip_mrouter_set(so, optname, m);
241 break;
242 #endif
243
244 default:
245 error = ip_ctloutput(op, so, level, optname, m);
246 break;
247 }
248 break;
249
250 case PRCO_GETOPT:
251 switch (optname) {
252 case IP_HDRINCL:
253 *m = m_get(M_WAIT, M_SOOPTS);
254 (*m)->m_len = sizeof (int);
255 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL ? 1 : 0;
256 break;
257
258 #ifdef MROUTING
259 case MRT_VERSION:
260 case MRT_ASSERT:
261 error = ip_mrouter_get(so, optname, m);
262 break;
263 #endif
264
265 default:
266 error = ip_ctloutput(op, so, level, optname, m);
267 break;
268 }
269 break;
270 }
271 return (error);
272 }
273
274 int
275 rip_bind(inp, nam)
276 struct inpcb *inp;
277 struct mbuf *nam;
278 {
279 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
280
281 if (nam->m_len != sizeof(*addr))
282 return (EINVAL);
283 if (ifnet.tqh_first == 0)
284 return (EADDRNOTAVAIL);
285 if (addr->sin_family != AF_INET &&
286 addr->sin_family != AF_IMPLINK)
287 return (EAFNOSUPPORT);
288 if (addr->sin_addr.s_addr != INADDR_ANY &&
289 ifa_ifwithaddr(sintosa(addr)) == 0)
290 return (EADDRNOTAVAIL);
291 inp->inp_laddr = addr->sin_addr;
292 return (0);
293 }
294
295 int
296 rip_connect(inp, nam)
297 struct inpcb *inp;
298 struct mbuf *nam;
299 {
300 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
301
302 if (nam->m_len != sizeof(*addr))
303 return (EINVAL);
304 if (ifnet.tqh_first == 0)
305 return (EADDRNOTAVAIL);
306 if (addr->sin_family != AF_INET &&
307 addr->sin_family != AF_IMPLINK)
308 return (EAFNOSUPPORT);
309 inp->inp_faddr = addr->sin_addr;
310 return (0);
311 }
312
313 void
314 rip_disconnect(inp)
315 struct inpcb *inp;
316 {
317
318 inp->inp_faddr.s_addr = INADDR_ANY;
319 }
320
321 u_long rip_sendspace = RIPSNDQ;
322 u_long rip_recvspace = RIPRCVQ;
323
324 /*ARGSUSED*/
325 int
326 rip_usrreq(so, req, m, nam, control, p)
327 register struct socket *so;
328 int req;
329 struct mbuf *m, *nam, *control;
330 struct proc *p;
331 {
332 register struct inpcb *inp;
333 int s;
334 register int error = 0;
335 #ifdef MROUTING
336 extern struct socket *ip_mrouter;
337 #endif
338
339 if (req == PRU_CONTROL)
340 return (in_control(so, (long)m, (caddr_t)nam,
341 (struct ifnet *)control, p));
342
343 s = splsoftnet();
344 inp = sotoinpcb(so);
345 #ifdef DIAGNOSTIC
346 if (req != PRU_SEND && req != PRU_SENDOOB && control)
347 panic("rip_usrreq: unexpected control mbuf");
348 #endif
349 if (inp == 0 && req != PRU_ATTACH) {
350 error = EINVAL;
351 goto release;
352 }
353
354 switch (req) {
355
356 case PRU_ATTACH:
357 if (inp != 0) {
358 error = EISCONN;
359 break;
360 }
361 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) {
362 error = EACCES;
363 break;
364 }
365 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
366 error = soreserve(so, rip_sendspace, rip_recvspace);
367 if (error)
368 break;
369 }
370 error = in_pcballoc(so, &rawcbtable);
371 if (error)
372 break;
373 inp = sotoinpcb(so);
374 inp->inp_ip.ip_p = (long)nam;
375 break;
376
377 case PRU_DETACH:
378 #ifdef MROUTING
379 if (so == ip_mrouter)
380 ip_mrouter_done();
381 #endif
382 in_pcbdetach(inp);
383 break;
384
385 case PRU_BIND:
386 error = rip_bind(inp, nam);
387 break;
388
389 case PRU_LISTEN:
390 error = EOPNOTSUPP;
391 break;
392
393 case PRU_CONNECT:
394 error = rip_connect(inp, nam);
395 if (error)
396 break;
397 soisconnected(so);
398 break;
399
400 case PRU_CONNECT2:
401 error = EOPNOTSUPP;
402 break;
403
404 case PRU_DISCONNECT:
405 soisdisconnected(so);
406 rip_disconnect(inp);
407 break;
408
409 /*
410 * Mark the connection as being incapable of further input.
411 */
412 case PRU_SHUTDOWN:
413 socantsendmore(so);
414 break;
415
416 case PRU_RCVD:
417 error = EOPNOTSUPP;
418 break;
419
420 /*
421 * Ship a packet out. The appropriate raw output
422 * routine handles any massaging necessary.
423 */
424 case PRU_SEND:
425 if (control && control->m_len) {
426 m_freem(control);
427 m_freem(m);
428 error = EINVAL;
429 break;
430 }
431 {
432 if (nam) {
433 if ((so->so_state & SS_ISCONNECTED) != 0) {
434 error = EISCONN;
435 goto die;
436 }
437 error = rip_connect(inp, nam);
438 if (error) {
439 die:
440 m_freem(m);
441 break;
442 }
443 } else {
444 if ((so->so_state & SS_ISCONNECTED) == 0) {
445 error = ENOTCONN;
446 goto die;
447 }
448 }
449 error = rip_output(m, inp);
450 if (nam)
451 rip_disconnect(inp);
452 }
453 break;
454
455 case PRU_SENSE:
456 /*
457 * stat: don't bother with a blocksize.
458 */
459 splx(s);
460 return (0);
461
462 case PRU_RCVOOB:
463 error = EOPNOTSUPP;
464 break;
465
466 case PRU_SENDOOB:
467 m_freem(control);
468 m_freem(m);
469 error = EOPNOTSUPP;
470 break;
471
472 case PRU_SOCKADDR:
473 in_setsockaddr(inp, nam);
474 break;
475
476 case PRU_PEERADDR:
477 in_setpeeraddr(inp, nam);
478 break;
479
480 default:
481 panic("rip_usrreq");
482 }
483
484 release:
485 splx(s);
486 return (error);
487 }
488