函数先清空校验和,然后设置IP首部标志总第0x14字节中不分段位为1,表示不允许分段,段偏移量为0,设置生存时间为64跳。最后计算校验和,填充校验和。校验和计算函数的计算方法我们这里不做介绍。
make_ip函数执行完成后,将ICMP相应的包类型修改为回射应答。然后填写IP校验和,最后通过ENC28J60将数据发送出去。
48行处理完ICMP回射应答后,通过continue语句重新接收数据包做处理。
如果不是ICMP包41行if函数不成立,程序继续往下执行。
52行if语句判断是否TCP包,判断的依据为查看IP首部(总第0x17字节)的协议代码是否为6(6代表TCP),并且TCP首部目的端口(总第0x24字节和0x25字节)是否与服务器的port相同,如果不正确则说明不是TCP包,程序继续往下执行。如果两者都正确说明是TCP包,if条件成立,执行if里面的函数
57行if语句判断TCP包类型,判断方法是对TCP首部中的6个标识位进行识别(总第0x2F字节的后6位)判断SYN位是否置位,如果没有置位则if条件不成立继续往下执行,如果SYN位置位说明TCP包是一个连接请求TCP包。
60行对连接请求TCP包做应答,该行函数的内部操作是
1. void make_tcp_synack_from_syn(unsigned char *buf)
2. {
3. unsigned int ck;
4.
5. // 填写包的目的MAC地址以及源MAC地址
6. make_eth(buf);
7.
8. // 计算包长度=IP头(20)+TCP头(24)
9. buf[IP_TOTLEN_H_P]=0;
10. buf[IP_TOTLEN_L_P]=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4;
11.
12. // 填写包的目的IP地址以及源IP地址
13. make_ip(buf);
14.
15. buf[TCP_FLAGS_P]=TCP_FLAGS_SYNACK_V;
16.
17. // 填写TCP头
18. make_tcphead(buf,1,1,0);
19.
20. // 计算校验和 长度=8 (开始于ip.src) + TCP头长(20) + 可选选项(4字节,mss)
21. ck=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN+4,2);
22. buf[TCP_CHECKSUM_H_P]=ck>>8;
23. buf[TCP_CHECKSUM_L_P]=ck& 0xff;
24.
25. printf("nr神舟III号[%d.%d.%d.%d]发送SYN包响应",ipaddr[0],ipaddr[1],ipaddr[2],ipaddr[3]);
26.
27. enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4+ETH_HEADER_LEN,buf);
28. }
首先是make_eth,然后计算包裹长度填入IP首部的包裹长度(总第0x10字节和0x11字节),接着make_ip,接着修改TCP首部中6个标志为中的ACK与SYN位置位,表示同步确认。接着调用make_tcphead函数,该函数的内部操作:"首先将TCP首部的源端口与目的端口互相对调,然后设置数据序号与确认序号,接着设置选项字节,最后更新偏移位。"接着计算校验和填充TCP首部中的校验和,最后通过ENC28J60将数据发送出去。
61行,发送同步请求应答TCP包后,continue语句重新接收数据包做处理。
65行通过if语句判断TCP包类型,判断方法是对TCP首部中的6个标识位进行识别(总第0x2F字节的后6位)判断ACK位是否置位,如果没有置位则if条件不成立继续往下执行,如果ACK位置位说明TCP包是一个TCP确认包。接下来就解析这个包数据
70行初始化数据格式,并获取TCP包,数据区长度。数据区长度保存在全局变量info_data_len中
71行用于获取数据区首地址在buf中的位置。其结果返回到dat_p变量。
74行判断是否为一个无数据的TCP包,如果有数据则不进入if内部,程序继续往下进行,如果是无数据的TCP包,则在if内部做继续判断
77行在上一个if内部继续做判断通过6个bit的标志位判断是否为要求释放连接(终止)的TCP包。如果不是则,continue继续等待重新接收数据包,如果是执行81行函数
81行函数对要求释放连接(终止)的TCP包做应答,它内部到操作函数是
1. void make_tcp_ack_from_any(unsigned char *buf)
2. {
3. unsigned int j;
4.
5. // 填写包的目的MAC地址以及源MAC地址
6. make_eth(buf);
7.
8. // 填充包的类型为ack响应包
9. buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V;
10.
11. // 判断接收的TCP包内是否有数据
12. if (info_data_len==0)
13. {
14. make_tcphead(buf,1,0,1);
15. }
16. else
17. {
18. make_tcphead(buf,info_data_len,0,1);
19. }
20.
21. // 设置IP包头中总长度:长度=IP头(20)+TCP头(20(不包括选项字节))
22. j=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN;
23. buf[IP_TOTLEN_H_P]=j>>8;
24. buf[IP_TOTLEN_L_P]=j& 0xff;
25.
26. // 填写包的目的IP地址以及源IP地址
27. make_ip(buf);
28.
29. // 计算校验和 长度=8 (开始于ip.src) + TCP头长(20) + 数据长度
30. j=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN,2);
31. buf[TCP_CHECKSUM_H_P]=j>>8;
32. buf[TCP_CHECKSUM_L_P]=j& 0xff;
33.
34. printf("nr神舟III号[%d.%d.%d.%d]发送ACK包响应",ipaddr[0],ipaddr[1],ipaddr[2],ipaddr[3]);
35.
36. enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN,buf);
37. }
首先make_eth,然后修改TCP中标志位,使TCP包变为应答包,根据TCP包中是否有数据make_tcphead,接着设置IP首部中包裹长度,接着make_ip,接着填充校验和,最后通过ENC28J60函数将数据发送出去。
如果是有数据的TCP包则接下来解析数据。
88行到93行为判断网络为Telnet方式登录的处理程序。首先判断的依据是真正用户数据(TCP数据)的前四个字节不是“GET ”,如果是Telnet登录方式则通过91行的函数填充数据。然后通过92行语句跳转至131行至135行,发送TCP确认包及TCP数据包。
94行到 101行为判断通过网页方式登录的处理程序。首先判断的依据是真正用户数据(TCP数据)的第4个字节和第5个字节为“/ ”,如果是这种方式则通过97行至99行填充TCP要发送的数据。同100行语句跳转至131行至135行,发送TCP确认包及TCP数据包。
如果不是以上两者之一的登录方式,则程序继续往下执行,分析TCP数据
104行分析网页控制命令,函数内部操作为
1. signed char analyse_get_url(char *str)
2. {
3. unsigned char i=0;
4.
5. // 密码错误则返回-1
6. if (verify_password(str)==0)
7. {
8. return(-1);
9. }
10.
11. // 密码不要长于9个,寻找第一个'/'
12. while(*str && i<10 && *str >',' && *str<'{')
13. {
14. if (*str=='/')
15. {
16. str++;
17. break;
18. }
19. i++;
20. str++;
21. }
22.
23. if (*str < 0x3a && *str > 0x2f)
24. {
25. // ascii码表中的数字
26. return(*str-0x30);
27. }
28.
29. return(-2);
30. }
该函数的实参是&(buf[dat_p+5]),即从实际用户数据的第5个字节开始分析,首先通过verify_password函数验证密码是否正确,验证的方式是通过strncmp函数将数据与密码做依次对比。接下来通过while语句寻找第一个“/”,然后返回“/”后面的那个数字作为命令。
当cmd命令为负数时实际上是没有通过密码验证的。当cmd为正数时是正确的命令根据不同的命令做不同的操作。具体看106行至124行。
127行用于更新网页信息,整个函数实际上都是在填充TCP数据。这个我也没太研究这里就不说了。。
如果也不是TCP包,我们继续往下执行程序看是否为UDP包
142行if语句判断是否UDP包,判断的依据为查看IP首部(总第0x17字节)的协议代码是否为17(17代表UDP),并且UDP首部目的端口(总第0x24字节和0x25字节)是否为1200.如果不正确则说明不是UDP包,程序继续往下执行。如果是UDP包,则执行if里面的函数
145行至147行用于获取UDP数据长度。
150行至153行,将UDP数据导入到buf1数组中
156行用于回复一个UDP应答包,包的发送的数据内容与接收到的包数据内容相同。
上一篇:STM32以太网程序解析二
下一篇:STM32以太网程序解析三
推荐阅读最新更新时间:2024-11-12 10:25
设计资源 培训 开发板 精华推荐
- LTC3638MPMSE 5V 至 140V 输入至 5V/250mA 输出和 20kHz 最小突发频率的典型应用电路
- 基于STHV64SW高压开关矩阵的评估板,用于超声成像应用
- LTC2258CUJ-12、12 位、65Msps 超低功耗 1.8V ADC 的典型应用电路
- 便携式电池充电器
- GS1084-1.8、5A 低压差正固定稳压器的典型应用
- 具有可编程电流限制的 LT3091HT7 线性稳压器的典型应用
- LT1764EFE-2.5 并联 LDO 稳压器以实现更高输出电流的典型应用
- 使用 ROHM Semiconductor 的 BD90640EFJ-C 的参考设计
- LT8631EFE 1MHz、3.3V、1A 降压转换器的典型应用电路
- OP284ESZ-REEL 高端负载电流监控器的典型应用