#include "lwip/err.h"
#include "lwip/pbuf.h"
#include "lwip/netif.h"
#include "lwip/ip_addr.h"
Include dependency graph for ip_frag.h:
This graph shows which files directly or indirectly include this file:
Go to the source code of this file.
Functions | |
pbuf * | ip_reass (struct pbuf *) |
err_t | ip_frag (struct pbuf *, struct netif *, struct ip_addr *) |
|
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:
|
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: