⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pbuf.c

📁 最新rtlinux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/** * @file * Packet buffer management * * Packets are represented by the pbuf data structure. It supports dynamic * memory allocation for packet contents or can reference externally * managed packet contents both in RAM and ROM. Quick allocation for * incoming packets is provided through pools with fixed sized pbufs. * * Pbufs can be chained as a singly linked list, called a pbuf chain, so * that a packet may span over several pbufs. * *//* * Copyright (c) 2001-2003 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. * * This file is part of the lwIP TCP/IP stack. *  * Author: Adam Dunkels <adam@sics.se> * * CHANGELOG: this file has been modified by Sergio Perez Alca駃z <serpeal@upvnet.upv.es>  *            Departamento de Inform醫ica de Sistemas y Computadores           *            Universidad Polit閏nica de Valencia                              *            Valencia (Spain)     *            Date: April 2003                                           *   */#include "lwip/opt.h"#include "lwip/stats.h"#include "lwip/def.h"#include "lwip/mem.h"#include "lwip/memp.h"#include "lwip/pbuf.h"#include "lwip/sys.h"static u8_t pbuf_pool_memory[(PBUF_POOL_SIZE * MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE + sizeof(struct pbuf)))];#if !SYS_LIGHTWEIGHT_PROTstatic volatile u8_t pbuf_pool_free_lock, pbuf_pool_alloc_lock;static sys_sem_t pbuf_pool_free_sem;#endifstatic struct pbuf *pbuf_pool = NULL;static struct pbuf *pbuf_pool_alloc_cache = NULL;static struct pbuf *pbuf_pool_free_cache = NULL;/** * Initializes the pbuf module. * * A large part of memory is allocated for holding the pool of pbufs. * The size of the individual pbufs in the pool is given by the size * parameter, and the number of pbufs in the pool by the num parameter. * * After the memory has been allocated, the pbufs are set up. The * ->next pointer in each pbuf is set up to point to the next pbuf in * the pool. * */voidpbuf_init(void){  struct pbuf *p, *q = NULL;  u16_t i;  pbuf_pool = (struct pbuf *)&pbuf_pool_memory[0];  LWIP_ASSERT("pbuf_init: pool aligned", (long)pbuf_pool % MEM_ALIGNMENT == 0);   #ifdef PBUF_STATS  lwip_stats.pbuf.avail = PBUF_POOL_SIZE;#endif /* PBUF_STATS */    /* Set up ->next pointers to link the pbufs of the pool together */  p = pbuf_pool;    for(i = 0; i < PBUF_POOL_SIZE; ++i) {    p->next = (struct pbuf *)((u8_t *)p + PBUF_POOL_BUFSIZE + sizeof(struct pbuf));    p->len = p->tot_len = PBUF_POOL_BUFSIZE;    p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf)));    q = p;    p = p->next;  }    /* The ->next pointer of last pbuf is NULL to indicate that there     are no more pbufs in the pool */  q->next = NULL;#if !SYS_LIGHTWEIGHT_PROT    pbuf_pool_alloc_lock = 0;  pbuf_pool_free_lock = 0;  pbuf_pool_free_sem = sys_sem_new(1);#endif  }/** * @internal only called from pbuf_alloc() */static struct pbuf *pbuf_pool_alloc(void){  struct pbuf *p = NULL;  unsigned int state;  sys_stop_interrupts(&state);  /* First, see if there are pbufs in the cache. */  if(pbuf_pool_alloc_cache) {    p = pbuf_pool_alloc_cache;    if(p) {      pbuf_pool_alloc_cache = p->next;     }  } else {#if !SYS_LIGHTWEIGHT_PROT          /* Next, check the actual pbuf pool, but if the pool is locked, we       pretend to be out of buffers and return NULL. */    if(pbuf_pool_free_lock) {#ifdef PBUF_STATS      ++lwip_stats.pbuf.alloc_locked;#endif /* PBUF_STATS */      return NULL;    }    pbuf_pool_alloc_lock = 1;    if(!pbuf_pool_free_lock) {#endif /* SYS_LIGHTWEIGHT_PROT */              p = pbuf_pool;      if(p) {	pbuf_pool = p->next;       }#if !SYS_LIGHTWEIGHT_PROT      #ifdef PBUF_STATS    } else {      ++lwip_stats.pbuf.alloc_locked;#endif /* PBUF_STATS */    }    pbuf_pool_alloc_lock = 0;#endif /* SYS_LIGHTWEIGHT_PROT */      }  #ifdef PBUF_STATS  if(p != NULL) {        ++lwip_stats.pbuf.used;    if(lwip_stats.pbuf.used > lwip_stats.pbuf.max) {      lwip_stats.pbuf.max = lwip_stats.pbuf.used;    }  }#endif /* PBUF_STATS */  sys_allow_interrupts(&state);  return p;   }/** * @internal only called from pbuf_alloc() */static voidpbuf_pool_free(struct pbuf *p){  struct pbuf *q;  unsigned int state;  sys_stop_interrupts(&state);#ifdef PBUF_STATS    for(q = p; q != NULL; q = q->next) {      --lwip_stats.pbuf.used;    }#endif /* PBUF_STATS */  if(pbuf_pool_alloc_cache == NULL) {    pbuf_pool_alloc_cache = p;  } else {      for(q = pbuf_pool_alloc_cache; q->next != NULL; q = q->next);    q->next = p;      }  sys_allow_interrupts(&state);}/** * Allocates a pbuf. * * The actual memory allocated for the pbuf is determined by the * layer at which the pbuf is allocated and the requested size * (from the size parameter). * * @param flag this parameter decides how and where the pbuf * should be allocated as follows: *  * - PBUF_RAM: buffer memory for pbuf is allocated as one large *             chunk. This includes protocol headers as well.  * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for *             protocol headers. Additional headers must be prepended *             by allocating another pbuf and chain in to the front of *             the ROM pbuf. It is assumed that the memory used is really *             similar to ROM in that it is immutable and will not be *             changed. Memory which is dynamic should generally not *             be attached to PBUF_ROM pbufs. Use PBUF_REF instead. * - PBUF_REF: no buffer memory is allocated for the pbuf, even for *             protocol headers. It is assumed that the pbuf is only *             being used in a single thread. If the pbuf gets queued, *             then pbuf_take should be called to copy the buffer. * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from *              the pbuf pool that is allocated during pbuf_init(). * * @return the allocated pbuf. If multiple pbufs where allocated, this * is the first pbuf of a pbuf chain.  */struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag){  struct pbuf *p, *q, *r;  u16_t offset;  s32_t rem_len; /* remaining length */  /* determine header offset */  offset = 0;  switch (l) {  case PBUF_TRANSPORT:    /* add room for transport (often TCP) layer header */    offset += PBUF_TRANSPORT_HLEN;    /* FALLTHROUGH */  case PBUF_IP:    /* add room for IP layer header */    offset += PBUF_IP_HLEN;    /* FALLTHROUGH */  case PBUF_LINK:    /* add room for link layer header */    offset += PBUF_LINK_HLEN;    break;  case PBUF_RAW:    break;  default:    LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);    return NULL;  }  switch (flag) {  case PBUF_POOL:    /* allocate head of pbuf chain into p */    p = pbuf_pool_alloc();    if (p == NULL) {#ifdef PBUF_STATS      ++lwip_stats.pbuf.err;#endif /* PBUF_STATS */      return NULL;    }    p->next = NULL;        /* make the payload pointer point 'offset' bytes into pbuf data memory */    p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset)));    LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",	    ((u32_t)p->payload % MEM_ALIGNMENT) == 0);    /* the total length of the pbuf chain is the requested size */    p->tot_len = length;    /* set the length of the first pbuf in the chain */    p->len = length > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: length;    /* set pbuf type */    p->flags = PBUF_FLAG_POOL;        /* now allocate the tail of the pbuf chain */        /* remember first pbuf for linkage in next iteration */    r = p;    /* remaining length to be allocated */    rem_len = length - p->len;    /* any remaining pbufs to be allocated? */    while(rem_len > 0) {            q = pbuf_pool_alloc();      if (q == NULL) {       DEBUGF(PBUF_DEBUG | 2, ("pbuf_alloc: Out of pbufs in pool.\n"));#ifdef PBUF_STATS        ++lwip_stats.pbuf.err;#endif /* PBUF_STATS */        /* bail out unsuccesfully */        pbuf_pool_free(p);        return NULL;      }      //q->next = NULL;      /* make previous pbuf point to this pbuf */      r->next = q;      /* set length of this pbuf */      q->len = rem_len > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rem_len;      q->flags = PBUF_FLAG_POOL;      q->payload = (void *)((u8_t *)q + sizeof(struct pbuf));      LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",	      ((u32_t)q->payload % MEM_ALIGNMENT) == 0);      q->ref = 1;      /* calculate remaining length to be allocated */      rem_len -= q->len;      /* remember this pbuf for linkage in next iteration */      r = q;    }    /* end of chain */    r->next = NULL;    break;  case PBUF_RAM:    /* If pbuf is to be allocated in RAM, allocate memory for it. */    p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + length + offset));    if (p == NULL) {      return NULL;    }    /* Set up internal structure of the pbuf. */    p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf) + offset));    p->len = p->tot_len = length;    p->next = NULL;    p->flags = PBUF_FLAG_RAM;    LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",	   ((u32_t)p->payload % MEM_ALIGNMENT) == 0);    break;  /* pbuf references existing (static constant) ROM payload? */  case PBUF_ROM:  /* pbuf references existing (externally allocated) RAM payload? */  case PBUF_REF:    /* only allocate memory for the pbuf structure */    p = memp_mallocp(MEMP_PBUF);    if (p == NULL) {      DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_REF.\n"));      return NULL;    }    /* caller must set this field properly, afterwards */    p->payload = NULL;    p->len = p->tot_len = length;    p->next = NULL;    p->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF);    break;  default:    LWIP_ASSERT("pbuf_alloc: erroneous flag", 0);    return NULL;  }  p->ref = 1;  return p;}/** * * Moves free buffers from the pbuf_pool_free_cache to the pbuf_pool * list (if possible). * */voidpbuf_refresh(void){  struct pbuf *p;  unsigned int state;  sys_stop_interrupts(&state); #if !SYS_LIGHTWEIGHT_PROT  sys_sem_wait(pbuf_pool_free_sem);#endif /* else SYS_LIGHTWEIGHT_PROT */    if(pbuf_pool_free_cache != NULL) {#if !SYS_LIGHTWEIGHT_PROT          pbuf_pool_free_lock = 1;    if(!pbuf_pool_alloc_lock) {#endif /* SYS_LIGHTWEIGHT_PROT */      if(pbuf_pool == NULL) {	pbuf_pool = pbuf_pool_free_cache;	      } else {  	for(p = pbuf_pool; p->next != NULL; p = p->next);	p->next = pbuf_pool_free_cache;         }      pbuf_pool_free_cache = NULL;#if !SYS_LIGHTWEIGHT_PROT      #ifdef PBUF_STATS    } else {      ++lwip_stats.pbuf.refresh_locked;#endif /* PBUF_STATS */    }        pbuf_pool_free_lock = 0;#endif /* SYS_LIGHTWEIGHT_PROT */      }  sys_allow_interrupts(&state);#if !SYS_LIGHTWEIGHT_PROT        sys_sem_signal(pbuf_pool_free_sem);#endif /* SYS_LIGHTWEIGHT_PROT */  }#ifdef PBUF_STATS#define DEC_PBUF_STATS do { --lwip_stats.pbuf.used; } while (0)#else /* PBUF_STATS */#define DEC_PBUF_STATS#endif /* PBUF_STATS */#define PBUF_POOL_FAST_FREE(p)  do {                                    \                                  p->next = pbuf_pool_free_cache;       \                                  pbuf_pool_free_cache = p;             \                                  DEC_PBUF_STATS;                       \                                } while (0)#if SYS_LIGHTWEIGHT_PROT#define PBUF_POOL_FREE(p)  do {                                         \                                unsigned int state;                     \                                sys_stop_interrupts(&state);            \                                PBUF_POOL_FAST_FREE(p);                 \                                sys_allow_interrupts(&state)            \                               } while(0)#else /* SYS_LIGHTWEIGHT_PROT */#define PBUF_POOL_FREE(p)  do {                                         \                             sys_sem_wait(pbuf_pool_free_sem);          \                             PBUF_POOL_FAST_FREE(p);                    \                             sys_sem_signal(pbuf_pool_free_sem);        \                           } while(0)#endif /* SYS_LIGHTWEIGHT_PROT *//** * Shrink a pbuf chain to a desired length. * * @param p pbuf to shrink. * @param new_len desired new length of pbuf chain * * Depending on the desired length, the first few pbufs in a chain might * be skipped and left unchanged. The new last pbuf in the chain will be * resized, and any remaining pbufs will be freed. *  * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -