问题
作者在STM32平台移植LWIP后计划向PC传输数据,再传输之前修改一些必要的参数值,tot_len和len,如下图所示:
但是网络助手无法接收到数据,作者采取了WireShark抓包的方式分析了PC-STM32开发板之间的UDP数据包,发现开发板传来的数据包IP头中的数据长度出现了错误。
那么错误具体是什么呢?
UDP echo 正常数据包分析
如下图所示,IP头中的版本号和包头长是正确的,协议版本号为IPV4,UDP包头长度20Bytes。
下一个字段的IP数据包总长度,如下图所示,为38,也是正确的。
整个MAC帧一行16Bytes,总共4行,64-4=60Bytes,其中含有以太网的14+8=22Bytes,剩余的就是38Bytes的IP部分。
换言之,整个以太网包共有60bytes,其中38Bytes是IP包内容,也就是以太网的数据段,这个IP包里面有地址和端口信息和真正要传输的数据。
如下图所示,这个字段是生存时间TTL,再跳255次,此包将被认为不可达,进而被删除。
如下图所示的字段标识IP的上一层的协议内容,这里就是UDP了。
如下图所示的红黄两个方框标识的是发送IP和接收IP,分别为192.168.240和接收192.168.1.68。
r如下图所示的两个字段是源端口和目的端口,分别为2040和2041。注意端口号16bits,最大为FFFF也就是是65535,所以端口号不会大于65535.
如下图所示的字段是数据段长度,IP部分共38Bytes,除去头的20Bytes,就是此数据段的18Bytes。
这18Bytes里面含源端口目的端口,数据段长度以及校验和之类的其他数据(也就是UDP头),真正传输的数据部分长度为10,这里是66666666/n/r
UDP负载长度10bytes如下图所示,这里是66666666/n/r。
这里就是UDP的真实负载了。
UDP Send 错误数据包分析
如下图左所示,hellooooooooooooooooo oooooooooooo!这个字符串以及数组越界的UDP负载长度为52,也就是我们设置的len,可见len这部分(如下图右所示)并不会被写入网络帧,只是用于记录待发送数据包有多长。
我的UDP负载字段是52,那么UDP包长度就应该为52+8 = 60,加上IP头,IP包总长度应该是60+20=80,但是如下图所示的总长度字段为122=94+20+8。
可见LWIP中len字段是用于截取字符串的,tot_len才是表示UDP payload长度的变量,因而此变量会被加上UDP头长度8和IP头长度20作为IP头中的总长度字段。
因此此值如下图所示设置为与len一致即可。
若不一致接收端(PC)计算检验和时对不上,认为有错误,就不会显示了。
参考资料
IP头格式(https://blog.csdn.net/u011425939/article/details/103135282):
UDP头格式(https://blog.csdn.net/zuochao_2013/article/details/80561793):
检验和计算方法(https://blog.csdn.net/gao1440156051/article/details/51210320):
最后对上述过程举个例子:
IP头:
45 00 00 31
89 F5 00 00
6E 06 00 00(校验字段)
DE B7 45 5D -> 222.183.69.93
C0 A8 00 DC -> 192.168.0.220
计算:
4500 + 0031 +89F5 + 0000 + 6e06+ 0000 + DEB7 + 455D + C0A8 + 00DC =3 22C4
0003 + 22C4 = 22C7
~22C7 = DD38 ->即为应填充的校验和
当接受到IP数据包时,要检查IP头是否正确,则对IP头进行检验,方法同上:
计算:
4500 + 0031 +89F5 + 0000 + 6E06+ DD38 + DEB7 + 455D + C0A8 + 00DC =3 FFFC
0003 + FFFC = FFFF
得到的结果是全一,正确。