Annotation of cci/sys/netinet/ip_output.c, revision 1.1.1.2

1.1       root        1: /*     ip_output.c     6.1     83/07/29        */
                      2: 
                      3: #include "../h/param.h"
                      4: #include "../h/mbuf.h"
                      5: #include "../h/errno.h"
                      6: #include "../h/socket.h"
                      7: #include "../h/socketvar.h"
                      8: 
                      9: #include "../net/if.h"
                     10: #include "../net/route.h"
                     11: 
                     12: #include "../netinet/in.h"
                     13: #include "../netinet/in_systm.h"
                     14: #include "../netinet/ip.h"
                     15: #include "../netinet/ip_var.h"
                     16: 
                     17: #include "../machine/mtpr.h"
                     18: 
                     19: ip_output(m, opt, ro, flags)
                     20:        struct mbuf *m;
                     21:        struct mbuf *opt;
                     22:        struct route *ro;
                     23:        int flags;
                     24: {
                     25:        register struct ip *ip = mtod(m, struct ip *);
                     26:        register struct ifnet *ifp;
                     27:        int len, hlen = sizeof (struct ip), off, error = 0;
                     28:        struct route iproute;
                     29:        struct sockaddr *dst;
                     30: 
                     31:        if (opt)                                /* XXX */
                     32:                (void) m_free(opt);             /* XXX */
                     33:        /*
                     34:         * Fill in IP header.
                     35:         */
                     36:        ip->ip_hl = hlen >> 2;
                     37:        if ((flags & IP_FORWARDING) == 0) {
                     38:                ip->ip_v = IPVERSION;
                     39:                ip->ip_off &= IP_DF;
                     40:                ip->ip_id = htons(ip_id++);
                     41:        }
                     42: 
                     43:        /*
                     44:         * Route packet.
                     45:         */
                     46:        if (ro == 0) {
                     47:                ro = &iproute;
                     48:                bzero((caddr_t)ro, sizeof (*ro));
                     49:        }
                     50:        dst = &ro->ro_dst;
                     51:        if (ro->ro_rt == 0) {
                     52:                ro->ro_dst.sa_family = AF_INET;
                     53:                ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = ip->ip_dst;
                     54:                /*
                     55:                 * If routing to interface only,
                     56:                 * short circuit routing lookup.
                     57:                 */
                     58:                if (flags & IP_ROUTETOIF) {
                     59:                        ifp = if_ifonnetof(in_netof(ip->ip_dst));
                     60:                        if (ifp == 0) {
                     61:                                error = ENETUNREACH;
                     62:                                goto bad;
                     63:                        }
                     64:                        goto gotif;
                     65:                }
                     66:                rtalloc(ro);
                     67:        }
                     68:        if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
                     69:                error = ENETUNREACH;
                     70:                goto bad;
                     71:        }
                     72:        ro->ro_rt->rt_use++;
                     73:        if (ro->ro_rt->rt_flags & RTF_GATEWAY)
                     74:                dst = &ro->ro_rt->rt_gateway;
                     75: gotif:
                     76: #ifndef notdef
                     77:        /*
                     78:         * If source address not specified yet, use address
                     79:         * of outgoing interface.
                     80:         */
                     81:        if (in_lnaof(ip->ip_src) == INADDR_ANY)
                     82:                ip->ip_src.s_addr =
                     83:                    ((struct sockaddr_in *)&ifp->if_addr)->sin_addr.s_addr;
                     84: #endif
                     85: 
                     86:        /*
                     87:         * Look for broadcast address and
                     88:         * and verify user is allowed to send
                     89:         * such a packet.
                     90:         */
                     91:        if (in_lnaof(((struct sockaddr_in *)dst)->sin_addr) == INADDR_ANY) {
                     92:                if ((ifp->if_flags & IFF_BROADCAST) == 0) {
                     93:                        error = EADDRNOTAVAIL;
                     94:                        goto bad;
                     95:                }
                     96:                if ((flags & IP_ALLOWBROADCAST) == 0) {
                     97:                        error = EACCES;
                     98:                        goto bad;
                     99:                }
                    100:                /* don't allow broadcast messages to be fragmented */
                    101:                if (ip->ip_len > ifp->if_mtu) {
                    102:                        error = EMSGSIZE;
                    103:                        goto bad;
                    104:                }
                    105:        }
                    106: 
                    107:        /*
                    108:         * If small enough for interface, can just send directly.
                    109:         */
                    110:        if (ip->ip_len <= ifp->if_mtu) {
                    111:                ip->ip_len = htons((u_short)ip->ip_len);
                    112:                ip->ip_off = htons((u_short)ip->ip_off);
                    113:                ip->ip_sum = 0;
                    114:                ip->ip_sum = in_cksum(m, hlen);
                    115:                error = (*ifp->if_output)(ifp, m, dst);
                    116:                goto done;
                    117:        }
                    118: 
                    119:        /*
                    120:         * Too large for interface; fragment if possible.
                    121:         * Must be able to put at least 8 bytes per fragment.
                    122:         */
                    123:        if (ip->ip_off & IP_DF) {
                    124:                error = EMSGSIZE;
                    125:                goto bad;
                    126:        }
                    127:        len = (ifp->if_mtu - hlen) &~ 7;
                    128:        if (len < 8) {
                    129:                error = EMSGSIZE;
                    130:                goto bad;
                    131:        }
                    132: 
                    133:        /*
                    134:         * Discard IP header from logical mbuf for m_copy's sake.
                    135:         * Loop through length of segment, make a copy of each
                    136:         * part and output.
                    137:         */
                    138:        m->m_len -= sizeof (struct ip);
                    139:        m->m_off += sizeof (struct ip);
                    140:        for (off = 0; off < ip->ip_len-hlen; off += len) {
                    141:                struct mbuf *mh = m_get(M_DONTWAIT, MT_HEADER);
                    142:                struct ip *mhip;
                    143: 
                    144:                MBUFNULL(9, mh);                        /* for debugging */
                    145:                if (mh == 0) {
                    146:                        error = ENOBUFS;
                    147:                        goto bad;
                    148:                }
                    149:                mh->m_off = MMAXOFF - hlen;
                    150:                mhip = mtod(mh, struct ip *);
                    151:                *mhip = *ip;
                    152:                if (hlen > sizeof (struct ip)) {
                    153:                        int olen = ip_optcopy(ip, mhip, off);
                    154:                        mh->m_len = sizeof (struct ip) + olen;
                    155:                } else
                    156:                        mh->m_len = sizeof (struct ip);
                    157:                mhip->ip_off = off >> 3;
1.1.1.2 ! root      158:                if (off + len >= ip->ip_len-hlen) {
1.1       root      159:                        len = mhip->ip_len = ip->ip_len - hlen - off;
1.1.1.2 ! root      160:                        /*
        !           161:                         * if the output packet has M flag set, make sure
        !           162:                         * this flag is set for the last fragment
        !           163:                         */
        !           164:                        if (ip->ip_off & IP_MF) 
        !           165:                                mhip->ip_off |= IP_MF;
        !           166:                } else {
1.1       root      167:                        mhip->ip_len = len;
                    168:                        mhip->ip_off |= IP_MF;
                    169:                }
                    170:                mhip->ip_len += sizeof (struct ip);
                    171:                mhip->ip_len = htons((u_short)mhip->ip_len);
                    172:                mh->m_next = m_copy(m, off, len);
                    173:                MBUFNULL(36, mh->m_next);       /* for debugging */
                    174:                if (mh->m_next == 0) {
                    175:                        (void) m_free(mh);
                    176:                        error = ENOBUFS;        /* ??? */
                    177:                        goto bad;
                    178:                }
                    179:                mhip->ip_off = htons((u_short)mhip->ip_off);
                    180:                mhip->ip_sum = 0;
                    181:                mhip->ip_sum = in_cksum(mh, hlen);
                    182:                if (error = (*ifp->if_output)(ifp, mh, dst))
                    183:                        break;
                    184:        }
                    185:        m_freem(m);
                    186:        goto done;
                    187: 
                    188: bad:
                    189:        m_freem(m);
                    190: done:
                    191:        if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt)
                    192:                RTFREE(ro->ro_rt);
                    193:        return (error);
                    194: }
                    195: 
                    196: /*
                    197:  * Copy options from ip to jp.
                    198:  * If off is 0 all options are copied
                    199:  * otherwise copy selectively.
                    200:  */
                    201: ip_optcopy(ip, jp, off)
                    202:        struct ip *ip, *jp;
                    203:        int off;
                    204: {
                    205:        register u_char *cp, *dp;
                    206:        int opt, optlen, cnt;
                    207: 
                    208:        cp = (u_char *)(ip + 1);
                    209:        dp = (u_char *)(jp + 1);
                    210:        cnt = (ip->ip_hl << 2) - sizeof (struct ip);
                    211:        for (; cnt > 0; cnt -= optlen, cp += optlen) {
                    212:                opt = cp[0];
                    213:                if (opt == IPOPT_EOL)
                    214:                        break;
                    215:                if (opt == IPOPT_NOP)
                    216:                        optlen = 1;
                    217:                else
                    218:                        optlen = cp[1];
                    219:                if (optlen > cnt)                       /* XXX */
                    220:                        optlen = cnt;                   /* XXX */
                    221:                if (off == 0 || IPOPT_COPIED(opt)) {
                    222:                        bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
                    223:                        dp += optlen;
                    224:                }
                    225:        }
                    226:        for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
                    227:                *dp++ = IPOPT_EOL;
                    228:        return (optlen);
                    229: }

unix.superglobalmegacorp.com

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