From 29df95c514fdf83cb0b2862694290bdfc7ea5297 Mon Sep 17 00:00:00 2001 From: likewise Date: Wed, 5 May 2004 18:28:42 +0000 Subject: [PATCH] As etharp already sends packets from the queue asynchronously, also make it send packet submitted through etharp_output(). etharp_output() now returns err_t. etharp_query() now sends a packet directly if the IP address is stable. --- src/include/netif/etharp.h | 2 +- src/netif/etharp.c | 260 +++++++++++++++++++------------------ src/netif/ethernetif.c | 61 +++------ 3 files changed, 153 insertions(+), 170 deletions(-) diff --git a/src/include/netif/etharp.h b/src/include/netif/etharp.h index 83a722f0..0f1eeef6 100644 --- a/src/include/netif/etharp.h +++ b/src/include/netif/etharp.h @@ -98,7 +98,7 @@ void etharp_tmr(void); void etharp_ip_input(struct netif *netif, struct pbuf *p); void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p); -struct pbuf *etharp_output(struct netif *netif, struct ip_addr *ipaddr, +err_t etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q); err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q); diff --git a/src/netif/etharp.c b/src/netif/etharp.c index 985d978d..c3c0bece 100644 --- a/src/netif/etharp.c +++ b/src/netif/etharp.c @@ -514,29 +514,33 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) * * @return If non-NULL, a packet ready to be sent by caller. * + * @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_RTE No route to destination (no gateway to external networks). */ -struct pbuf * +err_t 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; + err_t result; - /* make room for Ethernet header */ + /* make room for Ethernet header - should not fail*/ 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.. */ + /* bail out */ LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n")); LINK_STATS_INC(link.lenerr); - return NULL; + pbuf_free(q); + return ERR_BUF; } /* 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. */ + /* Determine on destination hardware address. Broadcasts and multicasts + * are special, other IP 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)) { @@ -557,86 +561,67 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) } /* 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 */ + /* outside local network? */ 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 */ + if (netif->gw.addr != 0) { + /* send to hardware address of 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; + /* no default gateway available? */ + } else { + /* destination unreachable, discard packet */ + pbuf_free(q); + return ERR_RTE; } } - - /* 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 */ - } - } + result = etharp_query(netif, ipaddr, q); + } /* else unicast */ /* 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; + /* send packet */ + result = netif->linkoutput(netif, q); } /* never reached; here for safety */ - return NULL; + pbuf_free(q); + 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. + * 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, the packet is + * directly sent. An ARP request is sent out. + * * @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. + * @param q If non-NULL, a pbuf that must be delivered to the IP address. * + * @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). + * * @note Might be used in the future by manual IP configuration * as well. * @@ -645,39 +630,71 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) */ 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; - s8_t i; - u8_t perform_arp_request = 1; - /* prevent 'unused argument' compiler warning if ARP_QUEUEING == 0 */ - (void)q; - srcaddr = (struct eth_addr *)netif->hwaddr; - /* bail out if this IP address is pending */ + s8_t i; /* ARP entry index */ + u8_t k; /* Ethernet address octet index */ + + /* Do three things in this order (by design): + * + * 1) send out ARP request + * 2) find entry in ARP cache + * 3) handle the packet + */ + + /* 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_query: sending ARP request.\n")); + hdr->opcode = htons(ARP_REQUEST); + for (k = 0; k < netif->hwaddr_len; 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)); + for (k = 0; k < netif->hwaddr_len; ++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_query: could not allocate pbuf for ARP request.\n")); + } + + /* search entry of queried IP address in the ARP cache */ for (i = 0; i < ARP_TABLE_SIZE; ++i) { /* valid ARP cache entry with matching IP address? */ 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 | 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 */ + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already pending in entry %u\n", i)); /* { i != ARP_TABLE_SIZE } */ break; } - /* stable entry? */ 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); + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already stable in entry %u\n", i)); /* { i != ARP_TABLE_SIZE } */ break; } @@ -696,56 +713,43 @@ err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) /* i is available, create ARP entry */ arp_table[i].state = ETHARP_STATE_PENDING; ip_addr_set(&arp_table[i].ipaddr, ipaddr); + arp_table[i].p = NULL; + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: added pending entry %u for IP address\n", i)); } - /* { i is now valid } */ + + /* { i is either a (new or existing) PENDING or STABLE entry } */ + + /* 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_addr * srcaddr = (struct eth_addr *)netif->hwaddr; + struct eth_hdr *ethhdr = q->payload; + for(k = 0; k < netif->hwaddr_len; 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); #if ARP_QUEUEING /* queue the given q packet */ - /* copy any PBUF_REF referenced payloads into PBUF_RAM */ - /* (the caller assumes the referenced payload can be freed) */ - q = pbuf_take(q); - /* queue packet (even on a stable entry, see above) */ - pbuf_queue(arp_table[i].p, q); + /* pending entry? (either just created or already pending */ + } else if (arp_table[i].state == ETHARP_STATE_PENDING) { + /* copy any PBUF_REF referenced payloads into PBUF_RAM */ + /* (the caller assumes the referenced payload can be freed) */ + p = pbuf_take(q); + /* queue packet */ + if (p != NULL) { + pbuf_queue(arp_table[i].p, p); + LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %d\n", (void *)q, i)); + } 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; + } #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; diff --git a/src/netif/ethernetif.c b/src/netif/ethernetif.c index f7ad781f..2b53f655 100644 --- a/src/netif/ethernetif.c +++ b/src/netif/ethernetif.c @@ -61,7 +61,6 @@ static void ethernetif_input(struct netif *netif); static err_t ethernetif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr); - static void low_level_init(struct netif *netif) { @@ -95,7 +94,6 @@ low_level_init(struct netif *netif) * */ - static err_t low_level_output(struct ethernetif *ethernetif, struct pbuf *p) { @@ -199,30 +197,10 @@ static err_t ethernetif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr) { - struct ethernetif *ethernetif; - struct pbuf *q; - struct eth_hdr *ethhdr; - struct eth_addr *dest, mcastaddr; - struct ip_addr *queryaddr; - err_t err; - u8_t i; - ethernetif = netif->state; - - /* resolve the link destination hardware address */ - p = etharp_output(netif, ipaddr, p); - - /* network hardware address obtained? */ - if (p == NULL) - { - /* we cannot tell if the packet was sent: the packet could */ - /* have been queued on an ARP entry that was already pending. */ - return ERR_OK; - } - - /* send out the packet */ - return low_level_output(ethernetif, p); - + /* resolve hardware address, then send (or queue) packet */ + return etharp_output(netif, ipaddr, p); + } /* @@ -240,42 +218,43 @@ ethernetif_input(struct netif *netif) { struct ethernetif *ethernetif; struct eth_hdr *ethhdr; - struct pbuf *p, *q; + struct pbuf *p; ethernetif = netif->state; + /* move received packet into a new pbuf */ p = low_level_input(ethernetif); - - if (p != NULL) - return; + /* no packet could be read, silently ignore this */ + if (p == NULL) return; + /* points to packet payload, which starts with an Ethernet header */ + ethhdr = p->payload; #ifdef LINK_STATS lwip_stats.link.recv++; #endif /* LINK_STATS */ ethhdr = p->payload; - q = NULL; switch (htons(ethhdr->type)) { - case ETHTYPE_IP: - q = etharp_ip_input(netif, p); - pbuf_header(p, -sizeof(struct eth_hdr)); - netif->input(p, netif); - break; + /* IP packet? */ + case ETHTYPE_IP: + /* update ARP table */ + etharp_ip_input(netif, p); + /* skip Ethernet header */ + pbuf_header(p, -sizeof(struct eth_hdr)); + /* pass to network layer */ + netif->input(p, netif); + break; case ETHTYPE_ARP: - q = etharp_arp_input(netif, ethernetif->ethaddr, p); + /* pass p to ARP module */ + etharp_arp_input(netif, ethernetif->ethaddr, p); break; default: pbuf_free(p); p = NULL; break; } - if (q != NULL) { - low_level_output(ethernetif, q); - pbuf_free(q); - q = NULL; - } } static void