Home | History | Annotate | Download | only in core
      1 /**
      2  * @file
      3  * Dynamic pool memory manager
      4  *
      5  * lwIP has dedicated pools for many structures (netconn, protocol control blocks,
      6  * packet buffers, ...). All these pools are managed here.
      7  */
      8 
      9 /*
     10  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
     11  * All rights reserved.
     12  *
     13  * Redistribution and use in source and binary forms, with or without modification,
     14  * are permitted provided that the following conditions are met:
     15  *
     16  * 1. Redistributions of source code must retain the above copyright notice,
     17  *    this list of conditions and the following disclaimer.
     18  * 2. Redistributions in binary form must reproduce the above copyright notice,
     19  *    this list of conditions and the following disclaimer in the documentation
     20  *    and/or other materials provided with the distribution.
     21  * 3. The name of the author may not be used to endorse or promote products
     22  *    derived from this software without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     25  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
     27  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     28  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
     29  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     32  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
     33  * OF SUCH DAMAGE.
     34  *
     35  * This file is part of the lwIP TCP/IP stack.
     36  *
     37  * Author: Adam Dunkels <adam (at) sics.se>
     38  *
     39  */
     40 
     41 #include "lwip/opt.h"
     42 
     43 #include "lwip/memp.h"
     44 #include "lwip/pbuf.h"
     45 #include "lwip/udp.h"
     46 #include "lwip/raw.h"
     47 #include "lwip/tcp_impl.h"
     48 #include "lwip/igmp.h"
     49 #include "lwip/api.h"
     50 #include "lwip/api_msg.h"
     51 #include "lwip/tcpip.h"
     52 #include "lwip/sys.h"
     53 #include "lwip/timers.h"
     54 #include "lwip/stats.h"
     55 #include "netif/etharp.h"
     56 #include "lwip/ip_frag.h"
     57 #include "lwip/snmp_structs.h"
     58 #include "lwip/snmp_msg.h"
     59 #include "lwip/dns.h"
     60 #include "netif/ppp_oe.h"
     61 
     62 #include <string.h>
     63 
     64 #if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
     65 
     66 struct memp {
     67   struct memp *next;
     68 #if MEMP_OVERFLOW_CHECK
     69   const char *file;
     70   int line;
     71 #endif /* MEMP_OVERFLOW_CHECK */
     72 };
     73 
     74 #if MEMP_OVERFLOW_CHECK
     75 /* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning
     76  * and at the end of each element, initialize them as 0xcd and check
     77  * them later. */
     78 /* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,
     79  * every single element in each pool is checked!
     80  * This is VERY SLOW but also very helpful. */
     81 /* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in
     82  * lwipopts.h to change the amount reserved for checking. */
     83 #ifndef MEMP_SANITY_REGION_BEFORE
     84 #define MEMP_SANITY_REGION_BEFORE  16
     85 #endif /* MEMP_SANITY_REGION_BEFORE*/
     86 #if MEMP_SANITY_REGION_BEFORE > 0
     87 #define MEMP_SANITY_REGION_BEFORE_ALIGNED    LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)
     88 #else
     89 #define MEMP_SANITY_REGION_BEFORE_ALIGNED    0
     90 #endif /* MEMP_SANITY_REGION_BEFORE*/
     91 #ifndef MEMP_SANITY_REGION_AFTER
     92 #define MEMP_SANITY_REGION_AFTER   16
     93 #endif /* MEMP_SANITY_REGION_AFTER*/
     94 #if MEMP_SANITY_REGION_AFTER > 0
     95 #define MEMP_SANITY_REGION_AFTER_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)
     96 #else
     97 #define MEMP_SANITY_REGION_AFTER_ALIGNED     0
     98 #endif /* MEMP_SANITY_REGION_AFTER*/
     99 
    100 /* MEMP_SIZE: save space for struct memp and for sanity check */
    101 #define MEMP_SIZE          (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)
    102 #define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)
    103 
    104 #else /* MEMP_OVERFLOW_CHECK */
    105 
    106 /* No sanity checks
    107  * We don't need to preserve the struct memp while not allocated, so we
    108  * can save a little space and set MEMP_SIZE to 0.
    109  */
    110 #define MEMP_SIZE           0
    111 #define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
    112 
    113 #endif /* MEMP_OVERFLOW_CHECK */
    114 
    115 /** This array holds the first free element of each pool.
    116  *  Elements form a linked list. */
    117 static struct memp *memp_tab[MEMP_MAX];
    118 
    119 #else /* MEMP_MEM_MALLOC */
    120 
    121 #define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
    122 
    123 #endif /* MEMP_MEM_MALLOC */
    124 
    125 /** This array holds the element sizes of each pool. */
    126 #if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
    127 static
    128 #endif
    129 const u16_t memp_sizes[MEMP_MAX] = {
    130 #define LWIP_MEMPOOL(name,num,size,desc)  LWIP_MEM_ALIGN_SIZE(size),
    131 #include "lwip/memp_std.h"
    132 };
    133 
    134 #if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
    135 
    136 /** This array holds the number of elements in each pool. */
    137 static const u16_t memp_num[MEMP_MAX] = {
    138 #define LWIP_MEMPOOL(name,num,size,desc)  (num),
    139 #include "lwip/memp_std.h"
    140 };
    141 
    142 /** This array holds a textual description of each pool. */
    143 #ifdef LWIP_DEBUG
    144 static const char *memp_desc[MEMP_MAX] = {
    145 #define LWIP_MEMPOOL(name,num,size,desc)  (desc),
    146 #include "lwip/memp_std.h"
    147 };
    148 #endif /* LWIP_DEBUG */
    149 
    150 #if MEMP_SEPARATE_POOLS
    151 
    152 /** This creates each memory pool. These are named memp_memory_XXX_base (where
    153  * XXX is the name of the pool defined in memp_std.h).
    154  * To relocate a pool, declare it as extern in cc.h. Example for GCC:
    155  *   extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_UDP_PCB_base[];
    156  */
    157 #define LWIP_MEMPOOL(name,num,size,desc) u8_t memp_memory_ ## name ## _base \
    158   [((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))];
    159 #include "lwip/memp_std.h"
    160 
    161 /** This array holds the base of each memory pool. */
    162 static u8_t *const memp_bases[] = {
    163 #define LWIP_MEMPOOL(name,num,size,desc) memp_memory_ ## name ## _base,
    164 #include "lwip/memp_std.h"
    165 };
    166 
    167 #else /* MEMP_SEPARATE_POOLS */
    168 
    169 /** This is the actual memory used by the pools (all pools in one big block). */
    170 static u8_t memp_memory[MEM_ALIGNMENT - 1
    171 #define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
    172 #include "lwip/memp_std.h"
    173 ];
    174 
    175 #endif /* MEMP_SEPARATE_POOLS */
    176 
    177 #if MEMP_SANITY_CHECK
    178 /**
    179  * Check that memp-lists don't form a circle
    180  */
    181 static int
    182 memp_sanity(void)
    183 {
    184   s16_t i, c;
    185   struct memp *m, *n;
    186 
    187   for (i = 0; i < MEMP_MAX; i++) {
    188     for (m = memp_tab[i]; m != NULL; m = m->next) {
    189       c = 1;
    190       for (n = memp_tab[i]; n != NULL; n = n->next) {
    191         if (n == m && --c < 0) {
    192           return 0;
    193         }
    194       }
    195     }
    196   }
    197   return 1;
    198 }
    199 #endif /* MEMP_SANITY_CHECK*/
    200 #if MEMP_OVERFLOW_CHECK
    201 #if defined(LWIP_DEBUG) && MEMP_STATS
    202 static const char * memp_overflow_names[] = {
    203 #define LWIP_MEMPOOL(name,num,size,desc) "/"desc,
    204 #include "lwip/memp_std.h"
    205   };
    206 #endif
    207 
    208 /**
    209  * Check if a memp element was victim of an overflow
    210  * (e.g. the restricted area after it has been altered)
    211  *
    212  * @param p the memp element to check
    213  * @param memp_type the pool p comes from
    214  */
    215 static void
    216 memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type)
    217 {
    218   u16_t k;
    219   u8_t *m;
    220 #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
    221   m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type];
    222   for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
    223     if (m[k] != 0xcd) {
    224       char errstr[128] = "detected memp overflow in pool ";
    225       char digit[] = "0";
    226       if(memp_type >= 10) {
    227         digit[0] = '0' + (memp_type/10);
    228         strcat(errstr, digit);
    229       }
    230       digit[0] = '0' + (memp_type%10);
    231       strcat(errstr, digit);
    232 #if defined(LWIP_DEBUG) && MEMP_STATS
    233       strcat(errstr, memp_overflow_names[memp_type]);
    234 #endif
    235       LWIP_ASSERT(errstr, 0);
    236     }
    237   }
    238 #endif
    239 }
    240 
    241 /**
    242  * Check if a memp element was victim of an underflow
    243  * (e.g. the restricted area before it has been altered)
    244  *
    245  * @param p the memp element to check
    246  * @param memp_type the pool p comes from
    247  */
    248 static void
    249 memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type)
    250 {
    251   u16_t k;
    252   u8_t *m;
    253 #if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
    254   m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
    255   for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {
    256     if (m[k] != 0xcd) {
    257       char errstr[128] = "detected memp underflow in pool ";
    258       char digit[] = "0";
    259       if(memp_type >= 10) {
    260         digit[0] = '0' + (memp_type/10);
    261         strcat(errstr, digit);
    262       }
    263       digit[0] = '0' + (memp_type%10);
    264       strcat(errstr, digit);
    265 #if defined(LWIP_DEBUG) && MEMP_STATS
    266       strcat(errstr, memp_overflow_names[memp_type]);
    267 #endif
    268       LWIP_ASSERT(errstr, 0);
    269     }
    270   }
    271 #endif
    272 }
    273 
    274 /**
    275  * Do an overflow check for all elements in every pool.
    276  *
    277  * @see memp_overflow_check_element for a description of the check
    278  */
    279 static void
    280 memp_overflow_check_all(void)
    281 {
    282   u16_t i, j;
    283   struct memp *p;
    284 
    285   p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
    286   for (i = 0; i < MEMP_MAX; ++i) {
    287     p = p;
    288     for (j = 0; j < memp_num[i]; ++j) {
    289       memp_overflow_check_element_overflow(p, i);
    290       p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
    291     }
    292   }
    293   p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
    294   for (i = 0; i < MEMP_MAX; ++i) {
    295     p = p;
    296     for (j = 0; j < memp_num[i]; ++j) {
    297       memp_overflow_check_element_underflow(p, i);
    298       p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
    299     }
    300   }
    301 }
    302 
    303 /**
    304  * Initialize the restricted areas of all memp elements in every pool.
    305  */
    306 static void
    307 memp_overflow_init(void)
    308 {
    309   u16_t i, j;
    310   struct memp *p;
    311   u8_t *m;
    312 
    313   p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
    314   for (i = 0; i < MEMP_MAX; ++i) {
    315     p = p;
    316     for (j = 0; j < memp_num[i]; ++j) {
    317 #if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
    318       m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
    319       memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);
    320 #endif
    321 #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
    322       m = (u8_t*)p + MEMP_SIZE + memp_sizes[i];
    323       memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
    324 #endif
    325       p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
    326     }
    327   }
    328 }
    329 #endif /* MEMP_OVERFLOW_CHECK */
    330 
    331 /**
    332  * Initialize this module.
    333  *
    334  * Carves out memp_memory into linked lists for each pool-type.
    335  */
    336 void
    337 memp_init(void)
    338 {
    339   struct memp *memp;
    340   u16_t i, j;
    341 
    342   for (i = 0; i < MEMP_MAX; ++i) {
    343     MEMP_STATS_AVAIL(used, i, 0);
    344     MEMP_STATS_AVAIL(max, i, 0);
    345     MEMP_STATS_AVAIL(err, i, 0);
    346     MEMP_STATS_AVAIL(avail, i, memp_num[i]);
    347   }
    348 
    349 #if !MEMP_SEPARATE_POOLS
    350   memp = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
    351 #endif /* !MEMP_SEPARATE_POOLS */
    352   /* for every pool: */
    353   for (i = 0; i < MEMP_MAX; ++i) {
    354     memp_tab[i] = NULL;
    355 #if MEMP_SEPARATE_POOLS
    356     memp = (struct memp*)memp_bases[i];
    357 #endif /* MEMP_SEPARATE_POOLS */
    358     /* create a linked list of memp elements */
    359     for (j = 0; j < memp_num[i]; ++j) {
    360       memp->next = memp_tab[i];
    361       memp_tab[i] = memp;
    362       memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]
    363 #if MEMP_OVERFLOW_CHECK
    364         + MEMP_SANITY_REGION_AFTER_ALIGNED
    365 #endif
    366       );
    367     }
    368   }
    369 #if MEMP_OVERFLOW_CHECK
    370   memp_overflow_init();
    371   /* check everything a first time to see if it worked */
    372   memp_overflow_check_all();
    373 #endif /* MEMP_OVERFLOW_CHECK */
    374 }
    375 
    376 /**
    377  * Get an element from a specific pool.
    378  *
    379  * @param type the pool to get an element from
    380  *
    381  * the debug version has two more parameters:
    382  * @param file file name calling this function
    383  * @param line number of line where this function is called
    384  *
    385  * @return a pointer to the allocated memory or a NULL pointer on error
    386  */
    387 void *
    388 #if !MEMP_OVERFLOW_CHECK
    389 memp_malloc(memp_t type)
    390 #else
    391 memp_malloc_fn(memp_t type, const char* file, const int line)
    392 #endif
    393 {
    394   struct memp *memp;
    395   SYS_ARCH_DECL_PROTECT(old_level);
    396 
    397   LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);
    398 
    399   SYS_ARCH_PROTECT(old_level);
    400 #if MEMP_OVERFLOW_CHECK >= 2
    401   memp_overflow_check_all();
    402 #endif /* MEMP_OVERFLOW_CHECK >= 2 */
    403 
    404   memp = memp_tab[type];
    405 
    406   if (memp != NULL) {
    407     memp_tab[type] = memp->next;
    408 #if MEMP_OVERFLOW_CHECK
    409     memp->next = NULL;
    410     memp->file = file;
    411     memp->line = line;
    412 #endif /* MEMP_OVERFLOW_CHECK */
    413     MEMP_STATS_INC_USED(used, type);
    414     LWIP_ASSERT("memp_malloc: memp properly aligned",
    415                 ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
    416     memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE);
    417   } else {
    418     LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
    419     MEMP_STATS_INC(err, type);
    420   }
    421 
    422   SYS_ARCH_UNPROTECT(old_level);
    423 
    424   return memp;
    425 }
    426 
    427 /**
    428  * Put an element back into its pool.
    429  *
    430  * @param type the pool where to put mem
    431  * @param mem the memp element to free
    432  */
    433 void
    434 memp_free(memp_t type, void *mem)
    435 {
    436   struct memp *memp;
    437   SYS_ARCH_DECL_PROTECT(old_level);
    438 
    439   if (mem == NULL) {
    440     return;
    441   }
    442   LWIP_ASSERT("memp_free: mem properly aligned",
    443                 ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);
    444 
    445   memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE);
    446 
    447   SYS_ARCH_PROTECT(old_level);
    448 #if MEMP_OVERFLOW_CHECK
    449 #if MEMP_OVERFLOW_CHECK >= 2
    450   memp_overflow_check_all();
    451 #else
    452   memp_overflow_check_element_overflow(memp, type);
    453   memp_overflow_check_element_underflow(memp, type);
    454 #endif /* MEMP_OVERFLOW_CHECK >= 2 */
    455 #endif /* MEMP_OVERFLOW_CHECK */
    456 
    457   MEMP_STATS_DEC(used, type);
    458 
    459   memp->next = memp_tab[type];
    460   memp_tab[type] = memp;
    461 
    462 #if MEMP_SANITY_CHECK
    463   LWIP_ASSERT("memp sanity", memp_sanity());
    464 #endif /* MEMP_SANITY_CHECK */
    465 
    466   SYS_ARCH_UNPROTECT(old_level);
    467 }
    468 
    469 #endif /* MEMP_MEM_MALLOC */
    470