ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
etharp\_output()函数被IP层的ip4\_output()函数调用,IP层传递一个数据包到ARP中,etharp\_output()会根据数据包的目标IP地址选择不同的处理,其源码具体见代码清单 10‑11。 ``` 1 const struct eth_addr ethbroadcast = 2 {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; 3 4 const struct eth_addr ethzero = {{0, 0, 0, 0, 0, 0}}; 5 6 /** 24位IANA IPv4多播OUI为01-00-5e: */ 7 #define LL_IP4_MULTICAST_ADDR_0 0x01 8 #define LL_IP4_MULTICAST_ADDR_1 0x00 9 #define LL_IP4_MULTICAST_ADDR_2 0x5e 10 11 err_t etharp_output 12 (struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr) 13 { 14 const struct eth_addr *dest; 15 struct eth_addr mcastaddr; 16 const ip4_addr_t *dst_addr = ipaddr; 17 18 LWIP_ASSERT_CORE_LOCKED(); 19 LWIP_ASSERT("netif != NULL", netif != NULL); 20 LWIP_ASSERT("q != NULL", q != NULL); 21 LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL); 22 23 if (ip4_addr_isbroadcast(ipaddr, netif)) 24 { 25 /* 如果是广播数据包,目标MAC地址设置为FF-FF-FF-FF-FF-FF-FF */ 26 dest = (const struct eth_addr *)&ethbroadcast; (1) 27 /* multicast destination IP address? */ 28 } 29 else if (ip4_addr_ismulticast(ipaddr)) 30 { 31 /* 如果是多播数据包,目标MAC地址设置为多播地址:01-00-5E-XX-XX-XX*/ 32 mcastaddr.addr[0] = LL_IP4_MULTICAST_ADDR_0; 33 mcastaddr.addr[1] = LL_IP4_MULTICAST_ADDR_1; 34 mcastaddr.addr[2] = LL_IP4_MULTICAST_ADDR_2; 35 mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; 36 mcastaddr.addr[4] = ip4_addr3(ipaddr); 37 mcastaddr.addr[5] = ip4_addr4(ipaddr); 38 39 dest = &mcastaddr; (2) 40 41 } 42 else 43 { 44 /* 如果是单播目标地IP地址 */ 45 netif_addr_idx_t i; 46 /* 判断目标IP地址是否与主机处于同一子网上, 47 如果不是,则修改IP地址 */ 48 if (!ip4_addr_netcmp(ipaddr, netif_ip4_addr(netif), 49 netif_ip4_netmask(netif)) && 50 !ip4_addr_islinklocal(ipaddr)) (3) 51 { 52 #if LWIP_AUTOIP 53 struct ip_hdr *iphdr = 54 LWIP_ALIGNMENT_CAST(struct ip_hdr *, q->payload); 55 56 if (!ip4_addr_islinklocal(&iphdr->src)) 57 #endif 58 { 59 #ifdef LWIP_HOOK_ETHARP_GET_GW 60 dst_addr = LWIP_HOOK_ETHARP_GET_GW(netif, ipaddr); 61 if (dst_addr == NULL) 62 #endif 63 { 64 /* 判断一下网关地址是否有效 */ 65 if (!ip4_addr_isany_val(*netif_ip4_gw(netif))) (4) 66 { 67 /* 发送到默认网关,让网关进行转发 */ 68 dst_addr = netif_ip4_gw(netif); 69 /* 没有默认网关可用 */ 70 } 71 else 72 { 73 /* 返回错误 */ 74 return ERR_RTE; 75 } 76 } 77 } 78 } 79 /* 遍历ARP缓存表 */ 80 for (i = 0; i < ARP_TABLE_SIZE; i++) 81 { 82 if ((arp_table[i].state >= ETHARP_STATE_STABLE) && 83 (arp_table[i].netif == netif) && 84 (ip4_addr_cmp(dst_addr, &arp_table[i].ipaddr))) 85 { 86 /* 如果找到目标IP地址对应的表项,直接发送 */ 87 ETHARP_SET_ADDRHINT(netif, i); 88 return etharp_output_to_arp_index(netif, q, i); (5) 89 } 90 } 91 /* 如果没有找到与目标IP地址对应的ARP表项 */ 92 return etharp_query(netif, dst_addr, q); (6) 93 } 94 95 /* 对于多播、广播数据包,直接能得到对应的MAC地址,可以进行发送*/ 96 return ethernet_output(netif, q, 97 (struct eth_addr *)(netif->hwaddr), dest, ETHTYPE_IP); (7) 98 } ``` (1):如果是广播数据包,目标MAC地址设置为FF-FF-FF-FF-FF-FF-FF。 (2):如果是多播数据包,目标MAC地址设置为多播地址:01-00-5E-XX-XX-XX。 此处简单补充一下单播包、广播包与多播包的相关知识: 单播包:顾名思义,就是一对一通信,发送的目标主机IP地址是唯一的,就像是人们之间的对话一样,一个人对另外一个人说话。 多播包:“多播”可以理解为一个人向多个人(但不是在场的所有人)说话,比如在一个大餐厅中,一个人说话只能让一桌人知道,而其他桌上的人并不知道说了什么。同理的,主机发送的多播包只能让某些满足条件的目标主机接收到。 广播包:而广播就是类似于用大喇叭进行广播通知,在场的所有人都能知道。广播包是让所有处于同一子网的主机都能接收到数据包。 (3):如果是单播目标地IP地址,首先判断目标IP地址是否与主机处于同一子网上,如果不是,则修改IP地址,IP地址为网关的IP地址,目的是为了让网关进行转发。 (4):判断一下网关地址是否有效,如果有效,则发送到默认网关,让网关进行转发,没有默认网关可用则返回错误代码。 (5):遍历ARP缓存表,如果找到目标IP地址对应的表项,调用etharp_output_to_arp_index()函数直接发送,该函数源码具体见代码清单 10 12。 (6):如果没有找到与目标IP地址对应的ARP表项,需要调用etharp_query()函数进行发送,这个函数在稍后讲解,具体见10.11.3 小节。 (7):对于多播、广播数据包,直接能得到对应的MAC地址,可以进行发送。