void update_arp_entry(uint32 ip, uint8 mac[6], struct net_dev *nd) { struct arp_entry *t; if(!(t = find_arp_entry(ip))) { t = kmalloc(sizeof(struct arp_entry), "arp_entry", NULL); if(!t) { printf("update_arp_entry: kmalloc failed\n"); return; } t->ip = ip; t->dev = nd; t->next = arptable; arptable = t; } memcpy(t->mac, mac, sizeof(t->mac)); //dump_arp(); }
/** * 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; struct pbuf *p; err_t result = ERR_OK; u8_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) { 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 */ /* 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) { 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 */ 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; } /* we will now recycle entry i */ 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")); /* fall-through into next if */ } #endif /* packet can be queued? */ if (arp_table[i].p == NULL) { /* copy PBUF_REF referenced payloads into 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; }
/** * 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 (arp_table[i].state != ETHARP_STATE_EMPTY && 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) */ /* copy any PBUF_REF referenced payloads into PBUF_RAM */ q = pbuf_take(q); pbuf_queue(arp_table[i].p, 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; } 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)); 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; }
/** * Update (or insert) a IP/MAC address pair in the ARP cache. * * @param ipaddr IP address of the inserted ARP entry. * @param ethaddr Ethernet address of the inserted ARP entry. * @param flags Defines behaviour: * - ARP_INSERT_FLAG Allows ARP to insert this as a new item. If not specified, * only existing ARP entries will be updated. * * @return pbuf If non-NULL, a packet that was queued on a pending entry. * You should sent it and must call pbuf_free() afterwards. * * @see pbuf_free() */ static struct pbuf * update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags) { u8_t i, k; DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("update_arp_entry()\n")); LWIP_ASSERT("netif->hwaddr_len != 0", netif->hwaddr_len != 0); DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: %u.%u.%u.%u - %02x:%02x:%02x:%02x:%02x:%02x\n", ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr), ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); /* do not update for 0.0.0.0 addresses */ if (ipaddr->addr == 0) { DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: will not add 0.0.0.0 to ARP cache\n")); return NULL; } /* Walk through the ARP mapping table and try to find an entry to update. If none is found, the IP -> MAC address mapping is inserted in the ARP table. */ for (i = 0; i < ARP_TABLE_SIZE; ++i) { /* Check if the source IP address of the incoming packet matches the IP address in this ARP table entry. */ if (ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { /* pending entry? */ if (arp_table[i].state == ETHARP_STATE_PENDING) { DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: pending entry %u goes stable\n", i)); /* A pending entry was found, mark it stable */ arp_table[i].state = ETHARP_STATE_STABLE; /* fall-through to next if */ } /* stable entry? (possible just marked to become stable) */ if (arp_table[i].state == ETHARP_STATE_STABLE) { #if ARP_QUEUEING struct pbuf *p; struct eth_hdr *ethhdr; #endif DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %u\n", i)); /* An old entry found, update this and return. */ 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; #if ARP_QUEUEING p = arp_table[i].p; /* queued packet present? */ if (p != NULL) { /* NULL attached buffer immediately */ arp_table[i].p = NULL; /* fill-in Ethernet header */ ethhdr = p->payload; for (k = 0; k < netif->hwaddr_len; ++k) { ethhdr->dest.addr[k] = ethaddr->addr[k]; } ethhdr->type = htons(ETHTYPE_IP); DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet.\n")); /* send the queued IP packet */ netif->linkoutput(netif, p); /* free the queued IP packet */ pbuf_free(p); } #endif return NULL; } } /* if */ } /* for */ /* no matching ARP entry was found */ LWIP_ASSERT("update_arp_entry: i == ARP_TABLE_SIZE", i == ARP_TABLE_SIZE); DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: IP address not yet in table\n")); /* allowed to insert an entry? */ if ((ETHARP_ALWAYS_INSERT) || (flags & ARP_INSERT_FLAG)) { DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: adding entry to table\n")); /* find an empty or old entry. */ i = find_arp_entry(); if (i == ARP_TABLE_SIZE) { DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no available entry found\n")); return NULL; } /* see if find_arp_entry() gave us an old stable, or empty entry to re-use */ if (arp_table[i].state == ETHARP_STATE_STABLE) { DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: overwriting old stable entry %u\n", i)); /* stable entries should have no queued packets (TODO: allow later) */ #if ARP_QUEUEING LWIP_ASSERT("update_arp_entry: arp_table[i].p == NULL", arp_table[i].p == NULL); #endif } else { DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("update_arp_entry: filling empty entry %u with state %u\n", i, arp_table[i].state)); LWIP_ASSERT("update_arp_entry: arp_table[i].state == ETHARP_STATE_EMPTY", arp_table[i].state == ETHARP_STATE_EMPTY); } /* 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 { DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no matching stable entry to update\n")); } return NULL; }
/** * Update (or insert) a IP/MAC address pair in the ARP cache. * * If a pending entry is resolved, any queued packets will be sent * at this point. * * @param ipaddr IP address of the inserted ARP entry. * @param ethaddr Ethernet address of the inserted ARP entry. * @param flags Defines behaviour: * - ARP_INSERT_FLAG Allows ARP to insert this as a new item. If not specified, * only existing ARP entries will be updated. * * @return pbuf If non-NULL, a packet that was queued on a pending entry. * You should sent it and must call pbuf_free() afterwards. * * @see pbuf_free() */ static struct pbuf * update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags) { s8_t i, k; LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("update_arp_entry()\n")); LWIP_ASSERT("netif->hwaddr_len != 0", netif->hwaddr_len != 0); LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: %u.%u.%u.%u - %02x:%02x:%02x:%02x:%02x:%02x\n", ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr), ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); /* do not update for 0.0.0.0 addresses */ if (ipaddr->addr == 0) { LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: will not add 0.0.0.0 to ARP cache\n")); return NULL; } /* Walk through the ARP mapping table and try to find an entry to update. If none is found, the IP -> MAC address mapping is inserted in the ARP table. */ for (i = 0; i < ARP_TABLE_SIZE; ++i) { /* Check if the source IP address of the incoming packet matches the IP address in this ARP table entry. */ if (arp_table[i].state != ETHARP_STATE_EMPTY && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { /* pending entry? */ if (arp_table[i].state == ETHARP_STATE_PENDING) { LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: pending entry %u goes stable\n", i)); /* A pending entry was found, mark it stable */ arp_table[i].state = ETHARP_STATE_STABLE; /* fall-through to next if */ } /* stable entry? (possibly just marked to become stable) */ if (arp_table[i].state == ETHARP_STATE_STABLE) { #if ARP_QUEUEING struct pbuf *p; struct eth_hdr *ethhdr; #endif LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %u\n", i)); /* An old entry found, update this and return. */ 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; /* this is where we will send out queued packets! */ #if ARP_QUEUEING while (arp_table[i].p != NULL) { /* get the first packet on the queue (if any) */ p = arp_table[i].p; /* remember (and reference) remainder of queue */ arp_table[i].p = pbuf_dequeue(p); /* fill-in Ethernet header */ ethhdr = p->payload; for (k = 0; k < netif->hwaddr_len; ++k) { ethhdr->dest.addr[k] = ethaddr->addr[k]; ethhdr->src.addr[k] = netif->hwaddr[k]; } ethhdr->type = htons(ETHTYPE_IP); LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet %p.\n", (void *)p)); /* send the queued IP packet */ netif->linkoutput(netif, p); /* free the queued IP packet */ pbuf_free(p); } #endif /* IP addresses should only occur once in the ARP entry, we are done */ return NULL; } } /* if STABLE */ } /* for all ARP entries */ /* no matching ARP entry was found */ LWIP_ASSERT("update_arp_entry: i == ARP_TABLE_SIZE", i == ARP_TABLE_SIZE); LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: IP address not yet in table\n")); /* allowed to insert a new entry? */ if (flags & ARP_INSERT_FLAG) { LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: adding entry to table\n")); /* find an empty or old entry. */ i = find_arp_entry(); if (i == ERR_MEM) { 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; }