网络接口
网络接口(以太网)是硬件接口,LwIP是软件,并且网卡也是由很多种的
LwIP使用一个数据结构,nitif来描述网卡
用户提供最底层的接口函数,LwIP则提供统一的接口,这样用户根据网卡不同提供底层接口,上层则不需要改变
ethernetif.c文件提供了netif访问不同的网卡,每个网卡有不同的实现方式,用户仅仅修改ethernetif文件即可
单网卡中,netif结构体只有一个;多网卡设备中,LwIP将每个用netif描述的网卡连接成一个单项链表
网卡结构体
struct netif
{
#if !LWIP_SINGLE_NETIF
struct netif *next; //指向下一个节点,通过next指针遍历链表
#endif
#if LWIP_IPV4
ip_addr_t ip_addr; // ip地址,与网卡对应,多个网卡 即 多个ip地址
ip_addr_t netmask; // 子网掩码,判断IP与网卡是否在一个子网,IP发送数据包会选择与目标IP在一个子网的网卡
ip_addr_t gw; // 向不同子网的主机发送数据包,数据包先发送到网关,网关对数据包进行转发
#endif
netif_input_fn input; // 数据包递交到IP层 回调函数 ,对于物理层,一般赋值为 ethernet_input
#if LWIP_IPV4
netif_output_fn output; // IP层调用,发送数据包;先解析地址,再发送;物理层一般赋值为 etharp_output
#endif
netif_linkoutput_fn linkoutput; // 被函数 ethernet_output 调用,网卡发送数据包,底层硬件输出数据函数
#if LWIP_NETIF_STATUS_CALLBACK
netif_status_callback_fn status_callback; // netif状态为up/down时,调用这个函数
#endif
#if LWIP_NETIF_LINK_CALLBACK
netif_status_callback_fn link_callback; // netif链接为up/down时,调用这个函数
#endif
#if LWIP_NETIF_REMOVE_CALLBACK
netif_status_callback_fn remove_callback; // netif 被删除时,调用这个函数
#endif
void *state; // 由设备驱动程序设置,指向设备状态信息,将网卡的私有信息传递给上层
#ifdef netif_get_client_data
void* client_data[LWIP_NETIF_CLIENT_DATA_INDEX_MAX + LWIP_NUM_NETIF_CLIENT_DATA];
#endif
#if LWIP_NETIF_HOSTNAME
const char* hostname; // netif 的主机名,NULL也是有效值
#endif
#if LWIP_CHECKSUM_CTRL_PER_NETIF
u16_t chksum_flags;
#endif
u16_t mtu; // 最大传输字节,一般以太网设置为 1500
u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; // 网卡的链路层硬件地址,MAC地址
u8_t hwaddr_len; // MAC地址长度,一般是6个人字节
u8_t flags; // 网卡状态标志位,包括网卡功能,广播,ARP使能等控制位
char name; // 保存网卡的名字,表示网卡种类,蓝牙bt,WLAN wl,同名使用num区分
u8_t num; // 用来标示使用同种驱动类型的不同网卡
#if MIB2_STATS
u8_t link_type; // 连接类型
u32_t link_speed; // 连接速度
u32_t ts; // 最后一次更改的时间戳
struct stats_mib2_netif_ctrs mib2_counters;
#endif
#if LWIP_IPV4 && LWIP_IGMP
netif_igmp_mac_filter_fn igmp_mac_filter; // 调用这个函数来添加或删除多播中的条目,以太网的MAC过滤表
#endif
#if LWIP_NETIF_USE_HINTS
struct netif_hint *hints;
#endif
#if ENABLE_LOOPBACK
struct pbuf *loop_first;
struct pbuf *loop_last;
#if LWIP_LOOPBACK_MAX_PBUFS
u16_t loop_cnt_current;
#endif
#endif
};
使用
netif只定义了类型,使用时需要用户自行定义对应变量
在定义变量之后,将网卡挂载到链表中,通过 netif_add 函数
只要添加了新网卡,都需要通过函数 netif_add 将网卡挂载到网卡链表中
#define ip_addr_set_zero_ip4(ipaddr) ip4_addr_set_zero(ipaddr)
#define ip4_addr_set_zero(ipaddr) ((ipaddr)->addr = 0)
struct netif * netif_add( struct netif *netif, // 网卡结构体
#if LWIP_IPV4
const ip4_addr_t *ipaddr, // ip地址
const ip4_addr_t *netmask, // 子网掩码
const ip4_addr_t *gw, // 网关地址
#endif
void *state, // 网卡状态
netif_init_fn init, // 网卡初始化函数
netif_input_fn input) //
{
#if LWIP_IPV4
if (ipaddr == NULL)
{
ipaddr = ip_2_ip4(IP4_ADDR_ANY); // ipaddr = (&((IP4_ADDR_ANY)->u_addr.ip4))
}
if (netmask == NULL)
{
netmask = ip_2_ip4(IP4_ADDR_ANY);
}
if (gw == NULL)
{
gw = ip_2_ip4(IP4_ADDR_ANY);
}
ip_addr_set_zero_ip4(&netif->ip_addr); // ip地址置零
ip_addr_set_zero_ip4(&netif->netmask); // 子网掩码置零
ip_addr_set_zero_ip4(&netif->gw); // 网关置零
netif->output = netif_null_output_ip4; // 回调函数赋值
#endif
#if LWIP_IPV6
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) // IPV6相关数据清零
{
ip_addr_set_zero_ip6(&netif->ip6_addr[i]);
netif->ip6_addr_state[i] = IP6_ADDR_INVALID;
#if LWIP_IPV6_ADDRESS_LIFETIMES
netif->ip6_addr_valid_life[i] = IP6_ADDR_LIFE_STATIC;
netif->ip6_addr_pref_life[i] = IP6_ADDR_LIFE_STATIC;
#endif
}
netif->output_ip6 = netif_null_output_ip6;
#endif
NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL); // (netif)->chksum_flags = NETIF_CHECKSUM_ENABLE_ALL
netif->mtu = 0; // 底层最大传输量清零,标志位清零
netif->flags = 0;
#ifdef netif_get_client_data
memset(netif->client_data, 0, sizeof(netif->client_data)); // 客户端数据清零
#endif
#if LWIP_IPV6
#if LWIP_IPV6_AUTOCONFIG
netif->ip6_autoconfig_enabled = 0;
#endif
nd6_restart_netif(netif);
#endif
#if LWIP_NETIF_STATUS_CALLBACK
netif->status_callback = NULL;
#endif
#if LWIP_NETIF_LINK_CALLBACK
netif->link_callback = NULL;
#endif
#if LWIP_IGMP
netif->igmp_mac_filter = NULL;
#endif
#if LWIP_IPV6 && LWIP_IPV6_MLD
netif->mld_mac_filter = NULL;
#endif
#if ENABLE_LOOPBACK
netif->loop_first = NULL;
netif->loop_last = NULL;
#endif
netif->state = state; // 相关数据赋值,填写网卡state,input字段
netif->num = netif_num;
netif->input = input; // 赋值为 tcpip_input
NETIF_RESET_HINTS(netif);
#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
netif->loop_cnt_current = 0;
#endif
#if LWIP_IPV4
netif_set_addr(netif, ipaddr, netmask, gw); // 设置ip信息,子网掩码,网关
#endif
if (init(netif) != ERR_OK) // 通过回调函数对网卡进行初始化,一般由用户实现,ethernetif_init 函数
{ // 或者调用函数
return NULL;
}
#if LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES
netif->mtu6 = netif->mtu;
#endif
#if !LWIP_SINGLE_NETIF // 支持多网卡
{
struct netif *netif2;
int num_netifs;
do {
if (netif->num == 255) // 遍历网卡链表
{
netif->num = 0;
}
num_netifs = 0; // 网卡数量为0,从首字节开始遍历链表
for (netif2 = netif_list; netif2 != NULL; netif2 = netif2->next)
{
num_netifs++; // 只要链表next指针不为空,一直移动next指针
if (netif2->num == netif->num) //
{
netif->num++;
break;
}
}
} while (netif2 != NULL);
}
if (netif->num == 254)
{
netif_num = 0;
}
else
{
netif_num = (u8_t)(netif->num + 1); // 计算携带有多少网卡
}
netif->next = netif_list; // next 指针指向 netif_list
netif_list = netif;
#endif
mib2_netif_added(netif); // 网卡挂载到链表中
#if LWIP_IGMP
if (netif->flags & NETIF_FLAG_IGMP) // 网卡状态为 0x20
{
igmp_start(netif);
}
#endif
#if LWIP_IPV4
ip4_addr_debug_print(NETIF_DEBUG, ipaddr);
ip4_addr_debug_print(NETIF_DEBUG, netmask);
ip4_addr_debug_print(NETIF_DEBUG, gw);
#endif
netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_ADDED, NULL);
return netif;
}