Example #1
0
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;
}
/**
 * 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()
 */
void
etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
{
  struct etharp_hdr *hdr;
  /* these are aligned properly, whereas the ARP header fields might not be */
  struct ip_addr sipaddr, dipaddr;
  u8_t i;
  u8_t for_us;

  LWIP_ASSERT("netif != NULL", netif != NULL);
  
  /* 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 (%"S16_F"/%"S16_F")\n", p->tot_len, sizeof(struct etharp_hdr)));
    pbuf_free(p);
    return;
  }

  hdr = p->payload;
 
  /* get aligned copies of addresses */
  *(struct ip_addr2 *)&sipaddr = hdr->sipaddr;
  *(struct ip_addr2 *)&dipaddr = hdr->dipaddr;

  /* 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(&dipaddr, &(netif->ip_addr));
  }

  /* ARP message directed to us? */
  if (for_us) {
    /* add IP address in ARP cache; assume requester wants to talk to us.
     * can result in directly sending the queued packets for this host. */
    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);
  /* ARP message not directed to us? */
  } else {
    /* update the source IP address in the cache, if present */
    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0);
  }

  /* now act on the message itself */
  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"));
    /* 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);

      hdr->dipaddr = hdr->sipaddr;
      hdr->sipaddr = *(struct ip_addr2 *)&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);
    /* 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);
}
Example #3
0
/*-----------------------------------------------------------------------------------*/
struct pbuf *
etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
{
    struct eth_addr *dest, *srcaddr, mcastaddr;
    struct eth_hdr *ethhdr;
    struct etharp_hdr *hdr;
    struct pbuf *p;
    u8_t i;

    srcaddr = (struct eth_addr *)netif->hwaddr;

    /* 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, ("etharp_output: could not allocate room for header.\n"));
#ifdef LINK_STATS
        ++stats.link.lenerr;
#endif /* LINK_STATS */
        return NULL;
    }


    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. */
    if(ip_addr_isany(ipaddr) ||
            ip_addr_isbroadcast(ipaddr, &(netif->netmask))) {
        dest = (struct eth_addr *)&ethbroadcast;
    } 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);
        dest = &mcastaddr;
    } else {
#ifdef __PAULOS__
        /* abort on insane conditions */
        if (!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)))
            return NULL;
        if (ipaddr->addr == netif->ip_addr.addr)
            return NULL;
#else
        if(!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {
            /* Use the IP address of the default gateway if the destination
               is NOT on the same subnet as we are. ("NOT" added 20021113 psheer@) */
            ipaddr = &(netif->gw);
        }
#endif

        /* We try to find a stable mapping. */
        for(i = 0; i < arp_table_last; ++i) {
            if((arp_table[i].state == ETHARP_STATE_STABLE || arp_table[i].state == ETHARP_STATE_STATIC) &&
                    ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
                dest = &arp_table[i].ethaddr;

#if 0
// FIXME: remove this test code
                if (!((int) rand() % 2)) {
                    dest = NULL;
                    arp_table[i].state = ETHARP_STATE_EMPTY;
                    if (arp_table[i].p)
                        pbuf_free (arp_table[i].p);
                    arp_table[i].p = NULL;
                    arp_table[i].payload = NULL;
                    arp_table[i].len = arp_table[0].tot_len = 0;
                }
#endif

                break;
            }
        }
    }

    if(dest == NULL) {
        /* No destination address has been found, so we'll have to send
           out an ARP request for the IP address. The outgoing packet is
           queued unless the queue is full. */

        /* We check if we are already querying for this address. If so,
           we'll bail out. */
        for(i = 0; i < arp_table_last; ++i) {
            if(arp_table[i].state == ETHARP_STATE_PENDING &&
                    ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
                DEBUGF(ETHARP_DEBUG, ("etharp_output: already queued\n"));
                return NULL;
            }
        }

        hdr = q->payload;
        for(i = 0; i < 6; ++i)
            hdr->ethhdr.src.addr[i] = srcaddr->addr[i];
        hdr->ethhdr.type = htons(ETHTYPE_IP);

        i = etharp_new_entry(q, ipaddr, NULL, ETHARP_STATE_PENDING);

        /* We allocate a pbuf for the outgoing ARP request packet. */
        p = pbuf_alloc(PBUF_RAW, sizeof(struct etharp_hdr) + 2, PBUF_RAM);
        if(p == NULL) {
            /* No ARP request packet could be allocated, so we forget about
            the ARP table entry. */
            if(i != ARP_TABLE_SIZE) {
                arp_table[i].state = ETHARP_STATE_EMPTY;
                /* We decrease the reference count of the queued pbuf (which now
                   is dequeued). */
                DEBUGF(ETHARP_DEBUG, ("etharp_output: couldn't alloc pbuf for query, dequeueing %p\n", q));
            }
            return NULL;
        }
        pbuf_header (p, (s16_t) -2);

        hdr = p->payload;

        hdr->opcode = htons(ARP_REQUEST);

        for(i = 0; i < 6; ++i) {
            hdr->dhwaddr.addr[i] = 0x00;
            hdr->shwaddr.addr[i] = srcaddr->addr[i];
        }

        memcpy (&(hdr->dipaddr), ipaddr, sizeof (hdr->dipaddr));
        memcpy (&(hdr->sipaddr), &(netif->ip_addr), sizeof (hdr->sipaddr));

        hdr->hwtype = htons(HWTYPE_ETHERNET);
        ARPH_HWLEN_SET(hdr, 6);

        hdr->proto = htons(ETHTYPE_IP);
        ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));

        for(i = 0; i < 6; ++i) {
            hdr->ethhdr.dest.addr[i] = 0xff;
            hdr->ethhdr.src.addr[i] = srcaddr->addr[i];
        }

        hdr->ethhdr.type = htons(ETHTYPE_ARP);
        return p;	/* (1) */
    } else {
        /* 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 < 6; i++) {
            ethhdr->dest.addr[i] = dest->addr[i];
            ethhdr->src.addr[i] = srcaddr->addr[i];
        }

        ethhdr->type = htons(ETHTYPE_IP);

        pbuf_ref (q);  /* <--- this is important, because the reference
must parallel that when returning over here (1). Callers must then
ALWAYS do a pbuf_free on the return value of etharp_output(). */
        return q;
    }


}
Example #4
0
/*-----------------------------------------------------------------------------------*/
struct pbuf *
etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p, struct pbuf **queued)
{
    struct etharp_hdr *hdr;
    u8_t i;

    if(p->tot_len < sizeof(struct etharp_hdr)) {
        DEBUGF(ETHARP_DEBUG, ("etharp_etharp_input: packet too short (%d/%d)\n", (int) p->tot_len, (int) sizeof(struct etharp_hdr)));
        return NULL;
    }

    hdr = p->payload;

    switch(htons(hdr->opcode)) {
    case ARP_REQUEST:
        *queued = update_arp_entry(&(hdr->sipaddr), &(hdr->shwaddr), 0);
        /* ARP request. If it asked for our address, we send out a
           reply. */
        DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP request\n"));
        if(!memcmp(&(hdr->dipaddr), &(netif->ip_addr), sizeof (hdr->dipaddr))) {
            pbuf_ref(p);
            hdr->opcode = htons(ARP_REPLY);

            memcpy (&(hdr->dipaddr), &(hdr->sipaddr), sizeof (hdr->dipaddr));
            memcpy (&(hdr->sipaddr), &(netif->ip_addr), sizeof (hdr->sipaddr));

            for(i = 0; i < 6; ++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, 6);

            hdr->proto = htons(ETHTYPE_IP);
            ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));

            hdr->ethhdr.type = htons(ETHTYPE_ARP);
            return p;
        }
        break;
    case ARP_REPLY:
        /* ARP reply. We insert or update the ARP table. */
        DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: ARP reply\n"));
        if(!memcmp (&(hdr->dipaddr), &(netif->ip_addr), sizeof (hdr->dipaddr))) {
#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
            dhcp_arp_reply(&hdr->sipaddr);
#endif
            /* add_arp_entry() will return a pbuf that has previously been
            queued waiting for an ARP reply. */
        }
        /* whether its destined for us or not, we update the arp table */
        return add_arp_entry(&(hdr->sipaddr), &(hdr->shwaddr));
        break;
    default:
        DEBUGF(ETHARP_DEBUG, ("etharp_arp_input: unknown type %d\n", htons(hdr->opcode)));
        break;
    }

    return NULL;
}
Example #5
0
/**
 * 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;
}
Example #6
0
/**
 * Responds to ARP requests, updates ARP entries and sends queued IP packets.
 * 
 * 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 (%ld/%u)\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;
}
Example #7
0
/**
 * 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;
}
/**
 * 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()
 */
void
etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
{
  struct etharp_hdr *hdr;
  /* these are aligned properly, whereas the ARP header fields might not be */
  struct ip_addr sipaddr, dipaddr;
  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;
  }

  hdr = p->payload;
 
  /* get aligned copies of addresses */
  *(struct ip_addr2 *)&sipaddr = hdr->sipaddr;
  *(struct ip_addr2 *)&dipaddr = hdr->dipaddr;

  /* 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(&dipaddr, &(netif->ip_addr));
  }

  /* ARP message directed to us? */
  if (for_us) {
    /* add IP address in ARP cache; assume requester wants to talk to us.
     * can result in directly sending the queued packets for this host. */
    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_CREATE);
  /* ARP message not directed to us? */
  } else {
    /* update the source IP address in the cache, if present */
    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0);
  }

  /* now act on the message itself */
  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"));
    /* 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);

      hdr->dipaddr = hdr->sipaddr;
      hdr->sipaddr = *(struct ip_addr2 *)&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);
      
#ifdef LINKLOCAL_IP //Ron Add for Rendzvous 12/10/04    
	  if( mRENVEnable && (LinkLocal_get_current_state() != NO_USE ) 
	  		&& is_linklocal_ip( dipaddr.addr ) )
	  {
	  		if( (LinkLocal_get_current_state() != IDLE) && ip_conflict_cnt++ == 0 )
  	  			linklocal_alarm();
  	  		else if( (LinkLocal_get_current_state() == IDLE) && ip_conflict_cnt++ == 0) 	
  	  		{
  	  			linklocal_alarm();
  	  		}
  	  }
#endif	  
    /* we are not configured? */
    } else if (netif->ip_addr.addr == 0) {
      /* { for_us == 0 and netif->ip_addr.addr == 0 } */
#ifdef LINKLOCAL_IP //Ron Add for Rendzvous 12/10/04    
		if( mRENVEnable && (LinkLocal_get_current_state() != NO_USE )
		  		&& is_linklocal_ip( dipaddr.addr ) )
		{
			if( (LinkLocal_get_current_state() != IDLE) && ip_conflict_cnt++ == 0 )
  	  			linklocal_alarm();
  	  		else if( (LinkLocal_get_current_state() == IDLE) && ip_conflict_cnt++ == 0) 	
  	  		{
  	  			linklocal_alarm();
  	  		}
  	  		
   		    	hdr->opcode = htons(ARP_REPLY);
				
				hdr->sipaddr = hdr->dipaddr;
				hdr->dipaddr = *(struct ip_addr2 *)&netif->ip_addr;
//		      hdr->dipaddr = hdr->sipaddr;
//		      hdr->sipaddr = *(struct ip_addr2 *)&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);
				
				netif->linkoutput(netif, p);
		      
		}
#endif 
      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 to our wanna-have-address */
    if (for_us){ 
    	dhcp_arp_reply(netif, &sipaddr);
    }
    	
#endif

#ifdef LINKLOCAL_IP //Ron Add for Rendzvous 12/10/04    
		if( mRENVEnable && (LinkLocal_get_current_state() != NO_USE ) && is_linklocal_ip( sipaddr.addr )  )
		{
	  		if( (LinkLocal_get_current_state() != IDLE) && ip_conflict_cnt++ == 0 )
  	  			linklocal_alarm();
  	  		else if( (LinkLocal_get_current_state() == IDLE) && ip_conflict_cnt++ == 0) 	
  	  		{
  	  			linklocal_alarm();
  	  		}
  	  	}
#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);
}
Example #9
0
/**
 * 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;
}