---------------------------------------------------------------------------------------------------------------------------
首先判断以太网数据包的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以太网程序解析一
推荐阅读最新更新时间:2024-11-17 00:09
推荐帖子
- 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与安卓
设计资源 培训 开发板 精华推荐
- 具有 SPI 和 PWM 控制的 MCZ33999EK 16 输出开关的典型应用电路
- AM2M-2412DH30-NZ ±12 Vout、2W 双路输出 DC-DC 转换器的典型应用
- 基于555定时器的呼吸灯电路
- 带恒流源的低压精密可调并联稳压器的典型应用
- TWR-S12G64,用于 MC9S12GN32 超可靠 16 位 MCU 塔式系统模块的开发塔式系统模块,适用于汽车应用
- USB扩展器-V1
- 电源模块
- EVAL-AD7989-5SDZ,用于 AD7989-5BRMZ 18 位 500 kSPS PulSAR ADC 10 引脚 MSOP 的评估板
- RT8259 1.2A、24V、1.4MHz降压转换器典型应用
- AM1G-4815DH30Z ±15V 1 瓦 DC-DC 转换器的典型应用