Appearance
ARP协议
Address Resolution Protocol地址解析协议
ARP协议就是根据目标IP地址以广播方式获取相应的MAC地址,并将MAC地址存入ARP缓存表, 是TCP/IP协议里面的其中一个
在发送数据包的时候需要使用这一个格式(以太网帧), 需要知道对方的MAC地址, IP地址主要使用在广域网里面, 是一个可变的, 解决数据在外网里面传输的问题, MAC地址是使用在内网里面, 是不可变的唯一的地址
实际获取的是路由器的MAC地址, 在到达路由器以后路由器会重新进行填充
发送ARP请求
主要是在etharp文件里面实现的
函数的名字是etharp_output()
c
struct etharp_entry {
/** Pointer to a single pending outgoing packet on this ARP entry. */
struct pbuf *q; //挂起数据
ip4_addr_t ipaddr; //目标的地址
struct netif *netif; //当前使用的网卡
struct eth_addr ethaddr; //MAC地址
u16_t ctime; //保存的时间
u8_t state; //状态
};
使用这一个结构体记录ARP缓存表, 这里面记录的信息是有时效的
c/** ARP states */ enum etharp_state { ETHARP_STATE_EMPTY = 0, //ARP缓存表处于初始化的状态 ETHARP_STATE_PENDING, //只记录IP地址, 还没有获取MAC地址 ETHARP_STATE_STABLE, //应答前, 数据包被挂起了, 应答以后更新以及发送数据 ETHARP_STATE_STABLE_REREQUESTING_1,//发送状态 ETHARP_STATE_STABLE_REREQUESTING_2 };
etharp_output函数调用的时候, 如果可以在这一个表里面获取到对方的MAC地址, 进行添加以太网的头部(etharp_output_to_arp_index => ethernet_output函数里面进行), 然后发送数据
找不到的话会使用etharp_query这一个函数
这一个函数首先调用etharp_find_entry再次进行查找, 如果没有的话返回一个可以使用的etharp_entry表项的索引, 记录ip地址, 这时候他的状态是ETHARP_EMPTY
之后在etharp_query函数里面对这一个结构体进行初始化, 以及使用函数etharp_request发送一个ARP包, 最后调用的是etharp_raw函数, 会在这个函数里面构建一个pbuf进行发送
ARP帧(28字节)
000e: 00 01
0010: 08 00 06 04 00 01 00 05 5d 61 58 a8 c0 a8 00 37
0020: 00 00 00 00 00 00 c0 a8 00 02
00 01: 硬件为以太网
08 00 : 解析一个IP地址
06 :硬件地址长度
04 :协议地址长度, 表示ip地址长度
00 01 : op字段为1表示ARP请求,op字段为2表示ARP应答。
00 05 5d 61 58 a8 : 自己的MAC地址
c0 a8 00 37 : IP地址192.168.0.55
00 00 00 00 00 00 : 目的MAC地址, 未知填0
c0 a8 00 02 : 目的地ip地址
c
struct etharp_hdr {
PACK_STRUCT_FIELD(u16_t hwtype);
PACK_STRUCT_FIELD(u16_t proto);
PACK_STRUCT_FLD_8(u8_t hwlen);
PACK_STRUCT_FLD_8(u8_t protolen);
PACK_STRUCT_FIELD(u16_t opcode);
PACK_STRUCT_FLD_S(struct eth_addr shwaddr);
PACK_STRUCT_FLD_S(struct ip4_addr_wordaligned sipaddr);
PACK_STRUCT_FLD_S(struct eth_addr dhwaddr);
PACK_STRUCT_FLD_S(struct ip4_addr_wordaligned dipaddr);
} PACK_STRUCT_STRUCT;
使用这一个进行填充, 最后使用ethernet_output进行发送
会在ethernet_input这一个函数里面去除以太网首部, 以及根类型调用不同的处理函数