LWIP协议栈:ARP协议
Posted linfeng-learning
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LWIP协议栈:ARP协议相关的知识,希望对你有一定的参考价值。
1. ARP协议简介
-
ARP(Address Resolution Protocol),地址解析协议。ARP协议处于网络层,其主要功能就是通过目标设备的 IP 地址,查询目标设备的 MAC 地址,从而进行网络通信。
-
网络层中,源主机和目标主机依赖于IP地址进行通信。而链路层又有自己的寻址寻址机制(如,以太网依赖于MAC地址进行通信)。ARP的作用在于将IP地址转换为MAC地址,从而连接网络层与链路层,使得上层可以通过IP地址进行网络通信。
-
ARP协议的基本运作过程如下:
2. ARP缓存表
2.1 ARP缓存表的定义
每台主机或路由器在其内存中都存储着一个ARP缓存表,表中记录着了<IP 地址,MAC 地址>对,反映着目标主机的IP地址与MAC地址的映射关系。
1 /*lwip/src/netif/etharp.c*/ 2 3 enum etharp_state { 4 ETHARP_STATE_EMPTY = 0, //空状态,表示该表项为空 5 ETHARP_STATE_PENDING, //挂起状态,表示该表项还未收到目标主机的ARP应答 6 ETHARP_STATE_STABLE, //可用状态,表示该表项可用 7 ETHARP_STATE_STABLE_REREQUESTING_1,//过渡状态 8 ETHARP_STATE_STABLE_REREQUESTING_2 //过渡状态 9 #if ETHARP_SUPPORT_STATIC_ENTRIES 10 , ETHARP_STATE_STATIC 11 #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ 12 }; 13 14 struct etharp_entry { 15 #if ARP_QUEUEING 16 /* 指向此ARP表项上挂起的数据包队列*/ 17 struct etharp_q_entry *q; 18 #else /* ARP_QUEUEING */ 19 /*指向此ARP表项上挂起的单个数据包 */ 20 struct pbuf *q; 21 #endif /* ARP_QUEUEING */ 22 ip_addr_t ipaddr; //目标主机的IP地址 23 struct netif *netif; //目标主机的网卡信息 24 struct eth_addr ethaddr;//目标主机的MAC地址 25 u8_t state; //此表项的状态 26 u8_t ctime; //此表项的生存时间 27 }; 28 29 static struct etharp_entry arp_table[ARP_TABLE_SIZE]; //LWIP协议栈的ARP缓存表
- 表项的数据包指针q:指针q指向需要发送至该目标主机的数据包。struct etharp_q_entry *q指向一个数据包队列,struct pbuf *q指向单个数据包。
- 表项的生存时间ctime:每个表项都包含一个ctime变量,表示该表项的生存时间。当达到指定的生存时间,该表项会被删除。
2.2 缓存表的动态处理
ARP协议的核心就是对缓存表的动态处理。因为IP地址可能是动态的,所以ARP缓存表必须动态更新。
ARP协议中,通过发送ARP请求包、接收ARP应答包、ARP缓存表超时处理来实现缓存表的动态更新。
(1)发送ARP请求包
发送数据时,若不存在目标主机的表项,则新建一个表项,并发送ARP请求包;若存在目标主机的表项,对处于ETHARP_STATE_STABLE的表项,会再次发送ARP请求包,以确认目标主机依然在工作状态。详见4. ARP协议工作流程。
(2)接收ARP应答包
接收到ARP应答包时,将ARP应答包包含的<IP 地址,MAC 地址>对添加到缓存表。详见4. ARP协议工作流程。
(3)ARP缓存表超时处理
缓存表的超时处理。周期性(1S)调用 etharp_tmr()函数,动态更新缓存表项的生存时间,以及它的状态。
在ARP缓存表的动态更新过程中,其表现状态变化过程如下:
3. ARP报文
ARP协议的请求与应答同时通过ARP报文来实现的。ARP的报文将被封装在以太网帧中进行发送。
3.1 以太网帧结构
(1)MAC地址
MAC Address(Media Access Control Address),亦称为 EHA(Ethernet Hardware Address)、硬件地址、物理地址(Physical Address)、链路地址。MAC的值被固化在网卡的ROM中,以唯一标识该网卡。MAC地址长度为 6字节,其前 3个字节(组 织唯一标志符)表示厂家的代码,后 3个字节(扩展标识符)由厂家自行分配。 目标 MAC地址可以分成三类,单播地址、多播地址和广播地址。
- 单播地址:即目标主机的MAC地址,发送数据至特定的目标主机。
- 多播地址:MAC的第一个字节的bit0为1,发送数据至多个目标主机。
- 广播地址:MAC地址为全1,即FF-FF-FF-FF-FF-FF,发送数据至同一子网内的所有主机。
(2)以太网帧结构
在链路层中,数据被封装为以太网帧结构进行发送。以太网帧结构如下:
前同步码:它的作用是实现物理层帧输入输出的同步,其值都是 10101010(0x55,大端模式)。
- 帧开始符:表示着以 太网帧的开始,其值都是 10101011(0xD5, 大端模式)。
- 目标MAC地址:接收设备的MAC地址。
- 源MAC地址:发送设备的MAC地址。
- 类型:表示网络协议的类型。一台给定的主机可以支持多种网络层协议,不同的应用采用不同的协议。因此,当以太网帧到达网卡中,网卡需要知道它应该将数据字段的内容传递给哪个网络层协议。如 IP 协议、ARP协议等。
- 数据:包含需要被发送的数据(如IP数据包、ARP数据包)。以太网的最大传输单元 (MTU)是1500字节,若数据包超过1500字节,则需要分片传输;若数据包小于46字节,则需要填充至46字节再发送。
- CRC:以太网的差错校验信息。
P.S.:当“类型”字段的值小于 1518时,它表示后面数据字段的数据长度,当大于1518的时候才表示递交给哪个协议。
3.2 ARP报文结构
(1)ARP报文格式如下:
- 硬件类型:目标网卡的硬件类型,表明ARP报文可以在哪种类型的网络上传输。1表示以太网地址。
- 协议类型:硬件地址要映射的协议地址类型。映射IP地址时的值为0x0800.
- 硬件地址长度:即MAC地址的长度(以太网的MAC地址长度为6)。
- 协议地址长度:即IP地址的长度。
- 操作类型:指定本次ARP报文的类型。1:ARP请求报文;0:ARP响应报文。
- 源MAC地址:发送设备的MAC地址。
- 源IP地址:发送设备的IP地址。
- 目标MAC地址:接收设备的MAC地址。在ARP请求报文中,目标MAC地址未知,MAC字段的值为全0(即00-00-00-00-00-00)。
- 目标IP地址:接收设备的IP地址。
(2)ARP帧格式:
ARP报文将被传输到链路层,加上以太网的帧头,形成ARP帧,再通过链路层发送出去。ARP帧的格式如下:
- 目标MAC地址:接收设备的MAC地址。在ARP请求报文中,它的目标为网络上的所有主机,目标MAC字段的值为FF-FF-FF-FF-FF-FF(广播地址)。
- 源MAC地址:发送设备的MAC地址。
- 帧类型:标识帧封装的上层协议。此处封装的为ARP协议,它的值为0x0806。
(3)帧格式的定义
1 /*lwip2.1.2/src/include/lwip/port/ethernet.h*/ 2 #define ETH_HWADDR_LEN 6 //以太网地址长度 3 4 struct eth_addr //以太网地址结构体 5 { 6 PACK_STRUCT_FLD_8(u8_t addr[ETH_HWADDR_LEN]); 7 } PACK_STRUCT_STRUCT; 8 9 struct eth_hdr //以太网首部 9 10 { 11 PACK_STRUCT_FLD_S(struct eth_addr dest); //以太网目标 MAC 地址 12 PACK_STRUCT_FLD_S(struct eth_addr src); //以太网源 MAC 地址 13 PACK_STRUCT_FIELD(u16_t type); //帧类型 14 } PACK_STRUCT_STRUCT; 15 16 17 /*lwip2.1.2/src/include/lwip/port/etharp.h*/ 18 struct etharp_hdr //ARP 报文 19 { 20 PACK_STRUCT_FIELD(u16_t hwtype); //硬件类型 21 PACK_STRUCT_FIELD(u16_t proto); //协议类型 22 PACK_STRUCT_FLD_8(u8_t hwlen); //硬件地址长度 23 PACK_STRUCT_FLD_8(u8_t protolen); //协议地址长度 24 PACK_STRUCT_FIELD(u16_t opcode); //op 字段 25 /* 以上是 ARP 报文首部 */ 26 27 PACK_STRUCT_FLD_S(struct eth_addr shwaddr); //源 MAC 地址 28 PACK_STRUCT_FLD_S(struct ip4_addr_wordaligned sipaddr);//源 ip 地址 29 PACK_STRUCT_FLD_S(struct eth_addr dhwaddr); //目标 MAC 地址 30 PACK_STRUCT_FLD_S(struct ip4_addr_wordaligned dipaddr);//目标 ip 地址 31 } PACK_STRUCT_STRUCT; 32 33 enum etharp_opcode //op 字段操作 34 { 35 ARP_REQUEST = 1, //请求包 33 36 ARP_REPLY = 2 //应答包 34 37 };
4. ARP协议工作流程
(1)数据包接收流程说明:
- 硬件网卡接收到数据之后,会调用ethernet_input()函数来处理接收到的数据包。ethernet_input()函数根据数据包中的以太网首部的帧类型进行分别处理;当帧类型为IP协议,则该数据包为IP数据包,调用ip4_input()函数进行处理;当帧类型为ARP协议,则该数据包为ARP数据包,调用 etharp_input()函数进行处理。
- etharp_input()函数对ARP数据包进行处理。首先调用 etharp_update_arp_entry()更新ARP缓存表。然后判断ARP数据包类型。如果是ARP请求包,且是发送给本机的,则调用 etharp_raw()函数发送ARP应答包;如果不是发送给本机的ARP请求包,则丢弃。
- etharp_update_arp_entry()对ARP缓存表进行更新。首先查找或创建ARP表项,设置新建表项的信息。然后检查改表项是否含有未发送的数据包,若存在,则调用ethernet_output()函数发送该表项上的数据。
(2) 数据包接收流程说明:
- 上层调用etharp_output()函数来发送IP数据包。对于广播、多播数据包,调用ethernet_output()函数直接发送数据包。对于单播数据包,若源主机与目标主机不在同一个子网,则修改IP地址为网关地址;然后遍历ARP缓存表,如果存在与目标IP地址对应的表项,且表项状态>=ETHARP_STATE_STABLE,则调用 etharp_output_to_arp_index()函数发送IP数据包;若不存在,则调用etharp_query()函数。
- etharp_output_to_arp_index()函数用来发送IP数据包。(此时表项状态必须>=ETHARP_STATE_STABLE)首先,更新该表项信息,确认目标主机是否在工作状态。当表项还有15s到期,调用(etharp_request()函数以广播方式发送ARP数据包;当表项还有30秒到期,调用etharp_request_dst()函数以单播方式发送ARP请求包。若表项有效期大于30s,则调用ethernet_output()函数发送IP数据包。
- 当ARP表中没有与目标IP地址对应的表项,或表项的状态为ETHARP_STATE_PENDING,则etharp_query()函数被调用。etharp_query()函数首先调用 etharp_find_entry()函数查询或创建新的表项,当该表项为新建表项,或该表项的数据队列为空时,调用etharp_request()函数发送ARP请求。然后判断表项的状态,当表项状态>=ETHARP_STATE_STABLE,则调用ethernet_output函数发送数据包;当表项状态为ETHARP_STATE_PENDING,则将数据包插入该表项的数据包队列。
以上是关于LWIP协议栈:ARP协议的主要内容,如果未能解决你的问题,请参考以下文章