LwIP之網絡接口管理

協議棧內部使用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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章