Annotation of Net2/netinet/ip_output.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms, with or without
        !             6:  * modification, are permitted provided that the following conditions
        !             7:  * are met:
        !             8:  * 1. Redistributions of source code must retain the above copyright
        !             9:  *    notice, this list of conditions and the following disclaimer.
        !            10:  * 2. Redistributions in binary form must reproduce the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer in the
        !            12:  *    documentation and/or other materials provided with the distribution.
        !            13:  * 3. All advertising materials mentioning features or use of this software
        !            14:  *    must display the following acknowledgement:
        !            15:  *     This product includes software developed by the University of
        !            16:  *     California, Berkeley and its contributors.
        !            17:  * 4. Neither the name of the University nor the names of its contributors
        !            18:  *    may be used to endorse or promote products derived from this software
        !            19:  *    without specific prior written permission.
        !            20:  *
        !            21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            31:  * SUCH DAMAGE.
        !            32:  *
        !            33:  *     @(#)ip_output.c 7.23 (Berkeley) 11/12/90
        !            34:  */
        !            35: 
        !            36: #include "param.h"
        !            37: #include "malloc.h"
        !            38: #include "mbuf.h"
        !            39: #include "errno.h"
        !            40: #include "protosw.h"
        !            41: #include "socket.h"
        !            42: #include "socketvar.h"
        !            43: 
        !            44: #include "../net/if.h"
        !            45: #include "../net/route.h"
        !            46: 
        !            47: #include "in.h"
        !            48: #include "in_systm.h"
        !            49: #include "ip.h"
        !            50: #include "in_pcb.h"
        !            51: #include "in_var.h"
        !            52: #include "ip_var.h"
        !            53: 
        !            54: #ifdef vax
        !            55: #include "machine/mtpr.h"
        !            56: #endif
        !            57: 
        !            58: struct mbuf *ip_insertoptions();
        !            59: 
        !            60: /*
        !            61:  * IP output.  The packet in mbuf chain m contains a skeletal IP
        !            62:  * header (with len, off, ttl, proto, tos, src, dst).
        !            63:  * The mbuf chain containing the packet will be freed.
        !            64:  * The mbuf opt, if present, will not be freed.
        !            65:  */
        !            66: ip_output(m0, opt, ro, flags)
        !            67:        struct mbuf *m0;
        !            68:        struct mbuf *opt;
        !            69:        struct route *ro;
        !            70:        int flags;
        !            71: {
        !            72:        register struct ip *ip, *mhip;
        !            73:        register struct ifnet *ifp;
        !            74:        register struct mbuf *m = m0;
        !            75:        register int hlen = sizeof (struct ip);
        !            76:        int len, off, error = 0;
        !            77:        struct route iproute;
        !            78:        struct sockaddr_in *dst;
        !            79:        struct in_ifaddr *ia;
        !            80: 
        !            81: #ifdef DIAGNOSTIC
        !            82:        if ((m->m_flags & M_PKTHDR) == 0)
        !            83:                panic("ip_output no HDR");
        !            84: #endif
        !            85:        if (opt) {
        !            86:                m = ip_insertoptions(m, opt, &len);
        !            87:                hlen = len;
        !            88:        }
        !            89:        ip = mtod(m, struct ip *);
        !            90:        /*
        !            91:         * Fill in IP header.
        !            92:         */
        !            93:        if ((flags & IP_FORWARDING) == 0) {
        !            94:                ip->ip_v = IPVERSION;
        !            95:                ip->ip_off &= IP_DF;
        !            96:                ip->ip_id = htons(ip_id++);
        !            97:                ip->ip_hl = hlen >> 2;
        !            98:        } else {
        !            99:                hlen = ip->ip_hl << 2;
        !           100:                ipstat.ips_localout++;
        !           101:        }
        !           102:        /*
        !           103:         * Route packet.
        !           104:         */
        !           105:        if (ro == 0) {
        !           106:                ro = &iproute;
        !           107:                bzero((caddr_t)ro, sizeof (*ro));
        !           108:        }
        !           109:        dst = (struct sockaddr_in *)&ro->ro_dst;
        !           110:        /*
        !           111:         * If there is a cached route,
        !           112:         * check that it is to the same destination
        !           113:         * and is still up.  If not, free it and try again.
        !           114:         */
        !           115:        if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
        !           116:           dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
        !           117:                RTFREE(ro->ro_rt);
        !           118:                ro->ro_rt = (struct rtentry *)0;
        !           119:        }
        !           120:        if (ro->ro_rt == 0) {
        !           121:                dst->sin_family = AF_INET;
        !           122:                dst->sin_len = sizeof(*dst);
        !           123:                dst->sin_addr = ip->ip_dst;
        !           124:        }
        !           125:        /*
        !           126:         * If routing to interface only,
        !           127:         * short circuit routing lookup.
        !           128:         */
        !           129:        if (flags & IP_ROUTETOIF) {
        !           130: 
        !           131:                ia = (struct in_ifaddr *)ifa_ifwithdstaddr((struct sockaddr *)dst);
        !           132:                if (ia == 0)
        !           133:                        ia = in_iaonnetof(in_netof(ip->ip_dst));
        !           134:                if (ia == 0) {
        !           135:                        error = ENETUNREACH;
        !           136:                        goto bad;
        !           137:                }
        !           138:                ifp = ia->ia_ifp;
        !           139:        } else {
        !           140:                if (ro->ro_rt == 0)
        !           141:                        rtalloc(ro);
        !           142:                if (ro->ro_rt == 0) {
        !           143:                        error = EHOSTUNREACH;
        !           144:                        goto bad;
        !           145:                }
        !           146:                ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa;
        !           147:                ifp = ro->ro_rt->rt_ifp;
        !           148:                ro->ro_rt->rt_use++;
        !           149:                if (ro->ro_rt->rt_flags & RTF_GATEWAY)
        !           150:                        dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
        !           151:        }
        !           152: #ifndef notdef
        !           153:        /*
        !           154:         * If source address not specified yet, use address
        !           155:         * of outgoing interface.
        !           156:         */
        !           157:        if (ip->ip_src.s_addr == INADDR_ANY)
        !           158:                ip->ip_src = IA_SIN(ia)->sin_addr;
        !           159: #endif
        !           160:        /*
        !           161:         * Look for broadcast address and
        !           162:         * and verify user is allowed to send
        !           163:         * such a packet.
        !           164:         */
        !           165:        if (in_broadcast(dst->sin_addr)) {
        !           166:                if ((ifp->if_flags & IFF_BROADCAST) == 0) {
        !           167:                        error = EADDRNOTAVAIL;
        !           168:                        goto bad;
        !           169:                }
        !           170:                if ((flags & IP_ALLOWBROADCAST) == 0) {
        !           171:                        error = EACCES;
        !           172:                        goto bad;
        !           173:                }
        !           174:                /* don't allow broadcast messages to be fragmented */
        !           175:                if ((u_short)ip->ip_len > ifp->if_mtu) {
        !           176:                        error = EMSGSIZE;
        !           177:                        goto bad;
        !           178:                }
        !           179:                m->m_flags |= M_BCAST;
        !           180:        }
        !           181: 
        !           182:        /*
        !           183:         * If small enough for interface, can just send directly.
        !           184:         */
        !           185:        if ((u_short)ip->ip_len <= ifp->if_mtu) {
        !           186:                ip->ip_len = htons((u_short)ip->ip_len);
        !           187:                ip->ip_off = htons((u_short)ip->ip_off);
        !           188:                ip->ip_sum = 0;
        !           189:                ip->ip_sum = in_cksum(m, hlen);
        !           190:                error = (*ifp->if_output)(ifp, m,
        !           191:                                (struct sockaddr *)dst, ro->ro_rt);
        !           192:                goto done;
        !           193:        }
        !           194:        ipstat.ips_fragmented++;
        !           195:        /*
        !           196:         * Too large for interface; fragment if possible.
        !           197:         * Must be able to put at least 8 bytes per fragment.
        !           198:         */
        !           199:        if (ip->ip_off & IP_DF) {
        !           200:                error = EMSGSIZE;
        !           201:                goto bad;
        !           202:        }
        !           203:        len = (ifp->if_mtu - hlen) &~ 7;
        !           204:        if (len < 8) {
        !           205:                error = EMSGSIZE;
        !           206:                goto bad;
        !           207:        }
        !           208: 
        !           209:     {
        !           210:        int mhlen, firstlen = len;
        !           211:        struct mbuf **mnext = &m->m_nextpkt;
        !           212: 
        !           213:        /*
        !           214:         * Loop through length of segment after first fragment,
        !           215:         * make new header and copy data of each part and link onto chain.
        !           216:         */
        !           217:        m0 = m;
        !           218:        mhlen = sizeof (struct ip);
        !           219:        for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
        !           220:                MGETHDR(m, M_DONTWAIT, MT_HEADER);
        !           221:                if (m == 0) {
        !           222:                        error = ENOBUFS;
        !           223:                        goto sendorfree;
        !           224:                }
        !           225:                m->m_data += max_linkhdr;
        !           226:                mhip = mtod(m, struct ip *);
        !           227:                *mhip = *ip;
        !           228:                if (hlen > sizeof (struct ip)) {
        !           229:                        mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
        !           230:                        mhip->ip_hl = mhlen >> 2;
        !           231:                }
        !           232:                m->m_len = mhlen;
        !           233:                mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
        !           234:                if (ip->ip_off & IP_MF)
        !           235:                        mhip->ip_off |= IP_MF;
        !           236:                if (off + len >= (u_short)ip->ip_len)
        !           237:                        len = (u_short)ip->ip_len - off;
        !           238:                else
        !           239:                        mhip->ip_off |= IP_MF;
        !           240:                mhip->ip_len = htons((u_short)(len + mhlen));
        !           241:                m->m_next = m_copy(m0, off, len);
        !           242:                if (m->m_next == 0) {
        !           243:                        error = ENOBUFS;        /* ??? */
        !           244:                        goto sendorfree;
        !           245:                }
        !           246:                m->m_pkthdr.len = mhlen + len;
        !           247:                m->m_pkthdr.rcvif = (struct ifnet *)0;
        !           248:                mhip->ip_off = htons((u_short)mhip->ip_off);
        !           249:                mhip->ip_sum = 0;
        !           250:                mhip->ip_sum = in_cksum(m, mhlen);
        !           251:                *mnext = m;
        !           252:                mnext = &m->m_nextpkt;
        !           253:                ipstat.ips_ofragments++;
        !           254:        }
        !           255:        /*
        !           256:         * Update first fragment by trimming what's been copied out
        !           257:         * and updating header, then send each fragment (in order).
        !           258:         */
        !           259:        m = m0;
        !           260:        m_adj(m, hlen + firstlen - (u_short)ip->ip_len);
        !           261:        m->m_pkthdr.len = hlen + firstlen;
        !           262:        ip->ip_len = htons((u_short)m->m_pkthdr.len);
        !           263:        ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
        !           264:        ip->ip_sum = 0;
        !           265:        ip->ip_sum = in_cksum(m, hlen);
        !           266: sendorfree:
        !           267:        for (m = m0; m; m = m0) {
        !           268:                m0 = m->m_nextpkt;
        !           269:                m->m_nextpkt = 0;
        !           270:                if (error == 0)
        !           271:                        error = (*ifp->if_output)(ifp, m,
        !           272:                            (struct sockaddr *)dst, ro->ro_rt);
        !           273:                else
        !           274:                        m_freem(m);
        !           275:        }
        !           276:     }
        !           277: done:
        !           278:        if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt)
        !           279:                RTFREE(ro->ro_rt);
        !           280:        return (error);
        !           281: bad:
        !           282:        m_freem(m0);
        !           283:        goto done;
        !           284: }
        !           285: 
        !           286: /*
        !           287:  * Insert IP options into preformed packet.
        !           288:  * Adjust IP destination as required for IP source routing,
        !           289:  * as indicated by a non-zero in_addr at the start of the options.
        !           290:  */
        !           291: struct mbuf *
        !           292: ip_insertoptions(m, opt, phlen)
        !           293:        register struct mbuf *m;
        !           294:        struct mbuf *opt;
        !           295:        int *phlen;
        !           296: {
        !           297:        register struct ipoption *p = mtod(opt, struct ipoption *);
        !           298:        struct mbuf *n;
        !           299:        register struct ip *ip = mtod(m, struct ip *);
        !           300:        unsigned optlen;
        !           301: 
        !           302:        optlen = opt->m_len - sizeof(p->ipopt_dst);
        !           303:        if (optlen + (u_short)ip->ip_len > IP_MAXPACKET)
        !           304:                return (m);             /* XXX should fail */
        !           305:        if (p->ipopt_dst.s_addr)
        !           306:                ip->ip_dst = p->ipopt_dst;
        !           307:        if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
        !           308:                MGETHDR(n, M_DONTWAIT, MT_HEADER);
        !           309:                if (n == 0)
        !           310:                        return (m);
        !           311:                n->m_pkthdr.len = m->m_pkthdr.len + optlen;
        !           312:                m->m_len -= sizeof(struct ip);
        !           313:                m->m_data += sizeof(struct ip);
        !           314:                n->m_next = m;
        !           315:                m = n;
        !           316:                m->m_len = optlen + sizeof(struct ip);
        !           317:                m->m_data += max_linkhdr;
        !           318:                bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
        !           319:        } else {
        !           320:                m->m_data -= optlen;
        !           321:                m->m_len += optlen;
        !           322:                m->m_pkthdr.len += optlen;
        !           323:                ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
        !           324:        }
        !           325:        ip = mtod(m, struct ip *);
        !           326:        bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen);
        !           327:        *phlen = sizeof(struct ip) + optlen;
        !           328:        ip->ip_len += optlen;
        !           329:        return (m);
        !           330: }
        !           331: 
        !           332: /*
        !           333:  * Copy options from ip to jp,
        !           334:  * omitting those not copied during fragmentation.
        !           335:  */
        !           336: ip_optcopy(ip, jp)
        !           337:        struct ip *ip, *jp;
        !           338: {
        !           339:        register u_char *cp, *dp;
        !           340:        int opt, optlen, cnt;
        !           341: 
        !           342:        cp = (u_char *)(ip + 1);
        !           343:        dp = (u_char *)(jp + 1);
        !           344:        cnt = (ip->ip_hl << 2) - sizeof (struct ip);
        !           345:        for (; cnt > 0; cnt -= optlen, cp += optlen) {
        !           346:                opt = cp[0];
        !           347:                if (opt == IPOPT_EOL)
        !           348:                        break;
        !           349:                if (opt == IPOPT_NOP)
        !           350:                        optlen = 1;
        !           351:                else
        !           352:                        optlen = cp[IPOPT_OLEN];
        !           353:                /* bogus lengths should have been caught by ip_dooptions */
        !           354:                if (optlen > cnt)
        !           355:                        optlen = cnt;
        !           356:                if (IPOPT_COPIED(opt)) {
        !           357:                        bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
        !           358:                        dp += optlen;
        !           359:                }
        !           360:        }
        !           361:        for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
        !           362:                *dp++ = IPOPT_EOL;
        !           363:        return (optlen);
        !           364: }
        !           365: 
        !           366: /*
        !           367:  * IP socket option processing.
        !           368:  */
        !           369: ip_ctloutput(op, so, level, optname, mp)
        !           370:        int op;
        !           371:        struct socket *so;
        !           372:        int level, optname;
        !           373:        struct mbuf **mp;
        !           374: {
        !           375:        register struct inpcb *inp = sotoinpcb(so);
        !           376:        register struct mbuf *m = *mp;
        !           377:        register int optval;
        !           378:        int error = 0;
        !           379: 
        !           380:        if (level != IPPROTO_IP)
        !           381:                error = EINVAL;
        !           382:        else switch (op) {
        !           383: 
        !           384:        case PRCO_SETOPT:
        !           385:                switch (optname) {
        !           386:                case IP_OPTIONS:
        !           387: #ifdef notyet
        !           388:                case IP_RETOPTS:
        !           389:                        return (ip_pcbopts(optname, &inp->inp_options, m));
        !           390: #else
        !           391:                        return (ip_pcbopts(&inp->inp_options, m));
        !           392: #endif
        !           393: 
        !           394:                case IP_TOS:
        !           395:                case IP_TTL:
        !           396:                case IP_RECVOPTS:
        !           397:                case IP_RECVRETOPTS:
        !           398:                case IP_RECVDSTADDR:
        !           399:                        if (m->m_len != sizeof(int))
        !           400:                                error = EINVAL;
        !           401:                        else {
        !           402:                                optval = *mtod(m, int *);
        !           403:                                switch (optname) {
        !           404: 
        !           405:                                case IP_TOS:
        !           406:                                        inp->inp_ip.ip_tos = optval;
        !           407:                                        break;
        !           408: 
        !           409:                                case IP_TTL:
        !           410:                                        inp->inp_ip.ip_ttl = optval;
        !           411:                                        break;
        !           412: #define        OPTSET(bit) \
        !           413:        if (optval) \
        !           414:                inp->inp_flags |= bit; \
        !           415:        else \
        !           416:                inp->inp_flags &= ~bit;
        !           417: 
        !           418:                                case IP_RECVOPTS:
        !           419:                                        OPTSET(INP_RECVOPTS);
        !           420:                                        break;
        !           421: 
        !           422:                                case IP_RECVRETOPTS:
        !           423:                                        OPTSET(INP_RECVRETOPTS);
        !           424:                                        break;
        !           425: 
        !           426:                                case IP_RECVDSTADDR:
        !           427:                                        OPTSET(INP_RECVDSTADDR);
        !           428:                                        break;
        !           429:                                }
        !           430:                        }
        !           431:                        break;
        !           432: #undef OPTSET
        !           433: 
        !           434:                default:
        !           435:                        error = EINVAL;
        !           436:                        break;
        !           437:                }
        !           438:                if (m)
        !           439:                        (void)m_free(m);
        !           440:                break;
        !           441: 
        !           442:        case PRCO_GETOPT:
        !           443:                switch (optname) {
        !           444:                case IP_OPTIONS:
        !           445:                case IP_RETOPTS:
        !           446:                        *mp = m = m_get(M_WAIT, MT_SOOPTS);
        !           447:                        if (inp->inp_options) {
        !           448:                                m->m_len = inp->inp_options->m_len;
        !           449:                                bcopy(mtod(inp->inp_options, caddr_t),
        !           450:                                    mtod(m, caddr_t), (unsigned)m->m_len);
        !           451:                        } else
        !           452:                                m->m_len = 0;
        !           453:                        break;
        !           454: 
        !           455:                case IP_TOS:
        !           456:                case IP_TTL:
        !           457:                case IP_RECVOPTS:
        !           458:                case IP_RECVRETOPTS:
        !           459:                case IP_RECVDSTADDR:
        !           460:                        *mp = m = m_get(M_WAIT, MT_SOOPTS);
        !           461:                        m->m_len = sizeof(int);
        !           462:                        switch (optname) {
        !           463: 
        !           464:                        case IP_TOS:
        !           465:                                optval = inp->inp_ip.ip_tos;
        !           466:                                break;
        !           467: 
        !           468:                        case IP_TTL:
        !           469:                                optval = inp->inp_ip.ip_ttl;
        !           470:                                break;
        !           471: 
        !           472: #define        OPTBIT(bit)     (inp->inp_flags & bit ? 1 : 0)
        !           473: 
        !           474:                        case IP_RECVOPTS:
        !           475:                                optval = OPTBIT(INP_RECVOPTS);
        !           476:                                break;
        !           477: 
        !           478:                        case IP_RECVRETOPTS:
        !           479:                                optval = OPTBIT(INP_RECVRETOPTS);
        !           480:                                break;
        !           481: 
        !           482:                        case IP_RECVDSTADDR:
        !           483:                                optval = OPTBIT(INP_RECVDSTADDR);
        !           484:                                break;
        !           485:                        }
        !           486:                        *mtod(m, int *) = optval;
        !           487:                        break;
        !           488: 
        !           489:                default:
        !           490:                        error = EINVAL;
        !           491:                        break;
        !           492:                }
        !           493:                break;
        !           494:        }
        !           495:        return (error);
        !           496: }
        !           497: 
        !           498: /*
        !           499:  * Set up IP options in pcb for insertion in output packets.
        !           500:  * Store in mbuf with pointer in pcbopt, adding pseudo-option
        !           501:  * with destination address if source routed.
        !           502:  */
        !           503: #ifdef notyet
        !           504: ip_pcbopts(optname, pcbopt, m)
        !           505:        int optname;
        !           506: #else
        !           507: ip_pcbopts(pcbopt, m)
        !           508: #endif
        !           509:        struct mbuf **pcbopt;
        !           510:        register struct mbuf *m;
        !           511: {
        !           512:        register cnt, optlen;
        !           513:        register u_char *cp;
        !           514:        u_char opt;
        !           515: 
        !           516:        /* turn off any old options */
        !           517:        if (*pcbopt)
        !           518:                (void)m_free(*pcbopt);
        !           519:        *pcbopt = 0;
        !           520:        if (m == (struct mbuf *)0 || m->m_len == 0) {
        !           521:                /*
        !           522:                 * Only turning off any previous options.
        !           523:                 */
        !           524:                if (m)
        !           525:                        (void)m_free(m);
        !           526:                return (0);
        !           527:        }
        !           528: 
        !           529: #ifndef        vax
        !           530:        if (m->m_len % sizeof(long))
        !           531:                goto bad;
        !           532: #endif
        !           533:        /*
        !           534:         * IP first-hop destination address will be stored before
        !           535:         * actual options; move other options back
        !           536:         * and clear it when none present.
        !           537:         */
        !           538:        if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
        !           539:                goto bad;
        !           540:        cnt = m->m_len;
        !           541:        m->m_len += sizeof(struct in_addr);
        !           542:        cp = mtod(m, u_char *) + sizeof(struct in_addr);
        !           543:        ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
        !           544:        bzero(mtod(m, caddr_t), sizeof(struct in_addr));
        !           545: 
        !           546:        for (; cnt > 0; cnt -= optlen, cp += optlen) {
        !           547:                opt = cp[IPOPT_OPTVAL];
        !           548:                if (opt == IPOPT_EOL)
        !           549:                        break;
        !           550:                if (opt == IPOPT_NOP)
        !           551:                        optlen = 1;
        !           552:                else {
        !           553:                        optlen = cp[IPOPT_OLEN];
        !           554:                        if (optlen <= IPOPT_OLEN || optlen > cnt)
        !           555:                                goto bad;
        !           556:                }
        !           557:                switch (opt) {
        !           558: 
        !           559:                default:
        !           560:                        break;
        !           561: 
        !           562:                case IPOPT_LSRR:
        !           563:                case IPOPT_SSRR:
        !           564:                        /*
        !           565:                         * user process specifies route as:
        !           566:                         *      ->A->B->C->D
        !           567:                         * D must be our final destination (but we can't
        !           568:                         * check that since we may not have connected yet).
        !           569:                         * A is first hop destination, which doesn't appear in
        !           570:                         * actual IP option, but is stored before the options.
        !           571:                         */
        !           572:                        if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
        !           573:                                goto bad;
        !           574:                        m->m_len -= sizeof(struct in_addr);
        !           575:                        cnt -= sizeof(struct in_addr);
        !           576:                        optlen -= sizeof(struct in_addr);
        !           577:                        cp[IPOPT_OLEN] = optlen;
        !           578:                        /*
        !           579:                         * Move first hop before start of options.
        !           580:                         */
        !           581:                        bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
        !           582:                            sizeof(struct in_addr));
        !           583:                        /*
        !           584:                         * Then copy rest of options back
        !           585:                         * to close up the deleted entry.
        !           586:                         */
        !           587:                        ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
        !           588:                            sizeof(struct in_addr)),
        !           589:                            (caddr_t)&cp[IPOPT_OFFSET+1],
        !           590:                            (unsigned)cnt + sizeof(struct in_addr));
        !           591:                        break;
        !           592:                }
        !           593:        }
        !           594:        if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
        !           595:                goto bad;
        !           596:        *pcbopt = m;
        !           597:        return (0);
        !           598: 
        !           599: bad:
        !           600:        (void)m_free(m);
        !           601:        return (EINVAL);
        !           602: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.