LwIP之数据包管理

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lushoumin/article/details/100004204

先看一下数据包结构体pbuf

/* 数据包结构体 */
struct pbuf {
  struct pbuf *next;		/* 下一个pbuf指针 */
  void *payload;                /* pbuf数据指针 */
  u16_t tot_len;                /* 当前和后面pbuf数据总长度 */
  u16_t len;		        /* 当前pbuf数据长度 */
  u8_t type_internal;		/* 类型 */
  u8_t flags;		        /* 标志位 */
  LWIP_PBUF_REF_T ref;		/* 被引用次数 */
  u8_t if_idx;		        /* 网卡索引 */
};

pbuf中有个成员type_internal,表示pbuf的类型。pbuf共有四种类型PBUF_REF、PBUF_ROM、PBUF_POOL和PBUF_RAM。

PBUF_REF:pbuf结构体由内存池分配,数据区在RAM中

PBUF_ROM:pbuf结构体由内存池分配,数据区在ROM中

PBUF_POOL:pbuf结构体和数据区都由内存池分配,数据区紧接着pbuf

PBUF_RAM:pbuf结构体和数据区都由内存堆分配,数据区紧接着pbuf

其中,系统在初始化内存池的时候,会初始化PBUF和PBUF_POOL两种内存池。PBUF内存池用于PBUF_REF和PBUF_ROM,PBUF_POOL内存池用于PBUF_POOL。PBUF_POOL内存池单元大小,为pbuf结构体大小+最大的TCB数据大小。

/* pbuf类型 */
typedef enum {
  PBUF_RAM = (PBUF_ALLOC_FLAG_DATA_CONTIGUOUS | PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS | PBUF_TYPE_ALLOC_SRC_MASK_STD_HEAP),
  PBUF_ROM = PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF,
  PBUF_REF = (PBUF_TYPE_FLAG_DATA_VOLATILE | PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF),
  PBUF_POOL = (PBUF_ALLOC_FLAG_RX | PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS | PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF_POOL)
} pbuf_type;

 

先看一下分配函数

/* 申请pbuf */
struct pbuf *pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)

其中pbuf_layer表示层类型,上层数据包需要为下层预留足够空间用来填充头部

/* pbuf层 */
typedef enum {
  /* 传输层 */
  PBUF_TRANSPORT = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN,
  /* 网络层 */
  PBUF_IP = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN,
  /* 链路层 */
  PBUF_LINK = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN,
  /* 原始层输出 */
  PBUF_RAW_TX = PBUF_LINK_ENCAPSULATION_HLEN,
  /* 原始层输入 */
  PBUF_RAW = 0
} pbuf_layer;

下面就一个一个类型来分析pbuf分配,先看PBUF_REF和PBUF_ROM

/* 申请pbuf */
struct pbuf *pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
{
  struct pbuf *p;
  u16_t offset = (u16_t)layer;

  /* 判断pbuf类型 */
  switch (type) 
  {
    /* PBUF_REF和PBUF_ROM */
    case PBUF_REF:
    case PBUF_ROM:
      /* 申请pbuf结构体,数据区为空 */
      p = pbuf_alloc_reference(NULL, length, type);
      break;

  }

  return p;
}
/* 为PBUF_REF和PBUF_ROM申请pbuf结构体 */
struct pbuf *pbuf_alloc_reference(void *payload, u16_t length, pbuf_type type)
{
  struct pbuf *p;
  
  /* 从内存池中分配pbuf结构体 */
  p = (struct pbuf *)memp_malloc(MEMP_PBUF);
  if (p == NULL) 
  {
    return NULL;
  }

  /* 初始化pbuf成员 */
  pbuf_init_alloced_pbuf(p, payload, length, length, type, 0);
  
  return p;
}
/* 初始化pbuf成员 */
static void pbuf_init_alloced_pbuf(struct pbuf *p, void *payload, u16_t tot_len, u16_t len, pbuf_type type, u8_t flags)
{
  p->next = NULL;
  p->payload = payload;
  p->tot_len = tot_len;
  p->len = len;
  p->type_internal = (u8_t)type;
  p->flags = flags;
  p->ref = 1;
  p->if_idx = NETIF_NO_INDEX;
}

再看PBUF_POOL

/* 申请pbuf */
struct pbuf *pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
{
  struct pbuf *p;
  u16_t offset = (u16_t)layer;

  /* 判断pbuf类型 */
  switch (type) 
  {
	/* PBUF_POOL */
    case PBUF_POOL: 
    {
      struct pbuf *q, *last;
      u16_t rem_len;
      p = NULL;
      last = NULL;
      rem_len = length;
      
      do
      {
        u16_t qlen;

        /* 从内存池中分配一个单元 */
        q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
        if (q == NULL)  {
          PBUF_POOL_IS_EMPTY();
          if (p) {
            pbuf_free(p);
          }
          return NULL;
        }

        /* 初始化pbuf成员 */
        qlen = LWIP_MIN(rem_len, (u16_t)(PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)));
        pbuf_init_alloced_pbuf(q, LWIP_MEM_ALIGN((void *)((u8_t *)q + SIZEOF_STRUCT_PBUF + offset)),
                               rem_len, qlen, type, 0);

        /* 第一个pbuf */
        if (p == NULL) {
          p = q;
        } 
		/* 不是第一个pbuf,需要挂接到pbuf链表中 */
        else {
          last->next = q;
        }
        last = q;

        /* 当前及往后数据区大小 */
        rem_len = (u16_t)(rem_len - qlen);

        /* 预留头部清空 */
        offset = 0;
      } while (rem_len > 0);
      break;
    }
  }

  return p;
}

最后看PBUF_RAM

/* 申请pbuf */
struct pbuf *pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
{
  struct pbuf *p;
  u16_t offset = (u16_t)layer;

  /* 判断pbuf类型 */
  switch (type) 
  {
    case PBUF_RAM: 
    {
      /* 计算pbuf结构体和数据区加起来大小 */
      u16_t payload_len = (u16_t)(LWIP_MEM_ALIGN_SIZE(offset) + LWIP_MEM_ALIGN_SIZE(length));
      mem_size_t alloc_len = (mem_size_t)(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF) + payload_len);

      if ((payload_len < LWIP_MEM_ALIGN_SIZE(length)) ||
          (alloc_len < LWIP_MEM_ALIGN_SIZE(length))) {
        return NULL;
      }

      /* 从内存堆中分配空间 */
      p = (struct pbuf *)mem_malloc(alloc_len);
      if (p == NULL) {
        return NULL;
      }

      /* 初始化pbuf结构体,数据区紧跟pbuf */
      pbuf_init_alloced_pbuf(p, LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)),
                             length, length, type, 0);
      break;
    }
  }

  return p;
}

 

下面看一下pbuf释放,当没有任何对象引用该pbuf的时候才能释放,否则引用次数减一。

/* pbuf释放 */
u8_t pbuf_free(struct pbuf *p)
{
  u8_t alloc_src;
  struct pbuf *q;
  u8_t count;

  if (p == NULL) {
    LWIP_ASSERT("p != NULL", p != NULL);
    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
                ("pbuf_free(p == NULL) was called.\n"));
    return 0;
  }
  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p));

  PERF_START;

  count = 0;
  
  while (p != NULL) {
    LWIP_PBUF_REF_T ref;
    SYS_ARCH_DECL_PROTECT(old_level);
    SYS_ARCH_PROTECT(old_level);
    LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);

    /* 引用次数减1 */
    ref = --(p->ref);
    SYS_ARCH_UNPROTECT(old_level);
    /* 没有任何对象引用该pbuf */
    if (ref == 0) {
      /* 保存下一个pbuf指针 */
      q = p->next;
      
      LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
      
      /* 获取数据区类型 */
      alloc_src = pbuf_get_allocsrc(p);
      
#if LWIP_SUPPORT_CUSTOM_PBUF
      if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) {
        struct pbuf_custom *pc = (struct pbuf_custom *)p;
        LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL);
        pc->custom_free_function(p);
      } else
#endif
      {
        /* PBUF_POOL */
        if (alloc_src == PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF_POOL) {
          memp_free(MEMP_PBUF_POOL, p);
          /* PBUF_REF和PBUF_ROM */
        } else if (alloc_src == PBUF_TYPE_ALLOC_SRC_MASK_STD_MEMP_PBUF) {
          memp_free(MEMP_PBUF, p);
          /* PBUF_RAM */
        } else if (alloc_src == PBUF_TYPE_ALLOC_SRC_MASK_STD_HEAP) {
          mem_free(p);
        } else {
          LWIP_ASSERT("invalid pbuf type", 0);
        }
      }
      /* 释放个数 */
      count++;

	  /* 指向下一个pbuf */
      p = q;
    } 
    /* 被其它对象引用,不能释放 */
    else {
      LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, (u16_t)ref));
      p = NULL;
    }
  }
  PERF_STOP("pbuf_free");

  return count;
}

 

 

其它,lwip还提供了其它很多的API

收缩数据区函数,从数据区尾部进行释放

/* 收缩数据区 */
void pbuf_realloc(struct pbuf *p, u16_t new_len)
{
  struct pbuf *q;
  u16_t rem_len; /* remaining length */
  u16_t shrink;

  LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);

  /* 新的数据区大小,不能大于原来的大小 */
  if (new_len >= p->tot_len) {
    return;
  }

  /* 需要切割的大小 */
  shrink = (u16_t)(p->tot_len - new_len);

  /* 更新tot_len变量,并且找出需要切割的pbuf */
  rem_len = new_len;
  q = p;
  while (rem_len > q->len) {
    rem_len = (u16_t)(rem_len - q->len);
    q->tot_len = (u16_t)(q->tot_len - shrink);
    q = q->next;
    LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
  }

  /* PBUF_RAM类型,需要调整最后一个pbuf的数据区 */
  if (pbuf_match_allocsrc(q, PBUF_TYPE_ALLOC_SRC_MASK_STD_HEAP) && (rem_len != q->len)
#if LWIP_SUPPORT_CUSTOM_PBUF
      && ((q->flags & PBUF_FLAG_IS_CUSTOM) == 0)
#endif
     ) {
    q = (struct pbuf *)mem_trim(q, (mem_size_t)(((u8_t *)q->payload - (u8_t *)q) + rem_len));
    LWIP_ASSERT("mem_trim returned q == NULL", q != NULL);
  }
  q->len = rem_len;
  q->tot_len = q->len;

  /* 后面多余的pbuf全部释放 */
  if (q->next != NULL) {
    pbuf_free(q->next);
  }
  
  q->next = NULL;

}

 

调整头部pbuf有效数据指针

/* 调整头部pbuf有效数据指针 */
u8_t pbuf_header(struct pbuf *p, s16_t header_size_increment)
{
  return pbuf_header_impl(p, header_size_increment, 0);
}

/* 强制调整头部pbuf有效数据指针 */
u8_t pbuf_header_force(struct pbuf *p, s16_t header_size_increment)
{
  return pbuf_header_impl(p, header_size_increment, 1);
}

/* 向前偏移头部pbuf有效数据指针 */
u8_t pbuf_add_header(struct pbuf *p, size_t header_size_increment)
{
  return pbuf_add_header_impl(p, header_size_increment, 0);
}

/* 强制向前偏移头部pbuf有效数据指针 */
u8_t pbuf_add_header_force(struct pbuf *p, size_t header_size_increment)
{
  return pbuf_add_header_impl(p, header_size_increment, 1);
}

/* 调整头部pbuf有效数据指针,header_size_increment为正向前,header_size_increment为负向后 */
static u8_t pbuf_header_impl(struct pbuf *p, s16_t header_size_increment, u8_t force)
{
  if (header_size_increment < 0) {
    return pbuf_remove_header(p, (size_t) - header_size_increment);
  } else {
    return pbuf_add_header_impl(p, (size_t)header_size_increment, force);
  }
}

先看一下pbuf_remove_header函数

/* 向后偏移头部pbuf有效数据指针 */
u8_t pbuf_remove_header(struct pbuf *p, size_t header_size_decrement)
{
  void *payload;
  u16_t increment_magnitude;

  LWIP_ASSERT("p != NULL", p != NULL);
  if ((p == NULL) || (header_size_decrement > 0xFFFF)) {
    return 1;
  }
  if (header_size_decrement == 0) {
    return 0;
  }

  /* 偏移量大小 */
  increment_magnitude = (u16_t)header_size_decrement;

  LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);

  /* 有效数据指针 */
  payload = p->payload;
  LWIP_UNUSED_ARG(payload);

  /* 将有效数据指针向后偏移 */
  p->payload = (u8_t *)p->payload + header_size_decrement;

  /* 减小剩余pbuf数据大小 */
  p->len = (u16_t)(p->len - increment_magnitude);
  p->tot_len = (u16_t)(p->tot_len - increment_magnitude);

  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_remove_header: old %p new %p (%"U16_F")\n",
              (void *)payload, (void *)p->payload, increment_magnitude));

  return 0;
}

在看一下pbuf_add_header_impl函数

/* 强制向前偏移头部pbuf有效数据指针 */
static u8_t pbuf_add_header_impl(struct pbuf *p, size_t header_size_increment, u8_t force)
{
  u16_t type_internal;
  void *payload;
  u16_t increment_magnitude;

  LWIP_ASSERT("p != NULL", p != NULL);
  if ((p == NULL) || (header_size_increment > 0xFFFF)) {
    return 1;
  }
  if (header_size_increment == 0) {
    return 0;
  }

  /* 向前偏移量 */
  increment_magnitude = (u16_t)header_size_increment;
  if ((u16_t)(increment_magnitude + p->tot_len) < increment_magnitude) {
    return 1;
  }

  type_internal = p->type_internal;

  /* PBUF_RAM和PBUF_POOL */
  if (type_internal & PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS) {
    /* 有效数据指针向前偏移 */
    payload = (u8_t *)p->payload - header_size_increment;
    /* 检查pbuf预留的头部空间够不够偏移 */
    if ((u8_t *)payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {
      LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE,
                   ("pbuf_add_header: failed as %p < %p (not enough space for new header size)\n",
                    (void *)payload, (void *)((u8_t *)p + SIZEOF_STRUCT_PBUF)));
      return 1;
    }
  } 
  /* PBUF_REF和PBUF_ROM */
  else {
    /* 强制偏移 */
    if (force) {
      /* 有效数据指针向前偏移。因为不知道会不会溢出,因此这是非常危险的 */
      payload = (u8_t *)p->payload - header_size_increment;
    }
    /* 不强制偏移。返回错误 */
    else {
      return 1;
    }
  }
  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_add_header: old %p new %p (%"U16_F")\n",
              (void *)p->payload, (void *)payload, increment_magnitude));

  /* 更新pbuf有效数据指针和长度 */
  p->payload = payload;
  p->len = (u16_t)(p->len + increment_magnitude);
  p->tot_len = (u16_t)(p->tot_len + increment_magnitude);

  return 0;
}

 

释放头部,从头部进行释放

/* 从头部释放pbuf */
struct pbuf *pbuf_free_header(struct pbuf *q, u16_t size)
{
  struct pbuf *p = q;
  u16_t free_left = size;
  while (free_left && p) 
  {
	/* 请求释放的大小大于第一个pbuf */
    if (free_left >= p->len) 
    {
      struct pbuf *f = p;
      free_left = (u16_t)(free_left - p->len);
      p = p->next;
      f->next = 0;
      pbuf_free(f);
    } 
	/* 请求释放的大小小于第一个pbuf */
    else 
    {
      /* 向后偏移头部pbuf有效数据指针 */
      pbuf_remove_header(p, free_left);
      free_left = 0;
    }
  }
  return p;
}

 

引用次数加一

/* 引用次数加一 */
void pbuf_ref(struct pbuf *p)
{
  if (p != NULL) {
    SYS_ARCH_SET(p->ref, (LWIP_PBUF_REF_T)(p->ref + 1));
    LWIP_ASSERT("pbuf ref overflow", p->ref > 0);
  }
}

 

统计pbuf个数

/* 统计链表中有多少个pbuf */
u16_t pbuf_clen(const struct pbuf *p)
{
  u16_t len;

  len = 0;
  while (p != NULL)
  {
    ++len;
    p = p->next;
  }
  return len;
}

 

将两个pbuf链表拼接起来,pbuf_cat和pbuf_chain。

pbuf_cat,t原来的调用者不需要使用pbuf_free。

pbuf_chain,t原来的调用者需要使用pbuf_free。

/* 将两个pbuf拼接起来 */
void pbuf_cat(struct pbuf *h, struct pbuf *t)
{
  struct pbuf *p;

  LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)",
             ((h != NULL) && (t != NULL)), return;);

  /* 调整前一个链表中pbuf的tot_len值 */
  for (p = h; p->next != NULL; p = p->next) 
  {
    p->tot_len = (u16_t)(p->tot_len + t->tot_len);
  }

  LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
  LWIP_ASSERT("p->next == NULL", p->next == NULL);

  p->tot_len = (u16_t)(p->tot_len + t->tot_len);

  /* 将pbuf拼接起来 */
  p->next = t;
}
/* 将两个pbuf链表串接起来,并且后一个链表引用数加一 */
void pbuf_chain(struct pbuf *h, struct pbuf *t)
{
  pbuf_cat(h, t);
  pbuf_ref(t);
  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
}

 

解开pbuf

/* 将第一个pbuf和后面的链表解开 */
struct pbuf *pbuf_dechain(struct pbuf *p)
{
  struct pbuf *q;
  u8_t tail_gone = 1;

  q = p->next;
  
  /* 后面还有链 */
  if (q != NULL) 
  {
    LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);

	/* 更新后面的链 */
    q->tot_len = (u16_t)(p->tot_len - p->len);

    /* 更新第一个pbuf参数 */
    p->next = NULL;
    p->tot_len = p->len;
    
    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q));

	/* 解开后释放一次引用 */
    tail_gone = pbuf_free(q);
    if (tail_gone > 0) {
      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,
                  ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
    }
  }
  
  LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
  return ((tail_gone > 0) ? NULL : q);
}

 

 

展开阅读全文

没有更多推荐了,返回首页