Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

ip_frag.c File Reference

#include "lwip/opt.h"
#include "lwip/sys.h"
#include "lwip/ip.h"
#include "lwip/ip_frag.h"
#include "lwip/netif.h"
#include "lwip/stats.h"

Include dependency graph for ip_frag.c:

Go to the source code of this file.

Defines

#define htons   HTONS
#define htonl   HTONL
#define IP_REASS_BUFSIZE   5760
#define IP_REASS_MAXAGE   30
#define IP_REASS_TMO   1000
#define IP_REASS_FLAG_LASTFRAG   0x01
#define MAX_MTU   1500

Functions

pbufcopy_from_pbuf (struct pbuf *p, u16_t *offset, u8_t *buffer, u16_t len)
void ip_reass_timer (int signo)
pbufip_reass (struct pbuf *p)
err_t ip_frag (struct pbuf *p, struct netif *netif, struct ip_addr *dest)

Variables

u8_t ip_reassbuf [IP_HLEN+IP_REASS_BUFSIZE]
u8_t ip_reassbitmap [IP_REASS_BUFSIZE/(8 *8)]
const u8_t bitmap_bits [8]
u16_t ip_reasslen
u8_t ip_reassflags
u8_t ip_reasstmr
u8_t buf [MAX_MTU]


Define Documentation

#define htonl   HTONL
 

Definition at line 51 of file ip_frag.c.

#define htons   HTONS
 

Definition at line 50 of file ip_frag.c.

#define IP_REASS_BUFSIZE   5760
 

Definition at line 79 of file ip_frag.c.

Referenced by ip_reass().

#define IP_REASS_FLAG_LASTFRAG   0x01
 

Definition at line 90 of file ip_frag.c.

Referenced by ip_reass().

#define IP_REASS_MAXAGE   30
 

Definition at line 80 of file ip_frag.c.

Referenced by ip_reass().

#define IP_REASS_TMO   1000
 

Definition at line 81 of file ip_frag.c.

Referenced by ip_reass(), and ip_reass_timer().

#define MAX_MTU   1500
 

Definition at line 280 of file ip_frag.c.


Function Documentation

struct pbuf* copy_from_pbuf struct pbuf p,
u16_t offset,
u8_t buffer,
u16_t  len
[static]
 

Definition at line 59 of file ip_frag.c.

References buffer, len, pbuf::len, pbuf::next, pbuf::payload, u16_t, and u8_t.

Referenced by ip_frag(), and ip_reass().

00061 {
00062   u16_t l;
00063 
00064   p->payload = (u8_t *)p->payload + *offset;
00065   p->len -= *offset;
00066   while (len) {
00067     l = len < p->len ? len : p->len;
00068     memcpy(buffer, p->payload, l);
00069     buffer += l;
00070     len -= l;
00071     if (len)
00072       p = p->next;
00073     else
00074       *offset = l;
00075   }
00076   return p;
00077 }

err_t ip_frag struct pbuf p,
struct netif netif,
struct ip_addr dest
 

Fragment an IP packet if too large

Chop the packet in mtu sized chunks and send them in order by using a fixed size static memory buffer (PBUF_ROM)

Definition at line 290 of file ip_frag.c.

References buf, copy_from_pbuf(), ERR_OK, htons, inet_chksum(), IP_HLEN, IP_MF, IP_OFFMASK, IPH_CHKSUM_SET, IPH_LEN_SET, IPH_OFFSET, IPH_OFFSET_SET, netif::mtu, ntohs, netif::output, pbuf::payload, pbuf_alloc(), pbuf_chain(), pbuf_free(), PBUF_LINK, PBUF_RAM, pbuf_realloc(), PBUF_REF, pbuf::tot_len, u16_t, and u8_t.

Referenced by ip_output_if().

00291 {
00292   struct pbuf *rambuf;
00293   struct pbuf *header;
00294   struct ip_hdr *iphdr;
00295   u16_t nfb = 0;
00296   u16_t left, cop;
00297   u16_t mtu = netif->mtu;
00298   u16_t ofo, omf;
00299   u16_t last;
00300   u16_t poff = IP_HLEN;
00301   u16_t tmp;
00302 
00303   /* Get a RAM based MTU sized pbuf */
00304   rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
00305   rambuf->tot_len = rambuf->len = mtu;
00306   rambuf->payload = buf;
00307 
00308 
00309   /* Copy the IP header in it */
00310   iphdr = rambuf->payload;
00311   memcpy(iphdr, p->payload, IP_HLEN);
00312 
00313   /* Save original offset */
00314   tmp = ntohs(IPH_OFFSET(iphdr));
00315   ofo = tmp & IP_OFFMASK;
00316   omf = tmp & IP_MF;
00317 
00318   left = p->tot_len - IP_HLEN;
00319 
00320   while (left) {
00321     last = (left <= mtu - IP_HLEN);
00322 
00323     /* Set new offset and MF flag */
00324     ofo += nfb;
00325     tmp = omf | (IP_OFFMASK & (ofo));
00326     if (!last)
00327       tmp = tmp | IP_MF;
00328     IPH_OFFSET_SET(iphdr, htons(tmp));
00329 
00330     /* Fill this fragment */
00331     nfb = (mtu - IP_HLEN) / 8;
00332     cop = last ? left : nfb * 8;
00333 
00334     p = copy_from_pbuf(p, &poff, (u8_t *) iphdr + IP_HLEN, cop);
00335 
00336     /* Correct header */
00337     IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
00338     IPH_CHKSUM_SET(iphdr, 0);
00339     IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
00340 
00341     if (last)
00342       pbuf_realloc(rambuf, left + IP_HLEN);
00343     /* This part is ugly: we alloc a RAM based pbuf for 
00344      * the link level header for each chunk and then 
00345      * free it.A PBUF_ROM style pbuf for which pbuf_header
00346      * worked would make things simpler.
00347      */
00348     header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
00349     pbuf_chain(header, rambuf);
00350     netif->output(netif, header, dest);
00351 #ifdef IP_STATS
00352     ++lwip_stats.ip_frag.xmit;
00353 #endif /* IP_STATS */
00354     pbuf_free(header);
00355 
00356     left -= cop;
00357   }
00358   pbuf_free(rambuf);
00359   return ERR_OK;
00360 }

Here is the call graph for this function:

struct pbuf* ip_reass struct pbuf p  ) 
 

Definition at line 106 of file ip_frag.c.

References bitmap_bits, copy_from_pbuf(), DEBUGF, htons, inet_chksum(), ip_addr_cmp, IP_HLEN, IP_MF, IP_OFFMASK, IP_REASS_BUFSIZE, IP_REASS_DEBUG, IP_REASS_FLAG_LASTFRAG, IP_REASS_MAXAGE, ip_reass_timer(), IP_REASS_TMO, ip_reassbitmap, ip_reassbuf, ip_reassflags, ip_reasslen, ip_reasstmr, IPH_CHKSUM_SET, IPH_HL, IPH_ID, IPH_LEN, IPH_LEN_SET, IPH_OFFSET, IPH_OFFSET_SET, len, ntohs, NULL, pbuf::payload, pbuf_alloc(), pbuf_free(), PBUF_LINK, PBUF_POOL, sys_timeout(), sys_untimeout(), u16_t, and u8_t.

Referenced by ip_input().

00107 {
00108   struct pbuf *q;
00109   struct ip_hdr *fraghdr, *iphdr;
00110   u16_t offset, len;
00111   u16_t i;
00112 
00113 #ifdef IP_STATS
00114   ++lwip_stats.ip_frag.recv;
00115 #endif /* IP_STATS */
00116 
00117   iphdr = (struct ip_hdr *) ip_reassbuf;
00118   fraghdr = (struct ip_hdr *) p->payload;
00119   /* If ip_reasstmr is zero, no packet is present in the buffer, so we
00120      write the IP header of the fragment into the reassembly
00121      buffer. The timer is updated with the maximum age. */
00122   if (ip_reasstmr == 0) {
00123     DEBUGF(IP_REASS_DEBUG, ("ip_reass: new packet\n"));
00124     memcpy(iphdr, fraghdr, IP_HLEN);
00125     ip_reasstmr = IP_REASS_MAXAGE;
00126     sys_timeout(IP_REASS_TMO, ip_reass_timer, NULL);
00127     ip_reassflags = 0;
00128     /* Clear the bitmap. */
00129     memset(ip_reassbitmap, 0, sizeof(ip_reassbitmap));
00130   }
00131 
00132   /* Check if the incoming fragment matches the one currently present
00133      in the reasembly buffer. If so, we proceed with copying the
00134      fragment into the buffer. */
00135   if (ip_addr_cmp(&iphdr->src, &fraghdr->src) &&
00136       ip_addr_cmp(&iphdr->dest, &fraghdr->dest) &&
00137       IPH_ID(iphdr) == IPH_ID(fraghdr)) {
00138     DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching old packet\n"));
00139 #ifdef IP_STATS
00140     ++lwip_stats.ip_frag.cachehit;
00141 #endif /* IP_STATS */
00142     /* Find out the offset in the reassembly buffer where we should
00143        copy the fragment. */
00144     len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
00145     offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
00146 
00147     /* If the offset or the offset + fragment length overflows the
00148        reassembly buffer, we discard the entire packet. */
00149     if (offset > IP_REASS_BUFSIZE || offset + len > IP_REASS_BUFSIZE) {
00150       DEBUGF(IP_REASS_DEBUG,
00151              ("ip_reass: fragment outside of buffer (%d:%d/%d).\n", offset,
00152               offset + len, IP_REASS_BUFSIZE));
00153       sys_untimeout(ip_reass_timer, NULL);
00154       ip_reasstmr = 0;
00155       goto nullreturn;
00156     }
00157 
00158     /* Copy the fragment into the reassembly buffer, at the right
00159        offset. */
00160     DEBUGF(IP_REASS_DEBUG,
00161            ("ip_reass: copying with offset %d into %d:%d\n", offset,
00162             IP_HLEN + offset, IP_HLEN + offset + len));
00163     i = IPH_HL(fraghdr) * 4;
00164     copy_from_pbuf(p, &i, &ip_reassbuf[IP_HLEN + offset], len);
00165 
00166     /* Update the bitmap. */
00167     if (offset / (8 * 8) == (offset + len) / (8 * 8)) {
00168       DEBUGF(IP_REASS_DEBUG,
00169              ("ip_reass: updating single byte in bitmap.\n"));
00170       /* If the two endpoints are in the same byte, we only update
00171          that byte. */
00172       ip_reassbitmap[offset / (8 * 8)] |=
00173           bitmap_bits[(offset / 8) & 7] &
00174           ~bitmap_bits[((offset + len) / 8) & 7];
00175     } else {
00176       /* If the two endpoints are in different bytes, we update the
00177          bytes in the endpoints and fill the stuff inbetween with
00178          0xff. */
00179       ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8) & 7];
00180       DEBUGF(IP_REASS_DEBUG,
00181              ("ip_reass: updating many bytes in bitmap (%d:%d).\n",
00182               1 + offset / (8 * 8), (offset + len) / (8 * 8)));
00183       for (i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
00184         ip_reassbitmap[i] = 0xff;
00185       }
00186       ip_reassbitmap[(offset + len) / (8 * 8)] |=
00187           ~bitmap_bits[((offset + len) / 8) & 7];
00188     }
00189 
00190     /* If this fragment has the More Fragments flag set to zero, we
00191        know that this is the last fragment, so we can calculate the
00192        size of the entire packet. We also set the
00193        IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
00194        the final fragment. */
00195 
00196     if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {
00197       ip_reassflags |= IP_REASS_FLAG_LASTFRAG;
00198       ip_reasslen = offset + len;
00199       DEBUGF(IP_REASS_DEBUG,
00200              ("ip_reass: last fragment seen, total len %d\n",
00201               ip_reasslen));
00202     }
00203 
00204     /* Finally, we check if we have a full packet in the buffer. We do
00205        this by checking if we have the last fragment and if all bits
00206        in the bitmap are set. */
00207     if (ip_reassflags & IP_REASS_FLAG_LASTFRAG) {
00208       /* Check all bytes up to and including all but the last byte in
00209          the bitmap. */
00210       for (i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) {
00211         if (ip_reassbitmap[i] != 0xff) {
00212           DEBUGF(IP_REASS_DEBUG,
00213                  ("ip_reass: last fragment seen, bitmap %d/%d failed (%x)\n",
00214                   i, ip_reasslen / (8 * 8) - 1, ip_reassbitmap[i]));
00215           goto nullreturn;
00216         }
00217       }
00218       /* Check the last byte in the bitmap. It should contain just the
00219          right amount of bits. */
00220       if (ip_reassbitmap[ip_reasslen / (8 * 8)] !=
00221           (u8_t) ~ bitmap_bits[ip_reasslen / 8 & 7]) {
00222         DEBUGF(IP_REASS_DEBUG,
00223                ("ip_reass: last fragment seen, bitmap %d didn't contain %x (%x)\n",
00224                 ip_reasslen / (8 * 8), ~bitmap_bits[ip_reasslen / 8 & 7],
00225                 ip_reassbitmap[ip_reasslen / (8 * 8)]));
00226         goto nullreturn;
00227       }
00228 
00229       /* Pretend to be a "normal" (i.e., not fragmented) IP packet
00230          from now on. */
00231       ip_reasslen += IP_HLEN;
00232 
00233       IPH_LEN_SET(iphdr, htons(ip_reasslen));
00234       IPH_OFFSET_SET(iphdr, 0);
00235       IPH_CHKSUM_SET(iphdr, 0);
00236       IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
00237 
00238       /* If we have come this far, we have a full packet in the
00239          buffer, so we allocate a pbuf and copy the packet into it. We
00240          also reset the timer. */
00241       sys_untimeout(ip_reass_timer, NULL);
00242       ip_reasstmr = 0;
00243       pbuf_free(p);
00244       p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL);
00245       if (p != NULL) {
00246         i = 0;
00247         for (q = p; q != NULL; q = q->next) {
00248           /* Copy enough bytes to fill this pbuf in the chain. The
00249              available data in the pbuf is given by the q->len
00250              variable. */
00251           DEBUGF(IP_REASS_DEBUG,
00252                  ("ip_reass: memcpy from %p (%d) to %p, %d bytes\n",
00253                   &ip_reassbuf[i], i, q->payload,
00254                   q->len > ip_reasslen - i ? ip_reasslen - i : q->len));
00255           memcpy(q->payload, &ip_reassbuf[i],
00256                 q->len > ip_reasslen - i ? ip_reasslen - i : q->len);
00257           i += q->len;
00258         }
00259 #ifdef IP_STATS
00260         ++lwip_stats.ip_frag.fw;
00261 #endif /* IP_STATS */
00262       } else {
00263 #ifdef IP_STATS
00264         ++lwip_stats.ip_frag.memerr;
00265 #endif /* IP_STATS */
00266       }
00267       DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", (void*)p));
00268       return p;
00269     }
00270   }
00271 
00272 nullreturn:
00273 #ifdef IP_STATS
00274   ++lwip_stats.ip_frag.drop;
00275 #endif /* IP_STATS */
00276   pbuf_free(p);
00277   return NULL;
00278 }

Here is the call graph for this function:

void ip_reass_timer int  signo  )  [static]
 

Definition at line 96 of file ip_frag.c.

References ip_reass_timer(), IP_REASS_TMO, ip_reasstmr, NULL, and sys_timeout().

Referenced by ip_reass(), and ip_reass_timer().

00097 {
00098   if(ip_reasstmr > 1) {
00099     ip_reasstmr--;
00100     sys_timeout(IP_REASS_TMO, ip_reass_timer, NULL);
00101   } else if(ip_reasstmr == 1)
00102         ip_reasstmr = 0;
00103 }

Here is the call graph for this function:


Variable Documentation

const u8_t bitmap_bits[8] [static]
 

Initial value:

 { 0xff, 0x7f, 0x3f, 0x1f,
  0x0f, 0x07, 0x03, 0x01
}

Definition at line 85 of file ip_frag.c.

Referenced by ip_reass().

u8_t buf[MAX_MTU] [static]
 

Definition at line 281 of file ip_frag.c.

Referenced by ip_frag().

u8_t ip_reassbitmap[IP_REASS_BUFSIZE / (8 * 8)] [static]
 

Definition at line 84 of file ip_frag.c.

Referenced by ip_reass().

u8_t ip_reassbuf[IP_HLEN + IP_REASS_BUFSIZE] [static]
 

Definition at line 83 of file ip_frag.c.

Referenced by ip_reass().

u8_t ip_reassflags [static]
 

Definition at line 89 of file ip_frag.c.

Referenced by ip_reass().

u16_t ip_reasslen [static]
 

Definition at line 88 of file ip_frag.c.

Referenced by ip_reass().

u8_t ip_reasstmr [static]
 

Definition at line 92 of file ip_frag.c.

Referenced by ip_reass(), and ip_reass_timer().


Generated on Wed Jan 14 12:59:06 2004 for RTL-lwIP-0.4 by doxygen 1.3.4