协议栈设计_LwIP笔记

2023-05-16

文章目录

  • LWIP主进程工作
    • 链路层
    • LWIP数据包收发函数框架
    • ARP(地址解析协议)表
    • ARP表查询
    • IP层
    • ICMP处理(Internet 控制报文协议)
  • TCPIP_Thread线程启动流程
  • **tcpip_thread主线程处理**

LWIP主进程工作

/* LWIP 协议模拟了 TCP/IP 协议的分层思想,
表面上看 LWIP 也是有分层思想的,但从实现上看, LWIP 只在一个进程内实现了各个层次
的所有工作。具体如下: LWIP 完成相关初始化后,会阻塞在一个邮箱上,等待接收数据进
行处理。这个邮箱内的数据可能来自底层硬件驱动接收到的数据包,也可能来自应用程序。
当在该邮箱内取得数据后, LWIP 会对数据进行解析,然后再依次调用协议栈内部上层相关
处理函数处理数据。处理结束后, LWIP 继续阻塞在邮箱上等待下一批数据。
*/

当数据在各层之间传递时,LWIP极力禁止数据的拷贝工作,因为会耗费大量的时间和内存

struct pbuf{
  	struct pbuf *next;
    void *payload;	// 指向该pbuf管理的数据的起始地址:紧跟在pbuf结构后的RAM,或者ROM上的某个地址
    u16_t tot_len;
    u16_t len;
    u8_t type;	// PBUF_RAM\PBUF_ROM\PBUF_PER\PBUF_POOL
    u8_t flags;
    u16_t ref;
};
应用层
传输层
网络层
链路层

LWIP没有在各层之间进行严格的划分,各层协议之间有交叉存取。

链路层

netif描述一个硬件网络接口

struct netif{
    struct netif *next;
    
    struct ip_addr ip_addr;	// IP地址
    struct ip_addr netmask;	// 子网掩码
    struct ip_addr gw;		// 网关地址
    
    err_t (*input)(struct pbuf *p, struct netif *inp);	// 调用这个函数从网卡取得一个数据包
    err_t (*output)(struct netif *netif, struct pbuf* p, struct ip_addr *ipaddr);	// IP层调用函数,向网卡发送一个数据包
    err_t (*linkoutput)(struct netif *netif, struct pbuf *p);	// ARP模块调用,向网卡发送一个数据包
   
    void *state;	// 用于指向用户关心的网卡信息
    u8_t hwaddr_len;	// 硬件地址长度,对于以太网就是MAC地址长度,为6个字节
    u8_t hwaddr[NETIF_MAX_HWADDR_LEN];	//MAC地址
    u16_t mtu;	//	一次可以传输的最大字节数,以太网一般设1500
    u8_t flags;	//	网卡状态信息标志位
    
    char name[2];	// 网络接口使用的设备驱动类型的种类
    u8_t num;		// 用来标识使用同种驱动类型的不同网络接口
};

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

LWIP数据包收发函数框架

low_level_input low_level_output

LWIP应用系统包括三个进程:

  • 上层应用程序进程
  • LWIP协议栈进程
  • 底层硬件数据包接收进程
目标MAC地址源MAC地址类型/长度数据校验
6字节6字节2字节(IP:0x0800/ARP:0x0806)46-1500字节4字节

ps: 最大帧长1518字节,最小64字节

eth_hdr描述以太网数据包包头14个字节

PACK_STRUCT_BEGIN	// 与编译器字对其相关的宏定义
	struct eth_hdr{
        PACK_STRUCT_FIELD(struct eth_addr dest);	// 目标MAC地址
        PACK_STRUCT_FIELD(struct eth_addr src);		// 源MAC地址
        PACK_STRUCT_FIELD(u16_t type);			   // 类型
    }PACK_STRUCT_STRUCT;
PACK_STRUCT_END

大端模式:某个半字或字数据的高位字节存在内存的低地址端,低位字节存放在内存的高地址端
小端模式:某个半字或字数据的 高位字节存在内存的高地址端,低位字节存放在内存的低地址端

ARM处理器使用的是小端模式;;网络字节数据用的大端模式

在这里插入图片描述

ARP(地址解析协议)表

动态映射:将32位的IP地址转换为对应48位的MAC地址

核心:ARP缓存表;对缓存表的建立、更新、查询等操作

struct etharp_entry{	// 缓存表项
    #if ARP_QUEUEING
    	struct etharp_q_entry *q;	//数据包缓冲队列指针
    #endif 
    	struct ip_addr ipaddr;		// 目标IP地址
    	struct eth_addr	ethaddr;	// MAC地址
    	enum etharp_state state;	// 描述该entry的状态
    	u8_t ctime;				   // 描述entry的时间信息。当大于规定的值时,该表项被内核删除
    	struct netif *netif;		// 相应网络接口信息
};

enum etharp_state{
    ETHARP_STATE_EMPTY = 0,
    ETHARP_STATE_PENDING,	// 处于不稳定状态,会发送一个广播ARP请求到数据链路上,让对应IP地址的主机回应其MAC地址
    ETHARP_STATE_STABLE	
};

static struct etharp_entry arp_table[ARP_TABLE_SIZE];		//数组方式创建ARP缓存表

在这里插入图片描述
两个字节长的以太网帧类型表示后面数据的类型。对于 ARP 请求或应答数据包来说,
该字段的值为 0x0806,对于 IP 数据包来说,该字段的值为 0x0800。

在这里插入图片描述

在这里插入图片描述

// 数据报头
struct etharp_hdr{
    PACK_STRUCT_FIELD(struct eth_hdr ethhdr); // 14 字节的以太网数据报头
    PACK_STRUCT_FIELD(u16_t hwtype); // 2 字节的硬件类型
    PACK_STRUCT_FIELD(u16_t proto); // 2 字节的协议类型
    PACK_STRUCT_FIELD(u16_t _hwlen_protolen); // 两个 1 字节的长度字段
    PACK_STRUCT_FIELD(u16_t opcode); // 2 字节的操作字段 op
    PACK_STRUCT_FIELD(struct eth_addr shwaddr); // 6 字节源 MAC 地址
    PACK_STRUCT_FIELD(struct ip_addr2 sipaddr); // 4 字节源 IP 地址
    PACK_STRUCT_FIELD(struct eth_addr dhwaddr); // 6 字节目的 MAC 地址
    PACK_STRUCT_FIELD(struct ip_addr2 dipaddr); // 4 字节目的 IP 地址
}PACK_STRUCT_STRUCT;
// PACK_STRUCT_FIELD()是防止编译器字对齐的宏定义

ARP表查询

ARP攻击,针对是针对以太网地址解析协议( ARP)的一种攻击技术。在局域网中, ARP
病毒收到广播的 ARP 请求包,能够解析出其它节点的 (IP, MAC) 地址, 然后病毒伪装为目
的主机,告诉源主机一个假 MAC 地址,这样就使得源主机发送给目的主机的所有数据包都
被病毒软件截取,而源主机和目的主机却浑然不知。 ARP 攻击通过伪造 IP 地址和 MAC 地
址实现 ARP 欺骗,能够在网络中产生大量的 ARP 通信量使网络阻塞,攻击者只要持续不断
的发出伪造的 ARP 响应包就能更改目标主机 ARP 缓存中的 IP-MAC 条目。 ARP 协议在设
计时未考虑网络安全方面的特性,这就注定了其很容易遭受 ARP 攻击。黑客只要在局域网
内阅读送上门来的广播 ARP 请求数据包,就能偷听到网内所有的 (IP, MAC)地址。而源节
点收到 ARP 响应时,它也不会质疑,这样黑客很容易冒充他人。

 // 寻找一个匹配的ARP项或者创建一个新的ARP表项,并返回该表项的索引号
static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)

lwip 有一个比较巧妙的地方 ,LWIP 中有个全局的变量 etharp_cached_entry,它始终保存着上次用到的索引号,如
果这个索引恰好就是我们要找的内容,且索引的表项已经处于 stable 状态,那就直接返回这个索引号就完成了 。

// 向给定的 IP 地址发送一个数据包或者发送一个ARP请求,
err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
// 该函数用于更新 ARP 缓存表中的表项或者在缓存表中插入一个新的表项。
// 该函数会在收到一个 IP 数据包或 ARP 数据包后被调用。
static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)

在这里插入图片描述

IP层

在这里插入图片描述

IP 数据报头

struct ip_hdr {
    PACK_STRUCT_FIELD(u8_t _v_hl); 		// 前三个字段:版本号、首部长度
      /* type of service */
  	PACK_STRUCT_FIELD(u8_t _tos);		// 服务类型,描述该IP数据包急需的服务类型,如最小延时、最大吞吐量等
    PACK_STRUCT_FIELD(u16_t _len); 		// 总长度,整个IP数据报,包括IP数据报头的总字节数
    PACK_STRUCT_FIELD(u16_t _id); 		// 标识字段
    PACK_STRUCT_FIELD(u16_t _offset);	// 3 位标志和 13 位片偏移字段;用于IP数据包分片时使用
    #define IP_RF 0x8000 //
    #define IP_DF 0x4000 // 不分组标识位掩码
    #define IP_MF 0x2000 // 后续有分组到来标识位掩码
    #define IP_OFFMASK 0x1fff // 获取 13 位片偏移字段的掩码
    PACK_STRUCT_FIELD(u8_t _ttl); // TTL 字段,描述IP数据包最多能被转发的次数,为0时,一个ICMP报文会被返回至源主机
    PACK_STRUCT_FIELD(u8_t _proto);// 协议字段, 1 ICMP, 2 ICMP, 6 TCP, 17 UDP
    PACK_STRUCT_FIELD(u16_t _chksum); // 首部校验和字段,只针对IP首部做校验;它并不关心其内部数据在传输过程中出错与否对于数据的校验是上层协议负责的,如 ICMP、 IGMP、 TCP、 UDP 协议都会计算它们头部以及整个数据区的长度。
    PACK_STRUCT_FIELD(struct ip_addr src); // 源 IP 地址
    PACK_STRUCT_FIELD(struct ip_addr dest); // 目的 IP 地址
} PACK_STRUCT_STRUCT;

ICMP处理(Internet 控制报文协议)

控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。

在这里插入图片描述

在这里插入图片描述

TCPIP_Thread线程启动流程

源码文件tcpip.c tcpip.h

Created with Raphaël 2.2.0 tcpip_init() lwip_init() if(sys_mbox_new()!=ERR_OK) LWIP_ASSERT() sys_thread_new(...,tcpip_thread,...) yes no

tcpip_thread主线程处理

Created with Raphaël 2.2.0 tcpip_thread() if(tcpip_init_done!=NULL) tcpip_init_done(tcpip_init_done_arg) while(1) switch(msg->type) TCPIP_MSG_API msg->msg.apimsg->function() TCPIP_MSG_INPKT if(msg->msg.inp.netif->flags) ethernet_input() memp_free() ip_input() TCPIP_MSG_NETIFAPI msg->msg.netifapimsg->function() TCPIP_MSG_TIMEOUT sys_timeout() memp_free() TCPIP_MSG_UNTIMEOUT sys_untimeout() memp_free() TCPIP_MSG_CALLBACK msg->msg.cb.function() memp_free() TCPIP_MSG_CALLBACK_STATIC msg->msg.cb.function() default yes no yes yes no yes no yes no yes no yes no yes no yes no yes no yes
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

协议栈设计_LwIP笔记 的相关文章

随机推荐

  • docker部署nodejs项目

    本文主要分享使用docker部署nodejs项目 使用docker部署项目主要分为三步 1 创建nodejs项目 编写package json为项目安装依赖所用 34 name 34 34 expressPro 34 34 version
  • Android 开发跨进程大图

    对于跨进程传输数据的问题 xff0c 我之前也写了一篇 xff0c 配合阅读效果更好 xff1a Android 开发太难了 xff0c 这异常竟然捕获不到 xff1f 1 抛一个问题 这一天 xff0c 法海想锻炼小青的定力 xff0c
  • linux修改键位:ctrl与caps调换

    ctrl比caps的使用频率更高 xff0c 但是ctrl的位置却对小拇指并不友好 有时使用gnome tweak tool设置键位并没有生效 下面介绍两个简单的方法修改键位 1 使用xmodmap修改键位 我们可以使用包管理器轻松安装xm
  • pandas无法打开.xlsx文件,xlrd.biffh.XLRDError: Excel xlsx file; not supported

    原因是最近xlrd更新后只支持 xls文件 所以pandas read excel xxx xlsx 会报错 可以安装旧版xlrd xff0c 在终端中运行 xff1a pip3 uninstall xlrd pip3 install xl
  • python&多路归并

    问题 xff1a 在项目中 xff0c 需从待分析的数据中选出最大的前几名 xff0c 但由于数据量太大 xff0c 直接排序会内存报错 xff0c 因此尝试用多路归并的思路来解决问题 接口 xff1a 一个目录下有x个已排序好的csv 最
  • 03_spring的基本配置

    bean元素的id和name属性 在Spring配置中 xff0c id和name属性都可以表示bean元素的名称 xff0c 不同的是 xff1a id属性 xff0c 遵守XML语法ID约束 必须以字母开始 xff0c 可以使用字母 数
  • Linux服务器的登录与使用

    Linux服务器的登录与使用 关于登录Linux服务器的方式有很多种 xff0c 本文重点介绍了Linux和Windows下的登录和使用Linux服务器的方式 Linux服务器 服务器可看为是一台功能配置强大的电脑 xff0c 有独立的操作
  • Angular2 - [innerHTML] && pipe(把字符串里的 /n 替换成 <br/>)

    需求 把接口返回的使用说明字符串innerHTML出来 xff1b 本来想直接 innerHTML 就可以了 xff0c 但是事不遂人愿 xff0c 那就写个pipe过滤一下 xff1b 过程 接口返回字符串 xff1a 34 coupon
  • vscode ftp-sync 插件使用

    插件安装和配置 1 下载ftp sync插件 extensions中直接搜索安装即可 2 ctrl 43 shift 43 p 选择执行Ftp sync init 配置文件json含义如下 span class token punctuat
  • Ubuntu16.04终端执行`sudo apt-get update`遇到appstream问题

    Ubuntu 16 04 终端执行sudo apt get update遇到问题 E xff1a Problem executing scripts APT Update Post Invoke Success br 39 if usr b
  • Cloudflare5s盾破解|爬虫自动验证|解决方案

    一 什么是Cloudflare5s盾 Cloudflare是一个网站加速和安全服务提供商 Cloudflare 5s盾是指网站防御模式 xff0c 它可以防止恶意流量和攻击 xff0c 如DDoS SQL注入 XSS等 xff0c 保护网站
  • 若依Vue入门——服务器部署篇

    目录 前端 xff0c ruoyi ui 编译 部署 后端 xff0c ruoyi 使用若依前后端分离的Vue 43 Springboot脚手架 xff0c 进行编译与在Windows Server服务器上的部署 使用IDEA作为IDE 使
  • Spring启动流程解析(总)

    一 xff0c Spring启动流程概述 Spring的IoC容器在实现控制反转和依赖注入的过程中 xff0c 可以划分为两个阶段 xff1a 容器启动阶段 Bean实例化阶段 容器初始化 加载配置 分析配置信息 将Bean信息装配到Bea
  • Node,docker 中安装node.js

    1 启动docker服务 首先启动docker服务 systemctl start docker 2 获取node最新镜像 启动完成之后拉取node最新镜像 xff1a docker pull node 然后开始等待 xff0c 最后拉取完
  • 慎用!!! rm -rf 潜藏着巨大的危险!

    平时删除文件爱偷个懒 笔直 rm rf 过去就不想事了 今天碰到一个很意外的情况 以前也有碰到过 但总没留意到 在这里记下提醒自己 希望大家也多留个神 先说说 rm 的用法 官方的描述是这样的 rm 命令可以删除一个目录中的一个或多个文件或
  • 个人面试细节、技巧总结(没有面试题哦!)

    面试除了自身技能过硬外 xff0c 良好的沟通 xff0c 平和的心态 xff0c 细节的拿捏也都是额外的加分项 最后 xff0c 以些许运气加以点缀 xff0c offer 便八九不离十了 参加工作两年有余 xff0c 只大专文凭 xff
  • EFCore 实现连接MySQL并创建实体类

    EFCore 实现连接MySQL并创建实体类 所需文件版本 1 Pomelo EntityFrameworkCore MySql 2 2 0 2 Microsoft EntityFrameworkCore Tools 2 2 0 3 Pom
  • Win10设置文件夹背景色

    右键个性化 选择左侧的颜色 xff0c 根据自己的喜欢进行设置
  • 快速计算代码行小工具

    非常方便用于统计代码行的小工具叫line counter xff0c 使用以下命令获取工具 pip install line counter 使用 34 line 34 命令可以获取当前目录下的文件与行数统计 xff0c 效果如下 line
  • 协议栈设计_LwIP笔记

    文章目录 LWIP主进程工作链路层LWIP数据包收发函数框架ARP 地址解析协议 表ARP表查询IP层ICMP处理 Internet 控制报文协议 TCPIP Thread线程启动流程 tcpip thread主线程处理 LWIP主进程工作