/* * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include /* * Generally, an mbuf is a header for a buffer which adds some useful functionality with regards to * grouping multiple distinct buffers together into a single packet. They are primarily used for * networking. As you go down a tradditional network stack, headers need to be added to the data. * Rather than having to allocate and copy every time a new header needs to be added, or forcing the * upper layer to leave room for the header, mbufs allows for buffers to be chained together into an * mbuf chain. With mbufs, as you go down the stack, you simply add the headers as new mbufs at the * start of the chain. Then, the lowest layer can simply walk through the chain to get the content * of the entire packet, and no copying is necessary at any point in the process. Going up the stack * works the same way, except that MBufs are removed as you go up the stack instead of added. * * This is a very basic implementation of the mbuf type found in FreeBSD. If you're interested in * learning more about real mbufs, the FreeBSD man page is a good read: * https://www.freebsd.org/cgi/man.cgi?query=mbuf&sektion=9 * * For the purposes of this implementation, MBuf headers are of a fixed size with a single pointer * to the data which the header is responsible for. Linking multiple MBuf chains together is not * supported. */ //! Helper macro for clearing an MBuf #define MBUF_EMPTY ((MBuf){ 0 }) //! Flags used by consumers of MBufs (bits 0-23 are allocated for this purpose) #define MBUF_FLAG_IS_FRAMING ((uint32_t)(1 << 0)) //! Consumers of MBufs which use mbuf_get() should add an enum value and add the maximum number of //! MBufs which may be allocated for that pool to the MBUF_POOL_MAX_ALLOCATED array within mbuf.c. typedef enum { MBufPoolSmartstrap, #if UNITTEST MBufPoolUnitTest, #endif NumMBufPools } MBufPool; typedef struct MBuf { //! The next MBuf in the chain struct MBuf *next; //! A pointer to the data itself void *data; //! The length of the data uint32_t length; //! Flags which are used by the consumers of MBufs uint32_t flags; } MBuf; //! Initializes the MBuf code (called from main.c) void mbuf_init(void); //! Returns a new heap-allocated MBuf (either from an internal pool or by allocating a new one) MBuf *mbuf_get(void *data, uint32_t length, MBufPool pool); //! Frees an MBuf which was created via mbuf_get() void mbuf_free(MBuf *m); //! Sets the data and length fields of an MBuf void mbuf_set_data(MBuf *m, void *data, uint32_t length); //! Returns the data for the MBuf void *mbuf_get_data(MBuf *m); //! Returns whether or not the specified flag is set bool mbuf_is_flag_set(MBuf *m, uint32_t flag); //! Sets the specified flag to the specified value void mbuf_set_flag(MBuf *m, uint32_t flag, bool is_set); //! Gets the next MBuf in the chain MBuf *mbuf_get_next(MBuf *m); //! Gets the length of the specified MBuf (NOT the entire chain) uint32_t mbuf_get_length(MBuf *m); //! Gets the total number of bytes in the MBuf chain uint32_t mbuf_get_chain_length(MBuf *m); //! Appends a new MBuf chain to the end of the chain void mbuf_append(MBuf *m, MBuf *new_mbuf); //! Removes any MBufs in the chain after the specified one void mbuf_clear_next(MBuf *m); //! Dump an MBuf chain to dbgserial void mbuf_debug_dump(MBuf *m);