📄 etharp.c
字号:
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no available entry found\n")); return NULL; } /* set IP address */ ip_addr_set(&arp_table[i].ipaddr, ipaddr); /* set Ethernet hardware address */ for (k = 0; k < netif->hwaddr_len; ++k) { arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; } /* reset time-stamp */ arp_table[i].ctime = 0; /* mark as stable */ arp_table[i].state = ETHARP_STATE_STABLE; /* no queued packet */#if ARP_QUEUEING arp_table[i].p = NULL;#endif } else { LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no matching stable entry to update\n")); } return NULL;}/** * Updates the ARP table using the given IP packet. * * Uses the incoming IP packet's source address to update the * ARP cache for the local network. The function does not alter * or free the packet. This function must be called before the * packet p is passed to the IP layer. * * @param netif The lwIP network interface on which the IP packet pbuf arrived. * @param pbuf The IP packet that arrived on netif. * * @return NULL * * @see pbuf_free() */struct pbuf *etharp_ip_input(struct netif *netif, struct pbuf *p){ struct ethip_hdr *hdr; /* Only insert an entry if the source IP address of the incoming IP packet comes from a host on the local network. */ hdr = p->payload; /* source is on local network? */ if (!ip_addr_maskcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) { /* do nothing */ return NULL; } LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n")); /* update ARP table, ask to insert entry */ update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), ARP_INSERT_FLAG); return NULL;}/** * 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 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; u8_t for_us; /* drop short ARP packets */ if (p->tot_len < sizeof(struct etharp_hdr)) { LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 1, ("etharp_arp_input: packet dropped, too short (%d/%d)\n", p->tot_len, sizeof(struct etharp_hdr))); pbuf_free(p); return NULL; } hdr = p->payload; /* this interface is not configured? */ if (netif->ip_addr.addr == 0) { for_us = 0; } else { /* ARP packet directed to us? */ for_us = ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr)); } /* add or update entries in the ARP cache */ if (for_us) { /* insert IP address in ARP cache (assume requester wants to talk to us) * we might even send out a queued packet to this host */ update_arp_entry(netif, &(hdr->sipaddr), &(hdr->shwaddr), ARP_INSERT_FLAG); /* request was not directed to us, but snoop anyway */ } else { /* update the source IP address in the cache */ update_arp_entry(netif, &(hdr->sipaddr), &(hdr->shwaddr), 0); } 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. */ LWIP_DEBUGF (ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP request\n")); /* we are not configured? */ if (netif->ip_addr.addr == 0) { LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n")); pbuf_free(p); return NULL; } /* ARP request for our address? */ if (for_us) { LWIP_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); /* request was not directed to us */ } else { LWIP_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 later. */ 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 to our wanna-have-address */ if (for_us) dhcp_arp_reply(netif, &hdr->sipaddr);#endif break; default: LWIP_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 (if enabled and space available) and a ARP request is sent. * This ARP request is returned as a pbuf, which should be sent by * the caller. * * A returned non-NULL packet should be sent by the caller. * * If ARP failed to allocate resources, NULL is returned. * * @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 by caller. * */struct pbuf *etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q){ struct eth_addr *dest, *srcaddr, mcastaddr; struct eth_hdr *ethhdr; s8_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.. */ LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n")); LINK_STATS_INC(link.lenerr); return NULL; } /* 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] = 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; } /* destination IP address is an IP unicast address */ else { /* destination IP network address not on local network? * IP layer wants us to forward to the default gateway */ if (!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { /* interface has default gateway? */ if (netif->gw.addr != 0) { /* route to default gateway IP address */ ipaddr = &(netif->gw); } /* no gateway available? */ else { /* IP destination address outside local network, but no gateway available */ /* { packet is discarded } */ 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 */ /* TODO: How do we handle netif->ipaddr == ipaddr? */ etharp_query(netif, ipaddr, q); /* { packet was queued (ERR_OK), or discarded } */ /* return nothing */ return NULL; } /* destination Ethernet address resolved from ARP cache */ else { /* fallthrough */ } } /* destination Ethernet address known */ if (dest != NULL) { /* obtain source Ethernet address of the given interface */ srcaddr = (struct eth_addr *)netif->hwaddr; /* A valid IP->MAC address mapping was found, fill in 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: 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; err_t result = ERR_OK; s8_t i; u8_t perform_arp_request = 1; /* prevent 'unused argument' warning if ARP_QUEUEING == 0 */ (void)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) { LWIP_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 pending entry */ /* TODO: we will issue a new ARP request, which should not occur too often */ /* we might want to run a faster timer on ARP to limit this */ break; } else if (arp_table[i].state == ETHARP_STATE_STABLE) { LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already stable as entry %u\n", i)); /* User wishes to queue a packet on a stable entry (or does she want to send * out the packet immediately, we will not know), so we force an ARP request. * Upon response we will send out the queued packet in etharp_update(). * * Alternatively, we could accept the stable entry, and just send out the packet * immediately. I chose to implement the former approach. */ perform_arp_request = (q?1:0); break; } } } /* queried address not yet in ARP table? */ if (i == ARP_TABLE_SIZE) { LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: IP address not found in ARP table\n")); /* find an available (unused or old) entry */ i = find_arp_entry(); /* bail out if no ARP entries are available */ if (i == ERR_MEM) { LWIP_DEBUGF(ETHARP_DEBUG | 2, ("etharp_query: no more ARP entries available. Should seldom occur.\n")); return ERR_MEM; } /* i is available, create ARP entry */ arp_table[i].state = ETHARP_STATE_PENDING; ip_addr_set(&arp_table[i].ipaddr, ipaddr); } /* { i is now valid } */#if ARP_QUEUEING /* queue packet (even on a stable entry, see above) */ etharp_enqueue(i, q);#endif /* ARP request? */ if (perform_arp_request) { struct pbuf *p; /* 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; LWIP_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->shwaddr.addr[j] = srcaddr->addr[j]; /* the hardware address is what we ask for, in * a request it is a don't-care, we use 0's */ hdr->dhwaddr.addr[j] = 0x00; } 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; LWIP_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 + -