netif结构体
在 lwip 中,通过netif 来描述一个网卡,LwIP 提供统一的接口,但是底层的实现需要用户自己去完成,比如网卡的初始化, 网卡的收发数据,当 LwIP 底层得到了网络的数据之后,才会传入内核中去处理;同理, LwIP 内核需要发送一个数据包的时候,也需要调用网卡的发送函数,这样子才能把数据从硬件接口到软件内核无缝连接起来。
简化后的 netif 数据结构如下:
struct netif
{
struct netif* next; //指向下一个netif
ip_addr_t ip_addr; //ip 地址
ip_addr_t netmask; //子网掩码
ip_addr_t gw; //网关
netif_input_fn input; //此函数由网络设备驱动程序调用,将数据包传递到 TCP/IP 协议栈。对于以太网物理层,这通常是 ethernet_input()
netif_output_fn output; //由ip 层调用,在接口上发送数据包:首先解析硬件地址,然后发送数据包,通常是 etharp_output()
netif_linkoutput_fn linkoutput; //链路层底层发送函数,调用自定义 low_level_output
netif_status_callback_fn status_callback; //当 netif 状态设置为 up 或 down 时调用此函数
netif_status_callback_fn link_callback; //当 netif 链接设置为 up 或 down 时,将调用此函数
netif_status_callback_fn remove_callback; //当 netif 被删除时调用此函数
void* state; //此字段可由设备驱动程序设置并指向设备的状态信息,自由发挥,可以不用
char* hostname; //netif主机名,NULL也是一个有效值
u16_t mtu; //最大传输单位,一般设为1500
u8_t hwaddr_len; //硬件地址长度,对于以太网就是 MAC 地址长度,为 6 字节
u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; //网卡硬件地址
u8_t flags; //网卡状态信息标志位:包括网卡功能使能、广播使能、 ARP 使能等等重要控制位
char name[2]; //每一个网卡的名字,用两个字符的名字来标志网络接口使用的设备驱动的种类
u8_t num; //用来标示使用同种驱动类型的不同网卡
/* List of packets to be queued for ourselves. */
struct pbuf* loop_first; //回环测试用使用
struct pbuf* loop_last;
};
在netif 结构体中,注意三个函数指针:
1、input:该函数由网络设备驱动程序调用,将数据包传递到 TCP/IP 协议栈(IP 层) 。 对于以太网物理层,这通常是ethernet_input(), 参数为 pbuf 和 netif 类型,其中 pbuf 为接收到的数据包。
2、output :也是一个函数指针, 指向一个函数, 此函数由 IP 层调用,在接口上发送数据包,该函数通常是 etharp_output(),参数为 pbuf、 netif 和 ip_addr 类型。
3、linkoutput :链路层的数据输出函数,由 etharp_output() 调用最终在链路层发送数据。
4、flags:网卡状态信息标志位,指示网卡的状态,当有些功能如:广播、组播等功能无法实现时,有可能是网卡状态信息标志位未设置。
netif使用
想要使用netif ,首先需要根据我们的网卡定义一个netif 结构体变量 struct netif gnetif,我们首先通过调用netif_add() 把网卡挂载到netif_list链表上。
netif_add() 函数原型,删减版:
struct netif *
netif_add(struct netif *netif,
const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw,
void *state, netif_init_fn init, netif_input_fn input)
{
#if LWIP_IPV4
if (ipaddr == NULL) {
ipaddr = ip_2_ip4(IP4_ADDR_ANY); //若传入的ip 地址为空,则将ip、子网掩码、网关设置为 IP4_ADDR_ANY
}
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); //相关字段清0
ip_addr_set_zero_ip4(&netif->netmask);
ip_addr_set_zero_ip4(&netif->gw);
netif->output = netif_null_output_ip4;
#endif /* LWIP_IPV4 */
NETIF_SET_CHECKSUM_CTRL(netif, 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 /* LWIP_NUM_NETIF_CLIENT_DATA */
#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 LWIP_IPV6 && LWIP_IPV6_MLD
netif->mld_mac_filter = NULL;
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
#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; //根据传递进来的参数填写网卡 state、 input 等字段的相关信息
NETIF_RESET_HINTS(netif);
#if LWIP_IPV4
netif_set_addr(netif, ipaddr, netmask, gw); //设置网卡IP地址、子网掩码、网关等信息
#endif /* LWIP_IPV4 */
/* call user specified initialization function for netif */
if (init(netif) != ERR_OK) { //通过传递进来的回调函数 init() 进行网卡真正的初始化操作,由用户实现
return NULL;
}
#if !LWIP_SINGLE_NETIF
/* Assign a unique netif number in the range [0..254], so that (num+1) can
serve as an interface index that fits in a u8_t.
We assume that the new netif has not yet been added to the list here.
This algorithm is O(n^2), but that should be OK for lwIP.
*/
{
struct netif *netif2;
int num_netifs;
do {
if (netif->num == 255) {
netif->num = 0;
}
num_netifs = 0;
for (netif2 = netif_list; netif2 != NULL; netif2 = netif2->next) {
LWIP_ASSERT("netif already added", netif2 != netif);
num_netifs++;
LWIP_ASSERT("too many netifs, max. supported number is 255", num_netifs <= 255);
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);
}
/* add this netif to the list */
netif->next = netif_list;
netif_list = netif; //插入当前的网卡
#endif /* "LWIP_SINGLE_NETIF */
mib2_netif_added(netif);
#if LWIP_IGMP
/* start IGMP processing */
if (netif->flags & NETIF_FLAG_IGMP) {
igmp_start(netif);
}
#endif /* LWIP_IGMP */
LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP",
netif->name[0], netif->name[1]));
#if LWIP_IPV4
LWIP_DEBUGF(NETIF_DEBUG, (" addr "));
ip4_addr_debug_print(NETIF_DEBUG, ipaddr);
LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));
ip4_addr_debug_print(NETIF_DEBUG, netmask);
LWIP_DEBUGF(NETIF_DEBUG, (" gw "));
ip4_addr_debug_print(NETIF_DEBUG, gw);
#endif /* LWIP_IPV4 */
LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_ADDED, NULL);
return netif;
}
netif_add() 函数使用:
在lwip 初始化时,调用 netif_add() 函数如下:
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, &tcpip_input);
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, &tcpip_input);
/* Registers the default network interface */
netif_set_default(&gnetif);
if (netif_is_link_up(&gnetif))
{
/* When the netif is fully configured this function must be called */
netif_set_up(&gnetif);
}
else
{
/* When the netif link is down this function must be called */
netif_set_down(&gnetif);
}
注:新挂载的网卡会在链表的最前面。