LwIP之数据包管理

先看一下数据包结构体pbuf

/* pbuf结构体 */
struct pbuf {
  struct pbuf *next;	//用于将pbuf连接成链表
  void *payload;		//数据指针
  u16_t tot_len;		//当前以及后续所有pbuf包含的数据总长度
  u16_t len;  			//当前pbuf的数据长度
  u8_t type;			//pbuf类型
  u8_t flags;			//状态位
  u16_t ref;			//pbuf被引用的次数
};

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

/* pbuf类型 */
typedef enum {
  PBUF_RAM, 		/* pbuf和数据来自连续的内存堆 */
  PBUF_ROM, 		/* pbuf来自内存池MEMP_PBUF,数据来自ROM */
  PBUF_REF, 		/* pbuf来自内存池MEMP_PBUF,数据来自RAM */
  PBUF_POOL 		/* pbuf和数据来自一个或多个内存池MEMP_PBUF_POOL */
} pbuf_type;

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

/* pbuf分层类型 */
typedef enum {
  PBUF_TRANSPORT,	//传输层
  PBUF_IP,					//网络层
  PBUF_LINK,				//链路层
  PBUF_RAW				//原始层
} pbuf_layer;

下面看一下申请pbuf

/* 申请pbuf */
struct pbuf *pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
{
  struct pbuf *p, *q, *r;
  u16_t offset;
  s32_t rem_len;
  
  /* 根据pbuf所在层计算头部偏移量 */
  offset = 0;
  switch (layer) {
  case PBUF_TRANSPORT:
    offset += PBUF_TRANSPORT_HLEN;

  case PBUF_IP:
    offset += PBUF_IP_HLEN;

  case PBUF_LINK:
    offset += PBUF_LINK_HLEN;
    break;
    
  case PBUF_RAW:
    break;
    
  default:
    return NULL;
  }

  /* 判断pbuf类型 */
  switch (type) {
  /* PBUF_POOL类型 */
  case PBUF_POOL:
    /* 从内存池MEMP_PBUF_POOL申请第一个单元 */
    p = memp_malloc(MEMP_PBUF_POOL);
    if (p == NULL) {
      return NULL;
    }

    /* 填充pbuf成员 */
    p->type = type;
    p->next = NULL;
    p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));
    p->tot_len = length;
    p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset));
    p->ref = 1;

    /* 判断一个MEMP_PBUF_POOL单元够不够,如果不够则继续申请 */
    r = p;
    rem_len = length - p->len;
    while (rem_len > 0) {
      /* 从内存池MEMP_PBUF_POOL申请单元 */
      q = memp_malloc(MEMP_PBUF_POOL);
      if (q == NULL) {
        pbuf_free(p);
        return NULL;
      }

      /* 填充pbuf成员 */
      q->type = type;
      q->flags = 0;
      q->next = NULL;

      /* 将pbuf连接起来 */
      r->next = q;

      /* 继续填充pbuf成员 */
      q->tot_len = (u16_t)rem_len;
      q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);
      q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF);
      q->ref = 1;

      /* 更新剩余申请长度 */
      rem_len -= q->len;

      r = q;
    }
    break;

  /* PBUF_RAM类型 */
  case PBUF_RAM:
    /* 从内存堆申请pbuf和数据 */
    p = (struct pbuf *)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));
    if (p == NULL) {
      return NULL;
    }
    
    /* 填充pbuf成员 */
    p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset));
    p->len = p->tot_len = length;
    p->next = NULL;
    p->type = type;
    break;
    
  /* PBUF_ROM和PBUF_REF类型 */
  case PBUF_ROM:
  case PBUF_REF:
    /* 从内存堆申请pbuf */
    p = memp_malloc(MEMP_PBUF);
    if (p == NULL) {
      return NULL;
    }
    
    /* 填充pbuf成员 */
    p->payload = NULL;
    p->len = p->tot_len = length;
    p->next = NULL;
    p->type = type;
    break;
    
  default:
    return NULL;
  }

  /* 引用次数为1 */
  p->ref = 1;
  
  /* 状态为清空 */
  p->flags = 0;
  
  return p;
}

PBUF_RAM型

                                                  

PBUF_POOL型

          

PBUF_ROM/PBUF_REF型

                      

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

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

  if (p == NULL) {
    return 0;
  }

  /* 循环释放链表上的pbuf */
  count = 0;
  while (p != NULL) {
    u16_t ref;

	/* 引用次数减1 */
    ref = --(p->ref);

	/* 如果引用次数为0,则释放 */
    if (ref == 0) {
      /* 释放之前先找到下一个pbuf指针 */
      q = p->next;

      /* 根据pbuf类型,释放pbuf内存 */
      type = p->type;
      if (type == PBUF_POOL) {
        memp_free(MEMP_PBUF_POOL, p);
      } else if (type == PBUF_ROM || type == PBUF_REF) {
        memp_free(MEMP_PBUF, p);
      } else {
        mem_free(p);
      }

      /* 释放个数加1 */
      count++;
      
      /* 更新下一个pbuf指针到当前p */
      p = q;
    } 
	/* 引用次数不为0,则停止释放 */
    else {
      p = NULL;
    }
  }

  return count;
}

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

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

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

  /* 只能收缩不能扩展 */
  if (new_len >= p->tot_len) {
    return;
  }

  /* 数据扩展长度(负值) */
  grow = new_len - p->tot_len;

  /* 更新链表中每一个pbuf的tot_len变量,找出需要切割的第一个pbuf指针 */
  rem_len = new_len;
  q = p;
  while (rem_len > q->len) {
    rem_len -= q->len;
    q->tot_len += (u16_t)grow;
    q = q->next;
  }

  /* 当前pbuf类型为PBUF_RAM,并且该pbuf需要切割 */
  if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
    /* 当前pbuf收缩内存 */
    q = mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);
  }
  /* 调整当前pbuf数据长度和后续数据长度 */
  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)
{
  u16_t type;
  void *payload;
  u16_t increment_magnitude;

  if ((header_size_increment == 0) || (p == NULL))
    return 0;

  /* 调整长度 */
  if (header_size_increment < 0){
    increment_magnitude = -header_size_increment;
  } else {
    increment_magnitude = header_size_increment;
  }

  type = p->type;
  
  /* pbuf类型为PBUF_RAM和PBUF_POOL */
  payload = p->payload;
  if (type == PBUF_RAM || type == PBUF_POOL) {
    /* 调整pbuf有效数据指针 */
    p->payload = (u8_t *)p->payload - header_size_increment;
    /* 预留空间不够调整 */
    if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {
      p->payload = payload;
      return 1;
    }
  } 
  /* pbuf类型为PBUF_REF和PBUF_ROM */
  else if (type == PBUF_REF || type == PBUF_ROM) {
    /* 向后调整 */
    if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {
      p->payload = (u8_t *)p->payload - header_size_increment;
    }
    /* 不允许向前调整 */
    else {
      return 1;
    }
  }
  else {
    return 1;
  }
  
  /* 更新pbuf数据长度和pbuf链表数据总长度 */
  p->len += header_size_increment;
  p->tot_len += header_size_increment;

  return 0;
}

统计pbuf个数

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

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

引用次数加一

/* pbuf链表中第一个pbuf引用数加1 */
void pbuf_ref(struct pbuf *p)
{
  if (p != NULL) {
    ++(p->ref);
  }
}


 

将两个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;

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

  /* 将两个pbuf链表拼接起来 */
  p->next = t;
}
/* 将两个pbuf链表拼接起来,并且后一个pbuf链表中第一个pbuf引用数加1 */
void pbuf_chain(struct pbuf *h, struct pbuf *t)
{
  pbuf_cat(h, t);
  pbuf_ref(t);
}

解开pbuf

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

  /* 第一个pbuf后面还有pbuf */
  q = p->next;
  if (q != NULL) {
    /* 调整后面pbuf数据的总长度 */
    q->tot_len = p->tot_len - p->len;

    /* 更新第一个pbuf参数 */
    p->next = NULL;
    p->tot_len = p->len;

    /* 解开后释放一次引用 */
    tail_gone = pbuf_free(q);
    if (tail_gone > 0) {
    }
  }

  /* 解开后pbuf链表首节点指针 */
  return ((tail_gone > 0) ? NULL : q);
}

数据拷贝

pbuf_copy,pbuf之间拷贝数据

pbuf_copy_partial,将pbuf数据拷贝出来

pbuf_take,将数据拷贝进pbuf

/* pbuf之间拷贝 */
err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
{
  u16_t offset_to=0, offset_from=0, len;

  /* 遍历p_from链表 */
  do
  {
	/* 计算这次拷贝的数据长度 */
    if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {
      len = p_from->len - offset_from;
    } else {
      len = p_to->len - offset_to;
    }

    /* 将数据拷贝过来 */
    MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len);

    /* 调整偏移量 */
    offset_to += len;
    offset_from += len;

    /* 目的pbuf数据区已满,切换下一个pbuf */
    if (offset_to == p_to->len) {
      offset_to = 0;
      p_to = p_to->next;
    }

    /* 源pbuf数据区已空,切换下一个pbuf */
    if (offset_from >= p_from->len) {
      offset_from = 0;
      p_from = p_from->next;
    }

    /* 检查错误 */
    if((p_from != NULL) && (p_from->len == p_from->tot_len)) {
    }
    if((p_to != NULL) && (p_to->len == p_to->tot_len)) {
    }
  } while (p_from);
  
  return ERR_OK;
}
/* 将pbuf中指定长度、指定位置的数据拷贝到指定内存 */
u16_t pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
{
  struct pbuf *p;
  u16_t left;
  u16_t buf_copy_len;
  u16_t copied_total = 0;

  left = 0;

  if((buf == NULL) || (dataptr == NULL)) {
    return 0;
  }

  /* 遍历pbuf链表 */
  for(p = buf; len != 0 && p != NULL; p = p->next) {
    /* 数据不在当前pbuf中 */
    if ((offset != 0) && (offset >= p->len)) {
      offset -= p->len;
    } 
    /* 数据在当前pbuf中 */
    else {
      /* 计算该pbuf中可以拷贝的数据长度 */
      buf_copy_len = p->len - offset;
      if (buf_copy_len > len)
          buf_copy_len = len;

	  /* 将pbuf数据拷贝数据缓冲区 */
      MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);

      /* 计算已经拷贝的数据长度 */
      copied_total += buf_copy_len;
      left += buf_copy_len;

      /* 计算剩余数据长度 */
      len -= buf_copy_len;

      /* 清空偏移量 */
      offset = 0;
    }
  }

  /* 拷贝的数据长度 */
  return copied_total;
}
/* 将数据拷贝到pbuf链表 */
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
{
  struct pbuf *p;
  u16_t buf_copy_len;
  u16_t total_copy_len = len;
  u16_t copied_total = 0;

  if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
    return ERR_ARG;
  }

  /* 遍历整个pbuf链表 */
  for(p = buf; total_copy_len != 0; p = p->next) {
    /* 计算该pbuf中可以拷贝的数据长度 */
    buf_copy_len = total_copy_len;
    if (buf_copy_len > p->len) {
      buf_copy_len = p->len;
    }
    /* 将数据拷贝pbuf数据缓冲区 */
    MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);

    /* 计算剩余数据长度和已经拷贝数据长度 */
    total_copy_len -= buf_copy_len;
    copied_total += buf_copy_len;
  }

  return ERR_OK;
}

克隆pbuf

/* 在内存堆中克隆一个指定层的pbuf链表,并释放原有pbuf链表 */
struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
{
  struct pbuf *q;
  err_t err;
  
  if (p->next == NULL) {
    return p;
  }

  /* 从内存堆申请pbuf空间 */
  q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);
  if (q == NULL) {
    return p;
  }

  /* 将数据从p拷贝到q */
  err = pbuf_copy(q, p);

  /* 释放原pbuf链表 */
  pbuf_free(p);

  /* 返回新的pbuf链表指针 */
  return q;
}
发布了208 篇原创文章 · 获赞 90 · 访问量 25万+

猜你喜欢

转载自blog.csdn.net/lushoumin/article/details/100004204
今日推荐