Official mbed lwIP library (version 1.4.0)

Dependents:   LwIPNetworking NetServicesMin EthernetInterface EthernetInterface_RSF ... more

Legacy Networking Libraries

This is an mbed 2 networking library. For mbed OS 5, lwip has been integrated with built-in networking interfaces. The networking libraries have been revised to better support additional network stacks and thread safety here.

This library is based on the code of lwIP v1.4.0

Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
All rights reserved. 

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
Committer:
mbed_official
Date:
Mon Mar 14 16:15:36 2016 +0000
Revision:
20:08f08bfc3f3d
Parent:
0:51ac1d130fd4
Synchronized with git revision fec574a5ed6db26aca1b13992ff271bf527d4a0d

Full URL: https://github.com/mbedmicro/mbed/commit/fec574a5ed6db26aca1b13992ff271bf527d4a0d/

Increased allocated netbufs to handle DTLS handshakes

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 0:51ac1d130fd4 1 /**
mbed_official 0:51ac1d130fd4 2 * @file
mbed_official 0:51ac1d130fd4 3 * This is the IPv4 packet segmentation and reassembly implementation.
mbed_official 0:51ac1d130fd4 4 *
mbed_official 0:51ac1d130fd4 5 */
mbed_official 0:51ac1d130fd4 6
mbed_official 0:51ac1d130fd4 7 /*
mbed_official 0:51ac1d130fd4 8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
mbed_official 0:51ac1d130fd4 9 * All rights reserved.
mbed_official 0:51ac1d130fd4 10 *
mbed_official 0:51ac1d130fd4 11 * Redistribution and use in source and binary forms, with or without modification,
mbed_official 0:51ac1d130fd4 12 * are permitted provided that the following conditions are met:
mbed_official 0:51ac1d130fd4 13 *
mbed_official 0:51ac1d130fd4 14 * 1. Redistributions of source code must retain the above copyright notice,
mbed_official 0:51ac1d130fd4 15 * this list of conditions and the following disclaimer.
mbed_official 0:51ac1d130fd4 16 * 2. Redistributions in binary form must reproduce the above copyright notice,
mbed_official 0:51ac1d130fd4 17 * this list of conditions and the following disclaimer in the documentation
mbed_official 0:51ac1d130fd4 18 * and/or other materials provided with the distribution.
mbed_official 0:51ac1d130fd4 19 * 3. The name of the author may not be used to endorse or promote products
mbed_official 0:51ac1d130fd4 20 * derived from this software without specific prior written permission.
mbed_official 0:51ac1d130fd4 21 *
mbed_official 0:51ac1d130fd4 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
mbed_official 0:51ac1d130fd4 23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
mbed_official 0:51ac1d130fd4 24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
mbed_official 0:51ac1d130fd4 25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
mbed_official 0:51ac1d130fd4 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
mbed_official 0:51ac1d130fd4 27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
mbed_official 0:51ac1d130fd4 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
mbed_official 0:51ac1d130fd4 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
mbed_official 0:51ac1d130fd4 30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
mbed_official 0:51ac1d130fd4 31 * OF SUCH DAMAGE.
mbed_official 0:51ac1d130fd4 32 *
mbed_official 0:51ac1d130fd4 33 * This file is part of the lwIP TCP/IP stack.
mbed_official 0:51ac1d130fd4 34 *
mbed_official 0:51ac1d130fd4 35 * Author: Jani Monoses <jani@iv.ro>
mbed_official 0:51ac1d130fd4 36 * Simon Goldschmidt
mbed_official 0:51ac1d130fd4 37 * original reassembly code by Adam Dunkels <adam@sics.se>
mbed_official 0:51ac1d130fd4 38 *
mbed_official 0:51ac1d130fd4 39 */
mbed_official 0:51ac1d130fd4 40
mbed_official 0:51ac1d130fd4 41 #include "lwip/opt.h"
mbed_official 0:51ac1d130fd4 42 #include "lwip/ip_frag.h"
mbed_official 0:51ac1d130fd4 43 #include "lwip/def.h"
mbed_official 0:51ac1d130fd4 44 #include "lwip/inet_chksum.h"
mbed_official 0:51ac1d130fd4 45 #include "lwip/netif.h"
mbed_official 0:51ac1d130fd4 46 #include "lwip/snmp.h"
mbed_official 0:51ac1d130fd4 47 #include "lwip/stats.h"
mbed_official 0:51ac1d130fd4 48 #include "lwip/icmp.h"
mbed_official 0:51ac1d130fd4 49
mbed_official 0:51ac1d130fd4 50 #include <string.h>
mbed_official 0:51ac1d130fd4 51
mbed_official 0:51ac1d130fd4 52 #if IP_REASSEMBLY
mbed_official 0:51ac1d130fd4 53 /**
mbed_official 0:51ac1d130fd4 54 * The IP reassembly code currently has the following limitations:
mbed_official 0:51ac1d130fd4 55 * - IP header options are not supported
mbed_official 0:51ac1d130fd4 56 * - fragments must not overlap (e.g. due to different routes),
mbed_official 0:51ac1d130fd4 57 * currently, overlapping or duplicate fragments are thrown away
mbed_official 0:51ac1d130fd4 58 * if IP_REASS_CHECK_OVERLAP=1 (the default)!
mbed_official 0:51ac1d130fd4 59 *
mbed_official 0:51ac1d130fd4 60 * @todo: work with IP header options
mbed_official 0:51ac1d130fd4 61 */
mbed_official 0:51ac1d130fd4 62
mbed_official 0:51ac1d130fd4 63 /** Setting this to 0, you can turn off checking the fragments for overlapping
mbed_official 0:51ac1d130fd4 64 * regions. The code gets a little smaller. Only use this if you know that
mbed_official 0:51ac1d130fd4 65 * overlapping won't occur on your network! */
mbed_official 0:51ac1d130fd4 66 #ifndef IP_REASS_CHECK_OVERLAP
mbed_official 0:51ac1d130fd4 67 #define IP_REASS_CHECK_OVERLAP 1
mbed_official 0:51ac1d130fd4 68 #endif /* IP_REASS_CHECK_OVERLAP */
mbed_official 0:51ac1d130fd4 69
mbed_official 0:51ac1d130fd4 70 /** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is
mbed_official 0:51ac1d130fd4 71 * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller.
mbed_official 0:51ac1d130fd4 72 * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA
mbed_official 0:51ac1d130fd4 73 * is set to 1, so one datagram can be reassembled at a time, only. */
mbed_official 0:51ac1d130fd4 74 #ifndef IP_REASS_FREE_OLDEST
mbed_official 0:51ac1d130fd4 75 #define IP_REASS_FREE_OLDEST 1
mbed_official 0:51ac1d130fd4 76 #endif /* IP_REASS_FREE_OLDEST */
mbed_official 0:51ac1d130fd4 77
mbed_official 0:51ac1d130fd4 78 #define IP_REASS_FLAG_LASTFRAG 0x01
mbed_official 0:51ac1d130fd4 79
mbed_official 0:51ac1d130fd4 80 /** This is a helper struct which holds the starting
mbed_official 0:51ac1d130fd4 81 * offset and the ending offset of this fragment to
mbed_official 0:51ac1d130fd4 82 * easily chain the fragments.
mbed_official 0:51ac1d130fd4 83 * It has the same packing requirements as the IP header, since it replaces
mbed_official 0:51ac1d130fd4 84 * the IP header in memory in incoming fragments (after copying it) to keep
mbed_official 0:51ac1d130fd4 85 * track of the various fragments. (-> If the IP header doesn't need packing,
mbed_official 0:51ac1d130fd4 86 * this struct doesn't need packing, too.)
mbed_official 0:51ac1d130fd4 87 */
mbed_official 0:51ac1d130fd4 88 #ifdef PACK_STRUCT_USE_INCLUDES
mbed_official 0:51ac1d130fd4 89 # include "arch/bpstruct.h"
mbed_official 0:51ac1d130fd4 90 #endif
mbed_official 0:51ac1d130fd4 91 PACK_STRUCT_BEGIN
mbed_official 0:51ac1d130fd4 92 struct ip_reass_helper {
mbed_official 0:51ac1d130fd4 93 PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
mbed_official 0:51ac1d130fd4 94 PACK_STRUCT_FIELD(u16_t start);
mbed_official 0:51ac1d130fd4 95 PACK_STRUCT_FIELD(u16_t end);
mbed_official 0:51ac1d130fd4 96 } PACK_STRUCT_STRUCT;
mbed_official 0:51ac1d130fd4 97 PACK_STRUCT_END
mbed_official 0:51ac1d130fd4 98 #ifdef PACK_STRUCT_USE_INCLUDES
mbed_official 0:51ac1d130fd4 99 # include "arch/epstruct.h"
mbed_official 0:51ac1d130fd4 100 #endif
mbed_official 0:51ac1d130fd4 101
mbed_official 0:51ac1d130fd4 102 #define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \
mbed_official 0:51ac1d130fd4 103 (ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
mbed_official 0:51ac1d130fd4 104 ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \
mbed_official 0:51ac1d130fd4 105 IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0
mbed_official 0:51ac1d130fd4 106
mbed_official 0:51ac1d130fd4 107 /* global variables */
mbed_official 0:51ac1d130fd4 108 static struct ip_reassdata *reassdatagrams;
mbed_official 0:51ac1d130fd4 109 static u16_t ip_reass_pbufcount;
mbed_official 0:51ac1d130fd4 110
mbed_official 0:51ac1d130fd4 111 /* function prototypes */
mbed_official 0:51ac1d130fd4 112 static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);
mbed_official 0:51ac1d130fd4 113 static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);
mbed_official 0:51ac1d130fd4 114
mbed_official 0:51ac1d130fd4 115 /**
mbed_official 0:51ac1d130fd4 116 * Reassembly timer base function
mbed_official 0:51ac1d130fd4 117 * for both NO_SYS == 0 and 1 (!).
mbed_official 0:51ac1d130fd4 118 *
mbed_official 0:51ac1d130fd4 119 * Should be called every 1000 msec (defined by IP_TMR_INTERVAL).
mbed_official 0:51ac1d130fd4 120 */
mbed_official 0:51ac1d130fd4 121 void
mbed_official 0:51ac1d130fd4 122 ip_reass_tmr(void)
mbed_official 0:51ac1d130fd4 123 {
mbed_official 0:51ac1d130fd4 124 struct ip_reassdata *r, *prev = NULL;
mbed_official 0:51ac1d130fd4 125
mbed_official 0:51ac1d130fd4 126 r = reassdatagrams;
mbed_official 0:51ac1d130fd4 127 while (r != NULL) {
mbed_official 0:51ac1d130fd4 128 /* Decrement the timer. Once it reaches 0,
mbed_official 0:51ac1d130fd4 129 * clean up the incomplete fragment assembly */
mbed_official 0:51ac1d130fd4 130 if (r->timer > 0) {
mbed_official 0:51ac1d130fd4 131 r->timer--;
mbed_official 0:51ac1d130fd4 132 LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer));
mbed_official 0:51ac1d130fd4 133 prev = r;
mbed_official 0:51ac1d130fd4 134 r = r->next;
mbed_official 0:51ac1d130fd4 135 } else {
mbed_official 0:51ac1d130fd4 136 /* reassembly timed out */
mbed_official 0:51ac1d130fd4 137 struct ip_reassdata *tmp;
mbed_official 0:51ac1d130fd4 138 LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n"));
mbed_official 0:51ac1d130fd4 139 tmp = r;
mbed_official 0:51ac1d130fd4 140 /* get the next pointer before freeing */
mbed_official 0:51ac1d130fd4 141 r = r->next;
mbed_official 0:51ac1d130fd4 142 /* free the helper struct and all enqueued pbufs */
mbed_official 0:51ac1d130fd4 143 ip_reass_free_complete_datagram(tmp, prev);
mbed_official 0:51ac1d130fd4 144 }
mbed_official 0:51ac1d130fd4 145 }
mbed_official 0:51ac1d130fd4 146 }
mbed_official 0:51ac1d130fd4 147
mbed_official 0:51ac1d130fd4 148 /**
mbed_official 0:51ac1d130fd4 149 * Free a datagram (struct ip_reassdata) and all its pbufs.
mbed_official 0:51ac1d130fd4 150 * Updates the total count of enqueued pbufs (ip_reass_pbufcount),
mbed_official 0:51ac1d130fd4 151 * SNMP counters and sends an ICMP time exceeded packet.
mbed_official 0:51ac1d130fd4 152 *
mbed_official 0:51ac1d130fd4 153 * @param ipr datagram to free
mbed_official 0:51ac1d130fd4 154 * @param prev the previous datagram in the linked list
mbed_official 0:51ac1d130fd4 155 * @return the number of pbufs freed
mbed_official 0:51ac1d130fd4 156 */
mbed_official 0:51ac1d130fd4 157 static int
mbed_official 0:51ac1d130fd4 158 ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
mbed_official 0:51ac1d130fd4 159 {
mbed_official 0:51ac1d130fd4 160 u16_t pbufs_freed = 0;
mbed_official 0:51ac1d130fd4 161 u8_t clen;
mbed_official 0:51ac1d130fd4 162 struct pbuf *p;
mbed_official 0:51ac1d130fd4 163 struct ip_reass_helper *iprh;
mbed_official 0:51ac1d130fd4 164
mbed_official 0:51ac1d130fd4 165 LWIP_ASSERT("prev != ipr", prev != ipr);
mbed_official 0:51ac1d130fd4 166 if (prev != NULL) {
mbed_official 0:51ac1d130fd4 167 LWIP_ASSERT("prev->next == ipr", prev->next == ipr);
mbed_official 0:51ac1d130fd4 168 }
mbed_official 0:51ac1d130fd4 169
mbed_official 0:51ac1d130fd4 170 snmp_inc_ipreasmfails();
mbed_official 0:51ac1d130fd4 171 #if LWIP_ICMP
mbed_official 0:51ac1d130fd4 172 iprh = (struct ip_reass_helper *)ipr->p->payload;
mbed_official 0:51ac1d130fd4 173 if (iprh->start == 0) {
mbed_official 0:51ac1d130fd4 174 /* The first fragment was received, send ICMP time exceeded. */
mbed_official 0:51ac1d130fd4 175 /* First, de-queue the first pbuf from r->p. */
mbed_official 0:51ac1d130fd4 176 p = ipr->p;
mbed_official 0:51ac1d130fd4 177 ipr->p = iprh->next_pbuf;
mbed_official 0:51ac1d130fd4 178 /* Then, copy the original header into it. */
mbed_official 0:51ac1d130fd4 179 SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);
mbed_official 0:51ac1d130fd4 180 icmp_time_exceeded(p, ICMP_TE_FRAG);
mbed_official 0:51ac1d130fd4 181 clen = pbuf_clen(p);
mbed_official 0:51ac1d130fd4 182 LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
mbed_official 0:51ac1d130fd4 183 pbufs_freed += clen;
mbed_official 0:51ac1d130fd4 184 pbuf_free(p);
mbed_official 0:51ac1d130fd4 185 }
mbed_official 0:51ac1d130fd4 186 #endif /* LWIP_ICMP */
mbed_official 0:51ac1d130fd4 187
mbed_official 0:51ac1d130fd4 188 /* First, free all received pbufs. The individual pbufs need to be released
mbed_official 0:51ac1d130fd4 189 separately as they have not yet been chained */
mbed_official 0:51ac1d130fd4 190 p = ipr->p;
mbed_official 0:51ac1d130fd4 191 while (p != NULL) {
mbed_official 0:51ac1d130fd4 192 struct pbuf *pcur;
mbed_official 0:51ac1d130fd4 193 iprh = (struct ip_reass_helper *)p->payload;
mbed_official 0:51ac1d130fd4 194 pcur = p;
mbed_official 0:51ac1d130fd4 195 /* get the next pointer before freeing */
mbed_official 0:51ac1d130fd4 196 p = iprh->next_pbuf;
mbed_official 0:51ac1d130fd4 197 clen = pbuf_clen(pcur);
mbed_official 0:51ac1d130fd4 198 LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
mbed_official 0:51ac1d130fd4 199 pbufs_freed += clen;
mbed_official 0:51ac1d130fd4 200 pbuf_free(pcur);
mbed_official 0:51ac1d130fd4 201 }
mbed_official 0:51ac1d130fd4 202 /* Then, unchain the struct ip_reassdata from the list and free it. */
mbed_official 0:51ac1d130fd4 203 ip_reass_dequeue_datagram(ipr, prev);
mbed_official 0:51ac1d130fd4 204 LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed);
mbed_official 0:51ac1d130fd4 205 ip_reass_pbufcount -= pbufs_freed;
mbed_official 0:51ac1d130fd4 206
mbed_official 0:51ac1d130fd4 207 return pbufs_freed;
mbed_official 0:51ac1d130fd4 208 }
mbed_official 0:51ac1d130fd4 209
mbed_official 0:51ac1d130fd4 210 #if IP_REASS_FREE_OLDEST
mbed_official 0:51ac1d130fd4 211 /**
mbed_official 0:51ac1d130fd4 212 * Free the oldest datagram to make room for enqueueing new fragments.
mbed_official 0:51ac1d130fd4 213 * The datagram 'fraghdr' belongs to is not freed!
mbed_official 0:51ac1d130fd4 214 *
mbed_official 0:51ac1d130fd4 215 * @param fraghdr IP header of the current fragment
mbed_official 0:51ac1d130fd4 216 * @param pbufs_needed number of pbufs needed to enqueue
mbed_official 0:51ac1d130fd4 217 * (used for freeing other datagrams if not enough space)
mbed_official 0:51ac1d130fd4 218 * @return the number of pbufs freed
mbed_official 0:51ac1d130fd4 219 */
mbed_official 0:51ac1d130fd4 220 static int
mbed_official 0:51ac1d130fd4 221 ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
mbed_official 0:51ac1d130fd4 222 {
mbed_official 0:51ac1d130fd4 223 /* @todo Can't we simply remove the last datagram in the
mbed_official 0:51ac1d130fd4 224 * linked list behind reassdatagrams?
mbed_official 0:51ac1d130fd4 225 */
mbed_official 0:51ac1d130fd4 226 struct ip_reassdata *r, *oldest, *prev;
mbed_official 0:51ac1d130fd4 227 int pbufs_freed = 0, pbufs_freed_current;
mbed_official 0:51ac1d130fd4 228 int other_datagrams;
mbed_official 0:51ac1d130fd4 229
mbed_official 0:51ac1d130fd4 230 /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,
mbed_official 0:51ac1d130fd4 231 * but don't free the datagram that 'fraghdr' belongs to! */
mbed_official 0:51ac1d130fd4 232 do {
mbed_official 0:51ac1d130fd4 233 oldest = NULL;
mbed_official 0:51ac1d130fd4 234 prev = NULL;
mbed_official 0:51ac1d130fd4 235 other_datagrams = 0;
mbed_official 0:51ac1d130fd4 236 r = reassdatagrams;
mbed_official 0:51ac1d130fd4 237 while (r != NULL) {
mbed_official 0:51ac1d130fd4 238 if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) {
mbed_official 0:51ac1d130fd4 239 /* Not the same datagram as fraghdr */
mbed_official 0:51ac1d130fd4 240 other_datagrams++;
mbed_official 0:51ac1d130fd4 241 if (oldest == NULL) {
mbed_official 0:51ac1d130fd4 242 oldest = r;
mbed_official 0:51ac1d130fd4 243 } else if (r->timer <= oldest->timer) {
mbed_official 0:51ac1d130fd4 244 /* older than the previous oldest */
mbed_official 0:51ac1d130fd4 245 oldest = r;
mbed_official 0:51ac1d130fd4 246 }
mbed_official 0:51ac1d130fd4 247 }
mbed_official 0:51ac1d130fd4 248 if (r->next != NULL) {
mbed_official 0:51ac1d130fd4 249 prev = r;
mbed_official 0:51ac1d130fd4 250 }
mbed_official 0:51ac1d130fd4 251 r = r->next;
mbed_official 0:51ac1d130fd4 252 }
mbed_official 0:51ac1d130fd4 253 if (oldest != NULL) {
mbed_official 0:51ac1d130fd4 254 pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev);
mbed_official 0:51ac1d130fd4 255 pbufs_freed += pbufs_freed_current;
mbed_official 0:51ac1d130fd4 256 }
mbed_official 0:51ac1d130fd4 257 } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));
mbed_official 0:51ac1d130fd4 258 return pbufs_freed;
mbed_official 0:51ac1d130fd4 259 }
mbed_official 0:51ac1d130fd4 260 #endif /* IP_REASS_FREE_OLDEST */
mbed_official 0:51ac1d130fd4 261
mbed_official 0:51ac1d130fd4 262 /**
mbed_official 0:51ac1d130fd4 263 * Enqueues a new fragment into the fragment queue
mbed_official 0:51ac1d130fd4 264 * @param fraghdr points to the new fragments IP hdr
mbed_official 0:51ac1d130fd4 265 * @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space)
mbed_official 0:51ac1d130fd4 266 * @return A pointer to the queue location into which the fragment was enqueued
mbed_official 0:51ac1d130fd4 267 */
mbed_official 0:51ac1d130fd4 268 static struct ip_reassdata*
mbed_official 0:51ac1d130fd4 269 ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)
mbed_official 0:51ac1d130fd4 270 {
mbed_official 0:51ac1d130fd4 271 struct ip_reassdata* ipr;
mbed_official 0:51ac1d130fd4 272 /* No matching previous fragment found, allocate a new reassdata struct */
mbed_official 0:51ac1d130fd4 273 ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
mbed_official 0:51ac1d130fd4 274 if (ipr == NULL) {
mbed_official 0:51ac1d130fd4 275 #if IP_REASS_FREE_OLDEST
mbed_official 0:51ac1d130fd4 276 if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) {
mbed_official 0:51ac1d130fd4 277 ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
mbed_official 0:51ac1d130fd4 278 }
mbed_official 0:51ac1d130fd4 279 if (ipr == NULL)
mbed_official 0:51ac1d130fd4 280 #endif /* IP_REASS_FREE_OLDEST */
mbed_official 0:51ac1d130fd4 281 {
mbed_official 0:51ac1d130fd4 282 IPFRAG_STATS_INC(ip_frag.memerr);
mbed_official 0:51ac1d130fd4 283 LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n"));
mbed_official 0:51ac1d130fd4 284 return NULL;
mbed_official 0:51ac1d130fd4 285 }
mbed_official 0:51ac1d130fd4 286 }
mbed_official 0:51ac1d130fd4 287 memset(ipr, 0, sizeof(struct ip_reassdata));
mbed_official 0:51ac1d130fd4 288 ipr->timer = IP_REASS_MAXAGE;
mbed_official 0:51ac1d130fd4 289
mbed_official 0:51ac1d130fd4 290 /* enqueue the new structure to the front of the list */
mbed_official 0:51ac1d130fd4 291 ipr->next = reassdatagrams;
mbed_official 0:51ac1d130fd4 292 reassdatagrams = ipr;
mbed_official 0:51ac1d130fd4 293 /* copy the ip header for later tests and input */
mbed_official 0:51ac1d130fd4 294 /* @todo: no ip options supported? */
mbed_official 0:51ac1d130fd4 295 SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN);
mbed_official 0:51ac1d130fd4 296 return ipr;
mbed_official 0:51ac1d130fd4 297 }
mbed_official 0:51ac1d130fd4 298
mbed_official 0:51ac1d130fd4 299 /**
mbed_official 0:51ac1d130fd4 300 * Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs.
mbed_official 0:51ac1d130fd4 301 * @param ipr points to the queue entry to dequeue
mbed_official 0:51ac1d130fd4 302 */
mbed_official 0:51ac1d130fd4 303 static void
mbed_official 0:51ac1d130fd4 304 ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
mbed_official 0:51ac1d130fd4 305 {
mbed_official 0:51ac1d130fd4 306
mbed_official 0:51ac1d130fd4 307 /* dequeue the reass struct */
mbed_official 0:51ac1d130fd4 308 if (reassdatagrams == ipr) {
mbed_official 0:51ac1d130fd4 309 /* it was the first in the list */
mbed_official 0:51ac1d130fd4 310 reassdatagrams = ipr->next;
mbed_official 0:51ac1d130fd4 311 } else {
mbed_official 0:51ac1d130fd4 312 /* it wasn't the first, so it must have a valid 'prev' */
mbed_official 0:51ac1d130fd4 313 LWIP_ASSERT("sanity check linked list", prev != NULL);
mbed_official 0:51ac1d130fd4 314 prev->next = ipr->next;
mbed_official 0:51ac1d130fd4 315 }
mbed_official 0:51ac1d130fd4 316
mbed_official 0:51ac1d130fd4 317 /* now we can free the ip_reass struct */
mbed_official 0:51ac1d130fd4 318 memp_free(MEMP_REASSDATA, ipr);
mbed_official 0:51ac1d130fd4 319 }
mbed_official 0:51ac1d130fd4 320
mbed_official 0:51ac1d130fd4 321 /**
mbed_official 0:51ac1d130fd4 322 * Chain a new pbuf into the pbuf list that composes the datagram. The pbuf list
mbed_official 0:51ac1d130fd4 323 * will grow over time as new pbufs are rx.
mbed_official 0:51ac1d130fd4 324 * Also checks that the datagram passes basic continuity checks (if the last
mbed_official 0:51ac1d130fd4 325 * fragment was received at least once).
mbed_official 0:51ac1d130fd4 326 * @param root_p points to the 'root' pbuf for the current datagram being assembled.
mbed_official 0:51ac1d130fd4 327 * @param new_p points to the pbuf for the current fragment
mbed_official 0:51ac1d130fd4 328 * @return 0 if invalid, >0 otherwise
mbed_official 0:51ac1d130fd4 329 */
mbed_official 0:51ac1d130fd4 330 static int
mbed_official 0:51ac1d130fd4 331 ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p)
mbed_official 0:51ac1d130fd4 332 {
mbed_official 0:51ac1d130fd4 333 struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
mbed_official 0:51ac1d130fd4 334 struct pbuf *q;
mbed_official 0:51ac1d130fd4 335 u16_t offset,len;
mbed_official 0:51ac1d130fd4 336 struct ip_hdr *fraghdr;
mbed_official 0:51ac1d130fd4 337 int valid = 1;
mbed_official 0:51ac1d130fd4 338
mbed_official 0:51ac1d130fd4 339 /* Extract length and fragment offset from current fragment */
mbed_official 0:51ac1d130fd4 340 fraghdr = (struct ip_hdr*)new_p->payload;
mbed_official 0:51ac1d130fd4 341 len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
mbed_official 0:51ac1d130fd4 342 offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
mbed_official 0:51ac1d130fd4 343
mbed_official 0:51ac1d130fd4 344 /* overwrite the fragment's ip header from the pbuf with our helper struct,
mbed_official 0:51ac1d130fd4 345 * and setup the embedded helper structure. */
mbed_official 0:51ac1d130fd4 346 /* make sure the struct ip_reass_helper fits into the IP header */
mbed_official 0:51ac1d130fd4 347 LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN",
mbed_official 0:51ac1d130fd4 348 sizeof(struct ip_reass_helper) <= IP_HLEN);
mbed_official 0:51ac1d130fd4 349 iprh = (struct ip_reass_helper*)new_p->payload;
mbed_official 0:51ac1d130fd4 350 iprh->next_pbuf = NULL;
mbed_official 0:51ac1d130fd4 351 iprh->start = offset;
mbed_official 0:51ac1d130fd4 352 iprh->end = offset + len;
mbed_official 0:51ac1d130fd4 353
mbed_official 0:51ac1d130fd4 354 /* Iterate through until we either get to the end of the list (append),
mbed_official 0:51ac1d130fd4 355 * or we find on with a larger offset (insert). */
mbed_official 0:51ac1d130fd4 356 for (q = ipr->p; q != NULL;) {
mbed_official 0:51ac1d130fd4 357 iprh_tmp = (struct ip_reass_helper*)q->payload;
mbed_official 0:51ac1d130fd4 358 if (iprh->start < iprh_tmp->start) {
mbed_official 0:51ac1d130fd4 359 /* the new pbuf should be inserted before this */
mbed_official 0:51ac1d130fd4 360 iprh->next_pbuf = q;
mbed_official 0:51ac1d130fd4 361 if (iprh_prev != NULL) {
mbed_official 0:51ac1d130fd4 362 /* not the fragment with the lowest offset */
mbed_official 0:51ac1d130fd4 363 #if IP_REASS_CHECK_OVERLAP
mbed_official 0:51ac1d130fd4 364 if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {
mbed_official 0:51ac1d130fd4 365 /* fragment overlaps with previous or following, throw away */
mbed_official 0:51ac1d130fd4 366 goto freepbuf;
mbed_official 0:51ac1d130fd4 367 }
mbed_official 0:51ac1d130fd4 368 #endif /* IP_REASS_CHECK_OVERLAP */
mbed_official 0:51ac1d130fd4 369 iprh_prev->next_pbuf = new_p;
mbed_official 0:51ac1d130fd4 370 } else {
mbed_official 0:51ac1d130fd4 371 /* fragment with the lowest offset */
mbed_official 0:51ac1d130fd4 372 ipr->p = new_p;
mbed_official 0:51ac1d130fd4 373 }
mbed_official 0:51ac1d130fd4 374 break;
mbed_official 0:51ac1d130fd4 375 } else if(iprh->start == iprh_tmp->start) {
mbed_official 0:51ac1d130fd4 376 /* received the same datagram twice: no need to keep the datagram */
mbed_official 0:51ac1d130fd4 377 goto freepbuf;
mbed_official 0:51ac1d130fd4 378 #if IP_REASS_CHECK_OVERLAP
mbed_official 0:51ac1d130fd4 379 } else if(iprh->start < iprh_tmp->end) {
mbed_official 0:51ac1d130fd4 380 /* overlap: no need to keep the new datagram */
mbed_official 0:51ac1d130fd4 381 goto freepbuf;
mbed_official 0:51ac1d130fd4 382 #endif /* IP_REASS_CHECK_OVERLAP */
mbed_official 0:51ac1d130fd4 383 } else {
mbed_official 0:51ac1d130fd4 384 /* Check if the fragments received so far have no wholes. */
mbed_official 0:51ac1d130fd4 385 if (iprh_prev != NULL) {
mbed_official 0:51ac1d130fd4 386 if (iprh_prev->end != iprh_tmp->start) {
mbed_official 0:51ac1d130fd4 387 /* There is a fragment missing between the current
mbed_official 0:51ac1d130fd4 388 * and the previous fragment */
mbed_official 0:51ac1d130fd4 389 valid = 0;
mbed_official 0:51ac1d130fd4 390 }
mbed_official 0:51ac1d130fd4 391 }
mbed_official 0:51ac1d130fd4 392 }
mbed_official 0:51ac1d130fd4 393 q = iprh_tmp->next_pbuf;
mbed_official 0:51ac1d130fd4 394 iprh_prev = iprh_tmp;
mbed_official 0:51ac1d130fd4 395 }
mbed_official 0:51ac1d130fd4 396
mbed_official 0:51ac1d130fd4 397 /* If q is NULL, then we made it to the end of the list. Determine what to do now */
mbed_official 0:51ac1d130fd4 398 if (q == NULL) {
mbed_official 0:51ac1d130fd4 399 if (iprh_prev != NULL) {
mbed_official 0:51ac1d130fd4 400 /* this is (for now), the fragment with the highest offset:
mbed_official 0:51ac1d130fd4 401 * chain it to the last fragment */
mbed_official 0:51ac1d130fd4 402 #if IP_REASS_CHECK_OVERLAP
mbed_official 0:51ac1d130fd4 403 LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);
mbed_official 0:51ac1d130fd4 404 #endif /* IP_REASS_CHECK_OVERLAP */
mbed_official 0:51ac1d130fd4 405 iprh_prev->next_pbuf = new_p;
mbed_official 0:51ac1d130fd4 406 if (iprh_prev->end != iprh->start) {
mbed_official 0:51ac1d130fd4 407 valid = 0;
mbed_official 0:51ac1d130fd4 408 }
mbed_official 0:51ac1d130fd4 409 } else {
mbed_official 0:51ac1d130fd4 410 #if IP_REASS_CHECK_OVERLAP
mbed_official 0:51ac1d130fd4 411 LWIP_ASSERT("no previous fragment, this must be the first fragment!",
mbed_official 0:51ac1d130fd4 412 ipr->p == NULL);
mbed_official 0:51ac1d130fd4 413 #endif /* IP_REASS_CHECK_OVERLAP */
mbed_official 0:51ac1d130fd4 414 /* this is the first fragment we ever received for this ip datagram */
mbed_official 0:51ac1d130fd4 415 ipr->p = new_p;
mbed_official 0:51ac1d130fd4 416 }
mbed_official 0:51ac1d130fd4 417 }
mbed_official 0:51ac1d130fd4 418
mbed_official 0:51ac1d130fd4 419 /* At this point, the validation part begins: */
mbed_official 0:51ac1d130fd4 420 /* If we already received the last fragment */
mbed_official 0:51ac1d130fd4 421 if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
mbed_official 0:51ac1d130fd4 422 /* and had no wholes so far */
mbed_official 0:51ac1d130fd4 423 if (valid) {
mbed_official 0:51ac1d130fd4 424 /* then check if the rest of the fragments is here */
mbed_official 0:51ac1d130fd4 425 /* Check if the queue starts with the first datagram */
mbed_official 0:51ac1d130fd4 426 if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) {
mbed_official 0:51ac1d130fd4 427 valid = 0;
mbed_official 0:51ac1d130fd4 428 } else {
mbed_official 0:51ac1d130fd4 429 /* and check that there are no wholes after this datagram */
mbed_official 0:51ac1d130fd4 430 iprh_prev = iprh;
mbed_official 0:51ac1d130fd4 431 q = iprh->next_pbuf;
mbed_official 0:51ac1d130fd4 432 while (q != NULL) {
mbed_official 0:51ac1d130fd4 433 iprh = (struct ip_reass_helper*)q->payload;
mbed_official 0:51ac1d130fd4 434 if (iprh_prev->end != iprh->start) {
mbed_official 0:51ac1d130fd4 435 valid = 0;
mbed_official 0:51ac1d130fd4 436 break;
mbed_official 0:51ac1d130fd4 437 }
mbed_official 0:51ac1d130fd4 438 iprh_prev = iprh;
mbed_official 0:51ac1d130fd4 439 q = iprh->next_pbuf;
mbed_official 0:51ac1d130fd4 440 }
mbed_official 0:51ac1d130fd4 441 /* if still valid, all fragments are received
mbed_official 0:51ac1d130fd4 442 * (because to the MF==0 already arrived */
mbed_official 0:51ac1d130fd4 443 if (valid) {
mbed_official 0:51ac1d130fd4 444 LWIP_ASSERT("sanity check", ipr->p != NULL);
mbed_official 0:51ac1d130fd4 445 LWIP_ASSERT("sanity check",
mbed_official 0:51ac1d130fd4 446 ((struct ip_reass_helper*)ipr->p->payload) != iprh);
mbed_official 0:51ac1d130fd4 447 LWIP_ASSERT("validate_datagram:next_pbuf!=NULL",
mbed_official 0:51ac1d130fd4 448 iprh->next_pbuf == NULL);
mbed_official 0:51ac1d130fd4 449 LWIP_ASSERT("validate_datagram:datagram end!=datagram len",
mbed_official 0:51ac1d130fd4 450 iprh->end == ipr->datagram_len);
mbed_official 0:51ac1d130fd4 451 }
mbed_official 0:51ac1d130fd4 452 }
mbed_official 0:51ac1d130fd4 453 }
mbed_official 0:51ac1d130fd4 454 /* If valid is 0 here, there are some fragments missing in the middle
mbed_official 0:51ac1d130fd4 455 * (since MF == 0 has already arrived). Such datagrams simply time out if
mbed_official 0:51ac1d130fd4 456 * no more fragments are received... */
mbed_official 0:51ac1d130fd4 457 return valid;
mbed_official 0:51ac1d130fd4 458 }
mbed_official 0:51ac1d130fd4 459 /* If we come here, not all fragments were received, yet! */
mbed_official 0:51ac1d130fd4 460 return 0; /* not yet valid! */
mbed_official 0:51ac1d130fd4 461 #if IP_REASS_CHECK_OVERLAP
mbed_official 0:51ac1d130fd4 462 freepbuf:
mbed_official 0:51ac1d130fd4 463 ip_reass_pbufcount -= pbuf_clen(new_p);
mbed_official 0:51ac1d130fd4 464 pbuf_free(new_p);
mbed_official 0:51ac1d130fd4 465 return 0;
mbed_official 0:51ac1d130fd4 466 #endif /* IP_REASS_CHECK_OVERLAP */
mbed_official 0:51ac1d130fd4 467 }
mbed_official 0:51ac1d130fd4 468
mbed_official 0:51ac1d130fd4 469 /**
mbed_official 0:51ac1d130fd4 470 * Reassembles incoming IP fragments into an IP datagram.
mbed_official 0:51ac1d130fd4 471 *
mbed_official 0:51ac1d130fd4 472 * @param p points to a pbuf chain of the fragment
mbed_official 0:51ac1d130fd4 473 * @return NULL if reassembly is incomplete, ? otherwise
mbed_official 0:51ac1d130fd4 474 */
mbed_official 0:51ac1d130fd4 475 struct pbuf *
mbed_official 0:51ac1d130fd4 476 ip_reass(struct pbuf *p)
mbed_official 0:51ac1d130fd4 477 {
mbed_official 0:51ac1d130fd4 478 struct pbuf *r;
mbed_official 0:51ac1d130fd4 479 struct ip_hdr *fraghdr;
mbed_official 0:51ac1d130fd4 480 struct ip_reassdata *ipr;
mbed_official 0:51ac1d130fd4 481 struct ip_reass_helper *iprh;
mbed_official 0:51ac1d130fd4 482 u16_t offset, len;
mbed_official 0:51ac1d130fd4 483 u8_t clen;
mbed_official 0:51ac1d130fd4 484 struct ip_reassdata *ipr_prev = NULL;
mbed_official 0:51ac1d130fd4 485
mbed_official 0:51ac1d130fd4 486 IPFRAG_STATS_INC(ip_frag.recv);
mbed_official 0:51ac1d130fd4 487 snmp_inc_ipreasmreqds();
mbed_official 0:51ac1d130fd4 488
mbed_official 0:51ac1d130fd4 489 fraghdr = (struct ip_hdr*)p->payload;
mbed_official 0:51ac1d130fd4 490
mbed_official 0:51ac1d130fd4 491 if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {
mbed_official 0:51ac1d130fd4 492 LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n"));
mbed_official 0:51ac1d130fd4 493 IPFRAG_STATS_INC(ip_frag.err);
mbed_official 0:51ac1d130fd4 494 goto nullreturn;
mbed_official 0:51ac1d130fd4 495 }
mbed_official 0:51ac1d130fd4 496
mbed_official 0:51ac1d130fd4 497 offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
mbed_official 0:51ac1d130fd4 498 len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
mbed_official 0:51ac1d130fd4 499
mbed_official 0:51ac1d130fd4 500 /* Check if we are allowed to enqueue more datagrams. */
mbed_official 0:51ac1d130fd4 501 clen = pbuf_clen(p);
mbed_official 0:51ac1d130fd4 502 if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
mbed_official 0:51ac1d130fd4 503 #if IP_REASS_FREE_OLDEST
mbed_official 0:51ac1d130fd4 504 if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||
mbed_official 0:51ac1d130fd4 505 ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS))
mbed_official 0:51ac1d130fd4 506 #endif /* IP_REASS_FREE_OLDEST */
mbed_official 0:51ac1d130fd4 507 {
mbed_official 0:51ac1d130fd4 508 /* No datagram could be freed and still too many pbufs enqueued */
mbed_official 0:51ac1d130fd4 509 LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
mbed_official 0:51ac1d130fd4 510 ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));
mbed_official 0:51ac1d130fd4 511 IPFRAG_STATS_INC(ip_frag.memerr);
mbed_official 0:51ac1d130fd4 512 /* @todo: send ICMP time exceeded here? */
mbed_official 0:51ac1d130fd4 513 /* drop this pbuf */
mbed_official 0:51ac1d130fd4 514 goto nullreturn;
mbed_official 0:51ac1d130fd4 515 }
mbed_official 0:51ac1d130fd4 516 }
mbed_official 0:51ac1d130fd4 517
mbed_official 0:51ac1d130fd4 518 /* Look for the datagram the fragment belongs to in the current datagram queue,
mbed_official 0:51ac1d130fd4 519 * remembering the previous in the queue for later dequeueing. */
mbed_official 0:51ac1d130fd4 520 for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {
mbed_official 0:51ac1d130fd4 521 /* Check if the incoming fragment matches the one currently present
mbed_official 0:51ac1d130fd4 522 in the reassembly buffer. If so, we proceed with copying the
mbed_official 0:51ac1d130fd4 523 fragment into the buffer. */
mbed_official 0:51ac1d130fd4 524 if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
mbed_official 0:51ac1d130fd4 525 LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",
mbed_official 0:51ac1d130fd4 526 ntohs(IPH_ID(fraghdr))));
mbed_official 0:51ac1d130fd4 527 IPFRAG_STATS_INC(ip_frag.cachehit);
mbed_official 0:51ac1d130fd4 528 break;
mbed_official 0:51ac1d130fd4 529 }
mbed_official 0:51ac1d130fd4 530 ipr_prev = ipr;
mbed_official 0:51ac1d130fd4 531 }
mbed_official 0:51ac1d130fd4 532
mbed_official 0:51ac1d130fd4 533 if (ipr == NULL) {
mbed_official 0:51ac1d130fd4 534 /* Enqueue a new datagram into the datagram queue */
mbed_official 0:51ac1d130fd4 535 ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
mbed_official 0:51ac1d130fd4 536 /* Bail if unable to enqueue */
mbed_official 0:51ac1d130fd4 537 if(ipr == NULL) {
mbed_official 0:51ac1d130fd4 538 goto nullreturn;
mbed_official 0:51ac1d130fd4 539 }
mbed_official 0:51ac1d130fd4 540 } else {
mbed_official 0:51ac1d130fd4 541 if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
mbed_official 0:51ac1d130fd4 542 ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
mbed_official 0:51ac1d130fd4 543 /* ipr->iphdr is not the header from the first fragment, but fraghdr is
mbed_official 0:51ac1d130fd4 544 * -> copy fraghdr into ipr->iphdr since we want to have the header
mbed_official 0:51ac1d130fd4 545 * of the first fragment (for ICMP time exceeded and later, for copying
mbed_official 0:51ac1d130fd4 546 * all options, if supported)*/
mbed_official 0:51ac1d130fd4 547 SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
mbed_official 0:51ac1d130fd4 548 }
mbed_official 0:51ac1d130fd4 549 }
mbed_official 0:51ac1d130fd4 550 /* Track the current number of pbufs current 'in-flight', in order to limit
mbed_official 0:51ac1d130fd4 551 the number of fragments that may be enqueued at any one time */
mbed_official 0:51ac1d130fd4 552 ip_reass_pbufcount += clen;
mbed_official 0:51ac1d130fd4 553
mbed_official 0:51ac1d130fd4 554 /* At this point, we have either created a new entry or pointing
mbed_official 0:51ac1d130fd4 555 * to an existing one */
mbed_official 0:51ac1d130fd4 556
mbed_official 0:51ac1d130fd4 557 /* check for 'no more fragments', and update queue entry*/
mbed_official 0:51ac1d130fd4 558 if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) {
mbed_official 0:51ac1d130fd4 559 ipr->flags |= IP_REASS_FLAG_LASTFRAG;
mbed_official 0:51ac1d130fd4 560 ipr->datagram_len = offset + len;
mbed_official 0:51ac1d130fd4 561 LWIP_DEBUGF(IP_REASS_DEBUG,
mbed_official 0:51ac1d130fd4 562 ("ip_reass: last fragment seen, total len %"S16_F"\n",
mbed_official 0:51ac1d130fd4 563 ipr->datagram_len));
mbed_official 0:51ac1d130fd4 564 }
mbed_official 0:51ac1d130fd4 565 /* find the right place to insert this pbuf */
mbed_official 0:51ac1d130fd4 566 /* @todo: trim pbufs if fragments are overlapping */
mbed_official 0:51ac1d130fd4 567 if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {
mbed_official 0:51ac1d130fd4 568 /* the totally last fragment (flag more fragments = 0) was received at least
mbed_official 0:51ac1d130fd4 569 * once AND all fragments are received */
mbed_official 0:51ac1d130fd4 570 ipr->datagram_len += IP_HLEN;
mbed_official 0:51ac1d130fd4 571
mbed_official 0:51ac1d130fd4 572 /* save the second pbuf before copying the header over the pointer */
mbed_official 0:51ac1d130fd4 573 r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf;
mbed_official 0:51ac1d130fd4 574
mbed_official 0:51ac1d130fd4 575 /* copy the original ip header back to the first pbuf */
mbed_official 0:51ac1d130fd4 576 fraghdr = (struct ip_hdr*)(ipr->p->payload);
mbed_official 0:51ac1d130fd4 577 SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
mbed_official 0:51ac1d130fd4 578 IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));
mbed_official 0:51ac1d130fd4 579 IPH_OFFSET_SET(fraghdr, 0);
mbed_official 0:51ac1d130fd4 580 IPH_CHKSUM_SET(fraghdr, 0);
mbed_official 0:51ac1d130fd4 581 /* @todo: do we need to set calculate the correct checksum? */
mbed_official 0:51ac1d130fd4 582 IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
mbed_official 0:51ac1d130fd4 583
mbed_official 0:51ac1d130fd4 584 p = ipr->p;
mbed_official 0:51ac1d130fd4 585
mbed_official 0:51ac1d130fd4 586 /* chain together the pbufs contained within the reass_data list. */
mbed_official 0:51ac1d130fd4 587 while(r != NULL) {
mbed_official 0:51ac1d130fd4 588 iprh = (struct ip_reass_helper*)r->payload;
mbed_official 0:51ac1d130fd4 589
mbed_official 0:51ac1d130fd4 590 /* hide the ip header for every succeding fragment */
mbed_official 0:51ac1d130fd4 591 pbuf_header(r, -IP_HLEN);
mbed_official 0:51ac1d130fd4 592 pbuf_cat(p, r);
mbed_official 0:51ac1d130fd4 593 r = iprh->next_pbuf;
mbed_official 0:51ac1d130fd4 594 }
mbed_official 0:51ac1d130fd4 595 /* release the sources allocate for the fragment queue entry */
mbed_official 0:51ac1d130fd4 596 ip_reass_dequeue_datagram(ipr, ipr_prev);
mbed_official 0:51ac1d130fd4 597
mbed_official 0:51ac1d130fd4 598 /* and adjust the number of pbufs currently queued for reassembly. */
mbed_official 0:51ac1d130fd4 599 ip_reass_pbufcount -= pbuf_clen(p);
mbed_official 0:51ac1d130fd4 600
mbed_official 0:51ac1d130fd4 601 /* Return the pbuf chain */
mbed_official 0:51ac1d130fd4 602 return p;
mbed_official 0:51ac1d130fd4 603 }
mbed_official 0:51ac1d130fd4 604 /* the datagram is not (yet?) reassembled completely */
mbed_official 0:51ac1d130fd4 605 LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount));
mbed_official 0:51ac1d130fd4 606 return NULL;
mbed_official 0:51ac1d130fd4 607
mbed_official 0:51ac1d130fd4 608 nullreturn:
mbed_official 0:51ac1d130fd4 609 LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n"));
mbed_official 0:51ac1d130fd4 610 IPFRAG_STATS_INC(ip_frag.drop);
mbed_official 0:51ac1d130fd4 611 pbuf_free(p);
mbed_official 0:51ac1d130fd4 612 return NULL;
mbed_official 0:51ac1d130fd4 613 }
mbed_official 0:51ac1d130fd4 614 #endif /* IP_REASSEMBLY */
mbed_official 0:51ac1d130fd4 615
mbed_official 0:51ac1d130fd4 616 #if IP_FRAG
mbed_official 0:51ac1d130fd4 617 #if IP_FRAG_USES_STATIC_BUF
mbed_official 0:51ac1d130fd4 618 static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];
mbed_official 0:51ac1d130fd4 619 #else /* IP_FRAG_USES_STATIC_BUF */
mbed_official 0:51ac1d130fd4 620
mbed_official 0:51ac1d130fd4 621 #if !LWIP_NETIF_TX_SINGLE_PBUF
mbed_official 0:51ac1d130fd4 622 /** Allocate a new struct pbuf_custom_ref */
mbed_official 0:51ac1d130fd4 623 static struct pbuf_custom_ref*
mbed_official 0:51ac1d130fd4 624 ip_frag_alloc_pbuf_custom_ref(void)
mbed_official 0:51ac1d130fd4 625 {
mbed_official 0:51ac1d130fd4 626 return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
mbed_official 0:51ac1d130fd4 627 }
mbed_official 0:51ac1d130fd4 628
mbed_official 0:51ac1d130fd4 629 /** Free a struct pbuf_custom_ref */
mbed_official 0:51ac1d130fd4 630 static void
mbed_official 0:51ac1d130fd4 631 ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p)
mbed_official 0:51ac1d130fd4 632 {
mbed_official 0:51ac1d130fd4 633 LWIP_ASSERT("p != NULL", p != NULL);
mbed_official 0:51ac1d130fd4 634 memp_free(MEMP_FRAG_PBUF, p);
mbed_official 0:51ac1d130fd4 635 }
mbed_official 0:51ac1d130fd4 636
mbed_official 0:51ac1d130fd4 637 /** Free-callback function to free a 'struct pbuf_custom_ref', called by
mbed_official 0:51ac1d130fd4 638 * pbuf_free. */
mbed_official 0:51ac1d130fd4 639 static void
mbed_official 0:51ac1d130fd4 640 ipfrag_free_pbuf_custom(struct pbuf *p)
mbed_official 0:51ac1d130fd4 641 {
mbed_official 0:51ac1d130fd4 642 struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p;
mbed_official 0:51ac1d130fd4 643 LWIP_ASSERT("pcr != NULL", pcr != NULL);
mbed_official 0:51ac1d130fd4 644 LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p);
mbed_official 0:51ac1d130fd4 645 if (pcr->original != NULL) {
mbed_official 0:51ac1d130fd4 646 pbuf_free(pcr->original);
mbed_official 0:51ac1d130fd4 647 }
mbed_official 0:51ac1d130fd4 648 ip_frag_free_pbuf_custom_ref(pcr);
mbed_official 0:51ac1d130fd4 649 }
mbed_official 0:51ac1d130fd4 650 #endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
mbed_official 0:51ac1d130fd4 651 #endif /* IP_FRAG_USES_STATIC_BUF */
mbed_official 0:51ac1d130fd4 652
mbed_official 0:51ac1d130fd4 653 /**
mbed_official 0:51ac1d130fd4 654 * Fragment an IP datagram if too large for the netif.
mbed_official 0:51ac1d130fd4 655 *
mbed_official 0:51ac1d130fd4 656 * Chop the datagram in MTU sized chunks and send them in order
mbed_official 0:51ac1d130fd4 657 * by using a fixed size static memory buffer (PBUF_REF) or
mbed_official 0:51ac1d130fd4 658 * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).
mbed_official 0:51ac1d130fd4 659 *
mbed_official 0:51ac1d130fd4 660 * @param p ip packet to send
mbed_official 0:51ac1d130fd4 661 * @param netif the netif on which to send
mbed_official 0:51ac1d130fd4 662 * @param dest destination ip address to which to send
mbed_official 0:51ac1d130fd4 663 *
mbed_official 0:51ac1d130fd4 664 * @return ERR_OK if sent successfully, err_t otherwise
mbed_official 0:51ac1d130fd4 665 */
mbed_official 0:51ac1d130fd4 666 err_t
mbed_official 0:51ac1d130fd4 667 ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
mbed_official 0:51ac1d130fd4 668 {
mbed_official 0:51ac1d130fd4 669 struct pbuf *rambuf;
mbed_official 0:51ac1d130fd4 670 #if IP_FRAG_USES_STATIC_BUF
mbed_official 0:51ac1d130fd4 671 struct pbuf *header;
mbed_official 0:51ac1d130fd4 672 #else
mbed_official 0:51ac1d130fd4 673 #if !LWIP_NETIF_TX_SINGLE_PBUF
mbed_official 0:51ac1d130fd4 674 struct pbuf *newpbuf;
mbed_official 0:51ac1d130fd4 675 #endif
mbed_official 0:51ac1d130fd4 676 struct ip_hdr *original_iphdr;
mbed_official 0:51ac1d130fd4 677 #endif
mbed_official 0:51ac1d130fd4 678 struct ip_hdr *iphdr;
mbed_official 0:51ac1d130fd4 679 u16_t nfb;
mbed_official 0:51ac1d130fd4 680 u16_t left, cop;
mbed_official 0:51ac1d130fd4 681 u16_t mtu = netif->mtu;
mbed_official 0:51ac1d130fd4 682 u16_t ofo, omf;
mbed_official 0:51ac1d130fd4 683 u16_t last;
mbed_official 0:51ac1d130fd4 684 u16_t poff = IP_HLEN;
mbed_official 0:51ac1d130fd4 685 u16_t tmp;
mbed_official 0:51ac1d130fd4 686 #if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
mbed_official 0:51ac1d130fd4 687 u16_t newpbuflen = 0;
mbed_official 0:51ac1d130fd4 688 u16_t left_to_copy;
mbed_official 0:51ac1d130fd4 689 #endif
mbed_official 0:51ac1d130fd4 690
mbed_official 0:51ac1d130fd4 691 /* Get a RAM based MTU sized pbuf */
mbed_official 0:51ac1d130fd4 692 #if IP_FRAG_USES_STATIC_BUF
mbed_official 0:51ac1d130fd4 693 /* When using a static buffer, we use a PBUF_REF, which we will
mbed_official 0:51ac1d130fd4 694 * use to reference the packet (without link header).
mbed_official 0:51ac1d130fd4 695 * Layer and length is irrelevant.
mbed_official 0:51ac1d130fd4 696 */
mbed_official 0:51ac1d130fd4 697 rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
mbed_official 0:51ac1d130fd4 698 if (rambuf == NULL) {
mbed_official 0:51ac1d130fd4 699 LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));
mbed_official 0:51ac1d130fd4 700 return ERR_MEM;
mbed_official 0:51ac1d130fd4 701 }
mbed_official 0:51ac1d130fd4 702 rambuf->tot_len = rambuf->len = mtu;
mbed_official 0:51ac1d130fd4 703 rambuf->payload = LWIP_MEM_ALIGN((void *)buf);
mbed_official 0:51ac1d130fd4 704
mbed_official 0:51ac1d130fd4 705 /* Copy the IP header in it */
mbed_official 0:51ac1d130fd4 706 iphdr = (struct ip_hdr *)rambuf->payload;
mbed_official 0:51ac1d130fd4 707 SMEMCPY(iphdr, p->payload, IP_HLEN);
mbed_official 0:51ac1d130fd4 708 #else /* IP_FRAG_USES_STATIC_BUF */
mbed_official 0:51ac1d130fd4 709 original_iphdr = (struct ip_hdr *)p->payload;
mbed_official 0:51ac1d130fd4 710 iphdr = original_iphdr;
mbed_official 0:51ac1d130fd4 711 #endif /* IP_FRAG_USES_STATIC_BUF */
mbed_official 0:51ac1d130fd4 712
mbed_official 0:51ac1d130fd4 713 /* Save original offset */
mbed_official 0:51ac1d130fd4 714 tmp = ntohs(IPH_OFFSET(iphdr));
mbed_official 0:51ac1d130fd4 715 ofo = tmp & IP_OFFMASK;
mbed_official 0:51ac1d130fd4 716 omf = tmp & IP_MF;
mbed_official 0:51ac1d130fd4 717
mbed_official 0:51ac1d130fd4 718 left = p->tot_len - IP_HLEN;
mbed_official 0:51ac1d130fd4 719
mbed_official 0:51ac1d130fd4 720 nfb = (mtu - IP_HLEN) / 8;
mbed_official 0:51ac1d130fd4 721
mbed_official 0:51ac1d130fd4 722 while (left) {
mbed_official 0:51ac1d130fd4 723 last = (left <= mtu - IP_HLEN);
mbed_official 0:51ac1d130fd4 724
mbed_official 0:51ac1d130fd4 725 /* Set new offset and MF flag */
mbed_official 0:51ac1d130fd4 726 tmp = omf | (IP_OFFMASK & (ofo));
mbed_official 0:51ac1d130fd4 727 if (!last) {
mbed_official 0:51ac1d130fd4 728 tmp = tmp | IP_MF;
mbed_official 0:51ac1d130fd4 729 }
mbed_official 0:51ac1d130fd4 730
mbed_official 0:51ac1d130fd4 731 /* Fill this fragment */
mbed_official 0:51ac1d130fd4 732 cop = last ? left : nfb * 8;
mbed_official 0:51ac1d130fd4 733
mbed_official 0:51ac1d130fd4 734 #if IP_FRAG_USES_STATIC_BUF
mbed_official 0:51ac1d130fd4 735 poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);
mbed_official 0:51ac1d130fd4 736 #else /* IP_FRAG_USES_STATIC_BUF */
mbed_official 0:51ac1d130fd4 737 #if LWIP_NETIF_TX_SINGLE_PBUF
mbed_official 0:51ac1d130fd4 738 rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM);
mbed_official 0:51ac1d130fd4 739 if (rambuf == NULL) {
mbed_official 0:51ac1d130fd4 740 return ERR_MEM;
mbed_official 0:51ac1d130fd4 741 }
mbed_official 0:51ac1d130fd4 742 LWIP_ASSERT("this needs a pbuf in one piece!",
mbed_official 0:51ac1d130fd4 743 (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
mbed_official 0:51ac1d130fd4 744 poff += pbuf_copy_partial(p, rambuf->payload, cop, poff);
mbed_official 0:51ac1d130fd4 745 /* make room for the IP header */
mbed_official 0:51ac1d130fd4 746 if(pbuf_header(rambuf, IP_HLEN)) {
mbed_official 0:51ac1d130fd4 747 pbuf_free(rambuf);
mbed_official 0:51ac1d130fd4 748 return ERR_MEM;
mbed_official 0:51ac1d130fd4 749 }
mbed_official 0:51ac1d130fd4 750 /* fill in the IP header */
mbed_official 0:51ac1d130fd4 751 SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
mbed_official 0:51ac1d130fd4 752 iphdr = rambuf->payload;
mbed_official 0:51ac1d130fd4 753 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
mbed_official 0:51ac1d130fd4 754 /* When not using a static buffer, create a chain of pbufs.
mbed_official 0:51ac1d130fd4 755 * The first will be a PBUF_RAM holding the link and IP header.
mbed_official 0:51ac1d130fd4 756 * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
mbed_official 0:51ac1d130fd4 757 * but limited to the size of an mtu.
mbed_official 0:51ac1d130fd4 758 */
mbed_official 0:51ac1d130fd4 759 rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);
mbed_official 0:51ac1d130fd4 760 if (rambuf == NULL) {
mbed_official 0:51ac1d130fd4 761 return ERR_MEM;
mbed_official 0:51ac1d130fd4 762 }
mbed_official 0:51ac1d130fd4 763 LWIP_ASSERT("this needs a pbuf in one piece!",
mbed_official 0:51ac1d130fd4 764 (p->len >= (IP_HLEN)));
mbed_official 0:51ac1d130fd4 765 SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
mbed_official 0:51ac1d130fd4 766 iphdr = (struct ip_hdr *)rambuf->payload;
mbed_official 0:51ac1d130fd4 767
mbed_official 0:51ac1d130fd4 768 /* Can just adjust p directly for needed offset. */
mbed_official 0:51ac1d130fd4 769 p->payload = (u8_t *)p->payload + poff;
mbed_official 0:51ac1d130fd4 770 p->len -= poff;
mbed_official 0:51ac1d130fd4 771
mbed_official 0:51ac1d130fd4 772 left_to_copy = cop;
mbed_official 0:51ac1d130fd4 773 while (left_to_copy) {
mbed_official 0:51ac1d130fd4 774 struct pbuf_custom_ref *pcr;
mbed_official 0:51ac1d130fd4 775 newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
mbed_official 0:51ac1d130fd4 776 /* Is this pbuf already empty? */
mbed_official 0:51ac1d130fd4 777 if (!newpbuflen) {
mbed_official 0:51ac1d130fd4 778 p = p->next;
mbed_official 0:51ac1d130fd4 779 continue;
mbed_official 0:51ac1d130fd4 780 }
mbed_official 0:51ac1d130fd4 781 pcr = ip_frag_alloc_pbuf_custom_ref();
mbed_official 0:51ac1d130fd4 782 if (pcr == NULL) {
mbed_official 0:51ac1d130fd4 783 pbuf_free(rambuf);
mbed_official 0:51ac1d130fd4 784 return ERR_MEM;
mbed_official 0:51ac1d130fd4 785 }
mbed_official 0:51ac1d130fd4 786 /* Mirror this pbuf, although we might not need all of it. */
mbed_official 0:51ac1d130fd4 787 newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
mbed_official 0:51ac1d130fd4 788 if (newpbuf == NULL) {
mbed_official 0:51ac1d130fd4 789 ip_frag_free_pbuf_custom_ref(pcr);
mbed_official 0:51ac1d130fd4 790 pbuf_free(rambuf);
mbed_official 0:51ac1d130fd4 791 return ERR_MEM;
mbed_official 0:51ac1d130fd4 792 }
mbed_official 0:51ac1d130fd4 793 pbuf_ref(p);
mbed_official 0:51ac1d130fd4 794 pcr->original = p;
mbed_official 0:51ac1d130fd4 795 pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;
mbed_official 0:51ac1d130fd4 796
mbed_official 0:51ac1d130fd4 797 /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
mbed_official 0:51ac1d130fd4 798 * so that it is removed when pbuf_dechain is later called on rambuf.
mbed_official 0:51ac1d130fd4 799 */
mbed_official 0:51ac1d130fd4 800 pbuf_cat(rambuf, newpbuf);
mbed_official 0:51ac1d130fd4 801 left_to_copy -= newpbuflen;
mbed_official 0:51ac1d130fd4 802 if (left_to_copy) {
mbed_official 0:51ac1d130fd4 803 p = p->next;
mbed_official 0:51ac1d130fd4 804 }
mbed_official 0:51ac1d130fd4 805 }
mbed_official 0:51ac1d130fd4 806 poff = newpbuflen;
mbed_official 0:51ac1d130fd4 807 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
mbed_official 0:51ac1d130fd4 808 #endif /* IP_FRAG_USES_STATIC_BUF */
mbed_official 0:51ac1d130fd4 809
mbed_official 0:51ac1d130fd4 810 /* Correct header */
mbed_official 0:51ac1d130fd4 811 IPH_OFFSET_SET(iphdr, htons(tmp));
mbed_official 0:51ac1d130fd4 812 IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
mbed_official 0:51ac1d130fd4 813 IPH_CHKSUM_SET(iphdr, 0);
mbed_official 0:51ac1d130fd4 814 IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
mbed_official 0:51ac1d130fd4 815
mbed_official 0:51ac1d130fd4 816 #if IP_FRAG_USES_STATIC_BUF
mbed_official 0:51ac1d130fd4 817 if (last) {
mbed_official 0:51ac1d130fd4 818 pbuf_realloc(rambuf, left + IP_HLEN);
mbed_official 0:51ac1d130fd4 819 }
mbed_official 0:51ac1d130fd4 820
mbed_official 0:51ac1d130fd4 821 /* This part is ugly: we alloc a RAM based pbuf for
mbed_official 0:51ac1d130fd4 822 * the link level header for each chunk and then
mbed_official 0:51ac1d130fd4 823 * free it.A PBUF_ROM style pbuf for which pbuf_header
mbed_official 0:51ac1d130fd4 824 * worked would make things simpler.
mbed_official 0:51ac1d130fd4 825 */
mbed_official 0:51ac1d130fd4 826 header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
mbed_official 0:51ac1d130fd4 827 if (header != NULL) {
mbed_official 0:51ac1d130fd4 828 pbuf_chain(header, rambuf);
mbed_official 0:51ac1d130fd4 829 netif->output(netif, header, dest);
mbed_official 0:51ac1d130fd4 830 IPFRAG_STATS_INC(ip_frag.xmit);
mbed_official 0:51ac1d130fd4 831 snmp_inc_ipfragcreates();
mbed_official 0:51ac1d130fd4 832 pbuf_free(header);
mbed_official 0:51ac1d130fd4 833 } else {
mbed_official 0:51ac1d130fd4 834 LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));
mbed_official 0:51ac1d130fd4 835 pbuf_free(rambuf);
mbed_official 0:51ac1d130fd4 836 return ERR_MEM;
mbed_official 0:51ac1d130fd4 837 }
mbed_official 0:51ac1d130fd4 838 #else /* IP_FRAG_USES_STATIC_BUF */
mbed_official 0:51ac1d130fd4 839 /* No need for separate header pbuf - we allowed room for it in rambuf
mbed_official 0:51ac1d130fd4 840 * when allocated.
mbed_official 0:51ac1d130fd4 841 */
mbed_official 0:51ac1d130fd4 842 netif->output(netif, rambuf, dest);
mbed_official 0:51ac1d130fd4 843 IPFRAG_STATS_INC(ip_frag.xmit);
mbed_official 0:51ac1d130fd4 844
mbed_official 0:51ac1d130fd4 845 /* Unfortunately we can't reuse rambuf - the hardware may still be
mbed_official 0:51ac1d130fd4 846 * using the buffer. Instead we free it (and the ensuing chain) and
mbed_official 0:51ac1d130fd4 847 * recreate it next time round the loop. If we're lucky the hardware
mbed_official 0:51ac1d130fd4 848 * will have already sent the packet, the free will really free, and
mbed_official 0:51ac1d130fd4 849 * there will be zero memory penalty.
mbed_official 0:51ac1d130fd4 850 */
mbed_official 0:51ac1d130fd4 851
mbed_official 0:51ac1d130fd4 852 pbuf_free(rambuf);
mbed_official 0:51ac1d130fd4 853 #endif /* IP_FRAG_USES_STATIC_BUF */
mbed_official 0:51ac1d130fd4 854 left -= cop;
mbed_official 0:51ac1d130fd4 855 ofo += nfb;
mbed_official 0:51ac1d130fd4 856 }
mbed_official 0:51ac1d130fd4 857 #if IP_FRAG_USES_STATIC_BUF
mbed_official 0:51ac1d130fd4 858 pbuf_free(rambuf);
mbed_official 0:51ac1d130fd4 859 #endif /* IP_FRAG_USES_STATIC_BUF */
mbed_official 0:51ac1d130fd4 860 snmp_inc_ipfragoks();
mbed_official 0:51ac1d130fd4 861 return ERR_OK;
mbed_official 0:51ac1d130fd4 862 }
mbed_official 0:51ac1d130fd4 863 #endif /* IP_FRAG */