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