VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/ip_input.c@ 20383

Last change on this file since 20383 was 20165, checked in by vboxsync, 16 years ago

NAT: build fix

  • Property svn:eol-style set to native
File size: 15.2 KB
Line 
1/*
2 * Copyright (c) 1982, 1986, 1988, 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_input.c 8.2 (Berkeley) 1/4/94
34 * ip_input.c,v 1.11 1994/11/16 10:17:08 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#include "ip_icmp.h"
47#ifdef VBOX_WITH_SLIRP_ALIAS
48# include "alias.h"
49#endif
50
51
52/*
53 * IP initialization: fill in IP protocol switch table.
54 * All protocols not implemented in kernel go to raw IP protocol handler.
55 */
56void
57ip_init(PNATState pData)
58{
59 int i = 0;
60 for (i = 0; i < IPREASS_NHASH; ++i)
61 TAILQ_INIT(&ipq[i]);
62 maxnipq = 100; /* ??? */
63 maxfragsperpacket = 16;
64 nipq = 0;
65 ip_currid = tt.tv_sec & 0xffff;
66 udp_init(pData);
67 tcp_init(pData);
68}
69
70/*
71 * Ip input routine. Checksum and byte swap header. If fragmented
72 * try to reassemble. Process options. Pass to next level.
73 */
74void
75ip_input(PNATState pData, struct mbuf *m)
76{
77 register struct ip *ip;
78 int hlen = 0;
79
80 DEBUG_CALL("ip_input");
81 DEBUG_ARG("m = %lx", (long)m);
82 ip = mtod(m, struct ip *);
83 Log2(("ip_dst=%R[IP4](len:%d) m_len = %d", &ip->ip_dst, ntohs(ip->ip_len), m->m_len));
84 Log2(("ip_dst=%R[IP4](len:%d) m_len = %d\n", &ip->ip_dst, ntohs(ip->ip_len), m->m_len));
85
86 ipstat.ips_total++;
87#ifdef VBOX_WITH_SLIRP_ALIAS
88 {
89 int rc;
90 rc = LibAliasIn(m->m_la ? m->m_la : pData->proxy_alias, mtod(m, char *),
91 m->m_len);
92 Log2(("NAT: LibAlias return %d\n", rc));
93 }
94#endif
95
96 if (m->m_len < sizeof(struct ip))
97 {
98 ipstat.ips_toosmall++;
99 return;
100 }
101
102 ip = mtod(m, struct ip *);
103 if (ip->ip_v != IPVERSION)
104 {
105 ipstat.ips_badvers++;
106 goto bad;
107 }
108
109 hlen = ip->ip_hl << 2;
110 if ( hlen < sizeof(struct ip)
111 || hlen > m->m_len)
112 {
113 /* min header length */
114 ipstat.ips_badhlen++; /* or packet too short */
115 goto bad;
116 }
117
118 /* keep ip header intact for ICMP reply
119 * ip->ip_sum = cksum(m, hlen);
120 * if (ip->ip_sum) {
121 */
122 if (cksum(m, hlen))
123 {
124 ipstat.ips_badsum++;
125 goto bad;
126 }
127
128 /*
129 * Convert fields to host representation.
130 */
131 NTOHS(ip->ip_len);
132 if (ip->ip_len < hlen)
133 {
134 ipstat.ips_badlen++;
135 goto bad;
136 }
137 NTOHS(ip->ip_id);
138 NTOHS(ip->ip_off);
139
140 /*
141 * Check that the amount of data in the buffers
142 * is as at least much as the IP header would have us expect.
143 * Trim mbufs if longer than we expect.
144 * Drop packet if shorter than we expect.
145 */
146 if (m->m_len < ip->ip_len)
147 {
148 ipstat.ips_tooshort++;
149 goto bad;
150 }
151 /* Should drop packet if mbuf too long? hmmm... */
152 if (m->m_len > ip->ip_len)
153 m_adj(m, ip->ip_len - m->m_len);
154
155 /* check ip_ttl for a correct ICMP reply */
156 if (ip->ip_ttl==0 || ip->ip_ttl == 1)
157 {
158 icmp_error(pData, m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, "ttl");
159 goto bad;
160 }
161
162 ip->ip_ttl--;
163 /*
164 * If offset or IP_MF are set, must reassemble.
165 * Otherwise, nothing need be done.
166 * (We could look in the reassembly queue to see
167 * if the packet was previously fragmented,
168 * but it's not worth the time; just let them time out.)
169 *
170 * XXX This should fail, don't fragment yet
171 */
172 if (ip->ip_off & (IP_MF | IP_OFFMASK))
173 {
174 m = ip_reass(pData, m);
175 if (m == NULL)
176 return;
177 ip = mtod(m, struct ip *);
178 hlen = ip->ip_len;
179 }
180 else
181 ip->ip_len -= hlen;
182
183 /*
184 * Switch out to protocol's input routine.
185 */
186 ipstat.ips_delivered++;
187 switch (ip->ip_p)
188 {
189 case IPPROTO_TCP:
190 tcp_input(pData, m, hlen, (struct socket *)NULL);
191 break;
192 case IPPROTO_UDP:
193 udp_input(pData, m, hlen);
194 break;
195 case IPPROTO_ICMP:
196 icmp_input(pData, m, hlen);
197 break;
198 default:
199 ipstat.ips_noproto++;
200 m_free(pData, m);
201 }
202 return;
203bad:
204 Log2(("NAT: IP datagram to %R[IP4] with size(%d) claimed as bad\n",
205 &ip->ip_dst, ip->ip_len));
206 m_freem(pData, m);
207 return;
208}
209
210struct mbuf *
211ip_reass(PNATState pData, struct mbuf* m)
212{
213 struct ip *ip;
214 struct mbuf *p, *q, *nq;
215 struct ipq_t *fp = NULL;
216 struct ipqhead *head;
217 int i, hlen, next;
218 u_short hash;
219
220 /* If maxnipq or maxfragsperpacket are 0, never accept fragments. */
221 if ( maxnipq == 0
222 || maxfragsperpacket == 0)
223 {
224 ipstat.ips_fragments++;
225 ipstat.ips_fragdropped++;
226 m_freem(pData, m);
227 return (NULL);
228 }
229
230 ip = mtod(m, struct ip *);
231 hlen = ip->ip_hl << 2;
232
233 hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
234 head = &ipq[hash];
235
236 /*
237 * Look for queue of fragments
238 * of this datagram.
239 */
240 TAILQ_FOREACH(fp, head, ipq_list)
241 if (ip->ip_id == fp->ipq_id &&
242 ip->ip_src.s_addr == fp->ipq_src.s_addr &&
243 ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
244 ip->ip_p == fp->ipq_p)
245 goto found;
246
247 fp = NULL;
248
249 /*
250 * Attempt to trim the number of allocated fragment queues if it
251 * exceeds the administrative limit.
252 */
253 if ((nipq > maxnipq) && (maxnipq > 0))
254 {
255 /*
256 * drop something from the tail of the current queue
257 * before proceeding further
258 */
259 struct ipq_t *q = TAILQ_LAST(head, ipqhead);
260 if (q == NULL)
261 {
262 /* gak */
263 for (i = 0; i < IPREASS_NHASH; i++)
264 {
265 struct ipq_t *r = TAILQ_LAST(&ipq[i], ipqhead);
266 if (r)
267 {
268 ipstat.ips_fragtimeout += r->ipq_nfrags;
269 ip_freef(pData, &ipq[i], r);
270 break;
271 }
272 }
273 }
274 else
275 {
276 ipstat.ips_fragtimeout += q->ipq_nfrags;
277 ip_freef(pData, head, q);
278 }
279 }
280
281found:
282 /*
283 * Adjust ip_len to not reflect header,
284 * convert offset of this to bytes.
285 */
286 ip->ip_len -= hlen;
287 if (ip->ip_off & IP_MF)
288 {
289 /*
290 * Make sure that fragments have a data length
291 * that's a non-zero multiple of 8 bytes.
292 */
293 if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0)
294 {
295 ipstat.ips_toosmall++; /* XXX */
296 goto dropfrag;
297 }
298 m->m_flags |= M_FRAG;
299 }
300 else
301 m->m_flags &= ~M_FRAG;
302 ip->ip_off <<= 3;
303
304
305 /*
306 * Attempt reassembly; if it succeeds, proceed.
307 * ip_reass() will return a different mbuf.
308 */
309 ipstat.ips_fragments++;
310
311 /* Previous ip_reass() started here. */
312 /*
313 * Presence of header sizes in mbufs
314 * would confuse code below.
315 */
316 m->m_data += hlen;
317 m->m_len -= hlen;
318
319 /*
320 * If first fragment to arrive, create a reassembly queue.
321 */
322 if (fp == NULL)
323 {
324 fp = RTMemAlloc(sizeof(struct ipq_t));
325 if (fp == NULL)
326 goto dropfrag;
327 TAILQ_INSERT_HEAD(head, fp, ipq_list);
328 nipq++;
329 fp->ipq_nfrags = 1;
330 fp->ipq_ttl = IPFRAGTTL;
331 fp->ipq_p = ip->ip_p;
332 fp->ipq_id = ip->ip_id;
333 fp->ipq_src = ip->ip_src;
334 fp->ipq_dst = ip->ip_dst;
335 fp->ipq_frags = m;
336 m->m_nextpkt = NULL;
337 goto done;
338 }
339 else
340 {
341 fp->ipq_nfrags++;
342 }
343
344#define GETIP(m) ((struct ip*)(MBUF_IP_HEADER(m)))
345
346
347 /*
348 * Find a segment which begins after this one does.
349 */
350 for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
351 if (GETIP(q)->ip_off > ip->ip_off)
352 break;
353
354 /*
355 * If there is a preceding segment, it may provide some of
356 * our data already. If so, drop the data from the incoming
357 * segment. If it provides all of our data, drop us, otherwise
358 * stick new segment in the proper place.
359 *
360 * If some of the data is dropped from the the preceding
361 * segment, then it's checksum is invalidated.
362 */
363 if (p)
364 {
365 i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off;
366 if (i > 0)
367 {
368 if (i >= ip->ip_len)
369 goto dropfrag;
370 m_adj(m, i);
371 ip->ip_off += i;
372 ip->ip_len -= i;
373 }
374 m->m_nextpkt = p->m_nextpkt;
375 p->m_nextpkt = m;
376 }
377 else
378 {
379 m->m_nextpkt = fp->ipq_frags;
380 fp->ipq_frags = m;
381 }
382
383 /*
384 * While we overlap succeeding segments trim them or,
385 * if they are completely covered, dequeue them.
386 */
387 for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off;
388 q = nq)
389 {
390 i = (ip->ip_off + ip->ip_len) - GETIP(q)->ip_off;
391 if (i < GETIP(q)->ip_len)
392 {
393 GETIP(q)->ip_len -= i;
394 GETIP(q)->ip_off += i;
395 m_adj(q, i);
396 break;
397 }
398 nq = q->m_nextpkt;
399 m->m_nextpkt = nq;
400 ipstat.ips_fragdropped++;
401 fp->ipq_nfrags--;
402 m_freem(pData, q);
403 }
404
405 /*
406 * Check for complete reassembly and perform frag per packet
407 * limiting.
408 *
409 * Frag limiting is performed here so that the nth frag has
410 * a chance to complete the packet before we drop the packet.
411 * As a result, n+1 frags are actually allowed per packet, but
412 * only n will ever be stored. (n = maxfragsperpacket.)
413 *
414 */
415 next = 0;
416 for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
417 {
418 if (GETIP(q)->ip_off != next)
419 {
420 if (fp->ipq_nfrags > maxfragsperpacket)
421 {
422 ipstat.ips_fragdropped += fp->ipq_nfrags;
423 ip_freef(pData, head, fp);
424 }
425 goto done;
426 }
427 next += GETIP(q)->ip_len;
428 }
429 /* Make sure the last packet didn't have the IP_MF flag */
430 if (p->m_flags & M_FRAG)
431 {
432 if (fp->ipq_nfrags > maxfragsperpacket)
433 {
434 ipstat.ips_fragdropped += fp->ipq_nfrags;
435 ip_freef(pData, head, fp);
436 }
437 goto done;
438 }
439
440 /*
441 * Reassembly is complete. Make sure the packet is a sane size.
442 */
443 q = fp->ipq_frags;
444 ip = GETIP(q);
445 if (next + (ip->ip_hl << 2) > IP_MAXPACKET)
446 {
447 ipstat.ips_fragdropped += fp->ipq_nfrags;
448 ip_freef(pData, head, fp);
449 goto done;
450 }
451
452 /*
453 * Concatenate fragments.
454 */
455 m = q;
456 nq = q->m_nextpkt;
457 q->m_nextpkt = NULL;
458 for (q = nq; q != NULL; q = nq)
459 {
460 nq = q->m_nextpkt;
461 q->m_nextpkt = NULL;
462 m_cat(pData, m, q);
463 }
464
465 /*
466 * Create header for new ip packet by modifying header of first
467 * packet; dequeue and discard fragment reassembly header.
468 * Make header visible.
469 */
470#if 0
471 ip->ip_len = (ip->ip_hl << 2) + next;
472#else
473 ip->ip_len = next;
474#endif
475 ip->ip_src = fp->ipq_src;
476 ip->ip_dst = fp->ipq_dst;
477 TAILQ_REMOVE(head, fp, ipq_list);
478 nipq--;
479 RTMemFree(fp);
480
481 m->m_len += (ip->ip_hl << 2);
482 m->m_data -= (ip->ip_hl << 2);
483 /* some debugging cruft by sklower, below, will go away soon */
484#if 0
485 if (m->m_flags & M_PKTHDR) /* XXX this should be done elsewhere */
486 m_fixhdr(m);
487#endif
488 ipstat.ips_reassembled++;
489 return (m);
490
491dropfrag:
492 ipstat.ips_fragdropped++;
493 if (fp != NULL)
494 fp->ipq_nfrags--;
495 m_freem(pData, m);
496
497done:
498 return NULL;
499
500#undef GETIP
501}
502
503void
504ip_freef(PNATState pData, struct ipqhead *fhp, struct ipq_t *fp)
505{
506 struct mbuf *q;
507
508 while (fp->ipq_frags)
509 {
510 q = fp->ipq_frags;
511 fp->ipq_frags = q->m_nextpkt;
512 m_freem(pData, q);
513 }
514 TAILQ_REMOVE(fhp, fp, ipq_list);
515 RTMemFree(fp);
516 nipq--;
517}
518
519/*
520 * IP timer processing;
521 * if a timer expires on a reassembly
522 * queue, discard it.
523 */
524void
525ip_slowtimo(PNATState pData)
526{
527 register struct ipq_t *fp;
528
529 /* XXX: the fragment expiration is the same but requier
530 * additional loop see (see ip_input.c in FreeBSD tree)
531 */
532 int i;
533 DEBUG_CALL("ip_slowtimo");
534 for (i = 0; i < IPREASS_NHASH; i++)
535 {
536 for(fp = TAILQ_FIRST(&ipq[i]); fp;)
537 {
538 struct ipq_t *fpp;
539
540 fpp = fp;
541 fp = TAILQ_NEXT(fp, ipq_list);
542 if(--fpp->ipq_ttl == 0)
543 {
544 ipstat.ips_fragtimeout += fpp->ipq_nfrags;
545 ip_freef(pData, &ipq[i], fpp);
546 }
547 }
548 }
549 /*
550 * If we are over the maximum number of fragments
551 * (due to the limit being lowered), drain off
552 * enough to get down to the new limit.
553 */
554 if (maxnipq >= 0 && nipq > maxnipq)
555 {
556 for (i = 0; i < IPREASS_NHASH; i++)
557 {
558 while (nipq > maxnipq && !TAILQ_EMPTY(&ipq[i]))
559 {
560 ipstat.ips_fragdropped += TAILQ_FIRST(&ipq[i])->ipq_nfrags;
561 ip_freef(pData, &ipq[i], TAILQ_FIRST(&ipq[i]));
562 }
563 }
564 }
565}
566
567
568/*
569 * Strip out IP options, at higher
570 * level protocol in the kernel.
571 * Second argument is buffer to which options
572 * will be moved, and return value is their length.
573 * (XXX) should be deleted; last arg currently ignored.
574 */
575void
576ip_stripoptions(struct mbuf *m, struct mbuf *mopt)
577{
578 register int i;
579 struct ip *ip = mtod(m, struct ip *);
580 register caddr_t opts;
581 int olen;
582
583 olen = (ip->ip_hl<<2) - sizeof(struct ip);
584 opts = (caddr_t)(ip + 1);
585 i = m->m_len - (sizeof(struct ip) + olen);
586 memcpy(opts, opts + olen, (unsigned)i);
587 m->m_len -= olen;
588
589 ip->ip_hl = sizeof(struct ip) >> 2;
590}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette