TCPIP协议栈lwip的移植
更新时间:2024-01-23 16:50:01 阅读量: 教育文库 文档下载
- lwip协议栈移植推荐度:
- 相关推荐
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
正在阅读:
TCPIP协议栈lwip的移植01-23
八年级地理下册期末试题(内涵3套试题)06-04
初中物理中考知识点概要简单机械和功修订版04-14
试卷101-01
住宅区车库安全管理系统 - 图文01-05
项目办公室安全生产责任制度08-18
中山细胞生物学习题03-14
胶体-导学案及习题05-05
能力水平方面存在的问题及整改措施07-30
《植树节》大班教案(6篇)03-25
- exercise2
- 铅锌矿详查地质设计 - 图文
- 厨余垃圾、餐厨垃圾堆肥系统设计方案
- 陈明珠开题报告
- 化工原理精选例题
- 政府形象宣传册营销案例
- 小学一至三年级语文阅读专项练习题
- 2014.民诉 期末考试 复习题
- 巅峰智业 - 做好顶层设计对建设城市的重要意义
- (三起)冀教版三年级英语上册Unit4 Lesson24练习题及答案
- 2017年实心轮胎现状及发展趋势分析(目录)
- 基于GIS的农用地定级技术研究定稿
- 2017-2022年中国医疗保健市场调查与市场前景预测报告(目录) - 图文
- 作业
- OFDM技术仿真(MATLAB代码) - 图文
- Android工程师笔试题及答案
- 生命密码联合密码
- 空间地上权若干法律问题探究
- 江苏学业水平测试《机械基础》模拟试题
- 选课走班实施方案
- 移植
- 协议
- TCPIP
- lwip
- 诺贝尔科学奖的启迪对屠呦呦获得诺奖的感想
- 现代汉语(下)习题集
- 四川省成都市2009级高中语文“一诊”作文详解
- 2018-2024年中国光催化剂行业市场发展现状及投资前景预测报告
- PEP小学英语五年级上册教学计划及进度表(表格式)
- 2016年12月超星慕课大学生公民素质教育期末考试答案
- 仁爱版 初一英语 七年级全册下册教案 第二学期全套教学设计
- 因数倍数应用题
- 十公司车辆驾驶员安全知识考试题-答案
- MAXIMO - V7.1.0 安装文档(WebSphere发布)
- 桩基础工程施工方案
- PADS2007 - 教程之PADS LAYOUT
- 北京科技大学微机原理实验报告
- 初一年级上学期 期末试卷
- 中国果蔬食品罐头行业市场前景分析预测报告(目录) - 图文
- 关于事业单位资产管理系统(固定资产卡片系统)
- 年加工100万吨玉米、玉米生产及玉米系列开发动态提取SOD1万吨项目可行性报告
- 大理石托项目可行性研究报告(目录) - 图文
- 高教版分析化学课后习题答案第4至7章
- 前景基础英语综合教程教师用书(复旦第四册)