LWIP主线

STM32+LWIP------报文格式解析

1. DMA描述符

平台为stm32F407+LAN8720,使用DMA中断接收方式。在ST提供的以太网驱动程序stm32f4x7_eth.c中使用的DMA描述符管理缓冲区,其连接结构描述如下图:

  • 一个以太网数据包可以跨越一个或者多个DMA描述符。

  • 一个DMA描述符只能用于一个以太网数据包。

  • DMA描述符列表中的最后一个描述符指向第一个,形成链式结构。

    在ST的以太网驱动程序stm32f4x7_eth.h中用ETH_DMADESCTypeDef定义DMA描述符,代码如下:

    typedef struct  {
      __IO uint32_t   Status;           /*!状态 */
      uint32_t   ControlBufferSize;     /*控制Buffer1,和Buffer2的长度*/
      uint32_t   Buffer1Addr;           /*Buffer1 地址 */
      uint32_t   Buffer2NextDescAddr;   /* Buffer2 地址或者下一个描述符地址 */
    /* 增强的以太网DMA描述符 */
    #ifdef USE_ENHANCED_DMA_DESCRIPTORS
      uint32_t   ExtendedStatus;        /*增强描述符状态*/
      uint32_t   Reserved1;             /* 保留*/
      uint32_t   TimeStampLow;          /* 时间戳低位 */
      uint32_t   TimeStampHigh;         /* 时间戳高位 */
    #endif /* USE_ENHANCED_DMA_DESCRIPTORS */
    } ETH_DMADESCTypeDef;
    

    2. DMA描述符链式结构

    STM32的DMA描述符又分为发送描述符和接收描述符,它们都用ETH_DMADESCTypeDef来定义,用图说明以接收描述符(发送描述符类似)的链式结构如图:

在stm32f4x7_eth.c文件中定义两个DMA描述符数组,一个用DMA接收一个用于DMA发送,代码如下:

 __align(4)  ETH_DMADESCTypeDef  DMARxDscrTab[ETH_RXBUFNB];/* Ethernet Rx MA Descriptor */
 __align(4)  ETH_DMADESCTypeDef  DMATxDscrTab[ETH_TXBUFNB];/* Ethernet Tx DMA Descriptor */
 __align(4)  uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE]; /* Ethernet Receive Buffer */
 __align(4)  uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE]; /* Ethernet Transmit Buffer */

3. DMA追踪描述符

因为它们被用作数据缓冲,那么占用内部RAM太多,所以在工程中用内存分配函数为它们在外部SRAM中申请内存。有了缓冲区后,stm32f4x7_eth.c为了追踪Rx/Tx DMA描述符还定义了两个全局指针变量:

__IO ETH_DMADESCTypeDef  *DMATxDescToSet;
__IO ETH_DMADESCTypeDef  *DMARxDescToGet;

这两个指针变量用于指向下一个要发送或者接受的数据包,图示:

2. 以太网帧结构

我们知道TCP/IP协议采用分层结构,其分层模型及协议如下表:

应用层 HTTP、Telnet、FTP、SMTP、SNMP
传输层 TCP、UDP
网间网层 IP[ARP、RARP、ICMP]
网络接口层 Ethernet、X.25、SLIP、PPP

任何通讯协议都有独特的报文格式,TCP/IP协议也不例外。对于通讯协议编程,我们首先要清楚其报文格式。由于TCP/IP协议采用分层模型,各层都有专用的报头,以下就简单介绍以太网下TCP/IP各层报文格式。

以太网是目前最流行的一种局域网组网技术,其正式标准是IEEE 802.3标准,它规定了在以太网中传输的数据帧结构,其结构如下所示:

前同步码 SFD 目的地址 源地址 长度/类型 数据和填充 CRC
7字节 1字节 6字节 6字节 2字节 46字节~1500字节 4字节

8字节的前导用于帧同步,CRC域用于帧校验。这些用户不必关心其由网卡芯片自动添加。目的地址和源地址是指网卡的物理地址,即MAC地址,具有唯一性。帧类型或协议类型是指数据包的高级协议,如 0x0806表示ARP协议,0x0800表示IP协议等

  • 在物理层上看,一个完整的以太网帧有7个字段,事实上,前两个字段并不能算是真正意义的以太网数据帧,他们是网卡在物理层上的发送以太网数据时添加上去的,为了实现底层数据的数据传输,物理层使用7个字节前同步码(0和1交替的56位)实现物理层帧输入/输出的同步;使用1个字节SFD(帧首定界符,固定10101011)标识帧的开始。

  • 剩余5个字段是真正的以太网数据,其中包含了目的地址和源地址,它们都是6字节长度(MAC地址长度通常为6),因为MAC能在网络上唯一的标识自己,网卡接收数据时,通常将目的地址字段和自身MAC地址比较,判断是否接收该数据包。

  • 长度/类型字段具有两个意义,当这两个字节的值小于1518时,那么它代表了其后数据字段的长度;如果大于1518,则表示该以太网帧中的数据属于哪个上层协议(IP数据包:0x800, ARP数据包:0x806)。

  • 数据和填充表示该以太网帧携带的上层协议数据,它们的最小长度为46字节,最大长度位1500字节。

  • CRC字段值包含了该以太网帧的错插脚验信息。

    以太网帧又可细分,如图:

3. ARP数据报

ARR协议的基本功能是使用目标主机的IP地址,查询其对应的MAC地址,以保证底层链路上数据包通信的进行。

ARP数据包分为ARP请求包和应答包,ARP请求包通过以太网广播的方式发送,用于向具有某个IP地址的主机发送请求,希望该主机返回其MAC地址;ARP应答包,收到ARP请求的主机会对比该数据包中的IP地址与自己的IP是否符合,若是,则该主机向源主机返回一个ARP应答包,向源主机报告自己的MAC地址。源主机通过提取ARP应答包中的相关字段来更新ARP缓存表。ARP数据包经典的组成结构如下:

在LWIP中的etharp.h中用了一大堆的数据结构和宏来描述:

PACK_STRUCT_BEGIN
/** the ARP message, see RFC 826 ("Packet format") */
struct etharp_hdr {
  PACK_STRUCT_FIELD(u16_t hwtype);               //硬件类型(2个字节)
  PACK_STRUCT_FIELD(u16_t proto);                //协议类型(2个字节)
  PACK_STRUCT_FIELD(u8_t  hwlen);                //硬件地址长度(1个字节)
  PACK_STRUCT_FIELD(u8_t  protolen);             //协议地址长度(1个字节)
  PACK_STRUCT_FIELD(u16_t opcode);               //操作字段op(2字节)
  PACK_STRUCT_FIELD(struct eth_addr shwaddr);    //发送方MAC地址(6字节)
  PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);    //发送方IP地址(4字节)
  PACK_STRUCT_FIELD(struct eth_addr dhwaddr);    //接收方MAC地址(6字节)
  PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);    //接收方IP地址(4字节)
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END

4. IP数据报

IP数据报和ARP报文都是组装在以太网数据帧中发送的。IP数据报有自己的组织格式,它分为IP首部和数据,如图所示:

首部可以有20~60字节,可以包含40在细节的选项字段,但通常没有,银子常见的IP首部长度位20个字节。数据包规定首部的格式,却没有规定其后的数据的格式,所以P数据报可以用来运输任意类型的数据。

5. ICMP报文

ICMP协议用于在IP主机、路由器之间传递控制消息,这里的控制消息可以包括很多种,例如报错误信息、网络状况信息、主机状况信息等,这些控制消息虽然不传输用户数据,但是对于用户数据报的有效递交起着重要作用。

ICMP报文时使用IP数据报来封装和发送的,携带ICMP报文的IP数据报完全向携带其他类型的数据报那样在网络中被转发,没有额外的可靠性和优先性。IP数据报时封装在底层物理数据帧中发送的,这样ICMP报文会经历两次封装过程,如图:

ICMP使用IP进行交互,是因为一个报文可能要经过几个物理网络才能到达其最终目的地,因此它不可能单独地通过某个物理传输进行交付,必须使用IP提供的交付服务,屏蔽掉各种底层物理结构的差异。

ICMP的报文有8个字节首部和可变长度的数据部分组成。

  • 对于不同类型的ICMP报文,首部的格式也会出现一定的差异,但是首部前4个字节的字段对所有类型都是通用的。首部用一个结构体描述,如下:
PACK_STRUCT_BEGIN
struct icmp_echo_hdr {
  PACK_STRUCT_FIELD(u8_t type);//标识该ICMP报文的具体类型
  PACK_STRUCT_FIELD(u8_t code);//进一步指出产生这种类型的ICMP的原因
  PACK_STRUCT_FIELD(u16_t chksum);//校验
  PACK_STRUCT_FIELD(u16_t id);
  PACK_STRUCT_FIELD(u16_t seqno);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
  • 不同类型的报文,数据部分的长度和含义也存在着差异。总的来说,差错报告报文的数据部分携带了引起差错的IP数据报信息;查询报文的数据部分懈怠了查询请求或查询结果相关的数据。

    ICMP报文格式如图:

6. UDP数据报

UDP协议在IP协议上增加了复用、分用和差错检测功能。UDP的特点:

  1. 无连接的。相比于TCP协议,UDP协议在传送数据前不需要建立连接,当然也就没有释放连接。

    尽最大努力交付的。也就是说UDP协议无法保证数据能够准确的交付到目的主机。也不需要对接收到的UDP报文进行确认。

    1. 面向报文的。也就是说UDP协议将应用层传输下来的数据封装在一个UDP包中,不进行拆分或合并。因此,运输层在收到对方的UDP包后,会去掉首部后,将数据原封不动的交给应用进程。

      没有拥塞控制。因此UDP协议的发送速率不送网络的拥塞度影响。

      5. UDP支持一对一、一对多、多对一和多对多的交互通信。

UDP协议分为首部字段和数据字段,其中首部字段只占用8个字节,分别是个占用两个字节的源端口、目的端口、长度和检验和。

长度:UDP报文的整个大小,最小为8个字节(仅为首部)。

检验和:在进行检验和计算时,会添加一个伪首部一起进行运算。伪首部(占用12个字节)为:4个字节的源IP地址、4个字节的目的IP地址、1个字节的0、一个字节的数字17、以及占用2个字节UDP长度。这个伪首部不是报文的真正首部,只是引入为了计算校验和。相对于IP协议的只计算首部,UDP检验和会把首部和数据一起进行校验。接收端进行的校验和与UDP报文中的校验和相与,如果无差错应该全为1。如果有误,则将报文丢弃或者发给应用层、并附上差错警告。

最后给出udp报文的封装格式:

7. TCP数据报

(1)TCP源端口(Source Port):16位的源端口包含初始化通信的端口号。源端口和IP地址的作用是标识报文的返回地址。

(2)TCP目的端口(Destination Port):16位的目的端口域定义传输的目的。这个端口指明报文接收计算机上的应用程序地址接口。

(3)序列号(Sequence Number):TCP连线发送方向接收方的封包顺序号。

(4)确认序号(Acknowledge Number):接收方回发的应答顺序号。

(5)头长度(Header Length):表示TCP头的双四字节数,如果转化为字节个数需要乘以4。

(6)URG:是否使用紧急指针,0为不使用,1为使用。

(7)ACK:请求/应答状态。0为请求,1为应答。

(8)PSH:以最快的速度传输数据。

(9)RST:连线复位,首先断开连接,然后重建。

(10)SYN:同步连线序号,用来建立连线。

(11)FIN:结束连线。如果FIN为0是结束连线请求,FIN为1表示结束连线。

(12)窗口大小(Window):目的机使用16位的域告诉源主机,它想收到的每个TCP数据段大小。

(13)校验和(Check Sum):这个校验和和IP的校验和有所不同,不仅对头数据进行校验还对封包内容校验。

(14)紧急指针(Urgent Pointer):当URG为1的时候才有效。TCP的紧急方式是发送紧急数据的一种方式。

posted @ 2022-07-12 17:29  不明白就去明白  阅读(1030)  评论(0编辑  收藏  举报