lwip源码分析 之 网络接口netif

一,简介

以太网通信中,硬件层的实现是靠网卡,每个网卡都有ip地址,mac地址,最大传输包长度,输入输出功能,。lwip使用netif来描述这些网卡,并将网卡的输入输出数据传递给ip层。
在这里插入图片描述

二,源码分析

首先是网口的结构体,结合上图

struct netif {
  struct netif *next; //指向下一个网口

  ip_addr_t ip_addr;  //网口ip地址
  ip_addr_t netmask;  //网口子网掩码,用来判断ip是否处于同一网络
  ip_addr_t gw; //网关地址,若目的ip不在同一网络,则将报文发送给网关

  netif_input_fn input; //网口调用该函数将数据包传递给ip层

  netif_output_fn output; //ip层调用该函数将数据包传递给网口

  netif_linkoutput_fn linkoutput; //网口调用该函数将数据包传递给以太网驱动

  void *state;
#if LWIP_DHCP
  struct dhcp *dhcp;
#endif /* LWIP_DHCP */
  u16_t mtu;  //最大数据包长度
  u8_t hwaddr_len;  //硬件地址长度
  u8_t hwaddr[NETIF_MAX_HWADDR_LEN];//硬件地址
  u8_t flags; //网口的状态 属性控制位
  char name[2]; //网口名称
  u8_t num; //网口的编号
#if LWIP_IGMP
  netif_igmp_mac_filter_fn igmp_mac_filter;
#endif /* LWIP_IGMP */

};

netif的初始化函数为netif_add();这个函数实际上就是用获取到的ip地址等填充netif结构体,并将网卡的初始化和输入函数赋值到netif中,调用网卡初始化函数初始化网卡,并将netif插入链表。初始化和输入函数是由网卡的驱动者提供的。

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)
{
  static u8_t netifnum = 0; //静态变量:网口编号

  //重置网口地址
  ip_addr_set_zero(&netif->ip_addr);
  ip_addr_set_zero(&netif->netmask);
  ip_addr_set_zero(&netif->gw);
  
  netif->flags = 0;
  netif->dhcp = NULL;
  netif->igmp_mac_filter = NULL;

  netif->state = state;
  netif->num = netifnum++;  //新编号
  netif->input = input; //添加ip层输入函数

  netif_set_addr(netif, ipaddr, netmask, gw);//设置网口的地址

  //调用初始化函数,初始化硬件
  if (init(netif) != ERR_OK) {
    return NULL;
  }

  //将网口插入链表头
  netif->next = netif_list;
  netif_list = netif;
  snmp_inc_iflist();
  return netif;
}

需要注意的是在添加网口的ip地址时,会检查是否有tcp连接绑定在之前的网口上,若有则需要将该tcp连接终止,因为网口的ip地址修改将导致tcp连接断开。

//设置网口ip地址
void
netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
{
#if LWIP_TCP
  struct tcp_pcb *pcb;
  struct tcp_pcb_listen *lpcb;

  //新的ipaddr与之前的ip不一样,需要更新tcp控制块
  if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {
    pcb = tcp_active_pcbs;  //正常的tcp连接链表
    while (pcb != NULL) {
      //判断是否有tcp绑定到当前网口的ip上。若有则终止tcp
      if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr)))
       {
        struct tcp_pcb *next = pcb->next;//将pcb从链表删除
        tcp_abort(pcb);
        pcb = next;
      } else {
        pcb = pcb->next;  //检查下一个tcp
      }
    }
    //检查处于listen状态的tcp
    for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
     
      //若tcp绑定到当前网口,则更新tcp的ip信息,此时无tcp连接
      if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&
          (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {
        ip_addr_set(&(lpcb->local_ip), ipaddr);
      }
    }
  }
#endif

  ip_addr_set(&(netif->ip_addr), ipaddr); //设置网口ip
}

三,示例

以stm32为例,netif在移植中的作用
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值