|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.