OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [lwIP_MCF5235_GCC/] [lwip/] [src/] [core/] [ipv4/] [ip_frag.c] - Blame information for rev 583

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 583 jeremybenn
/* @file
2
 *
3
 * This is the IP packet segmentation and reassembly implementation.
4
 *
5
 */
6
 
7
/*
8
 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9
 * All rights reserved.
10
 *
11
 * Redistribution and use in source and binary forms, with or without modification,
12
 * are permitted provided that the following conditions are met:
13
 *
14
 * 1. Redistributions of source code must retain the above copyright notice,
15
 *    this list of conditions and the following disclaimer.
16
 * 2. Redistributions in binary form must reproduce the above copyright notice,
17
 *    this list of conditions and the following disclaimer in the documentation
18
 *    and/or other materials provided with the distribution.
19
 * 3. The name of the author may not be used to endorse or promote products
20
 *    derived from this software without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31
 * OF SUCH DAMAGE.
32
 *
33
 * This file is part of the lwIP TCP/IP stack.
34
 *
35
 * Author: Jani Monoses <jani@iv.ro>
36
 * original reassembly code by Adam Dunkels <adam@sics.se>
37
 *
38
 */
39
 
40
#include <string.h>
41
 
42
#include "lwip/opt.h"
43
/* #include "lwip/sys.h" */
44
#include "lwip/ip.h"
45
#include "lwip/ip_frag.h"
46
#include "lwip/netif.h"
47
#include "lwip/stats.h"
48
 
49
 
50
/*
51
 * Copy len bytes from offset in pbuf to buffer
52
 *
53
 * helper used by both ip_reass and ip_frag
54
 */
55
static struct pbuf *
56
copy_from_pbuf(struct pbuf *p, u16_t * offset,
57
           u8_t * buffer, u16_t len)
58
{
59
  u16_t l;
60
 
61
  p->payload = (u8_t *)p->payload + *offset;
62
  p->len -= *offset;
63
  while (len) {
64
    l = len < p->len ? len : p->len;
65
    memcpy(buffer, p->payload, l);
66
    buffer += l;
67
    len -= l;
68
    if (len)
69
      p = p->next;
70
    else
71
      *offset = l;
72
  }
73
  return p;
74
}
75
 
76
#define IP_REASS_BUFSIZE 5760
77
#define IP_REASS_MAXAGE 30
78
#define IP_REASS_TMO 1000
79
 
80
static u8_t ip_reassbuf[IP_HLEN + IP_REASS_BUFSIZE];
81
static u8_t ip_reassbitmap[IP_REASS_BUFSIZE / (8 * 8) + 1];
82
static const u8_t bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f,
83
  0x0f, 0x07, 0x03, 0x01
84
};
85
static u16_t ip_reasslen;
86
static u8_t ip_reassflags;
87
#define IP_REASS_FLAG_LASTFRAG 0x01
88
 
89
static u8_t ip_reasstmr;
90
 
91
/**
92
 * Reassembly timer base function
93
 * for both NO_SYS == 0 and 1 (!).
94
 *
95
 * Should be called every 1000 msec.
96
 */
97
void
98
ip_reass_tmr(void)
99
{
100
  if (ip_reasstmr > 0) {
101
    ip_reasstmr--;
102
  }
103
}
104
 
105
/**
106
 * Reassembles incoming IP fragments into an IP datagram.
107
 *
108
 * @param p points to a pbuf chain of the fragment
109
 * @return NULL if reassembly is incomplete, ? otherwise
110
 */
111
struct pbuf *
112
ip_reass(struct pbuf *p)
113
{
114
  struct pbuf *q;
115
  struct ip_hdr *fraghdr, *iphdr;
116
  u16_t offset, len;
117
  u16_t i;
118
 
119
  IPFRAG_STATS_INC(ip_frag.recv);
120
 
121
  iphdr = (struct ip_hdr *) ip_reassbuf;
122
  fraghdr = (struct ip_hdr *) p->payload;
123
  /* If ip_reasstmr is zero, no packet is present in the buffer, so we
124
     write the IP header of the fragment into the reassembly
125
     buffer. The timer is updated with the maximum age. */
126
  if (ip_reasstmr == 0) {
127
    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: new packet\n"));
128
    memcpy(iphdr, fraghdr, IP_HLEN);
129
    ip_reasstmr = IP_REASS_MAXAGE;
130
    ip_reassflags = 0;
131
    /* Clear the bitmap. */
132
    memset(ip_reassbitmap, 0, sizeof(ip_reassbitmap));
133
  }
134
 
135
  /* Check if the incoming fragment matches the one currently present
136
     in the reasembly buffer. If so, we proceed with copying the
137
     fragment into the buffer. */
138
  if (ip_addr_cmp(&iphdr->src, &fraghdr->src) &&
139
      ip_addr_cmp(&iphdr->dest, &fraghdr->dest) &&
140
      IPH_ID(iphdr) == IPH_ID(fraghdr)) {
141
    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",
142
      ntohs(IPH_ID(fraghdr))));
143
    IPFRAG_STATS_INC(ip_frag.cachehit);
144
    /* Find out the offset in the reassembly buffer where we should
145
       copy the fragment. */
146
    len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
147
    offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
148
 
149
    /* If the offset or the offset + fragment length overflows the
150
       reassembly buffer, we discard the entire packet. */
151
    if (offset > IP_REASS_BUFSIZE || offset + len > IP_REASS_BUFSIZE) {
152
      LWIP_DEBUGF(IP_REASS_DEBUG,
153
       ("ip_reass: fragment outside of buffer (%"S16_F":%"S16_F"/%"S16_F").\n", offset,
154
        offset + len, IP_REASS_BUFSIZE));
155
      ip_reasstmr = 0;
156
      goto nullreturn;
157
    }
158
 
159
    /* Copy the fragment into the reassembly buffer, at the right
160
       offset. */
161
    LWIP_DEBUGF(IP_REASS_DEBUG,
162
     ("ip_reass: copying with offset %"S16_F" into %"S16_F":%"S16_F"\n", offset,
163
      IP_HLEN + offset, IP_HLEN + offset + len));
164
    i = IPH_HL(fraghdr) * 4;
165
    copy_from_pbuf(p, &i, &ip_reassbuf[IP_HLEN + offset], len);
166
 
167
    /* Update the bitmap. */
168
    if (offset / (8 * 8) == (offset + len) / (8 * 8)) {
169
      LWIP_DEBUGF(IP_REASS_DEBUG,
170
       ("ip_reass: updating single byte in bitmap.\n"));
171
      /* If the two endpoints are in the same byte, we only update that byte. */
172
      LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)",
173
                   offset / (8 * 8) < sizeof(ip_reassbitmap));
174
      ip_reassbitmap[offset / (8 * 8)] |=
175
        bitmap_bits[(offset / 8) & 7] &
176
        ~bitmap_bits[((offset + len) / 8) & 7];
177
    } else {
178
      /* If the two endpoints are in different bytes, we update the
179
         bytes in the endpoints and fill the stuff inbetween with
180
         0xff. */
181
      LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)",
182
                   offset / (8 * 8) < sizeof(ip_reassbitmap));
183
      ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8) & 7];
184
      LWIP_DEBUGF(IP_REASS_DEBUG,
185
       ("ip_reass: updating many bytes in bitmap (%"S16_F":%"S16_F").\n",
186
        1 + offset / (8 * 8), (offset + len) / (8 * 8)));
187
      for (i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
188
        ip_reassbitmap[i] = 0xff;
189
      }
190
      LWIP_ASSERT("(offset + len) / (8 * 8) < sizeof(ip_reassbitmap)",
191
                   (offset + len) / (8 * 8) < sizeof(ip_reassbitmap));
192
      ip_reassbitmap[(offset + len) / (8 * 8)] |=
193
        ~bitmap_bits[((offset + len) / 8) & 7];
194
    }
195
 
196
    /* If this fragment has the More Fragments flag set to zero, we
197
       know that this is the last fragment, so we can calculate the
198
       size of the entire packet. We also set the
199
       IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
200
       the final fragment. */
201
 
202
    if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {
203
      ip_reassflags |= IP_REASS_FLAG_LASTFRAG;
204
      ip_reasslen = offset + len;
205
      LWIP_DEBUGF(IP_REASS_DEBUG,
206
       ("ip_reass: last fragment seen, total len %"S16_F"\n",
207
        ip_reasslen));
208
    }
209
 
210
    /* Finally, we check if we have a full packet in the buffer. We do
211
       this by checking if we have the last fragment and if all bits
212
       in the bitmap are set. */
213
    if (ip_reassflags & IP_REASS_FLAG_LASTFRAG) {
214
      /* Check all bytes up to and including all but the last byte in
215
         the bitmap. */
216
      LWIP_ASSERT("ip_reasslen / (8 * 8) - 1 < sizeof(ip_reassbitmap)",
217
                   ip_reasslen / (8 * 8) - 1 < sizeof(ip_reassbitmap));
218
      for (i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) {
219
        if (ip_reassbitmap[i] != 0xff) {
220
          LWIP_DEBUGF(IP_REASS_DEBUG,
221
           ("ip_reass: last fragment seen, bitmap %"S16_F"/%"S16_F" failed (%"X16_F")\n",
222
            i, ip_reasslen / (8 * 8) - 1, ip_reassbitmap[i]));
223
          goto nullreturn;
224
        }
225
      }
226
      /* Check the last byte in the bitmap. It should contain just the
227
         right amount of bits. */
228
      LWIP_ASSERT("ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap)",
229
                   ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap));
230
      if (ip_reassbitmap[ip_reasslen / (8 * 8)] !=
231
        (u8_t) ~ bitmap_bits[ip_reasslen / 8 & 7]) {
232
         LWIP_DEBUGF(IP_REASS_DEBUG,
233
          ("ip_reass: last fragment seen, bitmap %"S16_F" didn't contain %"X16_F" (%"X16_F")\n",
234
        ip_reasslen / (8 * 8), ~bitmap_bits[ip_reasslen / 8 & 7],
235
        ip_reassbitmap[ip_reasslen / (8 * 8)]));
236
        goto nullreturn;
237
      }
238
 
239
      /* Pretend to be a "normal" (i.e., not fragmented) IP packet
240
         from now on. */
241
      ip_reasslen += IP_HLEN;
242
 
243
      IPH_LEN_SET(iphdr, htons(ip_reasslen));
244
      IPH_OFFSET_SET(iphdr, 0);
245
      IPH_CHKSUM_SET(iphdr, 0);
246
      IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
247
 
248
      /* If we have come this far, we have a full packet in the
249
         buffer, so we allocate a pbuf and copy the packet into it. We
250
         also reset the timer. */
251
      ip_reasstmr = 0;
252
      pbuf_free(p);
253
      p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL);
254
      if (p != NULL) {
255
        i = 0;
256
        for (q = p; q != NULL; q = q->next) {
257
          /* Copy enough bytes to fill this pbuf in the chain. The
258
             available data in the pbuf is given by the q->len variable. */
259
          LWIP_DEBUGF(IP_REASS_DEBUG,
260
           ("ip_reass: memcpy from %p (%"S16_F") to %p, %"S16_F" bytes\n",
261
            (void *)&ip_reassbuf[i], i, q->payload,
262
            q->len > ip_reasslen - i ? ip_reasslen - i : q->len));
263
          memcpy(q->payload, &ip_reassbuf[i],
264
            q->len > ip_reasslen - i ? ip_reasslen - i : q->len);
265
          i += q->len;
266
        }
267
        IPFRAG_STATS_INC(ip_frag.fw);
268
      } else {
269
        IPFRAG_STATS_INC(ip_frag.memerr);
270
      }
271
      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", (void*)p));
272
      return p;
273
    }
274
  }
275
 
276
nullreturn:
277
  IPFRAG_STATS_INC(ip_frag.drop);
278
  pbuf_free(p);
279
  return NULL;
280
}
281
 
282
#define MAX_MTU 1500
283
static u8_t buf[MEM_ALIGN_SIZE(MAX_MTU)];
284
 
285
/**
286
 * Fragment an IP datagram if too large for the netif.
287
 *
288
 * Chop the datagram in MTU sized chunks and send them in order
289
 * by using a fixed size static memory buffer (PBUF_ROM)
290
 */
291
err_t
292
ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
293
{
294
  struct pbuf *rambuf;
295
  struct pbuf *header;
296
  struct ip_hdr *iphdr;
297
  u16_t nfb = 0;
298
  u16_t left, cop;
299
  u16_t mtu = netif->mtu;
300
  u16_t ofo, omf;
301
  u16_t last;
302
  u16_t poff = IP_HLEN;
303
  u16_t tmp;
304
 
305
  /* Get a RAM based MTU sized pbuf */
306
  rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
307
  if (rambuf == NULL) {
308
    return ERR_MEM;
309
  }
310
  rambuf->tot_len = rambuf->len = mtu;
311
  rambuf->payload = MEM_ALIGN((void *)buf);
312
 
313
  /* Copy the IP header in it */
314
  iphdr = rambuf->payload;
315
  memcpy(iphdr, p->payload, IP_HLEN);
316
 
317
  /* Save original offset */
318
  tmp = ntohs(IPH_OFFSET(iphdr));
319
  ofo = tmp & IP_OFFMASK;
320
  omf = tmp & IP_MF;
321
 
322
  left = p->tot_len - IP_HLEN;
323
 
324
  while (left) {
325
    last = (left <= mtu - IP_HLEN);
326
 
327
    /* Set new offset and MF flag */
328
    ofo += nfb;
329
    tmp = omf | (IP_OFFMASK & (ofo));
330
    if (!last)
331
      tmp = tmp | IP_MF;
332
    IPH_OFFSET_SET(iphdr, htons(tmp));
333
 
334
    /* Fill this fragment */
335
    nfb = (mtu - IP_HLEN) / 8;
336
    cop = last ? left : nfb * 8;
337
 
338
    p = copy_from_pbuf(p, &poff, (u8_t *) iphdr + IP_HLEN, cop);
339
 
340
    /* Correct header */
341
    IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
342
    IPH_CHKSUM_SET(iphdr, 0);
343
    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
344
 
345
    if (last)
346
      pbuf_realloc(rambuf, left + IP_HLEN);
347
    /* This part is ugly: we alloc a RAM based pbuf for
348
     * the link level header for each chunk and then
349
     * free it.A PBUF_ROM style pbuf for which pbuf_header
350
     * worked would make things simpler.
351
     */
352
    header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
353
    if (header != NULL) {
354
      pbuf_chain(header, rambuf);
355
      netif->output(netif, header, dest);
356
      IPFRAG_STATS_INC(ip_frag.xmit);
357
      pbuf_free(header);
358
    } else {
359
      pbuf_free(rambuf);
360
      return ERR_MEM;
361
    }
362
    left -= cop;
363
  }
364
  pbuf_free(rambuf);
365
  return ERR_OK;
366
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.