#ifndef UC_MBUF_H_ #define UC_MBUF_H_ #include #include #ifdef __GNUC__ # define UC_INLINE inline __attribute__((always_inline)) #else # define UC_INLINE inline #endif enum UC_MBUF_FLAGS { UC_MBUF_FL_MALLOC = 0x0001, //MBuf and MBuf->bufstart are seperatly malloc'd UC_MBUF_FL_MALLOC_BUF = 0x0001, //MBuf is not malloc'd. MBuf->bufstart is malloc'd UC_MBUF_FL_MALLOC_INLINE = 0x0002, //MBuf is one big malloc. Can't be extended UC_MBUF_FL_STATIC = 0x0004, //MBuf and MBuf->bustart is user controlled. Can't be extended }; struct MBuf { /** prev/next pointer, user can use this for a linked list*/ struct MBuf *prev; struct MBuf *next; /** Pointers the user can use to remember spots in * the data. (these must either be NULL pointers or point into * something in the buffer*/ uint8_t *p1; uint8_t *p2; uint8_t *p3; uint8_t *p4; /**Arbitary pointer user can associate with the mbuf*/ void *cookie; /*UC_MBUF_FLAGS. The upper 16 bits can be used by the application */ uint32_t flags; /** Total no of bytes from bufstart*/ uint32_t allocated; /** Start of the buffer*/ uint8_t *bufstart; /** Start of the data in the buffer*/ uint8_t *head; /** End of the buffer (one byte past the data) */ uint8_t *tail; /** Internal data, if we allocate it inline */ uint8_t inline_data[0]; }; /** * Concept: * <--------- allocated -----------> * <--- len --> * +--------------------------------+ * |Headroom| Data |Tailroom | * +--------------------------------+ * ^ ^ ^ * | | | * | | tail * | head * bufstart * * Initially when empty, head == tail, and the length is 0. * Data is added to the tail. * * If head == bufstart, there is no headroom * if tail points one past the allocated space, there is no * tailroom (the buffer is full) * * Conventions: * push - prepend data to the buffer (in the head room part) * (move head to the left) * pull - remove data from the beginning of the message. * (move head to the right) * put - Add data to the buffer. * (move tail to the right) */ /** Allocate an mbuf with a length and headroom, * the buffer will have the flag UC_MBUF_FL_MALLOC * The total length of the buffer will be length+headroom * * @param len the initial length of the mbuf * @param the initial headroom of the mbuf * @return NULL if the allocation fails */ struct MBuf *uc_mbuf_new_hr(uint32_t len, uint32_t headroom); /** As uc_mbuf_new_hr, but without any headroom*/ #define uc_mbuf_new(len) uc_mbuf_new_hr((len), 0) /** Allocate an mbuf with a length and headroom, * the buffer will have the flag UC_MBUF_FL_MALLOC_INLINE * The total length of the buffer will be length+headroom * * @param len the initial length of the mbuf * @param the initial headroom of the mbuf * @return NULL if the allocation fails */ struct MBuf *uc_mbuf_new_inline_hr(uint32_t len, uint32_t headroom); /** As uc_mbuf_new_inline_hr, but without any headroom*/ #define uc_mbuf_new_inline(len) uc_mbuf_new_inline_hr((len), 0) /** @param mbuf the mbuf to free. (passing NULL is a no-op)*/ void uc_mbuf_free(struct MBuf *mbuf); /** Create a new mbuf, with a copy of the data from the given * mbuf. The new mbuf will have the same headroom as the old one, * but no tailroom. * * @param mbuf mbuf to copy */ struct MBuf *uc_mbuf_copy_data(struct MBuf *mbuf); /** Initialize an mbuf. This function is mostly used internally, * but can be used to e.g. create an mbuf based on a local array * (in which case UC_MBUF_FL_STATIC must be set), or other data * whose memory is already allocated. * * The whole buffer must have len + headroom available data * * @param mbuf to initialise * @param buf start of the buffer * @param len length of the buffer (not including the headroom) * @param headroom the headroom in the buffer * @param flags The appropriate UC_MBUF_FLAGS */ void uc_mbuf_init(struct MBuf *mbuf, uint8_t *buf, uint32_t len, uint32_t headroom, uint32_t flags); /** Zero out all the data in this mbuf, including the headroom * * @param mbuf mbuf to zero out */ void uc_mbuf_zero(struct MBuf *mbuf); /** * @return the length of the data in this mbuf */ static UC_INLINE uint32_t uc_mbuf_len(struct MBuf *mbuf) { return (uint32_t)(mbuf->tail - mbuf->head); } /** * @return the length of the tailroom in this mbuf */ static UC_INLINE uint32_t uc_mbuf_tailroom(struct MBuf *mbuf) { return mbuf->allocated - (uint32_t)(mbuf->tail - mbuf->bufstart); } /** * @return the length of the headroom in this mbuf */ static UC_INLINE uint32_t uc_mbuf_headroom(struct MBuf *mbuf) { return (uint32_t)(mbuf->head - mbuf->bufstart); } /** Append data data to this buffer * The returned pointer points at the end of the current * data in the buffer, advancing the tail be size bytes . * You need to insert the size bytes at in the returned pointer. * * @param size bytes to put in the buffer * @return NULL if the mbuf does not have room for the given size */ uint8_t *uc_mbuf_put(struct MBuf *mbuf, uint32_t size); /** Prepend data to the buffer. The buffer needs to have enough * headroom to allow this. * The returned pointer points size bytes in front if the current * data in the buffer, retreating the head pointer by size butes * You need to insert the size bytes in the returned pointer. * * @oaram size bytes to prepend to the buffer * @return NULL if the mbuf does not have enough headroom */ uint8_t *uc_mbuf_push(struct MBuf *mbuf, uint32_t size); /** Remove data from the buffer ("read" data from it) * The returned pointer is the beginning of the data in the * buffer, advancing the head by size bytes. * * @param size number of bytes to pull * @return NULL if the buffer does not have at least size bytes **/ uint8_t *uc_mbuf_pull(struct MBuf *mbuf, uint32_t size); /** Add more tailroom to an mbuf. * Can only be done with mbufs with either * UC_MBUF_FL_MALLOC or UC_MBUF_FL_MALLOC_BUF. * * @param len additional tailroom to add to mbuf * @return 0 on success, otherwise failure * */ int uc_mbuf_extend_tailroom(struct MBuf *mbuf, uint32_t len); /** Get a pointer to the data of the buffer * * @return pointer to the start of the data (head) */ static UC_INLINE uint8_t *uc_mbuf_head(struct MBuf* mbuf) { return mbuf->head; } #undef UC_INLINE #endif