Annotation of 43BSDTahoe/sys/netinet/ip_output.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms are permitted
                      6:  * provided that the above copyright notice and this paragraph are
                      7:  * duplicated in all such forms and that any documentation,
                      8:  * advertising materials, and other materials related to such
                      9:  * distribution and use acknowledge that the software was developed
                     10:  * by the University of California, Berkeley.  The name of the
                     11:  * University may not be used to endorse or promote products derived
                     12:  * from this software without specific prior written permission.
                     13:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
                     14:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
                     15:  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     16:  *
                     17:  *     @(#)ip_output.c 7.13 (Berkeley) 6/29/88
                     18:  */
                     19: 
                     20: #include "param.h"
                     21: #include "mbuf.h"
                     22: #include "errno.h"
                     23: #include "protosw.h"
                     24: #include "socket.h"
                     25: #include "socketvar.h"
                     26: 
                     27: #include "../net/if.h"
                     28: #include "../net/route.h"
                     29: 
                     30: #include "in.h"
                     31: #include "in_pcb.h"
                     32: #include "in_systm.h"
                     33: #include "in_var.h"
                     34: #include "ip.h"
                     35: #include "ip_var.h"
                     36: 
                     37: #ifdef vax
                     38: #include "../machine/mtpr.h"
                     39: #endif
                     40: 
                     41: struct mbuf *ip_insertoptions();
                     42: 
                     43: /*
                     44:  * IP output.  The packet in mbuf chain m contains a skeletal IP
                     45:  * header (with len, off, ttl, proto, tos, src, dst).
                     46:  * The mbuf chain containing the packet will be freed.
                     47:  * The mbuf opt, if present, will not be freed.
                     48:  */
                     49: ip_output(m0, opt, ro, flags)
                     50:        struct mbuf *m0;
                     51:        struct mbuf *opt;
                     52:        struct route *ro;
                     53:        int flags;
                     54: {
                     55:        register struct ip *ip, *mhip;
                     56:        register struct ifnet *ifp;
                     57:        register struct mbuf *m = m0;
                     58:        register int hlen = sizeof (struct ip);
                     59:        int len, off, error = 0;
                     60:        struct route iproute;
                     61:        struct sockaddr_in *dst;
                     62: 
                     63:        if (opt) {
                     64:                m = ip_insertoptions(m, opt, &len);
                     65:                hlen = len;
                     66:        }
                     67:        ip = mtod(m, struct ip *);
                     68:        /*
                     69:         * Fill in IP header.
                     70:         */
                     71:        if ((flags & IP_FORWARDING) == 0) {
                     72:                ip->ip_v = IPVERSION;
                     73:                ip->ip_off &= IP_DF;
                     74:                ip->ip_id = htons(ip_id++);
                     75:                ip->ip_hl = hlen >> 2;
                     76:        } else
                     77:                hlen = ip->ip_hl << 2;
                     78: 
                     79:        /*
                     80:         * Route packet.
                     81:         */
                     82:        if (ro == 0) {
                     83:                ro = &iproute;
                     84:                bzero((caddr_t)ro, sizeof (*ro));
                     85:        }
                     86:        dst = (struct sockaddr_in *)&ro->ro_dst;
                     87:        /*
                     88:         * If there is a cached route,
                     89:         * check that it is to the same destination
                     90:         * and is still up.  If not, free it and try again.
                     91:         */
                     92:        if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
                     93:           dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
                     94:                RTFREE(ro->ro_rt);
                     95:                ro->ro_rt = (struct rtentry *)0;
                     96:        }
                     97:        if (ro->ro_rt == 0) {
                     98:                dst->sin_family = AF_INET;
                     99:                dst->sin_addr = ip->ip_dst;
                    100:        }
                    101:        /*
                    102:         * If routing to interface only,
                    103:         * short circuit routing lookup.
                    104:         */
                    105:        if (flags & IP_ROUTETOIF) {
                    106:                struct in_ifaddr *ia;
                    107: 
                    108:                ia = (struct in_ifaddr *)ifa_ifwithdstaddr((struct sockaddr *)dst);
                    109:                if (ia == 0)
                    110:                        ia = in_iaonnetof(in_netof(ip->ip_dst));
                    111:                if (ia == 0) {
                    112:                        error = ENETUNREACH;
                    113:                        goto bad;
                    114:                }
                    115:                ifp = ia->ia_ifp;
                    116:        } else {
                    117:                if (ro->ro_rt == 0)
                    118:                        rtalloc(ro);
                    119:                if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
                    120:                        if (in_localaddr(ip->ip_dst))
                    121:                                error = EHOSTUNREACH;
                    122:                        else
                    123:                                error = ENETUNREACH;
                    124:                        goto bad;
                    125:                }
                    126:                ro->ro_rt->rt_use++;
                    127:                if (ro->ro_rt->rt_flags & RTF_GATEWAY)
                    128:                        dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway;
                    129:        }
                    130: #ifndef notdef
                    131:        /*
                    132:         * If source address not specified yet, use address
                    133:         * of outgoing interface.
                    134:         */
                    135:        if (ip->ip_src.s_addr == INADDR_ANY) {
                    136:                register struct in_ifaddr *ia;
                    137: 
                    138:                for (ia = in_ifaddr; ia; ia = ia->ia_next)
                    139:                        if (ia->ia_ifp == ifp) {
                    140:                                ip->ip_src = IA_SIN(ia)->sin_addr;
                    141:                                break;
                    142:                        }
                    143:        }
                    144: #endif
                    145:        /*
                    146:         * Look for broadcast address and
                    147:         * and verify user is allowed to send
                    148:         * such a packet.
                    149:         */
                    150:        if (in_broadcast(dst->sin_addr)) {
                    151:                if ((ifp->if_flags & IFF_BROADCAST) == 0) {
                    152:                        error = EADDRNOTAVAIL;
                    153:                        goto bad;
                    154:                }
                    155:                if ((flags & IP_ALLOWBROADCAST) == 0) {
                    156:                        error = EACCES;
                    157:                        goto bad;
                    158:                }
                    159:                /* don't allow broadcast messages to be fragmented */
                    160:                if (ip->ip_len > ifp->if_mtu) {
                    161:                        error = EMSGSIZE;
                    162:                        goto bad;
                    163:                }
                    164:        }
                    165: 
                    166:        /*
                    167:         * If small enough for interface, can just send directly.
                    168:         */
                    169:        if (ip->ip_len <= ifp->if_mtu) {
                    170:                ip->ip_len = htons((u_short)ip->ip_len);
                    171:                ip->ip_off = htons((u_short)ip->ip_off);
                    172:                ip->ip_sum = 0;
                    173:                ip->ip_sum = in_cksum(m, hlen);
                    174:                error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst);
                    175:                goto done;
                    176:        }
                    177: 
                    178:        /*
                    179:         * Too large for interface; fragment if possible.
                    180:         * Must be able to put at least 8 bytes per fragment.
                    181:         */
                    182:        if (ip->ip_off & IP_DF) {
                    183:                error = EMSGSIZE;
                    184:                goto bad;
                    185:        }
                    186:        len = (ifp->if_mtu - hlen) &~ 7;
                    187:        if (len < 8) {
                    188:                error = EMSGSIZE;
                    189:                goto bad;
                    190:        }
                    191: 
                    192:     {
                    193:        int mhlen, firstlen = len;
                    194:        struct mbuf **mnext = &m->m_act;
                    195: 
                    196:        /*
                    197:         * Loop through length of segment after first fragment,
                    198:         * make new header and copy data of each part and link onto chain.
                    199:         */
                    200:        m0 = m;
                    201:        mhlen = sizeof (struct ip);
                    202:        for (off = hlen + len; off < ip->ip_len; off += len) {
                    203:                MGET(m, M_DONTWAIT, MT_HEADER);
                    204:                if (m == 0) {
                    205:                        error = ENOBUFS;
                    206:                        goto sendorfree;
                    207:                }
                    208:                m->m_off = MMAXOFF - hlen;
                    209:                mhip = mtod(m, struct ip *);
                    210:                *mhip = *ip;
                    211:                if (hlen > sizeof (struct ip)) {
                    212:                        mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
                    213:                        mhip->ip_hl = mhlen >> 2;
                    214:                }
                    215:                m->m_len = mhlen;
                    216:                mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
                    217:                if (ip->ip_off & IP_MF)
                    218:                        mhip->ip_off |= IP_MF;
                    219:                if (off + len >= ip->ip_len)
                    220:                        len = ip->ip_len - off;
                    221:                else
                    222:                        mhip->ip_off |= IP_MF;
                    223:                mhip->ip_len = htons((u_short)(len + mhlen));
                    224:                m->m_next = m_copy(m0, off, len);
                    225:                if (m->m_next == 0) {
                    226:                        error = ENOBUFS;        /* ??? */
                    227:                        goto sendorfree;
                    228:                }
                    229:                mhip->ip_off = htons((u_short)mhip->ip_off);
                    230:                mhip->ip_sum = 0;
                    231:                mhip->ip_sum = in_cksum(m, mhlen);
                    232:                *mnext = m;
                    233:                mnext = &m->m_act;
                    234:        }
                    235:        /*
                    236:         * Update first fragment by trimming what's been copied out
                    237:         * and updating header, then send each fragment (in order).
                    238:         */
                    239:        m_adj(m0, hlen + firstlen - ip->ip_len);
                    240:        ip->ip_len = htons((u_short)(hlen + firstlen));
                    241:        ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
                    242:        ip->ip_sum = 0;
                    243:        ip->ip_sum = in_cksum(m0, hlen);
                    244: sendorfree:
                    245:        for (m = m0; m; m = m0) {
                    246:                m0 = m->m_act;
                    247:                m->m_act = 0;
                    248:                if (error == 0)
                    249:                        error = (*ifp->if_output)(ifp, m,
                    250:                            (struct sockaddr *)dst);
                    251:                else
                    252:                        m_freem(m);
                    253:        }
                    254:     }
                    255: done:
                    256:        if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt)
                    257:                RTFREE(ro->ro_rt);
                    258:        return (error);
                    259: bad:
                    260:        m_freem(m0);
                    261:        goto done;
                    262: }
                    263: 
                    264: /*
                    265:  * Insert IP options into preformed packet.
                    266:  * Adjust IP destination as required for IP source routing,
                    267:  * as indicated by a non-zero in_addr at the start of the options.
                    268:  */
                    269: struct mbuf *
                    270: ip_insertoptions(m, opt, phlen)
                    271:        register struct mbuf *m;
                    272:        struct mbuf *opt;
                    273:        int *phlen;
                    274: {
                    275:        register struct ipoption *p = mtod(opt, struct ipoption *);
                    276:        struct mbuf *n;
                    277:        register struct ip *ip = mtod(m, struct ip *);
                    278:        unsigned optlen;
                    279: 
                    280:        optlen = opt->m_len - sizeof(p->ipopt_dst);
                    281:        if (p->ipopt_dst.s_addr)
                    282:                ip->ip_dst = p->ipopt_dst;
                    283:        if (m->m_off >= MMAXOFF || MMINOFF + optlen > m->m_off) {
                    284:                MGET(n, M_DONTWAIT, MT_HEADER);
                    285:                if (n == 0)
                    286:                        return (m);
                    287:                m->m_len -= sizeof(struct ip);
                    288:                m->m_off += sizeof(struct ip);
                    289:                n->m_next = m;
                    290:                m = n;
                    291:                m->m_off = MMAXOFF - sizeof(struct ip) - optlen;
                    292:                m->m_len = optlen + sizeof(struct ip);
                    293:                bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
                    294:        } else {
                    295:                m->m_off -= optlen;
                    296:                m->m_len += optlen;
                    297:                ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
                    298:        }
                    299:        ip = mtod(m, struct ip *);
                    300:        bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen);
                    301:        *phlen = sizeof(struct ip) + optlen;
                    302:        ip->ip_len += optlen;
                    303:        return (m);
                    304: }
                    305: 
                    306: /*
                    307:  * Copy options from ip to jp,
                    308:  * omitting those not copied during fragmentation.
                    309:  */
                    310: ip_optcopy(ip, jp)
                    311:        struct ip *ip, *jp;
                    312: {
                    313:        register u_char *cp, *dp;
                    314:        int opt, optlen, cnt;
                    315: 
                    316:        cp = (u_char *)(ip + 1);
                    317:        dp = (u_char *)(jp + 1);
                    318:        cnt = (ip->ip_hl << 2) - sizeof (struct ip);
                    319:        for (; cnt > 0; cnt -= optlen, cp += optlen) {
                    320:                opt = cp[0];
                    321:                if (opt == IPOPT_EOL)
                    322:                        break;
                    323:                if (opt == IPOPT_NOP)
                    324:                        optlen = 1;
                    325:                else
                    326:                        optlen = cp[IPOPT_OLEN];
                    327:                /* bogus lengths should have been caught by ip_dooptions */
                    328:                if (optlen > cnt)
                    329:                        optlen = cnt;
                    330:                if (IPOPT_COPIED(opt)) {
                    331:                        bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
                    332:                        dp += optlen;
                    333:                }
                    334:        }
                    335:        for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
                    336:                *dp++ = IPOPT_EOL;
                    337:        return (optlen);
                    338: }
                    339: 
                    340: /*
                    341:  * IP socket option processing.
                    342:  */
                    343: ip_ctloutput(op, so, level, optname, m)
                    344:        int op;
                    345:        struct socket *so;
                    346:        int level, optname;
                    347:        struct mbuf **m;
                    348: {
                    349:        int error = 0;
                    350:        struct inpcb *inp = sotoinpcb(so);
                    351: 
                    352:        if (level != IPPROTO_IP)
                    353:                error = EINVAL;
                    354:        else switch (op) {
                    355: 
                    356:        case PRCO_SETOPT:
                    357:                switch (optname) {
                    358:                case IP_OPTIONS:
                    359:                        return (ip_pcbopts(&inp->inp_options, *m));
                    360: 
                    361:                default:
                    362:                        error = EINVAL;
                    363:                        break;
                    364:                }
                    365:                break;
                    366: 
                    367:        case PRCO_GETOPT:
                    368:                switch (optname) {
                    369:                case IP_OPTIONS:
                    370:                        *m = m_get(M_WAIT, MT_SOOPTS);
                    371:                        if (inp->inp_options) {
                    372:                                (*m)->m_off = inp->inp_options->m_off;
                    373:                                (*m)->m_len = inp->inp_options->m_len;
                    374:                                bcopy(mtod(inp->inp_options, caddr_t),
                    375:                                    mtod(*m, caddr_t), (unsigned)(*m)->m_len);
                    376:                        } else
                    377:                                (*m)->m_len = 0;
                    378:                        break;
                    379:                default:
                    380:                        error = EINVAL;
                    381:                        break;
                    382:                }
                    383:                break;
                    384:        }
                    385:        if (op == PRCO_SETOPT && *m)
                    386:                (void)m_free(*m);
                    387:        return (error);
                    388: }
                    389: 
                    390: /*
                    391:  * Set up IP options in pcb for insertion in output packets.
                    392:  * Store in mbuf with pointer in pcbopt, adding pseudo-option
                    393:  * with destination address if source routed.
                    394:  */
                    395: ip_pcbopts(pcbopt, m)
                    396:        struct mbuf **pcbopt;
                    397:        register struct mbuf *m;
                    398: {
                    399:        register cnt, optlen;
                    400:        register u_char *cp;
                    401:        u_char opt;
                    402: 
                    403:        /* turn off any old options */
                    404:        if (*pcbopt)
                    405:                (void)m_free(*pcbopt);
                    406:        *pcbopt = 0;
                    407:        if (m == (struct mbuf *)0 || m->m_len == 0) {
                    408:                /*
                    409:                 * Only turning off any previous options.
                    410:                 */
                    411:                if (m)
                    412:                        (void)m_free(m);
                    413:                return (0);
                    414:        }
                    415: 
                    416: #ifndef        vax
                    417:        if (m->m_len % sizeof(long))
                    418:                goto bad;
                    419: #endif
                    420:        /*
                    421:         * IP first-hop destination address will be stored before
                    422:         * actual options; move other options back
                    423:         * and clear it when none present.
                    424:         */
                    425: #if    MAX_IPOPTLEN >= MMAXOFF - MMINOFF
                    426:        if (m->m_off + m->m_len + sizeof(struct in_addr) > MAX_IPOPTLEN)
                    427:                goto bad;
                    428: #else
                    429:        if (m->m_off + m->m_len + sizeof(struct in_addr) > MMAXOFF)
                    430:                goto bad;
                    431: #endif
                    432:        cnt = m->m_len;
                    433:        m->m_len += sizeof(struct in_addr);
                    434:        cp = mtod(m, u_char *) + sizeof(struct in_addr);
                    435:        ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
                    436:        bzero(mtod(m, caddr_t), sizeof(struct in_addr));
                    437: 
                    438:        for (; cnt > 0; cnt -= optlen, cp += optlen) {
                    439:                opt = cp[IPOPT_OPTVAL];
                    440:                if (opt == IPOPT_EOL)
                    441:                        break;
                    442:                if (opt == IPOPT_NOP)
                    443:                        optlen = 1;
                    444:                else {
                    445:                        optlen = cp[IPOPT_OLEN];
                    446:                        if (optlen <= IPOPT_OLEN || optlen > cnt)
                    447:                                goto bad;
                    448:                }
                    449:                switch (opt) {
                    450: 
                    451:                default:
                    452:                        break;
                    453: 
                    454:                case IPOPT_LSRR:
                    455:                case IPOPT_SSRR:
                    456:                        /*
                    457:                         * user process specifies route as:
                    458:                         *      ->A->B->C->D
                    459:                         * D must be our final destination (but we can't
                    460:                         * check that since we may not have connected yet).
                    461:                         * A is first hop destination, which doesn't appear in
                    462:                         * actual IP option, but is stored before the options.
                    463:                         */
                    464:                        if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
                    465:                                goto bad;
                    466:                        m->m_len -= sizeof(struct in_addr);
                    467:                        cnt -= sizeof(struct in_addr);
                    468:                        optlen -= sizeof(struct in_addr);
                    469:                        cp[IPOPT_OLEN] = optlen;
                    470:                        /*
                    471:                         * Move first hop before start of options.
                    472:                         */
                    473:                        bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
                    474:                            sizeof(struct in_addr));
                    475:                        /*
                    476:                         * Then copy rest of options back
                    477:                         * to close up the deleted entry.
                    478:                         */
                    479:                        ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
                    480:                            sizeof(struct in_addr)),
                    481:                            (caddr_t)&cp[IPOPT_OFFSET+1],
                    482:                            (unsigned)cnt + sizeof(struct in_addr));
                    483:                        break;
                    484:                }
                    485:        }
                    486:        *pcbopt = m;
                    487:        return (0);
                    488: 
                    489: bad:
                    490:        (void)m_free(m);
                    491:        return (EINVAL);
                    492: }

unix.superglobalmegacorp.com

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