raw_ip.c revision 1.42.6.1 1 /* $NetBSD: raw_ip.c,v 1.42.6.1 1999/06/28 06:37:01 itojun 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.7 (Berkeley) 5/15/95
36 */
37
38 #include "opt_mrouting.h"
39
40 #include <sys/param.h>
41 #include <sys/malloc.h>
42 #include <sys/mbuf.h>
43 #include <sys/socket.h>
44 #include <sys/protosw.h>
45 #include <sys/socketvar.h>
46 #include <sys/errno.h>
47 #include <sys/systm.h>
48 #include <sys/proc.h>
49
50 #include <net/if.h>
51 #include <net/route.h>
52
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
56 #include <netinet/ip_var.h>
57 #include <netinet/ip_mroute.h>
58 #include <netinet/in_pcb.h>
59 #include <netinet/in_var.h>
60
61 #include <machine/stdarg.h>
62
63 #ifdef IPSEC
64 #include <netinet6/ipsec.h>
65 #endif /*IPSEC*/
66
67 struct inpcbtable rawcbtable;
68
69 int rip_bind __P((struct inpcb *, struct mbuf *));
70 int rip_connect __P((struct inpcb *, struct mbuf *));
71 void rip_disconnect __P((struct inpcb *));
72
73 /*
74 * Nominal space allocated to a raw ip socket.
75 */
76 #define RIPSNDQ 8192
77 #define RIPRCVQ 8192
78
79 /*
80 * Raw interface to IP protocol.
81 */
82
83 /*
84 * Initialize raw connection block q.
85 */
86 void
87 rip_init()
88 {
89
90 in_pcbinit(&rawcbtable, 1, 1);
91 }
92
93 static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
94
95 /*
96 * Setup generic address and protocol structures
97 * for raw_input routine, then pass them along with
98 * mbuf chain.
99 */
100 void
101 #if __STDC__
102 rip_input(struct mbuf *m, ...)
103 #else
104 rip_input(m, va_alist)
105 struct mbuf *m;
106 va_dcl
107 #endif
108 {
109 int off, proto;
110 register struct ip *ip = mtod(m, struct ip *);
111 register struct inpcb *inp;
112 struct inpcb *last = 0;
113 struct mbuf *opts = 0;
114 struct sockaddr_in ripsrc;
115 va_list ap;
116
117 va_start(ap, m);
118 off = va_arg(ap, int);
119 proto = va_arg(ap, int);
120 va_end(ap);
121
122 ripsrc.sin_family = AF_INET;
123 ripsrc.sin_len = sizeof(struct sockaddr_in);
124 ripsrc.sin_addr = ip->ip_src;
125 ripsrc.sin_port = 0;
126 bzero((caddr_t)ripsrc.sin_zero, sizeof(ripsrc.sin_zero));
127
128 /*
129 * XXX Compatibility: programs using raw IP expect ip_len
130 * XXX to have the header length subtracted.
131 */
132 ip->ip_len -= ip->ip_hl << 2;
133
134 for (inp = rawcbtable.inpt_queue.cqh_first;
135 inp != (struct inpcb *)&rawcbtable.inpt_queue;
136 inp = inp->inp_queue.cqe_next) {
137 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != proto)
138 continue;
139 if (!in_nullhost(inp->inp_laddr) &&
140 !in_hosteq(inp->inp_laddr, ip->ip_dst))
141 continue;
142 if (!in_nullhost(inp->inp_faddr) &&
143 !in_hosteq(inp->inp_faddr, ip->ip_src))
144 continue;
145 if (last) {
146 struct mbuf *n;
147 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
148 if (last->inp_flags & INP_CONTROLOPTS ||
149 last->inp_socket->so_options & SO_TIMESTAMP)
150 ip_savecontrol(last, &opts, ip, n);
151 if (sbappendaddr(&last->inp_socket->so_rcv,
152 sintosa(&ripsrc), n, opts) == 0) {
153 /* should notify about lost packet */
154 m_freem(n);
155 if (opts)
156 m_freem(opts);
157 } else
158 sorwakeup(last->inp_socket);
159 opts = NULL;
160 }
161 }
162 last = inp;
163 }
164 if (last) {
165 if (last->inp_flags & INP_CONTROLOPTS ||
166 last->inp_socket->so_options & SO_TIMESTAMP)
167 ip_savecontrol(last, &opts, ip, m);
168 if (sbappendaddr(&last->inp_socket->so_rcv,
169 sintosa(&ripsrc), m, opts) == 0) {
170 m_freem(m);
171 if (opts)
172 m_freem(opts);
173 } else
174 sorwakeup(last->inp_socket);
175 } else {
176 m_freem(m);
177 ipstat.ips_noproto++;
178 ipstat.ips_delivered--;
179 }
180 return;
181 }
182
183 /*
184 * Generate IP header and pass packet to ip_output.
185 * Tack on options user may have setup with control call.
186 */
187 int
188 #if __STDC__
189 rip_output(struct mbuf *m, ...)
190 #else
191 rip_output(m, va_alist)
192 struct mbuf *m;
193 va_dcl
194 #endif
195 {
196 register struct inpcb *inp;
197 register struct ip *ip;
198 struct mbuf *opts;
199 int flags;
200 va_list ap;
201
202 va_start(ap, m);
203 inp = va_arg(ap, struct inpcb *);
204 va_end(ap);
205
206 flags =
207 (inp->inp_socket->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST
208 | IP_RETURNMTU;
209
210 /*
211 * If the user handed us a complete IP packet, use it.
212 * Otherwise, allocate an mbuf for a header and fill it in.
213 */
214 if ((inp->inp_flags & INP_HDRINCL) == 0) {
215 if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) {
216 m_freem(m);
217 return (EMSGSIZE);
218 }
219 M_PREPEND(m, sizeof(struct ip), M_WAIT);
220 ip = mtod(m, struct ip *);
221 ip->ip_tos = 0;
222 ip->ip_off = 0;
223 ip->ip_p = inp->inp_ip.ip_p;
224 ip->ip_len = m->m_pkthdr.len;
225 ip->ip_src = inp->inp_laddr;
226 ip->ip_dst = inp->inp_faddr;
227 ip->ip_ttl = MAXTTL;
228 opts = inp->inp_options;
229 } else {
230 if (m->m_pkthdr.len > IP_MAXPACKET) {
231 m_freem(m);
232 return (EMSGSIZE);
233 }
234 ip = mtod(m, struct ip *);
235 if (m->m_pkthdr.len != ip->ip_len) {
236 m_freem(m);
237 return (EINVAL);
238 }
239 if (ip->ip_id == 0)
240 ip->ip_id = htons(ip_id++);
241 opts = NULL;
242 /* XXX prevent ip_output from overwriting header fields */
243 flags |= IP_RAWOUTPUT;
244 ipstat.ips_rawout++;
245 }
246 #ifdef IPSEC
247 m->m_pkthdr.rcvif = (struct ifnet *)inp->inp_socket; /*XXX*/
248 #endif /*IPSEC*/
249 return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions, &inp->inp_errormtu));
250 }
251
252 /*
253 * Raw IP socket option processing.
254 */
255 int
256 rip_ctloutput(op, so, level, optname, m)
257 int op;
258 struct socket *so;
259 int level, optname;
260 struct mbuf **m;
261 {
262 register struct inpcb *inp = sotoinpcb(so);
263 int error = 0;
264
265 if (level != IPPROTO_IP) {
266 error = ENOPROTOOPT;
267 if (op == PRCO_SETOPT && *m != 0)
268 (void) m_free(*m);
269 } else switch (op) {
270
271 case PRCO_SETOPT:
272 switch (optname) {
273 case IP_HDRINCL:
274 if (*m == 0 || (*m)->m_len < sizeof (int))
275 error = EINVAL;
276 else {
277 if (*mtod(*m, int *))
278 inp->inp_flags |= INP_HDRINCL;
279 else
280 inp->inp_flags &= ~INP_HDRINCL;
281 }
282 if (*m != 0)
283 (void) m_free(*m);
284 break;
285
286 #ifdef MROUTING
287 case MRT_INIT:
288 case MRT_DONE:
289 case MRT_ADD_VIF:
290 case MRT_DEL_VIF:
291 case MRT_ADD_MFC:
292 case MRT_DEL_MFC:
293 case MRT_ASSERT:
294 error = ip_mrouter_set(so, optname, m);
295 break;
296 #endif
297
298 default:
299 error = ip_ctloutput(op, so, level, optname, m);
300 break;
301 }
302 break;
303
304 case PRCO_GETOPT:
305 switch (optname) {
306 case IP_HDRINCL:
307 *m = m_get(M_WAIT, M_SOOPTS);
308 (*m)->m_len = sizeof (int);
309 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL ? 1 : 0;
310 break;
311
312 #ifdef MROUTING
313 case MRT_VERSION:
314 case MRT_ASSERT:
315 error = ip_mrouter_get(so, optname, m);
316 break;
317 #endif
318
319 default:
320 error = ip_ctloutput(op, so, level, optname, m);
321 break;
322 }
323 break;
324 }
325 return (error);
326 }
327
328 int
329 rip_bind(inp, nam)
330 struct inpcb *inp;
331 struct mbuf *nam;
332 {
333 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
334
335 if (nam->m_len != sizeof(*addr))
336 return (EINVAL);
337 if (ifnet.tqh_first == 0)
338 return (EADDRNOTAVAIL);
339 if (addr->sin_family != AF_INET &&
340 addr->sin_family != AF_IMPLINK)
341 return (EAFNOSUPPORT);
342 if (!in_nullhost(addr->sin_addr) &&
343 ifa_ifwithaddr(sintosa(addr)) == 0)
344 return (EADDRNOTAVAIL);
345 inp->inp_laddr = addr->sin_addr;
346 return (0);
347 }
348
349 int
350 rip_connect(inp, nam)
351 struct inpcb *inp;
352 struct mbuf *nam;
353 {
354 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
355
356 if (nam->m_len != sizeof(*addr))
357 return (EINVAL);
358 if (ifnet.tqh_first == 0)
359 return (EADDRNOTAVAIL);
360 if (addr->sin_family != AF_INET &&
361 addr->sin_family != AF_IMPLINK)
362 return (EAFNOSUPPORT);
363 inp->inp_faddr = addr->sin_addr;
364 return (0);
365 }
366
367 void
368 rip_disconnect(inp)
369 struct inpcb *inp;
370 {
371
372 inp->inp_faddr = zeroin_addr;
373 }
374
375 u_long rip_sendspace = RIPSNDQ;
376 u_long rip_recvspace = RIPRCVQ;
377
378 /*ARGSUSED*/
379 int
380 rip_usrreq(so, req, m, nam, control, p)
381 register struct socket *so;
382 int req;
383 struct mbuf *m, *nam, *control;
384 struct proc *p;
385 {
386 register struct inpcb *inp;
387 int s;
388 register int error = 0;
389 #ifdef MROUTING
390 extern struct socket *ip_mrouter;
391 #endif
392
393 if (req == PRU_CONTROL)
394 return (in_control(so, (long)m, (caddr_t)nam,
395 (struct ifnet *)control, p));
396
397 s = splsoftnet();
398 inp = sotoinpcb(so);
399 #ifdef DIAGNOSTIC
400 if (req != PRU_SEND && req != PRU_SENDOOB && control)
401 panic("rip_usrreq: unexpected control mbuf");
402 #endif
403 if (inp == 0 && req != PRU_ATTACH) {
404 error = EINVAL;
405 goto release;
406 }
407
408 switch (req) {
409
410 case PRU_ATTACH:
411 if (inp != 0) {
412 error = EISCONN;
413 break;
414 }
415 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) {
416 error = EACCES;
417 break;
418 }
419 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
420 error = soreserve(so, rip_sendspace, rip_recvspace);
421 if (error)
422 break;
423 }
424 error = in_pcballoc(so, &rawcbtable);
425 if (error)
426 break;
427 inp = sotoinpcb(so);
428 inp->inp_ip.ip_p = (long)nam;
429 #ifdef IPSEC
430 error = ipsec_init_policy(&inp->inp_sp);
431 #endif /*IPSEC*/
432 break;
433
434 case PRU_DETACH:
435 #ifdef MROUTING
436 if (so == ip_mrouter)
437 ip_mrouter_done();
438 #endif
439 in_pcbdetach(inp);
440 break;
441
442 case PRU_BIND:
443 error = rip_bind(inp, nam);
444 break;
445
446 case PRU_LISTEN:
447 error = EOPNOTSUPP;
448 break;
449
450 case PRU_CONNECT:
451 error = rip_connect(inp, nam);
452 if (error)
453 break;
454 soisconnected(so);
455 break;
456
457 case PRU_CONNECT2:
458 error = EOPNOTSUPP;
459 break;
460
461 case PRU_DISCONNECT:
462 soisdisconnected(so);
463 rip_disconnect(inp);
464 break;
465
466 /*
467 * Mark the connection as being incapable of further input.
468 */
469 case PRU_SHUTDOWN:
470 socantsendmore(so);
471 break;
472
473 case PRU_RCVD:
474 error = EOPNOTSUPP;
475 break;
476
477 /*
478 * Ship a packet out. The appropriate raw output
479 * routine handles any massaging necessary.
480 */
481 case PRU_SEND:
482 if (control && control->m_len) {
483 m_freem(control);
484 m_freem(m);
485 error = EINVAL;
486 break;
487 }
488 {
489 if (nam) {
490 if ((so->so_state & SS_ISCONNECTED) != 0) {
491 error = EISCONN;
492 goto die;
493 }
494 error = rip_connect(inp, nam);
495 if (error) {
496 die:
497 m_freem(m);
498 break;
499 }
500 } else {
501 if ((so->so_state & SS_ISCONNECTED) == 0) {
502 error = ENOTCONN;
503 goto die;
504 }
505 }
506 error = rip_output(m, inp);
507 if (nam)
508 rip_disconnect(inp);
509 }
510 break;
511
512 case PRU_SENSE:
513 /*
514 * stat: don't bother with a blocksize.
515 */
516 splx(s);
517 return (0);
518
519 case PRU_RCVOOB:
520 error = EOPNOTSUPP;
521 break;
522
523 case PRU_SENDOOB:
524 m_freem(control);
525 m_freem(m);
526 error = EOPNOTSUPP;
527 break;
528
529 case PRU_SOCKADDR:
530 in_setsockaddr(inp, nam);
531 break;
532
533 case PRU_PEERADDR:
534 in_setpeeraddr(inp, nam);
535 break;
536
537 default:
538 panic("rip_usrreq");
539 }
540
541 release:
542 splx(s);
543 return (error);
544 }
545