Beispiel #1
0
Datei: arp.c Projekt: juur/FailOS
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();
}
Beispiel #2
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;
}
Beispiel #3
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;
}
Beispiel #4
0
/**
 * 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;
}
Beispiel #5
0
/**
 * 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;
}