本文论述的网络接口属于链路层的范畴。运行LwIP的嵌入式设备可以有很多个网络接口,这些网络接口的种类可以互不相同。有效的管理这些网络接口就显得尤为必要。
在netif.h和netif.c文件中定义和实现了所有的和网络接口相关的数据结构和函数,接下来我们看下在netif.h文件中定义的netif结构类型,nitif结构描述了网络接口所有的属性。
netif.h文件中的部分定义:
#define NETIF_MAX_HWADDR_LEN 6U //网卡的物理地址长度
/*为netif结构体中flags的标志位*/
#define NETIF_FLAG_UP 0x01U //网络接口是否被上层使用
#define NETIF_FLAG_BROADCAST 0x02U //网络接口是否支持广播
#define NETIF_FLAG_POINTTOPOINT 0x04U //网络接口是否属于点到点连接
#define NETIF_FLAG_DHCP 0x08U //网络接口是否支持DHCP功能
#define NETIF_FLAG_LINK_UP 0x10U //网络接口底层链路是否已经使用
#define NETIF_FLAG_ETHARP 0x20U //网络接口是否支持ARP功能
#define NETIF_FLAG_ETHERNET 0x40U
#define NETIF_FLAG_IGMP 0x80U //网络接口是否IGMP 功能
//定义几个函数指针
typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p);
typedef void (*netif_status_callback_fn)(struct netif *netif);
typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif,ip_addr_t *group, u8_t action);
netif结构体定义(已去掉部分条件编译):
struct netif {
struct netif *next; //指向下一个netif结构,在构成netif_list时使用
/** IP address configuration in network byte order */
ip_addr_t ip_addr; //IP地址
ip_addr_t netmask; //子网掩码
ip_addr_t gw; //网关地址
netif_input_fn input; //该函数向IP层输入数据包netif_output_fn output; //该函数发送IP层的数据包
netif_linkoutput_fn linkoutput; //ARP调用,实现底层数据包发送
void *state; //指向用户信息区(可以不用)
u16_t mtu; //改接口允许的最大数据包长度
u8_t hwaddr_len; //该接口的物理地址长度
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 ENABLE_LOOPBACK
/* List of packets to be queued for ourselves. */
struct pbuf *loop_first; //指向发送给自己的第一个数据包
struct pbuf *loop_last; //指向发送给自己的最后个数据包
};
我们可以看到,netif结构基本上包含了网络接口所有的特性,虽然看起来很复杂,其实在使用的时候很多东西都用不上。
上面介绍了网络接口的数据结构,接下来我们看下网络接口管理的相关函数。在netif.c文件中定义了这样几个非常重要的函数。
(1)网络接口注册函数
//函数功能:向LwIP内核注册一个网络接口结构
//参数netif:指向一个已经定义好的netif结构
//参数ipaddr:指向接口的IP地址
//参数netmask:接口的子网掩码
//参数gw:网关地址
//参数state:用户自定义一些数据
//参数init:网络接口的初始化函数
//参数input:网络接口向IP层发送数据包的函数
//返回值:成功注册的网络接口指针,失败为NULL
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);
需要注意的是, init函数是你的网络接口初始化函数,它会调用你自己写的网卡驱动初始化函数,写这个网络接口初始化函数的目的事为了统一标准,因为每一个网卡驱动函数不一样。
源码:
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)
{
LWIP_ASSERT("No init function given", init != NULL);
/* reset new interface configuration state */
ip_addr_set_zero(&netif->ip_addr);
ip_addr_set_zero(&netif->netmask);
ip_addr_set_zero(&netif->gw);
#if LWIP_DHCP
/* netif not under DHCP control by default */
netif->dhcp = NULL;
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
/* netif not under AutoIP control by default */
netif->autoip = NULL;
#endif /* LWIP_AUTOIP */
#if LWIP_NETIF_STATUS_CALLBACK
netif->status_callback = NULL;
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_LINK_CALLBACK
netif->link_callback = NULL;
#endif /* LWIP_NETIF_LINK_CALLBACK */
#if LWIP_IGMP
netif->igmp_mac_filter = NULL;
#endif /* LWIP_IGMP */
#if ENABLE_LOOPBACK
netif->loop_first = NULL;
netif->loop_last = NULL;
#endif /* ENABLE_LOOPBACK */
/* remember netif specific state information data */
netif->state = state;
netif->num = netif_num++;
netif->input = input;
NETIF_SET_HWADDRHINT(netif, NULL);
#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
netif->loop_cnt_current = 0;
#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
netif_set_addr(netif, ipaddr, netmask, gw);
/* call user specified initialization function for netif */
if (init(netif) != ERR_OK) {
return NULL;
}