嵌入式LwIP学习笔记之数据包管理2

一、其他数据包操作函数

本章接上篇《嵌入式LwIP学习笔记之数据包管理1》,继续讲解其他的数据包操作函数,

pbuf_realloc 函数、pbuf_header 函数、pbuf_take 函数的具体流程。

二、pbuf_realloc 函数

pbuf_realloc 函数在相应 pbuf(链表)尾部释放一定的空间,将数据包 pbuf 中的数

据长度减少为某个长度值。对于 PBUF_RAM 类型的 pbuf,函数将调用内存堆管理中介绍到的 mem_realloc 函数,释放这些多余的空间;对于其他三种类型的 pbuf,该函数只是修改 pbuf 中的长度字段值,并不释放对应的内存池空间。

/**

 * 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).

 */

//将数据链表pbuf的尾部释放一定的空间,以期获得指定长度的pbuf

//p 需要释放的数据链表pbuf

//new_len 释放后的pbuf的数据长度

void pbuf_realloc(struct pbuf *p, u16_t new_len)

{

  struct pbuf *q;

  u16_t rem_len;      /*用于指定当前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数据长度应在原总的数据长度内

    /* enlarging not yet supported*/

    return;

  }


  grow = new_len - p->tot_len;  //获取需要释放的数据

  rem_len = new_len;   //保留当前应该剩余的数据长度

  q = p;       //使用q指向数据链表的p的首地址

  //剩余数据的长度大于数据链表q的数据长度,则进入循环,否则说明已经找到需要释

//放数据的pbuf在链表中的位置

  while (rem_len > q->len) {  

    rem_len -= q->len;       //剩余的长度减去当前的pbuf的数据长度

    /* decrease total lengthindicator */

    LWIP_ASSERT("grow

    q->tot_len += (u16_t)grow;       //减少总的数据长度

    q = q->next;                    //指向数据链表中的下一个pbuf

    LWIP_ASSERT("pbuf_realloc:q != NULL", q != NULL);//判断q是否为NULL

  }


//执行到这一步,说明我们找到了要释放数据的pbuf的位置

  //为PBUF_RAM类型时,释放内存空间,其他的类型,只是减少数据长度

  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的数据长度为最后的剩余长度

  q->tot_len = q->len; //最后一个pbuf的数据总长度为最后的剩余长度,因为后面没有pbuf

  /*如果pbuf后还接有链表,则释放掉*/

  if (q->next != NULL) {

    /* free remaining pbufs in chain*/

    pbuf_free(q->next);

  }

  /* q is last packet in chain */

  q->next = NULL;   //数据释放后,应置空

}

三、pbuf_header 函数

pbuf_header 函数用于调整 pbuf 的 payload 指针(向前或向后移动一定的字节数),

在前面也说到过了,在 pbuf 的数据区前可能会预留一些协议首部空间,而pbuf 被创建时,payload 指针是指向数据区的,为了实现对这些预留空间的操作,可以调用函数pbuf_header 使 payload 指针指向数据区前的首部字段,这就为各层对数据包首部的操作提供了方便。当然,进行这个操作的时候,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.

*/

//函数功能:调整 pbuf 的 payload 指针,指向数据区或pbuf的数据区的首部字段

//pbuf 需要更改的数据表pbuf

//header_size_increment  更改payload的指向位置,向前或者向后

u8_t pbuf_header(struct pbuf *p, s16_theader_size_increment)

{

 u16_t type;

  void*payload;   //指向pbuf的数据区首地址

 u16_t increment_magnitude;  //描述指针的改变值


 LWIP_ASSERT("p != NULL", p != NULL);

//位置改变量为0,说明不要更改,返回

//数据区p为空,则无数据可操作,返回 

if ((header_size_increment == 0) || (p == NULL)) {

   return 0;

  }


  if(header_size_increment < 0){ // header_size_increment小于0,表示向数据区的首部移动

   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;  //获取数据区的首地址

  //为PBUF_RAM或PBUF_POOL类型

  if(type == PBUF_RAM || type == PBUF_POOL) {

    /*set new payload pointer */

   p->payload = (u8_t *)p->payload - header_size_increment;  //设置新的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等外部内存*/

  }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的数据区的数据长度

 p->tot_len += header_size_increment; //增加pbuf的数据区的数据总长度


 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 函数

  pbuf_take 函数用于向 pbuf 的数据区域拷贝数据;pbuf_copy 函数用于将一个任何类型的 pbuf中的数据拷贝到一个 PBUF_RAM 类型的 pbuf 中。pbuf_chain 函数用于连接两个 pbuf(链表)为一个 pbuf 链表;pbuf_ref 函数用于将 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的数据区拷贝指定长度的数据

//buf 数据链表buf

//len 拷贝的数据长度

//dataptr 拷贝数据后存入的缓存区

err_t pbuf_take(struct pbuf *buf, const void*dataptr, u16_t len)

{

  struct pbuf*p;   //定义数据表pbuf

  u16_tbuf_copy_len; //每个pbuf中需要拷贝的数据长度

  u16_ttotal_copy_len = len;  //需要拷贝的总的数据长度

  u16_tcopied_total = 0;


 LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return0;);

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


//数据有效性判断

  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. */

//遍历拷贝数据链表buf,直到拷贝完len的数据

  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) {

      /* thispbuf cannot hold all remaining data */

     buf_copy_len = p->len;    //本次需要从pbuf数据区中拷贝的数据长度

    }

    /*拷贝pbuf中的数据区到缓存区中*/

   MEMCPY(p->payload, &((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);

  returnERR_OK;   //返回数据拷贝成功

}





五、pbuf_fill_chksum函数


/**

 *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;   //目的地址为数据区首地址 + 偏移地址

  //以目的地址为首地址拷贝指定长度len的数据到dataptr中

copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len); 

  if((start_offset & 1) != 0) {  //若偏移地址为奇数,需要补齐计算校验和

   copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum);

  }

  acc= *chksum;    //获取已有数据的校验和 

  acc+= copy_chksum; //加上当前新拷贝的数据的检验和

 *chksum = FOLD_U32T(acc);  //取校验和的反码

 return ERR_OK;

}

你可能感兴趣的:(嵌入式LwIP学习笔记之数据包管理2)