LwIP之数据包管理

先看一下数据包结构体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);
}

 

数据拷贝

pbuf_copy,pbuf之间拷贝数据

pbuf_copy_partial,将pbuf数据拷贝出来

pbuf_copy_partial,将pbuf数据指针返回出来或者将数据拷贝出来

pbuf_take,将数据拷贝进pbuf

pbuf_take_at,将数据拷贝进pbuf指定位置

pbuf_get_at,从pbuf中获取一字节数据,错误返回0

pbuf_try_get_at,从pbuf中获取一字节数据,错误返回-1

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

  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
              (const void *)p_to, (const void *)p_from));

  LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&
             (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;);

  /* 遍历整个链表 */
  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;
    LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);
    LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);

    /* 切换pbuf */
    if (offset_from >= p_from->len) {
      offset_from = 0;
      p_from = p_from->next;
    }
    if (offset_to == p_to->len) {
      offset_to = 0;
      p_to = p_to->next;
      LWIP_ERROR("p_to != NULL", (p_to != NULL) || (p_from == NULL), return ERR_ARG;);
    }

	/* 检查错误 */
    if ((p_from != NULL) && (p_from->len == p_from->tot_len)) {
      LWIP_ERROR("pbuf_copy() does not allow packet queues!",
                 (p_from->next == NULL), return ERR_VAL;);
    }
    if ((p_to != NULL) && (p_to->len == p_to->tot_len)) {
      LWIP_ERROR("pbuf_copy() does not allow packet queues!",
                 (p_to->next == NULL), return ERR_VAL;);
    }
  } while (p_from);
  
  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n"));
  
  return ERR_OK;
}
/* 将pbuf中指定位置的数据拷贝到指定内存 */
u16_t pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
{
  const struct pbuf *p;
  u16_t left = 0;
  u16_t buf_copy_len;
  u16_t copied_total = 0;

  LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
  LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);

  /* 遍历pbuf链表 */
  for (p = buf; len != 0 && p != NULL; p = p->next) 
  {
  	/* 想要拷贝的数据不在当前pbuf中 */
    if ((offset != 0) && (offset >= p->len)) 
    {
      offset = (u16_t)(offset - p->len);
    } 
    /* 想要拷贝的数据在当前pbuf中 */
    else 
    {
      /* 计算需要拷贝数据长度 */
      buf_copy_len = (u16_t)(p->len - offset);
      if (buf_copy_len > len) 
      {
        buf_copy_len = len;
      }
      /* 将数据拷贝出来 */
      MEMCPY(&((char *)dataptr)[left], &((char *)p->payload)[offset], buf_copy_len);

      /* 总共拷贝的数据长度 */
      copied_total = (u16_t)(copied_total + buf_copy_len);

      /* 目标区域偏移量 */
      left = (u16_t)(left + buf_copy_len);
      /* 剩余数据长度 */
      len = (u16_t)(len - buf_copy_len);
      /* 下一个pbuf中数据偏移值 */
      offset = 0;
    }
  }

  /* 返回拷贝数据总长度 */
  return copied_total;
}
/* 从pbuf链获取数据,在一个pbuf上返回指针,在多个pbuf上拷贝数据 */
void *pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset)
{
  const struct pbuf *q;
  u16_t out_offset;

  LWIP_ERROR("pbuf_get_contiguous: invalid buf", (p != NULL), return NULL;);
  LWIP_ERROR("pbuf_get_contiguous: invalid dataptr", (buffer != NULL), return NULL;);
  LWIP_ERROR("pbuf_get_contiguous: invalid dataptr", (bufsize >= len), return NULL;);

  /* 从pbuf链中找出偏移量所在的pbuf和在pbuf中的偏移 */
  q = pbuf_skip_const(p, offset, &out_offset);
  if (q != NULL) 
  {
  	/* 所有数据都在这个pbuf里面,直接把指针传出去不复制 */
    if (q->len >= (out_offset + len))
    {
      return (u8_t *)q->payload + out_offset;
    }

    /* 从pbuf中将数据拷贝出去 */
    if (pbuf_copy_partial(q, buffer, len, out_offset) != len) 
    {
      return NULL;
    }

    /* 返回buffer指针 */
    return buffer;
  }
/* 将数据拷贝到pbuf链 */
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
{
  struct pbuf *p;
  size_t buf_copy_len;
  size_t total_copy_len = len;
  size_t copied_total = 0;

  LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return ERR_ARG;);
  LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return ERR_ARG;);
  LWIP_ERROR("pbuf_take: buf not large enough", (buf->tot_len >= len), return ERR_MEM;);

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

  /* 遍历整个pbuf链 */
  for (p = buf; total_copy_len != 0; p = p->next) 
  {
    LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);

    /* 计算拷贝的数据长度 */
    buf_copy_len = total_copy_len;
    if (buf_copy_len > p->len) 
    {
      buf_copy_len = p->len;
    }

    /* 拷贝数据 */
    MEMCPY(p->payload, &((const char *)dataptr)[copied_total], buf_copy_len);

    /* 更新剩余长度 */
    total_copy_len -= buf_copy_len;

    /* 更新已经拷贝的数据长度 */
    copied_total += buf_copy_len;
  }

  LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
  
  return ERR_OK;
}
/* 将数据拷贝到pbuf链(跳过头部) */
err_t pbuf_take_at(struct pbuf *buf, const void *dataptr, u16_t len, u16_t offset)
{
  u16_t target_offset;

  /* 从pbuf链中找出偏移量所在的pbuf和在pbuf中的偏移 */
  struct pbuf *q = pbuf_skip(buf, offset, &target_offset);

  /* pbuf链中数据长度必须够 */
  if ((q != NULL) && (q->tot_len >= target_offset + len)) 
  {
    u16_t remaining_len = len;
    const u8_t *src_ptr = (const u8_t *)dataptr;
    u16_t first_copy_len;
    
    LWIP_ASSERT("check pbuf_skip result", target_offset < q->len);

    /* 将数据拷贝进行第一个需要偏移的pbuf */
    first_copy_len = (u16_t)LWIP_MIN(q->len - target_offset, len);
    MEMCPY(((u8_t *)q->payload) + target_offset, dataptr, first_copy_len);

	/* 更新剩余字节数和数据指针 */
    remaining_len = (u16_t)(remaining_len - first_copy_len);
    src_ptr += first_copy_len;

    /* 将后续数据拷贝进pbuf链 */
    if (remaining_len > 0) 
    {
      return pbuf_take(q->next, src_ptr, remaining_len);
    }
    
    return ERR_OK;
  }

  return ERR_MEM;
}
/* 从pbuf中获取指定位置的一字节数据,错误返回0 */
u8_t pbuf_get_at(const struct pbuf *p, u16_t offset)
{
  /* 从pbuf中获取指定位置的数据 */
  int ret = pbuf_try_get_at(p, offset);
  if (ret >= 0) 
  {
    return (u8_t)ret;
  }
  return 0;
}
/* 从pbuf中获取指定位置的一字节数据,错误返回-1 */
int pbuf_try_get_at(const struct pbuf *p, u16_t offset)
{
  u16_t q_idx;
  /* 从pbuf链中找出偏移量所在的pbuf和在pbuf中的偏移 */
  const struct pbuf *q = pbuf_skip_const(p, offset, &q_idx);

  /* 返回数据 */
  if ((q != NULL) && (q->len > q_idx)) 
  {
    return ((u8_t *)q->payload)[q_idx];
  }
  return -1;
}
/* 将一字节数据写入pbuf指定位置 */
void pbuf_put_at(struct pbuf *p, u16_t offset, u8_t data)
{
  u16_t q_idx;
  /* 从pbuf链中找出偏移量所在的pbuf和在pbuf中的偏移 */
  struct pbuf *q = pbuf_skip(p, offset, &q_idx);

  /* 将数据写入pbuf中 */
  if ((q != NULL) && (q->len > q_idx)) 
  {
    ((u8_t *)q->payload)[q_idx] = data;
  }
}

 

通过数据偏移量查询在pbuf链中的位置

/* 从pbuf链中找出偏移量所在的pbuf和在pbuf中的偏移 */
struct pbuf *pbuf_skip(struct pbuf *in, u16_t in_offset, u16_t *out_offset)
{
  /* 从pbuf链中找出偏移量所在的pbuf和在pbuf中的偏移 */
  const struct pbuf *out = pbuf_skip_const(in, in_offset, out_offset);
  return LWIP_CONST_CAST(struct pbuf *, out);
}

 

克隆pbuf

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

  /* 从内存堆中克隆一个pbuf */
  q = pbuf_clone(layer, PBUF_RAM, p);
  if (q == NULL) 
  {
    return p;
  }

  /* 释放原pbuf */
  pbuf_free(p);
 
  return q;
}
/* 克隆一个指定层、指定类型的pbuf */
struct pbuf *pbuf_clone(pbuf_layer layer, pbuf_type type, struct pbuf *p)
{
  struct pbuf *q;
  err_t err;

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

  /* 拷贝pbuf内容 */
  err = pbuf_copy(q, p);
  
  LWIP_UNUSED_ARG(err);
  LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
  
  return q;
}

 

比较数据大小

/* 比较pbuf指定位置数据和指定内存数据的大小 */
u16_t pbuf_memcmp(const struct pbuf *p, u16_t offset, const void *s2, u16_t n)
{
  u16_t start = offset;
  const struct pbuf *q = p;
  u16_t i;

  /* pbuf数据必须够长 */
  if (p->tot_len < (offset + n)) 
  {
    return 0xffff;
  }

  /* 从pbuf链中找出指定位置所在的pbuf指针和在该pbuf中的偏移量 */
  while ((q != NULL) && (q->len <= start)) 
  {
    start = (u16_t)(start - q->len);
    q = q->next;
  }

  for (i = 0; i < n; i++)
  {
  	/* 从pbuf中获取指定位置的一字节数据 */
    u8_t a = pbuf_get_at(q, (u16_t)(start + i));
    /* 从指定内存中获取一个字节 */
    u8_t b = ((const u8_t *)s2)[i];

    /* 不相等返回不等的位置 */
    if (a != b) 
    {
      return (u16_t)LWIP_MIN(i + 1, 0xFFFF);
    }
  }

  /* 相等返回0 */
  return 0;
}

 

查找数据位置

/* 从pbuf指定位置开始查找指定数据,返回这段数据在pbuf中位置 */
u16_t pbuf_memfind(const struct pbuf *p, const void *mem, u16_t mem_len, u16_t start_offset)
{
  u16_t i;
  /* 计算比较时最大的起始位置 */
  u16_t max_cmp_start = (u16_t)(p->tot_len - mem_len);

  /* 数据必须足够长 */
  if (p->tot_len >= mem_len + start_offset) 
  {
    /* 遍历所有位置 */
    for (i = start_offset; i <= max_cmp_start; i++) 
    {
      /* 从当前位置开始比较 */
      u16_t plus = pbuf_memcmp(p, i, mem, mem_len);
      /* 返回位置 */
      if (plus == 0) 
      {
        return i;
      }
    }
  }
  return 0xFFFF;
}
/* 找出指定字符串在pbuf中的位置 */
u16_t pbuf_strstr(const struct pbuf *p, const char *substr)
{
  size_t substr_len;
  if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) 
  {
    return 0xFFFF;
  }
  substr_len = strlen(substr);
  if (substr_len >= 0xFFFF) {
    return 0xFFFF;
  }

  /* 从pbuf查找指定数据,返回这段数据在pbuf中位置 */
  return pbuf_memfind(p, substr, (u16_t)substr_len, 0);
}

 

你可能感兴趣的:(LwIP)