* Dechains the first pbuf from its succeeding pbufs in the chain. * * Makes p->tot_len field equal to p->len. * @param p pbuf to dechain * @return remainder of the pbuf chain, or NULL if it was de-allocated. * @note May not be called on a packet queue. */
| 909 | * @note May not be called on a packet queue. |
| 910 | */ |
| 911 | struct pbuf * |
| 912 | pbuf_dechain(struct pbuf *p) |
| 913 | { |
| 914 | struct pbuf *q; |
| 915 | u8_t tail_gone = 1; |
| 916 | /* tail */ |
| 917 | q = p->next; |
| 918 | /* pbuf has successor in chain? */ |
| 919 | if (q != NULL) { |
| 920 | /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ |
| 921 | LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); |
| 922 | /* enforce invariant if assertion is disabled */ |
| 923 | q->tot_len = (u16_t)(p->tot_len - p->len); |
| 924 | /* decouple pbuf from remainder */ |
| 925 | p->next = NULL; |
| 926 | /* total length of pbuf p is its own length only */ |
| 927 | p->tot_len = p->len; |
| 928 | /* q is no longer referenced by p, free it */ |
| 929 | LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); |
| 930 | tail_gone = pbuf_free(q); |
| 931 | if (tail_gone > 0) { |
| 932 | LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, |
| 933 | ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q)); |
| 934 | } |
| 935 | /* return remaining tail or NULL if deallocated */ |
| 936 | } |
| 937 | /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ |
| 938 | LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); |
| 939 | return ((tail_gone > 0) ? NULL : q); |
| 940 | } |
| 941 | |
| 942 | /** |
| 943 | * @ingroup pbuf |
no test coverage detected