一、ARP数据包的处理
ARP数据包的处理函数为etharp_arp_input,他完成两个任务:第一、如果收到的是应答包,说明是本机之前发出的ARP请求包,更新自身的ARP缓存表;第二、如果收到的是请求包,如果与自身IP匹配,记录原主机的IP与MAC地址,更新自身的ARP表外,还要发送一个应答包,如果不匹配,则记录原主机的IP与MAC地址,更新自身的ARP表。
二、对于ARP表的更新:(下一文章具体讲解)
其中更新ARP表的主要函数为:etharp_update_arp_entry(netif,&sipaddr, &(hdr->shwaddr),for_us ? ETHARP_FLAG_TRY_HARD :ETHARP_FLAG_FIND_ONLY); 根据ARP包(IP地址)是否是给本机的设置标志,如果设置标志为ETHARP_FLAG_TRY_HARD,则无论如何都要更新ARP表,如果表项已满,则删除年龄较老的表项;如果设置为ETHARP_FLAG_FIND_ONLY,先遍历整个表项,如果有空则插入,如果没有则舍弃。此函数后面讲
以下为etharp_arp_input函数的源码
/**
* Responds to ARP requests to us. Upon ARP replies to us, add entry to cache
* send out queued IP packets. Updates cache with snooped address pairs.
*
* Should be called for incoming ARP packets. The pbuf in the argument
* is freed by this function.
*
* @param netif The lwIP network interface on which the ARP packet pbuf arrived.
* @param ethaddr Ethernet address of netif.
* @param p The ARP packet that arrived on netif. Is freed by this function.
*
* @return NULL
*
* @see pbuf_free()
*/
static void
etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
{
struct etharp_hdr *hdr;
struct eth_hdr *ethhdr;
/* these are aligned properly, whereas the ARP header fields might not be */
ip_addr_t sipaddr, dipaddr;
u8_t for_us;
/* drop short ARP packets: we have to check for p->len instead of p->tot_len here
since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */
if (p->len < SIZEOF_ETHARP_PACKET) {
pbuf_free(p);
return;
}
ethhdr = (struct eth_hdr *)p->payload;
hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
/* RFC 826 "Packet Reception": */
if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) ||
(hdr->hwlen != ETHARP_HWADDR_LEN) ||
(hdr->protolen != sizeof(ip_addr_t)) ||
(hdr->proto != PP_HTONS(ETHTYPE_IP))) {
pbuf_free(p);
return;
}
/* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
* structure packing (not using structure copy which breaks strict-aliasing rules). */
IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
/* this interface is not configured? */
if (ip_addr_isany(&netif->ip_addr)) {
for_us = 0;
} else {
/* ARP packet directed to us? */
for_us = (u8_t)ip_addr_cmp(&dipaddr, &(netif->ip_addr));
}
/* ARP message directed to us?
-> add IP address in ARP cache; assume requester wants to talk to us,
can result in directly sending the queued packets for this host.
ARP message not directed to us?
-> update the source IP address in the cache, if present */
etharp_update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),
for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY);
/* now act on the message itself */
switch (hdr->opcode) {
/* ARP request? */
case PP_HTONS(ARP_REQUEST):
/* ARP request. If it asked for our address, we send out a
* reply. In any case, we time-stamp any existing ARP entry,
* and possiby send out an IP packet that was queued on it. */
/* ARP request for our address? */
if (for_us) {
/* Re-use pbuf to send ARP reply.
Since we are re-using an existing pbuf, we can't call etharp_raw since
that would allocate a new pbuf. */
hdr->opcode = htons(ARP_REPLY);
IPADDR2_COPY(&hdr->dipaddr, &hdr->sipaddr);
IPADDR2_COPY(&hdr->sipaddr, &netif->ip_addr);
ETHADDR16_COPY(&hdr->dhwaddr, &hdr->shwaddr);
ETHADDR16_COPY(ðhdr->dest, &hdr->shwaddr);
ETHADDR16_COPY(&hdr->shwaddr, ethaddr);
ETHADDR16_COPY(ðhdr->src, ethaddr);
/* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header
are already correct, we tested that before */
/* return ARP reply */
netif->linkoutput(netif, p);
/* we are not configured? */
} else if (ip_addr_isany(&netif->ip_addr)) {
/* { for_us == 0 and netif->ip_addr.addr == 0 } */
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n"));
/* request was not directed to us */
} else {
/* { for_us == 0 and netif->ip_addr.addr != 0 } */
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n"));
}
break;
case PP_HTONS(ARP_REPLY):
break;
default:
break;
}
/* free ARP packet */
pbuf_free(p);
}