美文网首页
嵌入式LwIP学习笔记之数据包管理2

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

作者: 天心_3a2d | 来源:发表于2019-03-01 13:19 被阅读0次

    一、其他数据包操作函数

    本章接上篇《嵌入式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

          本文链接:https://www.haomeiwen.com/subject/yidluqtx.html