44 |
#include "lwip/def.h" |
#include "lwip/def.h" |
45 |
#include "lwip/mem.h" |
#include "lwip/mem.h" |
46 |
#include "lwip/ip.h" |
#include "lwip/ip.h" |
47 |
|
#include "lwip/ip_frag.h" |
48 |
#include "lwip/inet.h" |
#include "lwip/inet.h" |
49 |
#include "lwip/netif.h" |
#include "lwip/netif.h" |
50 |
#include "lwip/icmp.h" |
#include "lwip/icmp.h" |
221 |
} |
} |
222 |
#endif /* IP_FORWARD */ |
#endif /* IP_FORWARD */ |
223 |
/*-----------------------------------------------------------------------------------*/ |
/*-----------------------------------------------------------------------------------*/ |
|
/* ip_reass: |
|
|
* |
|
|
* Tries to reassemble a fragmented IP packet. |
|
|
*/ |
|
|
/*-----------------------------------------------------------------------------------*/ |
|
|
#define IP_REASSEMBLY 1 |
|
|
#define IP_REASS_BUFSIZE 5760 |
|
|
#define IP_REASS_MAXAGE 10 |
|
|
|
|
|
#if IP_REASSEMBLY |
|
|
static u8_t ip_reassbuf[IP_HLEN + IP_REASS_BUFSIZE]; |
|
|
static u8_t ip_reassbitmap[IP_REASS_BUFSIZE / (8 * 8)]; |
|
|
static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f, |
|
|
0x0f, 0x07, 0x03, 0x01}; |
|
|
static u16_t ip_reasslen; |
|
|
static u8_t ip_reassflags; |
|
|
#define IP_REASS_FLAG_LASTFRAG 0x01 |
|
|
static u8_t ip_reasstmr; |
|
|
|
|
|
static struct pbuf * |
|
|
ip_reass(struct pbuf *p) |
|
|
{ |
|
|
struct pbuf *q; |
|
|
struct ip_hdr *fraghdr, *iphdr; |
|
|
u16_t offset, len; |
|
|
u16_t i; |
|
|
|
|
|
iphdr = (struct ip_hdr *)ip_reassbuf; |
|
|
fraghdr = (struct ip_hdr *)p->payload; |
|
|
|
|
|
/* If ip_reasstmr is zero, no packet is present in the buffer, so we |
|
|
write the IP header of the fragment into the reassembly |
|
|
buffer. The timer is updated with the maximum age. */ |
|
|
if(ip_reasstmr == 0) { |
|
|
DEBUGF(IP_REASS_DEBUG, ("ip_reass: new packet\n")); |
|
|
bcopy(fraghdr, iphdr, IP_HLEN); |
|
|
ip_reasstmr = IP_REASS_MAXAGE; |
|
|
ip_reassflags = 0; |
|
|
/* Clear the bitmap. */ |
|
|
bzero(ip_reassbitmap, sizeof(ip_reassbitmap)); |
|
|
} |
|
|
|
|
|
/* Check if the incoming fragment matches the one currently present |
|
|
in the reasembly buffer. If so, we proceed with copying the |
|
|
fragment into the buffer. */ |
|
|
if(ip_addr_cmp(&iphdr->src, &fraghdr->src) && |
|
|
ip_addr_cmp(&iphdr->dest, &fraghdr->dest) && |
|
|
IPH_ID(iphdr) == IPH_ID(fraghdr)) { |
|
|
DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching old packet\n")); |
|
|
/* Find out the offset in the reassembly buffer where we should |
|
|
copy the fragment. */ |
|
|
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; |
|
|
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; |
|
|
|
|
|
/* If the offset or the offset + fragment length overflows the |
|
|
reassembly buffer, we discard the entire packet. */ |
|
|
if(offset > IP_REASS_BUFSIZE || |
|
|
offset + len > IP_REASS_BUFSIZE) { |
|
|
DEBUGF(IP_REASS_DEBUG, ("ip_reass: fragment outside of buffer (%d:%d/%d).\n", |
|
|
offset, offset + len, IP_REASS_BUFSIZE)); |
|
|
ip_reasstmr = 0; |
|
|
goto nullreturn; |
|
|
} |
|
|
|
|
|
/* Copy the fragment into the reassembly buffer, at the right |
|
|
offset. */ |
|
|
DEBUGF(IP_REASS_DEBUG, ("ip_reass: copying with offset %d into %d:%d\n", |
|
|
offset, IP_HLEN + offset, IP_HLEN + offset + len)); |
|
|
bcopy((u8_t *)fraghdr + IPH_HL(fraghdr) * 4, |
|
|
&ip_reassbuf[IP_HLEN + offset], len); |
|
|
|
|
|
/* Update the bitmap. */ |
|
|
if(offset / (8 * 8) == (offset + len) / (8 * 8)) { |
|
|
DEBUGF(IP_REASS_DEBUG, ("ip_reass: updating single byte in bitmap.\n")); |
|
|
/* If the two endpoints are in the same byte, we only update |
|
|
that byte. */ |
|
|
ip_reassbitmap[offset / (8 * 8)] |= |
|
|
bitmap_bits[(offset / 8 ) & 7] & |
|
|
~bitmap_bits[((offset + len) / 8 ) & 7]; |
|
|
} else { |
|
|
/* If the two endpoints are in different bytes, we update the |
|
|
bytes in the endpoints and fill the stuff inbetween with |
|
|
0xff. */ |
|
|
ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8 ) & 7]; |
|
|
DEBUGF(IP_REASS_DEBUG, ("ip_reass: updating many bytes in bitmap (%d:%d).\n", |
|
|
1 + offset / (8 * 8), (offset + len) / (8 * 8))); |
|
|
for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) { |
|
|
ip_reassbitmap[i] = 0xff; |
|
|
} |
|
|
ip_reassbitmap[(offset + len) / (8 * 8)] |= ~bitmap_bits[((offset + len) / 8 ) & 7]; |
|
|
} |
|
|
|
|
|
/* If this fragment has the More Fragments flag set to zero, we |
|
|
know that this is the last fragment, so we can calculate the |
|
|
size of the entire packet. We also set the |
|
|
IP_REASS_FLAG_LASTFRAG flag to indicate that we have received |
|
|
the final fragment. */ |
|
|
|
|
|
if((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) { |
|
|
ip_reassflags |= IP_REASS_FLAG_LASTFRAG; |
|
|
ip_reasslen = offset + len; |
|
|
DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, total len %d\n", ip_reasslen)); |
|
|
} |
|
|
|
|
|
/* Finally, we check if we have a full packet in the buffer. We do |
|
|
this by checking if we have the last fragment and if all bits |
|
|
in the bitmap are set. */ |
|
|
if(ip_reassflags & IP_REASS_FLAG_LASTFRAG) { |
|
|
/* Check all bytes up to and including all but the last byte in |
|
|
the bitmap. */ |
|
|
for(i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) { |
|
|
if(ip_reassbitmap[i] != 0xff) { |
|
|
DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, bitmap %d/%d failed (%x)\n", i, ip_reasslen / (8 * 8) - 1, ip_reassbitmap[i])); |
|
|
goto nullreturn; |
|
|
} |
|
|
} |
|
|
/* Check the last byte in the bitmap. It should contain just the |
|
|
right amount of bits. */ |
|
|
if(ip_reassbitmap[ip_reasslen / (8 * 8)] != |
|
|
(u8_t)~bitmap_bits[ip_reasslen / 8 & 7]) { |
|
|
DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, bitmap %d didn't contain %x (%x)\n", |
|
|
ip_reasslen / (8 * 8), ~bitmap_bits[ip_reasslen / 8 & 7], |
|
|
ip_reassbitmap[ip_reasslen / (8 * 8)])); |
|
|
goto nullreturn; |
|
|
} |
|
|
|
|
|
/* Pretend to be a "normal" (i.e., not fragmented) IP packet |
|
|
from now on. */ |
|
|
IPH_OFFSET_SET(iphdr, 0); |
|
|
IPH_CHKSUM_SET(iphdr, 0); |
|
|
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); |
|
|
|
|
|
/* If we have come this far, we have a full packet in the |
|
|
buffer, so we allocate a pbuf and copy the packet into it. We |
|
|
also reset the timer. */ |
|
|
ip_reasstmr = 0; |
|
|
pbuf_free(p); |
|
|
p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL); |
|
|
if(p != NULL) { |
|
|
i = 0; |
|
|
for(q = p; q != NULL; q = q->next) { |
|
|
/* Copy enough bytes to fill this pbuf in the chain. The |
|
|
avaliable data in the pbuf is given by the q->len |
|
|
variable. */ |
|
|
DEBUGF(IP_REASS_DEBUG, ("ip_reass: bcopy from %p (%d) to %p, %d bytes\n", |
|
|
&ip_reassbuf[i], i, q->payload, q->len > ip_reasslen - i? ip_reasslen - i: q->len)); |
|
|
bcopy(&ip_reassbuf[i], q->payload, |
|
|
q->len > ip_reasslen - i? ip_reasslen - i: q->len); |
|
|
i += q->len; |
|
|
} |
|
|
} |
|
|
DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", p)); |
|
|
return p; |
|
|
} |
|
|
} |
|
|
|
|
|
nullreturn: |
|
|
pbuf_free(p); |
|
|
return NULL; |
|
|
} |
|
|
#endif /* IP_REASSEMBLY */ |
|
|
/*-----------------------------------------------------------------------------------*/ |
|
224 |
/* ip_input: |
/* ip_input: |
225 |
* |
* |
226 |
* This function is called by the network interface device driver when |
* This function is called by the network interface device driver when |
507 |
dest = &(iphdr->dest); |
dest = &(iphdr->dest); |
508 |
} |
} |
509 |
|
|
510 |
|
#if IP_FRAG |
511 |
|
if (p->tot_len > netif->mtu) |
512 |
|
return ip_frag(p,netif,dest); |
513 |
|
#endif |
514 |
|
|
515 |
#ifdef IP_STATS |
#ifdef IP_STATS |
516 |
stats.ip.xmit++; |
stats.ip.xmit++; |
517 |
#endif /* IP_STATS */ |
#endif /* IP_STATS */ |