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