📄 etharp.c
字号:
* * 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 pbuf The ARP packet that arrived on netif. Is freed by this function. * @param ethaddr Ethernet address of netif. * * @return NULL * * @see pbuf_free() */struct pbuf *etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p){ struct etharp_hdr *hdr; u8_t i; /* drop short ARP packets */ if(p->tot_len < sizeof(struct etharp_hdr)) { DEBUGF(ETHARP_DEBUG | DBG_TRACE | 1, ("etharp_arp_input: packet too short (%d/%d)\n", p->tot_len, sizeof(struct etharp_hdr))); pbuf_free(p); return NULL; } hdr = p->payload; switch(htons(hdr->opcode)) { /* ARP request? */ case 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. */ DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP request\n")); /* we are not configured? */ if(netif->ip_addr.addr == 0) { DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n")); pbuf_free(p); return NULL; } /* update the ARP cache */ update_arp_entry(netif, &(hdr->sipaddr), &(hdr->shwaddr), 0); /* ARP request for our address? */ if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) { DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n")); /* re-use pbuf to send ARP reply */ hdr->opcode = htons(ARP_REPLY); ip_addr_set(&(hdr->dipaddr), &(hdr->sipaddr)); ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr)); for(i = 0; i < netif->hwaddr_len; ++i) { hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i]; hdr->shwaddr.addr[i] = ethaddr->addr[i]; hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i]; hdr->ethhdr.src.addr[i] = ethaddr->addr[i]; } hdr->hwtype = htons(HWTYPE_ETHERNET); ARPH_HWLEN_SET(hdr, netif->hwaddr_len); hdr->proto = htons(ETHTYPE_IP); ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr)); hdr->ethhdr.type = htons(ETHTYPE_ARP); /* return ARP reply */ netif->linkoutput(netif, p); } else { DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP request was not for us.\n")); } break; case ARP_REPLY: /* ARP reply. We insert or update the ARP table. */ DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) /* DHCP needs to know about ARP replies */ dhcp_arp_reply(netif, &hdr->sipaddr);#endif /* ARP reply directed to us? */ if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) { DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply is for us\n")); /* update_the ARP cache, ask to insert */ update_arp_entry(netif, &(hdr->sipaddr), &(hdr->shwaddr), ARP_INSERT_FLAG); /* ARP reply not directed to us */ } else { DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply is not for us\n")); /* update the destination address pair */ update_arp_entry(netif, &(hdr->sipaddr), &(hdr->shwaddr), 0); /* update the destination address pair */ update_arp_entry(netif, &(hdr->dipaddr), &(hdr->dhwaddr), 0); } break; default: DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %d\n", htons(hdr->opcode))); break; } /* free ARP packet */ pbuf_free(p); p = NULL; /* nothing to send, we did it! */ return NULL;}/** * Resolve and fill-in Ethernet address header for outgoing packet. * * If ARP has the Ethernet address in cache, the given packet is * returned, ready to be sent. * * If ARP does not have the Ethernet address in cache the packet is * queued and a ARP request is sent (on a best-effort basis). This * ARP request is returned as a pbuf, which should be sent by the * caller. * * If ARP failed to allocate resources, NULL is returned. * * A returned non-NULL packet should be sent by the caller and * etharp_output_sent() must be called afterwards to free any ARP * request. * * @param netif The lwIP network interface which the IP packet will be sent on. * @param ipaddr The IP address of the packet destination. * @param pbuf The pbuf(s) containing the IP packet to be sent. * * @return If non-NULL, a packet ready to be sent. * @see etharp_output_sent() */struct pbuf *etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q){ struct eth_addr *dest, *srcaddr, mcastaddr; struct eth_hdr *ethhdr; u8_t i; /* Make room for Ethernet header. */ if(pbuf_header(q, sizeof(struct eth_hdr)) != 0) { /* The pbuf_header() call shouldn't fail, and we'll just bail out if it does.. */ DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n"));#ifdef LINK_STATS ++lwip_stats.link.lenerr;#endif /* LINK_STATS */ return NULL; } /* obtain source Ethernet address of the given interface */ srcaddr = (struct eth_addr *)netif->hwaddr; /* assume unresolved Ethernet address */ dest = NULL; /* Construct Ethernet header. Start with looking up deciding which MAC address to use as a destination address. Broadcasts and multicasts are special, all other addresses are looked up in the ARP table. */ /* destination IP address is an IP broadcast address? */ if(ip_addr_isany(ipaddr) || ip_addr_isbroadcast(ipaddr, &(netif->netmask))) { /* broadcast on Ethernet also */ dest = (struct eth_addr *)ðbroadcast; } /* destination IP address is an IP multicast address? */ else if(ip_addr_ismulticast(ipaddr)) { /* Hash IP multicast address to MAC address. */ mcastaddr.addr[0] = 0x01; mcastaddr.addr[1] = 0x0; mcastaddr.addr[2] = 0x5e; mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; mcastaddr.addr[4] = ip4_addr3(ipaddr); mcastaddr.addr[5] = ip4_addr4(ipaddr); /* destination Ethernet address is multicast */ dest = &mcastaddr; } /* destination IP address is an IP unicast address */ else { /* destination IP network address not on local network? */ /* this occurs if the packet is routed to the default gateway on this interface */ if(!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { /* gateway available? */ if (netif->gw.addr != 0) { /* use the gateway IP address */ ipaddr = &(netif->gw); } /* no gateway available? */ else { /* IP destination address outside local network, but no gateway available */ return NULL; } } /* Ethernet address for IP destination address is in ARP cache? */ for(i = 0; i < ARP_TABLE_SIZE; ++i) { /* match found? */ if(arp_table[i].state == ETHARP_STATE_STABLE && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { dest = &arp_table[i].ethaddr; break; } } /* could not find the destination Ethernet address in ARP cache? */ if (dest == NULL) { /* ARP query for the IP address, submit this IP packet for queueing */ etharp_query(netif, ipaddr, q); /* return nothing */ return NULL; } /* destination Ethernet address resolved from ARP cache */ else { /* fallthrough */ } } /* destination Ethernet address known */ if (dest != NULL) { /* A valid IP->MAC address mapping was found, so we construct the Ethernet header for the outgoing packet. */ ethhdr = q->payload; for(i = 0; i < netif->hwaddr_len; i++) { ethhdr->dest.addr[i] = dest->addr[i]; ethhdr->src.addr[i] = srcaddr->addr[i]; } ethhdr->type = htons(ETHTYPE_IP); /* return the outgoing packet */ return q; } /* never reached; here for safety */ return NULL;}/** * Send an ARP request for the given IP address. * * Sends an ARP request for the given IP address, unless * a request for this address is already pending. Optionally * queues an outgoing packet on the resulting ARP entry. * * @param netif The lwIP network interface where ipaddr * must be queried for. * @param ipaddr The IP address to be resolved. * @param q If non-NULL, a pbuf that must be queued on the * ARP entry for the ipaddr IP address. * * @return NULL. * * @note Might be used in the future by manual IP configuration * as well. * * TODO: enqueue q here if possible (BEWARE: possible other packet already * queued. * TODO: The host requirements RFC states that ARP should save at least one * packet, and this should be the _latest_ packet. * TODO: use the ctime field to see how long ago an ARP request was sent, * possibly retry. */err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q){ struct eth_addr *srcaddr; struct etharp_hdr *hdr; struct pbuf *p; err_t result = ERR_OK; u8_t i; u8_t perform_arp_request = 1; /* prevent warning if ARP_QUEUEING == 0 */ if (q); srcaddr = (struct eth_addr *)netif->hwaddr; /* bail out if this IP address is pending */ for(i = 0; i < ARP_TABLE_SIZE; ++i) { if(ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { if (arp_table[i].state == ETHARP_STATE_PENDING) { DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already pending as entry %u\n", i)); /* break out of for-loop, user may wish to queue a packet on a stable entry */ break; } else if (arp_table[i].state == ETHARP_STATE_STABLE) { DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already stable as entry %u\n", i)); /* user may wish to queue a packet on a stable entry, so we proceed without ARP requesting */ /* TODO: even if the ARP entry is stable, we might do an ARP request anyway in some cases? */ perform_arp_request = 0; break; } } } /* queried address not yet in ARP table? */ if (i == ARP_TABLE_SIZE) { DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: IP address not found in ARP table\n")); /* find an available entry */ i = find_arp_entry(); /* bail out if no ARP entries are available */ if (i == ARP_TABLE_SIZE) { DEBUGF(ETHARP_DEBUG | 2, ("etharp_query: no more ARP entries available.\n")); return ERR_MEM; } DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: created ARP table entry %u.\n", i)); /* i is available, create ARP entry */ ip_addr_set(&arp_table[i].ipaddr, ipaddr); arp_table[i].ctime = 0; arp_table[i].state = ETHARP_STATE_PENDING;#if ARP_QUEUEING /* free queued packet, as entry is now invalidated */ if (arp_table[i].p != NULL) { pbuf_free(arp_table[i].p); arp_table[i].p = NULL; DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("etharp_query: dropped packet on ARP queue. Should not occur.\n")); }#endif }#if ARP_QUEUEING /* any pbuf to queue and queue is empty? */ if (q != NULL) {/* yield later packets over older packets? */#if ARP_QUEUE_FIRST == 0 /* earlier queued packet on this entry? */ if (arp_table[i].p != NULL) { pbuf_free(arp_table[i].p); arp_table[i].p = NULL; DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("etharp_query: dropped packet on ARP queue. Should not occur.\n")); }#endif /* packet can be queued? */ if (arp_table[i].p == NULL) { /* copy PBUF_REF referenced payloads to PBUF_RAM */ q = pbuf_take(q); /* remember pbuf to queue, if any */ arp_table[i].p = q; /* pbufs are queued, increase the reference count */ pbuf_ref(q); DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: queued packet %p on ARP entry %u.\n", (void *)q, i)); } }#endif /* ARP request? */ if (perform_arp_request) { /* allocate a pbuf for the outgoing ARP request packet */ p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM); /* could allocate pbuf? */ if (p != NULL) { u8_t j; DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending ARP request.\n")); hdr = p->payload; hdr->opcode = htons(ARP_REQUEST); for(j = 0; j < netif->hwaddr_len; ++j) { hdr->dhwaddr.addr[j] = 0x00; hdr->shwaddr.addr[j] = srcaddr->addr[j]; } ip_addr_set(&(hdr->dipaddr), ipaddr); ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr)); hdr->hwtype = htons(HWTYPE_ETHERNET); ARPH_HWLEN_SET(hdr, netif->hwaddr_len); hdr->proto = htons(ETHTYPE_IP); ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr)); for(j = 0; j < netif->hwaddr_len; ++j) { hdr->ethhdr.dest.addr[j] = 0xff; hdr->ethhdr.src.addr[j] = srcaddr->addr[j]; } hdr->ethhdr.type = htons(ETHTYPE_ARP); /* send ARP query */ result = netif->linkoutput(netif, p); /* free ARP query packet */ pbuf_free(p); p = NULL; } else { result = ERR_MEM; DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_query: could not allocate pbuf for ARP request.\n")); } } return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -