lwip网络接口netif

一个系统中可能有多个网络接口,有可能是以太网,有可能是WiFi,也有可能是其他的网络接口。
在lwip中每一个网络接口都由一个netif结构体表示。表示不同网卡的netif结构体链接成一个链表。全局变量struct netif *netif_list指向该链表表头。
全局变量struct netif *netif_default指向的netif结构所表示的网卡为缺省网卡。在发送消息的时候,会首先会通过这个网卡,若是没有回应,再使用其他网卡。
在之前的移植实例中,因为只有一个以太网卡作为网络接口,所以网卡就用struct netif netif表示了。

struct netif定义如下
struct netif {
struct netif *next;
char name[2];
int num;
struct ip_addr ip_addr;
struct ip_addr netmask;
struct ip_addr gw;
void (* input)(struct pbuf *p, struct netif *inp);
int (* output)(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr);
void *state;
};
(1) next
指向链表中下一个netif结构
(2) ip_addr、netmask 和 gw
这三个结构体成员分别用来存储本网卡的 IP 地址、子网掩码和网关。
(3) err_t (* input)(struct pbuf *p, struct netif *inp)
这个函数是用来接收底层硬件输入的数据包的。函数的返回值是 err_t 类型,它是由 LwIP 定义的一种用于表示操作成功、失败等参数的变量。函数的输入参数为 pbuf 类型的 p 指针和 netif 类型的 inp 指针,表示我们要接收 inp 网卡通过底层硬件接收到的数据包,并把数据包保存到结构体 p 中。
(4) err_t (* output)(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
本成员也是一个函数指针,它指向一个用于 IP 层输出的函数。在 IP 层有数据包需要发送时,就通过该指针调用 output 函数。本函数输入参数有 netif、pbuf 和 ip_addr 三个参数,表示使用 netif 网卡、把 pbuf 结构体的内容发送到 IP 地址为 ip_addr 的设备中。 但由于在硬件底层收发数据时是使用 MAC 地址的,所以本函数把 IP 地址经过转化得到 MAC地址后,调用下一个成员——linkoutput 函数。
(5) err_t (* linkoutput)(struct netif *netif, struct pbuf *p)
这个函数指针是指向最底层的网卡发送数据包函数。它是被上面的 output 函数调用的。在 output 函数中的 pbuf 数据包实际上缺少了 MAC 包中的 DA 段(目标 MAC 地址),output 函数把它的输入参数 IP 地址转化成 MAC 地址后,添加到 pbuf 的 payload 成员,组成完整 MAC 包,再由本函数 linkoutput 输出到网络中。
(6) state
state 指针指向一用户感兴趣的信息,这部分可以由用户自行配置,也可以不使用。
(7) mtu
本成员记录了最大传输单元,我们知道 MAC 数据段的最大长度为 1500 字节,所以本成员我们一般会直接赋值为 1500。
(8) hwaddr_len 和 hwaddr[NETIF_MAX_HWADDR_LEN]
hwaddr_len 存储的是 MAC 地长度,hwaddr[]数组则存储了本网卡的 MAC 完整地址。
(9) flags
本成员保存了网卡允许使用的功能,如使用广播地址、ARP 功能等。
(10) name 和 num
name 用于保存网络接口的名字,可以自由设置,名字是两个字节的

网络接口的初始化过程,根据之前的移植工程的步骤(主要netcong.c中)

struct netif netif; //定义网卡netif结构体

struct ip_addr ipaddr;
struct ip_addr netmask;
struct ip_addr gw;

IP4_ADDR(&ipaddr, 192, 168, 1, 254); //ip
IP4_ADDR(&netmask, 255, 255, 255, 0); //掩码
IP4_ADDR(&gw, 192, 168, 1, 1);//网关

netif_add(&netif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &ethernet_input);
//将之前设定的ip,掩码,网关初始化初始化netif结构体,结构体相关成员设定。
//链路层输出函数ethernet_input函数(ethnetif.c)与绑定结构体成员函数指针input
//netif_add函数的还有一个功能是调用底层硬件初始化函数ethernetif_init(ethnetif.c )对底层硬件进行初始化,同时netif结构体的部分成员在这里初始化。ethernetif_init部分如下:
  netif->state = ethernetif;
  netif->name[0] = IFNAME0;//网络接口模块
  netif->name[1] = IFNAME1;
  netif->output = etharp_output; //将netif结构体的输出函数指正与etharp_output(etharp.c)绑定
  netif->linkoutput = low_level_output;//将netif结构体的arp连接输出指针与low_level_output(ethernetif.c)绑定
  ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
low_level_init(netif);//对网络模块进行初始化,具体会根据网络接口,之前的移植实例用的Enc28j60模块。该函数同时会将硬件地址赋值给netif 相关成员,netif结构体也被链入链表 netif_list。

netif_set_default(&netif);
//设定该网卡为默认网卡,全局变量netif_default指针指向该结构体
netif_set_up(&netif);//实现该接口

网络接口初初始化之后,除了节本的网络参数之外(ip,mac等)。
两个全局变量指针netif_list,netif_default的都指向了改网络接口节点。
IP 层有数据发送时,它首先会以 netif_list 为索引选择满足 某个条件的网络接口发送数据包,但是,当找不到这样的接口时,协议栈就会调用缺省的网 络接口直接发送数据包。

netif结构体相关函数指针成员都绑定了相关函数
netif->input =  ethernet_input;
netif->output = etharp_output;
netif->linkoutput = low_level_output;

当网卡有接收到数据(查询或者中断的方式)的时候,调用netif->input即ethernet_input(ethnernetif.c)会根据不同的报文类型,会执行不同的动作,具体看函数源码。例如若是ETHTYPE_IP时ip报文的时候,则调用ip_input(p, netif)将发往ip,交由ip层处理。

若是ip层有数据需要发送出去,则调用netif->output即etharp_output(etharp_out.c)将数据发送到底层。

若是底层数据发送到网络接口上发送出去,则调用 netif->linkoutput 即low_level_output(ethnernetif.c)将数据通过网卡发送出去。






### lwIP 中 `netif` 和 PPP 的配置与使用 #### 关于网络接口 (`netif`) 配置 在网络接口(`netif`)方面,lwIP 提供了一套灵活的 API 来管理不同类型的物理或虚拟网络设备。为了创建一个新的网络接口实例并将其加入到系统的网络接口列表中,可以调用函数 `netif_add()` 函数[^1]。 ```c 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)); ``` 此函数接受多个参数来初始化新网卡对象及其关联属性,比如 IP 地址、子网掩码以及默认网关等信息。对于状态字段(state),可以根据具体需求传递额外的数据结构指针给底层驱动程序;而对于输入回调(input callback)则用于处理接收到的数据包。 当完成上述设置之后还需要通过 `netif_set_up(netif)` 启动该接口,并可通过 `netif_set_default(netif)` 设置其作为默认路由使用的接口。 #### PPP 协议支持 针对点对点协议(Point-to-Point Protocol,PPP),lwIP 实现了一个完整的 PPP 堆栈,允许开发者轻松集成拨号连接或其他形式的串行链路通信功能。要启用 PPP 支持,在编译时需确保定义了宏 `LWIP_NETIF_API` 及 `LWIP_PPPAPI` ,以便能够访问相应的 API 接口[^2]。 启动 PPP 连接通常涉及以下几个步骤: 1. 创建一个 PPP 控制块(ppp_pcb); 2. 使用 `pppos_create(&ppp, &tcpip_thread->tcpthread, link_output_cb, status_callback);` 初始化 PPPoS 会话; 3. 调用 `pppos_connect(ppp, serial_fd);` 开始建立实际链接过程。 其中 `link_output_cb` 是发送数据前由上层应用提供的回调函数,而 `status_callback` 则是在连接状态发生变化时触发的通知机制。此外还需注意提供合适的认证方式(PAP/CHAP),这取决于远程服务器的要求。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值