《lwip学习2》- 网络接口管理

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, &ethernetif_init, &tcpip_input);

netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, &ethernetif_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);
  }

注:新挂载的网卡会在链表的最前面。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大文梅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值