调用流程:
ip4_input函数接收到数据包后,获取IP报头并分析,若获取的IP报文长度小于pbuf总长度,
调用pbuf_realloc函数缩减一个pbuf链到希望的长度。
函数简析:
缩减一个pbuf链到希望的长度。
根据所期望的长度,链中的前几个pbufs可能跳过并保持不变,链中的最后一个pbuf将调整大小,剩余的pbufs将被释放。
具体分析: (在源码中有详细注释)
1.通过IP报文长度和pbuf总长度的差值,得到需要缩减的长度;
2.将IP报文长度作为剩余长度,通过while循环跨过所有应该留在链中的pbufs;
3.得到最后一个pbuf,若为PBUF_RAM类型,缩减其内存分配;
4.为最后一个pbuf调整长度字段,并将链中所有其余的pbuf释放。
源码:
/**
* 缩减一个pbuf链到希望的长度
*
* @参数p:要缩减的pbuf
* @参数new_len:pbuf数据链希望的新长度
*
* 根据所期望的长度,链中的前几个pbufs可能跳过并保持不变
* 链中的最后一个pbuf将调整大小,剩余的pbufs将被释放
*
* @注意:如果pbuf是ROM/REF, 只有pbuf的->tot_len和 ->len区域被调整
* @注意:不能调用一个数据包序列。
*
* @注意:pbuf_realloc不能增加一个pbuf(链)的大小
*/
void
pbuf_realloc(struct pbuf *p, u16_t new_len)
{
struct pbuf *q;
u16_t rem_len; /* 剩余长度 */
s32_t grow;
LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
p->type == PBUF_ROM ||
p->type == PBUF_RAM ||
p->type == PBUF_REF);
/* 若当前长度大于总长度,直接退出 */
if (new_len >= p->tot_len) {
return;
}
/* pbuf链增加的长度(new_len - p->tot_len)字节,(在缩减情况下为负数)
* 这里就是一个负数...*/
grow = new_len - p->tot_len;
/* 开始剩余长度即为所期望的长度 */
rem_len = new_len;
q = p;
/* 这个pbuf是否保留在pbuf链里面? */
/* 通过while循环,跨过所有应该留在链中的pbufs */
while (rem_len > q->len) {
/* 剩余长度 = 剩余长度-当前pbuf长度 */
rem_len -= q->len;
/* 新的总长度 */
LWIP_ASSERT("grow < max_u16_t", grow < 0xffff);
q->tot_len += (u16_t)grow;
/* 指向链中的下一个pbuf */
q = q->next;
LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
}
/* 现在到达新的最后一个pbuf(in q) */
/* rem_len == pbuf q希望的长度 */
/* 为PBUF_RAM缩减内存分配 */
/* 如果pbuf是ROM/REF, 只有pbuf的->tot_len和 ->len区域被调整 */
/* (其他类型值调整长度字段) */
if ((q->type == PBUF_RAM) && (rem_len != q->len)
#if LWIP_SUPPORT_CUSTOM_PBUF
&& ((q->flags & PBUF_FLAG_IS_CUSTOM) == 0)
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
) {
/* 重新分配和调整将要分割的pbuf的长度 */
q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len);
LWIP_ASSERT("mem_trim returned q == NULL", q != NULL);
}
/* 为新的最后一个pbuf调整长度字段 */
q->len = rem_len;
q->tot_len = q->len;
/* 若链中所有其余的pbufs,剩余的pbufs将被释放 */
if (q->next != NULL) {
pbuf_free(q->next);
}
/* q 是链中最后一个数据包 */
q->next = NULL;
}