前面提到netif->input()根据eth_hdr数据据构的type项决定下一步将数据传入ARP模块还是送入IP层,那先看看传入ARP模块的ARP数据包(数据结构为etharp_hdr)。etharp_arp_input()通过调用ip_addr_cmp(&dipaddr, &(netif->ip_addr))首先比较数据包里的目的IP地址与本地的IP地址是否相同,判断此数据包是否传给自己,然后调用update_arp_entry()更新ARP表,接着,根据数据包里的ARP数据报头的操作码散转处理,操作码主要是ARP请求和ARP应答。对于ARP请求,将接收到的数据包里的源IP地址和目的IP地址对换,操作码变为ARP应答,源MAC地址与目的MAC地址对换后,调用netif->linkoutput(netif, p)完成对ARP请求的响应,这个分支就到此结束了;对于ARP应答,前面调用update_arp_entry()时,已经处理了。
完整的ARP数据包由etharp.h里的eth_hdr数据结构定义:
PACK_STRUCT_BEGIN
struct etharp_hdr {
PACK_STRUCT_FIELD(struct eth_hdr ethhdr);//前面定义过的以太网包头
PACK_STRUCT_FIELD(u16_t hwtype);//硬件地址类型
PACK_STRUCT_FIELD(u16_t proto);//协议类型,其值与以太网包头的type值相同
PACK_STRUCT_FIELD(u16_t _hwlen_protolen);//硬件地址和协议地址的长度
PACK_STRUCT_FIELD(u16_t opcode);//操作码
PACK_STRUCT_FIELD(struct eth_addr shwaddr);//源MAC地址
PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);//源IP地址
PACK_STRUCT_FIELD(struct eth_addr dhwaddr);//目的MAC地址
PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);//目的IP地址
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
同前面一样,PACK_STRUCT_xxx是与编译器字对齐相关的宏定义。ARP实现的核心就是ARP缓存表,ARP缓存表的各表项数据结构如下:
struct etharp_entry {
#if ARP_QUEUEING
struct etharp_q_entry *q;//数据包缓冲队列指针
#endif
struct ip_addr ipaddr;//目标IP
struct eth_addr ethaddr;//目标MAC
enum etharp_state state;//当前entry状态
u8_t ctime;//当前entry的时间信息
struct netif *netif;//网络接口
};
etharp_state有三个值对应三个状态:empty、pending、stable。LwIP通过static struct etharp_entry arp_table[ARP_TABLE_SIZE]建立arp表。etharp_q_entry是数据包缓冲队列,结构如下:
struct etharp_q_entry {
struct etharp_q_entry *next;
struct pbuf *p;
};
接着看update_arp_entry()是如何更新ARP表的。

728

被折叠的 条评论
为什么被折叠?



