LwIP协议栈的网络接口管理

时间:2022-11-24 10:34:20

    本文论述的网络接口属于链路层的范畴。运行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);

                netif->flags = 0;
               #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;
  }