前言

本笔记记录 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 结构体

链接

参考:LWIP中netif结构体的介绍

源码:((20210727163318-nobqihq))

字段分析

网卡链表

/** pointer to next in linked list */
struct netif *next;

LWIP 使用链表来统一管理同一设备的多个网卡。

netif.c 文件中定义两个全局指针 struct netif *netif_liststruct 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(),参数为 pbufnetif 类型,其中 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 使用

简要步骤:

  1. 定义一个 netif 作为网卡设备结构体。

  2. 挂载到 netif_list 链表中。

    1. 使用函数:netif_add();
    2. 建议参考该函数源码。

源码

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 */
};

【lwip】lwip源码基础的更多相关文章

  1. Vue 源码 基础知识点

    1.数据类型判断 const _toString = Object.prototype.toString function toRawType(value) { return _toString.ca ...

  2. 2014年6月份第1周51Aspx源码发布详情

    企业汽车服务终端管理系统源码  2014-6-3 [VS2010]源码描述:本系统专门服务于(汽车美容4s店) 完整的一套汽车美容管理服务系统. 功能介绍:汽车美容服务终端功能强大而又简便实用,界面友 ...

  3. 使用MiniProfiler给Asp.net MVC和Entity Framework号脉(附源码)

    在学习python开发框架pylons/pyramid的过程中,里面有个非常棒的页面性能监控功能,这样在开发过程中,你能清楚的知道当前页面的性能以及其它参数. 这里介绍一下如何给Asp.net MVC ...

  4. Entity Framework在Asp.net MVC中的实现One Context Per Request(附源码)

    上篇中"Entity Framework中的Identity map和Unit of Work模式", 由于EF中的Identity map和Unit of Work模式,EF体现 ...

  5. 2013年7月份第4周51Aspx源码发布详情

    大型企业通用管理ERP源码  2013-7-26 [VS2010]2013.7.4更新内容:1.修复决策模式-客户等级不能保存问题.2.修复企业知识库有报错问题.3.修复运营模式-人力资源分析模块-在 ...

  6. Android fragment源码全解析

    Fragment 相信基本上每个android developer都用过,但是知晓其原理 用的好的还是不多,今天就从源码的角度上来带着大家分析一下Fragment的源码,对fragment有了更深层次 ...

  7. 如何通过eclipse查看、阅读hadoop2.4源码

    问题导读:1.官网src包下载包,能否直接使用?2.如何跟踪和查看hadoop源码? 此篇是从零教你如何获取hadoop2.4源码并使用eclipse关联hadoop2.4源码基础上的一个继续,上文其 ...

  8. leaflet图斑历史时空播放(附源码下载)

    前言 leaflet 入门开发系列环境知识点了解: leaflet api文档介绍,详细介绍 leaflet 每个类的函数以及属性等等 leaflet 在线例子 leaflet 插件,leaflet ...

  9. Tars | 第4篇 Subset路由规则业务分析与源码探索

    目录 前言 1. Subset不是负载均衡 1.1 任务需求 1.2 负载均衡源码结构图 1.3 负载均衡四种调用器 1.4 新增两种负载均衡调用器 1.5 Subset应该是"过滤&quo ...

随机推荐

  1. 通过了解Servlet和Http之间的关系,了解web中http通信使用(二)

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6512399401825075719/ 1.<Servlet简单实现开发部署过程> 2.<Serv ...

  2. Java安全之Spring内存马

    Java安全之Spring内存马 基础知识 Bean bean 是 Spring 框架的一个核心概念,它是构成应用程序的主干,并且是由 Spring IoC 容器负责实例化.配置.组装和管理的对象. ...

  3. CodeForces 519B A and B and Compilation Errors (超水题)

    这道题是超级水的,在博客上看有的人把这道题写的很麻烦. 用 Python 的话是超级的好写,这里就奉上 C/C++ 的AC. 代码如下: #include <cstdio> #includ ...

  4. [C语言基础] 数组与指针之间的引用

    通过指针引用数组,通过数组引用指针,你搞明白了么?通过下面3种情形来了解一下数组和指针 Case 1. unsigned char arry[10]; unsigned char *ptr; unsi ...

  5. Natasha 4.0 探索之路系列(四) 模板 API

    Natasha 模板 Natasha 在编译单元的基础上进行了封装整理, 并提供了多种模板帮助开发者构建功能. 使用此篇的 API 前提是您对 C# 非常熟悉, 对系统的一些类型足够了解. 据此 Na ...

  6. gorm连接mysql和模型定义那些事

    1. gorm操作mysql: 1.1 安装gorm gorm官网: https://gorm.io/zh_CN/docs/connecting_to_the_database.html gorm的g ...

  7. 科技爱好者周刊(第 175 期):知识广度 vs 知识深度

    这里记录每周值得分享的科技内容,周五发布. 本杂志开源(GitHub: ruanyf/weekly),欢迎提交 issue,投稿或推荐科技内容. 周刊讨论区的帖子<谁在招人?>,提供大量程 ...

  8. 使用Termux并与ubuntu建立ssh连接

    什么是Termux? Termux是一个Android终端仿真器和Linux环境应用程序,直接工作,无需根目录或设置.一个最小的基本系统被自动安装-额外的软件包可以使用APT软件包管理器来使用.不需要 ...

  9. 阿里智能运维实践|阿里巴巴DevOps实践指南

    编者按:本文源自阿里云云效团队出品的<阿里巴巴DevOps实践指南>,扫描上方二维码或前往:https://developer.aliyun.com/topic/devops,下载完整版电 ...

  10. javascript 判断对像是否相等

    在Javascript中相等运算包括"==","==="全等,两者不同之处,不必多数,本篇文章我们将来讲述如何判断两个对象是否相等? 你可能会认为,如果两个对象 ...