|
1 /* |
|
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993 |
|
3 * The Regents of the University of California. All rights reserved. |
|
4 * |
|
5 * Redistribution and use in source and binary forms, with or without |
|
6 * modification, are permitted provided that the following conditions |
|
7 * are met: |
|
8 * 1. Redistributions of source code must retain the above copyright |
|
9 * notice, this list of conditions and the following disclaimer. |
|
10 * 2. Redistributions in binary form must reproduce the above copyright |
|
11 * notice, this list of conditions and the following disclaimer in the |
|
12 * documentation and/or other materials provided with the distribution. |
|
13 * 3. All advertising materials mentioning features or use of this software |
|
14 * must display the following acknowledgement: |
|
15 * This product includes software developed by the University of |
|
16 * California, Berkeley and its contributors. |
|
17 * 4. Neither the name of the University nor the names of its contributors |
|
18 * may be used to endorse or promote products derived from this software |
|
19 * without specific prior written permission. |
|
20 * |
|
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
|
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
|
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
31 * SUCH DAMAGE. |
|
32 * |
|
33 * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 |
|
34 * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp |
|
35 */ |
|
36 |
|
37 /* |
|
38 * Changes and additions relating to SLiRP are |
|
39 * Copyright (c) 1995 Danny Gasparovski. |
|
40 * |
|
41 * Please read the file COPYRIGHT for the |
|
42 * terms and conditions of the copyright. |
|
43 */ |
|
44 |
|
45 #include <slirp.h> |
|
46 |
|
47 u_int16_t ip_id; |
|
48 |
|
49 /* Number of packets queued before we start sending |
|
50 * (to prevent allocing too many mbufs) */ |
|
51 #define IF_THRESH 10 |
|
52 |
|
53 /* |
|
54 * IP output. The packet in mbuf chain m contains a skeletal IP |
|
55 * header (with len, off, ttl, proto, tos, src, dst). |
|
56 * The mbuf chain containing the packet will be freed. |
|
57 * The mbuf opt, if present, will not be freed. |
|
58 */ |
|
59 int |
|
60 ip_output(so, m0) |
|
61 struct socket *so; |
|
62 struct mbuf *m0; |
|
63 { |
|
64 register struct ip *ip; |
|
65 register struct mbuf *m = m0; |
|
66 register int hlen = sizeof(struct ip ); |
|
67 int len, off, error = 0; |
|
68 |
|
69 DEBUG_CALL("ip_output"); |
|
70 DEBUG_ARG("so = %lx", (long)so); |
|
71 DEBUG_ARG("m0 = %lx", (long)m0); |
|
72 |
|
73 /* We do no options */ |
|
74 /* if (opt) { |
|
75 * m = ip_insertoptions(m, opt, &len); |
|
76 * hlen = len; |
|
77 * } |
|
78 */ |
|
79 ip = mtod(m, struct ip *); |
|
80 /* |
|
81 * Fill in IP header. |
|
82 */ |
|
83 ip->ip_v = IPVERSION; |
|
84 ip->ip_off &= IP_DF; |
|
85 ip->ip_id = htons(ip_id++); |
|
86 ip->ip_hl = hlen >> 2; |
|
87 STAT(ipstat.ips_localout++); |
|
88 |
|
89 /* |
|
90 * Verify that we have any chance at all of being able to queue |
|
91 * the packet or packet fragments |
|
92 */ |
|
93 /* XXX Hmmm... */ |
|
94 /* if (if_queued > IF_THRESH && towrite <= 0) { |
|
95 * error = ENOBUFS; |
|
96 * goto bad; |
|
97 * } |
|
98 */ |
|
99 |
|
100 /* |
|
101 * If small enough for interface, can just send directly. |
|
102 */ |
|
103 if ((u_int16_t)ip->ip_len <= IF_MTU) { |
|
104 ip->ip_len = htons((u_int16_t)ip->ip_len); |
|
105 ip->ip_off = htons((u_int16_t)ip->ip_off); |
|
106 ip->ip_sum = 0; |
|
107 ip->ip_sum = cksum(m, hlen); |
|
108 |
|
109 if_output(so, m); |
|
110 goto done; |
|
111 } |
|
112 |
|
113 /* |
|
114 * Too large for interface; fragment if possible. |
|
115 * Must be able to put at least 8 bytes per fragment. |
|
116 */ |
|
117 if (ip->ip_off & IP_DF) { |
|
118 error = -1; |
|
119 STAT(ipstat.ips_cantfrag++); |
|
120 goto bad; |
|
121 } |
|
122 |
|
123 len = (IF_MTU - hlen) &~ 7; /* ip databytes per packet */ |
|
124 if (len < 8) { |
|
125 error = -1; |
|
126 goto bad; |
|
127 } |
|
128 |
|
129 { |
|
130 int mhlen, firstlen = len; |
|
131 struct mbuf **mnext = &m->m_nextpkt; |
|
132 |
|
133 /* |
|
134 * Loop through length of segment after first fragment, |
|
135 * make new header and copy data of each part and link onto chain. |
|
136 */ |
|
137 m0 = m; |
|
138 mhlen = sizeof (struct ip); |
|
139 for (off = hlen + len; off < (u_int16_t)ip->ip_len; off += len) { |
|
140 register struct ip *mhip; |
|
141 m = m_get(); |
|
142 if (m == 0) { |
|
143 error = -1; |
|
144 STAT(ipstat.ips_odropped++); |
|
145 goto sendorfree; |
|
146 } |
|
147 m->m_data += IF_MAXLINKHDR; |
|
148 mhip = mtod(m, struct ip *); |
|
149 *mhip = *ip; |
|
150 |
|
151 /* No options */ |
|
152 /* if (hlen > sizeof (struct ip)) { |
|
153 * mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); |
|
154 * mhip->ip_hl = mhlen >> 2; |
|
155 * } |
|
156 */ |
|
157 m->m_len = mhlen; |
|
158 mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); |
|
159 if (ip->ip_off & IP_MF) |
|
160 mhip->ip_off |= IP_MF; |
|
161 if (off + len >= (u_int16_t)ip->ip_len) |
|
162 len = (u_int16_t)ip->ip_len - off; |
|
163 else |
|
164 mhip->ip_off |= IP_MF; |
|
165 mhip->ip_len = htons((u_int16_t)(len + mhlen)); |
|
166 |
|
167 if (m_copy(m, m0, off, len) < 0) { |
|
168 error = -1; |
|
169 goto sendorfree; |
|
170 } |
|
171 |
|
172 mhip->ip_off = htons((u_int16_t)mhip->ip_off); |
|
173 mhip->ip_sum = 0; |
|
174 mhip->ip_sum = cksum(m, mhlen); |
|
175 *mnext = m; |
|
176 mnext = &m->m_nextpkt; |
|
177 STAT(ipstat.ips_ofragments++); |
|
178 } |
|
179 /* |
|
180 * Update first fragment by trimming what's been copied out |
|
181 * and updating header, then send each fragment (in order). |
|
182 */ |
|
183 m = m0; |
|
184 m_adj(m, hlen + firstlen - (u_int16_t)ip->ip_len); |
|
185 ip->ip_len = htons((u_int16_t)m->m_len); |
|
186 ip->ip_off = htons((u_int16_t)(ip->ip_off | IP_MF)); |
|
187 ip->ip_sum = 0; |
|
188 ip->ip_sum = cksum(m, hlen); |
|
189 sendorfree: |
|
190 for (m = m0; m; m = m0) { |
|
191 m0 = m->m_nextpkt; |
|
192 m->m_nextpkt = 0; |
|
193 if (error == 0) |
|
194 if_output(so, m); |
|
195 else |
|
196 m_freem(m); |
|
197 } |
|
198 |
|
199 if (error == 0) |
|
200 STAT(ipstat.ips_fragmented++); |
|
201 } |
|
202 |
|
203 done: |
|
204 return (error); |
|
205 |
|
206 bad: |
|
207 m_freem(m0); |
|
208 goto done; |
|
209 } |