協議棧內部使用netif的結構體來描述網絡接口,先來看一下這個結構體。
/* netif結構體 */
struct netif {
struct netif *next; //用於將netif連接成鏈表
/* IP地址、子網掩碼、網關地址 */
struct ip_addr ip_addr;
struct ip_addr netmask;
struct ip_addr gw;
/* 向IP層輸入數據包 */
err_t (* input)(struct pbuf *p, struct netif *inp);
/* 發送IP層數據包(先通過ARP查找目的MAC,再調用linkoutput) */
err_t (* output)(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr);
/* 底層數據包發送 */
err_t (* linkoutput)(struct netif *netif, struct pbuf *p);
/* 用戶字段 */
void *state;
/* 最大允許數據包長度 */
u16_t mtu;
/* 物理MAC地址 */
u8_t hwaddr_len;
u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
u8_t flags; //標誌位
char name[2]; //網絡接口名字
u8_t num; //網路接口編號
};
關於標誌位的定義如下
/* 網絡接口標誌位 */
#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_IGMP 0x40U /* 網絡接口是否支持IGMP功能 */
LwIP最終會將所有網絡接口組織成一個鏈表
/* 網絡接口鏈表 */
struct netif *netif_list;
netif_add函數用於向協議棧添加一個網絡接口
/* 添加一個網絡接口到鏈表 */
struct netif *netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, struct ip_addr *gw, void *state, err_t (* init)(struct netif *netif), err_t (* input)(struct pbuf *p, struct netif *netif))
{
static u8_t netifnum = 0;
/* 清空網路接口成員 */
netif->ip_addr.addr = 0;
netif->netmask.addr = 0;
netif->gw.addr = 0;
netif->flags = 0;
/* 設置用戶數據 */
netif->state = state;
/* 設置網絡接口編號 */
netif->num = netifnum++;
/* 設置接收回調函數 */
netif->input = input;
/* 設置IP地址、子網掩碼、網關地址 */
netif_set_addr(netif, ipaddr, netmask, gw);
/* 調用參數提供的init函數,初始化網卡 */
if (init(netif) != ERR_OK) {
return NULL;
}
/* 將網絡接口添加到鏈表 */
netif->next = netif_list;
netif_list = netif;
return netif;
}
netif_remove從協議棧中移除網絡接口
/* 從鏈表中移除一個網絡接口 */
void netif_remove(struct netif * netif)
{
if ( netif == NULL ) return;
/* 網絡接口在鏈表頭部 */
if (netif_list == netif) {
/* 刪除頭節點 */
netif_list = netif->next;
}
else {
struct netif * tmpNetif;
/* 遍歷整個鏈表 */
for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {
/* 刪除該節點 */
if (tmpNetif->next == netif) {
tmpNetif->next = netif->next;
break;
}
}
/* 沒找到該節點 */
if (tmpNetif == NULL)
return;
}
/* 該網絡接口爲默認網絡接口,默認網絡接口置爲MULL */
if (netif_default == netif)
netif_set_default(NULL);
}
啓用和禁止網絡接口
/* 使能網絡接口 */
void netif_set_up(struct netif *netif)
{
/* 設置網絡接口使能標誌位 */
if (!(netif->flags & NETIF_FLAG_UP )) {
netif->flags |= NETIF_FLAG_UP;
/* 廣播無回報ARP */
if (netif->flags & NETIF_FLAG_ETHARP) {
etharp_gratuitous(netif);
}
}
}
/* 關閉網絡接口 */
void netif_set_down(struct netif *netif)
{
/* 清空網絡接口使能標誌位 */
if (netif->flags & NETIF_FLAG_UP )
{
netif->flags &= ~NETIF_FLAG_UP;
}
}
/* 網絡接口是否使能 */
u8_t netif_is_up(struct netif *netif)
{
return (netif->flags & NETIF_FLAG_UP) ? 1 : 0;
}
改變IP地址、子網掩碼、網關地址函數
/* 網絡接口改變IP地址 */
void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
{
struct tcp_pcb *pcb;
struct tcp_pcb_listen *lpcb;
/* IP發生變化 */
if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0)
{
/* 遍歷active狀態TCP控制塊鏈表 */
pcb = tcp_active_pcbs;
while (pcb != NULL) {
/* 查找和網絡接口IP相同的TCP控制塊 */
if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
struct tcp_pcb *next = pcb->next;
/* TCP連接復位(RST) */
tcp_abort(pcb);
pcb = next;
} else {
pcb = pcb->next;
}
}
/* 遍歷listen狀態TCP控制塊鏈表 */
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
/* 查找和網絡接口IP相同的TCP控制塊 */
if ((!(ip_addr_isany(&(lpcb->local_ip)))) && (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {
/* TCP控制塊設置新的本地IP地址 */
ip_addr_set(&(lpcb->local_ip), ipaddr);
}
}
}
/* 網絡接口設置新的IP地址 */
ip_addr_set(&(netif->ip_addr), ipaddr);
}
/* 設置IP地址 */
#define ip_addr_set(dest, src) (dest)->addr = \
((src) == NULL? 0:\
(src)->addr)
/* 網絡接口改變子網掩碼 */
void netif_set_netmask(struct netif *netif, struct ip_addr *netmask)
{
/* 網絡接口設置新的子網掩碼 */
ip_addr_set(&(netif->netmask), netmask);
}
/* 網絡接口改變網關地址 */
void netif_set_gw(struct netif *netif, struct ip_addr *gw)
{
/* 網絡接口設置新的網關地址 */
ip_addr_set(&(netif->gw), gw);
}
通過名字查找網絡接口
/* 通過名字查找網絡接口,name[0-1]爲網絡接口名字,name[2]爲網絡接口編號 */
struct netif *netif_find(char *name)
{
struct netif *netif;
u8_t num;
if (name == NULL) {
return NULL;
}
num = name[2] - '0';
/* 遍歷網絡接口鏈表 */
for(netif = netif_list; netif != NULL; netif = netif->next) {
/* 匹配網絡接口名字 */
if (num == netif->num && name[0] == netif->name[0] && name[1] == netif->name[1]) {
return netif;
}
}
return NULL;
}
LwIP提供了一個默認網絡接口
/* 默認網絡接口 */
struct netif *netif_default;
/* 設置netif爲默認網絡接口 */
void netif_set_default(struct netif *netif)
{
netif_default = netif;
}