🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
ARP数据包的处理函数为etharp _input(),在这里它完成两个任务: 1. 如果收到的是ARP应答包,说明本机之前发出的ARP请求包有了回应,就根据应答包更新自身的ARP缓存表; 2. 如果收到的是ARP请求包,如果包中的目标IP地址与主机IP地址匹配,除了记录原主机的IP与MAC地址,更新自身的ARP表外,还要向源主机发送一个ARP应答包。但是如果如果包中目标IP地址与主机IP地址不匹配,则尽可能记录源主机的IP与MAC地址,更新自身的ARP表,并丢弃该请求包,为什么说是尽可能呢,因为主机的ARP缓存表是有限的,不可能记录太多的ARP表项,所以在有空闲的表项时才记录,如果没有空闲的表项,ARP觉得它自己已经尽力了,也记不住那么多表项。 etharp _input()函数的源码具体见代码清单 10 9。 ``` 1 void 2 etharp_input(struct pbuf *p, struct netif *netif) 3 { 4 struct etharp_hdr *hdr; 5 6 ip4_addr_t sipaddr, dipaddr; 7 u8_t for_us; 8 9 LWIP_ASSERT_CORE_LOCKED(); 10 11 LWIP_ERROR("netif != NULL", (netif != NULL), return;); 12 13 hdr = (struct etharp_hdr *)p->payload; 14 15 /* 判断ARP包的合法性 */ 16 if ((hdr->hwtype != PP_HTONS(LWIP_IANA_HWTYPE_ETHERNET)) || 17 (hdr->hwlen != ETH_HWADDR_LEN) || 18 (hdr->protolen != sizeof(ip4_addr_t)) || 19 (hdr->proto != PP_HTONS(ETHTYPE_IP))) (1) 20 { 21 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, 22 ("etharp_input: packet dropped, wrong hw type, hwlen, proto, 23 protolen or ethernet type(%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n", 24 hdr->hwtype,(u16_t)hdr->hwlen, hdr->proto, (u16_t)hdr->protolen)); 25 26 ETHARP_STATS_INC(etharp.proterr); 27 ETHARP_STATS_INC(etharp.drop); 28 29 pbuf_free(p); 30 return; 31 } 32 ETHARP_STATS_INC(etharp.recv); 33 34 //拷贝源IP地址与目标IP地址 35 IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&sipaddr, &hdr->sipaddr); (2) 36 IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&dipaddr, &hdr->dipaddr); (3) 37 38 /* 看看主机网卡是否配置了IP地址 */ 39 if (ip4_addr_isany_val(*netif_ip4_addr(netif))) (4) 40 { 41 for_us = 0; 42 } 43 else 44 { 45 /* 判断目标IP地址与主机IP地址是否一样 */ 46 for_us = (u8_t)ip4_addr_cmp(&dipaddr, netif_ip4_addr(netif)); (5) 47 } 48 49 /* 更新ARP缓存表 */ 50 etharp_update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), (6) 51 for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY); 52 53 /* 更新完毕,根据包的类型处理 */ 54 switch (hdr->opcode) (7) 55 { 56 /* ARP request? */ 57 case PP_HTONS(ARP_REQUEST): (8) 58 /* ARP请求包 */ 59 LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, 60 ("etharp_input: incoming ARP request\n")); 61 /* 是请求自己的 */ 62 if (for_us) 63 { 64 /* 做出回应 */ 65 etharp_raw(netif, 66 (struct eth_addr *)netif->hwaddr, &hdr->shwaddr, 67 (struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif), 68 &hdr->shwaddr, &sipaddr, 69 ARP_REPLY); (9) 70 /* 不是给自己的 */ 71 } 72 else if (ip4_addr_isany_val(*netif_ip4_addr(netif))) (10) 73 { 74 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, 75 ("etharp_input: we are unconfigured, ARP request ignored.\n")); 76 } 77 else (11) 78 { 79 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, 80 ("etharp_input: ARP request was not for us.\n")); 81 } 82 break; 83 case PP_HTONS(ARP_REPLY): (12) 84 /* 对于ARP应答包*/ 85 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, 86 ("etharp_input: incoming ARP reply\n")); 87 break; 88 default: 89 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, 90 ("etharp_input: ARP unknown opcode type %"S16_F"\n", 91 lwip_htons(hdr->opcode))); 92 ETHARP_STATS_INC(etharp.err); (13) 93 break; 94 } 95 /* 释放内存 */ 96 pbuf_free(p); (14) 97 } ``` (1):判断ARP包的合法性,已经类型是否为以太网、硬件地址长度是否为ETH_HWADDR_LEN、协议地址长度是否为sizeof(ip4_addr_t)以及协议是否为ARP协议,如果都满足则表示ARP包合法。 (2):拷贝源IP地址到sipaddr变量中,因为在ARP包中的IP地址字段并不是对齐的,不能直接使用,所以需要拷贝到临时变量,方便直接操作。 (3):同理拷贝目标IP地址到dipaddr变量中。 (4):看看主机网卡是否配置了IP地址,如果没有配置,将for_us变量设置为0,表示不是给主机自己的ARP包。 (5):调用ip4_addr_cmp()函数判断目标IP地址与主机IP地址是否一样,如果一样则返回1,将for_us变量设置为1,反之设置为0。 (6):调用etharp_update_arp_entry()函数更新ARP缓存表,这个操作有点特殊,我们稍后讲解。 (7):更新完毕,根据包的类型处理,即根据ARP数据包的op字段进行处理。 (8):对于ARP请求包,首先要判断一下是否是给主机自己的,如果是则要回应,否则就直接丢弃即可。 (9):是请求自己的,调用etharp_raw()函数作出应答。 (10):如果不是给自己的,原因有两种,一种是网卡自身尚未配置IP地址,这样子就只打印相关调试信息。 (11):另一种是ARP包中的目标IP地址与主机IP地址不符合,也不用做出回应,直接丢弃即可,并输出相关调试信息。 (12):对于ARP应答包,理论上应该更新ARP缓存表的,毕竟发出去的ARP请求包得到回应,但是在前面已经更新了缓存表了,此处就不用重复更新了。 (13):对于其他情况,直接返回错误代码。 (14):释放内存。