📄 etharp.c
字号:
hdr->ethhdr.type = htons(ETHTYPE_ARP); /* return ARP reply */ netif->linkoutput(netif, p); /* we are not configured? */ } else if (netif->ip_addr.addr == 0) { /* { for_us == 0 and netif->ip_addr.addr == 0 } */ LWIP_DEBUGF(ETHARP_DEBUG | 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 | DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n")); } break; case ARP_REPLY: /* ARP reply. We already updated the ARP cache earlier. */ LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) /* DHCP wants to know about ARP replies from any host with an * IP address also offered to us by the DHCP server. We do not * want to take a duplicate IP address on a single network. * @todo How should we handle redundant (fail-over) interfaces? * */ dhcp_arp_reply(netif, &sipaddr);#endif break; default: LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode))); break; } /* free ARP packet */ pbuf_free(p);}/** * Resolve and fill-in Ethernet address header for outgoing packet. * * For IP multicast and broadcast, corresponding Ethernet addresses * are selected and the packet is transmitted on the link. * * For unicast addresses, the packet is submitted to etharp_query(). In * case the IP address is outside the local network, the IP address of * the gateway is used. * * @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 * - ERR_RTE No route to destination (no gateway to external networks), * or the return type of either etharp_query() or netif->linkoutput(). */err_tetharp_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 - should not fail */ if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { /* bail out */ LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n")); LINK_STATS_INC(link.lenerr); return ERR_BUF; } /* assume unresolved Ethernet address */ dest = NULL; /* Determine on destination hardware address. Broadcasts and multicasts * are special, other IP addresses are looked up in the ARP table. */ /* broadcast destination IP address? */ if (ip_addr_isbroadcast(ipaddr, netif)) { /* broadcast on Ethernet also */ dest = (struct eth_addr *)ðbroadcast; /* multicast destination IP address? */ } else if (ip_addr_ismulticast(ipaddr)) { /* Hash IP multicast address to MAC address.*/ mcastaddr.addr[0] = 0x01; mcastaddr.addr[1] = 0x00; 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; /* unicast destination IP address? */ } else { /* outside local network? */ if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { /* interface has default gateway? */ if (netif->gw.addr != 0) { /* send to hardware address of default gateway IP address */ ipaddr = &(netif->gw); /* no default gateway available */ } else { /* no route to destination error (default gateway missing) */ return ERR_RTE; } } /* queue on destination Ethernet address belonging to ipaddr */ return etharp_query(netif, ipaddr, q); } /* continuation for multicast/broadcast destinations */ /* obtain source Ethernet address of the given interface */ srcaddr = (struct eth_addr *)netif->hwaddr; ethhdr = q->payload; i = netif->hwaddr_len; while(i > 0) { i--; ethhdr->dest.addr[i] = dest->addr[i]; ethhdr->src.addr[i] = srcaddr->addr[i]; } ethhdr->type = htons(ETHTYPE_IP); /* send packet directly on the link */ return netif->linkoutput(netif, q);}/** * Send an ARP request for the given IP address and/or queue a packet. * * If the IP address was not yet in the cache, a pending ARP cache entry * is added and an ARP request is sent for the given address. The packet * is queued on this entry. * * If the IP address was already pending in the cache, a new ARP request * is sent for the given address. The packet is queued on this entry. * * If the IP address was already stable in the cache, and a packet is * given, it is directly sent and no ARP request is sent out. * * If the IP address was already stable in the cache, and no packet is * given, an ARP request is sent out. * * @param netif The lwIP network interface on which ipaddr * must be queried for. * @param ipaddr The IP address to be resolved. * @param q If non-NULL, a pbuf that must be delivered to the IP address. * q is not freed by this function. * * @return * - ERR_BUF Could not make room for Ethernet header. * - ERR_MEM Hardware address unknown, and no more ARP entries available * to query for address or queue the packet. * - ERR_MEM Could not queue packet due to memory shortage. * - ERR_RTE No route to destination (no gateway to external networks). * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. * */err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q){ struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr; err_t result = ERR_MEM; s8_t i; /* ARP entry index */ u8_t k; /* Ethernet address octet index */ /* non-unicast address? */ if (ip_addr_isbroadcast(ipaddr, netif) || ip_addr_ismulticast(ipaddr) || ip_addr_isany(ipaddr)) { LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n")); return ERR_ARG; } /* find entry in ARP cache, ask to create entry if queueing packet */ i = find_entry(ipaddr, ETHARP_TRY_HARD); /* could not find or create entry? */ if (i < 0) { LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not create ARP entry\n")); if (q) LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: packet dropped\n")); return (err_t)i; } /* mark a fresh entry as pending (we just sent a request) */ if (arp_table[i].state == ETHARP_STATE_EMPTY) { arp_table[i].state = ETHARP_STATE_PENDING; } /* { i is either a STABLE or (new or existing) PENDING entry } */ LWIP_ASSERT("arp_table[i].state == PENDING or STABLE", ((arp_table[i].state == ETHARP_STATE_PENDING) || (arp_table[i].state == ETHARP_STATE_STABLE))); /* do we have a pending entry? or an implicit query request? */ if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) { /* try to resolve it; send out ARP request */ result = etharp_request(netif, ipaddr); } /* packet given? */ if (q != NULL) { /* stable entry? */ if (arp_table[i].state == ETHARP_STATE_STABLE) { /* we have a valid IP->Ethernet address mapping, * fill in the Ethernet header for the outgoing packet */ struct eth_hdr *ethhdr = q->payload; k = netif->hwaddr_len; while(k > 0) { k--; ethhdr->dest.addr[k] = arp_table[i].ethaddr.addr[k]; ethhdr->src.addr[k] = srcaddr->addr[k]; } ethhdr->type = htons(ETHTYPE_IP); LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending packet %p\n", (void *)q)); /* send the packet */ result = netif->linkoutput(netif, q); /* pending entry? (either just created or already pending */ } else if (arp_table[i].state == ETHARP_STATE_PENDING) {#if ARP_QUEUEING /* queue the given q packet */ struct pbuf *p; /* copy any PBUF_REF referenced payloads into PBUF_RAM */ /* (the caller of lwIP assumes the referenced payload can be * freed after it returns from the lwIP call that brought us here) */ p = pbuf_take(q); /* packet could be taken over? */ if (p != NULL) { /* queue packet ... */ if (arp_table[i].p == NULL) { /* ... in the empty queue */ pbuf_ref(p); arp_table[i].p = p;#if 0 /* multi-packet-queueing disabled, see bug #11400 */ } else { /* ... at tail of non-empty queue */ pbuf_queue(arp_table[i].p, p);#endif } LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); result = ERR_OK; } else { LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); /* { result == ERR_MEM } through initialization */ }#else /* ARP_QUEUEING == 0 */ /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */ /* { result == ERR_MEM } through initialization */ LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));#endif } } return result;}err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr){ struct pbuf *p; struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr; err_t result = ERR_OK; u8_t k; /* ARP entry index */ /* allocate a pbuf for the outgoing ARP request packet */ p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM); /* could allocate a pbuf for an ARP request? */ if (p != NULL) { struct etharp_hdr *hdr = p->payload; LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_request: sending ARP request.\n")); hdr->opcode = htons(ARP_REQUEST); k = netif->hwaddr_len; while(k > 0) { k--; hdr->shwaddr.addr[k] = srcaddr->addr[k]; /* the hardware address is what we ask for, in * a request it is a don't-care value, we use zeroes */ hdr->dhwaddr.addr[k] = 0x00; } hdr->dipaddr = *(struct ip_addr2 *)ipaddr; hdr->sipaddr = *(struct ip_addr2 *)&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)); k = netif->hwaddr_len; while(k > 0) { k--; /* broadcast to all network interfaces on the local network */ hdr->ethhdr.dest.addr[k] = 0xff; hdr->ethhdr.src.addr[k] = srcaddr->addr[k]; } hdr->ethhdr.type = htons(ETHTYPE_ARP); /* send ARP query */ result = netif->linkoutput(netif, p); /* free ARP query packet */ pbuf_free(p); p = NULL; /* could not allocate pbuf for ARP request */ } else { result = ERR_MEM; LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_request: could not allocate pbuf for ARP request.\n")); } return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -