[BACK]Return to raw_ip.c CVS log [TXT][DIR] Up to [local] / sys / netinet

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