分类: 嵌入式
2014-05-31 16:03:24
第四章 ARP:地址解析协议
虽然数据链路层的第一道关卡是MAC地址,但基于TCP/IP的网络主要使用IP地址来标识主机而不使用MAC地址。比如要连接到别人的电脑或拷贝共享文件,一般会说:“告诉我你电脑的IP”,而不是“告诉我你电脑的MAC”。从以太网帧结构知道,不知道对方网卡的MAC地址是无法正常通讯的,那主机是怎样从IP地址上自动获取到MAC地址呢?这就是这章要讲的“地址解析协议”,以下简称其英文缩写“ARP”。
4.1 ARP工作原理
从对方的IP地址获取MAC地址最简单的方法是静态映射,即手工建立IP地址和MAC地址的映射表。这种方法必须预先知道每个IP对应的网卡的MAC地址,并写到程序里,发送数据时先搜索这张表,找到IP地址对应的MAC地址。静态映射表内容如下:
表 4-1 静态映射表
IP地址 |
MAC地址 |
192.168.1.15 |
00-0B-6A-8E-3F-C2 |
192.168.6.82 |
00-1C-35-27-59-A8 |
静态映射表有一定的局限性,如:一台电脑换过网卡后,查找得出的MAC地址就不正确,会导致通讯不上;当对方电脑的IP地址改变后,虽然MAC地址没有变,但映射关系变了,静态映射表也必须手工改变。这样,维护一张静态映射表就很费劲。
为了避免手工维护映射表,设计人员使用ARP协议来实现地址的映射,由主机自己智能地维护一张动态映射表。具体是怎样实现地呢?通过图4-1可以形象的说明。假如MCU主机需要与IP为192.168.1.15的主机建立连接,但不知道其MAC地址,于是先在整个网络广播,查询内“192.168.1.15“对应的MAC地址,由于是广播(目的MAC地址是FF-FF-FF-FF-FF-FF),同一网络上的所有主机都收到了这个请求。但只有电脑A应答,因为它的IP就是192.168.1.15。MCU收到电脑A的应答后,将IP和MAC地址存放在动态映射表中,下次连接的时候就能直接查找动态表。
当然,动态映射表中,IP和MAC的映射关系并不是一成不变的,ARP还启动一个定时器,当映射关系存在一定的时间(如1分钟)后,会被清除掉,下次发送数据时还是需要通过ARP请求获取它们的对应关系。这个过程称为ARP表老化。
图4-1 ARP 工作原理
4.2 ARP分组结构
ARP分组是封装在以太网帧中的数据段中,当以太网帧首部的TYPE段为0806H时,表示后边的数据是ARP分组。如图4-2。
图4-2 ARP 分组的封装
ARP分组的具体结构如图4-3。
0 8 16 24 31
硬件类型 |
协议类型 |
|
硬件长度 |
协议长度 |
操作 |
发送方MAC地址(6字节中的0-3字节) |
||
发送方MAC地址(4-5字节) |
发送方IP地址(0-1字节) |
|
发送方IP地址(2-3字节) |
接收方MAC地址(0-1字节) |
|
接收方MAC地址(2-5字节) |
||
接收方IP地址(0-3字节) |
||
图4-3 ARP 分组的格式
硬件类型:16位,定义运行ARP的物理网络。对以太网来说固定为0001H。还有0002H为实验以太网,0003H为业余无线电,0004H为令牌网等等。
协议类型:16位,定义发送方提供的高层协议类型。对IPV4来说,固定为0800H。
硬件长度:8位,定义物理地址(MAC地址)的长度,以字节为单位,对以太网来说,固定为06H。
协议长度:8位,定义逻辑地址(IP地址)的长度,以字节为单位,对应以太网的IPV4,长度固定为04H。
操作:16位,定义ARP分组是请求还是应答。请求则为01H,应答为02H。
发送方/接收方MAC地址:48位(针对以太网)。
发送方/接收方IP地址:32位(针对以太网)。
了解ARP的分组的格式后,就可以将图4-1 中ARP的工作原理用具体数据来表示,如图4-4。
图4-4 ARP 分组的图例
4.2 ARP的实现
uIP协议栈实现ARP的文件是Uip_arp.c,包含uip_arp_init(),uip_arp_timer(),uip_arp_update(),uip_arp_arpin(),uip_arp_out()5个函数。
4.2.1 ARP初始化
根据ARP分组的格式,uip头部结构定义如下,为了便于管理,它包含了以太网帧的头部uip_eth_hdr。
struct arp_hdr
{
struct uip_eth_hdr ethhdr; /*以太网首部,14字节*/
u16_t hwtype; /*硬件类型,0x0001*/
u16_t protocol; /*协议类型,0x0800*/
u8_t hwlen; /*硬件长度,0x06*/
u8_t protolen; /*协议长度,0x04*/
u16_t opcode; /*操作码,ARP请求:0x1;ARP应答:0x2*/
struct uip_eth_addr shwaddr; /*发送方MAC地址*/
u16_t sipaddr[2]; /*发送方IP地址*/
struct uip_eth_addr dhwaddr; /*接收方MAC地址*/
u16_t dipaddr[2]; /*接收方IP地址*/
};
前面说过,ARP协议的目的就是主机自动维护一张动态映射表,uIP对动态映射表的结构定义如下:
struct arp_entry
{
u16_t ipaddr[2]; /*IP地址*/
struct uip_eth_addr ethaddr; /*MAC地址*/
u8_t time; /*IP-MAC映射生成时间*/
};
表 4-2 uip的ARP动态映射表
IP地址 |
MAC地址 |
映射生成时间 |
192.168.1.15 |
00-0B-6A-8E-3F-C2 |
13 |
可以看到,它比静态映射表多了一项time,主要用来老化ARP表,存放的是一个时间计数arptime,这个计数默认是每10秒加1,写映射关系的时候取当前的arptime值存入time项。ARP动态映射表定义成一个全局变量arp_table ,在单片机的网路设计中,定义如下:static struct arp_entry xdata arp_table[UIP_ARPTAB_SIZE],其最多保存的映射关系是UIP_ARPTAB_SIZE个,默认值是8,可修改。
ARP的初始化函数uip_arp_init()就是将动态映射表arp_table里的IP地址项全部清零。使用的语句是:memset(arp_table[i].ipaddr, 0, 4);
4.2.2 ARP分组的处理
当收到的以太网帧的类型是0x0806时,调用void uip_arp_arpin(void)函数对收到的ARP分组进行处理。其实现流程图见图4-5。其中的更新动态映射表的功能由函数uip_arp_update()完成,流程图见4-6。
图4-5 ARP分组的处理流程图
图4-5 ARP更新动态映射表流程图
4.2.2 ARP动态映射表的老化
函数void uip_arp_timer(void)执行动态映射表的老化功能,这个函数每10秒被调用一次,进入该函数时,时间计数arptime加1,同时与动态映射表里的time项比较,当发现arptime - tabptr->time >= 120时,将该项的IP清零。也就是说,动态映射表里的映射关系在连续20分钟内没有刷新的话将失效。
4.2.2 ARP请求的自动发送
前面的介绍可以知道,本机IP层的发送函数只知道对方IP地址,而不知道对方的MAC地址,按分层的概念,它填充完IP头部的信息后就交给以太网帧处理。以太网帧的头部需要填充目的MAC地址,源MAC地址,类型。其中源MAC地址是本机MAC,类型是IP 0x0800,均已知。目的MAC呢?首先要查动态映射表,找到接收方IP对应的MAC地址填充。若此时动态映射表中没有映射关系,就必须按ARP请求的格式构造一个ARP请求分组发送给本地网路上的所有网络设备,获取到IP对应的MAC地址后才能正常发送。这些功能由void uip_arp_out(void)函数完成。