📄 pbuf.c
字号:
* * 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. */struct pbuf *pbuf_dechain(struct pbuf *p){ struct pbuf *q; u8_t tail_gone = 1; /* tail */ q = p->next; /* pbuf has successor in chain? */ if (q != NULL) { /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); /* enforce invariant if assertion is disabled */ q->tot_len = p->tot_len - p->len; /* decouple pbuf from remainder */ p->next = NULL; /* total length of pbuf p is its own length only */ p->tot_len = p->len; /* q is no longer referenced by p, free it */ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); tail_gone = pbuf_free(q); if (tail_gone > 0) { LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q)); } /* return remaining tail or NULL if deallocated */ } /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); return ((tail_gone > 0) ? NULL : q);}/** * * Create PBUF_RAM copies of pbufs. * * Used to queue packets on behalf of the lwIP stack, such as * ARP based queueing. * * @note You MUST explicitly use p = pbuf_take(p); * * @note Only one packet is copied, no packet queue! * * @param p_to pbuf destination of the copy * @param p_from pbuf source of the copy * * @return ERR_OK if pbuf was copied * ERR_ARG if one of the pbufs is NULL or p_to is not big * enough to hold p_from */err_tpbuf_copy(struct pbuf *p_to, struct pbuf *p_from){ u16_t offset_to=0, offset_from=0, len; LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n", (void*)p_to, (void*)p_from)); /* is the target big enough to hold the source? */ LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) && (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;); /* iterate through pbuf chain */ do { LWIP_ASSERT("p_to != NULL", p_to != NULL); /* copy one part of the original chain */ if ((p_to->len - offset_to) >= (p_from->len - offset_from)) { /* complete current p_from fits into current p_to */ len = p_from->len - offset_from; } else { /* current p_from does not fit into current p_to */ len = p_to->len - offset_to; } MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len); offset_to += len; offset_from += len; LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len); if (offset_to == p_to->len) { /* on to next p_to (if any) */ offset_to = 0; p_to = p_to->next; } LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len); if (offset_from >= p_from->len) { /* on to next p_from (if any) */ offset_from = 0; p_from = p_from->next; } if((p_from != NULL) && (p_from->len == p_from->tot_len)) { /* don't copy more than one packet! */ LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", (p_from->next == NULL), return ERR_VAL;); } if((p_to != NULL) && (p_to->len == p_to->tot_len)) { /* don't copy more than one packet! */ LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", (p_to->next == NULL), return ERR_VAL;); } } while (p_from); LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n")); return ERR_OK;}/** * Copy (part of) the contents of a packet buffer * to an application supplied buffer. * * @param buf the pbuf from which to copy data * @param dataptr the application supplied buffer * @param len length of data to copy (dataptr must be big enough). No more * than buf->tot_len will be copied, irrespective of len * @param offset offset into the packet buffer from where to begin copying len bytes * @return the number of bytes copied, or 0 on failure */u16_tpbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset){ struct pbuf *p; u16_t left; u16_t buf_copy_len; u16_t copied_total = 0; LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); left = 0; if((buf == NULL) || (dataptr == NULL)) { return 0; } /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ for(p = buf; len != 0 && p != NULL; p = p->next) { if ((offset != 0) && (offset >= p->len)) { /* don't copy from this buffer -> on to the next */ offset -= p->len; } else { /* copy from this buffer. maybe only partially. */ buf_copy_len = p->len - offset; if (buf_copy_len > len) buf_copy_len = len; /* copy the necessary parts of the buffer */ MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len); copied_total += buf_copy_len; left += buf_copy_len; len -= buf_copy_len; offset = 0; } } return copied_total;}/** * Copy application supplied data into a pbuf. * This function can only be used to copy the equivalent of buf->tot_len data. * * @param buf pbuf to fill with data * @param dataptr application supplied data buffer * @param len length of the application supplied data buffer * * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough */err_tpbuf_take(struct pbuf *buf, const void *dataptr, u16_t len){ struct pbuf *p; u16_t buf_copy_len; u16_t total_copy_len = len; u16_t copied_total = 0; LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;); LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;); if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) { return ERR_ARG; } /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ 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) { /* this pbuf cannot hold all remaining data */ buf_copy_len = p->len; } /* copy the necessary parts of the buffer */ 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); return ERR_OK;}/** * Creates a single pbuf out of a queue of pbufs. * * @remark: Either the source pbuf 'p' is freed by this function or the original * pbuf 'p' is returned, therefore the caller has to check the result! * * @param p the source pbuf * @param layer pbuf_layer of the new pbuf * * @return a new, single pbuf (p->next is NULL) * or the old pbuf if allocation fails */struct pbuf*pbuf_coalesce(struct pbuf *p, pbuf_layer layer){ struct pbuf *q; err_t err; if (p->next == NULL) { return p; } q = pbuf_alloc(layer, p->tot_len, PBUF_RAM); if (q == NULL) { /* @todo: what do we do now? */ return p; } err = pbuf_copy(q, p); LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); pbuf_free(p); return q;}#if LWIP_CHECKSUM_ON_COPY/** * 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_tpbuf_fill_chksum(struct pbuf *p, u16_t start_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; 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;}#endif /* LWIP_CHECKSUM_ON_COPY */ /** Get one byte from the specified position in a pbuf * WARNING: returns zero for offset >= p->tot_len * * @param p pbuf to parse * @param offset offset into p of the byte to return * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len */u8_tpbuf_get_at(struct pbuf* p, u16_t offset){ u16_t copy_from = offset; struct pbuf* q = p; /* get the correct pbuf */ while ((q != NULL) && (q->len <= copy_from)) { copy_from -= q->len; q = q->next; } /* return requested data if pbuf is OK */ if ((q != NULL) && (q->len > copy_from)) { return ((u8_t*)q->payload)[copy_from]; } return 0;}/** Compare pbuf contents at specified offset with memory s2, both of length n * * @param p pbuf to compare * @param offset offset into p at wich to start comparing * @param s2 buffer to compare * @param n length of buffer to compare * @return zero if equal, nonzero otherwise * (0xffff if p is too short, diffoffset+1 otherwise) */u16_tpbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n){ u16_t start = offset; struct pbuf* q = p; /* get the correct pbuf */ while ((q != NULL) && (q->len <= start)) { start -= q->len; q = q->next; } /* return requested data if pbuf is OK */ if ((q != NULL) && (q->len > start)) { u16_t i; for(i = 0; i < n; i++) { u8_t a = pbuf_get_at(q, start + i); u8_t b = ((u8_t*)s2)[i]; if (a != b) { return i+1; } } return 0; } return 0xffff;}/** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset * start_offset. * * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as * return value 'not found' * @param mem search for the contents of this buffer * @param mem_len length of 'mem' * @param start_offset offset into p at which to start searching * @return 0xFFFF if substr was not found in p or the index where it was found */u16_tpbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset){ u16_t i; u16_t max = p->tot_len - mem_len; if (p->tot_len >= mem_len + start_offset) { for(i = start_offset; i <= max; ) { u16_t plus = pbuf_memcmp(p, i, mem, mem_len); if (plus == 0) { return i; } else { i += plus; } } } return 0xFFFF;}/** Find occurrence of substr with length substr_len in pbuf p, start at offset * start_offset * WARNING: in contrast to strstr(), this one does not stop at the first \0 in * the pbuf/source string! * * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as * return value 'not found' * @param substr string to search for in p, maximum length is 0xFFFE * @return 0xFFFF if substr was not found in p or the index where it was found */u16_tpbuf_strstr(struct pbuf* p, const char* substr){ size_t substr_len; if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) { return 0xFFFF; } substr_len = strlen(substr); if (substr_len >= 0xFFFF) { return 0xFFFF; } return pbuf_memfind(p, substr, (u16_t)substr_len, 0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -