【lwip】lwip源码基础
[toc]
前言
本笔记记录 lwip 源码基础内容
李柱明博客:https://www.cnblogs.com/lizhuming/p/15487094.html
概念&作用
网络接口
概念引入
网络接口(以太网接口)是硬件接口(网络接口又可以称之为网卡)。
LWIP 是软件那么而怎样让硬件和软件无缝连接起来呢?
而且网卡又多种多样,怎样才能让 LWIP 使用同样的软件兼容不同的硬件平台?
LWIP 中使用了一个**
netif**结构体来描述网卡但是网卡是直接和硬件平台打交道的:
用户提供最底层接口函数。
LWIP 提供统一的 API。
举例:
收:如网卡的初始化和网卡的收发数据,当 LWIP 底层得到数据之后,才会传入到内核中去处理。- 发:LWIP 内核需要发送数据包的时候,也需要调用网卡的发送函数。
LWIP 中的 etherneif.c 文件的函数通常为硬件打交道的底层函数,当有数据需要通过网卡接收或者发送数据的时候就会被调用,通过 LWIP 的协议栈的内部进行处理后,从应用层就能得到数据或者可以发送数据。
总结
简单来说,netif 是 LWIP 抽象出来的网卡,LWIP 协议栈可以使用多种不同接口,而 etherneif.c 文件则提供了 netif 访问各种不同的网卡,每个网卡有不同的实方式,每户只需要修改 ethernetif.c 文件即可。
lwip netif 结构体
链接
源码:((20210727163318-nobqihq))
字段分析
网卡链表
/** pointer to next in linked list */ struct netif *next;
LWIP 使用链表来统一管理同一设备的多个网卡。
netif.c 文件中定义两个全局指针
struct netif *netif_list和
struct netif *netif_default
netif_list
就是网卡链表指针,指向网卡链表的首节点(第一个网卡)。netif_default
默认网卡。
网络 IP
#if LWIP_IPV4 /** IP address configuration in network byte order */ ip_addr_t ip_addr; ip_addr_t netmask; ip_addr_t gw; #endif /* LWIP_IPV4 */
ip_addr:网络中的 IP 地址。
netmask:子网掩码。
gw:网关地址。
接收数据函数
/** This function is called by the network device driver * to pass a packet up the TCP/IP stack. */ netif_input_fn input;
该函数由网络设备驱动程序调用,将数据包传递到 TCP/IP 协议栈(IP 层),这通常是
ethernet_input(),参数为
pbuf和
netif类型,其中
pbuf为接收到的数据包。
发送数据函数
#if LWIP_IPV4 /** This function is called by the IP module when it wants * to send a packet on the interface. This function typically * first resolves the hardware address, then sends the packet. * For ethernet physical layer, this is usually etharp_output() */ netif_output_fn output; #endif /* LWIP_IPV4 */
函数由 IP 层调用,在接口上发送数据包。用户需要编写该函数并使 output 指向它。
通这个函数的处理步骤是首先解析硬件地址,然后发送数据包。
对于以太网物理层,该函数通常是
etharp_output(),参数是
pbuf,
netif,和
ip_addr类型。
注意:其中
ipaddr代表要将数据包发送到的地址,但不一定数据包最终到达的 ip 地址。比如要发送 ip 数据报到一个并不在本网络的主机上,该数据包要被发送到一个路由器上,这里的 ipaddr 就是路由器的 ip 地址。
ARP 模块调用的发送函数
/** This function is called by ethernet_output() when it wants * to send a packet on the interface. This function outputs * the pbuf as-is on the link medium. */ netif_linkoutput_fn linkoutput;
该函数和
output类似,也需要用户自己实现一个函数,但是只有两个参数,它是由 ARP 模块调用的,一般是自定义函数
low_level_output()。
当需要在网卡上发送一个数据包时,该函数会被
ethernet_output()函数调用。
出口回调函数
#if LWIP_NETIF_REMOVE_CALLBACK /** This function is called when the netif has been removed */ netif_status_callback_fn remove_callback; #endif /* LWIP_NETIF_REMOVE_CALLBACK */
当 netif 被删除时调用此函数。
用户私有数据
/** This field can be set by the device driver and could point * to state information for the device. */ void *state; #ifdef netif_get_client_data void* client_data[LWIP_NETIF_CLIENT_DATA_INDEX_MAX + LWIP_NUM_NETIF_CLIENT_DATA]; #endif #if LWIP_IPV6_AUTOCONFIG /** is this netif enabled for IPv6 autoconfiguration */ u8_t ip6_autoconfig_enabled; #endif /* LWIP_IPV6_AUTOCONFIG */ #if LWIP_IPV6_SEND_ROUTER_SOLICIT /** Number of Router Solicitation messages that remain to be sent. */ u8_t rs_count; #endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ #if LWIP_NETIF_HOSTNAME /* the hostname for this netif, NULL is a valid value */ const char* hostname; #endif /* LWIP_NETIF_HOSTNAME */ #if LWIP_CHECKSUM_CTRL_PER_NETIF u16_t chksum_flags; #endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/
由设备驱动程序设置并指向设备的状态信息,主要将网卡的某些私有数据传递给上层。
最大传输单位
/** maximum transfer unit (in bytes) */ u16_t mtu;
链路硬件地址长度&地址
/** number of bytes used in hwaddr */ u8_t hwaddr_len; /** link level hardware address of this interface */ u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
网卡信息状态标志
/** flags (@see @ref netif_flags) */ u8_t flags;
网卡状态信息标志位,是很重要的控制字段,它包括网卡的功能使能,广播使能,ARP 使能等重要控制位。
网卡名字
/** descriptive abbreviation */ char name[2];
用于保存每一个网卡的名字,用两个字符的名字来标识。
网卡使用的设备驱动的种类,名字由设备驱动来设置并且应该反映通过网卡表示的硬件的种类。
如果两个网卡具有相同的网络名字,我们就用 num 字段来区分相同类别的不同网卡。
网卡标识
/** number of this interface */ u8_t num;
标识使用同种驱动类型的不同网卡。
netif 使用
简要步骤:
定义一个
netif
作为网卡设备结构体。挂载到
netif_list
链表中。 使用函数:netif_add();
- 建议参考该函数源码。
源码
struct netif
/** Generic data structure used for all lwIP network interfaces. * The following fields should be filled in by the initialization * function for the device driver: hwaddr_len, hwaddr[], mtu, flags */ struct netif { /** pointer to next in linked list */ struct netif *next; #if LWIP_IPV4 /** IP address configuration in network byte order */ ip_addr_t ip_addr; ip_addr_t netmask; ip_addr_t gw; #endif /* LWIP_IPV4 */#if LWIP_IPV6 /** Array of IPv6 addresses for this netif. */ ip_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES]; /** The state of each IPv6 address (Tentative, Preferred, etc). * @see ip6_addr.h */ u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES]; #endif /* LWIP_IPV6 */ /** This function is called by the network device driver * to pass a packet up the TCP/IP stack. */ netif_input_fn input;#if LWIP_IPV4 /** This function is called by the IP module when it wants * to send a packet on the interface. This function typically * first resolves the hardware address, then sends the packet. * For ethernet physical layer, this is usually etharp_output() */ netif_output_fn output; #endif /* LWIP_IPV4 *//** This function is called by ethernet_output() when it wants * to send a packet on the interface. This function outputs * the pbuf as-is on the link medium. */ netif_linkoutput_fn linkoutput;#if LWIP_IPV6 /** This function is called by the IPv6 module when it wants * to send a packet on the interface. This function typically * first resolves the hardware address, then sends the packet. * For ethernet physical layer, this is usually ethip6_output() */ netif_output_ip6_fn output_ip6; #endif /* LWIP_IPV6 */ #if LWIP_NETIF_STATUS_CALLBACK /** This function is called when the netif state is set to up or down */ netif_status_callback_fn status_callback; #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK /** This function is called when the netif link is set to up or down */ netif_status_callback_fn link_callback; #endif /* LWIP_NETIF_LINK_CALLBACK */ #if LWIP_NETIF_REMOVE_CALLBACK /** This function is called when the netif has been removed */ netif_status_callback_fn remove_callback; #endif /* LWIP_NETIF_REMOVE_CALLBACK *//** This field can be set by the device driver and could point * to state information for the device. */ void *state; #ifdef netif_get_client_data void* client_data[LWIP_NETIF_CLIENT_DATA_INDEX_MAX + LWIP_NUM_NETIF_CLIENT_DATA]; #endif #if LWIP_IPV6_AUTOCONFIG /** is this netif enabled for IPv6 autoconfiguration */ u8_t ip6_autoconfig_enabled; #endif /* LWIP_IPV6_AUTOCONFIG */ #if LWIP_IPV6_SEND_ROUTER_SOLICIT /** Number of Router Solicitation messages that remain to be sent. */ u8_t rs_count; #endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ #if LWIP_NETIF_HOSTNAME /* the hostname for this netif, NULL is a valid value */ const char* hostname; #endif /* LWIP_NETIF_HOSTNAME */ #if LWIP_CHECKSUM_CTRL_PER_NETIF u16_t chksum_flags; #endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*//** maximum transfer unit (in bytes) */ u16_t mtu;/** number of bytes used in hwaddr */ u8_t hwaddr_len; /** link level hardware address of this interface */ u8_t hwaddr[NETIF_MAX_HWADDR_LEN];/** flags (@see @ref netif_flags) */ u8_t flags;/** descriptive abbreviation */ char name[2];/** number of this interface */ u8_t num;#if MIB2_STATS /** link type (from "snmp_ifType" enum from snmp_mib2.h) */ u8_t link_type; /** (estimate) link speed */ u32_t link_speed; /** timestamp at last change made (up/down) */ u32_t ts; /** counters */ struct stats_mib2_netif_ctrs mib2_counters; #endif /* MIB2_STATS */ #if LWIP_IPV4 && LWIP_IGMP /** This function could be called to add or delete an entry in the multicast filter table of the ethernet MAC.*/ netif_igmp_mac_filter_fn igmp_mac_filter; #endif /* LWIP_IPV4 && LWIP_IGMP */ #if LWIP_IPV6 && LWIP_IPV6_MLD /** This function could be called to add or delete an entry in the IPv6 multicast filter table of the ethernet MAC. */ netif_mld_mac_filter_fn mld_mac_filter; #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ #if LWIP_NETIF_HWADDRHINT u8_t *addr_hint; #endif /* LWIP_NETIF_HWADDRHINT */ #if ENABLE_LOOPBACK /* List of packets to be queued for ourselves. */ struct pbuf *loop_first; struct pbuf *loop_last; #if LWIP_LOOPBACK_MAX_PBUFS u16_t loop_cnt_current; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ #endif /* ENABLE_LOOPBACK */ };
- IOS-20-数据库操作之(SQLite第三方封装库FMDB)的基础入门使用及demo源码
- 【算法】验证码识别基础方法及源码
- TP5源码分析-加载基础文件【Loader主要功能图解】
- 流星ASP.NET权限基础管理系统源码发布
- 1.2.Spring源码解析——容器的基础XmlBeanFactory
- Rxjava的基础用法和源码解析(二)
- Linux从用户层到内核层系列 - TCP/IP协议栈部分系列7: 基础知识之 - Linux内核源码目录与内核编译选项
- 【java基础之jdk源码】集合类
- [C++基础]042_用Visual Studio的命令行编译源码
- 清清月儿 .NET万花筒 Asp.net技术 Asp.net教程 Asp.net源码 Asp.net基础 Asp.net控件 Asp.net入门
- java基础入门-传智博客课后实训源码
- 最基础的一些入门级Android源码例子整理
- Java源码阅读基础----设计模式----工厂模式
- 【基础源码】strcpy函数实现
- 【转】Java并发基础:了解无锁CAS就从源码分析
- 【vuejs深入二】vue源码解析之一,基础源码结构和htmlParse解析器
- lwIP(V1.0.0) RAW API函数源码分析2----tcp_bind()函数
- lwIP(V1.0.0) RAW API函数源码分析4----tcp_accept()函数
- Hadoop基础教程-第13章 源码编译(13.1 Zookeeper源码编译)
- Springboot系列:Springboot与Thymeleaf模板引擎整合基础教程(附源码)