TCP/IP协议栈lwip的移植

时间:2021-07-22 16:20:34

新建几个头文件

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都可以了,不过每个结构上都要修改一下,这个是黑郁闷黑郁闷啊

 

 

 

 

“轻量级”保护

 "lightweight" synchronization mechanisms -

   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 "fast" protect. This could be implemented by

 * 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

 * "lev". This macro will default to calling the sys_arch_protect() 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_PROTECT(lev) lev = sys_arch_protect()

/** SYS_ARCH_UNPROTECT

 * Perform a "fast" set of the protection level to "lev". This could be

 * implemented by setting the interrupt level to "lev" within the MACRO or by

 * 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 "snmp_ifType" enum from snmp.h) */

  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, ("ethernetif_input: IP input error\n"));

       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("netif != NULL", (netif != NULL));

   

  ethernetif = mem_malloc(sizeof(struct ethernetif));

  if (ethernetif == NULL) {

    LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));

    return ERR_MEM;

  }

 

#if LWIP_NETIF_HOSTNAME

  /* Initialize interface hostname */

  netif->hostname = "lwip";

#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 "len"

     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 "standard" ones required

 * 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(34)的结果都是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