STM32以太网程序解析三

发布者:亚瑟摩根最新更新时间:2022-02-14 来源: eefocus关键字:STM32  以太网程序 手机看文章 扫描二维码
随时随地手机看文章

---------------------------------------------------------------------------------------------------------------------------


首先判断以太网数据包的ETH首部(总第12和13字节)类型长度是否为ARP协议代码(0x0806),然后判断ARP首部中总第0x26字节至第0x29字节存储的目的IP时候与本机相符,如果没有问题,则返回1,否则返回0


29行,在判断是arp包,且为目的IP为本机IP的情况下,设置返回一个ARP响应包,该行函数的内部操作函数为


1. void make_arp_answer_from_request(unsigned char *buf)  


2. {  


3.     unsigned char i=0;  


4.       


5.     // 填写ETH包头的目的MAC地址以及源MAC地址   


6.     make_eth(buf);   


7.       


8.     // 将ARP包的操作类型字节改为ARP响应   


9.     buf[ETH_ARP_OPCODE_H_P]=ETH_ARP_OPCODE_REPLY_H_V;     


10.     buf[ETH_ARP_OPCODE_L_P]=ETH_ARP_OPCODE_REPLY_L_V;  


11.       


12.     // 填写ARP包的目的MAC地址以及源MAC地址   


13.     while(i<6)  


14.     {  


15.         buf[ETH_ARP_DST_MAC_P+i]=buf[ETH_ARP_SRC_MAC_P+i];  


16.         buf[ETH_ARP_SRC_MAC_P+i]=macaddr[i];  


17.         i++;  


18.     }  


19.             


20.     i=0;  


21.   


22.     // 填写ARP包的目的IP地址以及源IP地址   


23.     while(i<4)  


24.     {  


25.         buf[ETH_ARP_DST_IP_P+i]=buf[ETH_ARP_SRC_IP_P+i];  


26.         buf[ETH_ARP_SRC_IP_P+i]=ipaddr[i];  


27.         i++;  


28.     }  


29.       


30.     printf("nr神舟III号[%d.%d.%d.%d]发送ARP相应",ipaddr[0],ipaddr[1],ipaddr[2],ipaddr[3]);  


31.       


32.     // 发送ARP相应包 ,ARP包有42个字节   


33.     enc28j60PacketSend(42,buf);   


34. }  


首先是填写ETH首部,因为是返回ARP响应,因此通过make_eth函数将buf中的源mac数据填入到目的mac位置处,将本服务器的mac填入源mac位置处,实现源mac与目的mac位置的对调。然后修改ARP首部中操作类型(总第0x14和0x15字节)为ARP响应(0x0002)(原本是0x0001,ARP请求)。接着将ARP首部中的MAC和源IP分别与目的MAC和目的IP对调。最后通过ENC28J60函数发送ARP数据包。完成一次ARP的通信。


30行表明在完成ARP响应后,通过continue重新开始接收数据包(后面的if函数就不执行,因为已经识别为ARP包了,其它的if肯定不成立)


如果不是ARP包则26行至31行不成立,程序继续往下执行。


34行判断以太网包是否为合法的合法的IP包,该行函数的内部操作函数为


1. unsigned char eth_type_is_ip_and_my_ip(unsigned char *buf,unsigned  int len)  


2. {  


3.     unsigned char i=0;  


4.       


5.     // 包长度不够,直接返回   


6.     if (len<42)  


7.     {  


8.         return(0);  


9.     }  


10.       


11.     // 如果包类型不是IP包,直接返回   


12.     if(buf[ETH_TYPE_H_P]!=ETHTYPE_IP_H_V || buf[ETH_TYPE_L_P]!=ETHTYPE_IP_L_V)  


13.     {      


14.        return(0);  


15.     }  


16.       


17.     //************************************ 


18.     如果长度参数不正确,直接返回  


19.     IP包头中 4位的版本,4位头长 


20.     1000     1001 


21.     IPv4    5个4字节 


22.     ************************************     


23.     if (buf[IP_HEADER_LEN_VER_P]!=0x45)     


24.     {  


25.         // must be IP V4 and 20 byte header   


26.         return(0);  


27.     }  


28.       


29.     // 如果IP包的IP地址与本机IP不一致,直接返回      


30.     while(i<4)  


31.     {  


32.         if(buf[IP_DST_P+i]!=ipaddr[i])  


33.         {  


34.             return(0);  


35.         }  


36.         i++;  


37.     }  


38.     return(1);  


39. }  


函数首先先判断包的长度是否小于42,如果小于42则肯定不对,直接返回错误。关于42这个数字的选取,它是把ICMP包也考虑进去了,(42=14+20+8),如果单纯考虑TCP包应该是60.


然后判断以太网数据包的ETH首部(总第12和13字节)类型长度是否为IP协议代码(0x0800),接着判断IP首部中总第0x0E字节是否为0x45(版本为0100代表IPv4,头长为5,以4字节为单位,所以IP首位长度为20个字节),最后判断IP首部中(总第0x1e字节至0x21字节)代表的目的IP是否与本机IP相符。如果没有问题,则返回1,否则返回0。


如果判断为不合法的IP包,则通过37行的continue,重新开始接收数据。如果判断为合法的IP包则继续往下执行,接下来有可能是ICMP,TCP或者UDP协议


41行通过if语句判断是否为ICMP包,并且是ICMP回射请求包,判断的方法是查看IP首部总第0x17字节的协议代码是否为1(1代表ICMP),并且总第0x22字节是否为8(8代表回射请求,0代表回射应答),如果两者都不正确,或者只有后者正确则说明不是ICMP,如果只有前者正确说明,是ICMP但是不是回射请求包,如果两者都正确说明是ICMP回射请求包,if条件成立,我们需要返回一个ICMP回射应答包


47行是发送回射应答包的处理程序,它的内部函数为


1. void make_echo_reply_from_request(unsigned char *buf,unsigned  int len)  


2. {  


3.     // 填写包的目的MAC地址以及源MAC地址    


4.     make_eth(buf);  


5.   


6.     // 填写包的目的IP地址以及源IP地址   


7.     make_ip(buf);  


8.   


9.     // 填写ICMP相应包类型,类型为回射应答   


10.     buf[ICMP_TYPE_P]=ICMP_TYPE_ECHOREPLY_V;     


11.   


12.     //****************************************************************** 


13.     we changed only the icmp.type field from request(=8) to reply(=0). 


14.     we can therefore easily correct the checksum: 


15.     ******************************************************************  


16.     if (buf[ICMP_CHECKSUM_P] > (0xff-0x08))  


17.     {  


18.         buf[ICMP_CHECKSUM_P+1]++;  


19.     }  


20.     buf[ICMP_CHECKSUM_P]+=0x08;  


21.   


22.     printf("nr神舟III号[%d.%d.%d.%d]发送ICMP包响应",ipaddr[0],ipaddr[1],ipaddr[2],ipaddr[3]);  


23.   


24.     // 发送ICMP响应包   


25.     enc28j60PacketSend(len,buf);  


26. }  


同样的调用make_eth函数实现源mac与目的mac的对调。调用make_ip函数实现源ip与目的ip的对调。不过在make_ip中还增加了fill_ip_hdr_checksum函数,它内部的操作是


1. void fill_ip_hdr_checksum(unsigned char *buf)  


2. {  


3.     unsigned  int ck;  


4.   


5.     // 清空两个字节的校验和   


6.     buf[IP_CHECKSUM_P]=0;  


7.     buf[IP_CHECKSUM_P+1]=0;  


8.   


9.     // 不允许数据包分段,,此为最后数据包,偏移地址为0   


10.     buf[IP_FLAGS_P]=0x40;   


11.     buf[IP_FLAGS_P+1]=0;    


12.   


13.     // 生存时间为64ms   


14.     buf[IP_TTL_P]=64;   


15.       


16.     // 计算校验和,并填充   


17.     ck=checksum(&buf[IP_P], IP_HEADER_LEN,0);  


18.     buf[IP_CHECKSUM_P]=ck>>8;  


19.     buf[IP_CHECKSUM_P+1]=ck& 0xff;  


20. }  


关键字:STM32  以太网程序 引用地址:STM32以太网程序解析三

上一篇:STM32以太网程序解析四
下一篇:STM32以太网程序解析一

推荐阅读最新更新时间:2024-11-17 00:09

STM32中stm32f10x.h头文件如何把宏定义的常量转化为地址
#define PERIPH_BASE ((uint32_t)0x40000000) /*! Peripheral base address in the alias region */ //单独此语句理解只是宏定义常量,不能作为地址,虽然((uint32_t)0x40000000)数字大小等于基值 #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) //单独此语句理解只是宏定义常量,不能作为地址 #define GPIOE_BASE (APB2PERIPH_BASE + 0x1800) //单独此语句理解只是宏定义常量,不能作为地址 #define
[单片机]
STM32之外部中断原理
STM32 的每一个GPIO都能配置成一个外部中断触发源,这点也是 STM32 的强大之处。STM32 通过根据引脚的序号不同将众多中断触发源分成不同的组,比如:PA0,PB0,PC0,PD0,PE0,PF0,PG0为第一组,那么依此类推,我们能得出一共有16 组,STM32 规定,每一组中同时只能有一个中断触发源工作,那么,最多工作的也就是16个外部中断。STM32F103 的中断控制器支持 19 个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。STM32F103 的19 个外部中断为: 线 0~15:对应外部 IO 口的输入中断。 线 16:连接到 PVD 输出。 线 17:连
[单片机]
STM32 PA15作普通IO用时的配置
调STM32F103RB板时,其中用到PA15作普通LED灯。一开始编程,配置成PP输出模式,但无论置0还是置1,均输出3.3V。后来发现此脚为JTAG口调试口。 经查找到问题解决办法: 需要重新映射一下,重新映射方法如下: 首先要打开GPIOA的AFIO时钟: RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); 然后调用GPIO重映射函数,根据需求实现重映射: GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE); 然后运行OK! 补充说明 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisab
[单片机]
STM中SPI运用的NSS引脚解读
STM的NSS引脚 首先我们说该引脚有两个电平需要注意,一个是与NSS引脚连接的外部电平,一个是NSS引脚的内部电平。 然后我们知道在SPI通信的时候master必须在NSS引脚的内部电平为高电平时才得以进行通信,slaver在NSS引脚的内部电平为低电平时才可以通信。这是前提条件。 我们知道NSS引脚电平的管理有两种方式,一个是软件管理和硬件管理。但当为硬件管理时(SSM=0),NSS管脚的内部电平由与NSS连接的外部电平决定,即外面是高电平,则NSS引脚的内部电平也为高电平。如果你想工作在该模式下,那么master的NSS引脚必须连接高电平,slaver必须连接低电平(一般接地)。软件管理模式(SSM=1)则是通过SS
[单片机]
学习STM32之认识常用函数
很多学了51单片机的小伙伴后选择学习更加高级的stm32的时候,就被stm32的代码吓到了,无数多个函数是否把你压得喘不过气?但是实际上一个硬件高手看到一段硬件代码,即使没有任何注释也能将代码读个七七八八。就是因为硬件代码中的各个函数的名字虽然长,但是却十分有规律,虽然多,但却可以总结,希望我这个博客可以增加初学者对于stm32代码的阅读能力。 以下是对stm32f4中一些常用函数的归纳: 当你把这些函数都记住了,那么学习stm32阅读代码的时候,把这些函数部分和初始化部分除开,其实就会发现剩下的代码也就不多了。
[单片机]
学习<font color='red'>STM32</font>之认识常用函数
绝对值编码器数据接收的问题
实验环境:STM32F407,KEIL5,绝对值式编码器 程序目的:将串口接收到的编码器的数据存到数组RecBufEncode中,Count计数,ch是编码器通过串口返回的数据,编码器设置的是自动发送数据。如果存入数据满足13位,进入while中执行后续操作 #define LEN 13 //定义接收一条指令的长度 绝对式编码器的返回值 RecBufEncode =ch; Count %= LEN; while(0 == Count) { ...//后续操作 } 上诉方式实现不了目的。 实验结果:只能读取每次上次后获取的第一个数据,在转动编码器后,数据存在但数值不变。 #define LE
[单片机]
基于STM32处理器的数字PDA系统设计
0 引言 以Cortex-M3为内核的处理器由于其低功耗以及低成本并且是32位处理器,越来越多的研究人员已经从51处理器、AVR等处理器开始转移到这个领域。数字PDA系统设计采用的是以Cortex-M3的内核STM32ZET6控制器,但是由于STM32ZET6内部没有MMU,不能移植WincE,Linux等操作系统,故只能应用ucLinux,μC/OS-Ⅱ等实时操作系统。传统的操作系统ucLinux,μC/OS-Ⅱ在微控制器中移植后,应用程序就开始了与操作系统、以及硬件驱动之间的交互,一旦要添加新的应用程序或者对应用程序的更改,代码的修改量以及整个操作系统的稳定性都会收到影响。这时就需要一种新的机制,能够在保证系统稳定性的基础上
[单片机]
基于<font color='red'>STM32</font>处理器的数字PDA系统设计
STM32 USB HID 自定义设备 bulk 传输
ST(意法半导体公司)为STM32系列处理器编写了外设USB的库,并提供了很好的参考例程,本文就是参考ST提供的例程,在STM32F4 discovery板子上实现usb bulk传输。Host端是在linux平台上利用libusb库函数写的读写USB应用。 本次实现在STM32 USB例程中的Device HID 鼠标例程基础上添加bulk传输端点修改而来。 usb_conf.h 文件中添加 bulk传输端点 /* * endpoint 0x80 and 0x00 are used for enumerating device. * endpoint 0x81 and 0x80 are used for cont
[单片机]

推荐帖子

embedded vb 如何把它编译的程序,转成cab阿。在线等
embeddedvb如何把它编译的程序,转成cab阿。在线等我初次是用这个软件,在他的模拟ppc2002上已经可以使用了,但是我想安装在真实的机器上测试,不知道怎么弄希望搞人指教embeddedvb如何把它编译的程序,转成cab阿。在线等
jurryz 嵌入式系统
TI【免费LED 阵列驱动器方案样片套件 】数量有限,立即获取!!
有源PFC控制器与智能线性LED驱动器的组合造就了一款富有吸引力的完整解决方案。其使客户实现了快速的产品上市进程,而且未给竞争对手留下任何可乘之机。点击详细查看情况 TI【免费LED阵列驱动器方案样片套件】数量有限,立即获取!!DetailedInformation样片装详细信息ComboName联赢方案名称PartNumber产品型号HighBayLEDLightingSolution高棚灯LED照明解决方案UCC2881
qwqwqw2088 模拟与混合信号
我想用单片机制作一个比较大音乐显示屏,
我想用单片机制作一个比较大音乐显示屏,但是我只是初学者。求大神给点电路图和材料列表。谢谢我想用单片机制作一个比较大音乐显示屏,参考答案只有结果,无计算过程,为170mA,求思路什么是音乐屏啊大有两种功率大,点数多.我都不懂呢,学习下从0开始吧,买块开发板先学习基础……
从雨中来 单片机
FreeRTOS学习笔记 (2)堆栈——任务切换的关键
  本篇中“堆栈”术语(stack)是指计算机(包括MCU)处理器通过堆栈寄存器(stackpointerregister)来存取数据的内存区域。常用的访问方式包括Push/Pop,以及根据堆栈指针寄存器的间接寻址访问。  先复习一下C语言中局部变量是怎么存放的。  举例,main()函数调用了func1(),然后func1()又调用了sub2(),如下图  当CPU执行到sub2()函数里面的时候,main()以及func1()中的局部变量不在
cruelfox 单片机
造纸机交流变频调速控制系统
随着随着交流变频控制技术的发展,交流变频调速控制系统以其稳速精度和可靠性高、调节特性好等优点,在电气调速领域中得以广泛应用。本文介绍了造纸机的特点以及交流变频调速控制系统在造纸厂的两种典型应用。造纸机交流变频调速控制系统
frozenviolet 工控电子
求助linux编译的一个问题
在linux下我用如下的命令去单步编译gcc-cADInclude.cgcc-ctest2.cgcc-otesttest2.oADInclude.o可以编译通过,但我用makefile文件去编译就会出错/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crt1.o(.text+0x18):Infunction`_start\':../sysdeps/i386/elf/start.S:77:undefinedr
fanzw Linux与安卓
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved