|
|
1.1 root 1: /* ip_output.c 6.1 83/07/29 */
2:
3: #include "../h/param.h"
4: #include "../h/stream.h"
5: #include "../h/inet/mbuf.h"
6: #include "../h/inet/in.h"
7: #include "../h/inet/ip.h"
8: #include "../h/inet/ip_var.h"
9:
10: int ip_errors[8];
11:
12: ip_output(m, opt, flags)
13: struct mbuf *m;
14: struct mbuf *opt;
15: int flags;
16: {
17: register struct ip *ip = mtod(m, struct ip *);
18: register struct ipif *ifp;
19: int len, hlen = sizeof (struct ip), off;
20: in_addr dst;
21: struct ip_route_info info;
22:
23: if (opt) /* XXX */
24: (void) m_free(opt); /* XXX */
25: /*
26: * Fill in IP header.
27: */
28: ip->ip_hl = hlen >> 2;
29: if ((flags & IP_FORWARDING) == 0) {
30: ip->ip_v = IPVERSION;
31: ip->ip_off &= IP_DF;
32: ip->ip_id = htons(ip_id++);
33: }
34:
35: dst = ip->ip_dst;
36:
37: /*
38: * If routing to interface only,
39: * short circuit routing lookup.
40: */
41: if (flags & IP_ROUTETOIF) {
42: ifp = ip_ifonnetof(dst);
43: if (ifp == 0)
44: goto bad;
45: goto gotif;
46: }
47: info = ip_route(dst);
48: if(info.ifp == 0){
49: ipstat.ips_route++;
50: goto bad;
51: }
52: ifp = info.ifp;
53: dst = info.addr;
54:
55: gotif:
56: #ifndef notdef
57: /*
58: * If source address not specified yet, use address
59: * of outgoing interface.
60: */
61: if (in_lnaof(ip->ip_src) == INADDR_ANY)
62: ip->ip_src = ifp->thishost;
63: #endif
64:
65: /*
66: * Look for broadcast address and
67: * and verify user is allowed to send
68: * such a packet.
69: */
70: if (in_lnaof(dst) == INADDR_ANY) {
71: /* don't allow broadcast messages to be fragmented */
72: if (ip->ip_len > ifp->mtu) {
73: ip_errors[0]++;
74: goto bad;
75: }
76: }
77:
78: /*
79: * If small enough for interface, can just send directly.
80: */
81: if (ip->ip_len <= ifp->mtu) {
82: ip->ip_src = htonl(ip->ip_src);
83: ip->ip_dst = htonl(ip->ip_dst);
84: ip->ip_len = htons((u_short)ip->ip_len);
85: ip->ip_off = htons((u_short)ip->ip_off);
86: ip->ip_sum = 0;
87: ip->ip_sum = in_cksum(m, hlen);
88: ip_ldout(m, dst, ifp);
89: goto done;
90: }
91: ipstat.ips_fragout++;
92:
93: /*
94: * Too large for interface; fragment if possible.
95: * Must be able to put at least 8 bytes per fragment.
96: */
97: if (ip->ip_off & IP_DF) {
98: goto bad;
99: }
100: len = (ifp->mtu - hlen) &~ 7;
101: if (len < 8) {
102: ip_errors[1]++;
103: goto bad;
104: }
105:
106: /*
107: * Discard IP header from logical mbuf for m_copy's sake.
108: * Loop through length of segment, make a copy of each
109: * part and output.
110: */
111: m->rptr += sizeof (struct ip);
112: for (off = 0; off < ip->ip_len-hlen; off += len) {
113: struct mbuf *mh = m_get(M_DONTWAIT, MT_HEADER);
114: struct ip *mhip;
115:
116: if (mh == 0) {
117: goto bad;
118: }
119: mh->next = 0;
120: mh->rptr = mh->lim - hlen;
121: mhip = mtod(mh, struct ip *);
122: *mhip = *ip;
123: if (hlen > sizeof (struct ip)) {
124: int olen = ip_optcopy(ip, mhip, off);
125: mh->wptr = mh->rptr + sizeof (struct ip) + olen;
126: } else
127: mh->wptr = mh->rptr + sizeof (struct ip);
128: mhip->ip_off = off >> 3;
129: /* HOMER fix: */
130: if(ip->ip_off & IP_MF) mhip->ip_off |= IP_MF;
131: /* :xif REMOH */
132: if (off + len >= ip->ip_len-hlen)
133: len = mhip->ip_len = ip->ip_len - hlen - off;
134: else {
135: mhip->ip_len = len;
136: mhip->ip_off |= IP_MF;
137: }
138: mhip->ip_len += sizeof (struct ip);
139: mhip->ip_len = htons((u_short)mhip->ip_len);
140: mh->m_next = m_copy(m, off, len);
141: if (mh->m_next == 0) {
142: (void) m_free(mh);
143: goto bad;
144: }
145: mhip->ip_off = htons((u_short)mhip->ip_off);
146: mhip->ip_src = htonl(mhip->ip_src);
147: mhip->ip_dst = htonl(mhip->ip_dst);
148: mhip->ip_sum = 0;
149: mhip->ip_sum = in_cksum(mh, hlen);
150: if (ip_ldout(mh, dst, ifp))
151: break;
152: }
153: m_freem(m);
154: goto done;
155:
156: bad:
157: m_freem(m);
158: done:
159: return(0);
160: }
161:
162: /*
163: * Copy options from ip to jp.
164: * If off is 0 all options are copied
165: * otherwise copy selectively.
166: */
167: ip_optcopy(ip, jp, off)
168: struct ip *ip, *jp;
169: int off;
170: {
171: register u_char *cp, *dp;
172: int opt, optlen, cnt;
173:
174: cp = (u_char *)(ip + 1);
175: dp = (u_char *)(jp + 1);
176: cnt = (ip->ip_hl << 2) - sizeof (struct ip);
177: for (; cnt > 0; cnt -= optlen, cp += optlen) {
178: opt = cp[0];
179: if (opt == IPOPT_EOL)
180: break;
181: if (opt == IPOPT_NOP)
182: optlen = 1;
183: else
184: optlen = cp[1];
185: if (optlen > cnt) /* XXX */
186: optlen = cnt; /* XXX */
187: if (off == 0 || IPOPT_COPIED(opt)) {
188: bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
189: dp += optlen;
190: }
191: }
192: for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
193: *dp++ = IPOPT_EOL;
194: return (optlen);
195: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.