1/* SPDX-License-Identifier: BSD-3-Clause */
2/*
3 * Copyright (c) 1982, 1986, 1988, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * @(#)ip_input.c 8.2 (Berkeley) 1/4/94
31 * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp
32 */
33
34/*
35 * Changes and additions relating to SLiRP are
36 * Copyright (c) 1995 Danny Gasparovski.
37 */
38
39#include "slirp.h"
40#include "ip_icmp.h"
41
42static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp);
43static void ip_freef(Slirp *slirp, struct ipq *fp);
44static void ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev);
45static void ip_deq(register struct ipasfrag *p);
46
47/*
48 * IP initialization: fill in IP protocol switch table.
49 * All protocols not implemented in kernel go to raw IP protocol handler.
50 */
51void ip_init(Slirp *slirp)
52{
53 slirp->ipq.ip_link.next = slirp->ipq.ip_link.prev = &slirp->ipq.ip_link;
54 udp_init(slirp);
55 tcp_init(slirp);
56 icmp_init(slirp);
57}
58
59void ip_cleanup(Slirp *slirp)
60{
61 udp_cleanup(slirp);
62 tcp_cleanup(slirp);
63 icmp_cleanup(slirp);
64}
65
66/*
67 * Ip input routine. Checksum and byte swap header. If fragmented
68 * try to reassemble. Process options. Pass to next level.
69 */
70void ip_input(struct mbuf *m)
71{
72 Slirp *slirp = m->slirp;
73 register struct ip *ip;
74 int hlen;
75
76 if (!slirp->in_enabled) {
77 goto bad;
78 }
79
80 DEBUG_CALL("ip_input");
81 DEBUG_ARG("m = %p", m);
82 DEBUG_ARG("m_len = %d", m->m_len);
83
84 if (m->m_len < sizeof(struct ip)) {
85 goto bad;
86 }
87
88 ip = mtod(m, struct ip *);
89
90 if (ip->ip_v != IPVERSION) {
91 goto bad;
92 }
93
94 hlen = ip->ip_hl << 2;
95 if (hlen < sizeof(struct ip) || hlen > m->m_len) { /* min header length */
96 goto bad; /* or packet too short */
97 }
98
99 /* keep ip header intact for ICMP reply
100 * ip->ip_sum = cksum(m, hlen);
101 * if (ip->ip_sum) {
102 */
103 if (cksum(m, hlen)) {
104 goto bad;
105 }
106
107 /*
108 * Convert fields to host representation.
109 */
110 NTOHS(ip->ip_len);
111 if (ip->ip_len < hlen) {
112 goto bad;
113 }
114 NTOHS(ip->ip_id);
115 NTOHS(ip->ip_off);
116
117 /*
118 * Check that the amount of data in the buffers
119 * is as at least much as the IP header would have us expect.
120 * Trim mbufs if longer than we expect.
121 * Drop packet if shorter than we expect.
122 */
123 if (m->m_len < ip->ip_len) {
124 goto bad;
125 }
126
127 /* Should drop packet if mbuf too long? hmmm... */
128 if (m->m_len > ip->ip_len)
129 m_adj(m, ip->ip_len - m->m_len);
130
131 /* check ip_ttl for a correct ICMP reply */
132 if (ip->ip_ttl == 0) {
133 icmp_send_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, "ttl");
134 goto bad;
135 }
136
137 /*
138 * If offset or IP_MF are set, must reassemble.
139 * Otherwise, nothing need be done.
140 * (We could look in the reassembly queue to see
141 * if the packet was previously fragmented,
142 * but it's not worth the time; just let them time out.)
143 *
144 * XXX This should fail, don't fragment yet
145 */
146 if (ip->ip_off & ~IP_DF) {
147 register struct ipq *fp;
148 struct qlink *l;
149 /*
150 * Look for queue of fragments
151 * of this datagram.
152 */
153 for (l = slirp->ipq.ip_link.next; l != &slirp->ipq.ip_link;
154 l = l->next) {
155 fp = container_of(l, struct ipq, ip_link);
156 if (ip->ip_id == fp->ipq_id &&
157 ip->ip_src.s_addr == fp->ipq_src.s_addr &&
158 ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
159 ip->ip_p == fp->ipq_p)
160 goto found;
161 }
162 fp = NULL;
163 found:
164
165 /*
166 * Adjust ip_len to not reflect header,
167 * set ip_mff if more fragments are expected,
168 * convert offset of this to bytes.
169 */
170 ip->ip_len -= hlen;
171 if (ip->ip_off & IP_MF)
172 ip->ip_tos |= 1;
173 else
174 ip->ip_tos &= ~1;
175
176 ip->ip_off <<= 3;
177
178 /*
179 * If datagram marked as having more fragments
180 * or if this is not the first fragment,
181 * attempt reassembly; if it succeeds, proceed.
182 */
183 if (ip->ip_tos & 1 || ip->ip_off) {
184 ip = ip_reass(slirp, ip, fp);
185 if (ip == NULL)
186 return;
187 m = dtom(slirp, ip);
188 } else if (fp)
189 ip_freef(slirp, fp);
190
191 } else
192 ip->ip_len -= hlen;
193
194 /*
195 * Switch out to protocol's input routine.
196 */
197 switch (ip->ip_p) {
198 case IPPROTO_TCP:
199 tcp_input(m, hlen, (struct socket *)NULL, AF_INET);
200 break;
201 case IPPROTO_UDP:
202 udp_input(m, hlen);
203 break;
204 case IPPROTO_ICMP:
205 icmp_input(m, hlen);
206 break;
207 default:
208 m_free(m);
209 }
210 return;
211bad:
212 m_free(m);
213}
214
215#define iptofrag(P) ((struct ipasfrag *)(((char *)(P)) - sizeof(struct qlink)))
216#define fragtoip(P) ((struct ip *)(((char *)(P)) + sizeof(struct qlink)))
217/*
218 * Take incoming datagram fragment and try to
219 * reassemble it into whole datagram. If a chain for
220 * reassembly of this datagram already exists, then it
221 * is given as fp; otherwise have to make a chain.
222 */
223static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)
224{
225 register struct mbuf *m = dtom(slirp, ip);
226 register struct ipasfrag *q;
227 int hlen = ip->ip_hl << 2;
228 int i, next;
229
230 DEBUG_CALL("ip_reass");
231 DEBUG_ARG("ip = %p", ip);
232 DEBUG_ARG("fp = %p", fp);
233 DEBUG_ARG("m = %p", m);
234
235 /*
236 * Presence of header sizes in mbufs
237 * would confuse code below.
238 * Fragment m_data is concatenated.
239 */
240 m->m_data += hlen;
241 m->m_len -= hlen;
242
243 /*
244 * If first fragment to arrive, create a reassembly queue.
245 */
246 if (fp == NULL) {
247 struct mbuf *t = m_get(slirp);
248
249 if (t == NULL) {
250 goto dropfrag;
251 }
252 fp = mtod(t, struct ipq *);
253 insque(&fp->ip_link, &slirp->ipq.ip_link);
254 fp->ipq_ttl = IPFRAGTTL;
255 fp->ipq_p = ip->ip_p;
256 fp->ipq_id = ip->ip_id;
257 fp->frag_link.next = fp->frag_link.prev = &fp->frag_link;
258 fp->ipq_src = ip->ip_src;
259 fp->ipq_dst = ip->ip_dst;
260 q = (struct ipasfrag *)fp;
261 goto insert;
262 }
263
264 /*
265 * Find a segment which begins after this one does.
266 */
267 for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
268 q = q->ipf_next)
269 if (q->ipf_off > ip->ip_off)
270 break;
271
272 /*
273 * If there is a preceding segment, it may provide some of
274 * our data already. If so, drop the data from the incoming
275 * segment. If it provides all of our data, drop us.
276 */
277 if (q->ipf_prev != &fp->frag_link) {
278 struct ipasfrag *pq = q->ipf_prev;
279 i = pq->ipf_off + pq->ipf_len - ip->ip_off;
280 if (i > 0) {
281 if (i >= ip->ip_len)
282 goto dropfrag;
283 m_adj(dtom(slirp, ip), i);
284 ip->ip_off += i;
285 ip->ip_len -= i;
286 }
287 }
288
289 /*
290 * While we overlap succeeding segments trim them or,
291 * if they are completely covered, dequeue them.
292 */
293 while (q != (struct ipasfrag *)&fp->frag_link &&
294 ip->ip_off + ip->ip_len > q->ipf_off) {
295 i = (ip->ip_off + ip->ip_len) - q->ipf_off;
296 if (i < q->ipf_len) {
297 q->ipf_len -= i;
298 q->ipf_off += i;
299 m_adj(dtom(slirp, q), i);
300 break;
301 }
302 q = q->ipf_next;
303 m_free(dtom(slirp, q->ipf_prev));
304 ip_deq(q->ipf_prev);
305 }
306
307insert:
308 /*
309 * Stick new segment in its place;
310 * check for complete reassembly.
311 */
312 ip_enq(iptofrag(ip), q->ipf_prev);
313 next = 0;
314 for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
315 q = q->ipf_next) {
316 if (q->ipf_off != next)
317 return NULL;
318 next += q->ipf_len;
319 }
320 if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1)
321 return NULL;
322
323 /*
324 * Reassembly is complete; concatenate fragments.
325 */
326 q = fp->frag_link.next;
327 m = dtom(slirp, q);
328
329 int was_ext = m->m_flags & M_EXT;
330
331 q = (struct ipasfrag *)q->ipf_next;
332 while (q != (struct ipasfrag *)&fp->frag_link) {
333 struct mbuf *t = dtom(slirp, q);
334 q = (struct ipasfrag *)q->ipf_next;
335 m_cat(m, t);
336 }
337
338 /*
339 * Create header for new ip packet by
340 * modifying header of first packet;
341 * dequeue and discard fragment reassembly header.
342 * Make header visible.
343 */
344 q = fp->frag_link.next;
345
346 /*
347 * If the fragments concatenated to an mbuf that's
348 * bigger than the total size of the fragment, then and
349 * m_ext buffer was alloced. But fp->ipq_next points to
350 * the old buffer (in the mbuf), so we must point ip
351 * into the new buffer.
352 */
353 if (!was_ext && m->m_flags & M_EXT) {
354 int delta = (char *)q - m->m_dat;
355 q = (struct ipasfrag *)(m->m_ext + delta);
356 }
357
358 ip = fragtoip(q);
359 ip->ip_len = next;
360 ip->ip_tos &= ~1;
361 ip->ip_src = fp->ipq_src;
362 ip->ip_dst = fp->ipq_dst;
363 remque(&fp->ip_link);
364 (void)m_free(dtom(slirp, fp));
365 m->m_len += (ip->ip_hl << 2);
366 m->m_data -= (ip->ip_hl << 2);
367
368 return ip;
369
370dropfrag:
371 m_free(m);
372 return NULL;
373}
374
375/*
376 * Free a fragment reassembly header and all
377 * associated datagrams.
378 */
379static void ip_freef(Slirp *slirp, struct ipq *fp)
380{
381 register struct ipasfrag *q, *p;
382
383 for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
384 q = p) {
385 p = q->ipf_next;
386 ip_deq(q);
387 m_free(dtom(slirp, q));
388 }
389 remque(&fp->ip_link);
390 (void)m_free(dtom(slirp, fp));
391}
392
393/*
394 * Put an ip fragment on a reassembly chain.
395 * Like insque, but pointers in middle of structure.
396 */
397static void ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev)
398{
399 DEBUG_CALL("ip_enq");
400 DEBUG_ARG("prev = %p", prev);
401 p->ipf_prev = prev;
402 p->ipf_next = prev->ipf_next;
403 ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p;
404 prev->ipf_next = p;
405}
406
407/*
408 * To ip_enq as remque is to insque.
409 */
410static void ip_deq(register struct ipasfrag *p)
411{
412 ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next;
413 ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev;
414}
415
416/*
417 * IP timer processing;
418 * if a timer expires on a reassembly
419 * queue, discard it.
420 */
421void ip_slowtimo(Slirp *slirp)
422{
423 struct qlink *l;
424
425 DEBUG_CALL("ip_slowtimo");
426
427 l = slirp->ipq.ip_link.next;
428
429 if (l == NULL)
430 return;
431
432 while (l != &slirp->ipq.ip_link) {
433 struct ipq *fp = container_of(l, struct ipq, ip_link);
434 l = l->next;
435 if (--fp->ipq_ttl == 0) {
436 ip_freef(slirp, fp);
437 }
438 }
439}
440
441/*
442 * Strip out IP options, at higher
443 * level protocol in the kernel.
444 * Second argument is buffer to which options
445 * will be moved, and return value is their length.
446 * (XXX) should be deleted; last arg currently ignored.
447 */
448void ip_stripoptions(register struct mbuf *m, struct mbuf *mopt)
449{
450 register int i;
451 struct ip *ip = mtod(m, struct ip *);
452 register char *opts;
453 int olen;
454
455 olen = (ip->ip_hl << 2) - sizeof(struct ip);
456 opts = (char *)(ip + 1);
457 i = m->m_len - (sizeof(struct ip) + olen);
458 memcpy(opts, opts + olen, (unsigned)i);
459 m->m_len -= olen;
460
461 ip->ip_hl = sizeof(struct ip) >> 2;
462}
463