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