Annotation of 42BSD/sys/netinet/ip_output.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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