TCPIP协议栈lwip的移植

更新时间:2024-01-23 16:50:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

TCP/IP协议栈lwip的移植

新建几个头文件

Include/lwipopts.h

Include/arch/cc.h

Include/arch/perf.h

Include/arch/sys_arch.h

除头文件外还需要添加一个C文件:sys_arch.c。

说明在doc/sys_arch.txt中。

修改netif/Ethernetif.c。

结构对齐的几个宏

对于一个结构下载下来的LWIP的通用定义如下: PACK_STRUCT_BEGIN struct icmp_echo_hdr { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t code); PACK_STRUCT_FIELD(u16_t chksum); PACK_STRUCT_FIELD(u16_t id); PACK_STRUCT_FIELD(u16_t seqno); } PACK_STRUCT_STRUCT; PACK_STRUCT_EN #define PACK_STRUCT_FIELD(x) 这个宏是为了字节序的转换,由于是用的小端,就不用转换了直接定义为#define PACK_STRUCT_FIELD(x) x #define PACK_STRUCT_STRUCT #define PACK_STRUCT_BEGIN #define PACK_STRUCT_END 以上三个宏都是为了做结构体对齐用: 对于gcc的编译器在结构体后跟个关键字就ok struct ip_hdr { } ;__attribute__ ((__packed__)) 因此可以定义为 #define PACK_STRUCT_STRUCT __attribute__ ((__packed__)) #define PACK_STRUCT_BEGIN #define PACK_STRUCT_END 对于vc的编译器就郁闷了,vc做结构体对齐是这样做的 #pragma pack(1) //结构体按照1字节对齐 struct ip_hdr { } ; #pragma pack() //结构体按照编译器默认值对齐 但是VC的编译器不允许将预处理做为宏,也就是不允许这种宏替代#define PACK_STRUCT_BEGIN #pragma pack(1) 所以想靠宏替换来完成字节对齐是不行了,于是就动了大工夫做了如下处理 #ifdef WIN32 #define PACK_STRUCT_STRUCT #define PACK_STRUCT_BEGIN #define PACK_STRUCT_END #else #define PACK_STRUCT_STRUCT __attribute__ ((__packed__)) #define PACK_STRUCT_BEGIN #define PACK_STRUCT_END endif PACK_STRUCT_BEGIN #ifdef WIN32 #pragma pack(1) #endif struct icmp_echo_hdr { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t code); PACK_STRUCT_FIELD(u16_t chksum); PACK_STRUCT_FIELD(u16_t id); PACK_STRUCT_FIELD(u16_t seqno); } PACK_STRUCT_STRUCT; #ifdef WIN32 #pragma pack() #endif PACK_STRUCT_END 这样一改在VC下和GCC都可以了,不过每个结构上都要修改一下,这个是黑郁闷黑郁闷啊

“轻量级”保护

\

SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.

SYS_ARCH_PROTECT(x) - enterprotection mode.

SYS_ARCH_UNPROTECT(x) - leaveprotection mode.

这三个宏定义一个快速的“保护”和“解除保护”操作。例如进入保护可以是屏蔽中断或使用一个信号量或mutex。注意:进入保护后还允许再次进入保护,旧的保护标志通过lev返回,退出保护时再恢复。

如果没有定义这三个宏,Sys.h中有一段代码进行了判断。

#ifndef SYS_ARCH_PROTECT 如果没有定义SYS_ARCH_PROTECT,那么可以在lwipopts.h中定义宏SYS_LIGHTWEIGHT_PROT,并在sys_arch.c中定义函数sys_arch_protect()和sys_arch_unprotect(lev) #if SYS_LIGHTWEIGHT_PROT #define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev /** SYS_ARCH_PROTECT * Perform a \ * disabling interrupts for an embedded system or by using a semaphore or * mutex. The implementation should allow calling SYS_ARCH_PROTECT when * already protected. The old protection level is returned in the variable * \ * which should be implemented in sys_arch.c. If a particular port needs a * different implementation, then this macro may be defined in sys_arch.h */ #define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect() /** SYS_ARCH_UNPROTECT * Perform a \ * implemented by setting the interrupt level to \ * using a semaphore or mutex. This macro will default to calling the * sys_arch_unprotect() function which should be implemented in * sys_arch.c. If a particular port needs a different implementation, then * this macro may be defined in sys_arch.h */ #define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev) sys_prot_t sys_arch_protect(void); void sys_arch_unprotect(sys_prot_t pval); #else #define SYS_ARCH_DECL_PROTECT(lev) #define SYS_ARCH_PROTECT(lev) #define SYS_ARCH_UNPROTECT(lev) #endif /* SYS_LIGHTWEIGHT_PROT */ #endif /* SYS_ARCH_PROTECT */

LWIP_COMPAT_MUTEX

定义此宏表示用信号量来代替mutex。

Init.c

不定义NO_SYS和“#define NO_SYS 0”的效果是一样的。

下面这些宏对代码有影响:

LWIP_SOCKET

LWIP_ARP

LWIP_RAW

LWIP_UDP

LWIP_TCP

LWIP_SNMP

LWIP_AUTOIP

LWIP_IGMP

LWIP_DNS

LWIP_TIMERS

void lwip_init(void) { /* Sanity check user-configurable values */ lwip_sanity_check(); /* Modules initialization */ stats_init(); #if !NO_SYS sys_init(); #endif /* !NO_SYS */ mem_init(); memp_init(); pbuf_init(); netif_init(); #if LWIP_SOCKET lwip_socket_init(); #endif /* LWIP_SOCKET */ ip_init(); #if LWIP_ARP etharp_init(); #endif /* LWIP_ARP */ #if LWIP_RAW raw_init(); #endif /* LWIP_RAW */ #if LWIP_UDP udp_init(); #endif /* LWIP_UDP */ #if LWIP_TCP tcp_init(); #endif /* LWIP_TCP */ #if LWIP_SNMP snmp_init(); #endif /* LWIP_SNMP */ #if LWIP_AUTOIP autoip_init(); #endif /* LWIP_AUTOIP */ #if LWIP_IGMP igmp_init(); #endif /* LWIP_IGMP */ #if LWIP_DNS dns_init(); #endif /* LWIP_DNS */ #if LWIP_TIMERS sys_timeouts_init(); #endif /* LWIP_TIMERS */ }

netif_add函数

它添加一个网络接口到lwip,一个网卡应该是一个网络接口。本地回环也是一个网络接口,它已经在tcpip_init中的lwip_init调用netif_init被添加。

/** * Add a network interface to the list of lwIP netifs. * * @param netif a pre-allocated netif structure * @param ipaddr IP address for the new netif * @param netmask network mask for the new netif * @param gw default gateway IP address for the new netif * @param state opaque data passed to the new netif * @param init callback function that initializes the interface * @param input callback function that is called to pass * ingress packets up in the protocol layer stack. * * @return netif, or NULL if failed. */ struct netif * netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)

Struct net_if

在初始化用netif_add添加到lwip中。

/** Generic data structure used for all lwIP network interfaces. * The following fields should be filled in by the initialization * function for the device driver: hwaddr_len, hwaddr[], mtu, flags */ struct netif { /** pointer to next in linked list */ struct netif *next; /** IP address configuration in network byte order */ ip_addr_t ip_addr; ip_addr_t netmask; ip_addr_t gw; /** This function is called by the network device driver * to pass a packet up the TCP/IP stack. */ netif_input_fn input; // 网卡数据接收函数,自定义设置 /** This function is called by the IP module when it wants * to send a packet on the interface. This function typically * first resolves the hardware address, then sends the packet. */ netif_output_fn output; //发送无连接的数据包,如广播包,多播包,最终还是调用下面的linkoutput函数。固定设置为etharp_output。 /** This function is called by the ARP module when it wants * to send a packet on the interface. This function outputs * the pbuf as-is on the link medium. */ netif_linkoutput_fn linkoutput; //发送有连接的数据包,已经包含MAC,类型等数据。 #if LWIP_NETIF_STATUS_CALLBACK /** This function is called when the netif state is set to up or down */ netif_status_callback_fn status_callback; #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK /** This function is called when the netif link is set to up or down */ netif_status_callback_fn link_callback; #endif /* LWIP_NETIF_LINK_CALLBACK */ /** This field can be set by the device driver and could point * to state information for the device. */ void *state; //一般设置为网卡的私有数据,如netif->state = ethernetif; #if LWIP_DHCP /** the DHCP client state information for this netif */ struct dhcp *dhcp; #endif /* LWIP_DHCP */ #if LWIP_AUTOIP /** the AutoIP client state information for this netif */ struct autoip *autoip; #endif #if LWIP_NETIF_HOSTNAME /* the hostname for this netif, NULL is a valid value */ char* hostname; #endif /* LWIP_NETIF_HOSTNAME */ /** maximum transfer unit (in bytes) */ u16_t mtu; /** number of bytes used in hwaddr */ u8_t hwaddr_len; /** link level hardware address of this interface */ u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; /** flags (see NETIF_FLAG_ above) */ u8_t flags; /** descriptive abbreviation */ char name[2]; /** number of this interface */ u8_t num; #if LWIP_SNMP

/** link type (from \ u8_t link_type; /** (estimate) link speed */ u32_t link_speed; /** timestamp at last change made (up/down) */ u32_t ts; /** counters */ u32_t ifinoctets; u32_t ifinucastpkts; u32_t ifinnucastpkts; u32_t ifindiscards; u32_t ifoutoctets; u32_t ifoutucastpkts; u32_t ifoutnucastpkts; u32_t ifoutdiscards; #endif /* LWIP_SNMP */ #if LWIP_IGMP /** This function could be called to add or delete a entry in the multicast filter table of the ethernet MAC.*/ netif_igmp_mac_filter_fn igmp_mac_filter; #endif /* LWIP_IGMP */ #if LWIP_NETIF_HWADDRHINT u8_t *addr_hint; #endif /* LWIP_NETIF_HWADDRHINT */ #if ENABLE_LOOPBACK /* List of packets to be queued for ourselves. */ struct pbuf *loop_first; struct pbuf *loop_last; #if LWIP_LOOPBACK_MAX_PBUFS u16_t loop_cnt_current; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ #endif /* ENABLE_LOOPBACK */ };

struct pbuf

一个网络包可能由多个pbuf组成,字段tot_len指定这个网络包的大小,字段len是当前pbuf包含数据的大小。

判断一个网络包的最后一个包不能以next字段等于空来判断,它可能不为空,下一个pbuf为下一个网络包的内容。应该计算tot_len来判断一个包的结束。

struct pbuf { /** next pbuf in singly linked pbuf chain */ struct pbuf *next; //下一个pbuf /** pointer to the actual data in the buffer */ void *payload; // 当前结构数据内容 /** * total length of this buffer and all next buffers in chain * belonging to the same packet. * * For non-queue packet chains this is the invariant: * p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ u16_t tot_len; /** length of this buffer */ u16_t len; /** pbuf_type as u8_t instead of enum to save space */ u8_t /*pbuf_type*/ type; /** misc flags */ u8_t flags; /** * the reference count always equals the number of pointers * that refer to this pbuf. This can be pointers from an application, * the stack itself, or pbuf->next pointers from a chain. */ u16_t ref; };

Ethernetif.c

它是你要移植的网卡驱动程序与lwip连接的文件。源代码提供了一个模板。

struct ethernetif结构

它是网卡私有数据结构

struct ethernetif { struct eth_addr *ethaddr; /* Add whatever per-interface state that is needed here. */在这里添加自定义的数据 };

ethernetif_input

网卡有数据时应该调用这个函数。过程大致如下:

网卡读任务 中断处理 (1)信号量pend(等待数据到来如果有中断表明数据包到达,给“网卡读任务”中断) 发送信号量。 (2)pend成功,调用ethernetif_input (3)回到步骤1.

ethernetif_input做的工作有:

(1) 调用low_level_input读取数据包

(2) 判断数据包的以太网类型并调用netif->input。netif->input是在协议栈初始化添加的。如netif_add(mLocalNetif, &ipaddr, &netmask, &gw, NULL,ethernetif_init, tcpip_input),那么它是tcpip_input,tcpip_input做的工作发送消息给tcpip主线线程,它把数据包交给上层处理。

/** * This function should be called when a packet is ready to be read * from the interface. It uses the function low_level_input() that * should handle the actual reception of bytes from the network * interface. Then the type of the received packet is determined and * the appropriate input function is called. * * @param netif the lwip network interface structure for this ethernetif */ static void ethernetif_input(struct netif *netif) { struct ethernetif *ethernetif; struct eth_hdr *ethhdr; struct pbuf *p; ethernetif = netif->state; /* move received packet into a new pbuf */ p = low_level_input(netif); /* no packet could be read, silently ignore this */ if (p == NULL) return; /* points to packet payload, which starts with an Ethernet header */ ethhdr = p->payload; switch (htons(ethhdr->type)) { /* IP or ARP packet? */ case ETHTYPE_IP: case ETHTYPE_ARP: #if PPPOE_SUPPORT /* PPPoE packet? */ case ETHTYPE_PPPOEDISC: case ETHTYPE_PPPOE: #endif /* PPPOE_SUPPORT */ /* full packet send to tcpip_thread to process */ if (netif->input(p, netif)!=ERR_OK) { LWIP_DEBUGF(NETIF_DEBUG, (\ pbuf_free(p); p = NULL; } break; default: pbuf_free(p); p = NULL; break; }

}

ethernetif_init

在初始化协议栈时,netif_add(mLocalNetif,&ipaddr, &netmask, &gw, NULL, ethernetif_init, tcpip_input)。

ethernetif_init做的工作:

(1) 初始化struct ethernetif

(2) 初始化struct net_if

(3) 调用硬件初始化low_level_init(netif);

/** * Should be called at the beginning of the program to set up the * network interface. It calls the function low_level_init() to do the * actual setup of the hardware. * * This function should be passed as a parameter to netif_add(). * * @param netif the lwip network interface structure for this ethernetif * @return ERR_OK if the loopif is initialized * ERR_MEM if private data couldn't be allocated * any other err_t on error */ err_t ethernetif_init(struct netif *netif) { struct ethernetif *ethernetif; LWIP_ASSERT(\ ethernetif = mem_malloc(sizeof(struct ethernetif)); if (ethernetif == NULL) { LWIP_DEBUGF(NETIF_DEBUG, (\ return ERR_MEM; } #if LWIP_NETIF_HOSTNAME /* Initialize interface hostname */ netif->hostname = \#endif /* LWIP_NETIF_HOSTNAME */ /* * Initialize the snmp variables and counters inside the struct netif. * The last argument should be replaced with your link speed, in units * of bits per second. */ NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); netif->state = ethernetif; netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; /* We directly use etharp_output() here to save a function call. * You can instead declare your own function an call etharp_output() * from it if you have to do some checks before sending (e.g. if link * is available...) */ netif->output = etharp_output; netif->linkoutput = low_level_output; ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); /* initialize the hardware */ low_level_init(netif); return ERR_OK; }

low_level_init

它是网卡硬件初始化的代码。它被ethernetif_init调用。

/** * In this function, the hardware should be initialized. * Called from ethernetif_init(). * * @param netif the already initialized lwip network interface structure * for this ethernetif */ static void low_level_init(struct netif *netif) { struct ethernetif *ethernetif = netif->state; /* set MAC hardware address length */ netif->hwaddr_len = ETHARP_HWADDR_LEN; /* set MAC hardware address */ netif->hwaddr[0] = 0x00; netif->hwaddr[1] = 0x50; netif->hwaddr[2] = 0x50; netif->hwaddr[3] = 0x50; netif->hwaddr[4] = 0x50; netif->hwaddr[5] = 0x01; /* maximum transfer unit */ netif->mtu = 1500; /* device capabilities */ /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; /* Do whatever else is needed to initialize interface. */ }

low_level_output

它是实现网卡发送数据的函数。

它发送链表structpbuf中的所有数据。

在代码:

netif->linkoutput = low_level_output;

中,low_level_output被赋于netif->linkoutput。

/** * This function should do the actual transmission of the packet. The packet is * contained in the pbuf that is passed to the function. This pbuf * might be chained. * * @param netif the lwip network interface structure for this ethernetif * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) * @return ERR_OK if the packet could be sent * an err_t value if the packet couldn't be sent * * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to * strange results. You might consider waiting for space in the DMA queue * to become availale since the stack doesn't retry to send a packet * dropped because of memory failure (except for the TCP timers). */ static err_t low_level_output(struct netif *netif, struct pbuf *p) { struct ethernetif *ethernetif = netif->state; struct pbuf *q; initiate transfer(); #if ETH_PAD_SIZE pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ #endif for(q = p; q != NULL; q = q->next) { /* Send the data from the pbuf to the interface, one pbuf at a time. The size of the data in each pbuf is kept in the ->len variable. */ send data from(q->payload, q->len); } signal that packet should be sent(); #if ETH_PAD_SIZE pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif LINK_STATS_INC(link.xmit);

return ERR_OK; }

low_level_input

它是实现网卡接收数据的函数。

它由ethernetif_input调用,具体参考ethernetif_input。

/** * Should allocate a pbuf and transfer the bytes of the incoming * packet from the interface into the pbuf. * * @param netif the lwip network interface structure for this ethernetif * @return a pbuf filled with the received packet (including MAC header) * NULL on memory error */ static struct pbuf * low_level_input(struct netif *netif) { struct ethernetif *ethernetif = netif->state; struct pbuf *p, *q; u16_t len; /* Obtain the size of the packet and put it into the \ variable. */ len = ; #if ETH_PAD_SIZE len += ETH_PAD_SIZE; /* allow room for Ethernet padding */ #endif /* We allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); if (p != NULL) { #if ETH_PAD_SIZE pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ #endif /* We iterate over the pbuf chain until we have read the entire * packet into the pbuf. */ for(q = p; q != NULL; q = q->next) { /* Read enough bytes to fill this pbuf in the chain. The * available data in the pbuf is given by the q->len * variable. * This does not necessarily have to be a memcpy, you can also preallocate * pbufs for a DMA-enabled MAC and after receiving truncate it to the * actually received size. In this case, ensure the tot_len member of the * pbuf is the sum of the chained pbuf len members. */ read data into(q->payload, q->len); } acknowledge that packet has been read(); #if ETH_PAD_SIZE pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif LINK_STATS_INC(link.recv); } else { drop packet(); LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); } return p; }

有关MEM

Opt.h中的配置宏

/* ------------------------------------ ---------- Memory options ---------- ------------------------------------ */ /** * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library * instead of the lwip internal allocator. Can save code size if you * already use it. */ MEM_LIBC_MALLOC==1: 使用C库的malloc/free/realloc #ifndef MEM_LIBC_MALLOC #define MEM_LIBC_MALLOC 0 #endif /** * MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. * Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution * speed and usage from interrupts! */ #ifndef MEMP_MEM_MALLOC #define MEMP_MEM_MALLOC 0 #endif /** * MEM_ALIGNMENT: should be set to the alignment of the CPU * 4 byte alignment -> #define MEM_ALIGNMENT 4 * 2 byte alignment -> #define MEM_ALIGNMENT 2 */ 设置内存对齐 #ifndef MEM_ALIGNMENT #define MEM_ALIGNMENT 1 #endif /** * MEM_SIZE: the size of the heap memory. If the application will send * a lot of data that needs to be copied, this should be set high. */ #ifndef MEM_SIZE #define MEM_SIZE 1600 #endif /** * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array. * This can be used to individually change the location of each pool. * Default is one big array for all pools */ #ifndef MEMP_SEPARATE_POOLS #define MEMP_SEPARATE_POOLS 0 #endif /** * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable * amount of bytes before and after each memp element in every pool and fills * it with a prominent default value. * MEMP_OVERFLOW_CHECK == 0 no checking * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time * memp_malloc() or memp_free() is called (useful but slow!) */ #ifndef MEMP_OVERFLOW_CHECK #define MEMP_OVERFLOW_CHECK 0 #endif /** * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make * sure that there are no cycles in the linked lists. */ #ifndef MEMP_SANITY_CHECK #define MEMP_SANITY_CHECK 0 #endif /** * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set * of memory pools of various sizes. When mem_malloc is called, an element of * the smallest pool that can provide the length needed is returned. * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. */ #ifndef MEM_USE_POOLS #define MEM_USE_POOLS 0 #endif /** * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more * reliable. */ #ifndef MEM_USE_POOLS_TRY_BIGGER_POOL #define MEM_USE_POOLS_TRY_BIGGER_POOL 0 #endif /** * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h * that defines additional pools beyond the \ * by lwIP. If you set this to 1, you must have lwippools.h in your * inlude path somewhere. */ #ifndef MEMP_USE_CUSTOM_POOLS #define MEMP_USE_CUSTOM_POOLS 0 #endif /** * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from * interrupt context (or another context that doesn't allow waiting for a * semaphore). * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs * with each loop so that mem_free can run. * * ATTENTION: As you can see from the above description, this leads to dis-/

* enabling interrupts often, which can be slow! Also, on low memory, mem_malloc * can need longer. * * If you don't want that, at least for NO_SYS=0, you can still use the following * functions to enqueue a deallocation call which then runs in the tcpip_thread * context: * - pbuf_free_callback(p); * - mem_free_callback(m); */ #ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT #define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 #endif

Mem.h中的几个宏、

/** Calculate memory size for an aligned buffer - returns the next highest * multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and * LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4). */ 计算内存对齐状态下size的实际大小。例如4字节对齐时,MEM_ALIGNMENT = 4,这时LWIP_MEM_ALIGN_SIZE(3或4)的结果都是4 #ifndef LWIP_MEM_ALIGN_SIZE #define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1)) #endif /** Calculate safe memory size for an aligned buffer when using an unaligned * type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the * start (e.g. if buffer is u8_t[] and actual data will be u32_t*) */ 当申请一个内存大小时,假如当前是4字节对齐,要申请3个字节的空间,但使用过程中地址要对齐,为使用对齐的地址仍然在安全地址空间,申请的内存大小要在一个安全范围内。 #ifndef LWIP_MEM_ALIGN_BUFFER #define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1)) #endif /** Align a memory pointer to the alignment defined by MEM_ALIGNMENT * so that ADDR % MEM_ALIGNMENT == 0 */ 当一个内存不对齐时,返回一个对齐的内存地址(不对齐时,去掉不对齐的空间,取得的对齐地址大于参数ADDR) #ifndef LWIP_MEM_ALIGN #define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) #endif

本文来源:https://www.bwwdw.com/article/p86o.html

Top