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