Merged from DEVEL. etharp prepared for queueing feature. DHCP fix.

This commit is contained in:
uid67528 2003-12-28 02:38:51 +00:00
parent a646b5374f
commit eed8ea5bc1
10 changed files with 241 additions and 168 deletions

View File

@ -5,8 +5,20 @@ TODO
HISTORY HISTORY
(STABLE-0_6_6)
++ Bug fixes:
* Fixed DHCP which did not include the IP address in DECLINE messages.
++ Changes:
* etharp.c has been hauled over a bit.
(STABLE-0_6_5) (STABLE-0_6_5)
++ Bug fixes:
* Fixed TCP bug induced by bad window resizing with unidirectional TCP traffic. * Fixed TCP bug induced by bad window resizing with unidirectional TCP traffic.
* Packets sent from ARP queue had invalid source hardware address. * Packets sent from ARP queue had invalid source hardware address.

View File

@ -192,6 +192,7 @@ static void dhcp_handle_offer(struct netif *netif)
/* remember offered address */ /* remember offered address */
ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr); ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr);
LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08lx\n", dhcp->offered_ip_addr.addr)); LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08lx\n", dhcp->offered_ip_addr.addr));
dhcp_select(netif); dhcp_select(netif);
} }
} }
@ -646,6 +647,9 @@ static err_t dhcp_decline(struct netif *netif)
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
dhcp_option_short(dhcp, 576); dhcp_option_short(dhcp, 576);
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
dhcp_option_trailer(dhcp); dhcp_option_trailer(dhcp);
/* resize pbuf to reflect true size of options */ /* resize pbuf to reflect true size of options */
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);

View File

@ -220,8 +220,6 @@ memp_malloc(memp_t type)
((u32_t)MEM_ALIGN((u8_t *)memp + sizeof(struct memp)) % MEM_ALIGNMENT) == 0); ((u32_t)MEM_ALIGN((u8_t *)memp + sizeof(struct memp)) % MEM_ALIGNMENT) == 0);
mem = MEM_ALIGN((u8_t *)memp + sizeof(struct memp)); mem = MEM_ALIGN((u8_t *)memp + sizeof(struct memp));
/* initialize memp memory with zeroes */
memset(mem, 0, memp_sizes[type]);
return mem; return mem;
} else { } else {
LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %d\n", type)); LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %d\n", type));

View File

@ -39,7 +39,6 @@
#include "lwip/opt.h" #include "lwip/opt.h"
#include "lwip/def.h" #include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/netif.h" #include "lwip/netif.h"
#include "lwip/ip_addr.h" #include "lwip/ip_addr.h"
#include "lwip/tcp.h" #include "lwip/tcp.h"
@ -61,22 +60,15 @@ struct netif *netif_default = NULL;
* @return netif, or NULL if failed. * @return netif, or NULL if failed.
*/ */
struct netif * struct netif *
netif_add(struct ip_addr *ipaddr, struct ip_addr *netmask, netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
struct ip_addr *gw, struct ip_addr *gw,
void *state, void *state,
err_t (* init)(struct netif *netif), err_t (* init)(struct netif *netif),
err_t (* input)(struct pbuf *p, struct netif *netif)) err_t (* input)(struct pbuf *p, struct netif *netif))
{ {
struct netif *netif;
static int netifnum = 0; static int netifnum = 0;
/* allocate netif structure */
netif = mem_malloc(sizeof(struct netif));
if (netif == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("netif_add(): out of memory for netif\n"));
return NULL;
}
#if LWIP_DHCP #if LWIP_DHCP
/* netif not under DHCP control by default */ /* netif not under DHCP control by default */
netif->dhcp = NULL; netif->dhcp = NULL;
@ -90,7 +82,6 @@ netif_add(struct ip_addr *ipaddr, struct ip_addr *netmask,
/* call user specified initialization function for netif */ /* call user specified initialization function for netif */
if (init(netif) != ERR_OK) { if (init(netif) != ERR_OK) {
mem_free(netif);
return NULL; return NULL;
} }
@ -142,7 +133,6 @@ void netif_remove(struct netif * netif)
/* reset default netif */ /* reset default netif */
netif_default = NULL; netif_default = NULL;
LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") ); LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
mem_free( netif );
} }
struct netif * struct netif *

View File

@ -504,29 +504,33 @@ pbuf_header(struct pbuf *p, s16_t header_size)
} }
/** /**
* Free a pbuf (chain) from usage, de-allocate non-used head of chain. * Dereference a pbuf (chain) and deallocate any no-longer-used
* pbufs at the head of this chain.
* *
* Decrements the pbuf reference count. If it reaches * Decrements the pbuf reference count. If it reaches
* zero, the pbuf is deallocated. * zero, the pbuf is deallocated.
* *
* For a pbuf chain, this is repeated for each pbuf in the chain, up to the * For a pbuf chain, this is repeated for each pbuf in the chain,
* pbuf which has a non-zero reference count after decrementing. * up to a pbuf which has a non-zero reference count after
* (This might be the whole chain.) * decrementing. (This might de-allocate the whole chain.)
* *
* @param pbuf pbuf (chain) to be freed from one user. * @param pbuf The pbuf (chain) to be dereferenced.
* *
* @return the number of unreferenced pbufs that were de-allocated * @return the number of pbufs that were de-allocated
* from the head of the chain. * from the head of the chain.
* *
* @note May not be called on a packet queue. * @note MUST NOT be called on a packet queue.
* @note the reference counter of a pbuf equals the number of pointers * @note the reference counter of a pbuf equals the number of pointers
* that refer to the pbuf (or into the pbuf). * that refer to the pbuf (or into the pbuf).
* *
* @internal examples: * @internal examples:
* *
* Assuming existing chains a->b->c with the following reference
* counts, calling pbuf_free(a) results in:
*
* 1->2->3 becomes ...1->3 * 1->2->3 becomes ...1->3
* 3->3->3 becomes 2->3->3 * 3->3->3 becomes 2->3->3
* 1->1->2 becomes ....->1 * 1->1->2 becomes ......1
* 2->1->1 becomes 1->1->1 * 2->1->1 becomes 1->1->1
* 1->1->1 becomes ....... * 1->1->1 becomes .......
* *
@ -636,11 +640,12 @@ pbuf_ref(struct pbuf *p)
/** /**
* Concatenate two pbufs (each may be a pbuf chain) and take over * Concatenate two pbufs (each may be a pbuf chain) and take over
* the reference of the tail pbuf. * the caller's reference of the tail pbuf.
* *
* @note The caller MAY NOT reference the tail pbuf afterwards. * @note The caller MAY NOT reference the tail pbuf afterwards.
* Use pbuf_chain() for that purpose.
* *
* @see pbuf_chain() * @see pbuf_chain()
*/ */
void void
@ -650,16 +655,14 @@ pbuf_cat(struct pbuf *h, struct pbuf *t)
LWIP_ASSERT("h != NULL", h != NULL); LWIP_ASSERT("h != NULL", h != NULL);
LWIP_ASSERT("t != NULL", t != NULL); LWIP_ASSERT("t != NULL", t != NULL);
if ((h == NULL) || (t == NULL)) return;
if (t == NULL)
return;
/* proceed to last pbuf of chain */ /* proceed to last pbuf of chain */
for (p = h; p->next != NULL; p = p->next) { for (p = h; p->next != NULL; p = p->next) {
/* add total length of second chain to all totals of first chain */ /* add total length of second chain to all totals of first chain */
p->tot_len += t->tot_len; p->tot_len += t->tot_len;
} }
/* p is last pbuf of first h chain */ /* { p is last pbuf of first h chain, p->next == NULL } */
LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
/* add total length of second chain to last pbuf total of first chain */ /* add total length of second chain to last pbuf total of first chain */
p->tot_len += t->tot_len; p->tot_len += t->tot_len;
@ -668,13 +671,15 @@ pbuf_cat(struct pbuf *h, struct pbuf *t)
} }
/** /**
* Chain two pbufs (or pbuf chains) together. They must belong to the same packet. * Chain two pbufs (or pbuf chains) together.
* It's the same as pbuf_cat with the addition that it increases the reference count *
* of the tail. * The caller MUST call pbuf_free(t) once it has stopped
* using it. Use pbuf_cat() instead if you no longer use t.
* *
* @param h head pbuf (chain) * @param h head pbuf (chain)
* @param t tail pbuf (chain) * @param t tail pbuf (chain)
* @note May not be called on a packet queue. * @note The pbufs MUST belong to the same packet.
* @note MAY NOT be called on a packet queue.
* *
* The ->tot_len fields of all pbufs of the head chain are adjusted. * The ->tot_len fields of all pbufs of the head chain are adjusted.
* The ->next field of the last pbuf of the head chain is adjusted. * The ->next field of the last pbuf of the head chain is adjusted.
@ -685,7 +690,7 @@ void
pbuf_chain(struct pbuf *h, struct pbuf *t) pbuf_chain(struct pbuf *h, struct pbuf *t)
{ {
pbuf_cat(h, t); pbuf_cat(h, t);
/* t is now referenced to one more time */ /* t is now referenced by h */
pbuf_ref(t); pbuf_ref(t);
LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t)); LWIP_DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
} }

View File

@ -133,7 +133,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
pcb->unsent != NULL); pcb->unsent != NULL);
} }
seg = NULL; seg = useg = NULL;
seglen = 0; seglen = 0;
/* First, break up the data into segments and tuck them together in /* First, break up the data into segments and tuck them together in
@ -158,6 +158,7 @@ tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
} }
else { else {
/* Attach the segment to the end of the queued segments. */ /* Attach the segment to the end of the queued segments. */
LWIP_ASSERT("useg != NULL", useg != NULL);
useg->next = seg; useg->next = seg;
useg = seg; useg = seg;
} }

View File

@ -191,10 +191,10 @@ void dhcp_fine_tmr(void);
#define DHCP_OPTION_MESSAGE_TYPE_LEN 1 #define DHCP_OPTION_MESSAGE_TYPE_LEN 1
#define DHCP_OPTION_SERVER_ID 54 /* RFC 2131 9.7, server IP address */ #define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */
#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2131 9.8, requested option types */ #define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */
#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2131 9.10, message size accepted >= 576 */ #define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */
#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2 #define DHCP_OPTION_MAX_MSG_SIZE_LEN 2
#define DHCP_OPTION_T1 58 /* T1 renewal time */ #define DHCP_OPTION_T1 58 /* T1 renewal time */

View File

@ -115,7 +115,7 @@ extern struct netif *netif_default;
/* netif_init() must be called first. */ /* netif_init() must be called first. */
void netif_init(void); void netif_init(void);
struct netif *netif_add(struct ip_addr *ipaddr, struct ip_addr *netmask, struct netif *netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
struct ip_addr *gw, struct ip_addr *gw,
void *state, void *state,
err_t (* init)(struct netif *netif), err_t (* init)(struct netif *netif),

View File

@ -42,6 +42,13 @@
* *
*/ */
/**
* TODO:
* - pbufs should be sent from the queue once an ARP entry state
* goes from PENDING to STABLE.
* - Non-PENDING entries MUST NOT have queued packets.
*/
/* /*
* TODO: * TODO:
* *
@ -113,6 +120,9 @@ struct etharp_entry {
struct eth_addr ethaddr; struct eth_addr ethaddr;
enum etharp_state state; enum etharp_state state;
#if ARP_QUEUEING #if ARP_QUEUEING
/**
* Pointer to queue of pending outgoing packets on this ARP entry.
* Must be at most a single packet for now. */
struct pbuf *p; struct pbuf *p;
#endif #endif
u8_t ctime; u8_t ctime;
@ -121,22 +131,27 @@ struct etharp_entry {
static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
static struct etharp_entry arp_table[ARP_TABLE_SIZE]; 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); static s8_t find_arp_entry(void);
#define ARP_INSERT_FLAG 1 #define ARP_INSERT_FLAG 1
static struct pbuf *update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);
#if ARP_QUEUEING
static struct pbuf *etharp_enqueue(s8_t i, struct pbuf *q);
static u8_t etharp_dequeue(s8_t i);
#endif
/** /**
* Initializes ARP module. * Initializes ARP module.
*/ */
void void
etharp_init(void) etharp_init(void)
{ {
u8_t i; s8_t i;
/* clear ARP entries */ /* clear ARP entries */
for(i = 0; i < ARP_TABLE_SIZE; ++i) { for(i = 0; i < ARP_TABLE_SIZE; ++i) {
arp_table[i].state = ETHARP_STATE_EMPTY; arp_table[i].state = ETHARP_STATE_EMPTY;
#if ARP_QUEUEING #if ARP_QUEUEING
arp_table[i].p = NULL; arp_table[i].p = NULL;
#endif #endif
arp_table[i].ctime = 0;
} }
} }
@ -149,22 +164,28 @@ etharp_init(void)
void void
etharp_tmr(void) etharp_tmr(void)
{ {
u8_t i; s8_t i;
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));
/* remove expired entries from the ARP table */ /* remove expired entries from the ARP table */
for (i = 0; i < ARP_TABLE_SIZE; ++i) { for (i = 0; i < ARP_TABLE_SIZE; ++i) {
arp_table[i].ctime++; arp_table[i].ctime++;
/* a resolved/stable entry? */
if ((arp_table[i].state == ETHARP_STATE_STABLE) && if ((arp_table[i].state == ETHARP_STATE_STABLE) &&
/* entry has become old? */
(arp_table[i].ctime >= ARP_MAXAGE)) { (arp_table[i].ctime >= ARP_MAXAGE)) {
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %u.\n", i)); LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %u.\n", i));
goto empty; goto empty;
/* an unresolved/pending entry? */
} else if ((arp_table[i].state == ETHARP_STATE_PENDING) && } else if ((arp_table[i].state == ETHARP_STATE_PENDING) &&
/* entry unresolved/pending for too long? */
(arp_table[i].ctime >= ARP_MAXPENDING)) { (arp_table[i].ctime >= ARP_MAXPENDING)) {
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u.\n", i)); LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u.\n", i));
empty: empty:
/* empty old entry */
arp_table[i].state = ETHARP_STATE_EMPTY; arp_table[i].state = ETHARP_STATE_EMPTY;
#if ARP_QUEUEING #if ARP_QUEUEING
/* and empty packet queue */
if (arp_table[i].p != NULL) { if (arp_table[i].p != NULL) {
/* remove any queued packet */ /* remove any queued packet */
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %u, packet queue %p.\n", i, (void *)(arp_table[i].p))); LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %u, packet queue %p.\n", i, (void *)(arp_table[i].p)));
@ -177,55 +198,125 @@ etharp_tmr(void)
} }
/** /**
* Return an empty ARP entry or, if the table is full, ARP_TABLE_SIZE if all * Return an empty ARP entry (possibly recycling the oldest stable entry).
* entries are pending, otherwise the oldest entry.
* *
* @return The ARP entry index that is available, ARP_TABLE_SIZE if no usable * @return The ARP entry index that is available, ERR_MEM if no usable
* entry is found. * entry is found.
*/ */
static u8_t static s8_t
find_arp_entry(void) find_arp_entry(void)
{ {
u8_t i, j, maxtime; s8_t i, j;
u8_t maxtime = 0;
/* Try to find an unused entry in the ARP table. */ j = ARP_TABLE_SIZE;
/* search ARP table for an unused or old entry */
for (i = 0; i < ARP_TABLE_SIZE; ++i) { for (i = 0; i < ARP_TABLE_SIZE; ++i) {
/* empty entry? */
if (arp_table[i].state == ETHARP_STATE_EMPTY) { if (arp_table[i].state == ETHARP_STATE_EMPTY) {
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found empty entry %u\n", i)); LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning empty entry %u\n", i));
break; return i;
/* stable entry? */
} else if (arp_table[i].state == ETHARP_STATE_STABLE) {
/* remember entry with oldest stable entry in j */
if (arp_table[i].ctime >= maxtime) maxtime = arp_table[j = i].ctime;
} }
} }
/* no empty entry found? */
if (i == ARP_TABLE_SIZE) {
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found oldest stable entry %u\n", j));
/* fall-back to oldest stable */
i = j;
}
/* no available entry found? */
if (i == ARP_TABLE_SIZE) {
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: no replacable entry could be found\n"));
/* return failure */
return ERR_MEM;
}
/* If no unused entry is found, we try to find the oldest entry and /* clean up the recycled stable entry */
throw it away. If all entries are new and have 0 ctime drop one */ if (arp_table[i].state == ETHARP_STATE_STABLE) {
if (i == ARP_TABLE_SIZE) { #if ARP_QUEUEING
maxtime = 0; /* free packets on queue */
j = ARP_TABLE_SIZE; etharp_dequeue(i);
for (i = 0; i < ARP_TABLE_SIZE; ++i) {
/* remember entry with oldest stable entry in j*/
if ((arp_table[i].state == ETHARP_STATE_STABLE) &&
#if ARP_QUEUEING /* do not want to re-use an entry with queued packets */
(arp_table[i].p == NULL) &&
#endif #endif
(arp_table[i].ctime >= maxtime)) { LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_arp_entry: recycling oldest stable entry %u\n", i));
maxtime = arp_table[i].ctime; arp_table[i].state = ETHARP_STATE_EMPTY;
j = i; arp_table[i].ctime = 0;
}
}
if (j != ARP_TABLE_SIZE) {
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found oldest stable entry %u\n", j));
} else {
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: no replacable entry could be found\n"));
}
i = j;
} }
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning %u, state %u\n", i, arp_table[i].state)); LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning %u\n", i));
return i; return i;
} }
#if ARP_QUEUEING
/*
* Enqueues a pbuf (chain) on an ARP entry.
*
* Places the pbuf (chain) on the queue (if space allows). The
* caller may safely free the pbuf (chain) afterwards, as the
* pbufs will be referenced by the queue and copies are made of
* pbufs referencing external payloads.
*
* @ i the ARP entry index
* @arg q the pbuf (chain) to be queued on the ARP entry
*
* @return Returns the new head of queue of the ARP entry.
*
*/
static struct pbuf *
etharp_enqueue(s8_t i, struct pbuf *q)
{
/* any pbuf to queue? */
if (q != NULL) {
/* queue later packet over earliers? TODO: Implement multiple pbuf queue */
#if ARP_QUEUE_FIRST == 0
/* remove any pbufs on queue */
u8_t deq = etharp_dequeue(i);
if (deq > 0) LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("etharp_query: dequeued %u pbufs from ARP entry %u. Should not occur.\n", deq, i));
#endif
/* packet can be queued? TODO: Implement multiple pbuf queue */
if (arp_table[i].p == NULL) {
/* copy any PBUF_REF referenced payloads into PBUF_RAM */
q = pbuf_take(q);
/* add pbuf to queue */
arp_table[i].p = q;
/* pbuf (chain) now queued, increase the reference count */
pbuf_ref(q);
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: queued packet %p on ARP entry %u.\n", (void *)q, i));
}
}
return arp_table[i].p;
}
/**
* Dequeues any pbufs queued on an ARP entry
*
* @return number of pbufs removed from the queue
*
* TODO: decide what is a sensible return value?
*/
static u8_t
etharp_dequeue(s8_t i)
{
/* queued packets on a stable entry (work in progress) */
if (arp_table[i].p != NULL) {
/* queue no longer references pbuf */
pbuf_free(arp_table[i].p);
arp_table[i].p = NULL;
return 1;
} else {
return 0;
}
}
#endif
/** /**
* Update (or insert) a IP/MAC address pair in the ARP cache. * 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 ipaddr IP address of the inserted ARP entry.
* @param ethaddr Ethernet address of the inserted ARP entry. * @param ethaddr Ethernet address of the inserted ARP entry.
* @param flags Defines behaviour: * @param flags Defines behaviour:
@ -240,7 +331,7 @@ find_arp_entry(void)
static struct pbuf * static struct pbuf *
update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags) update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)
{ {
u8_t i, k; s8_t i, k;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("update_arp_entry()\n")); LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("update_arp_entry()\n"));
LWIP_ASSERT("netif->hwaddr_len != 0", netif->hwaddr_len != 0); 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), 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),
@ -264,7 +355,7 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
arp_table[i].state = ETHARP_STATE_STABLE; arp_table[i].state = ETHARP_STATE_STABLE;
/* fall-through to next if */ /* fall-through to next if */
} }
/* stable entry? (possible just marked to become stable) */ /* stable entry? (possibly just marked to become stable) */
if (arp_table[i].state == ETHARP_STATE_STABLE) { if (arp_table[i].state == ETHARP_STATE_STABLE) {
#if ARP_QUEUEING #if ARP_QUEUEING
struct pbuf *p; struct pbuf *p;
@ -277,12 +368,25 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
} }
/* reset time stamp */ /* reset time stamp */
arp_table[i].ctime = 0; arp_table[i].ctime = 0;
/* this is where we will send out queued packets! */
#if ARP_QUEUEING #if ARP_QUEUEING
/* get the first packet on the queue (if any) */
p = arp_table[i].p; p = arp_table[i].p;
/* queued packet present? */ /* queued packet present? */
if (p != NULL) { while (p != NULL) {
/* NULL attached buffer immediately */ struct pbuf *q, *n;
arp_table[i].p = NULL; /* search for second packet on queue (n) */
q = p;
while (q->tot_len > q->len) {
/* proceed to next pbuf of this packet */
LWIP_ASSERT("q->next ! NULL", q->next != NULL);
q = q->next;
}
/* { q = last pbuf of first packet, q->tot_len = q->len } */
n = q->next;
/* { n = first pbuf of 2nd packet, or NULL if no 2nd packet } */
/* terminate the first packet pbuf chain */
q->next = NULL;
/* fill-in Ethernet header */ /* fill-in Ethernet header */
ethhdr = p->payload; ethhdr = p->payload;
for (k = 0; k < netif->hwaddr_len; ++k) { for (k = 0; k < netif->hwaddr_len; ++k) {
@ -290,12 +394,16 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
ethhdr->src.addr[k] = netif->hwaddr[k]; ethhdr->src.addr[k] = netif->hwaddr[k];
} }
ethhdr->type = htons(ETHTYPE_IP); ethhdr->type = htons(ETHTYPE_IP);
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet.\n")); LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet %p.\n",(void *)p));
/* send the queued IP packet */ /* send the queued IP packet */
netif->linkoutput(netif, p); netif->linkoutput(netif, p);
/* free the queued IP packet */ /* free the queued IP packet */
pbuf_free(p); pbuf_free(p);
/* proceed to next packet on queue */
p = n;
} }
/* NULL attached buffer*/
arp_table[i].p = NULL;
#endif #endif
return NULL; return NULL;
} }
@ -312,21 +420,10 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: adding entry to table\n")); LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: adding entry to table\n"));
/* find an empty or old entry. */ /* find an empty or old entry. */
i = find_arp_entry(); i = find_arp_entry();
if (i == ARP_TABLE_SIZE) { if (i == ERR_MEM) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no available entry found\n")); LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no available entry found\n"));
return NULL; 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) {
LWIP_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 {
LWIP_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 */ /* set IP address */
ip_addr_set(&arp_table[i].ipaddr, ipaddr); ip_addr_set(&arp_table[i].ipaddr, ipaddr);
/* set Ethernet hardware address */ /* set Ethernet hardware address */
@ -350,7 +447,7 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
} }
/** /**
* Updates the ARP table using the given packet. * Updates the ARP table using the given IP packet.
* *
* Uses the incoming IP packet's source address to update the * Uses the incoming IP packet's source address to update the
* ARP cache for the local network. The function does not alter * ARP cache for the local network. The function does not alter
@ -512,10 +609,10 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
* This ARP request is returned as a pbuf, which should be sent by * This ARP request is returned as a pbuf, which should be sent by
* the caller. * the caller.
* *
* If ARP failed to allocate resources, NULL is returned.
*
* A returned non-NULL packet should be sent by the caller. * A returned non-NULL packet should be sent by the caller.
* *
* If ARP failed to allocate resources, NULL is returned.
*
* @param netif The lwIP network interface which the IP packet will be sent on. * @param netif The lwIP network interface which the IP packet will be sent on.
* @param ipaddr The IP address of the packet destination. * @param ipaddr The IP address of the packet destination.
* @param pbuf The pbuf(s) containing the IP packet to be sent. * @param pbuf The pbuf(s) containing the IP packet to be sent.
@ -528,9 +625,9 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
{ {
struct eth_addr *dest, *srcaddr, mcastaddr; struct eth_addr *dest, *srcaddr, mcastaddr;
struct eth_hdr *ethhdr; struct eth_hdr *ethhdr;
u8_t i; s8_t i;
/* Make room for Ethernet header. */ /* make room for Ethernet header */
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
/* The pbuf_header() call shouldn't fail, and we'll just bail /* The pbuf_header() call shouldn't fail, and we'll just bail
out if it does.. */ out if it does.. */
@ -539,9 +636,6 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
return NULL; return NULL;
} }
/* obtain source Ethernet address of the given interface */
srcaddr = (struct eth_addr *)netif->hwaddr;
/* assume unresolved Ethernet address */ /* assume unresolved Ethernet address */
dest = NULL; dest = NULL;
/* Construct Ethernet header. Start with looking up deciding which /* Construct Ethernet header. Start with looking up deciding which
@ -569,19 +663,20 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
} }
/* destination IP address is an IP unicast address */ /* destination IP address is an IP unicast address */
else { else {
/* destination IP network address not on local network? */ /* destination IP network address not on local network?
/* this occurs if the packet is routed to the default gateway on this interface */ * IP layer wants us to forward to the default gateway */
if (!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { if (!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {
/* gateway available? */ /* interface has default gateway? */
if (netif->gw.addr != 0) if (netif->gw.addr != 0)
{ {
/* use the gateway IP address */ /* route to default gateway IP address */
ipaddr = &(netif->gw); ipaddr = &(netif->gw);
} }
/* no gateway available? */ /* no gateway available? */
else else
{ {
/* IP destination address outside local network, but no gateway available */ /* IP destination address outside local network, but no gateway available */
/* { packet is discarded } */
return NULL; return NULL;
} }
} }
@ -600,6 +695,7 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
/* ARP query for the IP address, submit this IP packet for queueing */ /* ARP query for the IP address, submit this IP packet for queueing */
/* TODO: How do we handle netif->ipaddr == ipaddr? */ /* TODO: How do we handle netif->ipaddr == ipaddr? */
etharp_query(netif, ipaddr, q); etharp_query(netif, ipaddr, q);
/* { packet was queued (ERR_OK), or discarded } */
/* return nothing */ /* return nothing */
return NULL; return NULL;
} }
@ -612,8 +708,11 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
/* destination Ethernet address known */ /* destination Ethernet address known */
if (dest != NULL) { if (dest != NULL) {
/* A valid IP->MAC address mapping was found, so we construct the /* obtain source Ethernet address of the given interface */
Ethernet header for the outgoing packet. */ 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; ethhdr = q->payload;
for(i = 0; i < netif->hwaddr_len; i++) { for(i = 0; i < netif->hwaddr_len; i++) {
@ -654,9 +753,8 @@ err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
{ {
struct eth_addr *srcaddr; struct eth_addr *srcaddr;
struct etharp_hdr *hdr; struct etharp_hdr *hdr;
struct pbuf *p;
err_t result = ERR_OK; err_t result = ERR_OK;
u8_t i; s8_t i;
u8_t perform_arp_request = 1; u8_t perform_arp_request = 1;
/* prevent 'unused argument' warning if ARP_QUEUEING == 0 */ /* prevent 'unused argument' warning if ARP_QUEUEING == 0 */
(void)q; (void)q;
@ -666,7 +764,7 @@ err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
if (ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { if (ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
if (arp_table[i].state == ETHARP_STATE_PENDING) { 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)); 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 stable entry */ /* 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 */ /* 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 */ /* we might want to run a faster timer on ARP to limit this */
break; break;
@ -683,56 +781,26 @@ err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
/* queried address not yet in ARP table? */ /* queried address not yet in ARP table? */
if (i == ARP_TABLE_SIZE) { if (i == ARP_TABLE_SIZE) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: IP address not found in ARP table\n")); LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: IP address not found in ARP table\n"));
/* find an available entry */ /* find an available (unused or old) entry */
i = find_arp_entry(); i = find_arp_entry();
/* bail out if no ARP entries are available */ /* bail out if no ARP entries are available */
if (i == ARP_TABLE_SIZE) { if (i == ERR_MEM) {
LWIP_DEBUGF(ETHARP_DEBUG | 2, ("etharp_query: no more ARP entries available.\n")); LWIP_DEBUGF(ETHARP_DEBUG | 2, ("etharp_query: no more ARP entries available. Should seldom occur.\n"));
return ERR_MEM; return ERR_MEM;
} }
/* we will now recycle entry i */
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: created ARP table entry %u.\n", i));
/* i is available, create ARP entry */ /* 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; arp_table[i].state = ETHARP_STATE_PENDING;
ip_addr_set(&arp_table[i].ipaddr, ipaddr);
/* queried address was already in ARP table */
} else {
#if ARP_QUEUEING #if ARP_QUEUEING
/* free queued packet, as entry is now invalidated */ etharp_enqueue(i, q);
if (arp_table[i].p != NULL) {
pbuf_free(arp_table[i].p);
arp_table[i].p = NULL;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("etharp_query: dropped packet on ARP queue. Should not occur.\n"));
}
#endif #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;
LWIP_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);
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: queued packet %p on ARP entry %u.\n", (void *)q, i));
}
}
#endif
/* ARP request? */ /* ARP request? */
if (perform_arp_request) if (perform_arp_request)
{ {
struct pbuf *p;
/* allocate a pbuf for the outgoing ARP request packet */ /* allocate a pbuf for the outgoing ARP request packet */
p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM); p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);
/* could allocate pbuf? */ /* could allocate pbuf? */

View File

@ -153,7 +153,7 @@ typedef struct PPPControl_s {
struct vjcompress vjComp; /* Van Jabobsen compression header. */ struct vjcompress vjComp; /* Van Jabobsen compression header. */
#endif #endif
struct netif *netif; struct netif netif;
struct ppp_addrs addrs; struct ppp_addrs addrs;
@ -296,7 +296,6 @@ void pppInit(void)
for (i = 0; i < NUM_PPP; i++) { for (i = 0; i < NUM_PPP; i++) {
pppControl[i].openFlag = 0; pppControl[i].openFlag = 0;
pppControl[i].netif = NULL;
subnetMask = htonl(0xffffff00); subnetMask = htonl(0xffffff00);
@ -537,14 +536,14 @@ static struct pbuf *pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)
/* Send a packet on the given connection. */ /* Send a packet on the given connection. */
static err_t pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr) static err_t pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr)
{ {
int pd = (int)netif->state; int pd = (int)netif->state;
u_short protocol = PPP_IP; u_short protocol = PPP_IP;
PPPControl *pc = &pppControl[pd]; PPPControl *pc = &pppControl[pd];
u_int fcsOut = PPP_INITFCS; u_int fcsOut = PPP_INITFCS;
struct pbuf *headMB = NULL, *tailMB = NULL, *p; struct pbuf *headMB = NULL, *tailMB = NULL, *p;
u_char c; u_char c;
(void)ipaddr; (void)ipaddr;
/* Validate parameters. */ /* Validate parameters. */
/* We let any protocol value go through - it can't hurt us /* We let any protocol value go through - it can't hurt us
@ -1003,12 +1002,10 @@ int sifup(int pd)
st = 0; st = 0;
PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
} else { } else {
if(pc->netif) netif_remove(&pc->netif);
netif_remove(pc->netif); if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask, &pc->addrs.his_ipaddr, (void *)pd, pppifNetifInit, ip_input)) {
pc->netif = netif_add(&pc->addrs.our_ipaddr, &pc->addrs.netmask, &pc->addrs.his_ipaddr, (void *)pd, pppifNetifInit, ip_input); pc->if_up = 1;
if(pc->netif) { pc->errCode = PPPERR_NONE;
pc->if_up = 1;
pc->errCode = PPPERR_NONE;
PPPDEBUG((LOG_DEBUG, "sifup: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); PPPDEBUG((LOG_DEBUG, "sifup: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
if(pc->linkStatusCB) if(pc->linkStatusCB)
@ -1046,12 +1043,10 @@ int sifdown(int pd)
PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd)); PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd));
} else { } else {
pc->if_up = 0; pc->if_up = 0;
if(pc->netif) netif_remove(&pc->netif);
netif_remove(pc->netif); PPPDEBUG((LOG_DEBUG, "sifdown: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
pc->netif = NULL; if(pc->linkStatusCB)
PPPDEBUG((LOG_DEBUG, "sifdown: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);
if(pc->linkStatusCB)
pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);
} }
return st; return st;
} }
@ -1126,7 +1121,7 @@ int sifdefaultroute(int pd, u32_t l, u32_t g)
st = 0; st = 0;
PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
} else { } else {
netif_set_default(pc->netif); netif_set_default(&pc->netif);
} }
/* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */ /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */
@ -1324,7 +1319,7 @@ static void pppInput(void *arg)
* pass the result to IP. * pass the result to IP.
*/ */
if (vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) { if (vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) {
pppControl[pd].netif->input(nb, pppControl[pd].netif); pppControl[pd].netif.input(nb, &pppControl[pd].netif);
return; return;
} }
/* Something's wrong so drop it. */ /* Something's wrong so drop it. */
@ -1342,7 +1337,7 @@ static void pppInput(void *arg)
* the packet to IP. * the packet to IP.
*/ */
if (vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) { if (vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) {
pppControl[pd].netif->input(nb, pppControl[pd].netif); pppControl[pd].netif.input(nb, &pppControl[pd].netif);
return; return;
} }
/* Something's wrong so drop it. */ /* Something's wrong so drop it. */
@ -1356,7 +1351,7 @@ static void pppInput(void *arg)
break; break;
case PPP_IP: /* Internet Protocol */ case PPP_IP: /* Internet Protocol */
PPPDEBUG((LOG_INFO, "pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len)); PPPDEBUG((LOG_INFO, "pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));
pppControl[pd].netif->input(nb, pppControl[pd].netif); pppControl[pd].netif.input(nb, &pppControl[pd].netif);
return; return;
default: default:
{ {