一、其他數(shù)據(jù)包操作函數(shù)
本章接上篇《嵌入式LwIP學(xué)習(xí)筆記之?dāng)?shù)據(jù)包管理1》朝聋,繼續(xù)講解其他的數(shù)據(jù)包操作函數(shù)狮腿,
pbuf_realloc 函數(shù)、pbuf_header 函數(shù)脏榆、pbuf_take 函數(shù)的具體流程。
二台谍、pbuf_realloc 函數(shù)
pbuf_realloc 函數(shù)在相應(yīng) pbuf(鏈表)尾部釋放一定的空間须喂,將數(shù)據(jù)包 pbuf 中的數(shù)
據(jù)長度減少為某個長度值。對于 PBUF_RAM 類型的 pbuf趁蕊,函數(shù)將調(diào)用內(nèi)存堆管理中介紹到的 mem_realloc 函數(shù)坞生,釋放這些多余的空間;對于其他三種類型的 pbuf掷伙,該函數(shù)只是修改 pbuf 中的長度字段值是己,并不釋放對應(yīng)的內(nèi)存池空間。
/**
?* Shrink a pbuf chain to a desiredlength.
?*
?* @param p pbuf to shrink.
?* @param new_len desired new lengthof pbuf chain
?*
?* Depending on the desired length,the first few pbufs in a chain might
?* be skipped and left unchanged.The new last pbuf in the chain will be
?* resized, and any remaining pbufswill be freed.
?*
?* @note If the pbuf is ROM/REF,only the ->tot_len and ->len fields are adjusted.
?* @note May not be called on a packetqueue.
?*
?* @note Despite its name,pbuf_realloc cannot grow the size of a pbuf (chain).
?*/
//將數(shù)據(jù)鏈表pbuf的尾部釋放一定的空間任柜,以期獲得指定長度的pbuf
//p 需要釋放的數(shù)據(jù)鏈表pbuf
//new_len 釋放后的pbuf的數(shù)據(jù)長度
void pbuf_realloc(struct pbuf *p, u16_t new_len)
{
? struct pbuf *q;
? u16_t rem_len;????? /*用于指定當(dāng)前pbuf的剩余長度*/
? 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);
? /* desired length larger thancurrent length? */
? if (new_len >= p->tot_len) {??? //新的pbuf數(shù)據(jù)長度應(yīng)在原總的數(shù)據(jù)長度內(nèi)
??? /* enlarging not yet supported*/
??? return;
? }
? grow = new_len - p->tot_len;? //獲取需要釋放的數(shù)據(jù)
? rem_len = new_len;?? //保留當(dāng)前應(yīng)該剩余的數(shù)據(jù)長度
? q = p;?????? //使用q指向數(shù)據(jù)鏈表的p的首地址
??//剩余數(shù)據(jù)的長度大于數(shù)據(jù)鏈表q的數(shù)據(jù)長度寒波,則進(jìn)入循環(huán)乘盼,否則說明已經(jīng)找到需要釋
//放數(shù)據(jù)的pbuf在鏈表中的位置
? while (rem_len > q->len) {??
??? rem_len -= q->len;?????? //剩余的長度減去當(dāng)前的pbuf的數(shù)據(jù)長度
??? /* decrease total lengthindicator */
??? LWIP_ASSERT("grow
??? q->tot_len += (u16_t)grow;?????? //減少總的數(shù)據(jù)長度
??? q = q->next;??????????????????? //指向數(shù)據(jù)鏈表中的下一個pbuf
??? LWIP_ASSERT("pbuf_realloc:q != NULL", q != NULL);//判斷q是否為NULL
? }
//執(zhí)行到這一步升熊,說明我們找到了要釋放數(shù)據(jù)的pbuf的位置
? //為PBUF_RAM類型時,釋放內(nèi)存空間绸栅,其他的類型级野,只是減少數(shù)據(jù)長度
? if ((q->type == PBUF_RAM)&& (rem_len != q->len)) {??
??? /* reallocate and adjust thelength of the pbuf that will be split */
??? q = (struct pbuf *)mem_trim(q,(u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len);
??? LWIP_ASSERT("mem_trimreturned q == NULL", q != NULL);
? }
? /* adjust length fields for newlast pbuf */
? q->len = rem_len;? //最后一個pbuf的數(shù)據(jù)長度為最后的剩余長度
? q->tot_len = q->len; //最后一個pbuf的數(shù)據(jù)總長度為最后的剩余長度,因為后面沒有pbuf
? /*如果pbuf后還接有鏈表粹胯,則釋放掉*/
? if (q->next != NULL) {
??? /* free remaining pbufs in chain*/
??? pbuf_free(q->next);
? }
? /* q is last packet in chain */
? q->next = NULL;?? //數(shù)據(jù)釋放后蓖柔,應(yīng)置空
}
三、pbuf_header 函數(shù)
pbuf_header 函數(shù)用于調(diào)整 pbuf 的 payload 指針(向前或向后移動一定的字節(jié)數(shù))风纠,
在前面也說到過了况鸣,在 pbuf 的數(shù)據(jù)區(qū)前可能會預(yù)留一些協(xié)議首部空間,而pbuf 被創(chuàng)建時竹观,payload 指針是指向數(shù)據(jù)區(qū)的镐捧,為了實現(xiàn)對這些預(yù)留空間的操作,可以調(diào)用函數(shù)pbuf_header 使 payload 指針指向數(shù)據(jù)區(qū)前的首部字段臭增,這就為各層對數(shù)據(jù)包首部的操作提供了方便懂酱。當(dāng)然,進(jìn)行這個操作的時候誊抛,len和 tot_len 字段值也會隨之更新列牺。
/**
?*Adjusts the payload pointer to hide or reveal headers in the payload.
* @param p pbuf to change the header size.
?*@param header_size_increment Number of bytes to increment header size which
?*increases the size of the pbuf. New space is on the front.
*/
//函數(shù)功能:調(diào)整 pbuf 的 payload 指針,指向數(shù)據(jù)區(qū)或pbuf的數(shù)據(jù)區(qū)的首部字段
//pbuf 需要更改的數(shù)據(jù)表pbuf
//header_size_increment? 更改payload的指向位置拗窃,向前或者向后
u8_t pbuf_header(struct pbuf *p, s16_theader_size_increment)
{
?u16_t type;
? void*payload;?? //指向pbuf的數(shù)據(jù)區(qū)首地址
?u16_t increment_magnitude;? //描述指針的改變值
?LWIP_ASSERT("p != NULL", p != NULL);
//位置改變量為0瞎领,說明不要更改,返回
//數(shù)據(jù)區(qū)p為空随夸,則無數(shù)據(jù)可操作九默,返回?
if ((header_size_increment == 0) || (p == NULL)) {
???return 0;
? }
? if(header_size_increment < 0){ // header_size_increment小于0,表示向數(shù)據(jù)區(qū)的首部移動
???increment_magnitude = -header_size_increment;? //獲取該變量
??? /*Check that we aren't going to move off the end of the pbuf */
???LWIP_ERROR("increment_magnitude <= p->len",(increment_magnitude <= p->len), return 1;);
? }else {
???increment_magnitude = header_size_increment;
? }
? type= p->type;? //獲取pbuf的類型
?payload = p->payload;? //獲取數(shù)據(jù)區(qū)的首地址
? //為PBUF_RAM或PBUF_POOL類型
? if(type == PBUF_RAM || type == PBUF_POOL) {
??? /*set new payload pointer */
???p->payload = (u8_t *)p->payload - header_size_increment;? //設(shè)置新的payload指向地址
??? /*新的payload指向地址超出最大值*/
?? ?if ((u8_t *)p->payload < (u8_t *)p +SIZEOF_STRUCT_PBUF) {
?????LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
???????("pbuf_header: failed as %p < %p (not enough space for newheader size)\n",
???????(void *)p->payload, (void *)(p + 1)));
?????/* restore old payload pointer */
?????p->payload = payload;?? //更新原來的payload到pbuf的payload
?????/* bail out unsuccesfully */
?????return 1;???? //返回失敗
??? }
? /*為PBUF_REF或PBUF_ROM等外部內(nèi)存*/
? }else if (type == PBUF_REF || type == PBUF_ROM) {
??? /*pbuf的payload指針不能向前移動逃魄,只能向增加的方向移動*/
??? if((header_size_increment < 0) && (increment_magnitude <=p->len)) {
?????p->payload = (u8_t *)p->payload - header_size_increment;? //增加payload的指向地址
??? }else {
????? /*指針不能向前移動荤西,所以返回失敗*/
?????return 1;??
??? }
? }else {
??? /*Unknown type */
???LWIP_ASSERT("bad pbuf type", 0);
???return 1;
? }
? /*modify pbuf length fields */
?p->len += header_size_increment;???//增加pbuf的數(shù)據(jù)區(qū)的數(shù)據(jù)長度
?p->tot_len += header_size_increment; //增加pbuf的數(shù)據(jù)區(qū)的數(shù)據(jù)總長度
?LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new%p (%"S16_F")\n", (void *)payload, (void *)p->payload,header_size_increment));
?return 0;?????? //返回移動指針成功
}
四、pbuf_take 函數(shù)
pbuf_take 函數(shù)用于向 pbuf 的數(shù)據(jù)區(qū)域拷貝數(shù)據(jù)伍俘;pbuf_copy 函數(shù)用于將一個任何類型的 pbuf中的數(shù)據(jù)拷貝到一個 PBUF_RAM 類型的 pbuf 中邪锌。pbuf_chain 函數(shù)用于連接兩個 pbuf(鏈表)為一個 pbuf 鏈表;pbuf_ref 函數(shù)用于將 pbuf 中的 ref 值加 1癌瘾。
?/**
?* Copyapplication supplied data into a pbuf.
?* Thisfunction can only be used to copy the equivalent of buf->tot_len data.
?*
?* @param bufpbuf to fill with data
?* @paramdataptr application supplied data buffer
?* @param lenlength of the application supplied data buffer
?*
?* @returnERR_OK if successful, ERR_MEM if the pbuf is not big enough
?*/
//向pbuf的數(shù)據(jù)區(qū)拷貝指定長度的數(shù)據(jù)
//buf 數(shù)據(jù)鏈表buf
//len 拷貝的數(shù)據(jù)長度
//dataptr 拷貝數(shù)據(jù)后存入的緩存區(qū)
err_t pbuf_take(struct pbuf *buf, const void*dataptr, u16_t len)
{
? struct pbuf*p;?? //定義數(shù)據(jù)表pbuf
? u16_tbuf_copy_len; //每個pbuf中需要拷貝的數(shù)據(jù)長度
? u16_ttotal_copy_len = len;? //需要拷貝的總的數(shù)據(jù)長度
? u16_tcopied_total = 0;
?LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return0;);
?LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL),return 0;);
//數(shù)據(jù)有效性判斷
? if ((buf ==NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
??? returnERR_ARG;
? }
? /* Notesome systems use byte copy if dataptr or one of the pbuf payload pointers areunaligned. */
//遍歷拷貝數(shù)據(jù)鏈表buf觅丰,直到拷貝完len的數(shù)據(jù)
? for(p =buf; total_copy_len != 0; p = p->next) {
???LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);
???buf_copy_len = total_copy_len;? //剩余需要拷貝的數(shù)據(jù)長度
??? if (buf_copy_len> p->len) {
????? /* thispbuf cannot hold all remaining data */
?????buf_copy_len = p->len;??? //本次需要從pbuf數(shù)據(jù)區(qū)中拷貝的數(shù)據(jù)長度
??? }
??? /*拷貝pbuf中的數(shù)據(jù)區(qū)到緩存區(qū)中*/
???MEMCPY(p->payload, &((char*)dataptr)[copied_total],buf_copy_len);
???total_copy_len -= buf_copy_len;?//更新還需要拷貝的數(shù)據(jù)長度
???copied_total += buf_copy_len;???//標(biāo)記已經(jīng)拷貝的數(shù)據(jù)長度
? }
?LWIP_ASSERT("did not copy all data", total_copy_len == 0&& copied_total == len);
? returnERR_OK;?? //返回數(shù)據(jù)拷貝成功
}
五、pbuf_fill_chksum函數(shù)
/**
?*Copies data into a single pbuf (*not* into a pbuf queue!) and updates
?*the checksum while copying
?*
?*@param p the pbuf to copy data into
?*@param start_offset offset of p->payload where to copy the data to
?*@param dataptr data to copy into the pbuf
?*@param len length of data to copy into the pbuf
?*@param chksum pointer to the checksum which is updated
?*@return ERR_OK if successful, another error if the data does not fit
?*????????within the (first) pbuf (no pbuf queues!)
?*/
err_t
pbuf_fill_chksum(struct pbuf *p, u16_tstart_offset, const void *dataptr,
???????????????? u16_t len, u16_t *chksum)
{
?u32_t acc;
?u16_t copy_chksum;
?char *dst_ptr;
?LWIP_ASSERT("p != NULL", p != NULL);
?LWIP_ASSERT("dataptr != NULL", dataptr != NULL);
? LWIP_ASSERT("chksum!= NULL", chksum != NULL);
?LWIP_ASSERT("len != 0", len != 0);
? if((start_offset >= p->len) || (start_offset + len > p->len)) {
???return ERR_ARG;
? }
?dst_ptr = ((char*)p->payload) + start_offset;?? //目的地址為數(shù)據(jù)區(qū)首地址 + 偏移地址
? //以目的地址為首地址拷貝指定長度len的數(shù)據(jù)到dataptr中
copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len);?
? if((start_offset & 1) != 0) {? //若偏移地址為奇數(shù)妨退,需要補(bǔ)齊計算校驗和
???copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum);
? }
? acc= *chksum;??? //獲取已有數(shù)據(jù)的校驗和?
? acc+= copy_chksum; //加上當(dāng)前新拷貝的數(shù)據(jù)的檢驗和
?*chksum = FOLD_U32T(acc);? //取校驗和的反碼
?return ERR_OK;
}