etharp.c
来自「Keil下移植好的lwip基于c166」· C语言 代码 · 共 823 行 · 第 1/2 页
C
823 行
/**
* @file
* Address Resolution Protocol module for IP over Ethernet
*
* $Log: etharp.c,v $
* Revision 1.29 2003/02/24 10:49:05 jani
* cleaned up opt.h a bit, added more option defaults ad changed SYS_LIGHTWEIGHT_PROT to be a 0/1 define.The same for COMPAT_SOCKET
*
* Revision 1.28 2003/02/21 16:43:46 jani
* byte-order handling functions are in inet.c now and the uperrcase counterparts are gone. opt.h has all the
* configurable items debug does not need to be directly included.
*
* Revision 1.27 2003/02/20 16:32:24 jani
* do not directly include lwipopts.h but lwip/opt.h instead
*
* Revision 1.26 2003/02/20 13:13:56 likewise
* Fixed some issues open after merging 'leon-dhcp'. Added new debugging.
*
* Revision 1.25 2003/02/20 08:42:04 likewise
* Merged with leon-dhcp branch. Tagged as POST_leon-dhcp afterwards.
*
* Revision 1.24.2.1 2003/02/10 22:42:59 likewise
* Massive amount of refactoring DHCP code.
*
* Revision 1.24 2003/02/06 22:18:57 davidhaas
* Add the following features and bugfixes:
*
* Added select() functionality to sockets library.
* Support for errno in sockets library.
* Byte ordering fixes.
* basic lwip_ioctl(), FIONREAD, get/setsockopt() etc. support
*
* - added additional argument to netif_add to pass state pointer so that the
* if_init function has access to context information before
* the interface is added, without accessing globals.
*
* - added netif_remove()
*
* - to conserve cpu load the tcpip_tcp_timer should only be active
* when tcbs that need it exist.
*
* - pass length of available data to callbacks for NETCONN_EVT_RCV events
*
* - added tcpip_link_input(), a hack to allow processing of PPP
* packets in tcpip_thread() context. This saves threads and context
* switches.
*
* - renamed incompatible ASSERT() macro to LWIP_ASSERT() to avoid name
* collision.
*
* - changed a bunch of %d's to %u's in format strings for unsigned values.
*
* - added ip_frag to lwip_stats.
*
* - changed IP_REASS_MAXAGE and IP_REASS_TMO defaults to more realistic
* values.
*
* - added sys_timeout_remove() function to cancel timeouts (needed by PPP
* amongst other things).
*
* - tolerate NULL returns from sys_arch_timeouts() since some threads might
* not need to use or have timeouts.
*
* - added sys_sem_wait_timeout()
*
* - moved mem_malloc() function to end of mem.c to work around tasking
* compiler bug.
*
* - automatically bind to local tcp port if 0.
*
* - allow customization of port ranges for automatic local bindings.
*
* - corrected various typos, spelling errors, etc..
*
* Thanks to Marc Boucher for many of these changes.
*
* Revision 1.23 2003/01/18 16:05:24 jani
* When all entries are 0 due to the whole table changing since the last arp tick (past 10 seconds) there's no oldest entry and the new entry does not get a spot.Fix this (from Ed Sutter)
*
* Revision 1.22 2003/01/13 09:38:21 jani
* remove global ctime.Each entry's ctime is now absolute.This avoids wrapping and also solves naming clash reported on the list
*
* Revision 1.21 2003/01/08 11:04:36 likewise
* Moved ETHARP_ALWAYS_INSERT switch to lwipopts.h
*
* Revision 1.19 2003/01/08 10:09:43 likewise
* Updated lwIP module copyright years to include 2003. Committers must check theirs.
*
* Revision 1.18 2003/01/08 09:24:50 likewise
* Removed etharp_output_sent() as etharp.c no longer returns ARP packets to the driver.
*
* Revision 1.17 2002/12/18 12:49:02 jani
* renamed (hopefully everywhere) stats to lwip_stats.closes bug #1901
*
* Revision 1.16 2002/12/17 09:41:16 jani
* Use C style comments.In debug stataments cast various struct pointers to void* to
* avoid printf warnings.misc warnings in etharp.
*
*/
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/*
* TODO:
*
RFC 3220 4.6 IP Mobility Support for IPv4 January 2002
- A Gratuitous ARP [45] is an ARP packet sent by a node in order
to spontaneously cause other nodes to update an entry in their
ARP cache. A gratuitous ARP MAY use either an ARP Request or
an ARP Reply packet. In either case, the ARP Sender Protocol
Address and ARP Target Protocol Address are both set to the IP
address of the cache entry to be updated, and the ARP Sender
Hardware Address is set to the link-layer address to which this
cache entry should be updated. When using an ARP Reply packet,
the Target Hardware Address is also set to the link-layer
address to which this cache entry should be updated (this field
is not used in an ARP Request packet).
In either case, for a gratuitous ARP, the ARP packet MUST be
transmitted as a local broadcast packet on the local link. As
specified in [36], any node receiving any ARP packet (Request
or Reply) MUST update its local ARP cache with the Sender
Protocol and Hardware Addresses in the ARP packet, if the
receiving node has an entry for that IP address already in its
ARP cache. This requirement in the ARP protocol applies even
for ARP Request packets, and for ARP Reply packets that do not
match any ARP Request transmitted by the receiving node [36].
*
My suggestion would be to send a ARP request for our newly obtained
address upon configuration of an Ethernet interface.
*/
#include "lwip/opt.h"
#include "lwip/inet.h"
#include "netif/etharp.h"
#include "lwip/ip.h"
#include "lwip/stats.h"
/* ARP needs to inform DHCP of any ARP replies? */
#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
# include "lwip/dhcp.h"
#endif
/** the time an ARP entry stays valid after its last update, (120 * 10) seconds = 20 minutes. */
#define ARP_MAXAGE 120
/** the time an ARP entry stays pending after first request, (2 * 10) seconds = 20 seconds. */
#define ARP_MAXPENDING 2
#define HWTYPE_ETHERNET 1
/** ARP message types */
#define ARP_REQUEST 1
#define ARP_REPLY 2
#define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8)
#define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff)
#define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8))
#define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8))
enum etharp_state {
ETHARP_STATE_EMPTY,
ETHARP_STATE_PENDING,
ETHARP_STATE_STABLE
};
struct etharp_entry {
struct ip_addr ipaddr;
struct eth_addr ethaddr;
enum etharp_state state;
#if ARP_QUEUEING
struct pbuf *p;
#endif
u8_t ctime;
};
static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
static struct etharp_entry arp_table[ARP_TABLE_SIZE];
static struct pbuf *update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);
#define ARP_INSERT_FLAG 1
/**
* Initializes ARP module.
*/
void
etharp_init(void)
{
u8_t i;
/* clear ARP entries */
for(i = 0; i < ARP_TABLE_SIZE; ++i) {
arp_table[i].state = ETHARP_STATE_EMPTY;
#if ARP_QUEUEING
arp_table[i].p = NULL;
#endif
}
}
/**
* Clears expired entries in the ARP table.
*
* This function should be called every ETHARP_TMR_INTERVAL microseconds (10 seconds),
* in order to expire entries in the ARP table.
*/
void
etharp_tmr(void)
{
u8_t i;
DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));
/* remove expired entries from the ARP table */
for(i = 0; i < ARP_TABLE_SIZE; ++i) {
arp_table[i].ctime++;
if((arp_table[i].state == ETHARP_STATE_STABLE) &&
(arp_table[i].ctime >= ARP_MAXAGE)) {
DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %u.\n", i));
arp_table[i].state = ETHARP_STATE_EMPTY;
#if ARP_QUEUEING
/* remove any queued packet */
pbuf_free(arp_table[i].p);
arp_table[i].p = NULL;
#endif
} else if((arp_table[i].state == ETHARP_STATE_PENDING) &&
(arp_table[i].ctime >= ARP_MAXPENDING)) {
arp_table[i].state = ETHARP_STATE_EMPTY;
#if ARP_QUEUEING
DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u - dequeueing %p.\n", i, (void *)(arp_table[i].p)));
/* remove any queued packet */
pbuf_free(arp_table[i].p);
arp_table[i].p = NULL;
#else
DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u.\n", i));
#endif
}
}
}
/**
* Return an empty ARP entry or, if the table is full, ARP_TABLE_SIZE if all
* entries are pending, otherwise the oldest entry.
*
* @return The ARP entry index that is available, ARP_TABLE_SIZE if no usable
* entry is found.
*/
static u8_t
find_arp_entry(void)
{
u8_t i, j, maxtime;
/* Try to find an unused entry in the ARP table. */
for(i = 0; i < ARP_TABLE_SIZE; ++i) {
if(arp_table[i].state == ETHARP_STATE_EMPTY) {
DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found empty entry %u\n", i));
break;
}
}
/* If no unused entry is found, we try to find the oldest entry and
throw it away. If all entries are new and have 0 ctime drop one */
if(i == ARP_TABLE_SIZE) {
maxtime = 0;
j = ARP_TABLE_SIZE;
for(i = 0; i < ARP_TABLE_SIZE; ++i) {
/* remember entry with oldest stable entry in j*/
if((arp_table[i].state == ETHARP_STATE_STABLE) &&
(arp_table[i].ctime >= maxtime)) {
maxtime = arp_table[i].ctime;
j = i;
}
}
DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found oldest stable entry %u\n", j));
i = j;
}
DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning %u, state %u\n", i, arp_table[i].state));
return i;
}
/**
* 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;
#if ARP_QUEUEING
struct eth_hdr *ethhdr;
#endif
DEBUGF(ETHARP_DEBUG, ("update_arp_entry()"));
DEBUGF(ETHARP_DEBUG, ("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, ("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, ("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) {
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: updating stable entry %u\n", i));
/* An old entry found, update this and return. */
for(k = 0; k < 6; ++k) {
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
}
/* reset time stamp */
arp_table[i].ctime = 0;
#if ARP_QUEUEING
/* queued packet present? */
if(arp_table[i].p != NULL) {
/* fill-in Ethernet header */
ethhdr = arp_table[i].p->payload;
for(k = 0; k < 6; ++k) {
ethhdr->dest.addr[k] = ethaddr->addr[k];
}
ethhdr->type = htons(ETHTYPE_IP);
DEBUGF(ETHARP_DEBUG, ("update_arp_entry: sending queued IP packet.\n"));
/* send the queued IP packet */
netif->linkoutput(netif, arp_table[i].p);
/* free the queued IP packet */
pbuf_free(arp_table[i].p);
/* remove queued packet from ARP entry (must be freed by the caller) */
arp_table[i].p = NULL;
}
#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, ("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, ("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, ("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, ("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, ("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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?