00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include "lwip/opt.h"
00043 #include "lwip/sys.h"
00044 #include "lwip/ip.h"
00045 #include "lwip/ip_frag.h"
00046 #include "lwip/netif.h"
00047
00048 #include "lwip/stats.h"
00049
00050 #define htons HTONS
00051 #define htonl HTONL
00052
00053
00054
00055
00056
00057
00058 static struct pbuf *
00059 copy_from_pbuf(struct pbuf *p, u16_t * offset,
00060 u8_t * buffer, u16_t len)
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 }
00078
00079 #define IP_REASS_BUFSIZE 5760
00080 #define IP_REASS_MAXAGE 30
00081 #define IP_REASS_TMO 1000
00082
00083 static u8_t ip_reassbuf[IP_HLEN + IP_REASS_BUFSIZE];
00084 static u8_t ip_reassbitmap[IP_REASS_BUFSIZE / (8 * 8)];
00085 static const u8_t bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f,
00086 0x0f, 0x07, 0x03, 0x01
00087 };
00088 static u16_t ip_reasslen;
00089 static u8_t ip_reassflags;
00090 #define IP_REASS_FLAG_LASTFRAG 0x01
00091
00092 static u8_t ip_reasstmr;
00093
00094
00095 static void
00096 ip_reass_timer(int signo)
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 }
00104
00105 struct pbuf *
00106 ip_reass(struct pbuf *p)
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
00116
00117 iphdr = (struct ip_hdr *) ip_reassbuf;
00118 fraghdr = (struct ip_hdr *) p->payload;
00119
00120
00121
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
00129 memset(ip_reassbitmap, 0, sizeof(ip_reassbitmap));
00130 }
00131
00132
00133
00134
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
00142
00143
00144 len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
00145 offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
00146
00147
00148
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
00159
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
00167 if (offset / (8 * 8) == (offset + len) / (8 * 8)) {
00168 DEBUGF(IP_REASS_DEBUG,
00169 ("ip_reass: updating single byte in bitmap.\n"));
00170
00171
00172 ip_reassbitmap[offset / (8 * 8)] |=
00173 bitmap_bits[(offset / 8) & 7] &
00174 ~bitmap_bits[((offset + len) / 8) & 7];
00175 } else {
00176
00177
00178
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
00191
00192
00193
00194
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
00205
00206
00207 if (ip_reassflags & IP_REASS_FLAG_LASTFRAG) {
00208
00209
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
00219
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
00230
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
00239
00240
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
00249
00250
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
00262 } else {
00263 #ifdef IP_STATS
00264 ++lwip_stats.ip_frag.memerr;
00265 #endif
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
00276 pbuf_free(p);
00277 return NULL;
00278 }
00279
00280 #define MAX_MTU 1500
00281 static u8_t buf[MAX_MTU];
00282
00289 err_t
00290 ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
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
00304 rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
00305 rambuf->tot_len = rambuf->len = mtu;
00306 rambuf->payload = buf;
00307
00308
00309
00310 iphdr = rambuf->payload;
00311 memcpy(iphdr, p->payload, IP_HLEN);
00312
00313
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
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
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
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
00344
00345
00346
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
00354 pbuf_free(header);
00355
00356 left -= cop;
00357 }
00358 pbuf_free(rambuf);
00359 return ERR_OK;
00360 }