switch from lwip-1.3.2 to lwip 1.4.0

This commit is contained in:
Stefan Lankes 2011-05-29 15:36:02 +02:00
parent 3ff984a21c
commit fdeceeac36
128 changed files with 13206 additions and 7913 deletions

1
.gitignore vendored
View file

@ -10,7 +10,6 @@
*.DS_Store
tags
include/metalsvm/config.h
Makefile
tools/make_initrd
newlib/examples/hello
newlib/examples/echo

View file

@ -40,10 +40,10 @@
*
*/
#include <metalsvm/stddef.h>
#include <metalsvm/stdio.h>
#if defined(CONFIG_LWIP)
#include <lwip/debug.h>
#include <lwip/stats.h>
#include <lwip/tcp.h>
@ -109,10 +109,13 @@ echo_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
err_t ret_err;
struct echo_state *es;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
/* commonly observed practive to call tcp_setprio(), why? */
tcp_setprio(newpcb, TCP_PRIO_MIN);
es = mem_malloc(sizeof(struct echo_state));
es = (struct echo_state *)mem_malloc(sizeof(struct echo_state));
if (es != NULL)
{
es->state = ES_ACCEPTED;
@ -140,7 +143,7 @@ echo_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
err_t ret_err;
LWIP_ASSERT("arg != NULL",arg != NULL);
es = arg;
es = (struct echo_state *)arg;
if (p == NULL)
{
/* remote host closed connection */
@ -222,7 +225,9 @@ echo_error(void *arg, err_t err)
{
struct echo_state *es;
es = arg;
LWIP_UNUSED_ARG(err);
es = (struct echo_state *)arg;
if (es != NULL)
{
mem_free(es);
@ -235,7 +240,7 @@ echo_poll(void *arg, struct tcp_pcb *tpcb)
err_t ret_err;
struct echo_state *es;
es = arg;
es = (struct echo_state *)arg;
if (es != NULL)
{
if (es->p != NULL)
@ -246,7 +251,7 @@ echo_poll(void *arg, struct tcp_pcb *tpcb)
}
else
{
/* no remaining pbuf (chain) */
/* no remaining pbuf (chain) */
if(es->state == ES_CLOSING)
{
echo_close(tpcb, es);
@ -268,7 +273,9 @@ echo_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
struct echo_state *es;
es = arg;
LWIP_UNUSED_ARG(len);
es = (struct echo_state *)arg;
es->retries = 0;
if(es->p != NULL)

View file

@ -33,6 +33,7 @@
#include <lwip/tcp.h>
#include <lwip/dhcp.h>
#include <lwip/netif.h>
#include <lwip/timers.h>
#include <netif/etharp.h>
#endif
#include <net/rtl8139.h>
@ -94,7 +95,7 @@ int STDCALL network_task(void* arg)
// start echo and ping server
echo_init();
ping_init();
//ping_init();
while(!done) {
rtl8139if_wait(&netif, 0);
@ -117,6 +118,7 @@ int network_shutdown(void)
int network_init(void)
{
#if defined(CONFIG_LWIP)
// Initialize lwIP modules
lwip_init();
#endif

View file

@ -43,16 +43,21 @@
#include <metalsvm/processor.h>
#include <lwip/opt.h>
#if LWIP_RAW && LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
#include <lwip/mem.h>
#include <lwip/raw.h>
#include <lwip/icmp.h>
#include <lwip/netif.h>
#include <lwip/sys.h>
#include <lwip/timers.h>
#include <lwip/inet_chksum.h>
#if PING_USE_SOCKETS
#include <lwip/sockets.h>
#include <lwip/inet.h>
#include <lwip/inet_chksum.h>
#endif /* PING_USE_SOCKETS */
/**
* PING_DEBUG: Enable debugging for PING.
@ -61,7 +66,7 @@
#define PING_DEBUG LWIP_DBG_ON
#endif
/** ping target - should be a "struct ip_addr" */
/** ping target - should be a "ip_addr_t" */
#ifndef PING_TARGET
#define PING_TARGET (netif_default?netif_default->gw:ip_addr_any)
#endif
@ -94,67 +99,53 @@
/* ping variables */
static u16_t ping_seq_num;
static u32_t ping_time;
#if NO_SYS
/* port-defined functions used for timer execution */
//void sys_msleep(u32_t ms);
inline u32_t sys_now(void)
{
static uint64_t start = 0;
uint64_t end;
uint64_t tmp;
if (start == 0)
start = rdtsc();
end = rdtsc();
tmp = (end > start) ? end - start : start - end;
return (u32_t) ((tmp * 1000) / get_cpu_frequency());
}
#endif /* NO_SYS */
#if !PING_USE_SOCKETS
static struct raw_pcb *ping_pcb;
#endif /* PING_USE_SOCKETS */
/** Prepare a echo ICMP request */
static void
ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len)
{
int i;
size_t i;
size_t data_len = len - sizeof(struct icmp_echo_hdr);
ICMPH_TYPE_SET(iecho,ICMP_ECHO);
ICMPH_TYPE_SET(iecho, ICMP_ECHO);
ICMPH_CODE_SET(iecho, 0);
iecho->chksum = 0;
iecho->id = PING_ID;
iecho->seqno = htons(++ping_seq_num);
iecho->chksum = inet_chksum(iecho, len);
/* fill the additional data buffer with some data */
for(i = 0; i < PING_DATA_SIZE; i++) {
((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = i;
for(i = 0; i < data_len; i++) {
((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;
}
iecho->chksum = inet_chksum(iecho, len);
}
#if LWIP_SOCKET
#if PING_USE_SOCKETS
/* Ping using the socket ip */
static err_t
ping_send(int s, struct ip_addr *addr)
ping_send(int s, ip_addr_t *addr)
{
int err;
struct icmp_echo_hdr *iecho;
struct sockaddr_in to;
size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;
LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff);
if (!(iecho = mem_malloc(ping_size))) {
iecho = (struct icmp_echo_hdr *)mem_malloc((mem_size_t)ping_size);
if (!iecho) {
return ERR_MEM;
}
ping_prepare_echo(iecho, ping_size);
ping_prepare_echo(iecho, (u16_t)ping_size);
to.sin_len = sizeof(to);
to.sin_family = AF_INET;
to.sin_addr.s_addr = addr->addr;
inet_addr_from_ipaddr(&to.sin_addr, addr);
err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to));
@ -173,13 +164,15 @@ ping_recv(int s)
struct icmp_echo_hdr *iecho;
while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0) {
if (len >= (sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr))) {
if (len >= (int)(sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr))) {
ip_addr_t fromaddr;
inet_addr_to_ipaddr(&fromaddr, &from.sin_addr);
LWIP_DEBUGF( PING_DEBUG, ("ping: recv "));
ip_addr_debug_print(PING_DEBUG, (struct ip_addr *)&(from.sin_addr));
LWIP_DEBUGF( PING_DEBUG, (" %lu ms\n", (sys_now()-ping_time)));
ip_addr_debug_print(PING_DEBUG, &fromaddr);
LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now() - ping_time)));
iphdr = (struct ip_hdr *)buf;
iecho = (struct icmp_echo_hdr *)(buf+(IPH_HL(iphdr) * 4));
iecho = (struct icmp_echo_hdr *)(buf + (IPH_HL(iphdr) * 4));
if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) {
/* do some ping result processing */
PING_RESULT((ICMPH_TYPE(iecho) == ICMP_ER));
@ -191,7 +184,7 @@ ping_recv(int s)
}
if (len == 0) {
LWIP_DEBUGF( PING_DEBUG, ("ping: recv - %lu ms - timeout\n", (sys_now()-ping_time)));
LWIP_DEBUGF( PING_DEBUG, ("ping: recv - %"U32_F" ms - timeout\n", (sys_now()-ping_time)));
}
/* do some ping result processing */
@ -203,7 +196,7 @@ ping_thread(void *arg)
{
int s;
int timeout = PING_RCV_TIMEO;
struct ip_addr ping_target;
ip_addr_t ping_target;
LWIP_UNUSED_ARG(arg);
@ -232,44 +225,56 @@ ping_thread(void *arg)
}
}
#else /* LWIP_SOCKET */
#else /* PING_USE_SOCKETS */
/* Ping using the raw ip */
static u8_t
ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *addr)
ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr)
{
struct icmp_echo_hdr *iecho;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(pcb);
LWIP_UNUSED_ARG(addr);
LWIP_ASSERT("p != NULL", p != NULL);
if (pbuf_header( p, -PBUF_IP_HLEN)==0) {
iecho = p->payload;
iecho = (struct icmp_echo_hdr *)p->payload;
if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) {
LWIP_DEBUGF( PING_DEBUG, ("ping: recv "));
ip_addr_debug_print(PING_DEBUG, addr);
LWIP_DEBUGF( PING_DEBUG, (" %lu ms\n", (sys_now()-ping_time)));
LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now()-ping_time)));
/* do some ping result processing */
PING_RESULT(1);
pbuf_free(p);
return 1; /* eat the packet */
}
}
return 1; /* eat the event */
return 0; /* don't eat the packet */
}
static void
ping_send(struct raw_pcb *raw, struct ip_addr *addr)
ping_send(struct raw_pcb *raw, ip_addr_t *addr)
{
struct pbuf *p;
struct icmp_echo_hdr *iecho;
size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;
if (!(p = pbuf_alloc(PBUF_IP, ping_size, PBUF_RAM))) {
LWIP_DEBUGF( PING_DEBUG, ("ping: send "));
ip_addr_debug_print(PING_DEBUG, addr);
LWIP_DEBUGF( PING_DEBUG, ("\n"));
LWIP_ASSERT("ping_size <= 0xffff", ping_size <= 0xffff);
p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM);
if (!p) {
return;
}
if ((p->len == p->tot_len) && (p->next == NULL)) {
iecho = p->payload;
iecho = (struct icmp_echo_hdr *)p->payload;
ping_prepare_echo(iecho, ping_size);
ping_prepare_echo(iecho, (u16_t)ping_size);
raw_sendto(raw, p, addr);
ping_time = sys_now();
@ -281,14 +286,10 @@ static void
ping_timeout(void *arg)
{
struct raw_pcb *pcb = (struct raw_pcb*)arg;
struct ip_addr ping_target = PING_TARGET;
ip_addr_t ping_target = PING_TARGET;
LWIP_ASSERT("ping_timeout: no pcb given!", pcb != NULL);
LWIP_DEBUGF( PING_DEBUG, ("ping: send "));
ip_addr_debug_print(PING_DEBUG, &ping_target);
LWIP_DEBUGF( PING_DEBUG, ("\n"));
ping_send(pcb, &ping_target);
sys_timeout(PING_DELAY, ping_timeout, pcb);
@ -297,28 +298,32 @@ ping_timeout(void *arg)
static void
ping_raw_init(void)
{
struct raw_pcb *pcb;
ping_pcb = raw_new(IP_PROTO_ICMP);
LWIP_ASSERT("ping_pcb != NULL", ping_pcb != NULL);
if (!(pcb = raw_new(IP_PROTO_ICMP))) {
LWIP_DEBUGF( PING_DEBUG, ("ping: raw_new failed!"));
return;
}
raw_recv(pcb, ping_recv, NULL);
raw_bind(pcb, IP_ADDR_ANY);
sys_timeout(PING_DELAY, ping_timeout, pcb);
raw_recv(ping_pcb, ping_recv, NULL);
raw_bind(ping_pcb, IP_ADDR_ANY);
sys_timeout(PING_DELAY, ping_timeout, ping_pcb);
}
#endif /* LWIP_SOCKET */
void
ping_send_now()
{
ip_addr_t ping_target = PING_TARGET;
LWIP_ASSERT("ping_pcb != NULL", ping_pcb != NULL);
ping_send(ping_pcb, &ping_target);
}
#endif /* PING_USE_SOCKETS */
void
ping_init(void)
{
#if LWIP_SOCKET
#if PING_USE_SOCKETS
sys_thread_new("ping_thread", ping_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
#else /* LWIP_SOCKET */
#else /* PING_USE_SOCKETS */
ping_raw_init();
#endif /* LWIP_SOCKET */
#endif /* PING_USE_SOCKETS */
}
#endif /* LWIP_RAW && LWIP_ICMP */
#endif /* LWIP_RAW */

View file

@ -1,27 +1,658 @@
FUTURE
* TODO: The lwIP source code makes some invalid assumptions on processor
word-length, storage sizes and alignment. See the mailing lists for
problems with exoteric (/DSP) architectures showing these problems.
We still have to fix some of these issues neatly.
* TODO: the PPP code is broken in a few ways. There are namespace
collisions on BSD systems and many assumptions on word-length
(sizeof(int)). In ppp.c an assumption is made on the availability of
a thread subsystem. Either PPP needs to be moved to contrib/ports/???
or rearranged to be more generic.
HISTORY
(CVS HEAD)
* [Enter new changes just after this line - do not remove this line]
++ New features:
++ Bugfixes:
(STABLE-1.4.0)
++ New features:
2011-03-27: Simon Goldschmidt
* tcp_impl.h, tcp_in.c, tcp_out.c: Removed 'dataptr' from 'struct tcp_seg' and
calculate it in tcp_zero_window_probe (the only place where it was used).
2010-11-21: Simon Goldschmidt
* dhcp.c/.h: Added a function to deallocate the struct dhcp from a netif
(fixes bug #31525).
2010-07-12: Simon Goldschmidt (patch by Stephane Lesage)
* ip.c, udp.c/.h, pbuf.h, sockets.c: task #10495: Added support for
IP_MULTICAST_LOOP at socket- and raw-API level.
2010-06-16: Simon Goldschmidt
* ip.c: Added an optional define (LWIP_IP_ACCEPT_UDP_PORT) that can allow
link-layer-addressed UDP traffic to be received while a netif is down (just
like DHCP during configuration)
2010-05-22: Simon Goldschmidt
* many many files: bug #27352: removed packing from ip_addr_t, the packed
version is now only used in protocol headers. Added global storage for
current src/dest IP address while in input functions.
2010-05-16: Simon Goldschmidt
* def.h: task #10391: Add preprocessor-macros for compile-time htonl
calculation (and use them throughout the stack where applicable)
2010-05-16: Simon Goldschmidt
* opt.h, memp_std.h, memp.c, ppp_oe.h/.c: PPPoE now uses its own MEMP pool
instead of the heap (moved struct pppoe_softc from ppp_oe.c to ppp_oe.h)
2010-05-16: Simon Goldschmidt
* opt.h, memp_std.h, dns.h/.c: DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses its own
MEMP pool instead of the heap
2010-05-13: Simon Goldschmidt
* tcp.c, udp.c: task #6995: Implement SO_REUSEADDR (correctly), added
new option SO_REUSE_RXTOALL to pass received UDP broadcast/multicast
packets to more than one pcb.
2010-05-02: Simon Goldschmidt
* netbuf.h/.c, sockets.c, api_msg.c: use checksum-on-copy for sending
UDP data for LWIP_NETIF_TX_SINGLE_PBUF==1
2010-04-30: Simon Goldschmidt
* udp.h/.c, pbuf.h/.c: task #6849: added udp_send(_to/_if) functions that
take a precalculated checksum, added pbuf_fill_chksum() to copy data
into a pbuf and at the same time calculating the checksum for that data
2010-04-29: Simon Goldschmidt
* ip_addr.h, etharp.h/.c, autoip.c: Create overridable macros for copying
2-byte-aligned IP addresses and MAC addresses
2010-04-28: Patch by Bill Auerbach
* ip.c: Inline generating IP checksum to save a function call
2010-04-14: Simon Goldschmidt
* tcpip.h/.c, timers.c: Added an overridable define to get informed when the
tcpip_thread processes messages or timeouts to implement a watchdog.
2010-03-28: Simon Goldschmidt
* ip_frag.c: create a new (contiguous) PBUF_RAM for every outgoing
fragment if LWIP_NETIF_TX_SINGLE_PBUF==1
2010-03-27: Simon Goldschmidt
* etharp.c: Speedup TX by moving code from find_entry to etharp_output/
etharp_query to prevent unnecessary function calls (inspired by
patch #7135).
2010-03-20: Simon Goldschmidt
* opt.h, tcpip.c/.h: Added an option to disable tcpip_(un)timeout code
since the linker cannot do this automatically to save space.
2010-03-20: Simon Goldschmidt
* opt.h, etharp.c/.h: Added support for static ARP table entries
2010-03-14: Simon Goldschmidt
* tcp_impl.h, tcp_out.c, inet_chksum.h/.c: task #6849: Calculate checksum
when creating TCP segments, not when (re-)transmitting them.
2010-03-07: Simon Goldschmidt
* sockets.c: bug #28775 (select/event_callback: only check select_cb_list
on change) plus use SYS_LIGHTWEIGHT_PROT to protect the select code.
This should speed up receiving data on sockets as the select code in
event_callback is only executed when select is waiting.
2010-03-06: Simon Goldschmidt
* tcp_out.c: task #7013 (Create option to have all packets delivered to
netif->output in one piece): Always copy to try to create single pbufs
in tcp_write.
2010-03-06: Simon Goldschmidt
* api.h, api_lib.c, sockets.c: task #10167 (sockets: speed up TCP recv
by not allocating a netbuf): added function netconn_recv_tcp_pbuf()
for tcp netconns to receive pbufs, not netbufs; use that function
for tcp sockets.
2010-03-05: Jakob Ole Stoklundsen / Simon Goldschmidt
* opt.h, tcp.h, tcp_impl.h, tcp.c, tcp_in.c, tcp_out.c: task #7040:
Work on tcp_enqueue: Don't waste memory when chaining segments,
added option TCP_OVERSIZE to prevent creating many small pbufs when
calling tcp_write with many small blocks of data. Instead, pbufs are
allocated larger than needed and the space is used for later calls to
tcp_write.
2010-02-21: Simon Goldschmidt
* stats.c/.h: Added const char* name to mem- and memp-stats for easier
debugging.
2010-02-21: Simon Goldschmidt
* tcp.h (and usages), added tcp_impl.h: Splitted API and internal
implementation of tcp to make API usage cleare to application programmers
2010-02-14: Simon Goldschmidt/Stephane Lesage
* ip_addr.h: Improved some defines working on ip addresses, added faster
macro to copy addresses that cannot be NULL
2010-02-13: Simon Goldschmidt
* api.h, api_lib.c, api_msg.c, sockets.c: task #7865 (implement non-
blocking send operation)
2010-02-12: Simon Goldschmidt
* sockets.c/.h: Added a minimal version of posix fctl() to have a
standardised way to set O_NONBLOCK for nonblocking sockets.
2010-02-12: Simon Goldschmidt
* dhcp.c/.h, autoip.c/.h: task #10139 (Prefer statically allocated
memory): added autoip_set_struct() and dhcp_set_struct() to let autoip
and dhcp work with user-allocated structs instead of callin mem_malloc
2010-02-12: Simon Goldschmidt/Jeff Barber
* tcp.c/h: patch #6865 (SO_REUSEADDR for TCP): if pcb.so_options has
SOF_REUSEADDR set, allow binding to endpoint in TIME_WAIT
2010-02-12: Simon Goldschmidt
* sys layer: task #10139 (Prefer statically allocated memory): converted
mbox and semaphore functions to take pointers to sys_mbox_t/sys_sem_t;
converted sys_mbox_new/sys_sem_new to take pointers and return err_t;
task #7212: Add Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX
to let sys.h use binary semaphores instead of mutexes - as before)
2010-02-09: Simon Goldschmidt (Simon Kallweit)
* timers.c/.h: Added function sys_restart_timeouts() from patch #7085
(Restart system timeout handling)
2010-02-09: Simon Goldschmidt
* netif.c/.h, removed loopif.c/.h: task #10153 (Integrate loopif into
netif.c) - loopif does not have to be created by the port any more,
just define LWIP_HAVE_LOOPIF to 1.
2010-02-08: Simon Goldschmidt
* inet.h, ip_addr.c/.h: Added reentrant versions of inet_ntoa/ipaddr_ntoa
inet_ntoa_r/ipaddr_ntoa_r
2010-02-08: Simon Goldschmidt
* netif.h: Added netif_s/get_igmp_mac_filter() macros
2010-02-05: Simon Goldschmidt
* netif.h: Added function-like macros to get/set the hostname on a netif
2010-02-04: Simon Goldschmidt
* nearly every file: Replaced struct ip_addr by typedef ip_addr_t to
make changing the actual implementation behind the typedef easier.
2010-02-01: Simon Goldschmidt
* opt.h, memp_std.h, dns.h, netdb.c, memp.c: Let netdb use a memp pool
for allocating memory when getaddrinfo() is called.
2010-01-31: Simon Goldschmidt
* dhcp.h, dhcp.c: Reworked the code that parses DHCP options: parse
them once instead of parsing for every option. This also removes
the need for mem_malloc from dhcp_recv and makes it possible to
correctly retrieve the BOOTP file.
2010-01-30: simon Goldschmidt
* sockets.c: Use SYS_LIGHTWEIGHT_PROT instead of a semaphore to protect
the sockets array.
2010-01-29: Simon Goldschmidt (patch by Laura Garrett)
* api.h, api_msg.c, sockets.c: Added except set support in select
(patch #6860)
2010-01-29: Simon Goldschmidt (patch by Laura Garrett)
* api.h, sockets.h, err.h, api_lib.c, api_msg.c, sockets.c, err.c:
Add non-blocking support for connect (partly from patch #6860),
plus many cleanups in socket & netconn API.
2010-01-27: Simon Goldschmidt
* opt.h, tcp.h, init.c, api_msg.c: Added TCP_SNDQUEUELOWAT corresponding
to TCP_SNDLOWAT and added tcp_sndqueuelen() - this fixes bug #28605
2010-01-26: Simon Goldschmidt
* snmp: Use memp pools for snmp instead of the heap; added 4 new pools.
2010-01-14: Simon Goldschmidt
* ppp.c/.h: Fixed bug #27856: PPP: Set netif link- and status-callback
by adding ppp_set_netif_statuscallback()/ppp_set_netif_linkcallback()
2010-01-13: Simon Goldschmidt
* mem.c: The heap now may be moved to user-defined memory by defining
LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address
(patch #6966 and bug #26133)
2010-01-10: Simon Goldschmidt (Bill Auerbach)
* opt.h, memp.c: patch #6822 (Add option to place memory pools in
separate arrays)
2010-01-10: Simon Goldschmidt
* init.c, igmp.c: patch #6463 (IGMP - Adding Random Delay): added define
LWIP_RAND() for lwip-wide randomization (to be defined in cc.h)
2009-12-31: Simon Goldschmidt
* tcpip.c, init.c, memp.c, sys.c, memp_std.h, sys.h, tcpip.h
added timers.c/.h: Separated timer implementation from semaphore/mbox
implementation, moved timer implementation to timers.c/.h, timers are
now only called from tcpip_thread or by explicitly checking them.
(TASK#7235)
2009-12-27: Simon Goldschmidt
* opt.h, etharp.h/.c, init.c, tcpip.c: Added an additional option
LWIP_ETHERNET to support ethernet without ARP (necessary for pure PPPoE)
++ Bugfixes:
2011-04-20: Simon Goldschmidt
* sys_arch.txt: sys_arch_timeouts() is not needed any more.
2011-04-13: Simon Goldschmidt
* tcp.c, udp.c: Fixed bug #33048 (Bad range for IP source port numbers) by
using ports in the IANA private/dynamic range (49152 through 65535).
2011-03-29: Simon Goldschmidt, patch by Emil Lhungdahl:
* etharp.h/.c: Fixed broken VLAN support.
2011-03-27: Simon Goldschmidt
* tcp.c: Fixed bug #32926 (TCP_RMV(&tcp_bound_pcbs) is called on unbound tcp
pcbs) by checking if the pcb was bound (local_port != 0).
2011-03-27: Simon Goldschmidt
* ppp.c: Fixed bug #32280 (ppp: a pbuf is freed twice)
2011-03-27: Simon Goldschmidt
* sockets.c: Fixed bug #32906: lwip_connect+lwip_send did not work for udp and
raw pcbs with LWIP_TCPIP_CORE_LOCKING==1.
2011-03-27: Simon Goldschmidt
* tcp_out.c: Fixed bug #32820 (Outgoing TCP connections created before route
is present never times out) by starting retransmission timer before checking
route.
2011-03-22: Simon Goldschmidt
* ppp.c: Fixed bug #32648 (PPP code crashes when terminating a link) by only
calling sio_read_abort() if the file descriptor is valid.
2011-03-14: Simon Goldschmidt
* err.h/.c, sockets.c, api_msg.c: fixed bug #31748 (Calling non-blocking connect
more than once can render a socket useless) since it mainly involves changing
"FATAL" classification of error codes: ERR_USE and ERR_ISCONN just aren't fatal.
2011-03-13: Simon Goldschmidt
* sockets.c: fixed bug #32769 (ESHUTDOWN is linux-specific) by fixing
err_to_errno_table (ERR_CLSD: ENOTCONN instead of ESHUTDOWN), ERR_ISCONN:
use EALRADY instead of -1
2011-03-13: Simon Goldschmidt
* api_lib.c: netconn_accept: return ERR_ABRT instead of ERR_CLSD if the
connection has been aborted by err_tcp (since this is not a normal closing
procedure).
2011-03-13: Simon Goldschmidt
* tcp.c: tcp_bind: return ERR_VAL instead of ERR_ISCONN when trying to bind
with pcb->state != CLOSED
2011-02-17: Simon Goldschmidt
* rawapi.txt: Fixed bug #32561 tcp_poll argument definition out-of-order in
documentation
2011-02-17: Simon Goldschmidt
* many files: Added missing U/UL modifiers to fix 16-bit-arch portability.
2011-01-24: Simon Goldschmidt
* sockets.c: Fixed bug #31741: lwip_select seems to have threading problems
2010-12-02: Simon Goldschmidt
* err.h: Fixed ERR_IS_FATAL so that ERR_WOULDBLOCK is not fatal.
2010-11-23: Simon Goldschmidt
* api.h, api_lib.c, api_msg.c, sockets.c: netconn.recv_avail is only used for
LWIP_SO_RCVBUF and ioctl/FIONREAD.
2010-11-23: Simon Goldschmidt
* etharp.c: Fixed bug #31720: ARP-queueing: RFC 1122 recommends to queue at
least 1 packet -> ARP_QUEUEING==0 now queues the most recent packet.
2010-11-23: Simon Goldschmidt
* tcp_in.c: Fixed bug #30577: tcp_input: don't discard ACK-only packets after
refusing 'refused_data' again.
2010-11-22: Simon Goldschmidt
* sockets.c: Fixed bug #31590: getsockopt(... SO_ERROR ...) gives EINPROGRESS
after a successful nonblocking connection.
2010-11-22: Simon Goldschmidt
* etharp.c: Fixed bug #31722: IP packets sent with an AutoIP source addr
must be sent link-local
2010-11-22: Simon Goldschmidt
* timers.c: patch #7329: tcp_timer_needed prototype was ifdef'ed out for
LWIP_TIMERS==0
2010-11-20: Simon Goldschmidt
* sockets.c: Fixed bug #31170: lwip_setsockopt() does not set socket number
2010-11-20: Simon Goldschmidt
* sockets.h: Fixed bug #31304: Changed SHUT_RD, SHUT_WR and SHUT_RDWR to
resemble other stacks.
2010-11-20: Simon Goldschmidt
* dns.c: Fixed bug #31535: TCP_SND_QUEUELEN must be at least 2 or else
no-copy TCP writes will never succeed.
2010-11-20: Simon Goldschmidt
* dns.c: Fixed bug #31701: Error return value from dns_gethostbyname() does
not match documentation: return ERR_ARG instead of ERR_VAL if not
initialized or wrong argument.
2010-10-20: Simon Goldschmidt
* sockets.h: Fixed bug #31385: sizeof(struct sockaddr) is 30 but should be 16
2010-10-05: Simon Goldschmidt
* dhcp.c: Once again fixed #30038: DHCP/AutoIP cooperation failed when
replugging the network cable after an AutoIP address was assigned.
2010-08-10: Simon Goldschmidt
* tcp.c: Fixed bug #30728: tcp_new_port() did not check listen pcbs
2010-08-03: Simon Goldschmidt
* udp.c, raw.c: Don't chain empty pbufs when sending them (fixes bug #30625)
2010-08-01: Simon Goldschmidt (patch by Greg Renda)
* ppp.c: Applied patch #7264 (PPP protocols are rejected incorrectly on big
endian architectures)
2010-07-28: Simon Goldschmidt
* api_lib.c, api_msg.c, sockets.c, mib2.c: Fixed compilation with TCP or UDP
disabled.
2010-07-27: Simon Goldschmidt
* tcp.c: Fixed bug #30565 (tcp_connect() check bound list): that check did no
harm but never did anything
2010-07-21: Simon Goldschmidt
* ip.c: Fixed invalid fix for bug #30402 (CHECKSUM_GEN_IP_INLINE does not
add IP options)
2010-07-16: Kieran Mansley
* msg_in.c: Fixed SNMP ASN constant defines to not use ! operator
2010-07-10: Simon Goldschmidt
* ip.c: Fixed bug #30402: CHECKSUM_GEN_IP_INLINE does not add IP options
2010-06-30: Simon Goldschmidt
* api_msg.c: fixed bug #30300 (shutdown parameter was not initialized in
netconn_delete)
2010-06-28: Kieran Mansley
* timers.c remove unportable printing of C function pointers
2010-06-24: Simon Goldschmidt
* init.c, timers.c/.h, opt.h, memp_std.h: From patch #7221: added flag
NO_SYS_NO_TIMERS to drop timer support for NO_SYS==1 for easier upgrading
2010-06-24: Simon Goldschmidt
* api(_lib).c/.h, api_msg.c/.h, sockets.c/.h: Fixed bug #10088: Correctly
implemented shutdown at socket level.
2010-06-21: Simon Goldschmidt
* pbuf.c/.h, ip_frag.c/.h, opt.h, memp_std.h: Fixed bug #29361 (ip_frag has
problems with zero-copy DMA MACs) by adding custom pbufs and implementing
custom pbufs that reference other (original) pbufs. Additionally set
IP_FRAG_USES_STATIC_BUF=0 as default to be on the safe side.
2010-06-15: Simon Goldschmidt
* dhcp.c: Fixed bug #29970: DHCP endian issue parsing option responses
2010-06-14: Simon Goldschmidt
* autoip.c: Fixed bug #30039: AutoIP does not reuse previous addresses
2010-06-12: Simon Goldschmidt
* dhcp.c: Fixed bug #30038: dhcp_network_changed doesn't reset AUTOIP coop
state
2010-05-17: Simon Goldschmidt
* netdb.c: Correctly NULL-terminate h_addr_list
2010-05-16: Simon Goldschmidt
* def.h/.c: changed the semantics of LWIP_PREFIX_BYTEORDER_FUNCS to prevent
"symbol already defined" i.e. when linking to winsock
2010-05-05: Simon Goldschmidt
* def.h, timers.c: Fixed bug #29769 (sys_check_timeouts: sys_now() may
overflow)
2010-04-21: Simon Goldschmidt
* api_msg.c: Fixed bug #29617 (sometime cause stall on delete listening
connection)
2010-03-28: Luca Ceresoli
* ip_addr.c/.h: patch #7143: Add a few missing const qualifiers
2010-03-27: Luca Ceresoli
* mib2.c: patch #7130: remove meaningless const qualifiers
2010-03-26: Simon Goldschmidt
* tcp_out.c: Make LWIP_NETIF_TX_SINGLE_PBUF work for TCP, too
2010-03-26: Simon Goldschmidt
* various files: Fixed compiling with different options disabled (TCP/UDP),
triggered by bug #29345; don't allocate acceptmbox if LWIP_TCP is disabled
2010-03-25: Simon Goldschmidt
* sockets.c: Fixed bug #29332: lwip_select() processes readset incorrectly
2010-03-25: Simon Goldschmidt
* tcp_in.c, test_tcp_oos.c: Fixed bug #29080: Correctly handle remote side
overrunning our rcv_wnd in ooseq case.
2010-03-22: Simon Goldschmidt
* tcp.c: tcp_listen() did not copy the pcb's prio.
2010-03-19: Simon Goldschmidt
* snmp_msg.c: Fixed bug #29256: SNMP Trap address was not correctly set
2010-03-14: Simon Goldschmidt
* opt.h, etharp.h: Fixed bug #29148 (Incorrect PBUF_POOL_BUFSIZE for ports
where ETH_PAD_SIZE > 0) by moving definition of ETH_PAD_SIZE to opt.h
and basing PBUF_LINK_HLEN on it.
2010-03-08: Simon Goldschmidt
* netif.c, ipv4/ip.c: task #10241 (AutoIP: don't break existing connections
when assiging routable address): when checking incoming packets and
aborting existing connection on address change, filter out link-local
addresses.
2010-03-06: Simon Goldschmidt
* sockets.c: Fixed LWIP_NETIF_TX_SINGLE_PBUF for LWIP_TCPIP_CORE_LOCKING
2010-03-06: Simon Goldschmidt
* ipv4/ip.c: Don't try to forward link-local addresses
2010-03-06: Simon Goldschmidt
* etharp.c: Fixed bug #29087: etharp: don't send packets for LinkLocal-
addresses to gw
2010-03-05: Simon Goldschmidt
* dhcp.c: Fixed bug #29072: Correctly set ciaddr based on message-type
and state.
2010-03-05: Simon Goldschmidt
* api_msg.c: Correctly set TCP_WRITE_FLAG_MORE when netconn_write is split
into multiple calls to tcp_write.
2010-02-21: Simon Goldschmidt
* opt.h, mem.h, dns.c: task #10140: Remove DNS_USES_STATIC_BUF (keep
the implementation of DNS_USES_STATIC_BUF==1)
2010-02-20: Simon Goldschmidt
* tcp.h, tcp.c, tcp_in.c, tcp_out.c: Task #10088: Correctly implement
close() vs. shutdown(). Now the application does not get any more
recv callbacks after calling tcp_close(). Added tcp_shutdown().
2010-02-19: Simon Goldschmidt
* mem.c/.h, pbuf.c: Renamed mem_realloc() to mem_trim() to prevent
confusion with realloc()
2010-02-15: Simon Goldschmidt/Stephane Lesage
* netif.c/.h: Link status does not depend on LWIP_NETIF_LINK_CALLBACK
(fixes bug #28899)
2010-02-14: Simon Goldschmidt
* netif.c: Fixed bug #28877 (Duplicate ARP gratuitous packet with
LWIP_NETIF_LINK_CALLBACK set on) by only sending if both link- and
admin-status of a netif are up
2010-02-14: Simon Goldschmidt
* opt.h: Disable ETHARP_TRUST_IP_MAC by default since it slows down packet
reception and is not really necessary
2010-02-14: Simon Goldschmidt
* etharp.c/.h: Fixed ARP input processing: only add a new entry if a
request was directed as us (RFC 826, Packet Reception), otherwise
only update existing entries; internalized some functions
2010-02-14: Simon Goldschmidt
* netif.h, etharp.c, tcpip.c: Fixed bug #28183 (ARP and TCP/IP cannot be
disabled on netif used for PPPoE) by adding a new netif flag
(NETIF_FLAG_ETHERNET) that tells the stack the device is an ethernet
device but prevents usage of ARP (so that ethernet_input can be used
for PPPoE).
2010-02-12: Simon Goldschmidt
* netif.c: netif_set_link_up/down: only do something if the link state
actually changes
2010-02-12: Simon Goldschmidt/Stephane Lesage
* api_msg.c: Fixed bug #28865 (Cannot close socket/netconn in non-blocking
connect)
2010-02-12: Simon Goldschmidt
* mem.h: Fixed bug #28866 (mem_realloc function defined in mem.h)
2010-02-09: Simon Goldschmidt
* api_lib.c, api_msg.c, sockets.c, api.h, api_msg.h: Fixed bug #22110
(recv() makes receive window update for data that wasn't received by
application)
2010-02-09: Simon Goldschmidt/Stephane Lesage
* sockets.c: Fixed bug #28853 (lwip_recvfrom() returns 0 on receive time-out
or any netconn_recv() error)
2010-02-09: Simon Goldschmidt
* ppp.c: task #10154 (PPP: Update snmp in/out counters for tx/rx packets)
2010-02-09: Simon Goldschmidt
* netif.c: For loopback packets, adjust the stats- and snmp-counters
for the loopback netif.
2010-02-08: Simon Goldschmidt
* igmp.c/.h, ip.h: Moved most defines from igmp.h to igmp.c for clarity
since they are not used anywhere else.
2010-02-08: Simon Goldschmidt (Stéphane Lesage)
* igmp.c, igmp.h, stats.c, stats.h: Improved IGMP stats
(patch from bug #28798)
2010-02-08: Simon Goldschmidt (Stéphane Lesage)
* igmp.c: Fixed bug #28798 (Error in "Max Response Time" processing) and
another bug when LWIP_RAND() returns zero.
2010-02-04: Simon Goldschmidt
* nearly every file: Use macros defined in ip_addr.h (some of them new)
to work with IP addresses (preparation for bug #27352 - Change ip_addr
from struct to typedef (u32_t) - and better code).
2010-01-31: Simon Goldschmidt
* netif.c: Don't call the link-callback from netif_set_up/down() since
this invalidly retriggers DHCP.
2010-01-29: Simon Goldschmidt
* ip_addr.h, inet.h, def.h, inet.c, def.c, more: Cleanly separate the
portability file inet.h and its contents from the stack: moved htonX-
functions to def.h (and the new def.c - they are not ipv4 dependent),
let inet.h depend on ip_addr.h and not the other way round.
This fixes bug #28732.
2010-01-28: Kieran Mansley
* tcp.c: Ensure ssthresh >= 2*MSS
2010-01-27: Simon Goldschmidt
* tcp.h, tcp.c, tcp_in.c: Fixed bug #27871: Calling tcp_abort() in recv
callback can lead to accessing unallocated memory. As a consequence,
ERR_ABRT means the application has called tcp_abort()!
2010-01-25: Simon Goldschmidt
* snmp_structs.h, msg_in.c: Partly fixed bug #22070 (MIB_OBJECT_WRITE_ONLY
not implemented in SNMP): write-only or not-accessible are still
returned by getnext (though not by get)
2010-01-24: Simon Goldschmidt
* snmp: Renamed the private mib node from 'private' to 'mib_private' to
not use reserved C/C++ keywords
2010-01-23: Simon Goldschmidt
* sockets.c: Fixed bug #28716: select() returns 0 after waiting for less
than 1 ms
2010-01-21: Simon Goldschmidt
* tcp.c, api_msg.c: Fixed bug #28651 (tcp_connect: no callbacks called
if tcp_enqueue fails) both in raw- and netconn-API
2010-01-19: Simon Goldschmidt
* api_msg.c: Fixed bug #27316: netconn: Possible deadlock in err_tcp
2010-01-18: Iordan Neshev/Simon Goldschmidt
* src/netif/ppp: reorganised PPP sourcecode to 2.3.11 including some
bugfix backports from 2.4.x.
2010-01-18: Simon Goldschmidt
* mem.c: Fixed bug #28679: mem_realloc calculates mem_stats wrong
2010-01-17: Simon Goldschmidt
* api_lib.c, api_msg.c, (api_msg.h, api.h, sockets.c, tcpip.c):
task #10102: "netconn: clean up conn->err threading issues" by adding
error return value to struct api_msg_msg
2010-01-17: Simon Goldschmidt
* api.h, api_lib.c, sockets.c: Changed netconn_recv() and netconn_accept()
to return err_t (bugs #27709 and #28087)
2010-01-14: Simon Goldschmidt
* ...: Use typedef for function prototypes throughout the stack.
2010-01-13: Simon Goldschmidt
* api_msg.h/.c, api_lib.c: Fixed bug #26672 (close connection when receive
window = 0) by correctly draining recvmbox/acceptmbox
2010-01-11: Simon Goldschmidt
* pap.c: Fixed bug #13315 (PPP PAP authentication can result in
erroneous callbacks) by copying the code from recent pppd
2010-01-10: Simon Goldschmidt
* raw.c: Fixed bug #28506 (raw_bind should filter received packets)
2010-01-10: Simon Goldschmidt
* tcp.h/.c: bug #28127 (remove call to tcp_output() from tcp_ack(_now)())
2010-01-08: Simon Goldschmidt
* sockets.c: Fixed bug #28519 (lwip_recvfrom bug with len > 65535)
2010-01-08: Simon Goldschmidt
* dns.c: Copy hostname for DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1 since string
passed to dns_local_addhost() might be volatile
2010-01-07: Simon Goldschmidt
* timers.c, tcp.h: Call tcp_timer_needed() with NO_SYS==1, too
2010-01-06: Simon Goldschmidt
* netdb.h: Fixed bug #28496: missing include guards in netdb.h
2009-12-31: Simon Goldschmidt
* many ppp files: Reorganised PPP source code from ucip structure to pppd
structure to easily compare our code against the pppd code (around v2.3.1)
2009-12-27: Simon Goldschmidt
* tcp_in.c: Another fix for bug #28241 (ooseq processing) and adapted
unit test
(STABLE-1.3.2)

144
lwip/UPGRADING Normal file
View file

@ -0,0 +1,144 @@
This file lists major changes between release versions that require
ports or applications to be changed. Use it to update a port or an
application written for an older version of lwIP to correctly work
with newer versions.
(CVS HEAD)
* [Enter new changes just after this line - do not remove this line]
++ Application changes:
* Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for
compatibility to old applications, but will be removed in the future).
* Renamed mem_realloc() to mem_trim() to prevent confusion with realloc()
+++ Raw API:
* Changed the semantics of tcp_close() (since it was rather a
shutdown before): Now the application does *NOT* get any calls to the recv
callback (aside from NULL/closed) after calling tcp_close()
* When calling tcp_abort() from a raw API TCP callback function,
make sure you return ERR_ABRT to prevent accessing unallocated memory.
(ERR_ABRT now means the applicaiton has called tcp_abort!)
+++ Netconn API:
* Changed netconn_receive() and netconn_accept() to return
err_t, not a pointer to new data/netconn.
+++ Socket API:
* LWIP_SO_RCVTIMEO: when accept() or recv() time out, they
now set errno to EWOULDBLOCK/EAGAIN, not ETIMEDOUT.
* Added a minimal version of posix fctl() to have a
standardised way to set O_NONBLOCK for nonblocking sockets.
+++ all APIs:
* correctly implemented SO(F)_REUSEADDR
++ Port changes
+++ new files:
* Added 4 new files: def.c, timers.c, timers.h, tcp_impl.h:
* Moved stack-internal parts of tcp.h to tcp_impl.h, tcp.h now only contains
the actual application programmer's API
* Separated timer implementation from sys.h/.c, moved to timers.h/.c;
Added timer implementation for NO_SYS==1, set NO_SYS_NO_TIMERS==1 if you
still want to use your own timer implementation for NO_SYS==0 (as before).
+++ sys layer:
* Converted mbox- and semaphore-functions to take pointers to sys_mbox_t/
sys_sem_t;
* Converted sys_mbox_new/sys_sem_new to take pointers and return err_t;
* Added Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX to let sys.h use
binary semaphores instead of mutexes - as before)
+++ new options:
* Don't waste memory when chaining segments, added option TCP_OVERSIZE to
prevent creating many small pbufs when calling tcp_write with many small
blocks of data. Instead, pbufs are allocated larger than needed and the
space is used for later calls to tcp_write.
* Added LWIP_NETIF_TX_SINGLE_PBUF to always copy to try to create single pbufs
in tcp_write/udp_send.
* Added an additional option LWIP_ETHERNET to support ethernet without ARP
(necessary for pure PPPoE)
* Add MEMP_SEPARATE_POOLS to place memory pools in separate arrays. This may
be used to place these pools into user-defined memory by using external
declaration.
* Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT
+++ new pools:
* Netdb uses a memp pool for allocating memory when getaddrinfo() is called,
so MEMP_NUM_NETDB has to be set accordingly.
* DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses a memp pool instead of the heap, so
MEMP_NUM_LOCALHOSTLIST has to be set accordingly.
* Snmp-agent uses a memp pools instead of the heap, so MEMP_NUM_SNMP_* have
to be set accordingly.
* PPPoE uses a MEMP pool instead of the heap, so MEMP_NUM_PPPOE_INTERFACES
has to be set accordingly
* Integrated loopif into netif.c - loopif does not have to be created by the
port any more, just define LWIP_HAVE_LOOPIF to 1.
* Added define LWIP_RAND() for lwip-wide randomization (needs to be defined
in cc.h, e.g. used by igmp)
* Added printf-formatter X8_F to printf u8_t as hex
* The heap now may be moved to user-defined memory by defining
LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address
* added autoip_set_struct() and dhcp_set_struct() to let autoip and dhcp work
with user-allocated structs instead of calling mem_malloc
* Added const char* name to mem- and memp-stats for easier debugging.
* Calculate the TCP/UDP checksum while copying to only fetch data once:
Define LWIP_CHKSUM_COPY to a memcpy-like function that returns the checksum
* Added SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to
more than one pcb.
* Changed the semantics of ARP_QUEUEING==0: ARP_QUEUEING now cannot be turned
off any more, if this is set to 0, only one packet (the most recent one) is
queued (like demanded by RFC 1122).
++ Major bugfixes/improvements
* Implemented tcp_shutdown() to only shut down one end of a connection
* Implemented shutdown() at socket- and netconn-level
* Added errorset support to select() + improved select speed overhead
* Merged pppd to v2.3.11 (including some backported bugfixes from 2.4.x)
* Added timer implementation for NO_SYS==1 (may be disabled with NO_SYS_NO_TIMERS==1
* Use macros defined in ip_addr.h to work with IP addresses
* Implemented many nonblocking socket/netconn functions
* Fixed ARP input processing: only add a new entry if a request was directed as us
* mem_realloc() to mem_trim() to prevent confusion with realloc()
* Some improvements for AutoIP (don't route/forward link-local addresses, don't break
existing connections when assigning a routable address)
* Correctly handle remote side overrunning our rcv_wnd in ooseq case
* Removed packing from ip_addr_t, the packed version is now only used in protocol headers
* Corrected PBUF_POOL_BUFSIZE for ports where ETH_PAD_SIZE > 0
* Added support for static ARP table entries
(STABLE-1.3.2)
* initial version of this file

View file

@ -251,8 +251,9 @@ if a call to tcp_write() has failed because memory wasn't available,
the application may use the polling functionality to call tcp_write()
again when the connection has been idle for a while.
- void tcp_poll(struct tcp_pcb *pcb, u8_t interval,
err_t (* poll)(void *arg, struct tcp_pcb *tpcb))
- void tcp_poll(struct tcp_pcb *pcb,
err_t (* poll)(void *arg, struct tcp_pcb *tpcb),
u8_t interval)
Specifies the polling interval and the callback function that should
be called to poll the application. The interval is specified in
@ -278,6 +279,11 @@ again when the connection has been idle for a while.
Aborts the connection by sending a RST (reset) segment to the remote
host. The pcb is deallocated. This function never fails.
ATTENTION: When calling this from one of the TCP callbacks, make
sure you always return ERR_ABRT (and never return ERR_ABRT otherwise
or you will risk accessing deallocated memory or memory leaks!
If a connection is aborted because of an error, the application is
alerted of this event by the err callback. Errors that might abort a
connection are when there is a shortage of memory. The callback
@ -476,3 +482,24 @@ to match your application and network.
For a production release it is recommended to set LWIP_STATS to 0.
Note that speed performance isn't influenced much by simply setting
high values to the memory options.
For more optimization hints take a look at the lwIP wiki.
--- Zero-copy MACs
To achieve zero-copy on transmit, the data passed to the raw API must
remain unchanged until sent. Because the send- (or write-)functions return
when the packets have been enqueued for sending, data must be kept stable
after that, too.
This implies that PBUF_RAM/PBUF_POOL pbufs passed to raw-API send functions
must *not* be reused by the application unless their ref-count is 1.
For no-copy pbufs (PBUF_ROM/PBUF_REF), data must be kept unchanged, too,
but the stack/driver will/must copy PBUF_REF'ed data when enqueueing, while
PBUF_ROM-pbufs are just enqueued (as ROM-data is expected to never change).
Also, data passed to tcp_write without the copy-flag must not be changed!
Therefore, be careful which type of PBUF you use and if you copy TCP data
or not!

View file

@ -46,7 +46,7 @@ Loading additional MIBs
Large SNMP message support
The packet decoding and encoding routines are designed
to use pbuf-chains. Larger payloads then the minimum
to use pbuf-chains. Larger payloads than the minimum
SNMP requirement of 484 octets are supported if the
PBUF_POOL_SIZE and IP_REASS_BUFSIZE are set to match your
local requirement.
@ -170,7 +170,7 @@ resembles the "auto-completion" operation)
The middle part is usually located in ROM (const)
to preserve precious RAM on small microcontrollers.
However RAM location is possible for an dynamically
However RAM location is possible for a dynamically
changing private tree.
The index part is handled by functions which in

View file

@ -123,18 +123,6 @@ The following functions must be implemented by the sys_arch:
sys_arch_mbox_fetch(mbox,msg,1)
although this would introduce unnecessary delays.
- struct sys_timeouts *sys_arch_timeouts(void)
Returns a pointer to the per-thread sys_timeouts structure. In lwIP,
each thread has a list of timeouts which is repressented as a linked
list of sys_timeout structures. The sys_timeouts structure holds a
pointer to a linked list of timeouts. This function is called by
the lwIP timeout scheduler and must not return a NULL value.
In a single thread sys_arch implementation, this function will
simply return a pointer to a global sys_timeouts variable stored in
the sys_arch module.
If threads are supported by the underlying operating system and if
such functionality is needed in lwIP, the following function will have
to be implemented as well:

View file

@ -71,19 +71,19 @@ netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_cal
struct api_msg msg;
conn = netconn_alloc(t, callback);
if (conn != NULL ) {
if (conn != NULL) {
msg.function = do_newconn;
msg.msg.msg.n.proto = proto;
msg.msg.conn = conn;
TCPIP_APIMSG(&msg);
if (conn->err != ERR_OK) {
if (TCPIP_APIMSG(&msg) != ERR_OK) {
LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
LWIP_ASSERT("conn has no op_completed", conn->op_completed != SYS_SEM_NULL);
LWIP_ASSERT("conn has no recvmbox", conn->recvmbox != SYS_MBOX_NULL);
LWIP_ASSERT("conn->acceptmbox shouldn't exist", conn->acceptmbox == SYS_MBOX_NULL);
sys_sem_free(conn->op_completed);
sys_mbox_free(conn->recvmbox);
LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
#if LWIP_TCP
LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
#endif /* LWIP_TCP */
sys_sem_free(&conn->op_completed);
sys_mbox_free(&conn->recvmbox);
memp_free(MEMP_NETCONN, conn);
return NULL;
}
@ -113,9 +113,10 @@ netconn_delete(struct netconn *conn)
msg.msg.conn = conn;
tcpip_apimsg(&msg);
conn->pcb.tcp = NULL;
netconn_free(conn);
/* don't care for return value of do_delconn since it only calls void functions */
return ERR_OK;
}
@ -131,9 +132,10 @@ netconn_delete(struct netconn *conn)
* ERR_OK if the information was retrieved
*/
err_t
netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t local)
netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
@ -144,9 +146,10 @@ netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t lo
msg.msg.msg.ad.ipaddr = addr;
msg.msg.msg.ad.port = port;
msg.msg.msg.ad.local = local;
TCPIP_APIMSG(&msg);
err = TCPIP_APIMSG(&msg);
return conn->err;
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
@ -160,9 +163,10 @@ netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t lo
* @return ERR_OK if bound, any other err_t on failure
*/
err_t
netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port)
netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
@ -170,8 +174,10 @@ netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port)
msg.msg.conn = conn;
msg.msg.msg.bc.ipaddr = addr;
msg.msg.msg.bc.port = port;
TCPIP_APIMSG(&msg);
return conn->err;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
@ -183,9 +189,10 @@ netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port)
* @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
*/
err_t
netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port)
netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
@ -194,8 +201,10 @@ netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port)
msg.msg.msg.bc.ipaddr = addr;
msg.msg.msg.bc.port = port;
/* This is the only function which need to not block tcpip_thread */
tcpip_apimsg(&msg);
return conn->err;
err = tcpip_apimsg(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
@ -208,13 +217,16 @@ err_t
netconn_disconnect(struct netconn *conn)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_disconnect;
msg.msg.conn = conn;
TCPIP_APIMSG(&msg);
return conn->err;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
@ -228,7 +240,9 @@ netconn_disconnect(struct netconn *conn)
err_t
netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
{
#if LWIP_TCP
struct api_msg msg;
err_t err;
/* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
LWIP_UNUSED_ARG(backlog);
@ -240,156 +254,276 @@ netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
#if TCP_LISTEN_BACKLOG
msg.msg.msg.lb.backlog = backlog;
#endif /* TCP_LISTEN_BACKLOG */
TCPIP_APIMSG(&msg);
return conn->err;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
#else /* LWIP_TCP */
LWIP_UNUSED_ARG(conn);
LWIP_UNUSED_ARG(backlog);
return ERR_ARG;
#endif /* LWIP_TCP */
}
/**
* Accept a new connection on a TCP listening netconn.
*
* @param conn the TCP listen netconn
* @return the newly accepted netconn or NULL on timeout
* @param new_conn pointer where the new connection is stored
* @return ERR_OK if a new connection has been received or an error
* code otherwise
*/
struct netconn *
netconn_accept(struct netconn *conn)
err_t
netconn_accept(struct netconn *conn, struct netconn **new_conn)
{
#if LWIP_TCP
struct netconn *newconn;
LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return NULL;);
LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return NULL;);
#if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
newconn = NULL;
} else
#else
sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0);
#endif /* LWIP_SO_RCVTIMEO*/
{
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
err_t err;
#if TCP_LISTEN_BACKLOG
if (newconn != NULL) {
/* Let the stack know that we have accepted the connection. */
struct api_msg msg;
msg.function = do_recv;
msg.msg.conn = conn;
TCPIP_APIMSG(&msg);
}
struct api_msg msg;
#endif /* TCP_LISTEN_BACKLOG */
LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;);
*new_conn = NULL;
LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_accept: invalid acceptmbox", sys_mbox_valid(&conn->acceptmbox), return ERR_ARG;);
err = conn->last_err;
if (ERR_IS_FATAL(err)) {
/* don't recv on fatal errors: this might block the application task
waiting on acceptmbox forever! */
return err;
}
return newconn;
#if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
return ERR_TIMEOUT;
}
#else
sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0);
#endif /* LWIP_SO_RCVTIMEO*/
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
if (newconn == NULL) {
/* connection has been aborted */
NETCONN_SET_SAFE_ERR(conn, ERR_ABRT);
return ERR_ABRT;
}
#if TCP_LISTEN_BACKLOG
/* Let the stack know that we have accepted the connection. */
msg.function = do_recv;
msg.msg.conn = conn;
/* don't care for the return value of do_recv */
TCPIP_APIMSG(&msg);
#endif /* TCP_LISTEN_BACKLOG */
*new_conn = newconn;
/* don't set conn->last_err: it's only ERR_OK, anyway */
return ERR_OK;
#else /* LWIP_TCP */
LWIP_UNUSED_ARG(conn);
LWIP_UNUSED_ARG(new_conn);
return ERR_ARG;
#endif /* LWIP_TCP */
}
/**
* Receive data: actual implementation that doesn't care whether pbuf or netbuf
* is received
*
* @param conn the netconn from which to receive data
* @param new_buf pointer where a new pbuf/netbuf is stored when received data
* @return ERR_OK if data has been received, an error code otherwise (timeout,
* memory error or another error)
*/
static err_t
netconn_recv_data(struct netconn *conn, void **new_buf)
{
void *buf = NULL;
u16_t len;
err_t err;
#if LWIP_TCP
struct api_msg msg;
#endif /* LWIP_TCP */
LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
*new_buf = NULL;
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
err = conn->last_err;
if (ERR_IS_FATAL(err)) {
/* don't recv on fatal errors: this might block the application task
waiting on recvmbox forever! */
/* @todo: this does not allow us to fetch data that has been put into recvmbox
before the fatal error occurred - is that a problem? */
return err;
}
#if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
return ERR_TIMEOUT;
}
#else
sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
#endif /* LWIP_SO_RCVTIMEO*/
#if LWIP_TCP
if (conn->type == NETCONN_TCP) {
if (!netconn_get_noautorecved(conn) || (buf == NULL)) {
/* Let the stack know that we have taken the data. */
/* TODO: Speedup: Don't block and wait for the answer here
(to prevent multiple thread-switches). */
msg.function = do_recv;
msg.msg.conn = conn;
if (buf != NULL) {
msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len;
} else {
msg.msg.msg.r.len = 1;
}
/* don't care for the return value of do_recv */
TCPIP_APIMSG(&msg);
}
/* If we are closed, we indicate that we no longer wish to use the socket */
if (buf == NULL) {
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
/* Avoid to lose any previous error code */
NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
return ERR_CLSD;
}
len = ((struct pbuf *)buf)->tot_len;
}
#endif /* LWIP_TCP */
#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
else
#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
#if (LWIP_UDP || LWIP_RAW)
{
LWIP_ASSERT("buf != NULL", buf != NULL);
len = netbuf_len((struct netbuf *)buf);
}
#endif /* (LWIP_UDP || LWIP_RAW) */
#if LWIP_SO_RCVBUF
SYS_ARCH_DEC(conn->recv_avail, len);
#endif /* LWIP_SO_RCVBUF */
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
*new_buf = buf;
/* don't set conn->last_err: it's only ERR_OK, anyway */
return ERR_OK;
}
/**
* Receive data (in form of a pbuf) from a TCP netconn
*
* @param conn the netconn from which to receive data
* @param new_buf pointer where a new pbuf is stored when received data
* @return ERR_OK if data has been received, an error code otherwise (timeout,
* memory error or another error)
* ERR_ARG if conn is not a TCP netconn
*/
err_t
netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
{
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
netconn_type(conn) == NETCONN_TCP, return ERR_ARG;);
return netconn_recv_data(conn, (void **)new_buf);
}
/**
* Receive data (in form of a netbuf containing a packet buffer) from a netconn
*
* @param conn the netconn from which to receive data
* @return a new netbuf containing received data or NULL on memory error or timeout
* @param new_buf pointer where a new netbuf is stored when received data
* @return ERR_OK if data has been received, an error code otherwise (timeout,
* memory error or another error)
*/
struct netbuf *
netconn_recv(struct netconn *conn)
err_t
netconn_recv(struct netconn *conn, struct netbuf **new_buf)
{
struct api_msg msg;
struct netbuf *buf = NULL;
struct pbuf *p;
u16_t len;
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return NULL;);
if (conn->recvmbox == SYS_MBOX_NULL) {
/* @todo: should calling netconn_recv on a TCP listen conn be fatal (ERR_CONN)?? */
/* TCP listen conns don't have a recvmbox! */
conn->err = ERR_CONN;
return NULL;
}
if (ERR_IS_FATAL(conn->err)) {
return NULL;
}
if (conn->type == NETCONN_TCP) {
#if LWIP_TCP
if (conn->state == NETCONN_LISTEN) {
/* @todo: should calling netconn_recv on a TCP listen conn be fatal?? */
conn->err = ERR_CONN;
return NULL;
}
struct netbuf *buf = NULL;
err_t err;
#endif /* LWIP_TCP */
buf = memp_malloc(MEMP_NETBUF);
LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
*new_buf = NULL;
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
#if LWIP_TCP
if (conn->type == NETCONN_TCP) {
struct pbuf *p = NULL;
/* This is not a listening netconn, since recvmbox is set */
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
if (buf == NULL) {
conn->err = ERR_MEM;
return NULL;
NETCONN_SET_SAFE_ERR(conn, ERR_MEM);
return ERR_MEM;
}
#if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
err = netconn_recv_data(conn, (void **)&p);
if (err != ERR_OK) {
memp_free(MEMP_NETBUF, buf);
conn->err = ERR_TIMEOUT;
return NULL;
}
#else
sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, 0);
#endif /* LWIP_SO_RCVTIMEO*/
if (p != NULL) {
len = p->tot_len;
SYS_ARCH_DEC(conn->recv_avail, len);
} else {
len = 0;
}
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
/* If we are closed, we indicate that we no longer wish to use the socket */
if (p == NULL) {
memp_free(MEMP_NETBUF, buf);
/* Avoid to lose any previous error code */
if (conn->err == ERR_OK) {
conn->err = ERR_CLSD;
}
return NULL;
return err;
}
LWIP_ASSERT("p != NULL", p != NULL);
buf->p = p;
buf->ptr = p;
buf->port = 0;
buf->addr = NULL;
/* Let the stack know that we have taken the data. */
msg.function = do_recv;
msg.msg.conn = conn;
if (buf != NULL) {
msg.msg.msg.r.len = buf->p->tot_len;
} else {
msg.msg.msg.r.len = 1;
}
TCPIP_APIMSG(&msg);
ip_addr_set_any(&buf->addr);
*new_buf = buf;
/* don't set conn->last_err: it's only ERR_OK, anyway */
return ERR_OK;
} else
#endif /* LWIP_TCP */
} else {
{
#if (LWIP_UDP || LWIP_RAW)
#if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
buf = NULL;
}
#else
sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, 0);
#endif /* LWIP_SO_RCVTIMEO*/
if (buf!=NULL) {
SYS_ARCH_DEC(conn->recv_avail, buf->p->tot_len);
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len);
}
return netconn_recv_data(conn, (void **)new_buf);
#endif /* (LWIP_UDP || LWIP_RAW) */
}
}
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err));
return buf;
/**
* TCP: update the receive window: by calling this, the application
* tells the stack that it has processed data and is able to accept
* new data.
* ATTENTION: use with care, this is mainly used for sockets!
* Can only be used when calling netconn_set_noautorecved(conn, 1) before.
*
* @param conn the netconn for which to update the receive window
* @param length amount of data processed (ATTENTION: this must be accurate!)
*/
void
netconn_recved(struct netconn *conn, u32_t length)
{
#if LWIP_TCP
if ((conn != NULL) && (conn->type == NETCONN_TCP) &&
(netconn_get_noautorecved(conn))) {
struct api_msg msg;
/* Let the stack know that we have taken the data. */
/* TODO: Speedup: Don't block and wait for the answer here
(to prevent multiple thread-switches). */
msg.function = do_recv;
msg.msg.conn = conn;
msg.msg.msg.r.len = length;
/* don't care for the return value of do_recv */
TCPIP_APIMSG(&msg);
}
#else /* LWIP_TCP */
LWIP_UNUSED_ARG(conn);
LWIP_UNUSED_ARG(length);
#endif /* LWIP_TCP */
}
/**
@ -403,10 +537,10 @@ netconn_recv(struct netconn *conn)
* @return ERR_OK if data was sent, any other err_t on error
*/
err_t
netconn_sendto(struct netconn *conn, struct netbuf *buf, struct ip_addr *addr, u16_t port)
netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port)
{
if (buf != NULL) {
buf->addr = addr;
ip_addr_set(&buf->addr, addr);
buf->port = port;
return netconn_send(conn, buf);
}
@ -424,6 +558,7 @@ err_t
netconn_send(struct netconn *conn, struct netbuf *buf)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
@ -431,8 +566,10 @@ netconn_send(struct netconn *conn, struct netbuf *buf)
msg.function = do_send;
msg.msg.conn = conn;
msg.msg.msg.b = buf;
TCPIP_APIMSG(&msg);
return conn->err;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
@ -442,18 +579,25 @@ netconn_send(struct netconn *conn, struct netbuf *buf)
* @param dataptr pointer to the application buffer that contains the data to send
* @param size size of the application data to send
* @param apiflags combination of following flags :
* - NETCONN_COPY (0x01) data will be copied into memory belonging to the stack
* - NETCONN_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent
* - NETCONN_COPY: data will be copied into memory belonging to the stack
* - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
* - NETCONN_DONTBLOCK: only write the data if all dat can be written at once
* @return ERR_OK if data was sent, any other err_t on error
*/
err_t
netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;);
if (size == 0) {
return ERR_OK;
}
/* @todo: for non-blocking write, check if 'size' would ever fit into
snd_queue or snd_buf */
msg.function = do_write;
msg.msg.conn = conn;
msg.msg.msg.w.dataptr = dataptr;
@ -462,8 +606,37 @@ netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apifl
/* For locking the core: this _can_ be delayed on low memory/low send buffer,
but if it is, this is done inside api_msg.c:do_write(), so we can use the
non-blocking version here. */
TCPIP_APIMSG(&msg);
return conn->err;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
* Close ot shutdown a TCP netconn (doesn't delete it).
*
* @param conn the TCP netconn to close or shutdown
* @param how fully close or only shutdown one side?
* @return ERR_OK if the netconn was closed, any other err_t on error
*/
static err_t
netconn_close_shutdown(struct netconn *conn, u8_t how)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_close;
msg.msg.conn = conn;
/* shutting down both ends is the same as closing */
msg.msg.msg.sd.shut = how;
/* because of the LWIP_TCPIP_CORE_LOCKING implementation of do_close,
don't use TCPIP_APIMSG here */
err = tcpip_apimsg(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
@ -475,14 +648,20 @@ netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apifl
err_t
netconn_close(struct netconn *conn)
{
struct api_msg msg;
/* shutting down both ends is the same as closing */
return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
}
LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_close;
msg.msg.conn = conn;
tcpip_apimsg(&msg);
return conn->err;
/**
* Shut down one or both sides of a TCP netconn (doesn't delete it).
*
* @param conn the TCP netconn to shut down
* @return ERR_OK if the netconn was closed, any other err_t on error
*/
err_t
netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
{
return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
}
#if LWIP_IGMP
@ -491,28 +670,31 @@ netconn_close(struct netconn *conn)
*
* @param conn the UDP netconn for which to change multicast addresses
* @param multiaddr IP address of the multicast group to join or leave
* @param interface the IP address of the network interface on which to send
* @param netif_addr the IP address of the network interface on which to send
* the igmp message
* @param join_or_leave flag whether to send a join- or leave-message
* @return ERR_OK if the action was taken, any err_t on error
*/
err_t
netconn_join_leave_group(struct netconn *conn,
struct ip_addr *multiaddr,
struct ip_addr *interface,
ip_addr_t *multiaddr,
ip_addr_t *netif_addr,
enum netconn_igmp join_or_leave)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_join_leave_group;
msg.msg.conn = conn;
msg.msg.msg.jl.multiaddr = multiaddr;
msg.msg.msg.jl.interface = interface;
msg.msg.msg.jl.netif_addr = netif_addr;
msg.msg.msg.jl.join_or_leave = join_or_leave;
TCPIP_APIMSG(&msg);
return conn->err;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
#endif /* LWIP_IGMP */
@ -521,14 +703,14 @@ netconn_join_leave_group(struct netconn *conn,
* Execute a DNS query, only one IP address is returned
*
* @param name a string representation of the DNS host name to query
* @param addr a preallocated struct ip_addr where to store the resolved IP address
* @param addr a preallocated ip_addr_t where to store the resolved IP address
* @return ERR_OK: resolving succeeded
* ERR_MEM: memory error, try again later
* ERR_ARG: dns client not initialized or invalid hostname
* ERR_VAL: dns server response was invalid
*/
err_t
netconn_gethostbyname(const char *name, struct ip_addr *addr)
netconn_gethostbyname(const char *name, ip_addr_t *addr)
{
struct dns_api_msg msg;
err_t err;
@ -537,19 +719,19 @@ netconn_gethostbyname(const char *name, struct ip_addr *addr)
LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
sem = sys_sem_new(0);
if (sem == SYS_SEM_NULL) {
return ERR_MEM;
err = sys_sem_new(&sem, 0);
if (err != ERR_OK) {
return err;
}
msg.name = name;
msg.addr = addr;
msg.err = &err;
msg.sem = sem;
msg.sem = &sem;
tcpip_callback(do_gethostbyname, &msg);
sys_sem_wait(sem);
sys_sem_free(sem);
sys_sem_wait(&sem);
sys_sem_free(&sem);
return err;
}

File diff suppressed because it is too large Load diff

View file

@ -44,18 +44,19 @@ static const char *err_strerr[] = {
"Ok.", /* ERR_OK 0 */
"Out of memory error.", /* ERR_MEM -1 */
"Buffer error.", /* ERR_BUF -2 */
"Timeout.", /* ERR_TIMEOUT -3 */
"Timeout.", /* ERR_TIMEOUT -3 */
"Routing problem.", /* ERR_RTE -4 */
"Connection aborted.", /* ERR_ABRT -5 */
"Connection reset.", /* ERR_RST -6 */
"Connection closed.", /* ERR_CLSD -7 */
"Not connected.", /* ERR_CONN -8 */
"Illegal value.", /* ERR_VAL -9 */
"Illegal argument.", /* ERR_ARG -10 */
"Address in use.", /* ERR_USE -11 */
"Low-level netif error.", /* ERR_IF -12 */
"Already connected.", /* ERR_ISCONN -13 */
"Operation in progress." /* ERR_INPROGRESS -14 */
"Operation in progress.", /* ERR_INPROGRESS -5 */
"Illegal value.", /* ERR_VAL -6 */
"Operation would block.", /* ERR_WOULDBLOCK -7 */
"Address in use.", /* ERR_USE -8 */
"Already connected.", /* ERR_ISCONN -9 */
"Connection aborted.", /* ERR_ABRT -10 */
"Connection reset.", /* ERR_RST -11 */
"Connection closed.", /* ERR_CLSD -12 */
"Not connected.", /* ERR_CONN -13 */
"Illegal argument.", /* ERR_ARG -14 */
"Low-level netif error.", /* ERR_IF -15 */
};
/**

View file

@ -57,16 +57,21 @@ netbuf *netbuf_new(void)
{
struct netbuf *buf;
buf = memp_malloc(MEMP_NETBUF);
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
if (buf != NULL) {
buf->p = NULL;
buf->ptr = NULL;
buf->addr = NULL;
ip_addr_set_any(&buf->addr);
buf->port = 0;
#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
#if LWIP_CHECKSUM_ON_COPY
buf->flags = 0;
#endif /* LWIP_CHECKSUM_ON_COPY */
buf->toport_chksum = 0;
#if LWIP_NETBUF_RECVINFO
buf->toaddr = NULL;
buf->toport = 0;
ip_addr_set_any(&buf->toaddr);
#endif /* LWIP_NETBUF_RECVINFO */
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
return buf;
} else {
return NULL;

View file

@ -39,16 +39,18 @@
#include "lwip/err.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/ip_addr.h"
#include "lwip/api.h"
#include "lwip/dns.h"
#include <string.h>
#include <stdlib.h>
/** helper struct for gethostbyname_r to access the char* buffer */
struct gethostbyname_r_helper {
struct ip_addr *addrs;
struct ip_addr addr;
ip_addr_t *addrs;
ip_addr_t addr;
char *aliases;
};
@ -83,13 +85,13 @@ struct hostent*
lwip_gethostbyname(const char *name)
{
err_t err;
struct ip_addr addr;
ip_addr_t addr;
/* buffer variables for lwip_gethostbyname() */
HOSTENT_STORAGE struct hostent s_hostent;
HOSTENT_STORAGE char *s_aliases;
HOSTENT_STORAGE struct ip_addr s_hostent_addr;
HOSTENT_STORAGE struct ip_addr *s_phostent_addr;
HOSTENT_STORAGE ip_addr_t s_hostent_addr;
HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2];
/* query host IP address */
err = netconn_gethostbyname(name, &addr);
@ -101,11 +103,12 @@ lwip_gethostbyname(const char *name)
/* fill hostent */
s_hostent_addr = addr;
s_phostent_addr = &s_hostent_addr;
s_phostent_addr[0] = &s_hostent_addr;
s_phostent_addr[1] = NULL;
s_hostent.h_name = (char*)name;
s_hostent.h_aliases = &s_aliases;
s_hostent.h_addrtype = AF_INET;
s_hostent.h_length = sizeof(struct ip_addr);
s_hostent.h_length = sizeof(ip_addr_t);
s_hostent.h_addr_list = (char**)&s_phostent_addr;
#if DNS_DEBUG
@ -126,7 +129,7 @@ lwip_gethostbyname(const char *name)
u8_t idx;
for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx]));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa(s_hostent.h_addr_list[idx])));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx])));
}
}
#endif /* DNS_DEBUG */
@ -211,7 +214,7 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
ret->h_name = (char*)hostname;
ret->h_aliases = &(h->aliases);
ret->h_addrtype = AF_INET;
ret->h_length = sizeof(struct ip_addr);
ret->h_length = sizeof(ip_addr_t);
ret->h_addr_list = (char**)&(h->addrs);
/* set result != NULL */
@ -235,7 +238,7 @@ lwip_freeaddrinfo(struct addrinfo *ai)
while (ai != NULL) {
next = ai->ai_next;
mem_free(ai);
memp_free(MEMP_NETDB, ai);
ai = next;
}
}
@ -264,7 +267,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
err_t err;
struct ip_addr addr;
ip_addr_t addr;
struct addrinfo *ai;
struct sockaddr_in *sa = NULL;
int port_nr = 0;
@ -296,7 +299,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
}
} else {
/* service location specified, use loopback address */
addr.addr = htonl(INADDR_LOOPBACK);
ip_addr_set_loopback(&addr);
}
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
@ -305,17 +308,20 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
total_size += namelen + 1;
}
ai = mem_malloc(total_size);
/* If this fails, please report to lwip-devel! :-) */
LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!",
total_size <= NETDB_ELEM_SIZE);
ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
if (ai == NULL) {
goto memerr;
}
memset(ai, 0, total_size);
sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo));
/* set up sockaddr */
sa->sin_addr.s_addr = addr.addr;
inet_addr_from_ipaddr(&sa->sin_addr, &addr);
sa->sin_family = AF_INET;
sa->sin_len = sizeof(struct sockaddr_in);
sa->sin_port = htons(port_nr);
sa->sin_port = htons((u16_t)port_nr);
/* set up addrinfo */
ai->ai_family = AF_INET;
@ -338,7 +344,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
return 0;
memerr:
if (ai != NULL) {
mem_free(ai);
memp_free(MEMP_NETDB, ai);
}
return EAI_MEMORY;
}

View file

@ -42,7 +42,7 @@
* Call netif_add() inside the tcpip_thread context.
*/
void
do_netifapi_netif_add( struct netifapi_msg_msg *msg)
do_netifapi_netif_add(struct netifapi_msg_msg *msg)
{
if (!netif_add( msg->netif,
msg->msg.add.ipaddr,
@ -62,7 +62,7 @@ do_netifapi_netif_add( struct netifapi_msg_msg *msg)
* Call netif_set_addr() inside the tcpip_thread context.
*/
void
do_netifapi_netif_set_addr( struct netifapi_msg_msg *msg)
do_netifapi_netif_set_addr(struct netifapi_msg_msg *msg)
{
netif_set_addr( msg->netif,
msg->msg.add.ipaddr,
@ -77,11 +77,10 @@ do_netifapi_netif_set_addr( struct netifapi_msg_msg *msg)
* tcpip_thread context.
*/
void
do_netifapi_netif_common( struct netifapi_msg_msg *msg)
do_netifapi_netif_common(struct netifapi_msg_msg *msg)
{
if (msg->msg.common.errtfunc!=NULL) {
msg->err =
msg->msg.common.errtfunc(msg->netif);
if (msg->msg.common.errtfunc != NULL) {
msg->err = msg->msg.common.errtfunc(msg->netif);
} else {
msg->err = ERR_OK;
msg->msg.common.voidfunc(msg->netif);
@ -97,12 +96,12 @@ do_netifapi_netif_common( struct netifapi_msg_msg *msg)
*/
err_t
netifapi_netif_add(struct netif *netif,
struct ip_addr *ipaddr,
struct ip_addr *netmask,
struct ip_addr *gw,
ip_addr_t *ipaddr,
ip_addr_t *netmask,
ip_addr_t *gw,
void *state,
err_t (* init)(struct netif *netif),
err_t (* input)(struct pbuf *p, struct netif *netif))
netif_init_fn init,
netif_input_fn input)
{
struct netifapi_msg msg;
msg.function = do_netifapi_netif_add;
@ -125,9 +124,9 @@ netifapi_netif_add(struct netif *netif,
*/
err_t
netifapi_netif_set_addr(struct netif *netif,
struct ip_addr *ipaddr,
struct ip_addr *netmask,
struct ip_addr *gw)
ip_addr_t *ipaddr,
ip_addr_t *netmask,
ip_addr_t *gw)
{
struct netifapi_msg msg;
msg.function = do_netifapi_netif_set_addr;
@ -146,9 +145,8 @@ netifapi_netif_set_addr(struct netif *netif,
* @note use only for functions where there is only "netif" parameter.
*/
err_t
netifapi_netif_common( struct netif *netif,
void (* voidfunc)(struct netif *netif),
err_t (* errtfunc)(struct netif *netif) )
netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,
netifapi_errt_fn errtfunc)
{
struct netifapi_msg msg;
msg.function = do_netifapi_netif_common;

File diff suppressed because it is too large Load diff

View file

@ -42,182 +42,23 @@
#include "lwip/sys.h"
#include "lwip/memp.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/ip_frag.h"
#include "lwip/tcp.h"
#include "lwip/autoip.h"
#include "lwip/dhcp.h"
#include "lwip/igmp.h"
#include "lwip/dns.h"
#include "lwip/tcpip.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "netif/ppp_oe.h"
/* global variables */
static void (* tcpip_init_done)(void *arg);
static tcpip_init_done_fn tcpip_init_done;
static void *tcpip_init_done_arg;
static sys_mbox_t mbox = SYS_MBOX_NULL;
static sys_mbox_t mbox;
#if LWIP_TCPIP_CORE_LOCKING
/** The global semaphore to lock the stack. */
sys_sem_t lock_tcpip_core;
sys_mutex_t lock_tcpip_core;
#endif /* LWIP_TCPIP_CORE_LOCKING */
#if LWIP_TCP
/* global variable that shows if the tcp timer is currently scheduled or not */
static int tcpip_tcp_timer_active;
/**
* Timer callback function that calls tcp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
tcpip_tcp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
/* call TCP timer handler */
tcp_tmr();
/* timer still needed? */
if (tcp_active_pcbs || tcp_tw_pcbs) {
/* restart timer */
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
} else {
/* disable timer */
tcpip_tcp_timer_active = 0;
}
}
#if !NO_SYS
/**
* Called from TCP_REG when registering a new PCB:
* the reason is to have the TCP timer only running when
* there are active (or time-wait) PCBs.
*/
void
tcp_timer_needed(void)
{
/* timer is off but needed again? */
if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
/* enable and start timer */
tcpip_tcp_timer_active = 1;
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
}
}
#endif /* !NO_SYS */
#endif /* LWIP_TCP */
#if IP_REASSEMBLY
/**
* Timer callback function that calls ip_reass_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
ip_reass_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n"));
ip_reass_tmr();
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
}
#endif /* IP_REASSEMBLY */
#if LWIP_ARP
/**
* Timer callback function that calls etharp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
arp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: etharp_tmr()\n"));
etharp_tmr();
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
}
#endif /* LWIP_ARP */
#if LWIP_DHCP
/**
* Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dhcp_timer_coarse(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
dhcp_coarse_tmr();
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
}
/**
* Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dhcp_timer_fine(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
dhcp_fine_tmr();
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
}
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
/**
* Timer callback function that calls autoip_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
autoip_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: autoip_tmr()\n"));
autoip_tmr();
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
}
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
/**
* Timer callback function that calls igmp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
igmp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: igmp_tmr()\n"));
igmp_tmr();
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
}
#endif /* LWIP_IGMP */
#if LWIP_DNS
/**
* Timer callback function that calls dns_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dns_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dns_tmr()\n"));
dns_tmr();
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
}
#endif /* LWIP_DNS */
/**
* The main lwIP thread. This thread has exclusive access to lwIP core functions
@ -235,33 +76,17 @@ tcpip_thread(void *arg)
struct tcpip_msg *msg;
LWIP_UNUSED_ARG(arg);
#if IP_REASSEMBLY
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
#endif /* IP_REASSEMBLY */
#if LWIP_ARP
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
#endif /* LWIP_ARP */
#if LWIP_DHCP
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
#endif /* LWIP_IGMP */
#if LWIP_DNS
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
#endif /* LWIP_DNS */
if (tcpip_init_done != NULL) {
tcpip_init_done(tcpip_init_done_arg);
}
LOCK_TCPIP_CORE();
while (1) { /* MAIN Loop */
sys_mbox_fetch(mbox, (void *)&msg);
UNLOCK_TCPIP_CORE();
LWIP_TCPIP_THREAD_ALIVE();
/* wait for a message, timeouts are processed while waiting */
sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
LOCK_TCPIP_CORE();
switch (msg->type) {
#if LWIP_NETCONN
case TCPIP_MSG_API:
@ -270,17 +95,20 @@ tcpip_thread(void *arg)
break;
#endif /* LWIP_NETCONN */
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
case TCPIP_MSG_INPKT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
#if LWIP_ARP
if (msg->msg.inp.netif->flags & NETIF_FLAG_ETHARP) {
#if LWIP_ETHERNET
if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
} else
#endif /* LWIP_ARP */
{ ip_input(msg->msg.inp.p, msg->msg.inp.netif);
#endif /* LWIP_ETHERNET */
{
ip_input(msg->msg.inp.p, msg->msg.inp.netif);
}
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
break;
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
#if LWIP_NETIF_API
case TCPIP_MSG_NETIFAPI:
@ -291,10 +119,11 @@ tcpip_thread(void *arg)
case TCPIP_MSG_CALLBACK:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
msg->msg.cb.f(msg->msg.cb.ctx);
msg->msg.cb.function(msg->msg.cb.ctx);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
#if LWIP_TCPIP_TIMEOUT
case TCPIP_MSG_TIMEOUT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
@ -305,8 +134,11 @@ tcpip_thread(void *arg)
sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
#endif /* LWIP_TCPIP_TIMEOUT */
default:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
LWIP_ASSERT("tcpip_thread: invalid message", 0);
break;
}
}
@ -316,16 +148,32 @@ tcpip_thread(void *arg)
* Pass a received packet to tcpip_thread for input processing
*
* @param p the received packet, p->payload pointing to the Ethernet header or
* to an IP header (if netif doesn't got NETIF_FLAG_ETHARP flag)
* to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or
* NETIF_FLAG_ETHERNET flags)
* @param inp the network interface on which the packet was received
*/
err_t
tcpip_input(struct pbuf *p, struct netif *inp)
{
#if LWIP_TCPIP_CORE_LOCKING_INPUT
err_t ret;
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp));
LOCK_TCPIP_CORE();
#if LWIP_ETHERNET
if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
ret = ethernet_input(p, inp);
} else
#endif /* LWIP_ETHERNET */
{
ret = ip_input(p, inp);
}
UNLOCK_TCPIP_CORE();
return ret;
#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
struct tcpip_msg *msg;
if (mbox != SYS_MBOX_NULL) {
msg = memp_malloc(MEMP_TCPIP_MSG_INPKT);
if (sys_mbox_valid(&mbox)) {
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
if (msg == NULL) {
return ERR_MEM;
}
@ -333,13 +181,14 @@ tcpip_input(struct pbuf *p, struct netif *inp)
msg->type = TCPIP_MSG_INPKT;
msg->msg.inp.p = p;
msg->msg.inp.netif = inp;
if (sys_mbox_trypost(mbox, msg) != ERR_OK) {
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
return ERR_MEM;
}
return ERR_OK;
}
return ERR_VAL;
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
}
/**
@ -354,23 +203,23 @@ tcpip_input(struct pbuf *p, struct netif *inp)
* @return ERR_OK if the function was called, another err_t if not
*/
err_t
tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block)
tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
{
struct tcpip_msg *msg;
if (mbox != SYS_MBOX_NULL) {
msg = memp_malloc(MEMP_TCPIP_MSG_API);
if (sys_mbox_valid(&mbox)) {
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_CALLBACK;
msg->msg.cb.f = f;
msg->msg.cb.function = function;
msg->msg.cb.ctx = ctx;
if (block) {
sys_mbox_post(mbox, msg);
sys_mbox_post(&mbox, msg);
} else {
if (sys_mbox_trypost(mbox, msg) != ERR_OK) {
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_API, msg);
return ERR_MEM;
}
@ -380,10 +229,11 @@ tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block)
return ERR_VAL;
}
#if LWIP_TCPIP_TIMEOUT
/**
* call sys_timeout in tcpip_thread
*
* @param msec time in miliseconds for timeout
* @param msec time in milliseconds for timeout
* @param h function to be called on timeout
* @param arg argument to pass to timeout function h
* @return ERR_MEM on memory error, ERR_OK otherwise
@ -393,8 +243,8 @@ tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
{
struct tcpip_msg *msg;
if (mbox != SYS_MBOX_NULL) {
msg = memp_malloc(MEMP_TCPIP_MSG_API);
if (sys_mbox_valid(&mbox)) {
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
}
@ -403,7 +253,7 @@ tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
msg->msg.tmo.msecs = msecs;
msg->msg.tmo.h = h;
msg->msg.tmo.arg = arg;
sys_mbox_post(mbox, msg);
sys_mbox_post(&mbox, msg);
return ERR_OK;
}
return ERR_VAL;
@ -412,7 +262,7 @@ tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
/**
* call sys_untimeout in tcpip_thread
*
* @param msec time in miliseconds for timeout
* @param msec time in milliseconds for timeout
* @param h function to be called on timeout
* @param arg argument to pass to timeout function h
* @return ERR_MEM on memory error, ERR_OK otherwise
@ -422,8 +272,8 @@ tcpip_untimeout(sys_timeout_handler h, void *arg)
{
struct tcpip_msg *msg;
if (mbox != SYS_MBOX_NULL) {
msg = memp_malloc(MEMP_TCPIP_MSG_API);
if (sys_mbox_valid(&mbox)) {
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
}
@ -431,11 +281,12 @@ tcpip_untimeout(sys_timeout_handler h, void *arg)
msg->type = TCPIP_MSG_UNTIMEOUT;
msg->msg.tmo.h = h;
msg->msg.tmo.arg = arg;
sys_mbox_post(mbox, msg);
sys_mbox_post(&mbox, msg);
return ERR_OK;
}
return ERR_VAL;
}
#endif /* LWIP_TCPIP_TIMEOUT */
#if LWIP_NETCONN
/**
@ -450,13 +301,17 @@ err_t
tcpip_apimsg(struct api_msg *apimsg)
{
struct tcpip_msg msg;
#ifdef LWIP_DEBUG
/* catch functions that don't set err */
apimsg->msg.err = ERR_VAL;
#endif
if (mbox != SYS_MBOX_NULL) {
if (sys_mbox_valid(&mbox)) {
msg.type = TCPIP_MSG_API;
msg.msg.apimsg = apimsg;
sys_mbox_post(mbox, &msg);
sys_arch_sem_wait(apimsg->msg.conn->op_completed, 0);
return ERR_OK;
sys_mbox_post(&mbox, &msg);
sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0);
return apimsg->msg.err;
}
return ERR_VAL;
}
@ -473,10 +328,15 @@ tcpip_apimsg(struct api_msg *apimsg)
err_t
tcpip_apimsg_lock(struct api_msg *apimsg)
{
#ifdef LWIP_DEBUG
/* catch functions that don't set err */
apimsg->msg.err = ERR_VAL;
#endif
LOCK_TCPIP_CORE();
apimsg->function(&(apimsg->msg));
UNLOCK_TCPIP_CORE();
return ERR_OK;
return apimsg->msg.err;
}
#endif /* LWIP_TCPIP_CORE_LOCKING */
@ -496,18 +356,18 @@ tcpip_netifapi(struct netifapi_msg* netifapimsg)
{
struct tcpip_msg msg;
if (mbox != SYS_MBOX_NULL) {
netifapimsg->msg.sem = sys_sem_new(0);
if (netifapimsg->msg.sem == SYS_SEM_NULL) {
netifapimsg->msg.err = ERR_MEM;
return netifapimsg->msg.err;
if (sys_mbox_valid(&mbox)) {
err_t err = sys_sem_new(&netifapimsg->msg.sem, 0);
if (err != ERR_OK) {
netifapimsg->msg.err = err;
return err;
}
msg.type = TCPIP_MSG_NETIFAPI;
msg.msg.netifapimsg = netifapimsg;
sys_mbox_post(mbox, &msg);
sys_sem_wait(netifapimsg->msg.sem);
sys_sem_free(netifapimsg->msg.sem);
sys_mbox_post(&mbox, &msg);
sys_sem_wait(&netifapimsg->msg.sem);
sys_sem_free(&netifapimsg->msg.sem);
return netifapimsg->msg.err;
}
return ERR_VAL;
@ -541,15 +401,19 @@ tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
* @param arg argument to pass to initfunc
*/
void
tcpip_init(void (* initfunc)(void *), void *arg)
tcpip_init(tcpip_init_done_fn initfunc, void *arg)
{
lwip_init();
tcpip_init_done = initfunc;
tcpip_init_done_arg = arg;
mbox = sys_mbox_new(TCPIP_MBOX_SIZE);
if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
}
#if LWIP_TCPIP_CORE_LOCKING
lock_tcpip_core = sys_sem_new(1);
if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
LWIP_ASSERT("failed to create lock_tcpip_core", 0);
}
#endif /* LWIP_TCPIP_CORE_LOCKING */
sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
@ -564,7 +428,7 @@ tcpip_init(void (* initfunc)(void *), void *arg)
static void
pbuf_free_int(void *p)
{
struct pbuf *q = p;
struct pbuf *q = (struct pbuf *)p;
pbuf_free(q);
}

4
lwip/src/arch/Makefile Normal file
View file

@ -0,0 +1,4 @@
C_source := sys_arch.c
MODULE := lwip_src_arch
include $(TOPDIR)/Makefile.inc

43
lwip/src/arch/sys_arch.c Normal file
View file

@ -0,0 +1,43 @@
/*
* Copyright 2010 Stefan Lankes, Chair for Operating Systems,
* RWTH Aachen University
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of MetalSVM.
*/
#include <metalsvm/stddef.h>
#include <metalsvm/time.h>
#include "lwip/debug.h"
#include "lwip/sys.h"
#include "lwip/opt.h"
#include "lwip/stats.h"
void sys_init(void)
{
}
/** Returns the current time in milliseconds,
* may be the same as sys_jiffies or at least based on it. */
u32_t
sys_now(void)
{
return (get_clock_tick() / TIMER_FREQ) * 1000;
}
u32_t
sys_jiffies(void)
{
return (get_clock_tick() / TIMER_FREQ) * 1000;
}

View file

@ -1,4 +1,4 @@
C_source := dhcp.c raw.c init.c mem.c memp.c netif.c pbuf.c stats.c udp.c tcp.c tcp_in.c tcp_out.c
C_source := dhcp.c raw.c init.c mem.c memp.c netif.c pbuf.c stats.c udp.c tcp.c tcp_in.c tcp_out.c def.c timers.c
MODULE := lwip_src_core
include $(TOPDIR)/Makefile.inc

108
lwip/src/core/def.c Normal file
View file

@ -0,0 +1,108 @@
/**
* @file
* Common functions used throughout the stack.
*
*/
/*
* Copyright (c) 2001-2004 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: Simon Goldschmidt
*
*/
#include "lwip/opt.h"
#include "lwip/def.h"
/**
* These are reference implementations of the byte swapping functions.
* Again with the aim of being simple, correct and fully portable.
* Byte swapping is the second thing you would want to optimize. You will
* need to port it to your architecture and in your cc.h:
*
* #define LWIP_PLATFORM_BYTESWAP 1
* #define LWIP_PLATFORM_HTONS(x) <your_htons>
* #define LWIP_PLATFORM_HTONL(x) <your_htonl>
*
* Note ntohs() and ntohl() are merely references to the htonx counterparts.
*/
#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)
/**
* Convert an u16_t from host- to network byte order.
*
* @param n u16_t in host byte order
* @return n in network byte order
*/
u16_t
lwip_htons(u16_t n)
{
return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
}
/**
* Convert an u16_t from network- to host byte order.
*
* @param n u16_t in network byte order
* @return n in host byte order
*/
u16_t
lwip_ntohs(u16_t n)
{
return lwip_htons(n);
}
/**
* Convert an u32_t from host- to network byte order.
*
* @param n u32_t in host byte order
* @return n in network byte order
*/
u32_t
lwip_htonl(u32_t n)
{
return ((n & 0xff) << 24) |
((n & 0xff00) << 8) |
((n & 0xff0000UL) >> 8) |
((n & 0xff000000UL) >> 24);
}
/**
* Convert an u32_t from network- to host byte order.
*
* @param n u32_t in network byte order
* @return n in host byte order
*/
u32_t
lwip_ntohl(u32_t n)
{
return lwip_htonl(n);
}
#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */

File diff suppressed because it is too large Load diff

View file

@ -78,13 +78,14 @@
#include "lwip/udp.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/dns.h"
#include <string.h>
/** DNS server IP address */
#ifndef DNS_SERVER_ADDRESS
#define DNS_SERVER_ADDRESS inet_addr("208.67.222.222") /* resolver1.opendns.com */
#define DNS_SERVER_ADDRESS(ipaddr) (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */
#endif
/** DNS server port address */
@ -141,40 +142,26 @@ PACK_STRUCT_END
#endif
#define SIZEOF_DNS_HDR 12
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** DNS query message structure */
/** DNS query message structure.
No packing needed: only used locally on the stack. */
struct dns_query {
/* DNS query record starts with either a domain name or a pointer
to a name already present somewhere in the packet. */
PACK_STRUCT_FIELD(u16_t type);
PACK_STRUCT_FIELD(u16_t class);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
u16_t type;
u16_t cls;
};
#define SIZEOF_DNS_QUERY 4
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** DNS answer message structure */
/** DNS answer message structure.
No packing needed: only used locally on the stack. */
struct dns_answer {
/* DNS answer record starts with either a domain name or a pointer
to a name already present somewhere in the packet. */
PACK_STRUCT_FIELD(u16_t type);
PACK_STRUCT_FIELD(u16_t class);
PACK_STRUCT_FIELD(u32_t ttl);
PACK_STRUCT_FIELD(u16_t len);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
u16_t type;
u16_t cls;
u32_t ttl;
u16_t len;
};
#define SIZEOF_DNS_ANSWER 10
/** DNS table entry */
@ -187,21 +174,13 @@ struct dns_table_entry {
u8_t err;
u32_t ttl;
char name[DNS_MAX_NAME_LENGTH];
struct ip_addr ipaddr;
ip_addr_t ipaddr;
/* pointer to callback on DNS query done */
dns_found_callback found;
void *arg;
};
#if DNS_LOCAL_HOSTLIST
/** struct used for local host-list */
struct local_hostlist_entry {
/** static hostname */
const char *name;
/** static host address in network byteorder */
u32_t addr;
struct local_hostlist_entry *next;
};
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
/** Local host-list. For hostnames in this list, no
@ -229,7 +208,7 @@ static void dns_init_local();
/* forward declarations */
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
static void dns_check_entries(void);
/*-----------------------------------------------------------------------------
@ -240,11 +219,10 @@ static void dns_check_entries(void);
static struct udp_pcb *dns_pcb;
static u8_t dns_seqno;
static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
static struct ip_addr dns_servers[DNS_MAX_SERVERS];
#if (DNS_USES_STATIC_BUF == 1)
static u8_t dns_payload[DNS_MSG_SIZE];
#endif /* (DNS_USES_STATIC_BUF == 1) */
static ip_addr_t dns_servers[DNS_MAX_SERVERS];
/** Contiguous buffer for processing responses */
static u8_t dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)];
static u8_t* dns_payload;
/**
* Initialize the resolver: set up the UDP pcb and configure the default server
@ -253,10 +231,12 @@ static u8_t dns_payload[DNS_MSG_SIZE];
void
dns_init()
{
struct ip_addr dnsserver;
ip_addr_t dnsserver;
dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);
/* initialize default DNS server address */
dnsserver.addr = DNS_SERVER_ADDRESS;
DNS_SERVER_ADDRESS(&dnsserver);
LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
@ -290,10 +270,10 @@ dns_init()
* @param dnsserver IP address of the DNS server to set
*/
void
dns_setserver(u8_t numdns, struct ip_addr *dnsserver)
dns_setserver(u8_t numdns, ip_addr_t *dnsserver)
{
if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
(dnsserver != NULL) && (dnsserver->addr !=0 )) {
(dnsserver != NULL) && !ip_addr_isany(dnsserver)) {
dns_servers[numdns] = (*dnsserver);
}
}
@ -305,7 +285,7 @@ dns_setserver(u8_t numdns, struct ip_addr *dnsserver)
* @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
* server has not been configured.
*/
struct ip_addr
ip_addr_t
dns_getserver(u8_t numdns)
{
if (numdns < DNS_MAX_SERVERS) {
@ -337,12 +317,18 @@ dns_init_local()
struct local_hostlist_entry *entry;
/* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
size_t namelen;
for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
entry = mem_malloc(sizeof(struct local_hostlist_entry));
struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL);
namelen = strlen(init_entry->name);
LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
if (entry != NULL) {
struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
entry->name = init_entry->name;
entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
MEMCPY((char*)entry->name, init_entry->name, namelen);
((char*)entry->name)[namelen] = 0;
entry->addr = init_entry->addr;
entry->next = local_hostlist_dynamic;
local_hostlist_dynamic = entry;
@ -356,7 +342,7 @@ dns_init_local()
*
* @param hostname Hostname to look for in the local host-list
* @return The first IP address for the hostname in the local host-list or
* INADDR_NONE if not found.
* IPADDR_NONE if not found.
*/
static u32_t
dns_lookup_local(const char *hostname)
@ -365,7 +351,7 @@ dns_lookup_local(const char *hostname)
struct local_hostlist_entry *entry = local_hostlist_dynamic;
while(entry != NULL) {
if(strcmp(entry->name, hostname) == 0) {
return entry->addr;
return ip4_addr_get_u32(&entry->addr);
}
entry = entry->next;
}
@ -373,11 +359,11 @@ dns_lookup_local(const char *hostname)
int i;
for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
return local_hostlist_static[i].addr;
return ip4_addr_get_u32(&local_hostlist_static[i].addr);
}
}
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
return INADDR_NONE;
return IPADDR_NONE;
}
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
@ -390,14 +376,14 @@ dns_lookup_local(const char *hostname)
* @return the number of removed entries
*/
int
dns_local_removehost(const char *hostname, const struct ip_addr *addr)
dns_local_removehost(const char *hostname, const ip_addr_t *addr)
{
int removed = 0;
struct local_hostlist_entry *entry = local_hostlist_dynamic;
struct local_hostlist_entry *last_entry = NULL;
while (entry != NULL) {
if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&
((addr == NULL) || (entry->addr == addr->addr))) {
((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
struct local_hostlist_entry *free_entry;
if (last_entry != NULL) {
last_entry->next = entry->next;
@ -406,7 +392,7 @@ dns_local_removehost(const char *hostname, const struct ip_addr *addr)
}
free_entry = entry;
entry = entry->next;
mem_free(free_entry);
memp_free(MEMP_LOCALHOSTLIST, free_entry);
removed++;
} else {
last_entry = entry;
@ -425,15 +411,21 @@ dns_local_removehost(const char *hostname, const struct ip_addr *addr)
* @return ERR_OK if succeeded or ERR_MEM on memory error
*/
err_t
dns_local_addhost(const char *hostname, const struct ip_addr *addr)
dns_local_addhost(const char *hostname, const ip_addr_t *addr)
{
struct local_hostlist_entry *entry;
entry = mem_malloc(sizeof(struct local_hostlist_entry));
size_t namelen;
LWIP_ASSERT("invalid host name (NULL)", hostname != NULL);
namelen = strlen(hostname);
LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
if (entry == NULL) {
return ERR_MEM;
}
entry->name = hostname;
entry->addr = addr->addr;
entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
MEMCPY((char*)entry->name, hostname, namelen);
((char*)entry->name)[namelen] = 0;
ip_addr_copy(entry->addr, *addr);
entry->next = local_hostlist_dynamic;
local_hostlist_dynamic = entry;
return ERR_OK;
@ -450,8 +442,8 @@ dns_local_addhost(const char *hostname, const struct ip_addr *addr)
* for a hostname.
*
* @param name the hostname to look up
* @return the hostname's IP address, as u32_t (instead of struct ip_addr to
* better check for failure: != INADDR_NONE) or INADDR_NONE if the hostname
* @return the hostname's IP address, as u32_t (instead of ip_addr_t to
* better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname
* was not found in the cached dns_table.
*/
static u32_t
@ -462,12 +454,12 @@ dns_lookup(const char *name)
u32_t addr;
#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
#if DNS_LOCAL_HOSTLIST
if ((addr = dns_lookup_local(name)) != INADDR_NONE) {
if ((addr = dns_lookup_local(name)) != IPADDR_NONE) {
return addr;
}
#endif /* DNS_LOCAL_HOSTLIST */
#ifdef DNS_LOOKUP_LOCAL_EXTERN
if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != INADDR_NONE) {
if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) {
return addr;
}
#endif /* DNS_LOOKUP_LOCAL_EXTERN */
@ -479,11 +471,11 @@ dns_lookup(const char *name)
LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
LWIP_DEBUGF(DNS_DEBUG, ("\n"));
return dns_table[i].ipaddr.addr;
return ip4_addr_get_u32(&dns_table[i].ipaddr);
}
}
return INADDR_NONE;
return IPADDR_NONE;
}
#if DNS_DOES_NAME_CHECK
@ -578,7 +570,7 @@ dns_send(u8_t numdns, const char* name, u8_t id)
LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
(u16_t)(numdns), name));
LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);
LWIP_ASSERT("dns server has no IP address set", dns_servers[numdns].addr != 0);
LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns]));
/* if here, we have either a new query or a retry on a previous query to process */
p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
@ -590,7 +582,7 @@ dns_send(u8_t numdns, const char* name, u8_t id)
memset(hdr, 0, SIZEOF_DNS_HDR);
hdr->id = htons(id);
hdr->flags1 = DNS_FLAG1_RD;
hdr->numquestions = htons(1);
hdr->numquestions = PP_HTONS(1);
query = (char*)hdr + SIZEOF_DNS_HDR;
pHostname = name;
--pHostname;
@ -610,12 +602,12 @@ dns_send(u8_t numdns, const char* name, u8_t id)
*query++='\0';
/* fill dns query */
qry.type = htons(DNS_RRTYPE_A);
qry.class = htons(DNS_RRCLASS_IN);
MEMCPY( query, &qry, SIZEOF_DNS_QUERY);
qry.type = PP_HTONS(DNS_RRTYPE_A);
qry.cls = PP_HTONS(DNS_RRCLASS_IN);
SMEMCPY(query, &qry, SIZEOF_DNS_QUERY);
/* resize pbuf to the exact dns query */
pbuf_realloc(p, (query + SIZEOF_DNS_QUERY) - ((char*)(p->payload)));
pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))));
/* connect to the server for faster receiving */
udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
@ -643,6 +635,7 @@ dns_send(u8_t numdns, const char* name, u8_t id)
static void
dns_check_entry(u8_t i)
{
err_t err;
struct dns_table_entry *pEntry = &dns_table[i];
LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
@ -657,14 +650,18 @@ dns_check_entry(u8_t i)
pEntry->retries = 0;
/* send DNS packet for this entry */
dns_send(pEntry->numdns, pEntry->name, i);
err = dns_send(pEntry->numdns, pEntry->name, i);
if (err != ERR_OK) {
LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
("dns_send returned error: %s\n", lwip_strerr(err)));
}
break;
}
case DNS_STATE_ASKING: {
if (--pEntry->tmr == 0) {
if (++pEntry->retries == DNS_MAX_RETRIES) {
if ((pEntry->numdns+1<DNS_MAX_SERVERS) && (dns_servers[pEntry->numdns+1].addr!=0)) {
if ((pEntry->numdns+1<DNS_MAX_SERVERS) && !ip_addr_isany(&dns_servers[pEntry->numdns+1])) {
/* change of server */
pEntry->numdns++;
pEntry->tmr = 1;
@ -686,7 +683,11 @@ dns_check_entry(u8_t i)
pEntry->tmr = pEntry->retries;
/* send DNS packet for this entry */
dns_send(pEntry->numdns, pEntry->name, i);
err = dns_send(pEntry->numdns, pEntry->name, i);
if (err != ERR_OK) {
LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
("dns_send returned error: %s\n", lwip_strerr(err)));
}
}
break;
}
@ -729,20 +730,14 @@ dns_check_entries(void)
* @params see udp.h
*/
static void
dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
{
u8_t i;
u16_t i;
char *pHostname;
struct dns_hdr *hdr;
struct dns_answer ans;
struct dns_table_entry *pEntry;
u8_t nquestions, nanswers;
#if (DNS_USES_STATIC_BUF == 0)
u8_t dns_payload[DNS_MSG_SIZE];
#endif /* (DNS_USES_STATIC_BUF == 0) */
#if (DNS_USES_STATIC_BUF == 2)
u8_t* dns_payload;
#endif /* (DNS_USES_STATIC_BUF == 2) */
u16_t nquestions, nanswers;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(pcb);
@ -753,25 +748,16 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
if (p->tot_len > DNS_MSG_SIZE) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
/* free pbuf and return */
goto memerr1;
goto memerr;
}
/* is the dns message big enough ? */
if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
/* free pbuf and return */
goto memerr1;
goto memerr;
}
#if (DNS_USES_STATIC_BUF == 2)
dns_payload = mem_malloc(p->tot_len);
if (dns_payload == NULL) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: mem_malloc error\n"));
/* free pbuf and return */
goto memerr1;
}
#endif /* (DNS_USES_STATIC_BUF == 2) */
/* copy dns payload inside static buffer for processing */
if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
/* The ID in the DNS header should be our entry into the name table. */
@ -808,20 +794,21 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
/* Skip the name in the "question" part */
pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;
while(nanswers > 0) {
while (nanswers > 0) {
/* skip answer resource record's host name */
pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
/* Check for IP address type and Internet class. Others are discarded. */
MEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
if((ntohs(ans.type) == DNS_RRTYPE_A) && (ntohs(ans.class) == DNS_RRCLASS_IN) && (ntohs(ans.len) == sizeof(struct ip_addr)) ) {
SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) &&
(ans.len == PP_HTONS(sizeof(ip_addr_t))) ) {
/* read the answer resource record's TTL, and maximize it if needed */
pEntry->ttl = ntohl(ans.ttl);
if (pEntry->ttl > DNS_MAX_TTL) {
pEntry->ttl = DNS_MAX_TTL;
}
/* read the IP address after answer resource record's header */
MEMCPY( &(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(struct ip_addr));
SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t));
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
LWIP_DEBUGF(DNS_DEBUG, ("\n"));
@ -830,7 +817,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
(*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
}
/* deallocate memory and return */
goto memerr2;
goto memerr;
} else {
pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
}
@ -844,7 +831,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
}
/* deallocate memory and return */
goto memerr2;
goto memerr;
responseerr:
/* ERROR: call specified callback function with NULL as name to indicate an error */
@ -855,13 +842,7 @@ responseerr:
pEntry->state = DNS_STATE_UNUSED;
pEntry->found = NULL;
memerr2:
#if (DNS_USES_STATIC_BUF == 2)
/* free dns buffer */
mem_free(dns_payload);
#endif /* (DNS_USES_STATIC_BUF == 2) */
memerr1:
memerr:
/* free pbuf */
pbuf_free(p);
return;
@ -881,6 +862,7 @@ dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
u8_t i;
u8_t lseq, lseqi;
struct dns_table_entry *pEntry = NULL;
size_t namelen;
/* search an unused entry, or the oldest one */
lseq = lseqi = 0;
@ -920,7 +902,9 @@ dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
pEntry->seqno = dns_seqno++;
pEntry->found = found;
pEntry->arg = callback_arg;
strcpy(pEntry->name, name);
namelen = LWIP_MIN(strlen(name), DNS_MAX_NAME_LENGTH-1);
MEMCPY(pEntry->name, name, namelen);
pEntry->name[namelen] = 0;
/* force to send query without waiting timer */
dns_check_entry(i);
@ -938,9 +922,10 @@ dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
* name is already in the local names table.
* - ERR_INPROGRESS enqueue a request to be sent to the DNS server
* for resolution if no errors are present.
* - ERR_ARG: dns client not initialized or invalid hostname
*
* @param hostname the hostname that is to be queried
* @param addr pointer to a struct ip_addr where to store the address if it is already
* @param addr pointer to a ip_addr_t where to store the address if it is already
* cached in the dns_table (only valid if ERR_OK is returned!)
* @param found a callback function to be called on success, failure or timeout (only if
* ERR_INPROGRESS is returned!)
@ -948,28 +933,33 @@ dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
* @return a err_t return code.
*/
err_t
dns_gethostbyname(const char *hostname, struct ip_addr *addr, dns_found_callback found,
dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,
void *callback_arg)
{
u32_t ipaddr;
/* not initialized or no valid server yet, or invalid addr pointer
* or invalid hostname or invalid hostname length */
if ((dns_pcb == NULL) || (addr == NULL) ||
(!hostname) || (!hostname[0]) ||
(strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
return ERR_VAL;
return ERR_ARG;
}
#if LWIP_HAVE_LOOPIF
if (strcmp(hostname,"localhost")==0) {
addr->addr = htonl(INADDR_LOOPBACK);
if (strcmp(hostname, "localhost")==0) {
ip_addr_set_loopback(addr);
return ERR_OK;
}
#endif /* LWIP_HAVE_LOOPIF */
/* host name already in octet notation? set ip addr and return ERR_OK
* already have this address cached? */
if (((addr->addr = inet_addr(hostname)) != INADDR_NONE) ||
((addr->addr = dns_lookup(hostname)) != INADDR_NONE)) {
/* host name already in octet notation? set ip addr and return ERR_OK */
ipaddr = ipaddr_addr(hostname);
if (ipaddr == IPADDR_NONE) {
/* already have this address cached? */
ipaddr = dns_lookup(hostname);
}
if (ipaddr != IPADDR_NONE) {
ip4_addr_set_u32(addr, ipaddr);
return ERR_OK;
}

View file

@ -49,11 +49,12 @@
#include "lwip/ip.h"
#include "lwip/raw.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/tcp_impl.h"
#include "lwip/snmp_msg.h"
#include "lwip/autoip.h"
#include "lwip/igmp.h"
#include "lwip/dns.h"
#include "lwip/timers.h"
#include "netif/etharp.h"
/* Compile-time sanity checks for configuration errors.
@ -80,12 +81,12 @@
#if (!LWIP_UDP && LWIP_IGMP)
#error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h"
#endif
#if (!LWIP_UDP && LWIP_SNMP)
#error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
#endif
#if (!LWIP_UDP && LWIP_DNS)
#error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h"
#endif
#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))
#error "If you want to use ARP, ARP_TABLE_SIZE must fit in an s8_t, so, you have to reduce it in your lwipopts.h"
#endif
#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0))
#error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h"
#endif
@ -104,6 +105,9 @@
#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff))
#error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
#endif
#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2))
#error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work"
#endif
#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12)))
#error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h"
#endif
@ -113,9 +117,6 @@
#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))
#error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"
#endif
#if (PPP_SUPPORT && (NO_SYS==1))
#error "If you want to use PPP, you have to define NO_SYS=0 in your lwipopts.h"
#endif
#if (LWIP_NETIF_API && (NO_SYS==1))
#error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h"
#endif
@ -147,7 +148,7 @@
#error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h"
#endif
/* There must be sufficient timeouts, taking into account requirements of the subsystems. */
#if ((NO_SYS==0) && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT)))
#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT))
#error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts"
#endif
#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))
@ -171,6 +172,21 @@
#if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT
#error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on"
#endif
#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT)
#error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT"
#endif
#if LWIP_IGMP && !defined(LWIP_RAND)
#error "When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value"
#endif
#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING
#error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too"
#endif
#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE
#error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets"
#endif
#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF
#error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues"
#endif
/* Compile-time checks for deprecated options.
@ -193,11 +209,6 @@
#ifdef ETHARP_ALWAYS_INSERT
#error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h."
#endif
#if SO_REUSE
/* I removed the lot since this was an ugly hack. It broke the raw-API.
It also came with many ugly goto's, Christiaan Simons. */
#error "SO_REUSE currently unavailable, this was a hack"
#endif
#ifdef LWIP_DEBUG
static void
@ -215,13 +226,28 @@ lwip_sanity_check(void)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly\n"));
if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS)))
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n"));
if (TCP_SNDLOWAT > TCP_SND_BUF)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than or equal to TCP_SND_BUF.\n"));
if (TCP_SNDLOWAT >= TCP_SND_BUF)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF.\n"));
if (TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN.\n"));
if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE))
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n"));
if (TCP_WND < TCP_MSS)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n"));
#endif /* LWIP_TCP */
#if LWIP_SOCKET
/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */
if (SO_ACCEPTCONN != SOF_ACCEPTCONN)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_ACCEPTCONN != SOF_ACCEPTCONN\n"));
if (SO_REUSEADDR != SOF_REUSEADDR)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_REUSEADDR != SOF_REUSEADDR\n"));
if (SO_KEEPALIVE != SOF_KEEPALIVE)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_KEEPALIVE != SOF_KEEPALIVE\n"));
if (SO_BROADCAST != SOF_BROADCAST)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_BROADCAST != SOF_BROADCAST\n"));
if (SO_LINGER != SOF_LINGER)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_LINGER != SOF_LINGER\n"));
#endif /* LWIP_SOCKET */
}
#else /* LWIP_DEBUG */
#define lwip_sanity_check()
@ -238,7 +264,9 @@ lwip_init(void)
/* Modules initialization */
stats_init();
#if !NO_SYS
sys_init();
#endif /* !NO_SYS */
mem_init();
memp_init();
pbuf_init();
@ -271,4 +299,8 @@ lwip_init(void)
#if LWIP_DNS
dns_init();
#endif /* LWIP_DNS */
#if LWIP_TIMERS
sys_timeouts_init();
#endif /* LWIP_TIMERS */
}

View file

@ -108,7 +108,7 @@
static void autoip_handle_arp_conflict(struct netif *netif);
/* creates a pseudo random LL IP-Address for a network interface */
static void autoip_create_addr(struct netif *netif, struct ip_addr *ipaddr);
static void autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr);
/* sends an ARP probe */
static err_t autoip_arp_probe(struct netif *netif);
@ -131,6 +131,36 @@ autoip_init(void)
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n"));
}
/** Set a statically allocated struct autoip to work with.
* Using this prevents autoip_start to allocate it using mem_malloc.
*
* @param netif the netif for which to set the struct autoip
* @param dhcp (uninitialised) dhcp struct allocated by the application
*/
void
autoip_set_struct(struct netif *netif, struct autoip *autoip)
{
LWIP_ASSERT("netif != NULL", netif != NULL);
LWIP_ASSERT("autoip != NULL", autoip != NULL);
LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL);
/* clear data structure */
memset(autoip, 0, sizeof(struct autoip));
/* autoip->state = AUTOIP_STATE_OFF; */
netif->autoip = autoip;
}
/** Restart AutoIP client and check the next address (conflict detected)
*
* @param netif The netif under AutoIP control
*/
static void
autoip_restart(struct netif *netif)
{
netif->autoip->tried_llipaddr++;
autoip_start(netif);
}
/**
* Handle a IP address conflict after an ARP conflict detection
*/
@ -149,7 +179,7 @@ autoip_handle_arp_conflict(struct netif *netif)
("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
/* TODO: close all TCP sessions */
autoip_start(netif);
autoip_restart(netif);
} else {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
@ -160,7 +190,7 @@ autoip_handle_arp_conflict(struct netif *netif)
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_handle_arp_conflict(): we do not defend, retreating\n"));
/* TODO: close all TCP sessions */
autoip_start(netif);
autoip_restart(netif);
}
}
@ -171,7 +201,7 @@ autoip_handle_arp_conflict(struct netif *netif)
* @param ipaddr ip address to initialize
*/
static void
autoip_create_addr(struct netif *netif, struct ip_addr *ipaddr)
autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr)
{
/* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255
* compliant to RFC 3927 Section 2.1
@ -190,11 +220,12 @@ autoip_create_addr(struct netif *netif, struct ip_addr *ipaddr)
}
LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
(addr <= AUTOIP_RANGE_END));
ipaddr->addr = htonl(addr);
ip4_addr_set_u32(ipaddr, htonl(addr));
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_create_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n",
(u16_t)(netif->autoip->tried_llipaddr), (u32_t)(ipaddr->addr)));
("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
(u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr),
ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
}
/**
@ -232,11 +263,13 @@ static err_t
autoip_bind(struct netif *netif)
{
struct autoip *autoip = netif->autoip;
struct ip_addr sn_mask, gw_addr;
ip_addr_t sn_mask, gw_addr;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_bind(netif=%p) %c%c%"U16_F" 0x%08"X32_F"\n",
(void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, autoip->llipaddr.addr));
("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
(void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num,
ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
IP4_ADDR(&sn_mask, 255, 255, 0, 0);
IP4_ADDR(&gw_addr, 0, 0, 0, 0);
@ -269,9 +302,9 @@ autoip_start(struct netif *netif)
/* Set IP-Address, Netmask and Gateway to 0 to make sure that
* ARP Packets are formed correctly
*/
netif->ip_addr.addr = 0;
netif->netmask.addr = 0;
netif->gw.addr = 0;
ip_addr_set_zero(&netif->ip_addr);
ip_addr_set_zero(&netif->netmask);
ip_addr_set_zero(&netif->gw);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0],
@ -280,13 +313,13 @@ autoip_start(struct netif *netif)
/* no AutoIP client attached yet? */
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_start(): starting new AUTOIP client\n"));
autoip = mem_malloc(sizeof(struct autoip));
autoip = (struct autoip *)mem_malloc(sizeof(struct autoip));
if(autoip == NULL) {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_start(): could not allocate autoip\n"));
return ERR_MEM;
}
memset( autoip, 0, sizeof(struct autoip));
memset(autoip, 0, sizeof(struct autoip));
/* store this AutoIP client in the netif */
netif->autoip = autoip;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));
@ -294,12 +327,11 @@ autoip_start(struct netif *netif)
autoip->state = AUTOIP_STATE_OFF;
autoip->ttw = 0;
autoip->sent_num = 0;
memset(&autoip->llipaddr, 0, sizeof(struct ip_addr));
ip_addr_set_zero(&autoip->llipaddr);
autoip->lastconflict = 0;
}
autoip_create_addr(netif, &(autoip->llipaddr));
autoip->tried_llipaddr++;
autoip_start_probing(netif);
return result;
@ -312,6 +344,10 @@ autoip_start_probing(struct netif *netif)
autoip->state = AUTOIP_STATE_PROBING;
autoip->sent_num = 0;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
/* time to wait to first probe, this is randomly
* choosen out of 0 to PROBE_WAIT seconds.
@ -385,6 +421,10 @@ autoip_tmr()
netif->autoip->state = AUTOIP_STATE_ANNOUNCING;
netif->autoip->sent_num = 0;
netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
} else {
autoip_arp_probe(netif);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
@ -422,6 +462,10 @@ autoip_tmr()
netif->autoip->state = AUTOIP_STATE_BOUND;
netif->autoip->sent_num = 0;
netif->autoip->ttw = 0;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
}
}
break;
@ -448,20 +492,15 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
* when probing ip.dst == llipaddr && hw.src != netif->hwaddr
* we have a conflict and must solve it
*/
struct ip_addr sipaddr, dipaddr;
ip_addr_t sipaddr, dipaddr;
struct eth_addr netifaddr;
netifaddr.addr[0] = netif->hwaddr[0];
netifaddr.addr[1] = netif->hwaddr[1];
netifaddr.addr[2] = netif->hwaddr[2];
netifaddr.addr[3] = netif->hwaddr[3];
netifaddr.addr[4] = netif->hwaddr[4];
netifaddr.addr[5] = netif->hwaddr[5];
ETHADDR16_COPY(netifaddr.addr, netif->hwaddr);
/* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
* structure packing (not using structure copy which breaks strict-aliasing rules).
*/
SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));
SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));
IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||
((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&
@ -477,7 +516,7 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
!eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
("autoip_arp_reply(): Probe Conflict detected\n"));
autoip_start(netif);
autoip_restart(netif);
}
} else {
/* RFC 3927 Section 2.5:

View file

@ -44,7 +44,6 @@
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/icmp.h"
#include "lwip/inet.h"
#include "lwip/inet_chksum.h"
#include "lwip/ip.h"
#include "lwip/def.h"
@ -83,14 +82,13 @@ icmp_input(struct pbuf *p, struct netif *inp)
#endif /* LWIP_DEBUG */
struct icmp_echo_hdr *iecho;
struct ip_hdr *iphdr;
struct ip_addr tmpaddr;
s16_t hlen;
ICMP_STATS_INC(icmp.recv);
snmp_inc_icmpinmsgs();
iphdr = p->payload;
iphdr = (struct ip_hdr *)p->payload;
hlen = IPH_HL(iphdr) * 4;
if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
@ -102,19 +100,23 @@ icmp_input(struct pbuf *p, struct netif *inp)
code = *(((u8_t *)p->payload)+1);
#endif /* LWIP_DEBUG */
switch (type) {
case ICMP_ER:
/* This is OK, echo reply might have been parsed by a raw PCB
(as obviously, an echo request has been sent, too). */
break;
case ICMP_ECHO:
#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
{
int accepted = 1;
#if !LWIP_MULTICAST_PING
/* multicast destination address? */
if (ip_addr_ismulticast(&iphdr->dest)) {
if (ip_addr_ismulticast(&current_iphdr_dest)) {
accepted = 0;
}
#endif /* LWIP_MULTICAST_PING */
#if !LWIP_BROADCAST_PING
/* broadcast destination address? */
if (ip_addr_isbroadcast(&iphdr->dest, inp)) {
if (ip_addr_isbroadcast(&current_iphdr_dest, inp)) {
accepted = 0;
}
#endif /* LWIP_BROADCAST_PING */
@ -163,7 +165,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
goto memerr;
}
iphdr = r->payload;
iphdr = (struct ip_hdr *)r->payload;
/* switch r->payload back to icmp header */
if (pbuf_header(r, -hlen)) {
LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
@ -184,16 +186,15 @@ icmp_input(struct pbuf *p, struct netif *inp)
/* At this point, all checks are OK. */
/* We generate an answer by switching the dest and src ip addresses,
* setting the icmp type to ECHO_RESPONSE and updating the checksum. */
iecho = p->payload;
tmpaddr.addr = iphdr->src.addr;
iphdr->src.addr = iphdr->dest.addr;
iphdr->dest.addr = tmpaddr.addr;
iecho = (struct icmp_echo_hdr *)p->payload;
ip_addr_copy(iphdr->src, *ip_current_dest_addr());
ip_addr_copy(iphdr->dest, *ip_current_src_addr());
ICMPH_TYPE_SET(iecho, ICMP_ER);
/* adjust the checksum */
if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) {
iecho->chksum += htons(ICMP_ECHO << 8) + 1;
if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) {
iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
} else {
iecho->chksum += htons(ICMP_ECHO << 8);
iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
}
/* Set the correct TTL and recalculate the header checksum. */
@ -213,7 +214,8 @@ icmp_input(struct pbuf *p, struct netif *inp)
LWIP_ASSERT("Can't move over header in packet", 0);
} else {
err_t ret;
ret = ip_output_if(p, &(iphdr->src), IP_HDRINCL,
/* send an ICMP packet, src addr is the dest addr of the curren packet */
ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL,
ICMP_TTL, 0, IP_PROTO_ICMP, inp);
if (ret != ERR_OK) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));
@ -288,6 +290,7 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
struct ip_hdr *iphdr;
/* we can use the echo header here */
struct icmp_echo_hdr *icmphdr;
ip_addr_t iphdr_src;
/* ICMP header + IP header + 8 bytes of data */
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
@ -299,14 +302,14 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
LWIP_ASSERT("check that first pbuf can hold icmp message",
(q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
iphdr = p->payload;
iphdr = (struct ip_hdr *)p->payload;
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
LWIP_DEBUGF(ICMP_DEBUG, (" to "));
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
icmphdr = q->payload;
icmphdr = (struct icmp_echo_hdr *)q->payload;
icmphdr->type = type;
icmphdr->code = code;
icmphdr->id = 0;
@ -324,7 +327,8 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
snmp_inc_icmpoutmsgs();
/* increase number of destination unreachable messages attempted to send */
snmp_inc_icmpouttimeexcds();
ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);
ip_addr_copy(iphdr_src, iphdr->src);
ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);
pbuf_free(q);
}

View file

@ -86,7 +86,6 @@ Steve Reynolds
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/ip.h"
#include "lwip/inet.h"
#include "lwip/inet_chksum.h"
#include "lwip/netif.h"
#include "lwip/icmp.h"
@ -96,13 +95,60 @@ Steve Reynolds
#include "string.h"
/*-----------------------------------------------------------------------------
* Globales
*----------------------------------------------------------------------------*/
/*
* IGMP constants
*/
#define IGMP_TTL 1
#define IGMP_MINLEN 8
#define ROUTER_ALERT 0x9404U
#define ROUTER_ALERTLEN 4
/*
* IGMP message types, including version number.
*/
#define IGMP_MEMB_QUERY 0x11 /* Membership query */
#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */
#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */
#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */
/* Group membership states */
#define IGMP_GROUP_NON_MEMBER 0
#define IGMP_GROUP_DELAYING_MEMBER 1
#define IGMP_GROUP_IDLE_MEMBER 2
/**
* IGMP packet format.
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct igmp_msg {
PACK_STRUCT_FIELD(u8_t igmp_msgtype);
PACK_STRUCT_FIELD(u8_t igmp_maxresp);
PACK_STRUCT_FIELD(u16_t igmp_checksum);
PACK_STRUCT_FIELD(ip_addr_p_t igmp_group_address);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr);
static err_t igmp_remove_group(struct igmp_group *group);
static void igmp_timeout( struct igmp_group *group);
static void igmp_start_timer(struct igmp_group *group, u8_t max_time);
static void igmp_stop_timer(struct igmp_group *group);
static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif);
static void igmp_send(struct igmp_group *group, u8_t type);
static struct igmp_group* igmp_group_list;
static struct ip_addr allsystems;
static struct ip_addr allrouters;
static ip_addr_t allsystems;
static ip_addr_t allrouters;
/**
* Initialize the IGMP module
@ -128,7 +174,7 @@ igmp_dump_group_list()
while (group != NULL) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface));
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
group = group->next;
}
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
@ -160,7 +206,7 @@ igmp_start(struct netif *netif)
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
ip_addr_debug_print(IGMP_DEBUG, &allsystems);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
netif->igmp_mac_filter( netif, &allsystems, IGMP_ADD_MAC_FILTER);
netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);
}
return ERR_OK;
@ -185,7 +231,7 @@ igmp_stop(struct netif *netif)
while (group != NULL) {
next = group->next;
/* is it a group joined on this interface? */
if (group->interface == netif) {
if (group->netif == netif) {
/* is it the first group of the list? */
if (group == igmp_group_list) {
igmp_group_list = next;
@ -219,15 +265,15 @@ igmp_stop(struct netif *netif)
* @param netif network interface on which report IGMP memberships
*/
void
igmp_report_groups( struct netif *netif)
igmp_report_groups(struct netif *netif)
{
struct igmp_group *group = igmp_group_list;
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
while (group != NULL) {
if (group->interface == netif) {
igmp_delaying_member( group, IGMP_JOIN_DELAYING_MEMBER_TMR);
if (group->netif == netif) {
igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
}
group = group->next;
}
@ -242,12 +288,12 @@ igmp_report_groups( struct netif *netif)
* NULL if the group wasn't found.
*/
struct igmp_group *
igmp_lookfor_group(struct netif *ifp, struct ip_addr *addr)
igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)
{
struct igmp_group *group = igmp_group_list;
while (group != NULL) {
if ((group->interface == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
return group;
}
group = group->next;
@ -268,7 +314,7 @@ igmp_lookfor_group(struct netif *ifp, struct ip_addr *addr)
* NULL on memory error.
*/
struct igmp_group *
igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)
igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)
{
struct igmp_group *group = igmp_group_list;
@ -280,9 +326,9 @@ igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)
}
/* Group doesn't exist yet, create a new one */
group = memp_malloc(MEMP_IGMP_GROUP);
group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
if (group != NULL) {
group->interface = ifp;
group->netif = ifp;
ip_addr_set(&(group->group_address), addr);
group->timer = 0; /* Not running */
group->group_state = IGMP_GROUP_NON_MEMBER;
@ -306,7 +352,7 @@ igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)
* @param group the group to remove from the global igmp_group_list
* @return ERR_OK if group was removed from the list, an err_t otherwise
*/
err_t
static err_t
igmp_remove_group(struct igmp_group *group)
{
err_t err = ERR_OK;
@ -341,15 +387,17 @@ igmp_remove_group(struct igmp_group *group)
* @param dest destination ip address of the igmp packet
*/
void
igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
{
struct ip_hdr * iphdr;
struct igmp_msg* igmp;
struct igmp_group* group;
struct igmp_group* groupref;
IGMP_STATS_INC(igmp.recv);
/* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
iphdr = p->payload;
iphdr = (struct ip_hdr *)p->payload;
if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
pbuf_free(p);
IGMP_STATS_INC(igmp.lenerr);
@ -373,11 +421,12 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
}
/* Packet is ok so find an existing group */
group = igmp_lookfor_group(inp, dest); /* use the incoming IP address! */
group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */
/* If group can be found or create... */
if (!group) {
pbuf_free(p);
IGMP_STATS_INC(igmp.drop);
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
return;
}
@ -386,50 +435,56 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
switch (igmp->igmp_msgtype) {
case IGMP_MEMB_QUERY: {
/* IGMP_MEMB_QUERY to the "all systems" address ? */
if ((ip_addr_cmp(dest, &allsystems)) && (igmp->igmp_group_address.addr == 0)) {
if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) {
/* THIS IS THE GENERAL QUERY */
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
if (igmp->igmp_maxresp == 0) {
IGMP_STATS_INC(igmp.v1_rxed);
IGMP_STATS_INC(igmp.rx_v1);
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
} else {
IGMP_STATS_INC(igmp.rx_general);
}
IGMP_STATS_INC(igmp.group_query_rxed);
groupref = igmp_group_list;
while (groupref) {
/* Do not send messages on the all systems group address! */
if ((groupref->interface == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
igmp_delaying_member( groupref, igmp->igmp_maxresp);
if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
igmp_delaying_member(groupref, igmp->igmp_maxresp);
}
groupref = groupref->next;
}
} else {
/* IGMP_MEMB_QUERY to a specific group ? */
if (group->group_address.addr != 0) {
if (!ip_addr_isany(&igmp->igmp_group_address)) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
if (ip_addr_cmp (dest, &allsystems)) {
ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);
if (ip_addr_cmp(dest, &allsystems)) {
ip_addr_t groupaddr;
LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
/* we first need to re-lookfor the group since we used dest last time */
group = igmp_lookfor_group(inp, &igmp->igmp_group_address);
/* we first need to re-look for the group since we used dest last time */
ip_addr_copy(groupaddr, igmp->igmp_group_address);
group = igmp_lookfor_group(inp, &groupaddr);
} else {
LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
}
if (group != NULL) {
IGMP_STATS_INC(igmp.unicast_query);
igmp_delaying_member( group, igmp->igmp_maxresp);
IGMP_STATS_INC(igmp.rx_group);
igmp_delaying_member(group, igmp->igmp_maxresp);
} else {
IGMP_STATS_INC(igmp.drop);
}
} else {
IGMP_STATS_INC(igmp.proterr);
}
}
break;
}
case IGMP_V2_MEMB_REPORT: {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
IGMP_STATS_INC(igmp.report_rxed);
IGMP_STATS_INC(igmp.rx_report);
if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
/* This is on a specific group we have already looked up */
group->timer = 0; /* stopped */
@ -440,7 +495,8 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
}
default: {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
igmp->igmp_msgtype, group->group_state, &group, group->interface));
igmp->igmp_msgtype, group->group_state, &group, group->netif));
IGMP_STATS_INC(igmp.proterr);
break;
}
}
@ -457,7 +513,7 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
* @return ERR_OK if group was joined on the netif(s), an err_t otherwise
*/
err_t
igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
{
err_t err = ERR_VAL; /* no matching interface */
struct igmp_group *group;
@ -493,7 +549,7 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
}
IGMP_STATS_INC(igmp.join_sent);
IGMP_STATS_INC(igmp.tx_join);
igmp_send(group, IGMP_V2_MEMB_REPORT);
igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
@ -527,7 +583,7 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
* @return ERR_OK if group was left on the netif(s), an err_t otherwise
*/
err_t
igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
{
err_t err = ERR_VAL; /* no matching interface */
struct igmp_group *group;
@ -556,7 +612,7 @@ igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
/* If we are the last reporter for this group */
if (group->last_reporter_flag) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
IGMP_STATS_INC(igmp.leave_sent);
IGMP_STATS_INC(igmp.tx_leave);
igmp_send(group, IGMP_LEAVE_GROUP);
}
@ -602,8 +658,8 @@ igmp_tmr(void)
struct igmp_group *group = igmp_group_list;
while (group != NULL) {
if (group->timer != 0) {
group->timer -= 1;
if (group->timer > 0) {
group->timer--;
if (group->timer == 0) {
igmp_timeout(group);
}
@ -618,15 +674,16 @@ igmp_tmr(void)
*
* @param group an igmp_group for which a timeout is reached
*/
void
static void
igmp_timeout(struct igmp_group *group)
{
/* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */
if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface));
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
IGMP_STATS_INC(igmp.tx_report);
igmp_send(group, IGMP_V2_MEMB_REPORT);
}
}
@ -638,13 +695,15 @@ igmp_timeout(struct igmp_group *group)
* @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with
* every call to igmp_tmr())
*/
void
static void
igmp_start_timer(struct igmp_group *group, u8_t max_time)
{
/**
* @todo Important !! this should be random 0 -> max_time. Find out how to do this
*/
group->timer = max_time;
/* ensure the input value is > 0 */
if (max_time == 0) {
max_time = 1;
}
/* ensure the random value is > 0 */
group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
}
/**
@ -652,7 +711,7 @@ igmp_start_timer(struct igmp_group *group, u8_t max_time)
*
* @param group the igmp_group for which to stop the timer
*/
void
static void
igmp_stop_timer(struct igmp_group *group)
{
group->timer = 0;
@ -664,12 +723,13 @@ igmp_stop_timer(struct igmp_group *group)
* @param group the igmp_group for which "delaying" membership report
* @param maxresp query delay
*/
void
igmp_delaying_member( struct igmp_group *group, u8_t maxresp)
static void
igmp_delaying_member(struct igmp_group *group, u8_t maxresp)
{
if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) {
igmp_start_timer(group, (maxresp)/2);
((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
((group->timer == 0) || (maxresp < group->timer)))) {
igmp_start_timer(group, maxresp);
group->group_state = IGMP_GROUP_DELAYING_MEMBER;
}
}
@ -693,15 +753,15 @@ igmp_delaying_member( struct igmp_group *group, u8_t maxresp)
* ERR_BUF if p doesn't have enough space for IP/LINK headers
* returns errors returned by netif->output
*/
err_t
igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
u8_t ttl, u8_t proto, struct netif *netif)
static err_t
igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)
{
/* This is the "router alert" option */
u16_t ra[2];
ra[0] = htons (ROUTER_ALERT);
ra[0] = PP_HTONS(ROUTER_ALERT);
ra[1] = 0x0000; /* Router shall examine packet */
return ip_output_if_opt(p, src, dest, ttl, 0, proto, netif, ra, ROUTER_ALERTLEN);
IGMP_STATS_INC(igmp.xmit);
return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
}
/**
@ -710,32 +770,31 @@ igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
* @param group the group to which to send the packet
* @param type the type of igmp packet to send
*/
void
static void
igmp_send(struct igmp_group *group, u8_t type)
{
struct pbuf* p = NULL;
struct igmp_msg* igmp = NULL;
struct ip_addr src = {0};
struct ip_addr* dest = NULL;
ip_addr_t src = *IP_ADDR_ANY;
ip_addr_t* dest = NULL;
/* IP header + "router alert" option + IGMP header */
p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
if (p) {
igmp = p->payload;
igmp = (struct igmp_msg *)p->payload;
LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
(p->len >= sizeof(struct igmp_msg)));
ip_addr_set(&src, &((group->interface)->ip_addr));
ip_addr_copy(src, group->netif->ip_addr);
if (type == IGMP_V2_MEMB_REPORT) {
dest = &(group->group_address);
IGMP_STATS_INC(igmp.report_sent);
ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));
ip_addr_copy(igmp->igmp_group_address, group->group_address);
group->last_reporter_flag = 1; /* Remember we were the last to report */
} else {
if (type == IGMP_LEAVE_GROUP) {
dest = &allrouters;
ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));
ip_addr_copy(igmp->igmp_group_address, group->group_address);
}
}
@ -743,14 +802,15 @@ igmp_send(struct igmp_group *group, u8_t type)
igmp->igmp_msgtype = type;
igmp->igmp_maxresp = 0;
igmp->igmp_checksum = 0;
igmp->igmp_checksum = inet_chksum( igmp, IGMP_MINLEN);
igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
igmp_ip_output_if(p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface);
igmp_ip_output_if(p, &src, dest, group->netif);
}
pbuf_free(p);
} else {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
IGMP_STATS_INC(igmp.memerr);
}
}

View file

@ -40,239 +40,3 @@
#include "lwip/inet.h"
/* Here for now until needed in other places in lwIP */
#ifndef isprint
#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up)
#define isprint(c) in_range(c, 0x20, 0x7f)
#define isdigit(c) in_range(c, '0', '9')
#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
#define islower(c) in_range(c, 'a', 'z')
#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
#endif
/**
* Ascii internet address interpretation routine.
* The value returned is in network order.
*
* @param cp IP address in ascii represenation (e.g. "127.0.0.1")
* @return ip address in network order
*/
u32_t
inet_addr(const char *cp)
{
struct in_addr val;
if (inet_aton(cp, &val)) {
return (val.s_addr);
}
return (INADDR_NONE);
}
/**
* Check whether "cp" is a valid ascii representation
* of an Internet address and convert to a binary address.
* Returns 1 if the address is valid, 0 if not.
* This replaces inet_addr, the return value from which
* cannot distinguish between failure and a local broadcast address.
*
* @param cp IP address in ascii represenation (e.g. "127.0.0.1")
* @param addr pointer to which to save the ip address in network order
* @return 1 if cp could be converted to addr, 0 on failure
*/
int
inet_aton(const char *cp, struct in_addr *addr)
{
u32_t val;
u8_t base;
char c;
u32_t parts[4];
u32_t *pp = parts;
c = *cp;
for (;;) {
/*
* Collect number up to ``.''.
* Values are specified as for C:
* 0x=hex, 0=octal, 1-9=decimal.
*/
if (!isdigit(c))
return (0);
val = 0;
base = 10;
if (c == '0') {
c = *++cp;
if (c == 'x' || c == 'X') {
base = 16;
c = *++cp;
} else
base = 8;
}
for (;;) {
if (isdigit(c)) {
val = (val * base) + (int)(c - '0');
c = *++cp;
} else if (base == 16 && isxdigit(c)) {
val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));
c = *++cp;
} else
break;
}
if (c == '.') {
/*
* Internet format:
* a.b.c.d
* a.b.c (with c treated as 16 bits)
* a.b (with b treated as 24 bits)
*/
if (pp >= parts + 3)
return (0);
*pp++ = val;
c = *++cp;
} else
break;
}
/*
* Check for trailing characters.
*/
if (c != '\0' && !isspace(c))
return (0);
/*
* Concoct the address according to
* the number of parts specified.
*/
switch (pp - parts + 1) {
case 0:
return (0); /* initial nondigit */
case 1: /* a -- 32 bits */
break;
case 2: /* a.b -- 8.24 bits */
if (val > 0xffffffUL)
return (0);
val |= parts[0] << 24;
break;
case 3: /* a.b.c -- 8.8.16 bits */
if (val > 0xffff)
return (0);
val |= (parts[0] << 24) | (parts[1] << 16);
break;
case 4: /* a.b.c.d -- 8.8.8.8 bits */
if (val > 0xff)
return (0);
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
break;
}
if (addr)
addr->s_addr = htonl(val);
return (1);
}
/**
* Convert numeric IP address into decimal dotted ASCII representation.
* returns ptr to static buffer; not reentrant!
*
* @param addr ip address in network order to convert
* @return pointer to a global static (!) buffer that holds the ASCII
* represenation of addr
*/
char *
inet_ntoa(struct in_addr addr)
{
static char str[16];
u32_t s_addr = addr.s_addr;
char inv[3];
char *rp;
u8_t *ap;
u8_t rem;
u8_t n;
u8_t i;
rp = str;
ap = (u8_t *)&s_addr;
for(n = 0; n < 4; n++) {
i = 0;
do {
rem = *ap % (u8_t)10;
*ap /= (u8_t)10;
inv[i++] = '0' + rem;
} while(*ap);
while(i--)
*rp++ = inv[i];
*rp++ = '.';
ap++;
}
*--rp = 0;
return str;
}
/**
* These are reference implementations of the byte swapping functions.
* Again with the aim of being simple, correct and fully portable.
* Byte swapping is the second thing you would want to optimize. You will
* need to port it to your architecture and in your cc.h:
*
* #define LWIP_PLATFORM_BYTESWAP 1
* #define LWIP_PLATFORM_HTONS(x) <your_htons>
* #define LWIP_PLATFORM_HTONL(x) <your_htonl>
*
* Note ntohs() and ntohl() are merely references to the htonx counterparts.
*/
#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)
/**
* Convert an u16_t from host- to network byte order.
*
* @param n u16_t in host byte order
* @return n in network byte order
*/
u16_t
htons(u16_t n)
{
return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
}
/**
* Convert an u16_t from network- to host byte order.
*
* @param n u16_t in network byte order
* @return n in host byte order
*/
u16_t
ntohs(u16_t n)
{
return htons(n);
}
/**
* Convert an u32_t from host- to network byte order.
*
* @param n u32_t in host byte order
* @return n in network byte order
*/
u32_t
htonl(u32_t n)
{
return ((n & 0xff) << 24) |
((n & 0xff00) << 8) |
((n & 0xff0000UL) >> 8) |
((n & 0xff000000UL) >> 24);
}
/**
* Convert an u32_t from network- to host byte order.
*
* @param n u32_t in network byte order
* @return n in host byte order
*/
u32_t
ntohl(u32_t n)
{
return htonl(n);
}
#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */

View file

@ -39,9 +39,10 @@
#include "lwip/opt.h"
#include "lwip/inet_chksum.h"
#include "lwip/inet.h"
#include "lwip/def.h"
#include <stddef.h>
#include <string.h>
/* These are some reference implementations of the checksum algorithm, with the
* aim of being simple, correct and fully portable. Checksumming is the
@ -57,7 +58,7 @@
#ifndef LWIP_CHKSUM
# define LWIP_CHKSUM lwip_standard_chksum
# ifndef LWIP_CHKSUM_ALGORITHM
# define LWIP_CHKSUM_ALGORITHM 1
# define LWIP_CHKSUM_ALGORITHM 2
# endif
#endif
/* If none set: */
@ -65,18 +66,6 @@
# define LWIP_CHKSUM_ALGORITHM 0
#endif
/** Like the name says... */
#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)
/* little endian and PLATFORM_BYTESWAP defined */
#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w)
#else
/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */
#define SWAP_BYTES_IN_WORD(w) ((w & 0xff) << 8) | ((w & 0xff00) >> 8)
#endif
/** Split an u32_t in two u16_ts and add them up */
#define FOLD_U32T(u) ((u >> 16) + (u & 0x0000ffffUL))
#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */
/**
* lwip checksum
@ -145,10 +134,10 @@ lwip_standard_chksum(void *dataptr, u16_t len)
static u16_t
lwip_standard_chksum(void *dataptr, int len)
{
u8_t *pb = dataptr;
u8_t *pb = (u8_t *)dataptr;
u16_t *ps, t = 0;
u32_t sum = 0;
int odd = ((u32_t)pb & 1);
int odd = ((mem_ptr_t)pb & 1);
/* Get aligned to u16_t */
if (odd && len > 0) {
@ -157,7 +146,7 @@ lwip_standard_chksum(void *dataptr, int len)
}
/* Add the bulk of the data */
ps = (u16_t *)pb;
ps = (u16_t *)(void *)pb;
while (len > 1) {
sum += *ps++;
len -= 2;
@ -165,7 +154,7 @@ lwip_standard_chksum(void *dataptr, int len)
/* Consume left-over byte, if any */
if (len > 0) {
((u8_t *)&t)[0] = *(u8_t *)ps;;
((u8_t *)&t)[0] = *(u8_t *)ps;
}
/* Add end bytes */
@ -181,7 +170,7 @@ lwip_standard_chksum(void *dataptr, int len)
sum = SWAP_BYTES_IN_WORD(sum);
}
return sum;
return (u16_t)sum;
}
#endif
@ -201,12 +190,12 @@ lwip_standard_chksum(void *dataptr, int len)
static u16_t
lwip_standard_chksum(void *dataptr, int len)
{
u8_t *pb = dataptr;
u8_t *pb = (u8_t *)dataptr;
u16_t *ps, t = 0;
u32_t *pl;
u32_t sum = 0, tmp;
/* starts at odd byte address? */
int odd = ((u32_t)pb & 1);
int odd = ((mem_ptr_t)pb & 1);
if (odd && len > 0) {
((u8_t *)&t)[1] = *pb++;
@ -215,7 +204,7 @@ lwip_standard_chksum(void *dataptr, int len)
ps = (u16_t *)pb;
if (((u32_t)ps & 3) && len > 1) {
if (((mem_ptr_t)ps & 3) && len > 1) {
sum += *ps++;
len -= 2;
}
@ -263,7 +252,7 @@ lwip_standard_chksum(void *dataptr, int len)
sum = SWAP_BYTES_IN_WORD(sum);
}
return sum;
return (u16_t)sum;
}
#endif
@ -281,10 +270,11 @@ lwip_standard_chksum(void *dataptr, int len)
*/
u16_t
inet_chksum_pseudo(struct pbuf *p,
struct ip_addr *src, struct ip_addr *dest,
ip_addr_t *src, ip_addr_t *dest,
u8_t proto, u16_t proto_len)
{
u32_t acc;
u32_t addr;
struct pbuf *q;
u8_t swapped;
@ -309,10 +299,12 @@ inet_chksum_pseudo(struct pbuf *p,
if (swapped) {
acc = SWAP_BYTES_IN_WORD(acc);
}
acc += (src->addr & 0xffffUL);
acc += ((src->addr >> 16) & 0xffffUL);
acc += (dest->addr & 0xffffUL);
acc += ((dest->addr >> 16) & 0xffffUL);
addr = ip4_addr_get_u32(src);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
addr = ip4_addr_get_u32(dest);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
acc += (u32_t)htons((u16_t)proto);
acc += (u32_t)htons(proto_len);
@ -336,14 +328,13 @@ inet_chksum_pseudo(struct pbuf *p,
* @param proto_len length of the ip data part (used for checksum of pseudo header)
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
/* Currently only used by UDPLITE, although this could change in the future. */
#if LWIP_UDPLITE
u16_t
inet_chksum_pseudo_partial(struct pbuf *p,
struct ip_addr *src, struct ip_addr *dest,
ip_addr_t *src, ip_addr_t *dest,
u8_t proto, u16_t proto_len, u16_t chksum_len)
{
u32_t acc;
u32_t addr;
struct pbuf *q;
u8_t swapped;
u16_t chklen;
@ -374,10 +365,12 @@ inet_chksum_pseudo_partial(struct pbuf *p,
if (swapped) {
acc = SWAP_BYTES_IN_WORD(acc);
}
acc += (src->addr & 0xffffUL);
acc += ((src->addr >> 16) & 0xffffUL);
acc += (dest->addr & 0xffffUL);
acc += ((dest->addr >> 16) & 0xffffUL);
addr = ip4_addr_get_u32(src);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
addr = ip4_addr_get_u32(dest);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
acc += (u32_t)htons((u16_t)proto);
acc += (u32_t)htons(proto_len);
@ -388,7 +381,6 @@ inet_chksum_pseudo_partial(struct pbuf *p,
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
return (u16_t)~(acc & 0xffffUL);
}
#endif /* LWIP_UDPLITE */
/* inet_chksum:
*
@ -436,3 +428,23 @@ inet_chksum_pbuf(struct pbuf *p)
}
return (u16_t)~(acc & 0xffffUL);
}
/* These are some implementations for LWIP_CHKSUM_COPY, which copies data
* like MEMCPY but generates a checksum at the same time. Since this is a
* performance-sensitive function, you might want to create your own version
* in assembly targeted at your hardware by defining it in lwipopts.h:
* #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len)
*/
#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */
/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM.
* For architectures with big caches, data might still be in cache when
* generating the checksum after copying.
*/
u16_t
lwip_chksum_copy(void *dst, const void *src, u16_t len)
{
MEMCPY(dst, src, len);
return LWIP_CHKSUM(dst, len);
}
#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */

View file

@ -43,21 +43,56 @@
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/ip_frag.h"
#include "lwip/inet.h"
#include "lwip/inet_chksum.h"
#include "lwip/netif.h"
#include "lwip/icmp.h"
#include "lwip/igmp.h"
#include "lwip/raw.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/tcp_impl.h"
#include "lwip/snmp.h"
#include "lwip/dhcp.h"
#include "lwip/autoip.h"
#include "lwip/stats.h"
#include "arch/perf.h"
#include <string.h>
/** Set this to 0 in the rare case of wanting to call an extra function to
* generate the IP checksum (in contrast to calculating it on-the-fly). */
#ifndef LWIP_INLINE_IP_CHKSUM
#define LWIP_INLINE_IP_CHKSUM 1
#endif
#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP
#define CHECKSUM_GEN_IP_INLINE 1
#else
#define CHECKSUM_GEN_IP_INLINE 0
#endif
#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT)
#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1
/** Some defines for DHCP to let link-layer-addressed packets through while the
* netif is down.
* To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT
* to return 1 if the port is accepted and 0 if the port is not accepted.
*/
#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT)
/* accept DHCP client port and custom port */
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \
|| (LWIP_IP_ACCEPT_UDP_PORT(port)))
#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
/* accept custom port only */
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port))
#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
/* accept DHCP client port only */
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT))
#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
#else /* LWIP_DHCP */
#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0
#endif /* LWIP_DHCP */
/**
* The interface that provided the packet for the current callback
* invocation.
@ -68,6 +103,13 @@ struct netif *current_netif;
* Header of the input packet currently being processed.
*/
const struct ip_hdr *current_header;
/** Source IP address of current_header */
ip_addr_t current_iphdr_src;
/** Destination IP address of current_header */
ip_addr_t current_iphdr_dest;
/** The IP header ID of the next outgoing IP packet */
static u16_t ip_id;
/**
* Finds the appropriate network interface for a given IP address. It
@ -79,7 +121,7 @@ const struct ip_hdr *current_header;
* @return the netif on which to send to reach dest
*/
struct netif *
ip_route(struct ip_addr *dest)
ip_route(ip_addr_t *dest)
{
struct netif *netif;
@ -94,7 +136,8 @@ ip_route(struct ip_addr *dest)
}
}
if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to 0x%"X32_F"\n", dest->addr));
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
IP_STATS_INC(ip.rterr);
snmp_inc_ipoutnoroutes();
return NULL;
@ -112,28 +155,35 @@ ip_route(struct ip_addr *dest)
* @param p the packet to forward (p->payload points to IP header)
* @param iphdr the IP header of the input packet
* @param inp the netif on which this packet was received
* @return the netif on which the packet was sent (NULL if it wasn't sent)
*/
static struct netif *
static void
ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
{
struct netif *netif;
PERF_START;
/* RFC3927 2.7: do not forward link-local addresses */
if (ip_addr_islinklocal(&current_iphdr_dest)) {
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
goto return_noroute;
}
/* Find network interface where to forward this IP packet to. */
netif = ip_route((struct ip_addr *)&(iphdr->dest));
netif = ip_route(&current_iphdr_dest);
if (netif == NULL) {
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%"X32_F" found\n",
iphdr->dest.addr));
snmp_inc_ipoutnoroutes();
return (struct netif *)NULL;
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n",
ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
goto return_noroute;
}
/* Do not forward packets onto the same network interface on which
* they arrived. */
if (netif == inp) {
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
snmp_inc_ipoutnoroutes();
return (struct netif *)NULL;
goto return_noroute;
}
/* decrement TTL */
@ -147,18 +197,19 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
icmp_time_exceeded(p, ICMP_TE_TTL);
}
#endif /* LWIP_ICMP */
return (struct netif *)NULL;
return;
}
/* Incrementally update the IP checksum. */
if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) {
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1);
if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) {
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1);
} else {
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100));
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100));
}
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%"X32_F"\n",
iphdr->dest.addr));
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
IP_STATS_INC(ip.fw);
IP_STATS_INC(ip.xmit);
@ -166,8 +217,10 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
PERF_STOP("ip_forward");
/* transmit pbuf on chosen interface */
netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));
return netif;
netif->output(netif, p, &current_iphdr_dest);
return;
return_noroute:
snmp_inc_ipoutnoroutes();
}
#endif /* IP_FORWARD */
@ -192,15 +245,15 @@ ip_input(struct pbuf *p, struct netif *inp)
struct netif *netif;
u16_t iphdr_hlen;
u16_t iphdr_len;
#if LWIP_DHCP
#if IP_ACCEPT_LINK_LAYER_ADDRESSING
int check_ip_src=1;
#endif /* LWIP_DHCP */
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
IP_STATS_INC(ip.recv);
snmp_inc_ipinreceives();
/* identify the IP header */
iphdr = p->payload;
iphdr = (struct ip_hdr *)p->payload;
if (IPH_V(iphdr) != 4) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
ip_debug_print(p);
@ -257,10 +310,14 @@ ip_input(struct pbuf *p, struct netif *inp)
* but we'll do it anyway just to be sure that its done. */
pbuf_realloc(p, iphdr_len);
/* copy IP addresses to aligned ip_addr_t */
ip_addr_copy(current_iphdr_dest, iphdr->dest);
ip_addr_copy(current_iphdr_src, iphdr->src);
/* match packet against an interface, i.e. is this packet for us? */
#if LWIP_IGMP
if (ip_addr_ismulticast(&(iphdr->dest))) {
if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(iphdr->dest)))) {
if (ip_addr_ismulticast(&current_iphdr_dest)) {
if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &current_iphdr_dest))) {
netif = inp;
} else {
netif = NULL;
@ -275,22 +332,33 @@ ip_input(struct pbuf *p, struct netif *inp)
netif = inp;
do {
LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",
iphdr->dest.addr, netif->ip_addr.addr,
iphdr->dest.addr & netif->netmask.addr,
netif->ip_addr.addr & netif->netmask.addr,
iphdr->dest.addr & ~(netif->netmask.addr)));
ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr),
ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask),
ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask),
ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask)));
/* interface is up and configured? */
if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {
/* unicast to this interface address? */
if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||
if (ip_addr_cmp(&current_iphdr_dest, &(netif->ip_addr)) ||
/* or broadcast on this interface network address? */
ip_addr_isbroadcast(&(iphdr->dest), netif)) {
ip_addr_isbroadcast(&current_iphdr_dest, netif)) {
LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
netif->name[0], netif->name[1]));
/* break out of for loop */
break;
}
#if LWIP_AUTOIP
/* connections to link-local addresses must persist after changing
the netif's address (RFC3927 ch. 1.9) */
if ((netif->autoip != NULL) &&
ip_addr_cmp(&current_iphdr_dest, &(netif->autoip->llipaddr))) {
LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n",
netif->name[0], netif->name[1]));
/* break out of for loop */
break;
}
#endif /* LWIP_AUTOIP */
}
if (first) {
first = 0;
@ -304,32 +372,38 @@ ip_input(struct pbuf *p, struct netif *inp)
} while(netif != NULL);
}
#if LWIP_DHCP
#if IP_ACCEPT_LINK_LAYER_ADDRESSING
/* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
* using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
* According to RFC 1542 section 3.1.1, referred by RFC 2131).
*
* If you want to accept private broadcast communication while a netif is down,
* define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.:
*
* #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345))
*/
if (netif == NULL) {
/* remote port is DHCP server? */
if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen);
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest)));
if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) {
ntohs(udphdr->dest)));
if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n"));
netif = inp;
check_ip_src = 0;
}
}
}
#endif /* LWIP_DHCP */
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
/* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
#if LWIP_DHCP
#if IP_ACCEPT_LINK_LAYER_ADDRESSING
/* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
if (check_ip_src && (iphdr->src.addr != 0))
#endif /* LWIP_DHCP */
{ if ((ip_addr_isbroadcast(&(iphdr->src), inp)) ||
(ip_addr_ismulticast(&(iphdr->src)))) {
if (check_ip_src && !ip_addr_isany(&current_iphdr_src))
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
{ if ((ip_addr_isbroadcast(&current_iphdr_src, inp)) ||
(ip_addr_ismulticast(&current_iphdr_src))) {
/* packet source is not valid */
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
/* free (drop) packet pbufs */
@ -347,7 +421,7 @@ ip_input(struct pbuf *p, struct netif *inp)
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n"));
#if IP_FORWARD
/* non-broadcast packet? */
if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {
if (!ip_addr_isbroadcast(&current_iphdr_dest, inp)) {
/* try to forward IP packet on (other) interfaces */
ip_forward(p, iphdr, inp);
} else
@ -360,17 +434,17 @@ ip_input(struct pbuf *p, struct netif *inp)
return ERR_OK;
}
/* packet consists of multiple fragments? */
if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) {
#if IP_REASSEMBLY /* packet fragment reassembly code present? */
LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n",
ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
/* reassemble the packet*/
p = ip_reass(p);
/* packet not fully reassembled yet? */
if (p == NULL) {
return ERR_OK;
}
iphdr = p->payload;
iphdr = (struct ip_hdr *)p->payload;
#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
pbuf_free(p);
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
@ -387,7 +461,7 @@ ip_input(struct pbuf *p, struct netif *inp)
#if LWIP_IGMP
/* there is an extra "router alert" option in IGMP messages which we allow for but do not police */
if((iphdr_hlen > IP_HLEN && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
if((iphdr_hlen > IP_HLEN) && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
#else
if (iphdr_hlen > IP_HLEN) {
#endif /* LWIP_IGMP */
@ -439,14 +513,14 @@ ip_input(struct pbuf *p, struct netif *inp)
#endif /* LWIP_ICMP */
#if LWIP_IGMP
case IP_PROTO_IGMP:
igmp_input(p,inp,&(iphdr->dest));
igmp_input(p, inp, &current_iphdr_dest);
break;
#endif /* LWIP_IGMP */
default:
#if LWIP_ICMP
/* send ICMP destination protocol unreachable unless is was a broadcast */
if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&
!ip_addr_ismulticast(&(iphdr->dest))) {
if (!ip_addr_isbroadcast(&current_iphdr_dest, inp) &&
!ip_addr_ismulticast(&current_iphdr_dest)) {
p->payload = iphdr;
icmp_dest_unreach(p, ICMP_DUR_PROTO);
}
@ -463,6 +537,8 @@ ip_input(struct pbuf *p, struct netif *inp)
current_netif = NULL;
current_header = NULL;
ip_addr_set_any(&current_iphdr_src);
ip_addr_set_any(&current_iphdr_dest);
return ERR_OK;
}
@ -493,7 +569,7 @@ ip_input(struct pbuf *p, struct netif *inp)
* unique identifiers independent of destination"
*/
err_t
ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos,
u8_t proto, struct netif *netif)
{
@ -507,13 +583,20 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
* @ param ip_options pointer to the IP options, copied into the IP header
* @ param optlen length of ip_options
*/
err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
u16_t optlen)
{
#endif /* IP_OPTIONS_SEND */
struct ip_hdr *iphdr;
static u16_t ip_id = 0;
ip_addr_t dest_addr;
#if CHECKSUM_GEN_IP_INLINE
u32_t chk_sum = 0;
#endif /* CHECKSUM_GEN_IP_INLINE */
/* pbufs passed to IP must have a ref-count of 1 as their payload pointer
gets altered as the packet is passed down the stack */
LWIP_ASSERT("p->ref == 1", p->ref == 1);
snmp_inc_ipoutrequests();
@ -523,6 +606,9 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest
#if IP_OPTIONS_SEND
u16_t optlen_aligned = 0;
if (optlen != 0) {
#if CHECKSUM_GEN_IP_INLINE
int i;
#endif /* CHECKSUM_GEN_IP_INLINE */
/* round up to a multiple of 4 */
optlen_aligned = ((optlen + 3) & ~3);
ip_hlen += optlen_aligned;
@ -538,6 +624,11 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest
/* zero the remaining bytes */
memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
}
#if CHECKSUM_GEN_IP_INLINE
for (i = 0; i < optlen_aligned/2; i++) {
chk_sum += ((u16_t*)p->payload)[i];
}
#endif /* CHECKSUM_GEN_IP_INLINE */
}
#endif /* IP_OPTIONS_SEND */
/* generate IP header */
@ -549,35 +640,63 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest
return ERR_BUF;
}
iphdr = p->payload;
iphdr = (struct ip_hdr *)p->payload;
LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",
(p->len >= sizeof(struct ip_hdr)));
IPH_TTL_SET(iphdr, ttl);
IPH_PROTO_SET(iphdr, proto);
#if CHECKSUM_GEN_IP_INLINE
chk_sum += LWIP_MAKE_U16(proto, ttl);
#endif /* CHECKSUM_GEN_IP_INLINE */
ip_addr_set(&(iphdr->dest), dest);
/* dest cannot be NULL here */
ip_addr_copy(iphdr->dest, *dest);
#if CHECKSUM_GEN_IP_INLINE
chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF;
chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16;
#endif /* CHECKSUM_GEN_IP_INLINE */
IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos);
#if CHECKSUM_GEN_IP_INLINE
chk_sum += iphdr->_v_hl_tos;
#endif /* CHECKSUM_GEN_IP_INLINE */
IPH_LEN_SET(iphdr, htons(p->tot_len));
#if CHECKSUM_GEN_IP_INLINE
chk_sum += iphdr->_len;
#endif /* CHECKSUM_GEN_IP_INLINE */
IPH_OFFSET_SET(iphdr, 0);
IPH_ID_SET(iphdr, htons(ip_id));
#if CHECKSUM_GEN_IP_INLINE
chk_sum += iphdr->_id;
#endif /* CHECKSUM_GEN_IP_INLINE */
++ip_id;
if (ip_addr_isany(src)) {
ip_addr_set(&(iphdr->src), &(netif->ip_addr));
ip_addr_copy(iphdr->src, netif->ip_addr);
} else {
ip_addr_set(&(iphdr->src), src);
/* src cannot be NULL here */
ip_addr_copy(iphdr->src, *src);
}
#if CHECKSUM_GEN_IP_INLINE
chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF;
chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16;
chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF);
chk_sum = (chk_sum >> 16) + chk_sum;
chk_sum = ~chk_sum;
iphdr->_chksum = chk_sum; /* network order */
#else /* CHECKSUM_GEN_IP_INLINE */
IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));
#endif
#endif /* CHECKSUM_GEN_IP_INLINE */
} else {
/* IP header already included in p */
iphdr = p->payload;
dest = &(iphdr->dest);
iphdr = (struct ip_hdr *)p->payload;
ip_addr_copy(dest_addr, iphdr->dest);
dest = &dest_addr;
}
IP_STATS_INC(ip.xmit);
@ -591,13 +710,18 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest
LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
return netif_loop_output(netif, p, dest);
}
#if LWIP_IGMP
if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) {
netif_loop_output(netif, p, dest);
}
#endif /* LWIP_IGMP */
#endif /* ENABLE_LOOPBACK */
#if IP_FRAG
/* don't fragment if interface has mtu set to 0 [loopif] */
if (netif->mtu && (p->tot_len > netif->mtu)) {
return ip_frag(p,netif,dest);
return ip_frag(p, netif, dest);
}
#endif
#endif /* IP_FRAG */
LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
return netif->output(netif, p, dest);
@ -621,13 +745,18 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest
* see ip_output_if() for more return values
*/
err_t
ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto)
{
struct netif *netif;
/* pbufs passed to IP must have a ref-count of 1 as their payload pointer
gets altered as the packet is passed down the stack */
LWIP_ASSERT("p->ref == 1", p->ref == 1);
if ((netif = ip_route(dest)) == NULL) {
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
IP_STATS_INC(ip.rterr);
return ERR_RTE;
}
@ -655,14 +784,19 @@ ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
* see ip_output_if() for more return values
*/
err_t
ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
{
struct netif *netif;
err_t err;
/* pbufs passed to IP must have a ref-count of 1 as their payload pointer
gets altered as the packet is passed down the stack */
LWIP_ASSERT("p->ref == 1", p->ref == 1);
if ((netif = ip_route(dest)) == NULL) {
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
IP_STATS_INC(ip.rterr);
return ERR_RTE;
}
@ -682,7 +816,7 @@ ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
void
ip_debug_print(struct pbuf *p)
{
struct ip_hdr *iphdr = p->payload;
struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
u8_t *payload;
payload = (u8_t *)iphdr + IP_HLEN;
@ -708,16 +842,16 @@ ip_debug_print(struct pbuf *p)
ntohs(IPH_CHKSUM(iphdr))));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n",
ip4_addr1(&iphdr->src),
ip4_addr2(&iphdr->src),
ip4_addr3(&iphdr->src),
ip4_addr4(&iphdr->src)));
ip4_addr1_16(&iphdr->src),
ip4_addr2_16(&iphdr->src),
ip4_addr3_16(&iphdr->src),
ip4_addr4_16(&iphdr->src)));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n",
ip4_addr1(&iphdr->dest),
ip4_addr2(&iphdr->dest),
ip4_addr3(&iphdr->dest),
ip4_addr4(&iphdr->dest)));
ip4_addr1_16(&iphdr->dest),
ip4_addr2_16(&iphdr->dest),
ip4_addr3_16(&iphdr->dest),
ip4_addr4_16(&iphdr->dest)));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
}
#endif /* IP_DEBUG */

View file

@ -38,15 +38,11 @@
#include "lwip/opt.h"
#include "lwip/ip_addr.h"
#include "lwip/inet.h"
#include "lwip/netif.h"
#define IP_ADDR_ANY_VALUE 0x00000000UL
#define IP_ADDR_BROADCAST_VALUE 0xffffffffUL
/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
const struct ip_addr ip_addr_any = { IP_ADDR_ANY_VALUE };
const struct ip_addr ip_addr_broadcast = { IP_ADDR_BROADCAST_VALUE };
const ip_addr_t ip_addr_any = { IPADDR_ANY };
const ip_addr_t ip_addr_broadcast = { IPADDR_BROADCAST };
/**
* Determine if an address is a broadcast address on a network interface
@ -55,30 +51,262 @@ const struct ip_addr ip_addr_broadcast = { IP_ADDR_BROADCAST_VALUE };
* @param netif the network interface against which the address is checked
* @return returns non-zero if the address is a broadcast address
*/
u8_t ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif)
u8_t
ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)
{
u32_t addr2test;
ip_addr_t ipaddr;
ip4_addr_set_u32(&ipaddr, addr);
addr2test = addr->addr;
/* all ones (broadcast) or all zeroes (old skool broadcast) */
if ((~addr2test == IP_ADDR_ANY_VALUE) ||
(addr2test == IP_ADDR_ANY_VALUE))
if ((~addr == IPADDR_ANY) ||
(addr == IPADDR_ANY)) {
return 1;
/* no broadcast support on this network interface? */
else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0)
} else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) {
/* the given address cannot be a broadcast address
* nor can we check against any broadcast addresses */
return 0;
/* address matches network interface address exactly? => no broadcast */
else if (addr2test == netif->ip_addr.addr)
} else if (addr == ip4_addr_get_u32(&netif->ip_addr)) {
return 0;
/* on the same (sub) network... */
else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask))
} else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask))
/* ...and host identifier bits are all ones? =>... */
&& ((addr2test & ~netif->netmask.addr) ==
(IP_ADDR_BROADCAST_VALUE & ~netif->netmask.addr)))
&& ((addr & ~ip4_addr_get_u32(&netif->netmask)) ==
(IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) {
/* => network broadcast address */
return 1;
else
} else {
return 0;
}
}
/** Checks if a netmask is valid (starting with ones, then only zeros)
*
* @param netmask the IPv4 netmask to check (in network byte order!)
* @return 1 if the netmask is valid, 0 if it is not
*/
u8_t
ip4_addr_netmask_valid(u32_t netmask)
{
u32_t mask;
u32_t nm_hostorder = lwip_htonl(netmask);
/* first, check for the first zero */
for (mask = 1UL << 31 ; mask != 0; mask >>= 1) {
if ((nm_hostorder & mask) == 0) {
break;
}
}
/* then check that there is no one */
for (; mask != 0; mask >>= 1) {
if ((nm_hostorder & mask) != 0) {
/* there is a one after the first zero -> invalid */
return 0;
}
}
/* no one after the first zero -> valid */
return 1;
}
/* Here for now until needed in other places in lwIP */
#ifndef isprint
#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up)
#define isprint(c) in_range(c, 0x20, 0x7f)
#define isdigit(c) in_range(c, '0', '9')
#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
#define islower(c) in_range(c, 'a', 'z')
#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
#endif
/**
* Ascii internet address interpretation routine.
* The value returned is in network order.
*
* @param cp IP address in ascii represenation (e.g. "127.0.0.1")
* @return ip address in network order
*/
u32_t
ipaddr_addr(const char *cp)
{
ip_addr_t val;
if (ipaddr_aton(cp, &val)) {
return ip4_addr_get_u32(&val);
}
return (IPADDR_NONE);
}
/**
* Check whether "cp" is a valid ascii representation
* of an Internet address and convert to a binary address.
* Returns 1 if the address is valid, 0 if not.
* This replaces inet_addr, the return value from which
* cannot distinguish between failure and a local broadcast address.
*
* @param cp IP address in ascii represenation (e.g. "127.0.0.1")
* @param addr pointer to which to save the ip address in network order
* @return 1 if cp could be converted to addr, 0 on failure
*/
int
ipaddr_aton(const char *cp, ip_addr_t *addr)
{
u32_t val;
u8_t base;
char c;
u32_t parts[4];
u32_t *pp = parts;
c = *cp;
for (;;) {
/*
* Collect number up to ``.''.
* Values are specified as for C:
* 0x=hex, 0=octal, 1-9=decimal.
*/
if (!isdigit(c))
return (0);
val = 0;
base = 10;
if (c == '0') {
c = *++cp;
if (c == 'x' || c == 'X') {
base = 16;
c = *++cp;
} else
base = 8;
}
for (;;) {
if (isdigit(c)) {
val = (val * base) + (int)(c - '0');
c = *++cp;
} else if (base == 16 && isxdigit(c)) {
val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));
c = *++cp;
} else
break;
}
if (c == '.') {
/*
* Internet format:
* a.b.c.d
* a.b.c (with c treated as 16 bits)
* a.b (with b treated as 24 bits)
*/
if (pp >= parts + 3) {
return (0);
}
*pp++ = val;
c = *++cp;
} else
break;
}
/*
* Check for trailing characters.
*/
if (c != '\0' && !isspace(c)) {
return (0);
}
/*
* Concoct the address according to
* the number of parts specified.
*/
switch (pp - parts + 1) {
case 0:
return (0); /* initial nondigit */
case 1: /* a -- 32 bits */
break;
case 2: /* a.b -- 8.24 bits */
if (val > 0xffffffUL) {
return (0);
}
val |= parts[0] << 24;
break;
case 3: /* a.b.c -- 8.8.16 bits */
if (val > 0xffff) {
return (0);
}
val |= (parts[0] << 24) | (parts[1] << 16);
break;
case 4: /* a.b.c.d -- 8.8.8.8 bits */
if (val > 0xff) {
return (0);
}
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
break;
default:
LWIP_ASSERT("unhandled", 0);
break;
}
if (addr) {
ip4_addr_set_u32(addr, htonl(val));
}
return (1);
}
/**
* Convert numeric IP address into decimal dotted ASCII representation.
* returns ptr to static buffer; not reentrant!
*
* @param addr ip address in network order to convert
* @return pointer to a global static (!) buffer that holds the ASCII
* represenation of addr
*/
char *
ipaddr_ntoa(const ip_addr_t *addr)
{
static char str[16];
return ipaddr_ntoa_r(addr, str, 16);
}
/**
* Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
*
* @param addr ip address in network order to convert
* @param buf target buffer where the string is stored
* @param buflen length of buf
* @return either pointer to buf which now holds the ASCII
* representation of addr or NULL if buf was too small
*/
char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)
{
u32_t s_addr;
char inv[3];
char *rp;
u8_t *ap;
u8_t rem;
u8_t n;
u8_t i;
int len = 0;
s_addr = ip4_addr_get_u32(addr);
rp = buf;
ap = (u8_t *)&s_addr;
for(n = 0; n < 4; n++) {
i = 0;
do {
rem = *ap % (u8_t)10;
*ap /= (u8_t)10;
inv[i++] = '0' + rem;
} while(*ap);
while(i--) {
if (len++ >= buflen) {
return NULL;
}
*rp++ = inv[i];
}
if (len++ >= buflen) {
return NULL;
}
*rp++ = '.';
ap++;
}
*--rp = 0;
return buf;
}

View file

@ -40,8 +40,7 @@
#include "lwip/opt.h"
#include "lwip/ip_frag.h"
#include "lwip/ip.h"
#include "lwip/inet.h"
#include "lwip/def.h"
#include "lwip/inet_chksum.h"
#include "lwip/netif.h"
#include "lwip/snmp.h"
@ -81,7 +80,10 @@
/** This is a helper struct which holds the starting
* offset and the ending offset of this fragment to
* easily chain the fragments.
* It has to be packed since it has to fit inside the IP header.
* It has the same packing requirements as the IP header, since it replaces
* the IP header in memory in incoming fragments (after copying it) to keep
* track of the various fragments. (-> If the IP header doesn't need packing,
* this struct doesn't need packing, too.)
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
@ -155,7 +157,8 @@ ip_reass_tmr(void)
static int
ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
{
int pbufs_freed = 0;
u16_t pbufs_freed = 0;
u8_t clen;
struct pbuf *p;
struct ip_reass_helper *iprh;
@ -175,7 +178,9 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p
/* Then, copy the original header into it. */
SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);
icmp_time_exceeded(p, ICMP_TE_FRAG);
pbufs_freed += pbuf_clen(p);
clen = pbuf_clen(p);
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
pbufs_freed += clen;
pbuf_free(p);
}
#endif /* LWIP_ICMP */
@ -189,8 +194,10 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p
pcur = p;
/* get the next pointer before freeing */
p = iprh->next_pbuf;
pbufs_freed += pbuf_clen(pcur);
pbuf_free(pcur);
clen = pbuf_clen(pcur);
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
pbufs_freed += clen;
pbuf_free(pcur);
}
/* Then, unchain the struct ip_reassdata from the list and free it. */
ip_reass_dequeue_datagram(ipr, prev);
@ -263,11 +270,11 @@ ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)
{
struct ip_reassdata* ipr;
/* No matching previous fragment found, allocate a new reassdata struct */
ipr = memp_malloc(MEMP_REASSDATA);
ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
if (ipr == NULL) {
#if IP_REASS_FREE_OLDEST
if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) {
ipr = memp_malloc(MEMP_REASSDATA);
ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
}
if (ipr == NULL)
#endif /* IP_REASS_FREE_OLDEST */
@ -548,7 +555,7 @@ ip_reass(struct pbuf *p)
* to an existing one */
/* check for 'no more fragments', and update queue entry*/
if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {
if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) {
ipr->flags |= IP_REASS_FLAG_LASTFRAG;
ipr->datagram_len = offset + len;
LWIP_DEBUGF(IP_REASS_DEBUG,
@ -609,6 +616,38 @@ nullreturn:
#if IP_FRAG
#if IP_FRAG_USES_STATIC_BUF
static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];
#else /* IP_FRAG_USES_STATIC_BUF */
#if !LWIP_NETIF_TX_SINGLE_PBUF
/** Allocate a new struct pbuf_custom_ref */
static struct pbuf_custom_ref*
ip_frag_alloc_pbuf_custom_ref(void)
{
return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
}
/** Free a struct pbuf_custom_ref */
static void
ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p)
{
LWIP_ASSERT("p != NULL", p != NULL);
memp_free(MEMP_FRAG_PBUF, p);
}
/** Free-callback function to free a 'struct pbuf_custom_ref', called by
* pbuf_free. */
static void
ipfrag_free_pbuf_custom(struct pbuf *p)
{
struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p;
LWIP_ASSERT("pcr != NULL", pcr != NULL);
LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p);
if (pcr->original != NULL) {
pbuf_free(pcr->original);
}
ip_frag_free_pbuf_custom_ref(pcr);
}
#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
#endif /* IP_FRAG_USES_STATIC_BUF */
/**
@ -625,13 +664,15 @@ static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];
* @return ERR_OK if sent successfully, err_t otherwise
*/
err_t
ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
{
struct pbuf *rambuf;
#if IP_FRAG_USES_STATIC_BUF
struct pbuf *header;
#else
#if !LWIP_NETIF_TX_SINGLE_PBUF
struct pbuf *newpbuf;
#endif
struct ip_hdr *original_iphdr;
#endif
struct ip_hdr *iphdr;
@ -642,7 +683,7 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
u16_t last;
u16_t poff = IP_HLEN;
u16_t tmp;
#if !IP_FRAG_USES_STATIC_BUF
#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
u16_t newpbuflen = 0;
u16_t left_to_copy;
#endif
@ -662,10 +703,10 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
rambuf->payload = LWIP_MEM_ALIGN((void *)buf);
/* Copy the IP header in it */
iphdr = rambuf->payload;
iphdr = (struct ip_hdr *)rambuf->payload;
SMEMCPY(iphdr, p->payload, IP_HLEN);
#else /* IP_FRAG_USES_STATIC_BUF */
original_iphdr = p->payload;
original_iphdr = (struct ip_hdr *)p->payload;
iphdr = original_iphdr;
#endif /* IP_FRAG_USES_STATIC_BUF */
@ -683,8 +724,9 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
/* Set new offset and MF flag */
tmp = omf | (IP_OFFMASK & (ofo));
if (!last)
if (!last) {
tmp = tmp | IP_MF;
}
/* Fill this fragment */
cop = last ? left : nfb * 8;
@ -692,6 +734,23 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
#if IP_FRAG_USES_STATIC_BUF
poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);
#else /* IP_FRAG_USES_STATIC_BUF */
#if LWIP_NETIF_TX_SINGLE_PBUF
rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM);
if (rambuf == NULL) {
return ERR_MEM;
}
LWIP_ASSERT("this needs a pbuf in one piece!",
(rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
poff += pbuf_copy_partial(p, rambuf->payload, cop, poff);
/* make room for the IP header */
if(pbuf_header(rambuf, IP_HLEN)) {
pbuf_free(rambuf);
return ERR_MEM;
}
/* fill in the IP header */
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
iphdr = rambuf->payload;
#else /* LWIP_NETIF_TX_SINGLE_PBUF */
/* When not using a static buffer, create a chain of pbufs.
* The first will be a PBUF_RAM holding the link and IP header.
* The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
@ -704,7 +763,7 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
LWIP_ASSERT("this needs a pbuf in one piece!",
(p->len >= (IP_HLEN)));
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
iphdr = rambuf->payload;
iphdr = (struct ip_hdr *)rambuf->payload;
/* Can just adjust p directly for needed offset. */
p->payload = (u8_t *)p->payload + poff;
@ -712,29 +771,40 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
left_to_copy = cop;
while (left_to_copy) {
struct pbuf_custom_ref *pcr;
newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
/* Is this pbuf already empty? */
if (!newpbuflen) {
p = p->next;
continue;
}
newpbuf = pbuf_alloc(PBUF_RAW, 0, PBUF_REF);
if (newpbuf == NULL) {
pcr = ip_frag_alloc_pbuf_custom_ref();
if (pcr == NULL) {
pbuf_free(rambuf);
return ERR_MEM;
}
/* Mirror this pbuf, although we might not need all of it. */
newpbuf->payload = p->payload;
newpbuf->len = newpbuf->tot_len = newpbuflen;
newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
if (newpbuf == NULL) {
ip_frag_free_pbuf_custom_ref(pcr);
pbuf_free(rambuf);
return ERR_MEM;
}
pbuf_ref(p);
pcr->original = p;
pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;
/* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
* so that it is removed when pbuf_dechain is later called on rambuf.
*/
pbuf_cat(rambuf, newpbuf);
left_to_copy -= newpbuflen;
if (left_to_copy)
if (left_to_copy) {
p = p->next;
}
}
poff = newpbuflen;
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
#endif /* IP_FRAG_USES_STATIC_BUF */
/* Correct header */
@ -744,8 +814,9 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
#if IP_FRAG_USES_STATIC_BUF
if (last)
if (last) {
pbuf_realloc(rambuf, left + IP_HLEN);
}
/* This part is ugly: we alloc a RAM based pbuf for
* the link level header for each chunk and then

View file

@ -48,7 +48,7 @@
#include "lwip/netif.h"
#include "lwip/icmp.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/tcp_impl.h"
#include "lwip/stats.h"

View file

@ -61,6 +61,7 @@
#include "lwip/mem.h"
#include "lwip/sys.h"
#include "lwip/stats.h"
#include "lwip/err.h"
#include <string.h>
@ -81,7 +82,7 @@ mem_malloc(mem_size_t size)
memp_t poolnr;
mem_size_t required_size = size + sizeof(struct memp_malloc_helper);
for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr++) {
for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) {
#if MEM_USE_POOLS_TRY_BIGGER_POOL
again:
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
@ -154,7 +155,7 @@ mem_free(void *rmem)
struct mem {
/** index (-> ram[next]) of the next struct */
mem_size_t next;
/** index (-> ram[next]) of the next struct */
/** index (-> ram[prev]) of the previous struct */
mem_size_t prev;
/** 1: this area is used; 0: this area is unused */
u8_t used;
@ -171,8 +172,16 @@ struct mem {
#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))
#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE)
/** If you want to relocate the heap to external memory, simply define
* LWIP_RAM_HEAP_POINTER as a void-pointer to that location.
* If so, make sure the memory at that location is big enough (see below on
* how that space is calculated). */
#ifndef LWIP_RAM_HEAP_POINTER
/** the heap. we need one struct mem at the end and some room for alignment */
static u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];
u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];
#define LWIP_RAM_HEAP_POINTER ram_heap
#endif /* LWIP_RAM_HEAP_POINTER */
/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */
static u8_t *ram;
/** the last entry, always unused! */
@ -181,7 +190,7 @@ static struct mem *ram_end;
static struct mem *lfree;
/** concurrent access protection */
static sys_sem_t mem_sem;
static sys_mutex_t mem_mutex;
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
@ -199,8 +208,8 @@ static volatile u8_t mem_free_count;
/* Protect the heap only by using a semaphore */
#define LWIP_MEM_FREE_DECL_PROTECT()
#define LWIP_MEM_FREE_PROTECT() sys_arch_sem_wait(mem_sem, 0)
#define LWIP_MEM_FREE_UNPROTECT() sys_sem_signal(mem_sem)
#define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex)
#define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex)
/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */
#define LWIP_MEM_ALLOC_DECL_PROTECT()
#define LWIP_MEM_ALLOC_PROTECT()
@ -215,7 +224,7 @@ static volatile u8_t mem_free_count;
* one empty struct mem pointing to another empty struct mem.
*
* @param mem this points to a struct mem which just has been freed
* @internal this function is only called by mem_free() and mem_realloc()
* @internal this function is only called by mem_free() and mem_trim()
*
* This assumes access to the heap is protected by the calling function
* already.
@ -233,25 +242,25 @@ plug_holes(struct mem *mem)
/* plug hole forward */
LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED);
nmem = (struct mem *)&ram[mem->next];
nmem = (struct mem *)(void *)&ram[mem->next];
if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
/* if mem->next is unused and not end of ram, combine mem and mem->next */
if (lfree == nmem) {
lfree = mem;
}
mem->next = nmem->next;
((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;
((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram);
}
/* plug hole backward */
pmem = (struct mem *)&ram[mem->prev];
pmem = (struct mem *)(void *)&ram[mem->prev];
if (pmem != mem && pmem->used == 0) {
/* if mem->prev is unused, combine mem and mem->prev */
if (lfree == mem) {
lfree = pmem;
}
pmem->next = mem->next;
((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;
((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram);
}
}
@ -267,24 +276,26 @@ mem_init(void)
(SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0);
/* align the heap */
ram = LWIP_MEM_ALIGN(ram_heap);
ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER);
/* initialize the start of the heap */
mem = (struct mem *)ram;
mem = (struct mem *)(void *)ram;
mem->next = MEM_SIZE_ALIGNED;
mem->prev = 0;
mem->used = 0;
/* initialize the end of the heap */
ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED];
ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED];
ram_end->used = 1;
ram_end->next = MEM_SIZE_ALIGNED;
ram_end->prev = MEM_SIZE_ALIGNED;
mem_sem = sys_sem_new(1);
/* initialize the lowest-free pointer to the start of the heap */
lfree = (struct mem *)ram;
lfree = (struct mem *)(void *)ram;
MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
if(sys_mutex_new(&mem_mutex) != ERR_OK) {
LWIP_ASSERT("failed to create mem_mutex", 0);
}
}
/**
@ -320,7 +331,7 @@ mem_free(void *rmem)
/* protect the heap from concurrent access */
LWIP_MEM_FREE_PROTECT();
/* Get the corresponding struct mem ... */
mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
/* ... which has to be in a used state ... */
LWIP_ASSERT("mem_free: mem->used", mem->used);
/* ... and is now unused. */
@ -331,7 +342,7 @@ mem_free(void *rmem)
lfree = mem;
}
MEM_STATS_DEC_USED(used, mem->next - ((u8_t *)mem - ram));
MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram)));
/* finally, see if prev or next are free also */
plug_holes(mem);
@ -342,9 +353,7 @@ mem_free(void *rmem)
}
/**
* In contrast to its name, mem_realloc can only shrink memory, not expand it.
* Since the only use (for now) is in pbuf_realloc (which also can only shrink),
* this shouldn't be a problem!
* Shrink memory returned by mem_malloc().
*
* @param rmem pointer to memory allocated by mem_malloc the is to be shrinked
* @param newsize required size after shrinking (needs to be smaller than or
@ -354,7 +363,7 @@ mem_free(void *rmem)
* or freed!
*/
void *
mem_realloc(void *rmem, mem_size_t newsize)
mem_trim(void *rmem, mem_size_t newsize)
{
mem_size_t size;
mem_size_t ptr, ptr2;
@ -375,12 +384,12 @@ mem_realloc(void *rmem, mem_size_t newsize)
return NULL;
}
LWIP_ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
(u8_t *)rmem < (u8_t *)ram_end);
if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
SYS_ARCH_DECL_PROTECT(lev);
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_realloc: illegal memory\n"));
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n"));
/* protect mem stats from concurrent access */
SYS_ARCH_PROTECT(lev);
MEM_STATS_INC(illegal);
@ -388,12 +397,12 @@ mem_realloc(void *rmem, mem_size_t newsize)
return rmem;
}
/* Get the corresponding struct mem ... */
mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
/* ... and its offset pointer */
ptr = (u8_t *)mem - ram;
ptr = (mem_size_t)((u8_t *)mem - ram);
size = mem->next - ptr - SIZEOF_STRUCT_MEM;
LWIP_ASSERT("mem_realloc can only shrink memory", newsize <= size);
LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size);
if (newsize > size) {
/* not supported */
return NULL;
@ -406,9 +415,7 @@ mem_realloc(void *rmem, mem_size_t newsize)
/* protect the heap from concurrent access */
LWIP_MEM_FREE_PROTECT();
MEM_STATS_DEC_USED(used, (size - newsize));
mem2 = (struct mem *)&ram[mem->next];
mem2 = (struct mem *)(void *)&ram[mem->next];
if(mem2->used == 0) {
/* The next struct is unused, we can simply move it at little */
mem_size_t next;
@ -417,9 +424,9 @@ mem_realloc(void *rmem, mem_size_t newsize)
/* create new struct mem which is moved directly after the shrinked mem */
ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
if (lfree == mem2) {
lfree = (struct mem *)&ram[ptr2];
lfree = (struct mem *)(void *)&ram[ptr2];
}
mem2 = (struct mem *)&ram[ptr2];
mem2 = (struct mem *)(void *)&ram[ptr2];
mem2->used = 0;
/* restore the next pointer */
mem2->next = next;
@ -431,8 +438,9 @@ mem_realloc(void *rmem, mem_size_t newsize)
* let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not
* the end of the heap */
if (mem2->next != MEM_SIZE_ALIGNED) {
((struct mem *)&ram[mem2->next])->prev = ptr2;
((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
}
MEM_STATS_DEC_USED(used, (size - newsize));
/* no need to plug holes, we've already done that */
} else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {
/* Next struct is used but there's room for another struct mem with
@ -443,7 +451,7 @@ mem_realloc(void *rmem, mem_size_t newsize)
* region that couldn't hold data, but when mem->next gets freed,
* the 2 regions would be combined, resulting in more free memory */
ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
mem2 = (struct mem *)&ram[ptr2];
mem2 = (struct mem *)(void *)&ram[ptr2];
if (mem2 < lfree) {
lfree = mem2;
}
@ -452,8 +460,9 @@ mem_realloc(void *rmem, mem_size_t newsize)
mem2->prev = ptr;
mem->next = ptr2;
if (mem2->next != MEM_SIZE_ALIGNED) {
((struct mem *)&ram[mem2->next])->prev = ptr2;
((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
}
MEM_STATS_DEC_USED(used, (size - newsize));
/* the original mem->next is used, so no need to plug holes! */
}
/* else {
@ -506,7 +515,7 @@ mem_malloc(mem_size_t size)
}
/* protect the heap from concurrent access */
sys_arch_sem_wait(mem_sem, 0);
sys_mutex_lock(&mem_mutex);
LWIP_MEM_ALLOC_PROTECT();
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
/* run as long as a mem_free disturbed mem_malloc */
@ -517,9 +526,9 @@ mem_malloc(mem_size_t size)
/* Scan through the heap searching for a free block that is big enough,
* beginning with the lowest free block.
*/
for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;
ptr = ((struct mem *)&ram[ptr])->next) {
mem = (struct mem *)&ram[ptr];
for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size;
ptr = ((struct mem *)(void *)&ram[ptr])->next) {
mem = (struct mem *)(void *)&ram[ptr];
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_free_count = 0;
LWIP_MEM_ALLOC_UNPROTECT();
@ -549,7 +558,7 @@ mem_malloc(mem_size_t size)
*/
ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
/* create mem2 struct */
mem2 = (struct mem *)&ram[ptr2];
mem2 = (struct mem *)(void *)&ram[ptr2];
mem2->used = 0;
mem2->next = mem->next;
mem2->prev = ptr;
@ -558,7 +567,7 @@ mem_malloc(mem_size_t size)
mem->used = 1;
if (mem2->next != MEM_SIZE_ALIGNED) {
((struct mem *)&ram[mem2->next])->prev = ptr2;
((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
}
MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));
} else {
@ -570,7 +579,7 @@ mem_malloc(mem_size_t size)
* will always be used at this point!
*/
mem->used = 1;
MEM_STATS_INC_USED(used, mem->next - ((u8_t *)mem - ram));
MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram));
}
if (mem == lfree) {
@ -579,12 +588,12 @@ mem_malloc(mem_size_t size)
LWIP_MEM_ALLOC_UNPROTECT();
/* prevent high interrupt latency... */
LWIP_MEM_ALLOC_PROTECT();
lfree = (struct mem *)&ram[lfree->next];
lfree = (struct mem *)(void *)&ram[lfree->next];
}
LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
}
LWIP_MEM_ALLOC_UNPROTECT();
sys_sem_signal(mem_sem);
sys_mutex_unlock(&mem_mutex);
LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
(mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
@ -602,7 +611,7 @@ mem_malloc(mem_size_t size)
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
MEM_STATS_INC(err);
LWIP_MEM_ALLOC_UNPROTECT();
sys_sem_signal(mem_sem);
sys_mutex_unlock(&mem_mutex);
return NULL;
}

View file

@ -44,15 +44,20 @@
#include "lwip/pbuf.h"
#include "lwip/udp.h"
#include "lwip/raw.h"
#include "lwip/tcp.h"
#include "lwip/tcp_impl.h"
#include "lwip/igmp.h"
#include "lwip/api.h"
#include "lwip/api_msg.h"
#include "lwip/tcpip.h"
#include "lwip/sys.h"
#include "lwip/timers.h"
#include "lwip/stats.h"
#include "netif/etharp.h"
#include "lwip/ip_frag.h"
#include "lwip/snmp_structs.h"
#include "lwip/snmp_msg.h"
#include "lwip/dns.h"
#include "netif/ppp_oe.h"
#include <string.h>
@ -142,12 +147,33 @@ static const char *memp_desc[MEMP_MAX] = {
};
#endif /* LWIP_DEBUG */
/** This is the actual memory used by the pools. */
#if MEMP_SEPARATE_POOLS
/** This creates each memory pool. These are named memp_memory_XXX_base (where
* XXX is the name of the pool defined in memp_std.h).
* To relocate a pool, declare it as extern in cc.h. Example for GCC:
* extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_UDP_PCB_base[];
*/
#define LWIP_MEMPOOL(name,num,size,desc) u8_t memp_memory_ ## name ## _base \
[((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))];
#include "lwip/memp_std.h"
/** This array holds the base of each memory pool. */
static u8_t *const memp_bases[] = {
#define LWIP_MEMPOOL(name,num,size,desc) memp_memory_ ## name ## _base,
#include "lwip/memp_std.h"
};
#else /* MEMP_SEPARATE_POOLS */
/** This is the actual memory used by the pools (all pools in one big block). */
static u8_t memp_memory[MEM_ALIGNMENT - 1
#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
#include "lwip/memp_std.h"
];
#endif /* MEMP_SEPARATE_POOLS */
#if MEMP_SANITY_CHECK
/**
* Check that memp-lists don't form a circle
@ -172,15 +198,55 @@ memp_sanity(void)
}
#endif /* MEMP_SANITY_CHECK*/
#if MEMP_OVERFLOW_CHECK
#if defined(LWIP_DEBUG) && MEMP_STATS
static const char * memp_overflow_names[] = {
#define LWIP_MEMPOOL(name,num,size,desc) "/"desc,
#include "lwip/memp_std.h"
};
#endif
/**
* Check if a memp element was victim of an overflow
* (e.g. the restricted area after it has been altered)
*
* @param p the memp element to check
* @param memp_size the element size of the pool p comes from
* @param memp_type the pool p comes from
*/
static void
memp_overflow_check_element(struct memp *p, u16_t memp_size)
memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type)
{
u16_t k;
u8_t *m;
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type];
for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
if (m[k] != 0xcd) {
char errstr[128] = "detected memp overflow in pool ";
char digit[] = "0";
if(memp_type >= 10) {
digit[0] = '0' + (memp_type/10);
strcat(errstr, digit);
}
digit[0] = '0' + (memp_type%10);
strcat(errstr, digit);
#if defined(LWIP_DEBUG) && MEMP_STATS
strcat(errstr, memp_overflow_names[memp_type]);
#endif
LWIP_ASSERT(errstr, 0);
}
}
#endif
}
/**
* Check if a memp element was victim of an underflow
* (e.g. the restricted area before it has been altered)
*
* @param p the memp element to check
* @param memp_type the pool p comes from
*/
static void
memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type)
{
u16_t k;
u8_t *m;
@ -188,15 +254,18 @@ memp_overflow_check_element(struct memp *p, u16_t memp_size)
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {
if (m[k] != 0xcd) {
LWIP_ASSERT("detected memp underflow!", 0);
}
}
char errstr[128] = "detected memp underflow in pool ";
char digit[] = "0";
if(memp_type >= 10) {
digit[0] = '0' + (memp_type/10);
strcat(errstr, digit);
}
digit[0] = '0' + (memp_type%10);
strcat(errstr, digit);
#if defined(LWIP_DEBUG) && MEMP_STATS
strcat(errstr, memp_overflow_names[memp_type]);
#endif
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE + memp_size;
for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
if (m[k] != 0xcd) {
LWIP_ASSERT("detected memp overflow!", 0);
LWIP_ASSERT(errstr, 0);
}
}
#endif
@ -213,11 +282,19 @@ memp_overflow_check_all(void)
u16_t i, j;
struct memp *p;
p = LWIP_MEM_ALIGN(memp_memory);
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
for (i = 0; i < MEMP_MAX; ++i) {
p = p;
for (j = 0; j < memp_num[i]; ++j) {
memp_overflow_check_element(p, memp_sizes[i]);
memp_overflow_check_element_overflow(p, i);
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
}
}
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
for (i = 0; i < MEMP_MAX; ++i) {
p = p;
for (j = 0; j < memp_num[i]; ++j) {
memp_overflow_check_element_underflow(p, i);
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
}
}
@ -233,7 +310,7 @@ memp_overflow_init(void)
struct memp *p;
u8_t *m;
p = LWIP_MEM_ALIGN(memp_memory);
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
for (i = 0; i < MEMP_MAX; ++i) {
p = p;
for (j = 0; j < memp_num[i]; ++j) {
@ -269,15 +346,20 @@ memp_init(void)
MEMP_STATS_AVAIL(avail, i, memp_num[i]);
}
memp = LWIP_MEM_ALIGN(memp_memory);
#if !MEMP_SEPARATE_POOLS
memp = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
#endif /* !MEMP_SEPARATE_POOLS */
/* for every pool: */
for (i = 0; i < MEMP_MAX; ++i) {
memp_tab[i] = NULL;
#if MEMP_SEPARATE_POOLS
memp = (struct memp*)memp_bases[i];
#endif /* MEMP_SEPARATE_POOLS */
/* create a linked list of memp elements */
for (j = 0; j < memp_num[i]; ++j) {
memp->next = memp_tab[i];
memp_tab[i] = memp;
memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]
memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]
#if MEMP_OVERFLOW_CHECK
+ MEMP_SANITY_REGION_AFTER_ALIGNED
#endif
@ -331,7 +413,7 @@ memp_malloc_fn(memp_t type, const char* file, const int line)
MEMP_STATS_INC_USED(used, type);
LWIP_ASSERT("memp_malloc: memp properly aligned",
((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
memp = (struct memp*)((u8_t*)memp + MEMP_SIZE);
memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE);
} else {
LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
MEMP_STATS_INC(err, type);
@ -360,14 +442,15 @@ memp_free(memp_t type, void *mem)
LWIP_ASSERT("memp_free: mem properly aligned",
((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);
memp = (struct memp *)((u8_t*)mem - MEMP_SIZE);
memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE);
SYS_ARCH_PROTECT(old_level);
#if MEMP_OVERFLOW_CHECK
#if MEMP_OVERFLOW_CHECK >= 2
memp_overflow_check_all();
#else
memp_overflow_check_element(memp, memp_sizes[type]);
memp_overflow_check_element_overflow(memp, type);
memp_overflow_check_element_underflow(memp, type);
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
#endif /* MEMP_OVERFLOW_CHECK */

View file

@ -41,10 +41,11 @@
#include "lwip/def.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/tcp.h"
#include "lwip/tcp_impl.h"
#include "lwip/snmp.h"
#include "lwip/igmp.h"
#include "netif/etharp.h"
#include "lwip/stats.h"
#if ENABLE_LOOPBACK
#include "lwip/sys.h"
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
@ -60,20 +61,64 @@
#endif /* LWIP_DHCP */
#if LWIP_NETIF_STATUS_CALLBACK
#define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); }
#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0)
#else
#define NETIF_STATUS_CALLBACK(n) { /* NOP */ }
#define NETIF_STATUS_CALLBACK(n)
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_LINK_CALLBACK
#define NETIF_LINK_CALLBACK(n) { if (n->link_callback) (n->link_callback)(n); }
#define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0)
#else
#define NETIF_LINK_CALLBACK(n) { /* NOP */ }
#define NETIF_LINK_CALLBACK(n)
#endif /* LWIP_NETIF_LINK_CALLBACK */
struct netif *netif_list;
struct netif *netif_default;
#if LWIP_HAVE_LOOPIF
static struct netif loop_netif;
/**
* Initialize a lwip network interface structure for a loopback interface
*
* @param netif the lwip network interface structure for this loopif
* @return ERR_OK if the loopif is initialized
* ERR_MEM if private data couldn't be allocated
*/
static err_t
netif_loopif_init(struct netif *netif)
{
/* initialize the snmp variables and counters inside the struct netif
* ifSpeed: no assumption can be made!
*/
NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0);
netif->name[0] = 'l';
netif->name[1] = 'o';
netif->output = netif_loop_output;
return ERR_OK;
}
#endif /* LWIP_HAVE_LOOPIF */
void
netif_init(void)
{
#if LWIP_HAVE_LOOPIF
ip_addr_t loop_ipaddr, loop_netmask, loop_gw;
IP4_ADDR(&loop_gw, 127,0,0,1);
IP4_ADDR(&loop_ipaddr, 127,0,0,1);
IP4_ADDR(&loop_netmask, 255,0,0,0);
#if NO_SYS
netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input);
#else /* NO_SYS */
netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input);
#endif /* NO_SYS */
netif_set_up(&loop_netif);
#endif /* LWIP_HAVE_LOOPIF */
}
/**
* Add a network interface to the list of lwIP netifs.
*
@ -89,18 +134,17 @@ struct netif *netif_default;
* @return netif, or NULL if failed.
*/
struct netif *
netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
struct ip_addr *gw,
void *state,
err_t (* init)(struct netif *netif),
err_t (* input)(struct pbuf *p, struct netif *netif))
netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
{
static u8_t netifnum = 0;
LWIP_ASSERT("No init function given", init != NULL);
/* reset new interface configuration state */
netif->ip_addr.addr = 0;
netif->netmask.addr = 0;
netif->gw.addr = 0;
ip_addr_set_zero(&netif->ip_addr);
ip_addr_set_zero(&netif->netmask);
ip_addr_set_zero(&netif->gw);
netif->flags = 0;
#if LWIP_DHCP
/* netif not under DHCP control by default */
@ -150,7 +194,7 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
#if LWIP_IGMP
/* start IGMP processing */
if (netif->flags & NETIF_FLAG_IGMP) {
igmp_start( netif);
igmp_start(netif);
}
#endif /* LWIP_IGMP */
@ -175,8 +219,8 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
* @param gw the new default gateway
*/
void
netif_set_addr(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
struct ip_addr *gw)
netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
ip_addr_t *gw)
{
netif_set_ipaddr(netif, ipaddr);
netif_set_netmask(netif, netmask);
@ -188,41 +232,47 @@ netif_set_addr(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netm
*
* @param netif the network interface to remove
*/
void netif_remove(struct netif * netif)
void
netif_remove(struct netif *netif)
{
if ( netif == NULL ) return;
if (netif == NULL) {
return;
}
#if LWIP_IGMP
/* stop IGMP processing */
if (netif->flags & NETIF_FLAG_IGMP) {
igmp_stop( netif);
igmp_stop(netif);
}
#endif /* LWIP_IGMP */
if (netif_is_up(netif)) {
/* set netif down before removing (call callback function) */
netif_set_down(netif);
}
snmp_delete_ipaddridx_tree(netif);
/* is it the first netif? */
if (netif_list == netif) {
netif_list = netif->next;
snmp_dec_iflist();
}
else {
} else {
/* look for netif further down the list */
struct netif * tmpNetif;
for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {
if (tmpNetif->next == netif) {
tmpNetif->next = netif->next;
snmp_dec_iflist();
break;
}
}
if (tmpNetif == NULL)
return; /* we didn't find any netif today */
}
snmp_dec_iflist();
/* this netif is default? */
if (netif_default == netif)
if (netif_default == netif) {
/* reset default netif */
netif_set_default(NULL);
}
LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
}
@ -266,7 +316,7 @@ netif_find(char *name)
* default gateway
*/
void
netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
{
/* TODO: Handling of obsolete pcbs */
/* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */
@ -275,14 +325,18 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
struct tcp_pcb_listen *lpcb;
/* address is actually being changed? */
if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0)
{
if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {
/* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
pcb = tcp_active_pcbs;
while (pcb != NULL) {
/* PCB bound to current local interface address? */
if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))
#if LWIP_AUTOIP
/* connections to link-local addresses must persist (RFC3927 ch. 1.9) */
&& !ip_addr_islinklocal(&(pcb->local_ip))
#endif /* LWIP_AUTOIP */
) {
/* this connection must be aborted */
struct tcp_pcb *next = pcb->next;
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
@ -312,10 +366,10 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
netif->name[0], netif->name[1],
ip4_addr1(&netif->ip_addr),
ip4_addr2(&netif->ip_addr),
ip4_addr3(&netif->ip_addr),
ip4_addr4(&netif->ip_addr)));
ip4_addr1_16(&netif->ip_addr),
ip4_addr2_16(&netif->ip_addr),
ip4_addr3_16(&netif->ip_addr),
ip4_addr4_16(&netif->ip_addr)));
}
/**
@ -327,15 +381,15 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
* @note call netif_set_addr() if you also want to change ip address and netmask
*/
void
netif_set_gw(struct netif *netif, struct ip_addr *gw)
netif_set_gw(struct netif *netif, ip_addr_t *gw)
{
ip_addr_set(&(netif->gw), gw);
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
netif->name[0], netif->name[1],
ip4_addr1(&netif->gw),
ip4_addr2(&netif->gw),
ip4_addr3(&netif->gw),
ip4_addr4(&netif->gw)));
ip4_addr1_16(&netif->gw),
ip4_addr2_16(&netif->gw),
ip4_addr3_16(&netif->gw),
ip4_addr4_16(&netif->gw)));
}
/**
@ -348,7 +402,7 @@ netif_set_gw(struct netif *netif, struct ip_addr *gw)
* default gateway
*/
void
netif_set_netmask(struct netif *netif, struct ip_addr *netmask)
netif_set_netmask(struct netif *netif, ip_addr_t *netmask)
{
snmp_delete_iprteidx_tree(0, netif);
/* set new netmask to netif */
@ -356,10 +410,10 @@ netif_set_netmask(struct netif *netif, struct ip_addr *netmask)
snmp_insert_iprteidx_tree(0, netif);
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
netif->name[0], netif->name[1],
ip4_addr1(&netif->netmask),
ip4_addr2(&netif->netmask),
ip4_addr3(&netif->netmask),
ip4_addr4(&netif->netmask)));
ip4_addr1_16(&netif->netmask),
ip4_addr2_16(&netif->netmask),
ip4_addr3_16(&netif->netmask),
ip4_addr4_16(&netif->netmask)));
}
/**
@ -371,13 +425,10 @@ netif_set_netmask(struct netif *netif, struct ip_addr *netmask)
void
netif_set_default(struct netif *netif)
{
if (netif == NULL)
{
if (netif == NULL) {
/* remove default route */
snmp_delete_iprteidx_tree(1, netif);
}
else
{
} else {
/* install default route */
snmp_insert_iprteidx_tree(1, netif);
}
@ -397,29 +448,30 @@ netif_set_default(struct netif *netif)
*/
void netif_set_up(struct netif *netif)
{
if ( !(netif->flags & NETIF_FLAG_UP )) {
if (!(netif->flags & NETIF_FLAG_UP)) {
netif->flags |= NETIF_FLAG_UP;
#if LWIP_SNMP
snmp_get_sysuptime(&netif->ts);
#endif /* LWIP_SNMP */
NETIF_LINK_CALLBACK(netif);
NETIF_STATUS_CALLBACK(netif);
if (netif->flags & NETIF_FLAG_LINK_UP) {
#if LWIP_ARP
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
if (netif->flags & NETIF_FLAG_ETHARP) {
etharp_gratuitous(netif);
}
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
if (netif->flags & (NETIF_FLAG_ETHARP)) {
etharp_gratuitous(netif);
}
#endif /* LWIP_ARP */
#if LWIP_IGMP
/* resend IGMP memberships */
if (netif->flags & NETIF_FLAG_IGMP) {
igmp_report_groups( netif);
}
/* resend IGMP memberships */
if (netif->flags & NETIF_FLAG_IGMP) {
igmp_report_groups( netif);
}
#endif /* LWIP_IGMP */
}
}
}
@ -433,73 +485,65 @@ void netif_set_up(struct netif *netif)
*/
void netif_set_down(struct netif *netif)
{
if ( netif->flags & NETIF_FLAG_UP )
{
netif->flags &= ~NETIF_FLAG_UP;
if (netif->flags & NETIF_FLAG_UP) {
netif->flags &= ~NETIF_FLAG_UP;
#if LWIP_SNMP
snmp_get_sysuptime(&netif->ts);
snmp_get_sysuptime(&netif->ts);
#endif
NETIF_LINK_CALLBACK(netif);
NETIF_STATUS_CALLBACK(netif);
}
}
/**
* Ask if an interface is up
*/
u8_t netif_is_up(struct netif *netif)
{
return (netif->flags & NETIF_FLAG_UP)?1:0;
NETIF_STATUS_CALLBACK(netif);
}
}
#if LWIP_NETIF_STATUS_CALLBACK
/**
* Set callback to be called when interface is brought up/down
*/
void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif ))
void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)
{
if ( netif )
netif->status_callback = status_callback;
if (netif) {
netif->status_callback = status_callback;
}
}
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_LINK_CALLBACK
/**
* Called by a driver when its link goes up
*/
void netif_set_link_up(struct netif *netif )
{
netif->flags |= NETIF_FLAG_LINK_UP;
if (!(netif->flags & NETIF_FLAG_LINK_UP)) {
netif->flags |= NETIF_FLAG_LINK_UP;
#if LWIP_DHCP
if (netif->dhcp) {
dhcp_network_changed(netif);
}
if (netif->dhcp) {
dhcp_network_changed(netif);
}
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
if (netif->autoip) {
autoip_network_changed(netif);
}
if (netif->autoip) {
autoip_network_changed(netif);
}
#endif /* LWIP_AUTOIP */
if (netif->flags & NETIF_FLAG_UP) {
if (netif->flags & NETIF_FLAG_UP) {
#if LWIP_ARP
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
if (netif->flags & NETIF_FLAG_ETHARP) {
etharp_gratuitous(netif);
}
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
if (netif->flags & NETIF_FLAG_ETHARP) {
etharp_gratuitous(netif);
}
#endif /* LWIP_ARP */
#if LWIP_IGMP
/* resend IGMP memberships */
if (netif->flags & NETIF_FLAG_IGMP) {
igmp_report_groups( netif);
}
/* resend IGMP memberships */
if (netif->flags & NETIF_FLAG_IGMP) {
igmp_report_groups( netif);
}
#endif /* LWIP_IGMP */
}
NETIF_LINK_CALLBACK(netif);
}
NETIF_LINK_CALLBACK(netif);
}
/**
@ -507,22 +551,17 @@ void netif_set_link_up(struct netif *netif )
*/
void netif_set_link_down(struct netif *netif )
{
netif->flags &= ~NETIF_FLAG_LINK_UP;
NETIF_LINK_CALLBACK(netif);
}
/**
* Ask if a link is up
*/
u8_t netif_is_link_up(struct netif *netif)
{
return (netif->flags & NETIF_FLAG_LINK_UP) ? 1 : 0;
if (netif->flags & NETIF_FLAG_LINK_UP) {
netif->flags &= ~NETIF_FLAG_LINK_UP;
NETIF_LINK_CALLBACK(netif);
}
}
#if LWIP_NETIF_LINK_CALLBACK
/**
* Set callback to be called when link is brought up/down
*/
void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif ))
void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback)
{
if (netif) {
netif->link_callback = link_callback;
@ -547,7 +586,7 @@ void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct
*/
err_t
netif_loop_output(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr)
ip_addr_t *ipaddr)
{
struct pbuf *r;
err_t err;
@ -555,22 +594,36 @@ netif_loop_output(struct netif *netif, struct pbuf *p,
#if LWIP_LOOPBACK_MAX_PBUFS
u8_t clen = 0;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
/* If we have a loopif, SNMP counters are adjusted for it,
* if not they are adjusted for 'netif'. */
#if LWIP_SNMP
#if LWIP_HAVE_LOOPIF
struct netif *stats_if = &loop_netif;
#else /* LWIP_HAVE_LOOPIF */
struct netif *stats_if = netif;
#endif /* LWIP_HAVE_LOOPIF */
#endif /* LWIP_SNMP */
SYS_ARCH_DECL_PROTECT(lev);
LWIP_UNUSED_ARG(ipaddr);
/* Allocate a new pbuf */
r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
if (r == NULL) {
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
snmp_inc_ifoutdiscards(stats_if);
return ERR_MEM;
}
#if LWIP_LOOPBACK_MAX_PBUFS
clen = pbuf_clen(r);
/* check for overflow or too many pbuf on queue */
if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) ||
((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) {
pbuf_free(r);
r = NULL;
return ERR_MEM;
((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) {
pbuf_free(r);
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
snmp_inc_ifoutdiscards(stats_if);
return ERR_MEM;
}
netif->loop_cnt_current += clen;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
@ -578,7 +631,9 @@ netif_loop_output(struct netif *netif, struct pbuf *p,
/* Copy the whole pbuf queue p into the single pbuf r */
if ((err = pbuf_copy(r, p)) != ERR_OK) {
pbuf_free(r);
r = NULL;
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
snmp_inc_ifoutdiscards(stats_if);
return err;
}
@ -599,9 +654,13 @@ netif_loop_output(struct netif *netif, struct pbuf *p,
}
SYS_ARCH_UNPROTECT(lev);
LINK_STATS_INC(link.xmit);
snmp_add_ifoutoctets(stats_if, p->tot_len);
snmp_inc_ifoutucastpkts(stats_if);
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
/* For multithreading environment, schedule a call to netif_poll */
tcpip_callback((void (*)(void *))(netif_poll), netif);
tcpip_callback((tcpip_callback_fn)netif_poll, netif);
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
return ERR_OK;
@ -617,13 +676,22 @@ void
netif_poll(struct netif *netif)
{
struct pbuf *in;
/* If we have a loopif, SNMP counters are adjusted for it,
* if not they are adjusted for 'netif'. */
#if LWIP_SNMP
#if LWIP_HAVE_LOOPIF
struct netif *stats_if = &loop_netif;
#else /* LWIP_HAVE_LOOPIF */
struct netif *stats_if = netif;
#endif /* LWIP_HAVE_LOOPIF */
#endif /* LWIP_SNMP */
SYS_ARCH_DECL_PROTECT(lev);
do {
/* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
SYS_ARCH_PROTECT(lev);
in = netif->loop_first;
if(in != NULL) {
if (in != NULL) {
struct pbuf *in_end = in;
#if LWIP_LOOPBACK_MAX_PBUFS
u8_t clen = pbuf_clen(in);
@ -632,12 +700,12 @@ netif_poll(struct netif *netif)
((netif->loop_cnt_current - clen) < netif->loop_cnt_current));
netif->loop_cnt_current -= clen;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
while(in_end->len != in_end->tot_len) {
while (in_end->len != in_end->tot_len) {
LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
in_end = in_end->next;
}
/* 'in_end' now points to the last pbuf from 'in' */
if(in_end == netif->loop_last) {
if (in_end == netif->loop_last) {
/* this was the last pbuf in the list */
netif->loop_first = netif->loop_last = NULL;
} else {
@ -650,16 +718,19 @@ netif_poll(struct netif *netif)
}
SYS_ARCH_UNPROTECT(lev);
if(in != NULL) {
if (in != NULL) {
LINK_STATS_INC(link.recv);
snmp_add_ifinoctets(stats_if, in->tot_len);
snmp_inc_ifinucastpkts(stats_if);
/* loopback packets are always IP packets! */
if(ip_input(in, netif) != ERR_OK) {
if (ip_input(in, netif) != ERR_OK) {
pbuf_free(in);
}
/* Don't reference the packet any more! */
in = NULL;
}
/* go on while there is a packet on the list */
} while(netif->loop_first != NULL);
} while (netif->loop_first != NULL);
}
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING

View file

@ -71,7 +71,10 @@
#include "lwip/sys.h"
#include "arch/perf.h"
#if TCP_QUEUE_OOSEQ
#include "lwip/tcp.h"
#include "lwip/tcp_impl.h"
#endif
#if LWIP_CHECKSUM_ON_COPY
#include "lwip/inet_chksum.h"
#endif
#include <string.h>
@ -81,9 +84,9 @@
aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
#if !TCP_QUEUE_OOSEQ || NO_SYS
#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS
#define PBUF_POOL_IS_EMPTY()
#else /* !TCP_QUEUE_OOSEQ || NO_SYS */
#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
#ifndef PBUF_POOL_FREE_OOSEQ
#define PBUF_POOL_FREE_OOSEQ 1
@ -145,7 +148,7 @@ pbuf_pool_is_empty(void)
}
}
#endif /* PBUF_POOL_FREE_OOSEQ */
#endif /* !TCP_QUEUE_OOSEQ || NO_SYS */
#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
/**
* Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
@ -211,7 +214,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
switch (type) {
case PBUF_POOL:
/* allocate head of pbuf chain into p */
p = memp_malloc(MEMP_PBUF_POOL);
p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
if (p == NULL) {
PBUF_POOL_IS_EMPTY();
@ -244,7 +247,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
rem_len = length - p->len;
/* any remaining pbufs to be allocated? */
while (rem_len > 0) {
q = memp_malloc(MEMP_PBUF_POOL);
q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
if (q == NULL) {
PBUF_POOL_IS_EMPTY();
/* free chain so far allocated */
@ -298,7 +301,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
/* pbuf references existing (externally allocated) RAM payload? */
case PBUF_REF:
/* only allocate memory for the pbuf structure */
p = memp_malloc(MEMP_PBUF);
p = (struct pbuf *)memp_malloc(MEMP_PBUF);
if (p == NULL) {
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
@ -323,6 +326,67 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
return p;
}
#if LWIP_SUPPORT_CUSTOM_PBUF
/** Initialize a custom pbuf (already allocated).
*
* @param layer flag to define header size
* @param length size of the pbuf's payload
* @param type type of the pbuf (only used to treat the pbuf accordingly, as
* this function allocates no memory)
* @param p pointer to the custom pbuf to initialize (already allocated)
* @param payload_mem pointer to the buffer that is used for payload and headers,
* must be at least big enough to hold 'length' plus the header size,
* may be NULL if set later
* @param payload_mem_len the size of the 'payload_mem' buffer, must be at least
* big enough to hold 'length' plus the header size
*/
struct pbuf*
pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p,
void *payload_mem, u16_t payload_mem_len)
{
u16_t offset;
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length));
/* determine header offset */
offset = 0;
switch (l) {
case PBUF_TRANSPORT:
/* add room for transport (often TCP) layer header */
offset += PBUF_TRANSPORT_HLEN;
/* FALLTHROUGH */
case PBUF_IP:
/* add room for IP layer header */
offset += PBUF_IP_HLEN;
/* FALLTHROUGH */
case PBUF_LINK:
/* add room for link layer header */
offset += PBUF_LINK_HLEN;
break;
case PBUF_RAW:
break;
default:
LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0);
return NULL;
}
if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) {
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length));
return NULL;
}
p->pbuf.next = NULL;
if (payload_mem != NULL) {
p->pbuf.payload = LWIP_MEM_ALIGN((void *)((u8_t *)payload_mem + offset));
} else {
p->pbuf.payload = NULL;
}
p->pbuf.flags = PBUF_FLAG_IS_CUSTOM;
p->pbuf.len = p->pbuf.tot_len = length;
p->pbuf.type = type;
p->pbuf.ref = 1;
return &p->pbuf;
}
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
/**
* Shrink a pbuf chain to a desired length.
@ -383,8 +447,8 @@ pbuf_realloc(struct pbuf *p, u16_t new_len)
/* (other types merely adjust their length fields */
if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
/* reallocate and adjust the length of the pbuf that will be split */
q = mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);
LWIP_ASSERT("mem_realloc give q == NULL", q != NULL);
q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len);
LWIP_ASSERT("mem_trim returned q == NULL", q != NULL);
}
/* adjust length fields for new last pbuf */
q->len = rem_len;
@ -428,8 +492,9 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment)
u16_t increment_magnitude;
LWIP_ASSERT("p != NULL", p != NULL);
if ((header_size_increment == 0) || (p == NULL))
if ((header_size_increment == 0) || (p == NULL)) {
return 0;
}
if (header_size_increment < 0){
increment_magnitude = -header_size_increment;
@ -478,8 +543,7 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment)
* bail out unsuccesfully */
return 1;
}
}
else {
} else {
/* Unknown type */
LWIP_ASSERT("bad pbuf type", 0);
return 1;
@ -570,15 +634,25 @@ pbuf_free(struct pbuf *p)
q = p->next;
LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
type = p->type;
/* is this a pbuf from the pool? */
if (type == PBUF_POOL) {
memp_free(MEMP_PBUF_POOL, p);
/* is this a ROM or RAM referencing pbuf? */
} else if (type == PBUF_ROM || type == PBUF_REF) {
memp_free(MEMP_PBUF, p);
/* type == PBUF_RAM */
} else {
mem_free(p);
#if LWIP_SUPPORT_CUSTOM_PBUF
/* is this a custom pbuf? */
if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) {
struct pbuf_custom *pc = (struct pbuf_custom*)p;
LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL);
pc->custom_free_function(p);
} else
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
{
/* is this a pbuf from the pool? */
if (type == PBUF_POOL) {
memp_free(MEMP_PBUF_POOL, p);
/* is this a ROM or RAM referencing pbuf? */
} else if (type == PBUF_ROM || type == PBUF_REF) {
memp_free(MEMP_PBUF, p);
/* type == PBUF_RAM */
} else {
mem_free(p);
}
}
count++;
/* proceed to next pbuf */
@ -900,8 +974,8 @@ pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
/**
* Creates a single pbuf out of a queue of pbufs.
*
* @remark: The source pbuf 'p' is not freed by this function because that can
* be illegal in some places!
* @remark: Either the source pbuf 'p' is freed by this function or the original
* pbuf 'p' is returned, therefore the caller has to check the result!
*
* @param p the source pbuf
* @param layer pbuf_layer of the new pbuf
@ -927,3 +1001,156 @@ pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
pbuf_free(p);
return q;
}
#if LWIP_CHECKSUM_ON_COPY
/**
* Copies data into a single pbuf (*not* into a pbuf queue!) and updates
* the checksum while copying
*
* @param p the pbuf to copy data into
* @param start_offset offset of p->payload where to copy the data to
* @param dataptr data to copy into the pbuf
* @param len length of data to copy into the pbuf
* @param chksum pointer to the checksum which is updated
* @return ERR_OK if successful, another error if the data does not fit
* within the (first) pbuf (no pbuf queues!)
*/
err_t
pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
u16_t len, u16_t *chksum)
{
u32_t acc;
u16_t copy_chksum;
char *dst_ptr;
LWIP_ASSERT("p != NULL", p != NULL);
LWIP_ASSERT("dataptr != NULL", dataptr != NULL);
LWIP_ASSERT("chksum != NULL", chksum != NULL);
LWIP_ASSERT("len != 0", len != 0);
if ((start_offset >= p->len) || (start_offset + len > p->len)) {
return ERR_ARG;
}
dst_ptr = ((char*)p->payload) + start_offset;
copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len);
if ((start_offset & 1) != 0) {
copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum);
}
acc = *chksum;
acc += copy_chksum;
*chksum = FOLD_U32T(acc);
return ERR_OK;
}
#endif /* LWIP_CHECKSUM_ON_COPY */
/** Get one byte from the specified position in a pbuf
* WARNING: returns zero for offset >= p->tot_len
*
* @param p pbuf to parse
* @param offset offset into p of the byte to return
* @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len
*/
u8_t
pbuf_get_at(struct pbuf* p, u16_t offset)
{
u16_t copy_from = offset;
struct pbuf* q = p;
/* get the correct pbuf */
while ((q != NULL) && (q->len <= copy_from)) {
copy_from -= q->len;
q = q->next;
}
/* return requested data if pbuf is OK */
if ((q != NULL) && (q->len > copy_from)) {
return ((u8_t*)q->payload)[copy_from];
}
return 0;
}
/** Compare pbuf contents at specified offset with memory s2, both of length n
*
* @param p pbuf to compare
* @param offset offset into p at wich to start comparing
* @param s2 buffer to compare
* @param n length of buffer to compare
* @return zero if equal, nonzero otherwise
* (0xffff if p is too short, diffoffset+1 otherwise)
*/
u16_t
pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)
{
u16_t start = offset;
struct pbuf* q = p;
/* get the correct pbuf */
while ((q != NULL) && (q->len <= start)) {
start -= q->len;
q = q->next;
}
/* return requested data if pbuf is OK */
if ((q != NULL) && (q->len > start)) {
u16_t i;
for(i = 0; i < n; i++) {
u8_t a = pbuf_get_at(q, start + i);
u8_t b = ((u8_t*)s2)[i];
if (a != b) {
return i+1;
}
}
return 0;
}
return 0xffff;
}
/** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset
* start_offset.
*
* @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
* return value 'not found'
* @param mem search for the contents of this buffer
* @param mem_len length of 'mem'
* @param start_offset offset into p at which to start searching
* @return 0xFFFF if substr was not found in p or the index where it was found
*/
u16_t
pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)
{
u16_t i;
u16_t max = p->tot_len - mem_len;
if (p->tot_len >= mem_len + start_offset) {
for(i = start_offset; i <= max; ) {
u16_t plus = pbuf_memcmp(p, i, mem, mem_len);
if (plus == 0) {
return i;
} else {
i += plus;
}
}
}
return 0xFFFF;
}
/** Find occurrence of substr with length substr_len in pbuf p, start at offset
* start_offset
* WARNING: in contrast to strstr(), this one does not stop at the first \0 in
* the pbuf/source string!
*
* @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
* return value 'not found'
* @param substr string to search for in p, maximum length is 0xFFFE
* @return 0xFFFF if substr was not found in p or the index where it was found
*/
u16_t
pbuf_strstr(struct pbuf* p, const char* substr)
{
size_t substr_len;
if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) {
return 0xFFFF;
}
substr_len = strlen(substr);
if (substr_len >= 0xFFFF) {
return 0xFFFF;
}
return pbuf_memfind(p, substr, (u16_t)substr_len, 0);
}

View file

@ -44,12 +44,10 @@
#include "lwip/def.h"
#include "lwip/memp.h"
#include "lwip/inet.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/raw.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "arch/perf.h"
#include <string.h>
@ -84,7 +82,7 @@ raw_input(struct pbuf *p, struct netif *inp)
LWIP_UNUSED_ARG(inp);
iphdr = p->payload;
iphdr = (struct ip_hdr *)p->payload;
proto = IPH_PROTO(iphdr);
prev = NULL;
@ -92,16 +90,18 @@ raw_input(struct pbuf *p, struct netif *inp)
/* loop through all raw pcbs until the packet is eaten by one */
/* this allows multiple pcbs to match against the packet by design */
while ((eaten == 0) && (pcb != NULL)) {
if (pcb->protocol == proto) {
if ((pcb->protocol == proto) &&
(ip_addr_isany(&pcb->local_ip) ||
ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest))) {
#if IP_SOF_BROADCAST_RECV
/* broadcast filter? */
if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&(iphdr->dest), inp))
if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&current_iphdr_dest, inp))
#endif /* IP_SOF_BROADCAST_RECV */
{
/* receive callback function available? */
if (pcb->recv != NULL) {
/* the receive callback function did not eat the packet? */
if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0) {
if (pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()) != 0) {
/* receive function ate the packet */
p = NULL;
eaten = 1;
@ -139,7 +139,7 @@ raw_input(struct pbuf *p, struct netif *inp)
* @see raw_disconnect()
*/
err_t
raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr)
raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
{
ip_addr_set(&pcb->local_ip, ipaddr);
return ERR_OK;
@ -159,7 +159,7 @@ raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr)
* @see raw_disconnect() and raw_sendto()
*/
err_t
raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr)
raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr)
{
ip_addr_set(&pcb->remote_ip, ipaddr);
return ERR_OK;
@ -180,10 +180,7 @@ raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr)
* available for others.
*/
void
raw_recv(struct raw_pcb *pcb,
u8_t (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p,
struct ip_addr *addr),
void *recv_arg)
raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
{
/* remember recv() callback and user data */
pcb->recv = recv;
@ -203,11 +200,11 @@ raw_recv(struct raw_pcb *pcb,
*
*/
err_t
raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
{
err_t err;
struct netif *netif;
struct ip_addr *src_ip;
ip_addr_t *src_ip;
struct pbuf *q; /* q will be sent down the stack */
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
@ -221,8 +218,10 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
return ERR_MEM;
}
/* chain header q in front of given pbuf p */
pbuf_chain(q, p);
if (p->tot_len != 0) {
/* chain header q in front of given pbuf p */
pbuf_chain(q, p);
}
/* { first pbuf q points to header pbuf } */
LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
} else {
@ -235,7 +234,8 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
}
if ((netif = ip_route(ipaddr)) == NULL) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr));
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
/* free any temporary header pbuf allocated by pbuf_header() */
if (q != p) {
pbuf_free(q);
@ -245,7 +245,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
#if IP_SOF_BROADCAST
/* broadcast filter? */
if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif) ) {
if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
/* free any temporary header pbuf allocated by pbuf_header() */
if (q != p) {
@ -332,12 +332,13 @@ raw_remove(struct raw_pcb *pcb)
* @see raw_remove()
*/
struct raw_pcb *
raw_new(u8_t proto) {
raw_new(u8_t proto)
{
struct raw_pcb *pcb;
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n"));
pcb = memp_malloc(MEMP_RAW_PCB);
pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB);
/* could allocate RAW PCB? */
if (pcb != NULL) {
/* initialize PCB to all zeroes */

View file

@ -61,7 +61,7 @@ snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)
plen += p->len;
if (ofs < plen)
{
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
*type = *msg_ptr;
return ERR_OK;
@ -94,7 +94,7 @@ snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length
plen += p->len;
if (ofs < plen)
{
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if (*msg_ptr < 0x80)
@ -125,7 +125,7 @@ snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
@ -160,7 +160,7 @@ snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
}
else
{
@ -186,7 +186,7 @@ snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
@ -249,7 +249,7 @@ snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
plen += p->len;
if (ofs < plen)
{
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if ((len > 0) && (len < 6))
{
@ -273,7 +273,7 @@ snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
@ -295,7 +295,7 @@ snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
@ -349,7 +349,7 @@ snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)
plen += p->len;
if (ofs < plen)
{
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if ((len > 0) && (len < 5))
{
@ -386,7 +386,7 @@ snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
@ -439,7 +439,7 @@ snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
plen += p->len;
if (ofs < plen)
{
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
oid->len = 0;
@ -493,7 +493,7 @@ snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
@ -519,7 +519,7 @@ snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
@ -551,7 +551,7 @@ snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
@ -607,7 +607,7 @@ snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw
plen += p->len;
if (ofs < plen)
{
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if (raw_len >= len)
{
@ -623,7 +623,7 @@ snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else

View file

@ -190,7 +190,7 @@ snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type)
plen += p->len;
if (ofs < plen)
{
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
*msg_ptr = type;
return ERR_OK;
@ -222,12 +222,12 @@ snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
plen += p->len;
if (ofs < plen)
{
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if (length < 0x80)
{
*msg_ptr = length;
*msg_ptr = (u8_t)length;
return ERR_OK;
}
else if (length < 0x100)
@ -239,14 +239,14 @@ snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
*msg_ptr = length;
*msg_ptr = (u8_t)length;
return ERR_OK;
}
else
@ -265,7 +265,7 @@ snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
@ -276,12 +276,12 @@ snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
if (i == 0)
{
/* least significant length octet */
*msg_ptr = length;
*msg_ptr = (u8_t)length;
}
else
{
/* most significant length octet */
*msg_ptr = length >> 8;
*msg_ptr = (u8_t)(length >> 8);
}
}
return ERR_OK;
@ -305,7 +305,7 @@ snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
* @see snmp_asn1_enc_u32t_cnt()
*/
err_t
snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)
snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value)
{
u16_t plen, base;
u8_t *msg_ptr;
@ -317,7 +317,7 @@ snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)
plen += p->len;
if (ofs < plen)
{
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if (octets_needed == 5)
@ -331,7 +331,7 @@ snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
@ -343,14 +343,14 @@ snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)
while (octets_needed > 1)
{
octets_needed--;
*msg_ptr = value >> (octets_needed << 3);
*msg_ptr = (u8_t)(value >> (octets_needed << 3));
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
@ -360,7 +360,7 @@ snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)
}
}
/* (only) one least significant octet */
*msg_ptr = value;
*msg_ptr = (u8_t)value;
return ERR_OK;
}
p = p->next;
@ -381,7 +381,7 @@ snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)
* @see snmp_asn1_enc_s32t_cnt()
*/
err_t
snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value)
snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value)
{
u16_t plen, base;
u8_t *msg_ptr;
@ -393,20 +393,20 @@ snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value)
plen += p->len;
if (ofs < plen)
{
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
while (octets_needed > 1)
{
octets_needed--;
*msg_ptr = value >> (octets_needed << 3);
*msg_ptr = (u8_t)(value >> (octets_needed << 3));
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
@ -416,7 +416,7 @@ snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value)
}
}
/* (only) one least significant octet */
*msg_ptr = value;
*msg_ptr = (u8_t)value;
return ERR_OK;
}
p = p->next;
@ -447,7 +447,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
plen += p->len;
if (ofs < plen)
{
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if (ident_len > 1)
@ -460,7 +460,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
else
{
/* calculate prefix */
*msg_ptr = (ident[0] * 40) + ident[1];
*msg_ptr = (u8_t)((ident[0] * 40) + ident[1]);
}
ofs += 1;
if (ofs >= plen)
@ -468,7 +468,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
@ -498,7 +498,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
{
u8_t code;
code = sub_id >> shift;
code = (u8_t)(sub_id >> shift);
if ((code != 0) || (tail != 0))
{
tail = 1;
@ -509,7 +509,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
@ -529,7 +529,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
@ -559,7 +559,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
* @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw)
snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw)
{
u16_t plen, base;
u8_t *msg_ptr;
@ -571,7 +571,7 @@ snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw)
plen += p->len;
if (ofs < plen)
{
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
while (raw_len > 1)
@ -586,7 +586,7 @@ snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw)
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = p->payload;
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else

File diff suppressed because it is too large Load diff

View file

@ -37,7 +37,8 @@
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/snmp_structs.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/netif.h"
/** .iso.org.dod.internet address prefix, @see snmp_iso_*() */
const s32_t prefix[4] = {1, 3, 6, 1};
@ -94,7 +95,7 @@ void
snmp_ifindextonetif(s32_t ifindex, struct netif **netif)
{
struct netif *nif = netif_list;
u16_t i, ifidx;
s32_t i, ifidx;
ifidx = ifindex - 1;
i = 0;
@ -132,18 +133,9 @@ snmp_netiftoifindex(struct netif *netif, s32_t *ifidx)
* @param ip points to output struct
*/
void
snmp_oidtoip(s32_t *ident, struct ip_addr *ip)
snmp_oidtoip(s32_t *ident, ip_addr_t *ip)
{
u32_t ipa;
ipa = ident[0];
ipa <<= 8;
ipa |= ident[1];
ipa <<= 8;
ipa |= ident[2];
ipa <<= 8;
ipa |= ident[3];
ip->addr = ipa;
IP4_ADDR(ip, ident[0], ident[1], ident[2], ident[3]);
}
/**
@ -152,15 +144,12 @@ snmp_oidtoip(s32_t *ident, struct ip_addr *ip)
* @param ident points to s32_t ident[4] output
*/
void
snmp_iptooid(struct ip_addr *ip, s32_t *ident)
snmp_iptooid(ip_addr_t *ip, s32_t *ident)
{
u32_t ipa;
ipa = ip->addr;
ident[0] = (ipa >> 24) & 0xff;
ident[1] = (ipa >> 16) & 0xff;
ident[2] = (ipa >> 8) & 0xff;
ident[3] = ipa & 0xff;
ident[0] = ip4_addr1(ip);
ident[1] = ip4_addr2(ip);
ident[2] = ip4_addr3(ip);
ident[3] = ip4_addr4(ip);
}
struct mib_list_node *
@ -168,7 +157,7 @@ snmp_mib_ln_alloc(s32_t id)
{
struct mib_list_node *ln;
ln = (struct mib_list_node *)mem_malloc(sizeof(struct mib_list_node));
ln = (struct mib_list_node *)memp_malloc(MEMP_SNMP_NODE);
if (ln != NULL)
{
ln->prev = NULL;
@ -182,7 +171,7 @@ snmp_mib_ln_alloc(s32_t id)
void
snmp_mib_ln_free(struct mib_list_node *ln)
{
mem_free(ln);
memp_free(MEMP_SNMP_NODE, ln);
}
struct mib_list_rootnode *
@ -190,7 +179,7 @@ snmp_mib_lrn_alloc(void)
{
struct mib_list_rootnode *lrn;
lrn = (struct mib_list_rootnode*)mem_malloc(sizeof(struct mib_list_rootnode));
lrn = (struct mib_list_rootnode*)memp_malloc(MEMP_SNMP_ROOTNODE);
if (lrn != NULL)
{
lrn->get_object_def = noleafs_get_object_def;
@ -209,7 +198,7 @@ snmp_mib_lrn_alloc(void)
void
snmp_mib_lrn_free(struct mib_list_rootnode *lrn)
{
mem_free(lrn);
memp_free(MEMP_SNMP_ROOTNODE, lrn);
}
/**
@ -456,7 +445,7 @@ snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n)
* @param node points to the root of the tree ('.internet')
* @param ident_len the length of the supplied object identifier
* @param ident points to the array of sub identifiers
* @param np points to the found object instance (rerurn)
* @param np points to the found object instance (return)
* @return pointer to the requested parent (!) node if success, NULL otherwise
*/
struct mib_node *
@ -753,7 +742,8 @@ snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snm
LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));
/* non-leaf, store right child ptr and id */
j = i + 1;
LWIP_ASSERT("i < 0xff", i < 0xff);
j = (u8_t)i + 1;
while ((j < an->maxlength) && (empty_table(an->nptr[j])))
{
j++;
@ -995,7 +985,8 @@ snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snm
LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));
/* non-leaf, store right child ptr and id */
j = i + 1;
LWIP_ASSERT("i < 0xff", i < 0xff);
j = (u8_t)i + 1;
if (j < len)
{
/* right node is the current external node */

View file

@ -36,14 +36,14 @@
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/ip_addr.h"
#include "lwip/mem.h"
#include "lwip/udp.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "lwip/snmp_asn1.h"
#include "lwip/snmp_msg.h"
#include "lwip/snmp_structs.h"
#include "lwip/ip_addr.h"
#include "lwip/memp.h"
#include "lwip/udp.h"
#include "lwip/stats.h"
#include <string.h>
@ -58,7 +58,7 @@ struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS];
/* UDP Protocol Control Block */
struct udp_pcb *snmp1_pcb;
static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
@ -88,6 +88,15 @@ snmp_init(void)
msg_ps++;
}
trap_msg.pcb = snmp1_pcb;
#ifdef SNMP_PRIVATE_MIB_INIT
/* If defined, rhis must be a function-like define to initialize the
* private MIB after the stack has been initialized.
* The private MIB can also be initialized in tcpip_callback (or after
* the stack is initialized), this define is only for convenience. */
SNMP_PRIVATE_MIB_INIT();
#endif /* SNMP_PRIVATE_MIB_INIT */
/* The coldstart trap will only be output
if our outgoing interface is up & configured */
snmp_coldstart_trap();
@ -150,7 +159,8 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
/* translate answer into a known lifeform */
en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
if ((msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) &&
(msg_ps->ext_object_def.access & MIB_ACCESS_READ))
{
msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
en->get_value_q(request_id, &msg_ps->ext_object_def);
@ -171,7 +181,7 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
en = msg_ps->ext_mib_node;
/* allocate output varbind */
vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
LWIP_ASSERT("vb != NULL",vb != NULL);
if (vb != NULL)
{
@ -186,10 +196,12 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
msg_ps->vb_ptr->ident_len = 0;
vb->value_type = msg_ps->ext_object_def.asn_type;
vb->value_len = msg_ps->ext_object_def.v_len;
LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff);
vb->value_len = (u8_t)msg_ps->ext_object_def.v_len;
if (vb->value_len > 0)
{
vb->value = mem_malloc(vb->value_len);
LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE);
vb->value = memp_malloc(MEMP_SNMP_VALUE);
LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
if (vb->value != NULL)
{
@ -205,7 +217,7 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n"));
msg_ps->vb_ptr->ident = vb->ident;
msg_ps->vb_ptr->ident_len = vb->ident_len;
mem_free(vb);
memp_free(MEMP_SNMP_VARBIND, vb);
snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
}
}
@ -268,7 +280,8 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
mn->get_object_def(np.ident_len, np.ident, &object_def);
if (object_def.instance != MIB_OBJECT_NONE)
if ((object_def.instance != MIB_OBJECT_NONE) &&
(object_def.access & MIB_ACCESS_READ))
{
mn = mn;
}
@ -283,7 +296,7 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
/* allocate output varbind */
vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
LWIP_ASSERT("vb != NULL",vb != NULL);
if (vb != NULL)
{
@ -298,10 +311,13 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
msg_ps->vb_ptr->ident_len = 0;
vb->value_type = object_def.asn_type;
vb->value_len = object_def.v_len;
LWIP_ASSERT("invalid length", object_def.v_len <= 0xff);
vb->value_len = (u8_t)object_def.v_len;
if (vb->value_len > 0)
{
vb->value = mem_malloc(vb->value_len);
LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low",
vb->value_len <= SNMP_MAX_VALUE_SIZE);
vb->value = memp_malloc(MEMP_SNMP_VALUE);
LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
if (vb->value != NULL)
{
@ -315,7 +331,7 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));
msg_ps->vb_ptr->ident = vb->ident;
msg_ps->vb_ptr->ident_len = vb->ident_len;
mem_free(vb);
memp_free(MEMP_SNMP_VARBIND, vb);
snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
}
}
@ -394,9 +410,10 @@ snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
/* get_value() answer */
en = msg_ps->ext_mib_node;
LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff);
vb = snmp_varbind_alloc(&msg_ps->ext_oid,
msg_ps->ext_object_def.asn_type,
msg_ps->ext_object_def.v_len);
(u8_t)msg_ps->ext_object_def.v_len);
if (vb != NULL)
{
en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
@ -468,7 +485,8 @@ snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
mn->get_object_def(1, &oid.id[oid.len - 1], &object_def);
vb = snmp_varbind_alloc(&oid, object_def.asn_type, object_def.v_len);
LWIP_ASSERT("invalid length", object_def.v_len <= 0xff);
vb = snmp_varbind_alloc(&oid, object_def.asn_type, (u8_t)object_def.v_len);
if (vb != NULL)
{
msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
@ -538,7 +556,7 @@ snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
/* set_test() answer*/
en = msg_ps->ext_mib_node;
if (msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE)
if (msg_ps->ext_object_def.access & MIB_ACCESS_WRITE)
{
if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&
(en->set_test_a(request_id,&msg_ps->ext_object_def,
@ -653,7 +671,7 @@ snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
{
msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;
if (object_def.access == MIB_OBJECT_READ_WRITE)
if (object_def.access & MIB_ACCESS_WRITE)
{
if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&
(mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
@ -788,123 +806,85 @@ snmp_msg_event(u8_t request_id)
/* lwIP UDP receive callback function */
static void
snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
{
struct udp_hdr *udphdr;
struct snmp_msg_pstat *msg_ps;
u8_t req_idx;
err_t err_ret;
u16_t payload_len = p->tot_len;
u16_t payload_ofs = 0;
u16_t varbind_ofs = 0;
/* suppress unused argument warning */
LWIP_UNUSED_ARG(arg);
/* peek in the UDP header (goto IP payload) */
if(pbuf_header(p, UDP_HLEN)){
LWIP_ASSERT("Can't move to UDP header", 0);
/* traverse input message process list, look for SNMP_MSG_EMPTY */
msg_ps = &msg_input_list[0];
req_idx = 0;
while ((req_idx < SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
{
req_idx++;
msg_ps++;
}
if (req_idx == SNMP_CONCURRENT_REQUESTS)
{
/* exceeding number of concurrent requests */
pbuf_free(p);
return;
}
udphdr = p->payload;
/* check if datagram is really directed at us (including broadcast requests) */
if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == SNMP_IN_PORT))
/* accepting request */
snmp_inc_snmpinpkts();
/* record used 'protocol control block' */
msg_ps->pcb = pcb;
/* source address (network order) */
msg_ps->sip = *addr;
/* source port (host order (lwIP oddity)) */
msg_ps->sp = port;
/* check total length, version, community, pdu type */
err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
/* Only accept requests and requests without error (be robust) */
/* Reject response and trap headers or error requests as input! */
if ((err_ret != ERR_OK) ||
((msg_ps->rt != SNMP_ASN1_PDU_GET_REQ) &&
(msg_ps->rt != SNMP_ASN1_PDU_GET_NEXT_REQ) &&
(msg_ps->rt != SNMP_ASN1_PDU_SET_REQ)) ||
((msg_ps->error_status != SNMP_ES_NOERROR) ||
(msg_ps->error_index != 0)) )
{
struct snmp_msg_pstat *msg_ps;
u8_t req_idx;
/* traverse input message process list, look for SNMP_MSG_EMPTY */
msg_ps = &msg_input_list[0];
req_idx = 0;
while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
{
req_idx++;
msg_ps++;
}
if (req_idx != SNMP_CONCURRENT_REQUESTS)
{
err_t err_ret;
u16_t payload_len;
u16_t payload_ofs;
u16_t varbind_ofs = 0;
/* accepting request */
snmp_inc_snmpinpkts();
/* record used 'protocol control block' */
msg_ps->pcb = pcb;
/* source address (network order) */
msg_ps->sip = *addr;
/* source port (host order (lwIP oddity)) */
msg_ps->sp = port;
/* read UDP payload length from UDP header */
payload_len = ntohs(udphdr->len) - UDP_HLEN;
/* adjust to UDP payload */
payload_ofs = UDP_HLEN;
/* check total length, version, community, pdu type */
err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) ||
(msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) ||
(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) &&
((msg_ps->error_status == SNMP_ES_NOERROR) &&
(msg_ps->error_index == 0)) )
{
/* Only accept requests and requests without error (be robust) */
err_ret = err_ret;
}
else
{
/* Reject response and trap headers or error requests as input! */
err_ret = ERR_ARG;
}
if (err_ret == ERR_OK)
{
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
/* Builds a list of variable bindings. Copy the varbinds from the pbuf
chain to glue them when these are divided over two or more pbuf's. */
err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0))
{
/* we've decoded the incoming message, release input msg now */
pbuf_free(p);
msg_ps->error_status = SNMP_ES_NOERROR;
msg_ps->error_index = 0;
/* find object for each variable binding */
msg_ps->state = SNMP_MSG_SEARCH_OBJ;
/* first variable binding from list to inspect */
msg_ps->vb_idx = 0;
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
/* handle input event and as much objects as possible in one go */
snmp_msg_event(req_idx);
}
else
{
/* varbind-list decode failed, or varbind list empty.
drop request silently, do not return error!
(errors are only returned for a specific varbind failure) */
pbuf_free(p);
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
}
}
else
{
/* header check failed
drop request silently, do not return error! */
pbuf_free(p);
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
}
}
else
{
/* exceeding number of concurrent requests */
pbuf_free(p);
}
}
else
{
/* datagram not for us */
/* header check failed drop request silently, do not return error! */
pbuf_free(p);
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
return;
}
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
/* Builds a list of variable bindings. Copy the varbinds from the pbuf
chain to glue them when these are divided over two or more pbuf's. */
err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
/* we've decoded the incoming message, release input msg now */
pbuf_free(p);
if ((err_ret != ERR_OK) || (msg_ps->invb.count == 0))
{
/* varbind-list decode failed, or varbind list empty.
drop request silently, do not return error!
(errors are only returned for a specific varbind failure) */
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
return;
}
msg_ps->error_status = SNMP_ES_NOERROR;
msg_ps->error_index = 0;
/* find object for each variable binding */
msg_ps->state = SNMP_MSG_SEARCH_OBJ;
/* first variable binding from list to inspect */
msg_ps->vb_idx = 0;
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
/* handle input event and as much objects as possible in one go */
snmp_msg_event(req_idx);
}
/**
@ -978,7 +958,7 @@ snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret,
/* add zero terminator */
len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN));
m_stat->community[len] = 0;
m_stat->com_strlen = len;
m_stat->com_strlen = (u8_t)len;
if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0)
{
/** @todo: move this if we need to check more names */
@ -1195,7 +1175,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_
vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t));
if (vb != NULL)
{
s32_t *vptr = vb->value;
s32_t *vptr = (s32_t*)vb->value;
derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr);
snmp_varbind_tail_add(&m_stat->invb, vb);
@ -1211,7 +1191,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_
vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t));
if (vb != NULL)
{
u32_t *vptr = vb->value;
u32_t *vptr = (u32_t*)vb->value;
derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr);
snmp_varbind_tail_add(&m_stat->invb, vb);
@ -1223,10 +1203,11 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
vb = snmp_varbind_alloc(&oid, type, len);
LWIP_ASSERT("invalid length", len <= 0xff);
vb = snmp_varbind_alloc(&oid, type, (u8_t)len);
if (vb != NULL)
{
derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value);
snmp_varbind_tail_add(&m_stat->invb, vb);
}
else
@ -1254,7 +1235,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_
if (vb != NULL)
{
u8_t i = oid_value.len;
s32_t *vptr = vb->value;
s32_t *vptr = (s32_t*)vb->value;
while(i > 0)
{
@ -1277,7 +1258,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_
vb = snmp_varbind_alloc(&oid, type, 4);
if (vb != NULL)
{
derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value);
snmp_varbind_tail_add(&m_stat->invb, vb);
}
else
@ -1323,7 +1304,7 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
{
struct snmp_varbind *vb;
vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
LWIP_ASSERT("vb != NULL",vb != NULL);
if (vb != NULL)
{
@ -1335,12 +1316,13 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
vb->ident_len = i;
if (i > 0)
{
LWIP_ASSERT("SNMP_MAX_TREE_DEPTH is configured too low", i <= SNMP_MAX_TREE_DEPTH);
/* allocate array of s32_t for our object identifier */
vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i);
vb->ident = (s32_t*)memp_malloc(MEMP_SNMP_VALUE);
LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL);
if (vb->ident == NULL)
{
mem_free(vb);
memp_free(MEMP_SNMP_VARBIND, vb);
return NULL;
}
while(i > 0)
@ -1358,16 +1340,17 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
vb->value_len = len;
if (len > 0)
{
LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE);
/* allocate raw bytes for our object value */
vb->value = mem_malloc(len);
vb->value = memp_malloc(MEMP_SNMP_VALUE);
LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
if (vb->value == NULL)
{
if (vb->ident != NULL)
{
mem_free(vb->ident);
memp_free(MEMP_SNMP_VALUE, vb->ident);
}
mem_free(vb);
memp_free(MEMP_SNMP_VARBIND, vb);
return NULL;
}
}
@ -1385,13 +1368,13 @@ snmp_varbind_free(struct snmp_varbind *vb)
{
if (vb->value != NULL )
{
mem_free(vb->value);
memp_free(MEMP_SNMP_VALUE, vb->value);
}
if (vb->ident != NULL )
{
mem_free(vb->ident);
memp_free(MEMP_SNMP_VALUE, vb->ident);
}
mem_free(vb);
memp_free(MEMP_SNMP_VARBIND, vb);
}
void

View file

@ -55,7 +55,7 @@
struct snmp_trap_dst
{
/* destination IP address in network order */
struct ip_addr dip;
ip_addr_t dip;
/* set to 0 when disabled, >0 when enabled */
u8_t enable;
};
@ -92,11 +92,11 @@ snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)
* @param dst IPv4 address in host order.
*/
void
snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst)
snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst)
{
if (dst_idx < SNMP_TRAP_DESTINATIONS)
{
trap_dst[dst_idx].dip.addr = htonl(dst->addr);
ip_addr_set(&trap_dst[dst_idx].dip, dst);
}
}
@ -221,23 +221,24 @@ snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)
{
struct snmp_trap_dst *td;
struct netif *dst_if;
struct ip_addr dst_ip;
ip_addr_t dst_ip;
struct pbuf *p;
u16_t i,tot_len;
for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++)
{
if ((td->enable != 0) && (td->dip.addr != 0))
if ((td->enable != 0) && !ip_addr_isany(&td->dip))
{
/* network order trap destination */
trap_msg.dip.addr = td->dip.addr;
ip_addr_copy(trap_msg.dip, td->dip);
/* lookup current source address for this dst */
dst_if = ip_route(&td->dip);
dst_ip.addr = ntohl(dst_if->ip_addr.addr);
trap_msg.sip_raw[0] = dst_ip.addr >> 24;
trap_msg.sip_raw[1] = dst_ip.addr >> 16;
trap_msg.sip_raw[2] = dst_ip.addr >> 8;
trap_msg.sip_raw[3] = dst_ip.addr;
ip_addr_copy(dst_ip, dst_if->ip_addr);
/* @todo: what about IPv6? */
trap_msg.sip_raw[0] = ip4_addr1(&dst_ip);
trap_msg.sip_raw[1] = ip4_addr2(&dst_ip);
trap_msg.sip_raw[2] = ip4_addr3(&dst_ip);
trap_msg.sip_raw[3] = ip4_addr4(&dst_ip);
trap_msg.gen_trap = generic_trap;
trap_msg.spc_trap = specific_trap;
if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC)
@ -269,11 +270,8 @@ snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)
snmp_inc_snmpouttraps();
snmp_inc_snmpoutpkts();
/** connect to the TRAP destination */
udp_connect(trap_msg.pcb, &trap_msg.dip, SNMP_TRAP_PORT);
udp_send(trap_msg.pcb, p);
/** disassociate remote address and port with this pcb */
udp_disconnect(trap_msg.pcb);
/** send to the TRAP destination */
udp_sendto(trap_msg.pcb, p, &trap_msg.dip, SNMP_TRAP_PORT);
pbuf_free(p);
}
@ -435,13 +433,13 @@ snmp_varbind_list_sum(struct snmp_varbind_root *root)
switch (vb->value_type)
{
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
sint_ptr = vb->value;
sint_ptr = (s32_t*)vb->value;
snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen);
break;
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
uint_ptr = vb->value;
uint_ptr = (u32_t*)vb->value;
snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen);
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
@ -451,7 +449,7 @@ snmp_varbind_list_sum(struct snmp_varbind_root *root)
vb->vlen = vb->value_len;
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
sint_ptr = vb->value;
sint_ptr = (s32_t*)vb->value;
snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen);
break;
default:
@ -649,25 +647,25 @@ snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs)
switch (vb->value_type)
{
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
sint_ptr = vb->value;
sint_ptr = (s32_t*)vb->value;
snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr);
break;
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
uint_ptr = vb->value;
uint_ptr = (u32_t*)vb->value;
snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr);
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
raw_ptr = vb->value;
raw_ptr = (u8_t*)vb->value;
snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr);
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
sint_ptr = vb->value;
sint_ptr = (s32_t*)vb->value;
snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr);
break;
default:

View file

@ -48,6 +48,25 @@
struct stats_ lwip_stats;
void stats_init(void)
{
#ifdef LWIP_DEBUG
#if MEMP_STATS
const char * memp_names[] = {
#define LWIP_MEMPOOL(name,num,size,desc) desc,
#include "lwip/memp_std.h"
};
int i;
for (i = 0; i < MEMP_MAX; i++) {
lwip_stats.memp[i].name = memp_names[i];
}
#endif /* MEMP_STATS */
#if MEM_STATS
lwip_stats.mem.name = "MEM";
#endif /* MEM_STATS */
#endif /* LWIP_DEBUG */
}
#if LWIP_STATS_DISPLAY
void
stats_display_proto(struct stats_proto *proto, char *name)
@ -72,15 +91,20 @@ void
stats_display_igmp(struct stats_igmp *igmp)
{
LWIP_PLATFORM_DIAG(("\nIGMP\n\t"));
LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr));
LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit));
LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv));
LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop));
LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr));
LWIP_PLATFORM_DIAG(("v1_rxed: %"STAT_COUNTER_F"\n\t", igmp->v1_rxed));
LWIP_PLATFORM_DIAG(("join_sent: %"STAT_COUNTER_F"\n\t", igmp->join_sent));
LWIP_PLATFORM_DIAG(("leave_sent: %"STAT_COUNTER_F"\n\t", igmp->leave_sent));
LWIP_PLATFORM_DIAG(("unicast_query: %"STAT_COUNTER_F"\n\t", igmp->unicast_query));
LWIP_PLATFORM_DIAG(("report_sent: %"STAT_COUNTER_F"\n\t", igmp->report_sent));
LWIP_PLATFORM_DIAG(("report_rxed: %"STAT_COUNTER_F"\n\t", igmp->report_rxed));
LWIP_PLATFORM_DIAG(("group_query_rxed: %"STAT_COUNTER_F"\n", igmp->group_query_rxed));
LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr));
LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", igmp->memerr));
LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", igmp->proterr));
LWIP_PLATFORM_DIAG(("rx_v1: %"STAT_COUNTER_F"\n\t", igmp->rx_v1));
LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n", igmp->rx_group));
LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n", igmp->rx_general));
LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report));
LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join));
LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave));
LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n\t", igmp->tx_report));
}
#endif /* IGMP_STATS */
@ -115,12 +139,15 @@ void
stats_display_sys(struct stats_sys *sys)
{
LWIP_PLATFORM_DIAG(("\nSYS\n\t"));
LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used));
LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max));
LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err));
LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used));
LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max));
LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err));
LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used));
LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max));
LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err));
LWIP_PLATFORM_DIAG(("mutex.used: %"U32_F"\n\t", (u32_t)sys->mutex.used));
LWIP_PLATFORM_DIAG(("mutex.max: %"U32_F"\n\t", (u32_t)sys->mutex.max));
LWIP_PLATFORM_DIAG(("mutex.err: %"U32_F"\n\t", (u32_t)sys->mutex.err));
LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used));
LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max));
LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err));
}
#endif /* SYS_STATS */

View file

@ -38,309 +38,29 @@
#include "lwip/opt.h"
#if (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */
#include "lwip/sys.h"
#include "lwip/def.h"
#include "lwip/memp.h"
#include "lwip/tcpip.h"
/* Most of the functions defined in sys.h must be implemented in the
* architecture-dependent file sys_arch.c */
#if !NO_SYS
/**
* Struct used for sys_sem_wait_timeout() to tell wether the time
* has run out or the semaphore has really become available.
*/
struct sswt_cb
{
s16_t timeflag;
sys_sem_t *psem;
};
/**
* Wait (forever) for a message to arrive in an mbox.
* While waiting, timeouts (for this thread) are processed.
*
* @param mbox the mbox to fetch the message from
* @param msg the place to store the message
*/
void
sys_mbox_fetch(sys_mbox_t mbox, void **msg)
{
u32_t time_needed;
struct sys_timeouts *timeouts;
struct sys_timeo *tmptimeout;
sys_timeout_handler h;
void *arg;
again:
timeouts = sys_arch_timeouts();
if (!timeouts || !timeouts->next) {
UNLOCK_TCPIP_CORE();
time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
LOCK_TCPIP_CORE();
} else {
if (timeouts->next->time > 0) {
UNLOCK_TCPIP_CORE();
time_needed = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);
LOCK_TCPIP_CORE();
} else {
time_needed = SYS_ARCH_TIMEOUT;
}
if (time_needed == SYS_ARCH_TIMEOUT) {
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
could be fetched. We should now call the timeout handler and
deallocate the memory allocated for the timeout. */
tmptimeout = timeouts->next;
timeouts->next = tmptimeout->next;
h = tmptimeout->h;
arg = tmptimeout->arg;
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
if (h != NULL) {
LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", *(void**)&h, arg));
h(arg);
}
/* We try again to fetch a message from the mbox. */
goto again;
} else {
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
occured. The time variable is set to the number of
milliseconds we waited for the message. */
if (time_needed < timeouts->next->time) {
timeouts->next->time -= time_needed;
} else {
timeouts->next->time = 0;
}
}
}
}
/**
* Wait (forever) for a semaphore to become available.
* While waiting, timeouts (for this thread) are processed.
*
* @param sem semaphore to wait for
*/
void
sys_sem_wait(sys_sem_t sem)
{
u32_t time_needed;
struct sys_timeouts *timeouts;
struct sys_timeo *tmptimeout;
sys_timeout_handler h;
void *arg;
again:
timeouts = sys_arch_timeouts();
if (!timeouts || !timeouts->next) {
sys_arch_sem_wait(sem, 0);
} else {
if (timeouts->next->time > 0) {
time_needed = sys_arch_sem_wait(sem, timeouts->next->time);
} else {
time_needed = SYS_ARCH_TIMEOUT;
}
if (time_needed == SYS_ARCH_TIMEOUT) {
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
could be fetched. We should now call the timeout handler and
deallocate the memory allocated for the timeout. */
tmptimeout = timeouts->next;
timeouts->next = tmptimeout->next;
h = tmptimeout->h;
arg = tmptimeout->arg;
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
if (h != NULL) {
LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", *(void**)&h, (void *)arg));
h(arg);
}
/* We try again to fetch a message from the mbox. */
goto again;
} else {
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
occured. The time variable is set to the number of
milliseconds we waited for the message. */
if (time_needed < timeouts->next->time) {
timeouts->next->time -= time_needed;
} else {
timeouts->next->time = 0;
}
}
}
}
/**
* Create a one-shot timer (aka timeout). Timeouts are processed in the
* following cases:
* - while waiting for a message using sys_mbox_fetch()
* - while waiting for a semaphore using sys_sem_wait() or sys_sem_wait_timeout()
* - while sleeping using the inbuilt sys_msleep()
*
* @param msecs time in milliseconds after that the timer should expire
* @param h callback function to call when msecs have elapsed
* @param arg argument to pass to the callback function
*/
void
sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
{
struct sys_timeouts *timeouts;
struct sys_timeo *timeout, *t;
timeout = memp_malloc(MEMP_SYS_TIMEOUT);
if (timeout == NULL) {
LWIP_ASSERT("sys_timeout: timeout != NULL", timeout != NULL);
return;
}
timeout->next = NULL;
timeout->h = h;
timeout->arg = arg;
timeout->time = msecs;
timeouts = sys_arch_timeouts();
LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n",
(void *)timeout, msecs, *(void**)&h, (void *)arg));
if (timeouts == NULL) {
LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);
return;
}
if (timeouts->next == NULL) {
timeouts->next = timeout;
return;
}
if (timeouts->next->time > msecs) {
timeouts->next->time -= msecs;
timeout->next = timeouts->next;
timeouts->next = timeout;
} else {
for(t = timeouts->next; t != NULL; t = t->next) {
timeout->time -= t->time;
if (t->next == NULL || t->next->time > timeout->time) {
if (t->next != NULL) {
t->next->time -= timeout->time;
}
timeout->next = t->next;
t->next = timeout;
break;
}
}
}
}
/**
* Go through timeout list (for this task only) and remove the first matching
* entry, even though the timeout has not triggered yet.
*
* @note This function only works as expected if there is only one timeout
* calling 'h' in the list of timeouts.
*
* @param h callback function that would be called by the timeout
* @param arg callback argument that would be passed to h
*/
void
sys_untimeout(sys_timeout_handler h, void *arg)
{
struct sys_timeouts *timeouts;
struct sys_timeo *prev_t, *t;
timeouts = sys_arch_timeouts();
if (timeouts == NULL) {
LWIP_ASSERT("sys_untimeout: timeouts != NULL", timeouts != NULL);
return;
}
if (timeouts->next == NULL) {
return;
}
for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
if ((t->h == h) && (t->arg == arg)) {
/* We have a match */
/* Unlink from previous in list */
if (prev_t == NULL) {
timeouts->next = t->next;
} else {
prev_t->next = t->next;
}
/* If not the last one, add time of this one back to next */
if (t->next != NULL) {
t->next->time += t->time;
}
memp_free(MEMP_SYS_TIMEOUT, t);
return;
}
}
return;
}
/**
* Timeout handler function for sys_sem_wait_timeout()
*
* @param arg struct sswt_cb* used to signal a semaphore and end waiting.
*/
static void
sswt_handler(void *arg)
{
struct sswt_cb *sswt_cb = (struct sswt_cb *) arg;
/* Timeout. Set flag to TRUE and signal semaphore */
sswt_cb->timeflag = 1;
sys_sem_signal(*(sswt_cb->psem));
}
/**
* Wait for a semaphore with timeout (specified in ms)
*
* @param sem semaphore to wait
* @param timeout timeout in ms (0: wait forever)
* @return 0 on timeout, 1 otherwise
*/
int
sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout)
{
struct sswt_cb sswt_cb;
sswt_cb.psem = &sem;
sswt_cb.timeflag = 0;
/* If timeout is zero, then just wait forever */
if (timeout > 0) {
/* Create a timer and pass it the address of our flag */
sys_timeout(timeout, sswt_handler, &sswt_cb);
}
sys_sem_wait(sem);
/* Was it a timeout? */
if (sswt_cb.timeflag) {
/* timeout */
return 0;
} else {
/* Not a timeout. Remove timeout entry */
sys_untimeout(sswt_handler, &sswt_cb);
return 1;
}
}
/**
* Sleep for some ms. Timeouts are processed while sleeping.
* Sleep for some ms. Timeouts are NOT processed while sleeping.
*
* @param ms number of milliseconds to sleep
*/
void
sys_msleep(u32_t ms)
{
sys_sem_t delaysem = sys_sem_new(0);
sys_sem_wait_timeout(delaysem, ms);
sys_sem_free(delaysem);
if (ms > 0) {
sys_sem_t delaysem;
err_t err = sys_sem_new(&delaysem, 0);
if (err == ERR_OK) {
sys_arch_sem_wait(&delaysem, ms);
sys_sem_free(&delaysem);
}
}
}
#endif /* NO_SYS */
#endif /* !NO_SYS */

View file

@ -49,12 +49,13 @@
#include "lwip/memp.h"
#include "lwip/snmp.h"
#include "lwip/tcp.h"
#include "lwip/tcp_impl.h"
#include "lwip/debug.h"
#include "lwip/stats.h"
#include <string.h>
const char *tcp_state_str[] = {
const char * const tcp_state_str[] = {
"CLOSED",
"LISTEN",
"SYN_SENT",
@ -78,17 +79,25 @@ const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 };
/* The TCP PCB lists. */
/** List of all TCP PCBs bound but not yet (connected || listening) */
struct tcp_pcb *tcp_bound_pcbs;
struct tcp_pcb *tcp_bound_pcbs;
/** List of all TCP PCBs in LISTEN state */
union tcp_listen_pcbs_t tcp_listen_pcbs;
/** List of all TCP PCBs that are in a state in which
* they accept or send data. */
struct tcp_pcb *tcp_active_pcbs;
struct tcp_pcb *tcp_active_pcbs;
/** List of all TCP PCBs in TIME-WAIT state */
struct tcp_pcb *tcp_tw_pcbs;
#define NUM_TCP_PCB_LISTS 4
#define NUM_TCP_PCB_LISTS_NO_TIME_WAIT 3
/** An array with all (non-temporary) PCB lists, mainly used for smaller code size */
struct tcp_pcb ** const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs,
&tcp_active_pcbs, &tcp_tw_pcbs};
/** Only used for temporary storage. */
struct tcp_pcb *tcp_tmp_pcb;
/** Timer counter to handle calling slow-timer from tcp_tmr() */
static u8_t tcp_timer;
static u16_t tcp_new_port(void);
@ -110,7 +119,9 @@ tcp_tmr(void)
}
/**
* Closes the connection held by the PCB.
* Closes the TX side of a connection held by the PCB.
* For tcp_close(), a RST is sent if the application didn't receive all data
* (tcp_recved() not called for all data passed to recv callback).
*
* Listening pcbs are freed and may not be referenced any more.
* Connection pcbs are freed if not yet connected and may not be referenced
@ -123,15 +134,34 @@ tcp_tmr(void)
* @return ERR_OK if connection has been closed
* another err_t if closing failed and pcb is not freed
*/
err_t
tcp_close(struct tcp_pcb *pcb)
static err_t
tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
{
err_t err;
#if TCP_DEBUG
LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in "));
tcp_debug_print_state(pcb->state);
#endif /* TCP_DEBUG */
if (rst_on_unacked_data && (pcb->state != LISTEN)) {
if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND)) {
/* Not all data received by application, send RST to tell the remote
side about this. */
LWIP_ASSERT("pcb->flags & TF_RXCLOSED", pcb->flags & TF_RXCLOSED);
/* don't call tcp_abort here: we must not deallocate the pcb since
that might not be expected when calling tcp_close */
tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
pcb->local_port, pcb->remote_port);
tcp_pcb_purge(pcb);
/* TODO: to which state do we move now? */
/* move to TIME_WAIT since we close actively */
TCP_RMV(&tcp_active_pcbs, pcb);
pcb->state = TIME_WAIT;
TCP_REG(&tcp_tw_pcbs, pcb);
return ERR_OK;
}
}
switch (pcb->state) {
case CLOSED:
@ -143,13 +173,15 @@ tcp_close(struct tcp_pcb *pcb)
* is erroneous, but this should never happen as the pcb has in those cases
* been freed, and so any remaining handles are bogus. */
err = ERR_OK;
TCP_RMV(&tcp_bound_pcbs, pcb);
if (pcb->local_port != 0) {
TCP_RMV(&tcp_bound_pcbs, pcb);
}
memp_free(MEMP_TCP_PCB, pcb);
pcb = NULL;
break;
case LISTEN:
err = ERR_OK;
tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb);
tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb);
memp_free(MEMP_TCP_PCB_LISTEN, pcb);
pcb = NULL;
break;
@ -161,21 +193,21 @@ tcp_close(struct tcp_pcb *pcb)
snmp_inc_tcpattemptfails();
break;
case SYN_RCVD:
err = tcp_send_ctrl(pcb, TCP_FIN);
err = tcp_send_fin(pcb);
if (err == ERR_OK) {
snmp_inc_tcpattemptfails();
pcb->state = FIN_WAIT_1;
}
break;
case ESTABLISHED:
err = tcp_send_ctrl(pcb, TCP_FIN);
err = tcp_send_fin(pcb);
if (err == ERR_OK) {
snmp_inc_tcpestabresets();
pcb->state = FIN_WAIT_1;
}
break;
case CLOSE_WAIT:
err = tcp_send_ctrl(pcb, TCP_FIN);
err = tcp_send_fin(pcb);
if (err == ERR_OK) {
snmp_inc_tcpestabresets();
pcb->state = LAST_ACK;
@ -195,12 +227,85 @@ tcp_close(struct tcp_pcb *pcb)
returns (unsent data is sent from tcp timer functions, also), we don't care
for the return value of tcp_output for now. */
/* @todo: When implementing SO_LINGER, this must be changed somehow:
If SOF_LINGER is set, the data should be sent when tcp_close returns. */
If SOF_LINGER is set, the data should be sent and acked before close returns.
This can only be valid for sequential APIs, not for the raw API. */
tcp_output(pcb);
}
return err;
}
/**
* Closes the connection held by the PCB.
*
* Listening pcbs are freed and may not be referenced any more.
* Connection pcbs are freed if not yet connected and may not be referenced
* any more. If a connection is established (at least SYN received or in
* a closing state), the connection is closed, and put in a closing state.
* The pcb is then automatically freed in tcp_slowtmr(). It is therefore
* unsafe to reference it (unless an error is returned).
*
* @param pcb the tcp_pcb to close
* @return ERR_OK if connection has been closed
* another err_t if closing failed and pcb is not freed
*/
err_t
tcp_close(struct tcp_pcb *pcb)
{
#if TCP_DEBUG
LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in "));
tcp_debug_print_state(pcb->state);
#endif /* TCP_DEBUG */
if (pcb->state != LISTEN) {
/* Set a flag not to receive any more data... */
pcb->flags |= TF_RXCLOSED;
}
/* ... and close */
return tcp_close_shutdown(pcb, 1);
}
/**
* Causes all or part of a full-duplex connection of this PCB to be shut down.
* This doesn't deallocate the PCB!
*
* @param pcb PCB to shutdown
* @param shut_rx shut down receive side if this is != 0
* @param shut_tx shut down send side if this is != 0
* @return ERR_OK if shutdown succeeded (or the PCB has already been shut down)
* another err_t on error.
*/
err_t
tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx)
{
if (pcb->state == LISTEN) {
return ERR_CONN;
}
if (shut_rx) {
/* shut down the receive side: free buffered data... */
if (pcb->refused_data != NULL) {
pbuf_free(pcb->refused_data);
pcb->refused_data = NULL;
}
/* ... and set a flag not to receive any more data */
pcb->flags |= TF_RXCLOSED;
}
if (shut_tx) {
/* This can't happen twice since if it succeeds, the pcb's state is changed.
Only close in these states as the others directly deallocate the PCB */
switch (pcb->state) {
case SYN_RCVD:
case ESTABLISHED:
case CLOSE_WAIT:
return tcp_close_shutdown(pcb, 0);
default:
/* don't shut down other states */
break;
}
}
/* @todo: return another err_t if not in correct state or already shut? */
return ERR_OK;
}
/**
* Abandons a connection and optionally sends a RST to the remote
* host. Deletes the local protocol control block. This is done when
@ -214,13 +319,15 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
{
u32_t seqno, ackno;
u16_t remote_port, local_port;
struct ip_addr remote_ip, local_ip;
ip_addr_t remote_ip, local_ip;
#if LWIP_CALLBACK_API
void (* errf)(void *arg, err_t err);
tcp_err_fn errf;
#endif /* LWIP_CALLBACK_API */
void *errf_arg;
/* pcb->state LISTEN not allowed here */
LWIP_ASSERT("don't call tcp_abort/tcp_abandon for listen-pcbs",
pcb->state != LISTEN);
/* Figure out on which TCP PCB list we are, and remove us. If we
are in an active state, call the receive function associated with
the PCB with a NULL argument, and send an RST to the remote end. */
@ -230,8 +337,8 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
} else {
seqno = pcb->snd_nxt;
ackno = pcb->rcv_nxt;
ip_addr_set(&local_ip, &(pcb->local_ip));
ip_addr_set(&remote_ip, &(pcb->remote_ip));
ip_addr_copy(local_ip, pcb->local_ip);
ip_addr_copy(remote_ip, pcb->remote_ip);
local_port = pcb->local_port;
remote_port = pcb->remote_port;
#if LWIP_CALLBACK_API
@ -259,6 +366,22 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
}
}
/**
* Aborts the connection by sending a RST (reset) segment to the remote
* host. The pcb is deallocated. This function never fails.
*
* ATTENTION: When calling this from one of the TCP callbacks, make
* sure you always return ERR_ABRT (and never return ERR_ABRT otherwise
* or you will risk accessing deallocated memory or memory leaks!
*
* @param pcb the tcp pcb to abort
*/
void
tcp_abort(struct tcp_pcb *pcb)
{
tcp_abandon(pcb, 1);
}
/**
* Binds the connection to a local portnumber and IP address. If the
* IP address is not given (i.e., ipaddr == NULL), the IP address of
@ -270,57 +393,51 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
* to any local address
* @param port the local port to bind to
* @return ERR_USE if the port is already in use
* ERR_VAL if bind failed because the PCB is not in a valid state
* ERR_OK if bound
*/
err_t
tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
{
int i;
int max_pcb_list = NUM_TCP_PCB_LISTS;
struct tcp_pcb *cpcb;
LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_VAL);
#if SO_REUSE
/* Unless the REUSEADDR flag is set,
we have to check the pcbs in TIME-WAIT state, also.
We do not dump TIME_WAIT pcb's; they can still be matched by incoming
packets using both local and remote IP addresses and ports to distinguish.
*/
if ((pcb->so_options & SOF_REUSEADDR) != 0) {
max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT;
}
#endif /* SO_REUSE */
if (port == 0) {
port = tcp_new_port();
}
/* Check if the address already is in use. */
/* Check the listen pcbs. */
for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs;
cpcb != NULL; cpcb = cpcb->next) {
if (cpcb->local_port == port) {
if (ip_addr_isany(&(cpcb->local_ip)) ||
ip_addr_isany(ipaddr) ||
ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
return ERR_USE;
}
}
}
/* Check the connected pcbs. */
for(cpcb = tcp_active_pcbs;
cpcb != NULL; cpcb = cpcb->next) {
if (cpcb->local_port == port) {
if (ip_addr_isany(&(cpcb->local_ip)) ||
ip_addr_isany(ipaddr) ||
ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
return ERR_USE;
}
}
}
/* Check the bound, not yet connected pcbs. */
for(cpcb = tcp_bound_pcbs; cpcb != NULL; cpcb = cpcb->next) {
if (cpcb->local_port == port) {
if (ip_addr_isany(&(cpcb->local_ip)) ||
ip_addr_isany(ipaddr) ||
ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
return ERR_USE;
}
}
}
/* @todo: until SO_REUSEADDR is implemented (see task #6995 on savannah),
* we have to check the pcbs in TIME-WAIT state, also: */
for(cpcb = tcp_tw_pcbs; cpcb != NULL; cpcb = cpcb->next) {
if (cpcb->local_port == port) {
if (ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
return ERR_USE;
/* Check if the address already is in use (on all lists) */
for (i = 0; i < max_pcb_list; i++) {
for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {
if (cpcb->local_port == port) {
#if SO_REUSE
/* Omit checking for the same port if both pcbs have REUSEADDR set.
For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in
tcp_connect. */
if (((pcb->so_options & SOF_REUSEADDR) == 0) ||
((cpcb->so_options & SOF_REUSEADDR) == 0))
#endif /* SO_REUSE */
{
if (ip_addr_isany(&(cpcb->local_ip)) ||
ip_addr_isany(ipaddr) ||
ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
return ERR_USE;
}
}
}
}
}
@ -374,19 +491,37 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
if (pcb->state == LISTEN) {
return pcb;
}
lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN);
#if SO_REUSE
if ((pcb->so_options & SOF_REUSEADDR) != 0) {
/* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage
is declared (listen-/connection-pcb), we have to make sure now that
this port is only used once for every local IP. */
for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
if (lpcb->local_port == pcb->local_port) {
if (ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) {
/* this address/port is already used */
return NULL;
}
}
}
}
#endif /* SO_REUSE */
lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN);
if (lpcb == NULL) {
return NULL;
}
lpcb->callback_arg = pcb->callback_arg;
lpcb->local_port = pcb->local_port;
lpcb->state = LISTEN;
lpcb->prio = pcb->prio;
lpcb->so_options = pcb->so_options;
lpcb->so_options |= SOF_ACCEPTCONN;
lpcb->ttl = pcb->ttl;
lpcb->tos = pcb->tos;
ip_addr_set(&lpcb->local_ip, &pcb->local_ip);
TCP_RMV(&tcp_bound_pcbs, pcb);
ip_addr_copy(lpcb->local_ip, pcb->local_ip);
if (pcb->local_port != 0) {
TCP_RMV(&tcp_bound_pcbs, pcb);
}
memp_free(MEMP_TCP_PCB, pcb);
#if LWIP_CALLBACK_API
lpcb->accept = tcp_accept_null;
@ -395,7 +530,7 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
lpcb->accepts_pending = 0;
lpcb->backlog = (backlog ? backlog : 1);
#endif /* TCP_LISTEN_BACKLOG */
TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb);
TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb);
return (struct tcp_pcb *)lpcb;
}
@ -420,7 +555,9 @@ u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)
pcb->rcv_ann_wnd = 0;
} else {
/* keep the right edge of window constant */
pcb->rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt;
u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt;
LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff", new_rcv_ann_wnd <= 0xffff);
pcb->rcv_ann_wnd = (u16_t)new_rcv_ann_wnd;
}
return 0;
}
@ -443,17 +580,20 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len)
len <= 0xffff - pcb->rcv_wnd );
pcb->rcv_wnd += len;
if (pcb->rcv_wnd > TCP_WND)
if (pcb->rcv_wnd > TCP_WND) {
pcb->rcv_wnd = TCP_WND;
}
wnd_inflation = tcp_update_rcv_ann_wnd(pcb);
/* If the change in the right edge of window is significant (default
* watermark is TCP_WND/2), then send an explicit update now.
* watermark is TCP_WND/4), then send an explicit update now.
* Otherwise wait for a packet to be sent in the normal course of
* events (or more window to be available later) */
if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD)
if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) {
tcp_ack_now(pcb);
tcp_output(pcb);
}
LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",
len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));
@ -468,31 +608,26 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len)
static u16_t
tcp_new_port(void)
{
int i;
struct tcp_pcb *pcb;
#ifndef TCP_LOCAL_PORT_RANGE_START
#define TCP_LOCAL_PORT_RANGE_START 4096
#define TCP_LOCAL_PORT_RANGE_END 0x7fff
/* From http://www.iana.org/assignments/port-numbers:
"The Dynamic and/or Private Ports are those from 49152 through 65535" */
#define TCP_LOCAL_PORT_RANGE_START 0xc000
#define TCP_LOCAL_PORT_RANGE_END 0xffff
#endif
static u16_t port = TCP_LOCAL_PORT_RANGE_START;
again:
if (++port > TCP_LOCAL_PORT_RANGE_END) {
if (port++ >= TCP_LOCAL_PORT_RANGE_END) {
port = TCP_LOCAL_PORT_RANGE_START;
}
for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
if (pcb->local_port == port) {
goto again;
}
}
for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
if (pcb->local_port == port) {
goto again;
}
}
for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
if (pcb->local_port == port) {
goto again;
/* Check all PCB lists. */
for (i = 0; i < NUM_TCP_PCB_LISTS; i++) {
for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) {
if (pcb->local_port == port) {
goto again;
}
}
}
return port;
@ -511,13 +646,14 @@ tcp_new_port(void)
* other err_t values if connect request couldn't be sent
*/
err_t
tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))
tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
tcp_connected_fn connected)
{
err_t ret;
u32_t iss;
u16_t old_local_port;
LWIP_ERROR("tcp_connect: can only connected from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));
if (ipaddr != NULL) {
@ -526,9 +662,44 @@ tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
return ERR_VAL;
}
pcb->remote_port = port;
/* check if we have a route to the remote host */
if (ip_addr_isany(&(pcb->local_ip))) {
/* no local IP address set, yet. */
struct netif *netif = ip_route(&(pcb->remote_ip));
if (netif == NULL) {
/* Don't even try to send a SYN packet if we have no route
since that will fail. */
return ERR_RTE;
}
/* Use the netif's IP address as local address. */
ip_addr_copy(pcb->local_ip, netif->ip_addr);
}
old_local_port = pcb->local_port;
if (pcb->local_port == 0) {
pcb->local_port = tcp_new_port();
}
#if SO_REUSE
if ((pcb->so_options & SOF_REUSEADDR) != 0) {
/* Since SOF_REUSEADDR allows reusing a local address, we have to make sure
now that the 5-tuple is unique. */
struct tcp_pcb *cpcb;
int i;
/* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */
for (i = 2; i < NUM_TCP_PCB_LISTS; i++) {
for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {
if ((cpcb->local_port == pcb->local_port) &&
(cpcb->remote_port == port) &&
ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) &&
ip_addr_cmp(&cpcb->remote_ip, ipaddr)) {
/* linux returns EISCONN here, but ERR_USE should be OK for us */
return ERR_USE;
}
}
}
}
#endif /* SO_REUSE */
iss = tcp_next_iss();
pcb->rcv_nxt = 0;
pcb->snd_nxt = iss;
@ -546,25 +717,27 @@ tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
pcb->cwnd = 1;
pcb->ssthresh = pcb->mss * 10;
pcb->state = SYN_SENT;
#if LWIP_CALLBACK_API
#if LWIP_CALLBACK_API
pcb->connected = connected;
#else /* LWIP_CALLBACK_API */
LWIP_UNUSED_ARG(connected);
#endif /* LWIP_CALLBACK_API */
TCP_RMV(&tcp_bound_pcbs, pcb);
TCP_REG(&tcp_active_pcbs, pcb);
snmp_inc_tcpactiveopens();
ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, TF_SEG_OPTS_MSS
#if LWIP_TCP_TIMESTAMPS
| TF_SEG_OPTS_TS
#endif
);
if (ret == ERR_OK) {
/* Send a SYN together with the MSS option. */
ret = tcp_enqueue_flags(pcb, TCP_SYN);
if (ret == ERR_OK) {
/* SYN segment was enqueued, changed the pcbs state now */
pcb->state = SYN_SENT;
if (old_local_port != 0) {
TCP_RMV(&tcp_bound_pcbs, pcb);
}
TCP_REG(&tcp_active_pcbs, pcb);
snmp_inc_tcpactiveopens();
tcp_output(pcb);
}
return ret;
}
}
/**
* Called every 500 ms and implements the retransmission timer and the timer that
@ -576,7 +749,7 @@ tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
void
tcp_slowtmr(void)
{
struct tcp_pcb *pcb, *pcb2, *prev;
struct tcp_pcb *pcb, *prev;
u16_t eff_wnd;
u8_t pcb_remove; /* flag if a PCB should be removed */
u8_t pcb_reset; /* flag if a RST should be sent when removing */
@ -643,8 +816,8 @@ tcp_slowtmr(void)
/* Reduce congestion window and ssthresh. */
eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);
pcb->ssthresh = eff_wnd >> 1;
if (pcb->ssthresh < pcb->mss) {
pcb->ssthresh = pcb->mss * 2;
if (pcb->ssthresh < (pcb->mss << 1)) {
pcb->ssthresh = (pcb->mss << 1);
}
pcb->cwnd = pcb->mss;
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F
@ -667,21 +840,21 @@ tcp_slowtmr(void)
}
/* Check if KEEPALIVE should be sent */
if((pcb->so_options & SOF_KEEPALIVE) &&
((pcb->state == ESTABLISHED) ||
if((pcb->so_options & SOF_KEEPALIVE) &&
((pcb->state == ESTABLISHED) ||
(pcb->state == CLOSE_WAIT))) {
#if LWIP_TCP_KEEPALIVE
if((u32_t)(tcp_ticks - pcb->tmr) >
if((u32_t)(tcp_ticks - pcb->tmr) >
(pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl))
/ TCP_SLOW_INTERVAL)
#else
if((u32_t)(tcp_ticks - pcb->tmr) >
if((u32_t)(tcp_ticks - pcb->tmr) >
(pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)
#endif /* LWIP_TCP_KEEPALIVE */
{
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",
ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
++pcb_remove;
++pcb_reset;
@ -704,7 +877,7 @@ tcp_slowtmr(void)
/* If this PCB has queued out of sequence data, but has been
inactive for too long, will drop the data (it will eventually
be retransmitted). */
#if TCP_QUEUE_OOSEQ
#if TCP_QUEUE_OOSEQ
if (pcb->ooseq != NULL &&
(u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) {
tcp_segs_free(pcb->ooseq);
@ -732,7 +905,8 @@ tcp_slowtmr(void)
/* If the PCB should be removed, do it. */
if (pcb_remove) {
tcp_pcb_purge(pcb);
struct tcp_pcb *pcb2;
tcp_pcb_purge(pcb);
/* Remove PCB from tcp_active_pcbs list. */
if (prev != NULL) {
LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);
@ -749,30 +923,31 @@ tcp_slowtmr(void)
pcb->local_port, pcb->remote_port);
}
pcb2 = pcb->next;
memp_free(MEMP_TCP_PCB, pcb);
pcb = pcb2;
pcb2 = pcb;
pcb = pcb->next;
memp_free(MEMP_TCP_PCB, pcb2);
} else {
/* We check if we should poll the connection. */
++pcb->polltmr;
if (pcb->polltmr >= pcb->pollinterval) {
pcb->polltmr = 0;
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
TCP_EVENT_POLL(pcb, err);
if (err == ERR_OK) {
tcp_output(pcb);
}
}
/* get the 'next' element now and work with 'prev' below (in case of abort) */
prev = pcb;
pcb = pcb->next;
/* We check if we should poll the connection. */
++prev->polltmr;
if (prev->polltmr >= prev->pollinterval) {
prev->polltmr = 0;
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
TCP_EVENT_POLL(prev, err);
/* if err == ERR_ABRT, 'prev' is already deallocated */
if (err == ERR_OK) {
tcp_output(prev);
}
}
}
}
/* Steps through all of the TIME-WAIT PCBs. */
prev = NULL;
prev = NULL;
pcb = tcp_tw_pcbs;
while (pcb != NULL) {
LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
@ -787,7 +962,8 @@ tcp_slowtmr(void)
/* If the PCB should be removed, do it. */
if (pcb_remove) {
tcp_pcb_purge(pcb);
struct tcp_pcb *pcb2;
tcp_pcb_purge(pcb);
/* Remove PCB from tcp_tw_pcbs list. */
if (prev != NULL) {
LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);
@ -797,9 +973,9 @@ tcp_slowtmr(void)
LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
tcp_tw_pcbs = pcb->next;
}
pcb2 = pcb->next;
memp_free(MEMP_TCP_PCB, pcb);
pcb = pcb2;
pcb2 = pcb;
pcb = pcb->next;
memp_free(MEMP_TCP_PCB, pcb2);
} else {
prev = pcb;
pcb = pcb->next;
@ -816,9 +992,10 @@ tcp_slowtmr(void)
void
tcp_fasttmr(void)
{
struct tcp_pcb *pcb;
struct tcp_pcb *pcb = tcp_active_pcbs;
for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
while(pcb != NULL) {
struct tcp_pcb *next = pcb->next;
/* If there is data which was previously "refused" by upper layer */
if (pcb->refused_data != NULL) {
/* Notify again application with data previously received. */
@ -827,15 +1004,21 @@ tcp_fasttmr(void)
TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
if (err == ERR_OK) {
pcb->refused_data = NULL;
} else if (err == ERR_ABRT) {
/* if err == ERR_ABRT, 'pcb' is already deallocated */
pcb = NULL;
}
}
/* send delayed ACKs */
if (pcb->flags & TF_ACK_DELAY) {
/* send delayed ACKs */
if (pcb && (pcb->flags & TF_ACK_DELAY)) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));
tcp_ack_now(pcb);
tcp_output(pcb);
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
}
pcb = next;
}
}
@ -843,42 +1026,34 @@ tcp_fasttmr(void)
* Deallocates a list of TCP segments (tcp_seg structures).
*
* @param seg tcp_seg list of TCP segments to free
* @return the number of pbufs that were deallocated
*/
u8_t
void
tcp_segs_free(struct tcp_seg *seg)
{
u8_t count = 0;
struct tcp_seg *next;
while (seg != NULL) {
next = seg->next;
count += tcp_seg_free(seg);
struct tcp_seg *next = seg->next;
tcp_seg_free(seg);
seg = next;
}
return count;
}
/**
* Frees a TCP segment (tcp_seg structure).
*
* @param seg single tcp_seg to free
* @return the number of pbufs that were deallocated
*/
u8_t
void
tcp_seg_free(struct tcp_seg *seg)
{
u8_t count = 0;
if (seg != NULL) {
if (seg->p != NULL) {
count = pbuf_free(seg->p);
pbuf_free(seg->p);
#if TCP_DEBUG
seg->p = NULL;
#endif /* TCP_DEBUG */
}
memp_free(MEMP_TCP_SEG, seg);
}
return count;
}
/**
@ -892,8 +1067,8 @@ tcp_setprio(struct tcp_pcb *pcb, u8_t prio)
{
pcb->prio = prio;
}
#if TCP_QUEUE_OOSEQ
#if TCP_QUEUE_OOSEQ
/**
* Returns a copy of the given TCP segment.
* The pbuf and data are not copied, only the pointers
@ -906,7 +1081,7 @@ tcp_seg_copy(struct tcp_seg *seg)
{
struct tcp_seg *cseg;
cseg = memp_malloc(MEMP_TCP_SEG);
cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG);
if (cseg == NULL) {
return NULL;
}
@ -914,7 +1089,7 @@ tcp_seg_copy(struct tcp_seg *seg)
pbuf_ref(cseg->p);
return cseg;
}
#endif
#endif /* TCP_QUEUE_OOSEQ */
#if LWIP_CALLBACK_API
/**
@ -966,7 +1141,7 @@ tcp_kill_prio(u8_t prio)
LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n",
(void *)inactive, inactivity));
tcp_abort(inactive);
}
}
}
/**
@ -992,7 +1167,7 @@ tcp_kill_timewait(void)
LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n",
(void *)inactive, inactivity));
tcp_abort(inactive);
}
}
}
/**
@ -1007,19 +1182,19 @@ tcp_alloc(u8_t prio)
struct tcp_pcb *pcb;
u32_t iss;
pcb = memp_malloc(MEMP_TCP_PCB);
pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);
if (pcb == NULL) {
/* Try killing oldest connection in TIME-WAIT. */
LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n"));
tcp_kill_timewait();
/* Try to allocate a tcp_pcb again. */
pcb = memp_malloc(MEMP_TCP_PCB);
pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);
if (pcb == NULL) {
/* Try killing active connections with lower priority than the new one. */
LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing connection with prio lower than %d\n", prio));
tcp_kill_prio(prio);
/* Try to allocate a tcp_pcb again. */
pcb = memp_malloc(MEMP_TCP_PCB);
pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);
if (pcb != NULL) {
/* adjust err stats: memp_malloc failed twice before */
MEMP_STATS_DEC(err, MEMP_TCP_PCB);
@ -1032,7 +1207,7 @@ tcp_alloc(u8_t prio)
}
if (pcb != NULL) {
memset(pcb, 0, sizeof(struct tcp_pcb));
pcb->prio = TCP_PRIO_NORMAL;
pcb->prio = prio;
pcb->snd_buf = TCP_SND_BUF;
pcb->snd_queuelen = 0;
pcb->rcv_wnd = TCP_WND;
@ -1113,8 +1288,7 @@ tcp_arg(struct tcp_pcb *pcb, void *arg)
* @param recv callback function to call for this pcb when data is received
*/
void
tcp_recv(struct tcp_pcb *pcb,
err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err))
tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv)
{
pcb->recv = recv;
}
@ -1127,8 +1301,7 @@ tcp_recv(struct tcp_pcb *pcb,
* @param sent callback function to call for this pcb when data is successfully sent
*/
void
tcp_sent(struct tcp_pcb *pcb,
err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len))
tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent)
{
pcb->sent = sent;
}
@ -1138,14 +1311,13 @@ tcp_sent(struct tcp_pcb *pcb,
* has occured on the connection.
*
* @param pcb tcp_pcb to set the err callback
* @param errf callback function to call for this pcb when a fatal error
* @param err callback function to call for this pcb when a fatal error
* has occured on the connection
*/
void
tcp_err(struct tcp_pcb *pcb,
void (* errf)(void *arg, err_t err))
tcp_err(struct tcp_pcb *pcb, tcp_err_fn err)
{
pcb->errf = errf;
pcb->errf = err;
}
/**
@ -1157,8 +1329,7 @@ tcp_err(struct tcp_pcb *pcb,
* connection has been connected to another host
*/
void
tcp_accept(struct tcp_pcb *pcb,
err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))
tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept)
{
pcb->accept = accept;
}
@ -1172,11 +1343,12 @@ tcp_accept(struct tcp_pcb *pcb,
*
*/
void
tcp_poll(struct tcp_pcb *pcb,
err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval)
tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval)
{
#if LWIP_CALLBACK_API
pcb->poll = poll;
#else /* LWIP_CALLBACK_API */
LWIP_UNUSED_ARG(poll);
#endif /* LWIP_CALLBACK_API */
pcb->pollinterval = interval;
}
@ -1228,21 +1400,24 @@ tcp_pcb_purge(struct tcp_pcb *pcb)
if (pcb->unacked != NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));
}
#if TCP_QUEUE_OOSEQ /* LW */
#if TCP_QUEUE_OOSEQ
if (pcb->ooseq != NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));
}
tcp_segs_free(pcb->ooseq);
pcb->ooseq = NULL;
#endif /* TCP_QUEUE_OOSEQ */
/* Stop the retransmission timer as it will expect data on unacked
queue if it fires */
pcb->rtime = -1;
tcp_segs_free(pcb->ooseq);
pcb->ooseq = NULL;
#endif /* TCP_QUEUE_OOSEQ */
tcp_segs_free(pcb->unsent);
tcp_segs_free(pcb->unacked);
pcb->unacked = pcb->unsent = NULL;
#if TCP_OVERSIZE
pcb->unsent_oversize = 0;
#endif /* TCP_OVERSIZE */
}
}
@ -1301,7 +1476,7 @@ tcp_next_iss(void)
* calculating the minimum of TCP_MSS and that netif's mtu (if set).
*/
u16_t
tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr)
tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr)
{
u16_t mss_s;
struct netif *outif;
@ -1311,8 +1486,7 @@ tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr)
mss_s = outif->mtu - IP_HLEN - TCP_HLEN;
/* RFC 1122, chap 4.2.2.6:
* Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize
* We correct for TCP options in tcp_enqueue(), and don't support
* IP options
* We correct for TCP options in tcp_write(), and don't support IP options.
*/
sendmss = LWIP_MIN(sendmss, mss_s);
}

View file

@ -45,13 +45,12 @@
#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
#include "lwip/tcp.h"
#include "lwip/tcp_impl.h"
#include "lwip/def.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/inet.h"
#include "lwip/inet_chksum.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
@ -94,6 +93,10 @@ tcp_input(struct pbuf *p, struct netif *inp)
{
struct tcp_pcb *pcb, *prev;
struct tcp_pcb_listen *lpcb;
#if SO_REUSE
struct tcp_pcb *lpcb_prev = NULL;
struct tcp_pcb_listen *lpcb_any = NULL;
#endif /* SO_REUSE */
u8_t hdrlen;
err_t err;
@ -102,7 +105,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
TCP_STATS_INC(tcp.recv);
snmp_inc_tcpinsegs();
iphdr = p->payload;
iphdr = (struct ip_hdr *)p->payload;
tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
#if TCP_INPUT_DEBUG
@ -121,8 +124,8 @@ tcp_input(struct pbuf *p, struct netif *inp)
}
/* Don't even process incoming broadcasts/multicasts. */
if (ip_addr_isbroadcast(&(iphdr->dest), inp) ||
ip_addr_ismulticast(&(iphdr->dest))) {
if (ip_addr_isbroadcast(&current_iphdr_dest, inp) ||
ip_addr_ismulticast(&current_iphdr_dest)) {
TCP_STATS_INC(tcp.proterr);
TCP_STATS_INC(tcp.drop);
snmp_inc_tcpinerrs();
@ -132,11 +135,10 @@ tcp_input(struct pbuf *p, struct netif *inp)
#if CHECKSUM_CHECK_TCP
/* Verify TCP checksum. */
if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
(struct ip_addr *)&(iphdr->dest),
if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
IP_PROTO_TCP, p->tot_len) != 0) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",
inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest),
inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
IP_PROTO_TCP, p->tot_len)));
#if TCP_DEBUG
tcp_debug_print(tcphdr);
@ -183,8 +185,8 @@ tcp_input(struct pbuf *p, struct netif *inp)
LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
if (pcb->remote_port == tcphdr->src &&
pcb->local_port == tcphdr->dest &&
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {
ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&
ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {
/* Move this PCB to the front of the list so that subsequent
lookups will be faster (we exploit locality in TCP segment
@ -208,8 +210,8 @@ tcp_input(struct pbuf *p, struct netif *inp)
LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
if (pcb->remote_port == tcphdr->src &&
pcb->local_port == tcphdr->dest &&
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {
ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&
ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {
/* We don't really care enough to move this PCB to the front
of the list since we are not very likely to receive that
many segments for connections in TIME-WAIT. */
@ -220,31 +222,55 @@ tcp_input(struct pbuf *p, struct netif *inp)
}
}
/* Finally, if we still did not get a match, we check all PCBs that
are LISTENing for incoming connections. */
/* Finally, if we still did not get a match, we check all PCBs that
are LISTENing for incoming connections. */
prev = NULL;
for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
if ((ip_addr_isany(&(lpcb->local_ip)) ||
ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) &&
lpcb->local_port == tcphdr->dest) {
/* Move this PCB to the front of the list so that subsequent
lookups will be faster (we exploit locality in TCP segment
arrivals). */
if (prev != NULL) {
((struct tcp_pcb_listen *)prev)->next = lpcb->next;
/* our successor is the remainder of the listening list */
lpcb->next = tcp_listen_pcbs.listen_pcbs;
/* put this listening pcb at the head of the listening list */
tcp_listen_pcbs.listen_pcbs = lpcb;
if (lpcb->local_port == tcphdr->dest) {
#if SO_REUSE
if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest)) {
/* found an exact match */
break;
} else if(ip_addr_isany(&(lpcb->local_ip))) {
/* found an ANY-match */
lpcb_any = lpcb;
lpcb_prev = prev;
}
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
tcp_listen_input(lpcb);
pbuf_free(p);
return;
#else /* SO_REUSE */
if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest) ||
ip_addr_isany(&(lpcb->local_ip))) {
/* found a match */
break;
}
#endif /* SO_REUSE */
}
prev = (struct tcp_pcb *)lpcb;
}
#if SO_REUSE
/* first try specific local IP */
if (lpcb == NULL) {
/* only pass to ANY if no specific local IP has been found */
lpcb = lpcb_any;
prev = lpcb_prev;
}
#endif /* SO_REUSE */
if (lpcb != NULL) {
/* Move this PCB to the front of the list so that subsequent
lookups will be faster (we exploit locality in TCP segment
arrivals). */
if (prev != NULL) {
((struct tcp_pcb_listen *)prev)->next = lpcb->next;
/* our successor is the remainder of the listening list */
lpcb->next = tcp_listen_pcbs.listen_pcbs;
/* put this listening pcb at the head of the listening list */
tcp_listen_pcbs.listen_pcbs = lpcb;
}
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
tcp_listen_input(lpcb);
pbuf_free(p);
return;
}
}
#if TCP_INPUT_DEBUG
@ -265,7 +291,6 @@ tcp_input(struct pbuf *p, struct netif *inp)
/* Set up a tcp_seg structure. */
inseg.next = NULL;
inseg.len = p->tot_len;
inseg.dataptr = p->payload;
inseg.p = p;
inseg.tcphdr = tcphdr;
@ -279,8 +304,10 @@ tcp_input(struct pbuf *p, struct netif *inp)
TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
if (err == ERR_OK) {
pcb->refused_data = NULL;
} else {
/* drop incoming packets, because pcb is "full" */
} else if ((err == ERR_ABRT) || (tcplen > 0)) {
/* if err == ERR_ABRT, 'pcb' is already deallocated */
/* Drop incoming packets because pcb is "full" (only if the incoming
segment contains data). */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
TCP_STATS_INC(tcp.drop);
snmp_inc_tcpinerrs();
@ -313,15 +340,29 @@ tcp_input(struct pbuf *p, struct netif *inp)
now. */
if (pcb->acked > 0) {
TCP_EVENT_SENT(pcb, pcb->acked, err);
if (err == ERR_ABRT) {
goto aborted;
}
}
if (recv_data != NULL) {
if(flags & TCP_PSH) {
LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL);
if (pcb->flags & TF_RXCLOSED) {
/* received data although already closed -> abort (send RST) to
notify the remote host that not all data has been processed */
pbuf_free(recv_data);
tcp_abort(pcb);
goto aborted;
}
if (flags & TCP_PSH) {
recv_data->flags |= PBUF_FLAG_PUSH;
}
/* Notify application that data has been received. */
TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
if (err == ERR_ABRT) {
goto aborted;
}
/* If the upper layer can't receive this data, store it */
if (err != ERR_OK) {
@ -333,7 +374,15 @@ tcp_input(struct pbuf *p, struct netif *inp)
/* If a FIN segment was received, we call the callback
function with a NULL buffer to indicate EOF. */
if (recv_flags & TF_GOT_FIN) {
TCP_EVENT_RECV(pcb, NULL, ERR_OK, err);
/* correct rcv_wnd as the application won't call tcp_recved()
for the FIN's seqno */
if (pcb->rcv_wnd != TCP_WND) {
pcb->rcv_wnd++;
}
TCP_EVENT_CLOSED(pcb, err);
if (err == ERR_ABRT) {
goto aborted;
}
}
tcp_input_pcb = NULL;
@ -346,8 +395,11 @@ tcp_input(struct pbuf *p, struct netif *inp)
#endif /* TCP_INPUT_DEBUG */
}
}
/* Jump target if pcb has been aborted in a callback (by calling tcp_abort()).
Below this line, 'pcb' may not be dereferenced! */
aborted:
tcp_input_pcb = NULL;
recv_data = NULL;
/* give up our reference to inseg.p */
if (inseg.p != NULL)
@ -364,7 +416,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
TCP_STATS_INC(tcp.proterr);
TCP_STATS_INC(tcp.drop);
tcp_rst(ackno, seqno + tcplen,
&(iphdr->dest), &(iphdr->src),
ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
pbuf_free(p);
@ -399,7 +451,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
RST. */
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
tcp_rst(ackno + 1, seqno + tcplen,
&(iphdr->dest), &(iphdr->src),
ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
} else if (flags & TCP_SYN) {
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
@ -422,9 +474,9 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
pcb->accepts_pending++;
#endif /* TCP_LISTEN_BACKLOG */
/* Set up the new PCB. */
ip_addr_set(&(npcb->local_ip), &(iphdr->dest));
ip_addr_copy(npcb->local_ip, current_iphdr_dest);
npcb->local_port = pcb->local_port;
ip_addr_set(&(npcb->remote_ip), &(iphdr->src));
ip_addr_copy(npcb->remote_ip, current_iphdr_src);
npcb->remote_port = tcphdr->src;
npcb->state = SYN_RCVD;
npcb->rcv_nxt = seqno + 1;
@ -437,7 +489,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
npcb->accept = pcb->accept;
#endif /* LWIP_CALLBACK_API */
/* inherit socket options */
npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER);
npcb->so_options = pcb->so_options & SOF_INHERITED;
/* Register the new PCB so that we can begin receiving segments
for it. */
TCP_REG(&tcp_active_pcbs, npcb);
@ -451,12 +503,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
snmp_inc_tcppassiveopens();
/* Send a SYN|ACK together with the MSS option. */
rc = tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, TF_SEG_OPTS_MSS
#if LWIP_TCP_TIMESTAMPS
/* and maybe include the TIMESTAMP option */
| (npcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0)
#endif
);
rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK);
if (rc != ERR_OK) {
tcp_abandon(npcb, 0);
return rc;
@ -492,7 +539,7 @@ tcp_timewait_input(struct tcp_pcb *pcb)
should be sent in reply */
if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
/* If the SYN is in the window it is an error, send a reset */
tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
return ERR_OK;
}
@ -565,8 +612,10 @@ tcp_process(struct tcp_pcb *pcb)
return ERR_OK;
}
/* Update the PCB (in)activity timer. */
pcb->tmr = tcp_ticks;
if ((pcb->flags & TF_RXCLOSED) == 0) {
/* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */
pcb->tmr = tcp_ticks;
}
pcb->keep_cnt_sent = 0;
tcp_parseopt(pcb);
@ -616,12 +665,15 @@ tcp_process(struct tcp_pcb *pcb)
/* Call the user specified function to call when sucessfully
* connected. */
TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
if (err == ERR_ABRT) {
return ERR_ABRT;
}
tcp_ack_now(pcb);
}
/* received ACK? possibly a half-open connection */
else if (flags & TCP_ACK) {
/* send a RST to bring the other side in a non-synchronized state. */
tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
break;
@ -640,7 +692,10 @@ tcp_process(struct tcp_pcb *pcb)
if (err != ERR_OK) {
/* If the accept function returns with an error, we abort
* the connection. */
tcp_abort(pcb);
/* Already aborted? */
if (err != ERR_ABRT) {
tcp_abort(pcb);
}
return ERR_ABRT;
}
old_cwnd = pcb->cwnd;
@ -659,11 +714,9 @@ tcp_process(struct tcp_pcb *pcb)
tcp_ack_now(pcb);
pcb->state = CLOSE_WAIT;
}
}
/* incorrect ACK number */
else {
/* send RST */
tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
} else {
/* incorrect ACK number, send RST */
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
} else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
@ -758,7 +811,7 @@ tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
(next->tcphdr->seqno + next->len))) {
/* cseg with FIN already processed */
if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
TCPH_FLAGS_SET(cseg->tcphdr, TCPH_FLAGS(cseg->tcphdr) | TCP_FIN);
TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN);
}
old_seg = next;
next = next->next;
@ -773,7 +826,7 @@ tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
}
cseg->next = next;
}
#endif
#endif /* TCP_QUEUE_OOSEQ */
/**
* Called by tcp_process. Checks if the given segment is an ACK for outstanding
@ -793,7 +846,7 @@ tcp_receive(struct tcp_pcb *pcb)
struct tcp_seg *next;
#if TCP_QUEUE_OOSEQ
struct tcp_seg *prev, *cseg;
#endif
#endif /* TCP_QUEUE_OOSEQ */
struct pbuf *p;
s32_t off;
s16_t m;
@ -1113,9 +1166,6 @@ tcp_receive(struct tcp_pcb *pcb)
LWIP_ASSERT("pbuf_header failed", 0);
}
}
/* KJM following line changed to use p->payload rather than inseg->p->payload
to fix bug #9076 */
inseg.dataptr = p->payload;
inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);
inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
}
@ -1143,7 +1193,7 @@ tcp_receive(struct tcp_pcb *pcb)
if (tcplen > pcb->rcv_wnd) {
LWIP_DEBUGF(TCP_INPUT_DEBUG,
("tcp_receive: other end overran receive window"
"seqno %"U32_F" len %"U32_F" right edge %"U32_F"\n",
"seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
/* Must remove the FIN from the header as we're trimming
@ -1161,60 +1211,53 @@ tcp_receive(struct tcp_pcb *pcb)
(seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
}
#if TCP_QUEUE_OOSEQ
/* Received in-sequence data, adjust ooseq data if:
- FIN has been received or
- inseq overlaps with ooseq */
if (pcb->ooseq != NULL) {
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
LWIP_DEBUGF(TCP_INPUT_DEBUG,
("tcp_receive: received in-order FIN, binning ooseq queue\n"));
/* Received in-order FIN means anything that was received
* out of order must now have been received in-order, so
* bin the ooseq queue
* rcv_nxt
* . |--ooseq--|
* .==seg============|FIN
*/
* bin the ooseq queue */
while (pcb->ooseq != NULL) {
struct tcp_seg *old_ooseq = pcb->ooseq;
pcb->ooseq = pcb->ooseq->next;
tcp_seg_free(old_ooseq);
}
}
}
}
else {
struct tcp_seg* next = pcb->ooseq;
struct tcp_seg *old_seg;
/* rcv_nxt
* . |--ooseq--|
* .==seg============|
*/
next = pcb->ooseq;
/* Remove all segments on ooseq that are covered by inseg already.
* FIN is copied from ooseq to inseg if present. */
while (next &&
TCP_SEQ_GEQ(seqno + tcplen,
next->tcphdr->seqno + next->len)) {
/* inseg doesn't have FIN (already processed) */
/* inseg cannot have FIN here (already processed above) */
if (TCPH_FLAGS(next->tcphdr) & TCP_FIN &&
(TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) {
TCPH_FLAGS_SET(inseg.tcphdr,
TCPH_FLAGS(inseg.tcphdr) | TCP_FIN);
TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN);
tcplen = TCP_TCPLEN(&inseg);
}
old_seg = next;
prev = next;
next = next->next;
tcp_seg_free(old_seg);
tcp_seg_free(prev);
}
/* rcv_nxt
* . |--ooseq--|
* .==seg============|
*/
/* Now trim right side of inseg if it overlaps with the first
* segment on ooseq */
if (next &&
TCP_SEQ_GT(seqno + tcplen,
next->tcphdr->seqno)) {
/* FIN in inseg already handled by dropping whole ooseq queue */
inseg.len = (u16_t)(pcb->ooseq->tcphdr->seqno - seqno);
/* inseg cannot have FIN here (already processed above) */
inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
inseg.len -= 1;
}
pbuf_realloc(inseg.p, inseg.len);
tcplen = TCP_TCPLEN(&inseg);
LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n",
(seqno + tcplen) == pcb->ooseq->tcphdr->seqno);
(seqno + tcplen) == next->tcphdr->seqno);
}
pcb->ooseq = next;
}
@ -1252,7 +1295,7 @@ tcp_receive(struct tcp_pcb *pcb)
#if TCP_QUEUE_OOSEQ
/* We now check if we have segments on the ->ooseq queue that
is now in sequence. */
are now in sequence. */
while (pcb->ooseq != NULL &&
pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
@ -1392,6 +1435,24 @@ tcp_receive(struct tcp_pcb *pcb)
next->len = (u16_t)(seqno - next->tcphdr->seqno);
pbuf_realloc(next->p, next->len);
}
/* check if the remote side overruns our receive window */
if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) {
LWIP_DEBUGF(TCP_INPUT_DEBUG,
("tcp_receive: other end overran receive window"
"seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) {
/* Must remove the FIN from the header as we're trimming
* that byte of sequence-space from the packet */
TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN);
}
/* Adjust length of segment to fit in the window. */
next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno;
pbuf_realloc(next->next->p, next->next->len);
tcplen = TCP_TCPLEN(next->next);
LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
(seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
}
}
break;
}

File diff suppressed because it is too large Load diff

482
lwip/src/core/timers.c Normal file
View file

@ -0,0 +1,482 @@
/**
* @file
* Stack-internal timers implementation.
* This file includes timer callbacks for stack-internal timers as well as
* functions to set up or stop timers and check for expired timers.
*
*/
/*
* Copyright (c) 2001-2004 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>
* Simon Goldschmidt
*
*/
#include "lwip/opt.h"
#include "lwip/timers.h"
#include "lwip/tcp_impl.h"
#if LWIP_TIMERS
#include "lwip/def.h"
#include "lwip/memp.h"
#include "lwip/tcpip.h"
#include "lwip/ip_frag.h"
#include "netif/etharp.h"
#include "lwip/dhcp.h"
#include "lwip/autoip.h"
#include "lwip/igmp.h"
#include "lwip/dns.h"
/** The one and only timeout list */
static struct sys_timeo *next_timeout;
#if NO_SYS
static u32_t timeouts_last_time;
#endif /* NO_SYS */
#if LWIP_TCP
/** global variable that shows if the tcp timer is currently scheduled or not */
static int tcpip_tcp_timer_active;
/**
* Timer callback function that calls tcp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
tcpip_tcp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
/* call TCP timer handler */
tcp_tmr();
/* timer still needed? */
if (tcp_active_pcbs || tcp_tw_pcbs) {
/* restart timer */
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
} else {
/* disable timer */
tcpip_tcp_timer_active = 0;
}
}
/**
* Called from TCP_REG when registering a new PCB:
* the reason is to have the TCP timer only running when
* there are active (or time-wait) PCBs.
*/
void
tcp_timer_needed(void)
{
/* timer is off but needed again? */
if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
/* enable and start timer */
tcpip_tcp_timer_active = 1;
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
}
}
#endif /* LWIP_TCP */
#if IP_REASSEMBLY
/**
* Timer callback function that calls ip_reass_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
ip_reass_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n"));
ip_reass_tmr();
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
}
#endif /* IP_REASSEMBLY */
#if LWIP_ARP
/**
* Timer callback function that calls etharp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
arp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n"));
etharp_tmr();
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
}
#endif /* LWIP_ARP */
#if LWIP_DHCP
/**
* Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dhcp_timer_coarse(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
dhcp_coarse_tmr();
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
}
/**
* Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dhcp_timer_fine(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
dhcp_fine_tmr();
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
}
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
/**
* Timer callback function that calls autoip_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
autoip_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n"));
autoip_tmr();
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
}
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
/**
* Timer callback function that calls igmp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
igmp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n"));
igmp_tmr();
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
}
#endif /* LWIP_IGMP */
#if LWIP_DNS
/**
* Timer callback function that calls dns_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dns_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n"));
dns_tmr();
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
}
#endif /* LWIP_DNS */
/** Initialize this module */
void sys_timeouts_init(void)
{
#if IP_REASSEMBLY
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
#endif /* IP_REASSEMBLY */
#if LWIP_ARP
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
#endif /* LWIP_ARP */
#if LWIP_DHCP
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
#endif /* LWIP_IGMP */
#if LWIP_DNS
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
#endif /* LWIP_DNS */
#if NO_SYS
/* Initialise timestamp for sys_check_timeouts */
timeouts_last_time = sys_now();
#endif
}
/**
* Create a one-shot timer (aka timeout). Timeouts are processed in the
* following cases:
* - while waiting for a message using sys_timeouts_mbox_fetch()
* - by calling sys_check_timeouts() (NO_SYS==1 only)
*
* @param msecs time in milliseconds after that the timer should expire
* @param handler callback function to call when msecs have elapsed
* @param arg argument to pass to the callback function
*/
#if LWIP_DEBUG_TIMERNAMES
void
sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)
#else /* LWIP_DEBUG_TIMERNAMES */
void
sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
#endif /* LWIP_DEBUG_TIMERNAMES */
{
struct sys_timeo *timeout, *t;
timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT);
if (timeout == NULL) {
LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL);
return;
}
timeout->next = NULL;
timeout->h = handler;
timeout->arg = arg;
timeout->time = msecs;
#if LWIP_DEBUG_TIMERNAMES
timeout->handler_name = handler_name;
LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n",
(void *)timeout, msecs, handler_name, (void *)arg));
#endif /* LWIP_DEBUG_TIMERNAMES */
if (next_timeout == NULL) {
next_timeout = timeout;
return;
}
if (next_timeout->time > msecs) {
next_timeout->time -= msecs;
timeout->next = next_timeout;
next_timeout = timeout;
} else {
for(t = next_timeout; t != NULL; t = t->next) {
timeout->time -= t->time;
if (t->next == NULL || t->next->time > timeout->time) {
if (t->next != NULL) {
t->next->time -= timeout->time;
}
timeout->next = t->next;
t->next = timeout;
break;
}
}
}
}
/**
* Go through timeout list (for this task only) and remove the first matching
* entry, even though the timeout has not triggered yet.
*
* @note This function only works as expected if there is only one timeout
* calling 'handler' in the list of timeouts.
*
* @param handler callback function that would be called by the timeout
* @param arg callback argument that would be passed to handler
*/
void
sys_untimeout(sys_timeout_handler handler, void *arg)
{
struct sys_timeo *prev_t, *t;
if (next_timeout == NULL) {
return;
}
for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
if ((t->h == handler) && (t->arg == arg)) {
/* We have a match */
/* Unlink from previous in list */
if (prev_t == NULL) {
next_timeout = t->next;
} else {
prev_t->next = t->next;
}
/* If not the last one, add time of this one back to next */
if (t->next != NULL) {
t->next->time += t->time;
}
memp_free(MEMP_SYS_TIMEOUT, t);
return;
}
}
return;
}
#if NO_SYS
/** Handle timeouts for NO_SYS==1 (i.e. without using
* tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout
* handler functions when timeouts expire.
*
* Must be called periodically from your main loop.
*/
void
sys_check_timeouts(void)
{
struct sys_timeo *tmptimeout;
u32_t diff;
sys_timeout_handler handler;
void *arg;
int had_one;
u32_t now;
now = sys_now();
if (next_timeout) {
/* this cares for wraparounds */
diff = LWIP_U32_DIFF(now, timeouts_last_time);
do
{
had_one = 0;
tmptimeout = next_timeout;
if (tmptimeout->time <= diff) {
/* timeout has expired */
had_one = 1;
timeouts_last_time = now;
diff -= tmptimeout->time;
next_timeout = tmptimeout->next;
handler = tmptimeout->h;
arg = tmptimeout->arg;
#if LWIP_DEBUG_TIMERNAMES
if (handler != NULL) {
LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n",
tmptimeout->handler_name, arg));
}
#endif /* LWIP_DEBUG_TIMERNAMES */
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
if (handler != NULL) {
handler(arg);
}
}
/* repeat until all expired timers have been called */
}while(had_one);
}
}
/** Set back the timestamp of the last call to sys_check_timeouts()
* This is necessary if sys_check_timeouts() hasn't been called for a long
* time (e.g. while saving energy) to prevent all timer functions of that
* period being called.
*/
void
sys_restart_timeouts(void)
{
timeouts_last_time = sys_now();
}
#else /* NO_SYS */
/**
* Wait (forever) for a message to arrive in an mbox.
* While waiting, timeouts are processed.
*
* @param mbox the mbox to fetch the message from
* @param msg the place to store the message
*/
void
sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
{
u32_t time_needed;
struct sys_timeo *tmptimeout;
sys_timeout_handler handler;
void *arg;
again:
if (!next_timeout) {
time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
} else {
if (next_timeout->time > 0) {
time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time);
} else {
time_needed = SYS_ARCH_TIMEOUT;
}
if (time_needed == SYS_ARCH_TIMEOUT) {
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
could be fetched. We should now call the timeout handler and
deallocate the memory allocated for the timeout. */
tmptimeout = next_timeout;
next_timeout = tmptimeout->next;
handler = tmptimeout->h;
arg = tmptimeout->arg;
#if LWIP_DEBUG_TIMERNAMES
if (handler != NULL) {
LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n",
tmptimeout->handler_name, arg));
}
#endif /* LWIP_DEBUG_TIMERNAMES */
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
if (handler != NULL) {
/* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the
timeout handler function. */
LOCK_TCPIP_CORE();
handler(arg);
UNLOCK_TCPIP_CORE();
}
LWIP_TCPIP_THREAD_ALIVE();
/* We try again to fetch a message from the mbox. */
goto again;
} else {
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
occured. The time variable is set to the number of
milliseconds we waited for the message. */
if (time_needed < next_timeout->time) {
next_timeout->time -= time_needed;
} else {
next_timeout->time = 0;
}
}
}
}
#endif /* NO_SYS */
#else /* LWIP_TIMERS */
/* Satisfy the TCP code which calls this function */
void
tcp_timer_needed(void)
{
}
#endif /* LWIP_TIMERS */

View file

@ -53,7 +53,6 @@
#include "lwip/udp.h"
#include "lwip/def.h"
#include "lwip/memp.h"
#include "lwip/inet.h"
#include "lwip/inet_chksum.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
@ -96,7 +95,7 @@ udp_input(struct pbuf *p, struct netif *inp)
UDP_STATS_INC(udp.recv);
iphdr = p->payload;
iphdr = (struct ip_hdr *)p->payload;
/* Check minimum length (IP header + UDP header)
* and move payload pointer to UDP header */
@ -114,7 +113,7 @@ udp_input(struct pbuf *p, struct netif *inp)
udphdr = (struct udp_hdr *)p->payload;
/* is broadcast packet ? */
broadcast = ip_addr_isbroadcast(&(iphdr->dest), inp);
broadcast = ip_addr_isbroadcast(&current_iphdr_dest, inp);
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));
@ -128,10 +127,10 @@ udp_input(struct pbuf *p, struct netif *inp)
LWIP_DEBUGF(UDP_DEBUG,
("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- "
"(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest),
ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest),
ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src),
ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src)));
ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest),
ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest), ntohs(udphdr->dest),
ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src),
ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src), ntohs(udphdr->src)));
#if LWIP_DHCP
pcb = NULL;
@ -145,7 +144,7 @@ udp_input(struct pbuf *p, struct netif *inp)
(- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY!
- inp->dhcp->pcb->remote == ANY or iphdr->src */
if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) ||
ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &(iphdr->src)))) {
ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &current_iphdr_src))) {
pcb = inp->dhcp->pcb;
}
}
@ -166,17 +165,17 @@ udp_input(struct pbuf *p, struct netif *inp)
LWIP_DEBUGF(UDP_DEBUG,
("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- "
"(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),
ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port,
ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port));
ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), pcb->local_port,
ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port));
/* compare PCB local addr+port to UDP destination addr+port */
if ((pcb->local_port == dest) &&
((!broadcast && ip_addr_isany(&pcb->local_ip)) ||
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) ||
ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest) ||
#if LWIP_IGMP
ip_addr_ismulticast(&(iphdr->dest)) ||
ip_addr_ismulticast(&current_iphdr_dest) ||
#endif /* LWIP_IGMP */
#if IP_SOF_BROADCAST_RECV
(broadcast && (pcb->so_options & SOF_BROADCAST)))) {
@ -194,7 +193,7 @@ udp_input(struct pbuf *p, struct netif *inp)
if ((local_match != 0) &&
(pcb->remote_port == src) &&
(ip_addr_isany(&pcb->remote_ip) ||
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) {
ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src))) {
/* the first fully matching PCB */
if (prev != NULL) {
/* move the pcb to the front of udp_pcbs so that is
@ -216,7 +215,7 @@ udp_input(struct pbuf *p, struct netif *inp)
}
/* Check checksum if this is a match or if it was directed at us. */
if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) {
if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &current_iphdr_dest)) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n"));
#if LWIP_UDPLITE
if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
@ -238,8 +237,7 @@ udp_input(struct pbuf *p, struct netif *inp)
goto end;
}
}
if (inet_chksum_pseudo_partial(p, (struct ip_addr *)&(iphdr->src),
(struct ip_addr *)&(iphdr->dest),
if (inet_chksum_pseudo_partial(p, &current_iphdr_src, &current_iphdr_dest,
IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
@ -255,8 +253,7 @@ udp_input(struct pbuf *p, struct netif *inp)
{
#if CHECKSUM_CHECK_UDP
if (udphdr->chksum != 0) {
if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
(struct ip_addr *)&(iphdr->dest),
if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
IP_PROTO_UDP, p->tot_len) != 0) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("udp_input: UDP datagram discarded due to failing checksum\n"));
@ -279,10 +276,58 @@ udp_input(struct pbuf *p, struct netif *inp)
}
if (pcb != NULL) {
snmp_inc_udpindatagrams();
#if SO_REUSE && SO_REUSE_RXTOALL
if ((broadcast || ip_addr_ismulticast(&current_iphdr_dest)) &&
((pcb->so_options & SOF_REUSEADDR) != 0)) {
/* pass broadcast- or multicast packets to all multicast pcbs
if SOF_REUSEADDR is set on the first match */
struct udp_pcb *mpcb;
u8_t p_header_changed = 0;
for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) {
if (mpcb != pcb) {
/* compare PCB local addr+port to UDP destination addr+port */
if ((mpcb->local_port == dest) &&
((!broadcast && ip_addr_isany(&mpcb->local_ip)) ||
ip_addr_cmp(&(mpcb->local_ip), &current_iphdr_dest) ||
#if LWIP_IGMP
ip_addr_ismulticast(&current_iphdr_dest) ||
#endif /* LWIP_IGMP */
#if IP_SOF_BROADCAST_RECV
(broadcast && (mpcb->so_options & SOF_BROADCAST)))) {
#else /* IP_SOF_BROADCAST_RECV */
(broadcast))) {
#endif /* IP_SOF_BROADCAST_RECV */
/* pass a copy of the packet to all local matches */
if (mpcb->recv != NULL) {
struct pbuf *q;
/* for that, move payload to IP header again */
if (p_header_changed == 0) {
pbuf_header(p, (s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
p_header_changed = 1;
}
q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
if (q != NULL) {
err_t err = pbuf_copy(q, p);
if (err == ERR_OK) {
/* move payload to UDP data */
pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src);
}
}
}
}
}
}
if (p_header_changed) {
/* and move payload to UDP data again */
pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
}
}
#endif /* SO_REUSE && SO_REUSE_RXTOALL */
/* callback */
if (pcb->recv != NULL) {
/* now the recv function is responsible for freeing p */
pcb->recv(pcb->recv_arg, pcb, p, &iphdr->src, src);
pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src);
} else {
/* no recv function registered? then we have to free the pbuf! */
pbuf_free(p);
@ -295,7 +340,7 @@ udp_input(struct pbuf *p, struct netif *inp)
/* No match was found, send ICMP destination port unreachable unless
destination address was broadcast/multicast. */
if (!broadcast &&
!ip_addr_ismulticast(&iphdr->dest)) {
!ip_addr_ismulticast(&current_iphdr_dest)) {
/* move payload pointer back to ip header */
pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN);
LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr));
@ -339,6 +384,19 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p)
return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);
}
#if LWIP_CHECKSUM_ON_COPY
/** Same as udp_send() but with checksum
*/
err_t
udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
u8_t have_chksum, u16_t chksum)
{
/* send to the packet using remote ip and port stored in the pcb */
return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port,
have_chksum, chksum);
}
#endif /* LWIP_CHECKSUM_ON_COPY */
/**
* Send data to a specified address using UDP.
*
@ -358,8 +416,18 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p)
*/
err_t
udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
struct ip_addr *dst_ip, u16_t dst_port)
ip_addr_t *dst_ip, u16_t dst_port)
{
#if LWIP_CHECKSUM_ON_COPY
return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0);
}
/** Same as udp_sendto(), but with checksum */
err_t
udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
u16_t dst_port, u8_t have_chksum, u16_t chksum)
{
#endif /* LWIP_CHECKSUM_ON_COPY */
struct netif *netif;
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));
@ -373,11 +441,16 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
/* no outgoing network interface could be found? */
if (netif == NULL) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to 0x%"X32_F"\n", dst_ip->addr));
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(dst_ip), ip4_addr2_16(dst_ip), ip4_addr3_16(dst_ip), ip4_addr4_16(dst_ip)));
UDP_STATS_INC(udp.rterr);
return ERR_RTE;
}
#if LWIP_CHECKSUM_ON_COPY
return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum);
#else /* LWIP_CHECKSUM_ON_COPY */
return udp_sendto_if(pcb, p, dst_ip, dst_port, netif);
#endif /* LWIP_CHECKSUM_ON_COPY */
}
/**
@ -401,10 +474,21 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
*/
err_t
udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif)
ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif)
{
#if LWIP_CHECKSUM_ON_COPY
return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0);
}
/** Same as udp_sendto_if(), but with checksum */
err_t
udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
u16_t dst_port, struct netif *netif, u8_t have_chksum,
u16_t chksum)
{
#endif /* LWIP_CHECKSUM_ON_COPY */
struct udp_hdr *udphdr;
struct ip_addr *src_ip;
ip_addr_t *src_ip;
err_t err;
struct pbuf *q; /* q will be sent down the stack */
@ -436,8 +520,10 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n"));
return ERR_MEM;
}
/* chain header q in front of given pbuf p */
pbuf_chain(q, p);
if (p->tot_len != 0) {
/* chain header q in front of given pbuf p (only if p contains data) */
pbuf_chain(q, p);
}
/* first pbuf q points to header pbuf */
LWIP_DEBUGF(UDP_DEBUG,
("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
@ -450,12 +536,20 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
LWIP_ASSERT("check that first pbuf can hold struct udp_hdr",
(q->len >= sizeof(struct udp_hdr)));
/* q now represents the packet to be sent */
udphdr = q->payload;
udphdr = (struct udp_hdr *)q->payload;
udphdr->src = htons(pcb->local_port);
udphdr->dest = htons(dst_port);
/* in UDP, 0 checksum means 'no checksum' */
udphdr->chksum = 0x0000;
/* Multicast Loop? */
#if LWIP_IGMP
if (ip_addr_ismulticast(dst_ip) && ((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0)) {
q->flags |= PBUF_FLAG_MCASTLOOP;
}
#endif /* LWIP_IGMP */
/* PCB local address is IP_ANY_ADDR? */
if (ip_addr_isany(&pcb->local_ip)) {
/* use outgoing network interface IP address as source address */
@ -503,11 +597,23 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
/* calculate checksum */
#if CHECKSUM_GEN_UDP
udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip,
IP_PROTO_UDPLITE, q->tot_len, chklen);
IP_PROTO_UDPLITE, q->tot_len,
#if !LWIP_CHECKSUM_ON_COPY
chklen);
#else /* !LWIP_CHECKSUM_ON_COPY */
(have_chksum ? UDP_HLEN : chklen));
if (have_chksum) {
u32_t acc;
acc = udphdr->chksum + (u16_t)~(chksum);
udphdr->chksum = FOLD_U32T(acc);
}
#endif /* !LWIP_CHECKSUM_ON_COPY */
/* chksum zero must become 0xffff, as zero means 'no checksum' */
if (udphdr->chksum == 0x0000)
if (udphdr->chksum == 0x0000) {
udphdr->chksum = 0xffff;
#endif /* CHECKSUM_CHECK_UDP */
}
#endif /* CHECKSUM_GEN_UDP */
/* output to IP */
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));
#if LWIP_NETIF_HWADDRHINT
@ -525,11 +631,27 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
/* calculate checksum */
#if CHECKSUM_GEN_UDP
if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
udphdr->chksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);
u16_t udpchksum;
#if LWIP_CHECKSUM_ON_COPY
if (have_chksum) {
u32_t acc;
udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP,
q->tot_len, UDP_HLEN);
acc = udpchksum + (u16_t)~(chksum);
udpchksum = FOLD_U32T(acc);
} else
#endif /* LWIP_CHECKSUM_ON_COPY */
{
udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);
}
/* chksum zero must become 0xffff, as zero means 'no checksum' */
if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;
if (udpchksum == 0x0000) {
udpchksum = 0xffff;
}
udphdr->chksum = udpchksum;
}
#endif /* CHECKSUM_CHECK_UDP */
#endif /* CHECKSUM_GEN_UDP */
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));
/* output to IP */
@ -576,7 +698,7 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
* @see udp_disconnect()
*/
err_t
udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
{
struct udp_pcb *ipcb;
u8_t rebind;
@ -596,13 +718,16 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
rebind = 1;
}
/* this code does not allow upper layer to share a UDP port for
listening to broadcast or multicast traffic (See SO_REUSE_ADDR and
SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR
combine with implementation of UDP PCB flags. Leon Woestenberg. */
#ifdef LWIP_UDP_TODO
/* port matches that of PCB in list? */
else
/* By default, we don't allow to bind to a port that any other udp
PCB is alread bound to, unless *all* PCBs with that port have tha
REUSEADDR flag set. */
#if SO_REUSE
else if (((pcb->so_options & SOF_REUSEADDR) == 0) &&
((ipcb->so_options & SOF_REUSEADDR) == 0)) {
#else /* SO_REUSE */
/* port matches that of PCB in list and REUSEADDR not set -> reject */
else {
#endif /* SO_REUSE */
if ((ipcb->local_port == port) &&
/* IP address matches, or one is IP_ADDR_ANY? */
(ip_addr_isany(&(ipcb->local_ip)) ||
@ -613,7 +738,7 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
("udp_bind: local port %"U16_F" already bound by another pcb\n", port));
return ERR_USE;
}
#endif
}
}
ip_addr_set(&pcb->local_ip, ipaddr);
@ -621,8 +746,10 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
/* no port specified? */
if (port == 0) {
#ifndef UDP_LOCAL_PORT_RANGE_START
#define UDP_LOCAL_PORT_RANGE_START 4096
#define UDP_LOCAL_PORT_RANGE_END 0x7fff
/* From http://www.iana.org/assignments/port-numbers:
"The Dynamic and/or Private Ports are those from 49152 through 65535" */
#define UDP_LOCAL_PORT_RANGE_START 0xc000
#define UDP_LOCAL_PORT_RANGE_END 0xffff
#endif
port = UDP_LOCAL_PORT_RANGE_START;
ipcb = udp_pcbs;
@ -632,9 +759,10 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
port++;
/* restart scanning all udp pcbs */
ipcb = udp_pcbs;
} else
} else {
/* go on with next udp pcb */
ipcb = ipcb->next;
}
}
if (ipcb != NULL) {
/* no more ports available in local range */
@ -652,10 +780,9 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
}
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",
(u16_t)((ntohl(pcb->local_ip.addr) >> 24) & 0xff),
(u16_t)((ntohl(pcb->local_ip.addr) >> 16) & 0xff),
(u16_t)((ntohl(pcb->local_ip.addr) >> 8) & 0xff),
(u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port));
ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip),
pcb->local_port));
return ERR_OK;
}
/**
@ -676,14 +803,15 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
* @see udp_disconnect()
*/
err_t
udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
{
struct udp_pcb *ipcb;
if (pcb->local_port == 0) {
err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
if (err != ERR_OK)
if (err != ERR_OK) {
return err;
}
}
ip_addr_set(&pcb->remote_ip, ipaddr);
@ -710,10 +838,9 @@ udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
#endif
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",
(u16_t)((ntohl(pcb->remote_ip.addr) >> 24) & 0xff),
(u16_t)((ntohl(pcb->remote_ip.addr) >> 16) & 0xff),
(u16_t)((ntohl(pcb->remote_ip.addr) >> 8) & 0xff),
(u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port));
ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip),
pcb->local_port));
/* Insert UDP PCB into the list of active UDP PCBs. */
for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
@ -737,7 +864,7 @@ void
udp_disconnect(struct udp_pcb *pcb)
{
/* reset remote address association */
ip_addr_set(&pcb->remote_ip, IP_ADDR_ANY);
ip_addr_set_any(&pcb->remote_ip);
pcb->remote_port = 0;
/* mark PCB as unconnected */
pcb->flags &= ~UDP_FLAGS_CONNECTED;
@ -753,10 +880,7 @@ udp_disconnect(struct udp_pcb *pcb)
* @param recv_arg additional argument to pass to the callback function
*/
void
udp_recv(struct udp_pcb *pcb,
void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p,
struct ip_addr *addr, u16_t port),
void *recv_arg)
udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg)
{
/* remember recv() callback and user data */
pcb->recv = recv;
@ -782,7 +906,7 @@ udp_remove(struct udp_pcb *pcb)
/* make list start at 2nd pcb */
udp_pcbs = udp_pcbs->next;
/* pcb not 1st in list */
} else
} else {
for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
/* find pcb in udp_pcbs list */
if (pcb2->next != NULL && pcb2->next == pcb) {
@ -790,6 +914,7 @@ udp_remove(struct udp_pcb *pcb)
pcb2->next = pcb->next;
}
}
}
memp_free(MEMP_UDP_PCB, pcb);
}
@ -805,7 +930,7 @@ struct udp_pcb *
udp_new(void)
{
struct udp_pcb *pcb;
pcb = memp_malloc(MEMP_UDP_PCB);
pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB);
/* could allocate UDP PCB? */
if (pcb != NULL) {
/* UDP Lite: by initializing to all zeroes, chksum_len is set to 0

View file

@ -52,6 +52,7 @@ typedef int32_t s32_t;
typedef size_t mem_ptr_t;
/* Define (sn)printf formatters for these lwIP types */
#define X8_F "02x"
#define U16_F "hu"
#define S16_F "hd"
#define X16_F "hx"

View file

@ -80,7 +80,7 @@ extern "C" {
struct autoip
{
struct ip_addr llipaddr; /* the currently selected, probed, announced or used LL IP-Address */
ip_addr_t llipaddr; /* the currently selected, probed, announced or used LL IP-Address */
u8_t state; /* current AutoIP state machine state */
u8_t sent_num; /* sent number of probes or announces, dependent on state */
u16_t ttw; /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */
@ -92,6 +92,9 @@ struct autoip
/** Init srand, has to be called before entering mainloop */
void autoip_init(void);
/** Set a struct autoip allocated by the application to work with */
void autoip_set_struct(struct netif *netif, struct autoip *autoip);
/** Start AutoIP client */
err_t autoip_start(struct netif *netif);

View file

@ -41,29 +41,29 @@
extern "C" {
#endif
#define ICMP_ER 0 /* echo reply */
#define ICMP_DUR 3 /* destination unreachable */
#define ICMP_SQ 4 /* source quench */
#define ICMP_RD 5 /* redirect */
#define ICMP_ER 0 /* echo reply */
#define ICMP_DUR 3 /* destination unreachable */
#define ICMP_SQ 4 /* source quench */
#define ICMP_RD 5 /* redirect */
#define ICMP_ECHO 8 /* echo */
#define ICMP_TE 11 /* time exceeded */
#define ICMP_PP 12 /* parameter problem */
#define ICMP_TS 13 /* timestamp */
#define ICMP_TE 11 /* time exceeded */
#define ICMP_PP 12 /* parameter problem */
#define ICMP_TS 13 /* timestamp */
#define ICMP_TSR 14 /* timestamp reply */
#define ICMP_IRQ 15 /* information request */
#define ICMP_IR 16 /* information reply */
#define ICMP_IR 16 /* information reply */
enum icmp_dur_type {
ICMP_DUR_NET = 0, /* net unreachable */
ICMP_DUR_HOST = 1, /* host unreachable */
ICMP_DUR_NET = 0, /* net unreachable */
ICMP_DUR_HOST = 1, /* host unreachable */
ICMP_DUR_PROTO = 2, /* protocol unreachable */
ICMP_DUR_PORT = 3, /* port unreachable */
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
ICMP_DUR_SR = 5 /* source route failed */
ICMP_DUR_PORT = 3, /* port unreachable */
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
ICMP_DUR_SR = 5 /* source route failed */
};
enum icmp_te_type {
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */
};

View file

@ -46,57 +46,20 @@
extern "C" {
#endif
/*
* IGMP constants
*/
#define IP_PROTO_IGMP 2
#define IGMP_TTL 1
#define IGMP_MINLEN 8
#define ROUTER_ALERT 0x9404
#define ROUTER_ALERTLEN 4
/*
* IGMP message types, including version number.
*/
#define IGMP_MEMB_QUERY 0x11 /* Membership query */
#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */
#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */
#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */
/* IGMP timer */
#define IGMP_TMR_INTERVAL 100 /* Milliseconds */
#define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL)
#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL)
/* MAC Filter Actions */
/* MAC Filter Actions, these are passed to a netif's
* igmp_mac_filter callback function. */
#define IGMP_DEL_MAC_FILTER 0
#define IGMP_ADD_MAC_FILTER 1
/* Group membership states */
#define IGMP_GROUP_NON_MEMBER 0
#define IGMP_GROUP_DELAYING_MEMBER 1
#define IGMP_GROUP_IDLE_MEMBER 2
/*
* IGMP packet format.
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct igmp_msg {
PACK_STRUCT_FIELD(u8_t igmp_msgtype);
PACK_STRUCT_FIELD(u8_t igmp_maxresp);
PACK_STRUCT_FIELD(u16_t igmp_checksum);
PACK_STRUCT_FIELD(struct ip_addr igmp_group_address);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/*
* now a group structure - there is
/**
* igmp group structure - there is
* a list of groups for each interface
* these should really be linked from the interface, but
* if we keep them separate we will not affect the lwip original code
@ -106,53 +69,34 @@ PACK_STRUCT_END
* will not run the state machine as it is used to kick off reports
* from all the other groups
*/
struct igmp_group {
/** next link */
struct igmp_group *next;
struct netif *interface;
struct ip_addr group_address;
u8_t last_reporter_flag; /* signifies we were the last person to report */
/** interface on which the group is active */
struct netif *netif;
/** multicast address */
ip_addr_t group_address;
/** signifies we were the last person to report */
u8_t last_reporter_flag;
/** current state of the group */
u8_t group_state;
/** timer for reporting, negative is OFF */
u16_t timer;
u8_t use; /* counter of simultaneous uses */
/** counter of simultaneous uses */
u8_t use;
};
/* Prototypes */
void igmp_init(void);
err_t igmp_start( struct netif *netif);
err_t igmp_stop( struct netif *netif);
void igmp_report_groups( struct netif *netif);
struct igmp_group *igmp_lookfor_group( struct netif *ifp, struct ip_addr *addr);
struct igmp_group *igmp_lookup_group( struct netif *ifp, struct ip_addr *addr);
err_t igmp_remove_group( struct igmp_group *group);
void igmp_input( struct pbuf *p, struct netif *inp, struct ip_addr *dest);
err_t igmp_joingroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr);
err_t igmp_leavegroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr);
err_t igmp_start(struct netif *netif);
err_t igmp_stop(struct netif *netif);
void igmp_report_groups(struct netif *netif);
struct igmp_group *igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr);
void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest);
err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr);
err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr);
void igmp_tmr(void);
void igmp_timeout( struct igmp_group *group);
void igmp_start_timer( struct igmp_group *group, u8_t max_time);
void igmp_stop_timer( struct igmp_group *group);
void igmp_delaying_member( struct igmp_group *group, u8_t maxresp);
err_t igmp_ip_output_if( struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t proto, struct netif *netif);
void igmp_send( struct igmp_group *group, u8_t type);
#ifdef __cplusplus
}
#endif

View file

@ -33,68 +33,72 @@
#define __LWIP_INET_H__
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/ip_addr.h"
#ifdef __cplusplus
extern "C" {
#endif
/* For compatibility with BSD code */
/** For compatibility with BSD code */
struct in_addr {
u32_t s_addr;
};
#define INADDR_NONE ((u32_t)0xffffffffUL) /* 255.255.255.255 */
#define INADDR_LOOPBACK ((u32_t)0x7f000001UL) /* 127.0.0.1 */
#define INADDR_ANY ((u32_t)0x00000000UL) /* 0.0.0.0 */
#define INADDR_BROADCAST ((u32_t)0xffffffffUL) /* 255.255.255.255 */
/** 255.255.255.255 */
#define INADDR_NONE IPADDR_NONE
/** 127.0.0.1 */
#define INADDR_LOOPBACK IPADDR_LOOPBACK
/** 0.0.0.0 */
#define INADDR_ANY IPADDR_ANY
/** 255.255.255.255 */
#define INADDR_BROADCAST IPADDR_BROADCAST
u32_t inet_addr(const char *cp);
int inet_aton(const char *cp, struct in_addr *addr);
char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */
/* Definitions of the bits in an Internet address integer.
#ifdef htons
#undef htons
#endif /* htons */
#ifdef htonl
#undef htonl
#endif /* htonl */
#ifdef ntohs
#undef ntohs
#endif /* ntohs */
#ifdef ntohl
#undef ntohl
#endif /* ntohl */
On subnets, host and network parts are found according to
the subnet mask, not these masks. */
#define IN_CLASSA(a) IP_CLASSA(a)
#define IN_CLASSA_NET IP_CLASSA_NET
#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT
#define IN_CLASSA_HOST IP_CLASSA_HOST
#define IN_CLASSA_MAX IP_CLASSA_MAX
#ifndef LWIP_PLATFORM_BYTESWAP
#define LWIP_PLATFORM_BYTESWAP 0
#endif
#define IN_CLASSB(b) IP_CLASSB(b)
#define IN_CLASSB_NET IP_CLASSB_NET
#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT
#define IN_CLASSB_HOST IP_CLASSB_HOST
#define IN_CLASSB_MAX IP_CLASSB_MAX
#if BYTE_ORDER == BIG_ENDIAN
#define htons(x) (x)
#define ntohs(x) (x)
#define htonl(x) (x)
#define ntohl(x) (x)
#else /* BYTE_ORDER != BIG_ENDIAN */
#ifdef LWIP_PREFIX_BYTEORDER_FUNCS
/* workaround for naming collisions on some platforms */
#define htons lwip_htons
#define ntohs lwip_ntohs
#define htonl lwip_htonl
#define ntohl lwip_ntohl
#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */
#if LWIP_PLATFORM_BYTESWAP
#define htons(x) LWIP_PLATFORM_HTONS(x)
#define ntohs(x) LWIP_PLATFORM_HTONS(x)
#define htonl(x) LWIP_PLATFORM_HTONL(x)
#define ntohl(x) LWIP_PLATFORM_HTONL(x)
#else /* LWIP_PLATFORM_BYTESWAP */
u16_t htons(u16_t x);
u16_t ntohs(u16_t x);
u32_t htonl(u32_t x);
u32_t ntohl(u32_t x);
#endif /* LWIP_PLATFORM_BYTESWAP */
#define IN_CLASSC(c) IP_CLASSC(c)
#define IN_CLASSC_NET IP_CLASSC_NET
#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT
#define IN_CLASSC_HOST IP_CLASSC_HOST
#define IN_CLASSC_MAX IP_CLASSC_MAX
#endif /* BYTE_ORDER == BIG_ENDIAN */
#define IN_CLASSD(d) IP_CLASSD(d)
#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */
#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */
#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */
#define IN_CLASSD_MAX IP_CLASSD_MAX
#define IN_MULTICAST(a) IP_MULTICAST(a)
#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a)
#define IN_BADCLASS(a) IP_BADCLASS(a)
#define IN_LOOPBACKNET IP_LOOPBACKNET
#define inet_addr_from_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr))
#define inet_addr_to_ipaddr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr))
/* ATTENTION: the next define only works because both s_addr and ip_addr_t are an u32_t effectively! */
#define inet_addr_to_ipaddr_p(target_ipaddr_p, source_inaddr) ((target_ipaddr_p) = (ip_addr_t*)&((source_inaddr)->s_addr))
/* directly map this to the lwip internal functions */
#define inet_addr(cp) ipaddr_addr(cp)
#define inet_aton(cp, addr) ipaddr_aton(cp, (ip_addr_t*)addr)
#define inet_ntoa(addr) ipaddr_ntoa((ip_addr_t*)&(addr))
#define inet_ntoa_r(addr, buf, buflen) ipaddr_ntoa_r((ip_addr_t*)&(addr), buf, buflen)
#ifdef __cplusplus
}

View file

@ -37,6 +37,35 @@
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
/** Swap the bytes in an u16_t: much like htons() for little-endian */
#ifndef SWAP_BYTES_IN_WORD
#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)
/* little endian and PLATFORM_BYTESWAP defined */
#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w)
#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */
/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */
#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8)
#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/
#endif /* SWAP_BYTES_IN_WORD */
/** Split an u32_t in two u16_ts and add them up */
#ifndef FOLD_U32T
#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL))
#endif
#if LWIP_CHECKSUM_ON_COPY
/** Function-like macro: same as MEMCPY but returns the checksum of copied data
as u16_t */
#ifndef LWIP_CHKSUM_COPY
#define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len)
#ifndef LWIP_CHKSUM_COPY_ALGORITHM
#define LWIP_CHKSUM_COPY_ALGORITHM 1
#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
#endif /* LWIP_CHKSUM_COPY */
#else /* LWIP_CHECKSUM_ON_COPY */
#define LWIP_CHKSUM_COPY_ALGORITHM 0
#endif /* LWIP_CHECKSUM_ON_COPY */
#ifdef __cplusplus
extern "C" {
#endif
@ -44,13 +73,14 @@ extern "C" {
u16_t inet_chksum(void *dataptr, u16_t len);
u16_t inet_chksum_pbuf(struct pbuf *p);
u16_t inet_chksum_pseudo(struct pbuf *p,
struct ip_addr *src, struct ip_addr *dest,
ip_addr_t *src, ip_addr_t *dest,
u8_t proto, u16_t proto_len);
#if LWIP_UDPLITE
u16_t inet_chksum_pseudo_partial(struct pbuf *p,
struct ip_addr *src, struct ip_addr *dest,
ip_addr_t *src, ip_addr_t *dest,
u8_t proto, u16_t proto_len, u16_t chksum_len);
#endif
#if LWIP_CHKSUM_COPY_ALGORITHM
u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len);
#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
#ifdef __cplusplus
}

View file

@ -50,6 +50,7 @@ extern "C" {
#define IP_HLEN 20
#define IP_PROTO_ICMP 1
#define IP_PROTO_IGMP 2
#define IP_PROTO_UDP 17
#define IP_PROTO_UDPLITE 136
#define IP_PROTO_TCP 6
@ -74,10 +75,10 @@ extern "C" {
having to change all PCB structs. */
#define IP_PCB \
/* ip addresses in network byte order */ \
struct ip_addr local_ip; \
struct ip_addr remote_ip; \
ip_addr_t local_ip; \
ip_addr_t remote_ip; \
/* Socket options */ \
u16_t so_options; \
u8_t so_options; \
/* Type Of Service */ \
u8_t tos; \
/* Time To Live */ \
@ -93,16 +94,19 @@ struct ip_pcb {
/*
* Option flags per-socket. These are the same like SO_XXX.
*/
#define SOF_DEBUG (u16_t)0x0001U /* turn on debugging info recording */
#define SOF_ACCEPTCONN (u16_t)0x0002U /* socket has had listen() */
#define SOF_REUSEADDR (u16_t)0x0004U /* allow local address reuse */
#define SOF_KEEPALIVE (u16_t)0x0008U /* keep connections alive */
#define SOF_DONTROUTE (u16_t)0x0010U /* just use interface addresses */
#define SOF_BROADCAST (u16_t)0x0020U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
#define SOF_USELOOPBACK (u16_t)0x0040U /* bypass hardware when possible */
#define SOF_LINGER (u16_t)0x0080U /* linger on close if data present */
#define SOF_OOBINLINE (u16_t)0x0100U /* leave received OOB data in line */
#define SOF_REUSEPORT (u16_t)0x0200U /* allow local address & port reuse */
/*#define SOF_DEBUG (u8_t)0x01U Unimplemented: turn on debugging info recording */
#define SOF_ACCEPTCONN (u8_t)0x02U /* socket has had listen() */
#define SOF_REUSEADDR (u8_t)0x04U /* allow local address reuse */
#define SOF_KEEPALIVE (u8_t)0x08U /* keep connections alive */
/*#define SOF_DONTROUTE (u8_t)0x10U Unimplemented: just use interface addresses */
#define SOF_BROADCAST (u8_t)0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
/*#define SOF_USELOOPBACK (u8_t)0x40U Unimplemented: bypass hardware when possible */
#define SOF_LINGER (u8_t)0x80U /* linger on close if data present */
/*#define SOF_OOBINLINE (u16_t)0x0100U Unimplemented: leave received OOB data in line */
/*#define SOF_REUSEPORT (u16_t)0x0200U Unimplemented: allow local address & port reuse */
/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */
#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/)
#ifdef PACK_STRUCT_USE_INCLUDES
@ -118,17 +122,19 @@ struct ip_hdr {
PACK_STRUCT_FIELD(u16_t _id);
/* fragment offset field */
PACK_STRUCT_FIELD(u16_t _offset);
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
/* time to live / protocol*/
PACK_STRUCT_FIELD(u16_t _ttl_proto);
#define IP_RF 0x8000U /* reserved fragment flag */
#define IP_DF 0x4000U /* dont fragment flag */
#define IP_MF 0x2000U /* more fragments flag */
#define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */
/* time to live */
PACK_STRUCT_FIELD(u8_t _ttl);
/* protocol*/
PACK_STRUCT_FIELD(u8_t _proto);
/* checksum */
PACK_STRUCT_FIELD(u16_t _chksum);
/* source and destination IP addresses */
PACK_STRUCT_FIELD(struct ip_addr src);
PACK_STRUCT_FIELD(struct ip_addr dest);
PACK_STRUCT_FIELD(ip_addr_p_t src);
PACK_STRUCT_FIELD(ip_addr_p_t dest);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
@ -141,37 +147,41 @@ PACK_STRUCT_END
#define IPH_LEN(hdr) ((hdr)->_len)
#define IPH_ID(hdr) ((hdr)->_id)
#define IPH_OFFSET(hdr) ((hdr)->_offset)
#define IPH_TTL(hdr) (ntohs((hdr)->_ttl_proto) >> 8)
#define IPH_PROTO(hdr) (ntohs((hdr)->_ttl_proto) & 0xff)
#define IPH_TTL(hdr) ((hdr)->_ttl)
#define IPH_PROTO(hdr) ((hdr)->_proto)
#define IPH_CHKSUM(hdr) ((hdr)->_chksum)
#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos)))
#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)
#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)
#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)
#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl_proto = (htons(IPH_PROTO(hdr) | ((u16_t)(ttl) << 8)))
#define IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8)))
#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl)
#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto)
#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
/** The interface that provided the packet for the current callback invocation. */
extern struct netif *current_netif;
/** Header of the input packet currently being processed. */
extern const struct ip_hdr *current_header;
/** Source IP address of current_header */
extern ip_addr_t current_iphdr_src;
/** Destination IP address of current_header */
extern ip_addr_t current_iphdr_dest;
#define ip_init() /* Compatibility define, not init needed. */
struct netif *ip_route(struct ip_addr *dest);
struct netif *ip_route(ip_addr_t *dest);
err_t ip_input(struct pbuf *p, struct netif *inp);
err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto);
err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto,
struct netif *netif);
#if LWIP_NETIF_HWADDRHINT
err_t ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint);
#endif /* LWIP_NETIF_HWADDRHINT */
#if IP_OPTIONS_SEND
err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
u16_t optlen);
#endif /* IP_OPTIONS_SEND */
@ -183,6 +193,11 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest
* This function must only be called from a receive callback (udp_recv,
* raw_recv, tcp_accept). It will return NULL otherwise. */
#define ip_current_header() (current_header)
/** Source IP address of current_header */
#define ip_current_src_addr() (&current_iphdr_src)
/** Destination IP address of current_header */
#define ip_current_dest_addr() (&current_iphdr_dest)
#if IP_DEBUG
void ip_debug_print(struct pbuf *p);
#else

View file

@ -33,18 +33,25 @@
#define __LWIP_IP_ADDR_H__
#include "lwip/opt.h"
#include "lwip/inet.h"
#include "lwip/def.h"
#ifdef __cplusplus
extern "C" {
#endif
/* This is the aligned version of ip_addr_t,
used as local variable, on the stack, etc. */
struct ip_addr {
u32_t addr;
};
/* This is the packed version of ip_addr_t,
used in network headers that are itself packed */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_addr {
struct ip_addr_packed {
PACK_STRUCT_FIELD(u32_t addr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
@ -52,6 +59,11 @@ PACK_STRUCT_END
# include "arch/epstruct.h"
#endif
/** ip_addr_t uses a struct for convenience only, so that the same defines can
* operate both on ip_addr_t as well as on ip_addr_p_t. */
typedef struct ip_addr ip_addr_t;
typedef struct ip_addr_packed ip_addr_p_t;
/*
* struct ipaddr2 is used in the definition of the ARP packet format in
* order to support compilers that don't have structure packing.
@ -68,59 +80,109 @@ PACK_STRUCT_END
# include "arch/epstruct.h"
#endif
/* Forward declaration to not include netif.h */
struct netif;
extern const struct ip_addr ip_addr_any;
extern const struct ip_addr ip_addr_broadcast;
extern const ip_addr_t ip_addr_any;
extern const ip_addr_t ip_addr_broadcast;
/** IP_ADDR_ can be used as a fixed IP address
* for the wildcard and the broadcast address
*/
#define IP_ADDR_ANY ((struct ip_addr *)&ip_addr_any)
#define IP_ADDR_BROADCAST ((struct ip_addr *)&ip_addr_broadcast)
#define IP_ADDR_ANY ((ip_addr_t *)&ip_addr_any)
#define IP_ADDR_BROADCAST ((ip_addr_t *)&ip_addr_broadcast)
/** 255.255.255.255 */
#define IPADDR_NONE ((u32_t)0xffffffffUL)
/** 127.0.0.1 */
#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL)
/** 0.0.0.0 */
#define IPADDR_ANY ((u32_t)0x00000000UL)
/** 255.255.255.255 */
#define IPADDR_BROADCAST ((u32_t)0xffffffffUL)
/* Definitions of the bits in an Internet address integer.
On subnets, host and network parts are found according to
the subnet mask, not these masks. */
#define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0)
#define IP_CLASSA_NET 0xff000000
#define IP_CLASSA_NSHIFT 24
#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET)
#define IP_CLASSA_MAX 128
#define IN_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0)
#define IN_CLASSA_NET 0xff000000
#define IN_CLASSA_NSHIFT 24
#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET)
#define IN_CLASSA_MAX 128
#define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL)
#define IP_CLASSB_NET 0xffff0000
#define IP_CLASSB_NSHIFT 16
#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET)
#define IP_CLASSB_MAX 65536
#define IN_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL)
#define IN_CLASSB_NET 0xffff0000
#define IN_CLASSB_NSHIFT 16
#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET)
#define IN_CLASSB_MAX 65536
#define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)
#define IP_CLASSC_NET 0xffffff00
#define IP_CLASSC_NSHIFT 8
#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET)
#define IN_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)
#define IN_CLASSC_NET 0xffffff00
#define IN_CLASSC_NSHIFT 8
#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET)
#define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL)
#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */
#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */
#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */
#define IP_MULTICAST(a) IP_CLASSD(a)
#define IN_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL)
#define IN_CLASSD_NET 0xf0000000 /* These ones aren't really */
#define IN_CLASSD_NSHIFT 28 /* net and host fields, but */
#define IN_CLASSD_HOST 0x0fffffff /* routing needn't know. */
#define IN_MULTICAST(a) IN_CLASSD(a)
#define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
#define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
#define IN_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
#define IN_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
#define IP_LOOPBACKNET 127 /* official! */
#define IN_LOOPBACKNET 127 /* official! */
#if BYTE_ORDER == BIG_ENDIAN
/** Set an IP address given by the four byte-parts */
#define IP4_ADDR(ipaddr, a,b,c,d) \
(ipaddr)->addr = htonl(((u32_t)((a) & 0xff) << 24) | \
((u32_t)((b) & 0xff) << 16) | \
((u32_t)((c) & 0xff) << 8) | \
(u32_t)((d) & 0xff))
(ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \
((u32_t)((b) & 0xff) << 16) | \
((u32_t)((c) & 0xff) << 8) | \
(u32_t)((d) & 0xff)
#else
/** Set an IP address given by the four byte-parts.
Little-endian version that prevents the use of htonl. */
#define IP4_ADDR(ipaddr, a,b,c,d) \
(ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \
((u32_t)((c) & 0xff) << 16) | \
((u32_t)((b) & 0xff) << 8) | \
(u32_t)((a) & 0xff)
#endif
/** MEMCPY-like copying of IP addresses where addresses are known to be
* 16-bit-aligned if the port is correctly configured (so a port could define
* this to copying 2 u16_t's) - no NULL-pointer-checking needed. */
#ifndef IPADDR2_COPY
#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip_addr_t))
#endif
/** Copy IP address - faster than ip_addr_set: no NULL check */
#define ip_addr_copy(dest, src) ((dest).addr = (src).addr)
/** Safely copy one IP address to another (src may be NULL) */
#define ip_addr_set(dest, src) ((dest)->addr = \
((src) == NULL ? 0 : \
(src)->addr))
/** Set complete address to zero */
#define ip_addr_set_zero(ipaddr) ((ipaddr)->addr = 0)
/** Set address to IPADDR_ANY (no need for htonl()) */
#define ip_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY)
/** Set address to loopback address */
#define ip_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK))
/** Safely copy one IP address to another and change byte order
* from host- to network-order. */
#define ip_addr_set_hton(dest, src) ((dest)->addr = \
((src) == NULL ? 0:\
htonl((src)->addr)))
/** IPv4 only: set the IP address given as an u32_t */
#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32))
/** IPv4 only: get the IP address as an u32_t */
#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr)
/** Get the network address by combining host address with netmask */
#define ip_addr_get_network(target, host, netmask) ((target)->addr = ((host)->addr) & ((netmask)->addr))
#define ip_addr_set(dest, src) (dest)->addr = \
((src) == NULL? 0:\
(src)->addr)
/**
* Determine if two address are on the same network.
*
@ -135,36 +197,45 @@ extern const struct ip_addr ip_addr_broadcast;
(mask)->addr))
#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)
#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0)
#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == IPADDR_ANY)
u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *);
#define ip_addr_isbroadcast(ipaddr, netif) ip4_addr_isbroadcast((ipaddr)->addr, (netif))
u8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif);
#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000UL)) == ntohl(0xe0000000UL))
#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr)
u8_t ip4_addr_netmask_valid(u32_t netmask);
#define ip_addr_islinklocal(addr1) (((addr1)->addr & ntohl(0xffff0000UL)) == ntohl(0xa9fe0000UL))
#define ip_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL))
#define ip_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL))
#define ip_addr_debug_print(debug, ipaddr) \
LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \
ipaddr != NULL ? \
(u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0, \
ipaddr != NULL ? \
(u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0, \
ipaddr != NULL ? \
(u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0, \
ipaddr != NULL ? \
(u16_t)ntohl((ipaddr)->addr) & 0xff : 0))
LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \
ipaddr != NULL ? ip4_addr1_16(ipaddr) : 0, \
ipaddr != NULL ? ip4_addr2_16(ipaddr) : 0, \
ipaddr != NULL ? ip4_addr3_16(ipaddr) : 0, \
ipaddr != NULL ? ip4_addr4_16(ipaddr) : 0))
/* Get one byte from the 4-byte address */
#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0])
#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1])
#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2])
#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3])
/* These are cast to u16_t, with the intent that they are often arguments
* to printf using the U16_F format from cc.h. */
#define ip4_addr1(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff)
#define ip4_addr2(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff)
#define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff)
#define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff)
#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr))
#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr))
#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr))
#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr))
/**
* Same as inet_ntoa() but takes a struct ip_addr*
*/
#define ip_ntoa(addr) ((addr != NULL) ? inet_ntoa(*((struct in_addr*)(addr))) : "NULL")
/** For backwards compatibility */
#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr)
u32_t ipaddr_addr(const char *cp);
int ipaddr_aton(const char *cp, ip_addr_t *addr);
/** returns ptr to static buffer; not reentrant! */
char *ipaddr_ntoa(const ip_addr_t *addr);
char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen);
#ifdef __cplusplus
}

View file

@ -66,7 +66,19 @@ struct pbuf * ip_reass(struct pbuf *p);
#endif /* IP_REASSEMBLY */
#if IP_FRAG
err_t ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest);
#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
/** A custom pbuf that holds a reference to another pbuf, which is freed
* when this custom pbuf is freed. This is used to create a custom PBUF_REF
* that points into the original pbuf. */
struct pbuf_custom_ref {
/** 'base class' */
struct pbuf_custom pc;
/** pointer to the original pbuf that is referenced */
struct pbuf *original;
};
#endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest);
#endif /* IP_FRAG */
#ifdef __cplusplus

View file

@ -51,16 +51,35 @@ extern "C" {
* the same byte order as in the corresponding pcb.
*/
/* Flags for netconn_write */
#define NETCONN_NOFLAG 0x00
#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */
#define NETCONN_COPY 0x01
#define NETCONN_MORE 0x02
/* Flags for netconn_write (u8_t) */
#define NETCONN_NOFLAG 0x00
#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */
#define NETCONN_COPY 0x01
#define NETCONN_MORE 0x02
#define NETCONN_DONTBLOCK 0x04
/* Flags for struct netconn.flags (u8_t) */
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
this temporarily stores whether to wake up the original application task
if data couldn't be sent in the first try. */
#define NETCONN_FLAG_WRITE_DELAYED 0x01
/** Should this netconn avoid blocking? */
#define NETCONN_FLAG_NON_BLOCKING 0x02
/** Was the last connect action a non-blocking one? */
#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04
/** If this is set, a TCP netconn must call netconn_recved() to update
the TCP receive window (done automatically if not set). */
#define NETCONN_FLAG_NO_AUTO_RECVED 0x08
/** If a nonblocking write has been rejected before, poll_tcp needs to
check if the netconn is writable again */
#define NETCONN_FLAG_CHECK_WRITESPACE 0x10
/* Helpers to process several netconn_types by the same code */
#define NETCONNTYPE_GROUP(t) (t&0xF0)
#define NETCONNTYPE_DATAGRAM(t) (t&0xE0)
/** Protocol family and type of the netconn */
enum netconn_type {
NETCONN_INVALID = 0,
/* NETCONN_TCP Group */
@ -73,6 +92,8 @@ enum netconn_type {
NETCONN_RAW = 0x40
};
/** Current state of the netconn. Non-TCP netconns are always
* in state NETCONN_NONE! */
enum netconn_state {
NETCONN_NONE,
NETCONN_WRITE,
@ -81,14 +102,17 @@ enum netconn_state {
NETCONN_CLOSE
};
/** Use to inform the callback function about changes */
enum netconn_evt {
NETCONN_EVT_RCVPLUS,
NETCONN_EVT_RCVMINUS,
NETCONN_EVT_SENDPLUS,
NETCONN_EVT_SENDMINUS
NETCONN_EVT_SENDMINUS,
NETCONN_EVT_ERROR
};
#if LWIP_IGMP
/** Used for netconn_join_leave_group() */
enum netconn_igmp {
NETCONN_JOIN,
NETCONN_LEAVE
@ -101,6 +125,7 @@ struct tcp_pcb;
struct udp_pcb;
struct raw_pcb;
struct netconn;
struct api_msg_msg;
/** A callback prototype to inform about events for a netconn */
typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len);
@ -119,99 +144,136 @@ struct netconn {
struct raw_pcb *raw;
} pcb;
/** the last error this netconn had */
err_t err;
err_t last_err;
/** sem that is used to synchroneously execute functions in the core context */
sys_sem_t op_completed;
/** mbox where received packets are stored until they are fetched
by the netconn application thread (can grow quite big) */
sys_mbox_t recvmbox;
#if LWIP_TCP
/** mbox where new connections are stored until processed
by the application thread */
sys_mbox_t acceptmbox;
#endif /* LWIP_TCP */
/** only used for socket layer */
#if LWIP_SOCKET
int socket;
#endif /* LWIP_SOCKET */
#if LWIP_SO_RCVTIMEO
/** timeout to wait for new data to be received
(or connections to arrive for listening netconns) */
int recv_timeout;
#endif /* LWIP_SO_RCVTIMEO */
#if LWIP_SO_RCVBUF
/** maximum amount of bytes queued in recvmbox */
/** maximum amount of bytes queued in recvmbox
not used for TCP: adjust TCP_WND instead! */
int recv_bufsize;
#endif /* LWIP_SO_RCVBUF */
/** number of bytes currently in recvmbox to be received,
tested against recv_bufsize to limit bytes on recvmbox
for UDP and RAW, used for FIONREAD */
s16_t recv_avail;
#endif /* LWIP_SO_RCVBUF */
/** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */
u8_t flags;
#if LWIP_TCP
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
this temporarily stores the message. */
struct api_msg_msg *write_msg;
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
this temporarily stores how much is already sent. */
size_t write_offset;
#if LWIP_TCPIP_CORE_LOCKING
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
this temporarily stores whether to wake up the original application task
if data couldn't be sent in the first try. */
u8_t write_delayed;
#endif /* LWIP_TCPIP_CORE_LOCKING */
this temporarily stores the message.
Also used during connect and close. */
struct api_msg_msg *current_msg;
#endif /* LWIP_TCP */
/** A callback function that is informed about events for this netconn */
netconn_callback callback;
};
/* Register an Network connection event */
/** Register an Network connection event */
#define API_EVENT(c,e,l) if (c->callback) { \
(*c->callback)(c, e, l); \
}
/** Set conn->last_err to err but don't overwrite fatal errors */
#define NETCONN_SET_SAFE_ERR(conn, err) do { \
SYS_ARCH_DECL_PROTECT(lev); \
SYS_ARCH_PROTECT(lev); \
if (!ERR_IS_FATAL((conn)->last_err)) { \
(conn)->last_err = err; \
} \
SYS_ARCH_UNPROTECT(lev); \
} while(0);
/* Network connection functions: */
#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL)
#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c)
struct
netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,
netconn_callback callback);
err_t netconn_delete (struct netconn *conn);
netconn_callback callback);
err_t netconn_delete(struct netconn *conn);
/** Get the type of a netconn (as enum netconn_type). */
#define netconn_type(conn) (conn->type)
err_t netconn_getaddr (struct netconn *conn,
struct ip_addr *addr,
u16_t *port,
u8_t local);
err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr,
u16_t *port, u8_t local);
#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0)
#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1)
err_t netconn_bind (struct netconn *conn,
struct ip_addr *addr,
u16_t port);
err_t netconn_connect (struct netconn *conn,
struct ip_addr *addr,
u16_t port);
err_t netconn_disconnect (struct netconn *conn);
err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);
err_t netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port);
err_t netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port);
err_t netconn_disconnect (struct netconn *conn);
err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);
#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG)
struct netconn * netconn_accept (struct netconn *conn);
struct netbuf * netconn_recv (struct netconn *conn);
err_t netconn_sendto (struct netconn *conn,
struct netbuf *buf, struct ip_addr *addr, u16_t port);
err_t netconn_send (struct netconn *conn,
struct netbuf *buf);
err_t netconn_write (struct netconn *conn,
const void *dataptr, size_t size,
u8_t apiflags);
err_t netconn_close (struct netconn *conn);
err_t netconn_accept(struct netconn *conn, struct netconn **new_conn);
err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf);
err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf);
void netconn_recved(struct netconn *conn, u32_t length);
err_t netconn_sendto(struct netconn *conn, struct netbuf *buf,
ip_addr_t *addr, u16_t port);
err_t netconn_send(struct netconn *conn, struct netbuf *buf);
err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size,
u8_t apiflags);
err_t netconn_close(struct netconn *conn);
err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx);
#if LWIP_IGMP
err_t netconn_join_leave_group (struct netconn *conn,
struct ip_addr *multiaddr,
struct ip_addr *interface,
enum netconn_igmp join_or_leave);
err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr,
ip_addr_t *netif_addr, enum netconn_igmp join_or_leave);
#endif /* LWIP_IGMP */
#if LWIP_DNS
err_t netconn_gethostbyname(const char *name, struct ip_addr *addr);
err_t netconn_gethostbyname(const char *name, ip_addr_t *addr);
#endif /* LWIP_DNS */
#define netconn_err(conn) ((conn)->err)
#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize)
#define netconn_err(conn) ((conn)->last_err)
#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize)
/** Set the blocking status of netconn calls (@todo: write/send is missing) */
#define netconn_set_nonblocking(conn, val) do { if(val) { \
(conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \
} else { \
(conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0)
/** Get the blocking status of netconn calls (@todo: write/send is missing) */
#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0)
/** TCP: Set the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
#define netconn_set_noautorecved(conn, val) do { if(val) { \
(conn)->flags |= NETCONN_FLAG_NO_AUTO_RECVED; \
} else { \
(conn)->flags &= ~ NETCONN_FLAG_NO_AUTO_RECVED; }} while(0)
/** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
#define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0)
#if LWIP_SO_RCVTIMEO
/** Set the receive timeout in milliseconds */
#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout))
/** Get the receive timeout in milliseconds */
#define netconn_get_recvtimeout(conn) ((conn)->recv_timeout)
#endif /* LWIP_SO_RCVTIMEO */
#if LWIP_SO_RCVBUF
/** Set the receive buffer in bytes */
#define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize))
/** Get the receive buffer in bytes */
#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize)
#endif /* LWIP_SO_RCVBUF*/
#ifdef __cplusplus
}

View file

@ -48,6 +48,11 @@
extern "C" {
#endif
/* For the netconn API, these values are use as a bitmask! */
#define NETCONN_SHUT_RD 1
#define NETCONN_SHUT_WR 2
#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR)
/* IP addresses and port numbers are expected to be in
* the same byte order as in the corresponding pcb.
*/
@ -58,6 +63,8 @@ struct api_msg_msg {
/** The netconn which to process - always needed: it includes the semaphore
which is used to block the application thread until the function finished. */
struct netconn *conn;
/** The return value of the function executed in tcpip_thread. */
err_t err;
/** Depending on the executed function, one of these union members is used */
union {
/** used for do_send */
@ -68,12 +75,12 @@ struct api_msg_msg {
} n;
/** used for do_bind and do_connect */
struct {
struct ip_addr *ipaddr;
ip_addr_t *ipaddr;
u16_t port;
} bc;
/** used for do_getaddr */
struct {
struct ip_addr *ipaddr;
ip_addr_t *ipaddr;
u16_t *port;
u8_t local;
} ad;
@ -85,13 +92,17 @@ struct api_msg_msg {
} w;
/** used for do_recv */
struct {
u16_t len;
u32_t len;
} r;
/** used for do_close (/shutdown) */
struct {
u8_t shut;
} sd;
#if LWIP_IGMP
/** used for do_join_leave_group */
struct {
struct ip_addr *multiaddr;
struct ip_addr *interface;
ip_addr_t *multiaddr;
ip_addr_t *netif_addr;
enum netconn_igmp join_or_leave;
} jl;
#endif /* LWIP_IGMP */
@ -122,10 +133,10 @@ struct dns_api_msg {
/** Hostname to query or dotted IP address string */
const char *name;
/** Rhe resolved address is stored here */
struct ip_addr *addr;
ip_addr_t *addr;
/** This semaphore is posted when the name is resolved, the application thread
should wait on it. */
sys_sem_t sem;
sys_sem_t *sem;
/** Errors are given back here */
err_t *err;
};
@ -142,6 +153,7 @@ void do_recv ( struct api_msg_msg *msg);
void do_write ( struct api_msg_msg *msg);
void do_getaddr ( struct api_msg_msg *msg);
void do_close ( struct api_msg_msg *msg);
void do_shutdown ( struct api_msg_msg *msg);
#if LWIP_IGMP
void do_join_leave_group( struct api_msg_msg *msg);
#endif /* LWIP_IGMP */

View file

@ -46,6 +46,11 @@
#ifndef SZT_F
#define SZT_F U32_F
#endif /* SZT_F */
/** Temporary upgrade helper: define format string for u8_t as hex if not
defined in cc.h */
#ifndef X8_F
#define X8_F "02x"
#endif /* X8_F */
#ifdef __cplusplus
extern "C" {
@ -71,154 +76,154 @@ extern "C" {
#ifdef LWIP_PROVIDE_ERRNO
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Arg list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Arg list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define EDEADLOCK EDEADLK
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale NFS file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale NFS file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#define ENSROK 0 /* DNS server returned answer with no data */
#define ENSRNODATA 160 /* DNS server returned answer with no data */
#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
#define ENSRSERVFAIL 162 /* DNS server returned general failure */
#define ENSRNOTFOUND 163 /* Domain name not found */
#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */
#define ENSRREFUSED 165 /* DNS server refused query */
#define ENSRBADQUERY 166 /* Misformatted DNS query */
#define ENSRBADNAME 167 /* Misformatted domain name */
#define ENSRBADFAMILY 168 /* Unsupported address family */
#define ENSRBADRESP 169 /* Misformatted DNS reply */
#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
#define ENSROF 172 /* End of file */
#define ENSRFILE 173 /* Error reading file */
#define ENSRNOMEM 174 /* Out of memory */
#define ENSRDESTRUCTION 175 /* Application terminated lookup */
#define ENSROK 0 /* DNS server returned answer with no data */
#define ENSRNODATA 160 /* DNS server returned answer with no data */
#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
#define ENSRSERVFAIL 162 /* DNS server returned general failure */
#define ENSRNOTFOUND 163 /* Domain name not found */
#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */
#define ENSRREFUSED 165 /* DNS server refused query */
#define ENSRBADQUERY 166 /* Misformatted DNS query */
#define ENSRBADNAME 167 /* Misformatted domain name */
#define ENSRBADFAMILY 168 /* Unsupported address family */
#define ENSRBADRESP 169 /* Misformatted DNS reply */
#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
#define ENSROF 172 /* End of file */
#define ENSRFILE 173 /* Error reading file */
#define ENSRNOMEM 174 /* Out of memory */
#define ENSRDESTRUCTION 175 /* Application terminated lookup */
#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */
#define ENSRCNAMELOOP 177 /* Domain name is too long */
#define ENSRCNAMELOOP 177 /* Domain name is too long */
#ifndef errno
extern int errno;

View file

@ -32,8 +32,13 @@
#ifndef __LWIP_DEF_H__
#define __LWIP_DEF_H__
/* this might define NULL already */
/* arch.h might define NULL already */
#include "lwip/arch.h"
#include "lwip/opt.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y))
#define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y))
@ -42,6 +47,81 @@
#define NULL ((void *)0)
#endif
/** Get the absolute difference between 2 u32_t values (correcting overflows)
* 'a' is expected to be 'higher' (without overflow) than 'b'. */
#define LWIP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))
/* Endianess-optimized shifting of two u8_t to create one u16_t */
#if BYTE_ORDER == LITTLE_ENDIAN
#define LWIP_MAKE_U16(a, b) ((a << 8) | b)
#else
#define LWIP_MAKE_U16(a, b) ((b << 8) | a)
#endif
#ifndef LWIP_PLATFORM_BYTESWAP
#define LWIP_PLATFORM_BYTESWAP 0
#endif
#ifndef LWIP_PREFIX_BYTEORDER_FUNCS
/* workaround for naming collisions on some platforms */
#ifdef htons
#undef htons
#endif /* htons */
#ifdef htonl
#undef htonl
#endif /* htonl */
#ifdef ntohs
#undef ntohs
#endif /* ntohs */
#ifdef ntohl
#undef ntohl
#endif /* ntohl */
#define htons(x) lwip_htons(x)
#define ntohs(x) lwip_ntohs(x)
#define htonl(x) lwip_htonl(x)
#define ntohl(x) lwip_ntohl(x)
#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */
#if BYTE_ORDER == BIG_ENDIAN
#define lwip_htons(x) (x)
#define lwip_ntohs(x) (x)
#define lwip_htonl(x) (x)
#define lwip_ntohl(x) (x)
#define PP_HTONS(x) (x)
#define PP_NTOHS(x) (x)
#define PP_HTONL(x) (x)
#define PP_NTOHL(x) (x)
#else /* BYTE_ORDER != BIG_ENDIAN */
#if LWIP_PLATFORM_BYTESWAP
#define lwip_htons(x) LWIP_PLATFORM_HTONS(x)
#define lwip_ntohs(x) LWIP_PLATFORM_HTONS(x)
#define lwip_htonl(x) LWIP_PLATFORM_HTONL(x)
#define lwip_ntohl(x) LWIP_PLATFORM_HTONL(x)
#else /* LWIP_PLATFORM_BYTESWAP */
u16_t lwip_htons(u16_t x);
u16_t lwip_ntohs(u16_t x);
u32_t lwip_htonl(u32_t x);
u32_t lwip_ntohl(u32_t x);
#endif /* LWIP_PLATFORM_BYTESWAP */
/* These macros should be calculated by the preprocessor and are used
with compile-time constants only (so that there is no little-endian
overhead at runtime). */
#define PP_HTONS(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
#define PP_NTOHS(x) PP_HTONS(x)
#define PP_HTONL(x) ((((x) & 0xff) << 24) | \
(((x) & 0xff00) << 8) | \
(((x) & 0xff0000UL) >> 8) | \
(((x) & 0xff000000UL) >> 24))
#define PP_NTOHL(x) PP_HTONL(x)
#endif /* BYTE_ORDER == BIG_ENDIAN */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_DEF_H__ */

View file

@ -22,6 +22,10 @@ extern "C" {
/** period (in milliseconds) of the application calling dhcp_fine_tmr() */
#define DHCP_FINE_TIMER_MSECS 500
#define DHCP_CHADDR_LEN 16U
#define DHCP_SNAME_LEN 64U
#define DHCP_FILE_LEN 128U
struct dhcp
{
/** transaction identifier of last sent request */
@ -30,14 +34,14 @@ struct dhcp
struct udp_pcb *pcb;
/** incoming msg */
struct dhcp_msg *msg_in;
/** incoming msg options */
void *options_in;
/** ingoing msg options length */
u16_t options_in_len;
/** current DHCP state machine state */
u8_t state;
/** retries of current request */
u8_t tries;
#if LWIP_DHCP_AUTOIP_COOP
u8_t autoip_coop_state;
#endif
u8_t subnet_mask_given;
struct pbuf *p_out; /* pbuf of outcoming msg */
struct dhcp_msg *msg_out; /* outgoing msg */
@ -45,28 +49,20 @@ struct dhcp
u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */
u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */
u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */
struct ip_addr server_ip_addr; /* dhcp server address that offered this lease */
struct ip_addr offered_ip_addr;
struct ip_addr offered_sn_mask;
struct ip_addr offered_gw_addr;
struct ip_addr offered_bc_addr;
#define DHCP_MAX_DNS 2
u32_t dns_count; /* actual number of DNS servers obtained */
struct ip_addr offered_dns_addr[DHCP_MAX_DNS]; /* DNS server addresses */
ip_addr_t server_ip_addr; /* dhcp server address that offered this lease */
ip_addr_t offered_ip_addr;
ip_addr_t offered_sn_mask;
ip_addr_t offered_gw_addr;
u32_t offered_t0_lease; /* lease period (in seconds) */
u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */
u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */
#if LWIP_DHCP_AUTOIP_COOP
u8_t autoip_coop_state;
#endif
/** Patch #1308
* TODO: See dhcp.c "TODO"s
*/
#if 0
struct ip_addr offered_si_addr;
u8_t *boot_file_name;
#endif
/* @todo: LWIP_DHCP_BOOTP_FILE configuration option?
integrate with possible TFTP-client for booting? */
#if LWIP_DHCP_BOOTP_FILE
ip_addr_t offered_si_addr;
char boot_file_name[DHCP_FILE_LEN];
#endif /* LWIP_DHCP_BOOTPFILE */
};
/* MUST be compiled with "pack structs" or equivalent! */
@ -84,15 +80,12 @@ struct dhcp_msg
PACK_STRUCT_FIELD(u32_t xid);
PACK_STRUCT_FIELD(u16_t secs);
PACK_STRUCT_FIELD(u16_t flags);
PACK_STRUCT_FIELD(struct ip_addr ciaddr);
PACK_STRUCT_FIELD(struct ip_addr yiaddr);
PACK_STRUCT_FIELD(struct ip_addr siaddr);
PACK_STRUCT_FIELD(struct ip_addr giaddr);
#define DHCP_CHADDR_LEN 16U
PACK_STRUCT_FIELD(ip_addr_p_t ciaddr);
PACK_STRUCT_FIELD(ip_addr_p_t yiaddr);
PACK_STRUCT_FIELD(ip_addr_p_t siaddr);
PACK_STRUCT_FIELD(ip_addr_p_t giaddr);
PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);
#define DHCP_SNAME_LEN 64U
PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]);
#define DHCP_FILE_LEN 128U
PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);
PACK_STRUCT_FIELD(u32_t cookie);
#define DHCP_MIN_OPTIONS_LEN 68U
@ -112,6 +105,10 @@ PACK_STRUCT_END
# include "arch/epstruct.h"
#endif
void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp);
/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */
#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0)
void dhcp_cleanup(struct netif *netif);
/** start DHCP configuration */
err_t dhcp_start(struct netif *netif);
/** enforce early lease renewal (not needed normally)*/
@ -127,7 +124,7 @@ void dhcp_network_changed(struct netif *netif);
/** if enabled, check whether the offered IP address is not in use, using ARP */
#if DHCP_DOES_ARP_CHECK
void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr);
void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr);
#endif
/** to be called every minute */
@ -136,66 +133,66 @@ void dhcp_coarse_tmr(void);
void dhcp_fine_tmr(void);
/** DHCP message item offsets and length */
#define DHCP_MSG_OFS (UDP_DATA_OFS)
#define DHCP_OP_OFS (DHCP_MSG_OFS + 0)
#define DHCP_HTYPE_OFS (DHCP_MSG_OFS + 1)
#define DHCP_HLEN_OFS (DHCP_MSG_OFS + 2)
#define DHCP_HOPS_OFS (DHCP_MSG_OFS + 3)
#define DHCP_XID_OFS (DHCP_MSG_OFS + 4)
#define DHCP_SECS_OFS (DHCP_MSG_OFS + 8)
#define DHCP_FLAGS_OFS (DHCP_MSG_OFS + 10)
#define DHCP_CIADDR_OFS (DHCP_MSG_OFS + 12)
#define DHCP_YIADDR_OFS (DHCP_MSG_OFS + 16)
#define DHCP_SIADDR_OFS (DHCP_MSG_OFS + 20)
#define DHCP_GIADDR_OFS (DHCP_MSG_OFS + 24)
#define DHCP_CHADDR_OFS (DHCP_MSG_OFS + 28)
#define DHCP_SNAME_OFS (DHCP_MSG_OFS + 44)
#define DHCP_FILE_OFS (DHCP_MSG_OFS + 108)
#define DHCP_MSG_LEN 236
#define DHCP_OP_OFS 0
#define DHCP_HTYPE_OFS 1
#define DHCP_HLEN_OFS 2
#define DHCP_HOPS_OFS 3
#define DHCP_XID_OFS 4
#define DHCP_SECS_OFS 8
#define DHCP_FLAGS_OFS 10
#define DHCP_CIADDR_OFS 12
#define DHCP_YIADDR_OFS 16
#define DHCP_SIADDR_OFS 20
#define DHCP_GIADDR_OFS 24
#define DHCP_CHADDR_OFS 28
#define DHCP_SNAME_OFS 44
#define DHCP_FILE_OFS 108
#define DHCP_MSG_LEN 236
#define DHCP_COOKIE_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN)
#define DHCP_OPTIONS_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN + 4)
#define DHCP_COOKIE_OFS DHCP_MSG_LEN
#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4)
#define DHCP_CLIENT_PORT 68
#define DHCP_SERVER_PORT 67
#define DHCP_CLIENT_PORT 68
#define DHCP_SERVER_PORT 67
/** DHCP client states */
#define DHCP_REQUESTING 1
#define DHCP_INIT 2
#define DHCP_REBOOTING 3
#define DHCP_REBINDING 4
#define DHCP_RENEWING 5
#define DHCP_SELECTING 6
#define DHCP_INFORMING 7
#define DHCP_CHECKING 8
#define DHCP_PERMANENT 9
#define DHCP_BOUND 10
#define DHCP_OFF 0
#define DHCP_REQUESTING 1
#define DHCP_INIT 2
#define DHCP_REBOOTING 3
#define DHCP_REBINDING 4
#define DHCP_RENEWING 5
#define DHCP_SELECTING 6
#define DHCP_INFORMING 7
#define DHCP_CHECKING 8
#define DHCP_PERMANENT 9
#define DHCP_BOUND 10
/** not yet implemented #define DHCP_RELEASING 11 */
#define DHCP_BACKING_OFF 12
#define DHCP_OFF 13
#define DHCP_BACKING_OFF 12
/** AUTOIP cooperatation flags */
#define DHCP_AUTOIP_COOP_STATE_OFF 0
#define DHCP_AUTOIP_COOP_STATE_ON 1
#define DHCP_AUTOIP_COOP_STATE_OFF 0
#define DHCP_AUTOIP_COOP_STATE_ON 1
#define DHCP_BOOTREQUEST 1
#define DHCP_BOOTREPLY 2
#define DHCP_BOOTREQUEST 1
#define DHCP_BOOTREPLY 2
/** DHCP message types */
#define DHCP_DISCOVER 1
#define DHCP_OFFER 2
#define DHCP_REQUEST 3
#define DHCP_DECLINE 4
#define DHCP_ACK 5
#define DHCP_NAK 6
#define DHCP_RELEASE 7
#define DHCP_INFORM 8
#define DHCP_OFFER 2
#define DHCP_REQUEST 3
#define DHCP_DECLINE 4
#define DHCP_ACK 5
#define DHCP_NAK 6
#define DHCP_RELEASE 7
#define DHCP_INFORM 8
/** DHCP hardware type, currently only ethernet is supported */
#define DHCP_HTYPE_ETH 1
#define DHCP_HLEN_ETH 6
#define DHCP_MAGIC_COOKIE 0x63825363UL
#define DHCP_BROADCAST_FLAG 15
#define DHCP_BROADCAST_MASK (1 << DHCP_FLAG_BROADCAST)
/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */
/** BootP options */
#define DHCP_OPTION_PAD 0
@ -217,7 +214,6 @@ void dhcp_fine_tmr(void);
#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */
#define DHCP_OPTION_MESSAGE_TYPE_LEN 1
#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */
#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */

View file

@ -38,6 +38,10 @@
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
#ifdef __cplusplus
extern "C" {
#endif
/** DNS timer period */
#define DNS_TMR_INTERVAL 1000
@ -66,32 +70,55 @@
#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */
#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */
/* The size used for the next line is rather a hack, but it prevents including socket.h in all files
that include memp.h, and that would possibly break portability (since socket.h defines some types
and constants possibly already define by the OS).
Calculation rule:
sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */
#define NETDB_ELEM_SIZE (32 + 16 + DNS_MAX_NAME_LENGTH + 1)
#if DNS_LOCAL_HOSTLIST
/** struct used for local host-list */
struct local_hostlist_entry {
/** static hostname */
const char *name;
/** static host address in network byteorder */
ip_addr_t addr;
struct local_hostlist_entry *next;
};
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN
#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH
#endif
#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1))
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
#endif /* DNS_LOCAL_HOSTLIST */
/** Callback which is invoked when a hostname is found.
* A function of this type must be implemented by the application using the DNS resolver.
* @param name pointer to the name that was looked up.
* @param ipaddr pointer to a struct ip_addr containing the IP address of the hostname,
* @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname,
* or NULL if the name could not be found (or on any other error).
* @param callback_arg a user-specified callback argument passed to dns_gethostbyname
*/
typedef void (*dns_found_callback)(const char *name, struct ip_addr *ipaddr, void *callback_arg);
typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg);
void dns_init(void);
void dns_tmr(void);
void dns_setserver(u8_t numdns, struct ip_addr *dnsserver);
struct ip_addr dns_getserver(u8_t numdns);
err_t dns_gethostbyname(const char *hostname, struct ip_addr *addr,
void dns_setserver(u8_t numdns, ip_addr_t *dnsserver);
ip_addr_t dns_getserver(u8_t numdns);
err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr,
dns_found_callback found, void *callback_arg);
#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC
int dns_local_removehost(const char *hostname, const struct ip_addr *addr);
err_t dns_local_addhost(const char *hostname, const struct ip_addr *addr);
int dns_local_removehost(const char *hostname, const ip_addr_t *addr);
err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr);
#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_DNS */
#endif /* __LWIP_DNS_H__ */

View file

@ -44,7 +44,7 @@ extern "C" {
#ifdef LWIP_ERR_T
typedef LWIP_ERR_T err_t;
#else /* LWIP_ERR_T */
typedef s8_t err_t;
typedef s8_t err_t;
#endif /* LWIP_ERR_T*/
/* Definitions for error constants. */
@ -54,24 +54,22 @@ typedef LWIP_ERR_T err_t;
#define ERR_BUF -2 /* Buffer error. */
#define ERR_TIMEOUT -3 /* Timeout. */
#define ERR_RTE -4 /* Routing problem. */
#define ERR_INPROGRESS -5 /* Operation in progress */
#define ERR_VAL -6 /* Illegal value. */
#define ERR_WOULDBLOCK -7 /* Operation would block. */
#define ERR_USE -8 /* Address in use. */
#define ERR_ISCONN -9 /* Already connected. */
#define ERR_IS_FATAL(e) ((e) < ERR_RTE)
#define ERR_IS_FATAL(e) ((e) < ERR_ISCONN)
#define ERR_ABRT -5 /* Connection aborted. */
#define ERR_RST -6 /* Connection reset. */
#define ERR_CLSD -7 /* Connection closed. */
#define ERR_CONN -8 /* Not connected. */
#define ERR_ABRT -10 /* Connection aborted. */
#define ERR_RST -11 /* Connection reset. */
#define ERR_CLSD -12 /* Connection closed. */
#define ERR_CONN -13 /* Not connected. */
#define ERR_VAL -9 /* Illegal value. */
#define ERR_ARG -14 /* Illegal argument. */
#define ERR_ARG -10 /* Illegal argument. */
#define ERR_USE -11 /* Address in use. */
#define ERR_IF -12 /* Low-level netif error */
#define ERR_ISCONN -13 /* Already connected. */
#define ERR_INPROGRESS -14 /* Operation in progress */
#define ERR_IF -15 /* Low-level netif error */
#ifdef LWIP_DEBUG

View file

@ -41,9 +41,9 @@ extern "C" {
/** X.x.x: Major version of the stack */
#define LWIP_VERSION_MAJOR 1U
/** x.X.x: Minor version of the stack */
#define LWIP_VERSION_MINOR 3U
#define LWIP_VERSION_MINOR 4U
/** x.x.X: Revision of the stack */
#define LWIP_VERSION_REVISION 2U
#define LWIP_VERSION_REVISION 0U
/** For release candidates, this is set to 1..254
* For official releases, this is set to 255 (LWIP_RC_RELEASE)
* For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */

View file

@ -58,44 +58,59 @@ typedef size_t mem_size_t;
#ifndef mem_calloc
#define mem_calloc calloc
#endif
#ifndef mem_realloc
static void *mem_realloc(void *mem, mem_size_t size)
{
LWIP_UNUSED_ARG(size);
return mem;
}
/* Since there is no C library allocation function to shrink memory without
moving it, define this to nothing. */
#ifndef mem_trim
#define mem_trim(mem, size) (mem)
#endif
#else /* MEM_LIBC_MALLOC */
/* MEM_SIZE would have to be aligned, but using 64000 here instead of
* 65535 leaves some room for alignment...
*/
#if MEM_SIZE > 64000l
#if MEM_SIZE > 64000L
typedef u32_t mem_size_t;
#define MEM_SIZE_F U32_F
#else
typedef u16_t mem_size_t;
#define MEM_SIZE_F U16_F
#endif /* MEM_SIZE > 64000 */
#if MEM_USE_POOLS
/** mem_init is not used when using pools instead of a heap */
#define mem_init()
/** mem_realloc is not used when using pools instead of a heap:
/** mem_trim is not used when using pools instead of a heap:
we can't free part of a pool element and don't want to copy the rest */
#define mem_realloc(mem, size) (mem)
#define mem_trim(mem, size) (mem)
#else /* MEM_USE_POOLS */
/* lwIP alternative malloc */
void mem_init(void);
void *mem_realloc(void *mem, mem_size_t size);
void *mem_trim(void *mem, mem_size_t size);
#endif /* MEM_USE_POOLS */
void *mem_malloc(mem_size_t size);
void *mem_calloc(mem_size_t count, mem_size_t size);
void mem_free(void *mem);
#endif /* MEM_LIBC_MALLOC */
/** Calculate memory size for an aligned buffer - returns the next highest
* multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and
* LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4).
*/
#ifndef LWIP_MEM_ALIGN_SIZE
#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))
#endif
/** Calculate safe memory size for an aligned buffer when using an unaligned
* type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the
* start (e.g. if buffer is u8_t[] and actual data will be u32_t*)
*/
#ifndef LWIP_MEM_ALIGN_BUFFER
#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1))
#endif
/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT
* so that ADDR % MEM_ALIGNMENT == 0
*/
#ifndef LWIP_MEM_ALIGN
#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1)))
#endif

View file

@ -47,6 +47,9 @@ LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg),
#if IP_REASSEMBLY
LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA")
#endif /* IP_REASSEMBLY */
#if IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF")
#endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
#if LWIP_NETCONN
LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF")
@ -55,7 +58,9 @@ LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn),
#if NO_SYS==0
LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API")
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT")
#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
#endif /* NO_SYS==0 */
#if ARP_QUEUEING
@ -66,10 +71,25 @@ LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_en
LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP")
#endif /* LWIP_IGMP */
#if NO_SYS==0
#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */
LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT")
#endif /* NO_SYS==0 */
#endif /* LWIP_TIMERS */
#if LWIP_SNMP
LWIP_MEMPOOL(SNMP_ROOTNODE, MEMP_NUM_SNMP_ROOTNODE, sizeof(struct mib_list_rootnode), "SNMP_ROOTNODE")
LWIP_MEMPOOL(SNMP_NODE, MEMP_NUM_SNMP_NODE, sizeof(struct mib_list_node), "SNMP_NODE")
LWIP_MEMPOOL(SNMP_VARBIND, MEMP_NUM_SNMP_VARBIND, sizeof(struct snmp_varbind), "SNMP_VARBIND")
LWIP_MEMPOOL(SNMP_VALUE, MEMP_NUM_SNMP_VALUE, SNMP_MAX_VALUE_SIZE, "SNMP_VALUE")
#endif /* LWIP_SNMP */
#if LWIP_DNS && LWIP_SOCKET
LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB")
#endif /* LWIP_DNS && LWIP_SOCKET */
#if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC
LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST")
#endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
#if PPP_SUPPORT && PPPOE_SUPPORT
LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF")
#endif /* PPP_SUPPORT && PPPOE_SUPPORT */
/*
* A list of pools of pbuf's used by LWIP.

View file

@ -40,14 +40,24 @@
extern "C" {
#endif
/** This netbuf has dest-addr/port set */
#define NETBUF_FLAG_DESTADDR 0x01
/** This netbuf includes a checksum */
#define NETBUF_FLAG_CHKSUM 0x02
struct netbuf {
struct pbuf *p, *ptr;
struct ip_addr *addr;
ip_addr_t addr;
u16_t port;
#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
#if LWIP_CHECKSUM_ON_COPY
u8_t flags;
#endif /* LWIP_CHECKSUM_ON_COPY */
u16_t toport_chksum;
#if LWIP_NETBUF_RECVINFO
struct ip_addr *toaddr;
u16_t toport;
ip_addr_t toaddr;
#endif /* LWIP_NETBUF_RECVINFO */
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
};
/* Network buffer functions: */
@ -56,13 +66,12 @@ void netbuf_delete (struct netbuf *buf);
void * netbuf_alloc (struct netbuf *buf, u16_t size);
void netbuf_free (struct netbuf *buf);
err_t netbuf_ref (struct netbuf *buf,
const void *dataptr, u16_t size);
const void *dataptr, u16_t size);
void netbuf_chain (struct netbuf *head,
struct netbuf *tail);
u16_t netbuf_len (struct netbuf *buf);
err_t netbuf_data (struct netbuf *buf,
void **dataptr, u16_t *len);
void **dataptr, u16_t *len);
s8_t netbuf_next (struct netbuf *buf);
void netbuf_first (struct netbuf *buf);
@ -72,12 +81,18 @@ void netbuf_first (struct netbuf *buf);
#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0)
#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len)
#define netbuf_len(buf) ((buf)->p->tot_len)
#define netbuf_fromaddr(buf) ((buf)->addr)
#define netbuf_fromaddr(buf) (&((buf)->addr))
#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set((&(buf)->addr), fromaddr)
#define netbuf_fromport(buf) ((buf)->port)
#if LWIP_NETBUF_RECVINFO
#define netbuf_destaddr(buf) ((buf)->toaddr)
#define netbuf_destport(buf) ((buf)->toport)
#define netbuf_destaddr(buf) (&((buf)->toaddr))
#define netbuf_set_destaddr(buf, destaddr) ip_addr_set((&(buf)->addr), destaddr)
#define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0)
#endif /* LWIP_NETBUF_RECVINFO */
#if LWIP_CHECKSUM_ON_COPY
#define netbuf_set_chksum(buf, chksum) do { (buf)->flags = NETBUF_FLAG_CHKSUM; \
(buf)->toport_chksum = chksum; } while(0)
#endif /* LWIP_CHECKSUM_ON_COPY */
#ifdef __cplusplus
}

View file

@ -26,6 +26,8 @@
* Author: Simon Goldschmidt
*
*/
#ifndef __LWIP_NETDB_H__
#define __LWIP_NETDB_H__
#include "lwip/opt.h"
@ -33,8 +35,13 @@
#include <stddef.h> /* for size_t */
#include "lwip/inet.h"
#include "lwip/sockets.h"
#ifdef __cplusplus
extern "C" {
#endif
/* some rarely used options */
#ifndef LWIP_DNS_API_DECLARE_H_ERRNO
#define LWIP_DNS_API_DECLARE_H_ERRNO 1
@ -108,4 +115,10 @@ int lwip_getaddrinfo(const char *nodename,
lwip_getaddrinfo(nodname, servname, hints, res)
#endif /* LWIP_COMPAT_SOCKETS */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_DNS && LWIP_SOCKET */
#endif /* __LWIP_NETDB_H__ */

View file

@ -40,7 +40,7 @@
#include "lwip/ip_addr.h"
#include "lwip/inet.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#if LWIP_DHCP
struct dhcp;
@ -60,61 +60,108 @@ extern "C" {
across all types of interfaces in use */
#define NETIF_MAX_HWADDR_LEN 6U
/** TODO: define the use (where, when, whom) of netif flags */
/** whether the network interface is 'up'. this is
/** Whether the network interface is 'up'. This is
* a software flag used to control whether this network
* interface is enabled and processes traffic.
* It is set by the startup code (for static IP configuration) or
* by dhcp/autoip when an address has been assigned.
*/
#define NETIF_FLAG_UP 0x01U
/** if set, the netif has broadcast capability */
/** If set, the netif has broadcast capability.
* Set by the netif driver in its init function. */
#define NETIF_FLAG_BROADCAST 0x02U
/** if set, the netif is one end of a point-to-point connection */
/** If set, the netif is one end of a point-to-point connection.
* Set by the netif driver in its init function. */
#define NETIF_FLAG_POINTTOPOINT 0x04U
/** if set, the interface is configured using DHCP */
/** If set, the interface is configured using DHCP.
* Set by the DHCP code when starting or stopping DHCP. */
#define NETIF_FLAG_DHCP 0x08U
/** if set, the interface has an active link
* (set by the network interface driver) */
/** If set, the interface has an active link
* (set by the network interface driver).
* Either set by the netif driver in its init function (if the link
* is up at that time) or at a later point once the link comes up
* (if link detection is supported by the hardware). */
#define NETIF_FLAG_LINK_UP 0x10U
/** if set, the netif is an device using ARP */
/** If set, the netif is an ethernet device using ARP.
* Set by the netif driver in its init function.
* Used to check input packet types and use of DHCP. */
#define NETIF_FLAG_ETHARP 0x20U
/** if set, the netif has IGMP capability */
#define NETIF_FLAG_IGMP 0x40U
/** If set, the netif is an ethernet device. It might not use
* ARP or TCP/IP if it is used for PPPoE only.
*/
#define NETIF_FLAG_ETHERNET 0x40U
/** If set, the netif has IGMP capability.
* Set by the netif driver in its init function. */
#define NETIF_FLAG_IGMP 0x80U
/** Function prototype for netif init functions. Set up flags and output/linkoutput
* callback functions in this function.
*
* @param netif The netif to initialize
*/
typedef err_t (*netif_init_fn)(struct netif *netif);
/** Function prototype for netif->input functions. This function is saved as 'input'
* callback function in the netif struct. Call it when a packet has been received.
*
* @param p The received packet, copied into a pbuf
* @param inp The netif which received the packet
*/
typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp);
/** Function prototype for netif->output functions. Called by lwIP when a packet
* shall be sent. For ethernet netif, set this to 'etharp_output' and set
* 'linkoutput'.
*
* @param netif The netif which shall send a packet
* @param p The packet to send (p->payload points to IP header)
* @param ipaddr The IP address to which the packet shall be sent
*/
typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p,
ip_addr_t *ipaddr);
/** Function prototype for netif->linkoutput functions. Only used for ethernet
* netifs. This function is called by ARP when a packet shall be sent.
*
* @param netif The netif which shall send a packet
* @param p The packet to send (raw ethernet packet)
*/
typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p);
/** Function prototype for netif status- or link-callback functions. */
typedef void (*netif_status_callback_fn)(struct netif *netif);
/** Function prototype for netif igmp_mac_filter functions */
typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif,
ip_addr_t *group, u8_t action);
/** Generic data structure used for all lwIP network interfaces.
* The following fields should be filled in by the initialization
* function for the device driver: hwaddr_len, hwaddr[], mtu, flags */
struct netif {
/** pointer to next in linked list */
struct netif *next;
/** IP address configuration in network byte order */
struct ip_addr ip_addr;
struct ip_addr netmask;
struct ip_addr gw;
ip_addr_t ip_addr;
ip_addr_t netmask;
ip_addr_t gw;
/** This function is called by the network device driver
* to pass a packet up the TCP/IP stack. */
err_t (* input)(struct pbuf *p, struct netif *inp);
netif_input_fn input;
/** This function is called by the IP module when it wants
* to send a packet on the interface. This function typically
* first resolves the hardware address, then sends the packet. */
err_t (* output)(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr);
netif_output_fn output;
/** This function is called by the ARP module when it wants
* to send a packet on the interface. This function outputs
* the pbuf as-is on the link medium. */
err_t (* linkoutput)(struct netif *netif, struct pbuf *p);
netif_linkoutput_fn linkoutput;
#if LWIP_NETIF_STATUS_CALLBACK
/** This function is called when the netif state is set to up or down
*/
void (* status_callback)(struct netif *netif);
netif_status_callback_fn status_callback;
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_LINK_CALLBACK
/** This function is called when the netif link is set to up or down
*/
void (* link_callback)(struct netif *netif);
netif_status_callback_fn link_callback;
#endif /* LWIP_NETIF_LINK_CALLBACK */
/** This field can be set by the device driver and could point
* to state information for the device. */
@ -161,8 +208,9 @@ struct netif {
u32_t ifoutdiscards;
#endif /* LWIP_SNMP */
#if LWIP_IGMP
/* This function could be called to add or delete a entry in the multicast filter table of the ethernet MAC.*/
err_t (*igmp_mac_filter)( struct netif *netif, struct ip_addr *group, u8_t action);
/** This function could be called to add or delete a entry in the multicast
filter table of the ethernet MAC.*/
netif_igmp_mac_filter_fn igmp_mac_filter;
#endif /* LWIP_IGMP */
#if LWIP_NETIF_HWADDRHINT
u8_t *addr_hint;
@ -180,18 +228,18 @@ struct netif {
#if LWIP_SNMP
#define NETIF_INIT_SNMP(netif, type, speed) \
/* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \
netif->link_type = type; \
(netif)->link_type = (type); \
/* your link speed here (units: bits per second) */ \
netif->link_speed = speed; \
netif->ts = 0; \
netif->ifinoctets = 0; \
netif->ifinucastpkts = 0; \
netif->ifinnucastpkts = 0; \
netif->ifindiscards = 0; \
netif->ifoutoctets = 0; \
netif->ifoutucastpkts = 0; \
netif->ifoutnucastpkts = 0; \
netif->ifoutdiscards = 0
(netif)->link_speed = (speed); \
(netif)->ts = 0; \
(netif)->ifinoctets = 0; \
(netif)->ifinucastpkts = 0; \
(netif)->ifinnucastpkts = 0; \
(netif)->ifindiscards = 0; \
(netif)->ifoutoctets = 0; \
(netif)->ifoutucastpkts = 0; \
(netif)->ifoutnucastpkts = 0; \
(netif)->ifoutdiscards = 0
#else /* LWIP_SNMP */
#define NETIF_INIT_SNMP(netif, type, speed)
#endif /* LWIP_SNMP */
@ -202,17 +250,14 @@ extern struct netif *netif_list;
/** The default network interface. */
extern struct netif *netif_default;
#define netif_init() /* Compatibility define, not init needed. */
void netif_init(void);
struct netif *netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
struct ip_addr *gw,
void *state,
err_t (* init)(struct netif *netif),
err_t (* input)(struct pbuf *p, struct netif *netif));
struct netif *netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input);
void
netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask,
struct ip_addr *gw);
netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
ip_addr_t *gw);
void netif_remove(struct netif * netif);
/* Returns a network interface given its name. The name is of the form
@ -223,41 +268,48 @@ struct netif *netif_find(char *name);
void netif_set_default(struct netif *netif);
void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr);
void netif_set_netmask(struct netif *netif, struct ip_addr *netmask);
void netif_set_gw(struct netif *netif, struct ip_addr *gw);
void netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr);
void netif_set_netmask(struct netif *netif, ip_addr_t *netmask);
void netif_set_gw(struct netif *netif, ip_addr_t *gw);
void netif_set_up(struct netif *netif);
void netif_set_down(struct netif *netif);
u8_t netif_is_up(struct netif *netif);
/** Ask if an interface is up */
#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0)
#if LWIP_NETIF_STATUS_CALLBACK
/*
* Set callback to be called when interface is brought up/down
*/
void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif));
void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback);
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_LINK_CALLBACK
void netif_set_link_up(struct netif *netif);
void netif_set_link_down(struct netif *netif);
u8_t netif_is_link_up(struct netif *netif);
/*
* Set callback to be called when link is brought up/down
*/
void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif));
/** Ask if a link is up */
#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0)
#if LWIP_NETIF_LINK_CALLBACK
void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback);
#endif /* LWIP_NETIF_LINK_CALLBACK */
#ifdef __cplusplus
}
#endif
#if LWIP_NETIF_HOSTNAME
#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0)
#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL)
#endif /* LWIP_NETIF_HOSTNAME */
#if LWIP_IGMP
#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0)
#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL)
#endif /* LWIP_IGMP */
#if ENABLE_LOOPBACK
err_t netif_loop_output(struct netif *netif, struct pbuf *p, struct ip_addr *dest_ip);
err_t netif_loop_output(struct netif *netif, struct pbuf *p, ip_addr_t *dest_ip);
void netif_poll(struct netif *netif);
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
void netif_poll_all(void);
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
#endif /* ENABLE_LOOPBACK */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_NETIF_H__ */

View file

@ -41,6 +41,9 @@
extern "C" {
#endif
typedef void (*netifapi_void_fn)(struct netif *netif);
typedef err_t (*netifapi_errt_fn)(struct netif *netif);
struct netifapi_msg_msg {
#if !LWIP_TCPIP_CORE_LOCKING
sys_sem_t sem;
@ -49,16 +52,16 @@ struct netifapi_msg_msg {
struct netif *netif;
union {
struct {
struct ip_addr *ipaddr;
struct ip_addr *netmask;
struct ip_addr *gw;
ip_addr_t *ipaddr;
ip_addr_t *netmask;
ip_addr_t *gw;
void *state;
err_t (* init) (struct netif *netif);
err_t (* input)(struct pbuf *p, struct netif *netif);
netif_init_fn init;
netif_input_fn input;
} add;
struct {
void (* voidfunc)(struct netif *netif);
err_t (* errtfunc)(struct netif *netif);
netifapi_void_fn voidfunc;
netifapi_errt_fn errtfunc;
} common;
} msg;
};
@ -71,21 +74,21 @@ struct netifapi_msg {
/* API for application */
err_t netifapi_netif_add ( struct netif *netif,
struct ip_addr *ipaddr,
struct ip_addr *netmask,
struct ip_addr *gw,
ip_addr_t *ipaddr,
ip_addr_t *netmask,
ip_addr_t *gw,
void *state,
err_t (* init)(struct netif *netif),
err_t (* input)(struct pbuf *p, struct netif *netif) );
netif_init_fn init,
netif_input_fn input);
err_t netifapi_netif_set_addr ( struct netif *netif,
struct ip_addr *ipaddr,
struct ip_addr *netmask,
struct ip_addr *gw );
ip_addr_t *ipaddr,
ip_addr_t *netmask,
ip_addr_t *gw );
err_t netifapi_netif_common ( struct netif *netif,
void (* voidfunc)(struct netif *netif),
err_t (* errtfunc)(struct netif *netif) );
netifapi_void_fn voidfunc,
netifapi_errt_fn errtfunc);
#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL)
#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL)

View file

@ -68,6 +68,14 @@
#define NO_SYS 0
#endif
/**
* NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1
* Mainly for compatibility to old versions.
*/
#ifndef NO_SYS_NO_TIMERS
#define NO_SYS_NO_TIMERS 0
#endif
/**
* MEMCPY: override this if you have a faster implementation at hand than the
* one included in your C library
@ -124,6 +132,15 @@
#define MEM_SIZE 1600
#endif
/**
* MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array.
* This can be used to individually change the location of each pool.
* Default is one big array for all pools
*/
#ifndef MEMP_SEPARATE_POOLS
#define MEMP_SEPARATE_POOLS 0
#endif
/**
* MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable
* amount of bytes before and after each memp element in every pool and fills
@ -251,13 +268,24 @@
#endif
/**
* MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for
* MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for
* reassembly (whole packets, not fragments!)
*/
#ifndef MEMP_NUM_REASSDATA
#define MEMP_NUM_REASSDATA 5
#endif
/**
* MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent
* (fragments, not whole packets!).
* This is only used with IP_FRAG_USES_STATIC_BUF==0 and
* LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs
* where the packet is not yet sent when netif->output returns.
*/
#ifndef MEMP_NUM_FRAG_PBUF
#define MEMP_NUM_FRAG_PBUF 15
#endif
/**
* MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing
* packets (pbufs) that are waiting for an ARP request (to resolve
@ -320,6 +348,63 @@
#define MEMP_NUM_TCPIP_MSG_INPKT 8
#endif
/**
* MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree.
*/
#ifndef MEMP_NUM_SNMP_NODE
#define MEMP_NUM_SNMP_NODE 50
#endif
/**
* MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree.
* Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least!
*/
#ifndef MEMP_NUM_SNMP_ROOTNODE
#define MEMP_NUM_SNMP_ROOTNODE 30
#endif
/**
* MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to
* be changed normally) - 2 of these are used per request (1 for input,
* 1 for output)
*/
#ifndef MEMP_NUM_SNMP_VARBIND
#define MEMP_NUM_SNMP_VARBIND 2
#endif
/**
* MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used
* (does not have to be changed normally) - 3 of these are used per request
* (1 for the value read and 2 for OIDs - input and output)
*/
#ifndef MEMP_NUM_SNMP_VALUE
#define MEMP_NUM_SNMP_VALUE 3
#endif
/**
* MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls
* (before freeing the corresponding memory using lwip_freeaddrinfo()).
*/
#ifndef MEMP_NUM_NETDB
#define MEMP_NUM_NETDB 1
#endif
/**
* MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list
* if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1.
*/
#ifndef MEMP_NUM_LOCALHOSTLIST
#define MEMP_NUM_LOCALHOSTLIST 1
#endif
/**
* MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE
* interfaces (only used with PPPOE_SUPPORT==1)
*/
#ifndef MEMP_NUM_PPPOE_INTERFACES
#define MEMP_NUM_PPPOE_INTERFACES 1
#endif
/**
* PBUF_POOL_SIZE: the number of buffers in the pbuf pool.
*/
@ -347,11 +432,14 @@
#endif
/**
* ARP_QUEUEING==1: Outgoing packets are queued during hardware address
* resolution.
* ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address
* resolution. By default, only the most recent packet is queued per IP address.
* This is sufficient for most protocols and mainly reduces TCP connection
* startup time. Set this to 1 if you know your application sends more than one
* packet in a row to an IP address that is not in the ARP cache.
*/
#ifndef ARP_QUEUEING
#define ARP_QUEUEING 1
#define ARP_QUEUEING 0
#endif
/**
@ -361,9 +449,11 @@
* correct addresses, or as a limited approach to attempt to handle
* spoofing. If disabled, lwIP will need to make a new ARP request if
* the peer is not already in the ARP table, adding a little latency.
* The peer *is* in the ARP table if it requested our address before.
* Also notice that this slows down input processing of every IP packet!
*/
#ifndef ETHARP_TRUST_IP_MAC
#define ETHARP_TRUST_IP_MAC 1
#define ETHARP_TRUST_IP_MAC 0
#endif
/**
@ -376,6 +466,30 @@
#define ETHARP_SUPPORT_VLAN 0
#endif
/** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP
* might be disabled
*/
#ifndef LWIP_ETHERNET
#define LWIP_ETHERNET (LWIP_ARP || PPPOE_SUPPORT)
#endif
/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure
* alignment of payload after that header. Since the header is 14 bytes long,
* without this padding e.g. addresses in the IP header will not be aligned
* on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms.
*/
#ifndef ETH_PAD_SIZE
#define ETH_PAD_SIZE 0
#endif
/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table
* entries (using etharp_add_static_entry/etharp_remove_static_entry).
*/
#ifndef ETHARP_SUPPORT_STATIC_ENTRIES
#define ETHARP_SUPPORT_STATIC_ENTRIES 0
#endif
/*
--------------------------------
---------- IP options ----------
@ -439,10 +553,12 @@
/**
* IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP
* fragmentation. Otherwise pbufs are allocated and reference the original
* packet data to be fragmented.
* packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1,
* new PBUF_RAM pbufs are used for fragments).
* ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs!
*/
#ifndef IP_FRAG_USES_STATIC_BUF
#define IP_FRAG_USES_STATIC_BUF 1
#define IP_FRAG_USES_STATIC_BUF 0
#endif
/**
@ -595,7 +711,8 @@
/**
* SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will
* allow. At least one request buffer is required.
* allow. At least one request buffer is required.
* Does not have to be changed unless external MIBs answer request asynchronously
*/
#ifndef SNMP_CONCURRENT_REQUESTS
#define SNMP_CONCURRENT_REQUESTS 1
@ -611,6 +728,8 @@
/**
* SNMP_PRIVATE_MIB:
* When using a private MIB, you have to create a file 'private_mib.h' that contains
* a 'struct mib_array_node mib_private' which contains your MIB.
*/
#ifndef SNMP_PRIVATE_MIB
#define SNMP_PRIVATE_MIB 0
@ -625,6 +744,31 @@
#define SNMP_SAFE_REQUESTS 1
#endif
/**
* The maximum length of strings used. This affects the size of
* MEMP_SNMP_VALUE elements.
*/
#ifndef SNMP_MAX_OCTET_STRING_LEN
#define SNMP_MAX_OCTET_STRING_LEN 127
#endif
/**
* The maximum depth of the SNMP tree.
* With private MIBs enabled, this depends on your MIB!
* This affects the size of MEMP_SNMP_VALUE elements.
*/
#ifndef SNMP_MAX_TREE_DEPTH
#define SNMP_MAX_TREE_DEPTH 15
#endif
/**
* The size of the MEMP_SNMP_VALUE elements, normally calculated from
* SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH.
*/
#ifndef SNMP_MAX_VALUE_SIZE
#define SNMP_MAX_VALUE_SIZE LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH))
#endif
/*
----------------------------------
---------- IGMP options ----------
@ -670,13 +814,6 @@
#define DNS_DOES_NAME_CHECK 1
#endif
/** DNS use a local buffer if DNS_USES_STATIC_BUF=0, a static one if
DNS_USES_STATIC_BUF=1, or a dynamic one if DNS_USES_STATIC_BUF=2.
The buffer will be of size DNS_MSG_SIZE */
#ifndef DNS_USES_STATIC_BUF
#define DNS_USES_STATIC_BUF 1
#endif
/** DNS message max. size. Default value is RFC compliant. */
#ifndef DNS_MSG_SIZE
#define DNS_MSG_SIZE 512
@ -820,18 +957,27 @@
* as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work.
*/
#ifndef TCP_SND_QUEUELEN
#define TCP_SND_QUEUELEN (4 * (TCP_SND_BUF)/(TCP_MSS))
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS))
#endif
/**
* TCP_SNDLOWAT: TCP writable space (bytes). This must be less than or equal
* to TCP_SND_BUF. It is the amount of space which must be available in the
* TCP snd_buf for select to return writable.
* TCP_SNDLOWAT: TCP writable space (bytes). This must be less than
* TCP_SND_BUF. It is the amount of space which must be available in the
* TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT).
*/
#ifndef TCP_SNDLOWAT
#define TCP_SNDLOWAT ((TCP_SND_BUF)/2)
#endif
/**
* TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater
* than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below
* this number, select returns writable (combined with TCP_SNDLOWAT).
*/
#ifndef TCP_SNDQUEUELOWAT
#define TCP_SNDQUEUELOWAT ((TCP_SND_QUEUELEN)/2)
#endif
/**
* TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb.
*/
@ -848,6 +994,24 @@
#define TCP_DEFAULT_LISTEN_BACKLOG 0xff
#endif
/**
* TCP_OVERSIZE: The maximum number of bytes that tcp_write may
* allocate ahead of time in an attempt to create shorter pbuf chains
* for transmission. The meaningful range is 0 to TCP_MSS. Some
* suggested values are:
*
* 0: Disable oversized allocation. Each tcp_write() allocates a new
pbuf (old behaviour).
* 1: Allocate size-aligned pbufs with minimal excess. Use this if your
* scatter-gather DMA requires aligned fragments.
* 128: Limit the pbuf/memory overhead to 20%.
* TCP_MSS: Try to create unfragmented TCP packets.
* TCP_MSS/4: Try to create 4 fragments or less per TCP packet.
*/
#ifndef TCP_OVERSIZE
#define TCP_OVERSIZE TCP_MSS
#endif
/**
* LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option.
*/
@ -890,7 +1054,7 @@
* Ethernet.
*/
#ifndef PBUF_LINK_HLEN
#define PBUF_LINK_HLEN 14
#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE)
#endif
/**
@ -1084,14 +1248,14 @@
#endif
/**
* PPP_THREAD_NAME: The name assigned to the pppMain thread.
* PPP_THREAD_NAME: The name assigned to the pppInputThread.
*/
#ifndef PPP_THREAD_NAME
#define PPP_THREAD_NAME "pppMain"
#define PPP_THREAD_NAME "pppInputThread"
#endif
/**
* PPP_THREAD_STACKSIZE: The stack size used by the pppMain thread.
* PPP_THREAD_STACKSIZE: The stack size used by the pppInputThread.
* The stack size value itself is platform-dependent, but is passed to
* sys_thread_new() when the thread is created.
*/
@ -1100,7 +1264,7 @@
#endif
/**
* PPP_THREAD_PRIO: The priority assigned to the pppMain thread.
* PPP_THREAD_PRIO: The priority assigned to the pppInputThread.
* The priority value itself is platform-dependent, but is passed to
* sys_thread_new() when the thread is created.
*/
@ -1182,6 +1346,14 @@
#define LWIP_TCPIP_CORE_LOCKING 0
#endif
/**
* LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!)
* Don't use it if you're not an active lwIP project member
*/
#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT
#define LWIP_TCPIP_CORE_LOCKING_INPUT 0
#endif
/**
* LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)
*/
@ -1189,6 +1361,13 @@
#define LWIP_NETCONN 1
#endif
/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create
* timers running in tcpip_thread from another thread.
*/
#ifndef LWIP_TCPIP_TIMEOUT
#define LWIP_TCPIP_TIMEOUT 1
#endif
/*
------------------------------------
---------- Socket options ----------
@ -1249,12 +1428,21 @@
#endif
/**
* SO_REUSE==1: Enable SO_REUSEADDR and SO_REUSEPORT options. DO NOT USE!
* SO_REUSE==1: Enable SO_REUSEADDR option.
*/
#ifndef SO_REUSE
#define SO_REUSE 0
#endif
/**
* SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets
* to all local matches if SO_REUSEADDR is turned on.
* WARNING: Adds a memcpy for every packet if passing to more than one pcb!
*/
#ifndef SO_REUSE_RXTOALL
#define SO_REUSE_RXTOALL 0
#endif
/*
----------------------------------------
---------- Statistics options ----------
@ -1583,6 +1771,14 @@
#define CHECKSUM_CHECK_TCP 1
#endif
/**
* LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from
* application buffers to pbufs.
*/
#ifndef LWIP_CHECKSUM_ON_COPY
#define LWIP_CHECKSUM_ON_COPY 0
#endif
/*
---------------------------------------
---------- Debugging options ----------
@ -1710,6 +1906,13 @@
#define SYS_DEBUG LWIP_DBG_OFF
#endif
/**
* TIMERS_DEBUG: Enable debugging in timers.c.
*/
#ifndef TIMERS_DEBUG
#define TIMERS_DEBUG LWIP_DBG_OFF
#endif
/**
* TCP_DEBUG: Enable debugging for TCP.
*/

View file

@ -40,6 +40,10 @@
extern "C" {
#endif
/** Currently, the pbuf_custom code is only needed for one specific configuration
* of IP_FRAG */
#define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF)
#define PBUF_TRANSPORT_HLEN 20
#define PBUF_IP_HLEN 20
@ -59,7 +63,12 @@ typedef enum {
/** indicates this packet's data should be immediately passed to the application */
#define PBUF_FLAG_PUSH 0x01U
#define PBUF_FLAG_PUSH 0x01U
/** indicates this is a custom pbuf: pbuf_free and pbuf_header handle such a
a pbuf differently */
#define PBUF_FLAG_IS_CUSTOM 0x02U
/** indicates this pbuf is UDP multicast to be looped back */
#define PBUF_FLAG_MCASTLOOP 0x04U
struct pbuf {
/** next pbuf in singly linked pbuf chain */
@ -67,7 +76,7 @@ struct pbuf {
/** pointer to the actual data in the buffer */
void *payload;
/**
* total length of this buffer and all next buffers in chain
* belonging to the same packet.
@ -76,9 +85,9 @@ struct pbuf {
* p->tot_len == p->len + (p->next? p->next->tot_len: 0)
*/
u16_t tot_len;
/** length of this buffer */
u16_t len;
u16_t len;
/** pbuf_type as u8_t instead of enum to save space */
u8_t /*pbuf_type*/ type;
@ -92,17 +101,33 @@ struct pbuf {
* the stack itself, or pbuf->next pointers from a chain.
*/
u16_t ref;
};
#if LWIP_SUPPORT_CUSTOM_PBUF
/** Prototype for a function to free a custom pbuf */
typedef void (*pbuf_free_custom_fn)(struct pbuf *p);
/** A custom pbuf: like a pbuf, but following a function pointer to free it. */
struct pbuf_custom {
/** The actual pbuf */
struct pbuf pbuf;
/** This function is called when pbuf_free deallocates this pbuf(_custom) */
pbuf_free_custom_fn custom_free_function;
};
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
/* Initializes the pbuf module. This call is empty for now, but may not be in future. */
#define pbuf_init()
struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_type type);
struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type);
#if LWIP_SUPPORT_CUSTOM_PBUF
struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type,
struct pbuf_custom *p, void *payload_mem,
u16_t payload_mem_len);
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
void pbuf_realloc(struct pbuf *p, u16_t size);
u8_t pbuf_header(struct pbuf *p, s16_t header_size);
void pbuf_ref(struct pbuf *p);
void pbuf_ref_chain(struct pbuf *p);
u8_t pbuf_free(struct pbuf *p);
u8_t pbuf_clen(struct pbuf *p);
void pbuf_cat(struct pbuf *head, struct pbuf *tail);
@ -112,6 +137,15 @@ err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from);
u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset);
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len);
struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer);
#if LWIP_CHECKSUM_ON_COPY
err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
u16_t len, u16_t *chksum);
#endif /* LWIP_CHECKSUM_ON_COPY */
u8_t pbuf_get_at(struct pbuf* p, u16_t offset);
u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n);
u16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset);
u16_t pbuf_strstr(struct pbuf* p, const char* substr);
#ifdef __cplusplus
}

View file

@ -37,7 +37,7 @@
#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
#include "lwip/pbuf.h"
#include "lwip/inet.h"
#include "lwip/def.h"
#include "lwip/ip.h"
#include "lwip/ip_addr.h"
@ -45,26 +45,31 @@
extern "C" {
#endif
struct raw_pcb;
/** Function prototype for raw pcb receive callback functions.
* @param arg user supplied argument (raw_pcb.recv_arg)
* @param pcb the raw_pcb which received data
* @param p the packet buffer that was received
* @param addr the remote IP address from which the packet was received
* @return 1 if the packet was 'eaten' (aka. deleted),
* 0 if the packet lives on
* If returning 1, the callback is responsible for freeing the pbuf
* if it's not used any more.
*/
typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
ip_addr_t *addr);
struct raw_pcb {
/* Common members of all PCB types */
/* Common members of all PCB types */
IP_PCB;
struct raw_pcb *next;
u8_t protocol;
/* receive callback function
* @param arg user supplied argument (raw_pcb.recv_arg)
* @param pcb the raw_pcb which received data
* @param p the packet buffer that was received
* @param addr the remote IP address from which the packet was received
* @return 1 if the packet was 'eaten' (aka. deleted),
* 0 if the packet lives on
* If returning 1, the callback is responsible for freeing the pbuf
* if it's not used any more.
*/
u8_t (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
struct ip_addr *addr);
/** receive callback function */
raw_recv_fn recv;
/* user-supplied argument for the recv callback */
void *recv_arg;
};
@ -73,15 +78,11 @@ struct raw_pcb {
RAW code. */
struct raw_pcb * raw_new (u8_t proto);
void raw_remove (struct raw_pcb *pcb);
err_t raw_bind (struct raw_pcb *pcb, struct ip_addr *ipaddr);
err_t raw_connect (struct raw_pcb *pcb, struct ip_addr *ipaddr);
err_t raw_bind (struct raw_pcb *pcb, ip_addr_t *ipaddr);
err_t raw_connect (struct raw_pcb *pcb, ip_addr_t *ipaddr);
void raw_recv (struct raw_pcb *pcb,
u8_t (* recv)(void *arg, struct raw_pcb *pcb,
struct pbuf *p,
struct ip_addr *addr),
void *recv_arg);
err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr);
void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg);
err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr);
err_t raw_send (struct raw_pcb *pcb, struct pbuf *p);
/* The following functions are the lower layer interface to RAW. */

View file

@ -34,13 +34,16 @@
#define __LWIP_SNMP_H__
#include "lwip/opt.h"
#include "lwip/netif.h"
#include "lwip/udp.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "lwip/ip_addr.h"
struct udp_pcb;
struct netif;
/**
* @see RFC1213, "MIB-II, 6. Definitions"
*/
@ -118,8 +121,8 @@ void snmp_inc_iflist(void);
void snmp_dec_iflist(void);
/* ARP (for atTable and ipNetToMediaTable) */
void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip);
void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip);
void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip);
void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip);
/* IP */
void snmp_inc_ipinreceives(void);

View file

@ -46,12 +46,12 @@
extern "C" {
#endif
#define SNMP_ASN1_UNIV (!0x80 | !0x40)
#define SNMP_ASN1_APPLIC (!0x80 | 0x40)
#define SNMP_ASN1_CONTXT ( 0x80 | !0x40)
#define SNMP_ASN1_UNIV (0) /* (!0x80 | !0x40) */
#define SNMP_ASN1_APPLIC (0x40) /* (!0x80 | 0x40) */
#define SNMP_ASN1_CONTXT (0x80) /* ( 0x80 | !0x40) */
#define SNMP_ASN1_CONSTR (0x20)
#define SNMP_ASN1_PRIMIT (!0x20)
#define SNMP_ASN1_CONSTR (0x20) /* ( 0x20) */
#define SNMP_ASN1_PRIMIT (0) /* (!0x20) */
/* universal tags */
#define SNMP_ASN1_INTEG 2
@ -87,10 +87,10 @@ void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);
void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed);
err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type);
err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length);
err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value);
err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value);
err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value);
err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value);
err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident);
err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw);
err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw);
#ifdef __cplusplus
}

View file

@ -38,10 +38,14 @@
#include "lwip/opt.h"
#include "lwip/snmp.h"
#include "lwip/snmp_structs.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#if LWIP_SNMP
#if SNMP_PRIVATE_MIB
/* When using a private MIB, you have to create a file 'private_mib.h' that contains
* a 'struct mib_array_node mib_private' which contains your MIB. */
#include "private_mib.h"
#endif
@ -219,7 +223,7 @@ struct snmp_msg_pstat
/* lwIP local port (161) binding */
struct udp_pcb *pcb;
/* source IP address */
struct ip_addr sip;
ip_addr_t sip;
/* source UDP port */
u16_t sp;
/* request type */
@ -258,7 +262,7 @@ struct snmp_msg_trap
/* lwIP local port (161) binding */
struct udp_pcb *pcb;
/* destination IP address in network order */
struct ip_addr dip;
ip_addr_t dip;
/* source enterprise ID (sysObjectID) */
struct snmp_obj_id *enterprise;
@ -286,7 +290,7 @@ extern struct snmp_msg_trap trap_msg;
/** Agent setup, start listening to port 161. */
void snmp_init(void);
void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable);
void snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst);
void snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst);
/** Varbind-list functions. */
struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len);

View file

@ -44,6 +44,8 @@
#include "lwip/snmp.h"
#if SNMP_PRIVATE_MIB
/* When using a private MIB, you have to create a file 'private_mib.h' that contains
* a 'struct mib_array_node mib_private' which contains your MIB. */
#include "private_mib.h"
#endif
@ -56,11 +58,15 @@ extern "C" {
#define MIB_OBJECT_SCALAR 1
#define MIB_OBJECT_TAB 2
/* MIB access types */
#define MIB_ACCESS_READ 1
#define MIB_ACCESS_WRITE 2
/* MIB object access */
#define MIB_OBJECT_READ_ONLY 0
#define MIB_OBJECT_READ_WRITE 1
#define MIB_OBJECT_WRITE_ONLY 2
#define MIB_OBJECT_NOT_ACCESSIBLE 3
#define MIB_OBJECT_READ_ONLY MIB_ACCESS_READ
#define MIB_OBJECT_READ_WRITE (MIB_ACCESS_READ | MIB_ACCESS_WRITE)
#define MIB_OBJECT_WRITE_ONLY MIB_ACCESS_WRITE
#define MIB_OBJECT_NOT_ACCESSIBLE 0
/** object definition returned by (get_object_def)() */
struct obj_def
@ -109,9 +115,9 @@ struct mib_node
/** sets object value, only to be called when set_test() */
void (*set_value)(struct obj_def *od, u16_t len, void *value);
/** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */
const u8_t node_type;
u8_t node_type;
/* array or max list length */
const u16_t maxlength;
u16_t maxlength;
};
/** derived node for scalars .0 index */
@ -122,15 +128,15 @@ typedef struct mib_node mib_scalar_node;
struct mib_array_node
{
/* inherited "base class" members */
void (* const get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
void (* const get_value)(struct obj_def *od, u16_t len, void *value);
void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
void (*get_value)(struct obj_def *od, u16_t len, void *value);
u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
void (*set_value)(struct obj_def *od, u16_t len, void *value);
const u8_t node_type;
const u16_t maxlength;
u8_t node_type;
u16_t maxlength;
/* aditional struct members */
/* additional struct members */
const s32_t *objid;
struct mib_node* const *nptr;
};
@ -174,7 +180,7 @@ struct mib_list_rootnode
u8_t node_type;
u16_t maxlength;
/* aditional struct members */
/* additional struct members */
struct mib_list_node *head;
struct mib_list_node *tail;
/* counts list nodes in list */
@ -194,8 +200,8 @@ struct mib_external_node
u8_t node_type;
u16_t maxlength;
/* aditional struct members */
/** points to an extenal (in memory) record of some sort of addressing
/* additional struct members */
/** points to an external (in memory) record of some sort of addressing
information, passed to and interpreted by the funtions below */
void* addr_inf;
/** tree levels under this node */
@ -234,8 +240,8 @@ void noleafs_get_value(struct obj_def *od, u16_t len, void *value);
u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value);
void noleafs_set_value(struct obj_def *od, u16_t len, void *value);
void snmp_oidtoip(s32_t *ident, struct ip_addr *ip);
void snmp_iptooid(struct ip_addr *ip, s32_t *ident);
void snmp_oidtoip(s32_t *ident, ip_addr_t *ip);
void snmp_iptooid(ip_addr_t *ip, s32_t *ident);
void snmp_ifindextonetif(s32_t ifindex, struct netif **netif);
void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx);

View file

@ -72,11 +72,11 @@ struct sockaddr {
#define SOCK_RAW 3
/*
* Option flags per-socket. These must match the SOF_ flags in ip.h!
* Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c)
*/
#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */
#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
#define SO_REUSEADDR 0x0004 /* Unimplemented: allow local address reuse */
#define SO_REUSEADDR 0x0004 /* Allow local address reuse */
#define SO_KEEPALIVE 0x0008 /* keep connections alive */
#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */
#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
@ -262,9 +262,27 @@ typedef struct ip_mreq {
#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */
#endif
/* Socket flags: */
/* commands for fnctl */
#ifndef F_GETFL
#define F_GETFL 3
#endif
#ifndef F_SETFL
#define F_SETFL 4
#endif
/* File status flags and file access modes for fnctl,
these are bits in an int. */
#ifndef O_NONBLOCK
#define O_NONBLOCK 04000U
#define O_NONBLOCK 1 /* nonblocking I/O */
#endif
#ifndef O_NDELAY
#define O_NDELAY 1 /* same as O_NONBLOCK, for compatibility */
#endif
#ifndef SHUT_RD
#define SHUT_RD 0
#define SHUT_WR 1
#define SHUT_RDWR 2
#endif
/* FD_SET used for lwip_select */
@ -320,6 +338,7 @@ int lwip_write(int s, const void *dataptr, size_t size);
int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
struct timeval *timeout);
int lwip_ioctl(int s, long cmd, void *argp);
int lwip_fcntl(int s, int cmd, int val);
#if LWIP_COMPAT_SOCKETS
#define accept(a,b,c) lwip_accept(a,b,c)

View file

@ -71,18 +71,26 @@ struct stats_proto {
};
struct stats_igmp {
STAT_COUNTER lenerr; /* Invalid length error. */
STAT_COUNTER xmit; /* Transmitted packets. */
STAT_COUNTER recv; /* Received packets. */
STAT_COUNTER drop; /* Dropped packets. */
STAT_COUNTER chkerr; /* Checksum error. */
STAT_COUNTER v1_rxed; /* */
STAT_COUNTER join_sent; /* */
STAT_COUNTER leave_sent; /* */
STAT_COUNTER unicast_query; /* */
STAT_COUNTER report_sent; /* */
STAT_COUNTER report_rxed; /* */
STAT_COUNTER group_query_rxed; /* */
STAT_COUNTER lenerr; /* Invalid length error. */
STAT_COUNTER memerr; /* Out of memory error. */
STAT_COUNTER proterr; /* Protocol error. */
STAT_COUNTER rx_v1; /* Received v1 frames. */
STAT_COUNTER rx_group; /* Received group-specific queries. */
STAT_COUNTER rx_general; /* Received general queries. */
STAT_COUNTER rx_report; /* Received reports. */
STAT_COUNTER tx_join; /* Sent joins. */
STAT_COUNTER tx_leave; /* Sent leaves. */
STAT_COUNTER tx_report; /* Sent reports. */
};
struct stats_mem {
#ifdef LWIP_DEBUG
const char *name;
#endif /* LWIP_DEBUG */
mem_size_t avail;
mem_size_t used;
mem_size_t max;
@ -98,6 +106,7 @@ struct stats_syselem {
struct stats_sys {
struct stats_syselem sem;
struct stats_syselem mutex;
struct stats_syselem mbox;
};
@ -139,14 +148,20 @@ struct stats_ {
extern struct stats_ lwip_stats;
#define stats_init() /* Compatibility define, not init needed. */
void stats_init(void);
#define STATS_INC(x) ++lwip_stats.x
#define STATS_DEC(x) --lwip_stats.x
#else
#define STATS_INC_USED(x, y) do { lwip_stats.x.used += y; \
if (lwip_stats.x.max < lwip_stats.x.used) { \
lwip_stats.x.max = lwip_stats.x.used; \
} \
} while(0)
#else /* LWIP_STATS */
#define stats_init()
#define STATS_INC(x)
#define STATS_DEC(x)
#define STATS_INC_USED(x)
#endif /* LWIP_STATS */
#if TCP_STATS
@ -216,11 +231,7 @@ extern struct stats_ lwip_stats;
#if MEM_STATS
#define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y
#define MEM_STATS_INC(x) STATS_INC(mem.x)
#define MEM_STATS_INC_USED(x, y) do { lwip_stats.mem.used += y; \
if (lwip_stats.mem.max < lwip_stats.mem.used) { \
lwip_stats.mem.max = lwip_stats.mem.used; \
} \
} while(0)
#define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y)
#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y
#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP")
#else
@ -235,11 +246,7 @@ extern struct stats_ lwip_stats;
#define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y
#define MEMP_STATS_INC(x, i) STATS_INC(memp[i].x)
#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x)
#define MEMP_STATS_INC_USED(x, i) do { ++lwip_stats.memp[i].used; \
if (lwip_stats.memp[i].max < lwip_stats.memp[i].used) { \
lwip_stats.memp[i].max = lwip_stats.memp[i].used; \
} \
} while(0)
#define MEMP_STATS_INC_USED(x, i) STATS_INC_USED(memp[i], 1)
#define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i)
#else
#define MEMP_STATS_AVAIL(x, i, y)
@ -252,10 +259,12 @@ extern struct stats_ lwip_stats;
#if SYS_STATS
#define SYS_STATS_INC(x) STATS_INC(sys.x)
#define SYS_STATS_DEC(x) STATS_DEC(sys.x)
#define SYS_STATS_INC_USED(x) STATS_INC_USED(sys.x, 1)
#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys)
#else
#define SYS_STATS_INC(x)
#define SYS_STATS_DEC(x)
#define SYS_STATS_INC_USED(x)
#define SYS_STATS_DISPLAY()
#endif
@ -267,7 +276,7 @@ void stats_display_igmp(struct stats_igmp *igmp);
void stats_display_mem(struct stats_mem *mem, char *name);
void stats_display_memp(struct stats_mem *mem, int index);
void stats_display_sys(struct stats_sys *sys);
#else
#else /* LWIP_STATS_DISPLAY */
#define stats_display()
#define stats_display_proto(proto, name)
#define stats_display_igmp(igmp)

View file

@ -43,19 +43,19 @@ extern "C" {
/* For a totally minimal and standalone system, we provide null
definitions of the sys_ functions. */
typedef u8_t sys_sem_t;
typedef u8_t sys_mutex_t;
typedef u8_t sys_mbox_t;
struct sys_timeo {u8_t dummy;};
#define sys_init()
#define sys_timeout(m,h,a)
#define sys_untimeout(m,a)
#define sys_sem_new(c) c
#define sys_sem_new(s, c) ERR_OK
#define sys_sem_signal(s)
#define sys_sem_wait(s)
#define sys_sem_wait_timeout(s,t)
#define sys_arch_sem_wait(s,t)
#define sys_sem_free(s)
#define sys_mbox_new(s) 0
#define sys_mutex_new(mu) ERR_OK
#define sys_mutex_lock(mu)
#define sys_mutex_unlock(mu)
#define sys_mutex_free(mu)
#define sys_mbox_new(m, s) ERR_OK
#define sys_mbox_fetch(m,d)
#define sys_mbox_tryfetch(m,d)
#define sys_mbox_post(m,d)
@ -64,12 +64,14 @@ struct sys_timeo {u8_t dummy;};
#define sys_thread_new(n,t,a,s,p)
#define sys_msleep(t)
#else /* NO_SYS */
/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */
#define SYS_ARCH_TIMEOUT 0xffffffffUL
/* sys_mbox_tryfetch returns SYS_MBOX_EMPTY if appropriate.
/** sys_mbox_tryfetch() returns SYS_MBOX_EMPTY if appropriate.
* For now we use the same magic value, but we allow this to change in future.
*/
#define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT
@ -77,70 +79,156 @@ struct sys_timeo {u8_t dummy;};
#include "lwip/err.h"
#include "arch/sys_arch.h"
typedef void (* sys_timeout_handler)(void *arg);
/** Function prototype for thread functions */
typedef void (*lwip_thread_fn)(void *arg);
struct sys_timeo {
struct sys_timeo *next;
u32_t time;
sys_timeout_handler h;
void *arg;
};
/* Function prototypes for functions to be implemented by platform ports
(in sys_arch.c) */
struct sys_timeouts {
struct sys_timeo *next;
};
/* Mutex functions: */
/* sys_init() must be called before anthing else. */
void sys_init(void);
/** Define LWIP_COMPAT_MUTEX if the port has no mutexes and binary semaphores
should be used instead */
#if LWIP_COMPAT_MUTEX
/* for old ports that don't have mutexes: define them to binary semaphores */
#define sys_mutex_t sys_sem_t
#define sys_mutex_new(mutex) sys_sem_new(mutex, 1)
#define sys_mutex_lock(mutex) sys_sem_wait(mutex)
#define sys_mutex_unlock(mutex) sys_sem_signal(mutex)
#define sys_mutex_free(mutex) sys_sem_free(mutex)
#define sys_mutex_valid(mutex) sys_sem_valid(mutex)
#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex)
/*
* sys_timeout():
*
* Schedule a timeout a specified amount of milliseconds in the
* future. When the timeout occurs, the specified timeout handler will
* be called. The handler will be passed the "arg" argument when
* called.
*
*/
void sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg);
void sys_untimeout(sys_timeout_handler h, void *arg);
struct sys_timeouts *sys_arch_timeouts(void);
#else /* LWIP_COMPAT_MUTEX */
/* Semaphore functions. */
sys_sem_t sys_sem_new(u8_t count);
void sys_sem_signal(sys_sem_t sem);
u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout);
void sys_sem_free(sys_sem_t sem);
void sys_sem_wait(sys_sem_t sem);
int sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout);
/** Create a new mutex
* @param mutex pointer to the mutex to create
* @return a new mutex */
err_t sys_mutex_new(sys_mutex_t *mutex);
/** Lock a mutex
* @param mutex the mutex to lock */
void sys_mutex_lock(sys_mutex_t *mutex);
/** Unlock a mutex
* @param mutex the mutex to unlock */
void sys_mutex_unlock(sys_mutex_t *mutex);
/** Delete a semaphore
* @param mutex the mutex to delete */
void sys_mutex_free(sys_mutex_t *mutex);
#ifndef sys_mutex_valid
/** Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid */
int sys_mutex_valid(sys_mutex_t *mutex);
#endif
#ifndef sys_mutex_set_invalid
/** Set a mutex invalid so that sys_mutex_valid returns 0 */
void sys_mutex_set_invalid(sys_mutex_t *mutex);
#endif
#endif /* LWIP_COMPAT_MUTEX */
/* Semaphore functions: */
/** Create a new semaphore
* @param sem pointer to the semaphore to create
* @param count initial count of the semaphore
* @return ERR_OK if successful, another err_t otherwise */
err_t sys_sem_new(sys_sem_t *sem, u8_t count);
/** Signals a semaphore
* @param sem the semaphore to signal */
void sys_sem_signal(sys_sem_t *sem);
/** Wait for a semaphore for the specified timeout
* @param sem the semaphore to wait for
* @param timeout timeout in milliseconds to wait (0 = wait forever)
* @return time (in milliseconds) waited for the semaphore
* or SYS_ARCH_TIMEOUT on timeout */
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout);
/** Delete a semaphore
* @param sem semaphore to delete */
void sys_sem_free(sys_sem_t *sem);
/** Wait for a semaphore - forever/no timeout */
#define sys_sem_wait(sem) sys_arch_sem_wait(sem, 0)
#ifndef sys_sem_valid
/** Check if a sempahore is valid/allocated: return 1 for valid, 0 for invalid */
int sys_sem_valid(sys_sem_t *sem);
#endif
#ifndef sys_sem_set_invalid
/** Set a semaphore invalid so that sys_sem_valid returns 0 */
void sys_sem_set_invalid(sys_sem_t *sem);
#endif
/* Time functions. */
#ifndef sys_msleep
void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */
#endif
#ifndef sys_jiffies
u32_t sys_jiffies(void); /* since power up. */
#endif
/* Mailbox functions. */
sys_mbox_t sys_mbox_new(int size);
void sys_mbox_post(sys_mbox_t mbox, void *msg);
err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg);
u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout);
#ifndef sys_arch_mbox_tryfetch /* Allow port to override with a macro */
u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg);
#endif
/* For now, we map straight to sys_arch implementation. */
#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg)
void sys_mbox_free(sys_mbox_t mbox);
void sys_mbox_fetch(sys_mbox_t mbox, void **msg);
/* Thread functions. */
sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio);
/** Create a new mbox of specified size
* @param mbox pointer to the mbox to create
* @param size (miminum) number of messages in this mbox
* @return ERR_OK if successful, another err_t otherwise */
err_t sys_mbox_new(sys_mbox_t *mbox, int size);
/** Post a message to an mbox - may not fail
* -> blocks if full, only used from tasks not from ISR
* @param mbox mbox to posts the message
* @param msg message to post (ATTENTION: can be NULL) */
void sys_mbox_post(sys_mbox_t *mbox, void *msg);
/** Try to post a message to an mbox - may fail if full or ISR
* @param mbox mbox to posts the message
* @param msg message to post (ATTENTION: can be NULL) */
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg);
/** Wait for a new message to arrive in the mbox
* @param mbox mbox to get a message from
* @param msg pointer where the message is stored
* @param timeout maximum time (in milliseconds) to wait for a message
* @return time (in milliseconds) waited for a message, may be 0 if not waited
or SYS_ARCH_TIMEOUT on timeout
* The returned time has to be accurate to prevent timer jitter! */
u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout);
/* Allow port to override with a macro, e.g. special timout for sys_arch_mbox_fetch() */
#ifndef sys_arch_mbox_tryfetch
/** Wait for a new message to arrive in the mbox
* @param mbox mbox to get a message from
* @param msg pointer where the message is stored
* @param timeout maximum time (in milliseconds) to wait for a message
* @return 0 (milliseconds) if a message has been received
* or SYS_MBOX_EMPTY if the mailbox is empty */
u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg);
#endif
/** For now, we map straight to sys_arch implementation. */
#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg)
/** Delete an mbox
* @param mbox mbox to delete */
void sys_mbox_free(sys_mbox_t *mbox);
#define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0)
#ifndef sys_mbox_valid
/** Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */
int sys_mbox_valid(sys_mbox_t *mbox);
#endif
#ifndef sys_mbox_set_invalid
/** Set an mbox invalid so that sys_mbox_valid returns 0 */
void sys_mbox_set_invalid(sys_mbox_t *mbox);
#endif
/** The only thread function:
* Creates a new thread
* @param name human-readable name for the thread (used for debugging purposes)
* @param thread thread-function
* @param arg parameter passed to 'thread'
* @param stacksize stack size in bytes for the new thread (may be ignored by ports)
* @param prio priority of the new thread (may be ignored by ports) */
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio);
#endif /* NO_SYS */
/** Returns the current time in milliseconds. */
/* sys_init() must be called before anthing else. */
void sys_init(void);
#ifndef sys_jiffies
/** Ticks/jiffies since power up. */
u32_t sys_jiffies(void);
#endif
/** Returns the current time in milliseconds,
* may be the same as sys_jiffies or at least based on it. */
u32_t sys_now(void);
/* Critical Region Protection */

View file

@ -49,198 +49,80 @@ extern "C" {
struct tcp_pcb;
/* Functions for interfacing with TCP: */
/* Lower layer interface to TCP: */
#define tcp_init() /* Compatibility define, not init needed. */
void tcp_tmr (void); /* Must be called every
TCP_TMR_INTERVAL
ms. (Typically 250 ms). */
/* Application program's interface: */
struct tcp_pcb * tcp_new (void);
struct tcp_pcb * tcp_alloc (u8_t prio);
void tcp_arg (struct tcp_pcb *pcb, void *arg);
void tcp_accept (struct tcp_pcb *pcb,
err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
err_t err));
void tcp_recv (struct tcp_pcb *pcb,
err_t (* recv)(void *arg, struct tcp_pcb *tpcb,
struct pbuf *p, err_t err));
void tcp_sent (struct tcp_pcb *pcb,
err_t (* sent)(void *arg, struct tcp_pcb *tpcb,
u16_t len));
void tcp_poll (struct tcp_pcb *pcb,
err_t (* poll)(void *arg, struct tcp_pcb *tpcb),
u8_t interval);
void tcp_err (struct tcp_pcb *pcb,
void (* err)(void *arg, err_t err));
#define tcp_mss(pcb) ((pcb)->mss)
#define tcp_sndbuf(pcb) ((pcb)->snd_buf)
#define tcp_nagle_disable(pcb) ((pcb)->flags |= TF_NODELAY)
#define tcp_nagle_enable(pcb) ((pcb)->flags &= ~TF_NODELAY)
#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0)
#if TCP_LISTEN_BACKLOG
#define tcp_accepted(pcb) (((struct tcp_pcb_listen *)(pcb))->accepts_pending--)
#else /* TCP_LISTEN_BACKLOG */
#define tcp_accepted(pcb)
#endif /* TCP_LISTEN_BACKLOG */
void tcp_recved (struct tcp_pcb *pcb, u16_t len);
err_t tcp_bind (struct tcp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port);
err_t tcp_connect (struct tcp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port, err_t (* connected)(void *arg,
struct tcp_pcb *tpcb,
err_t err));
struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog);
#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG)
void tcp_abandon (struct tcp_pcb *pcb, int reset);
#define tcp_abort(pcb) tcp_abandon((pcb), 1)
err_t tcp_close (struct tcp_pcb *pcb);
/* Flags for "apiflags" parameter in tcp_write and tcp_enqueue */
#define TCP_WRITE_FLAG_COPY 0x01
#define TCP_WRITE_FLAG_MORE 0x02
err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len,
u8_t apiflags);
void tcp_setprio (struct tcp_pcb *pcb, u8_t prio);
#define TCP_PRIO_MIN 1
#define TCP_PRIO_NORMAL 64
#define TCP_PRIO_MAX 127
/* It is also possible to call these two functions at the right
intervals (instead of calling tcp_tmr()). */
void tcp_slowtmr (void);
void tcp_fasttmr (void);
/* Only used by IP to pass a TCP segment to TCP: */
void tcp_input (struct pbuf *p, struct netif *inp);
/* Used within the TCP code only: */
err_t tcp_send_empty_ack(struct tcp_pcb *pcb);
err_t tcp_output (struct tcp_pcb *pcb);
void tcp_rexmit (struct tcp_pcb *pcb);
void tcp_rexmit_rto (struct tcp_pcb *pcb);
void tcp_rexmit_fast (struct tcp_pcb *pcb);
u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb);
/**
* This is the Nagle algorithm: try to combine user data to send as few TCP
* segments as possible. Only send if
* - no previously transmitted data on the connection remains unacknowledged or
* - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or
* - the only unsent segment is at least pcb->mss bytes long (or there is more
* than one unsent segment - with lwIP, this can happen although unsent->len < mss)
* - or if we are in fast-retransmit (TF_INFR)
/** Function prototype for tcp accept callback functions. Called when a new
* connection can be accepted on a listening pcb.
*
* @param arg Additional argument to pass to the callback function (@see tcp_arg())
* @param newpcb The new connection pcb
* @param err An error code if there has been an error accepting.
* Only return ERR_ABRT if you have called tcp_abort from within the
* callback function!
*/
#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \
((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \
(((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \
((tpcb)->unsent->len >= (tpcb)->mss))) \
) ? 1 : 0)
#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK)
typedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err);
#define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0)
#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0)
#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0)
#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0)
/* is b<=a<=c? */
#if 0 /* see bug #10548 */
#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b))
#endif
#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c))
#define TCP_FIN 0x01U
#define TCP_SYN 0x02U
#define TCP_RST 0x04U
#define TCP_PSH 0x08U
#define TCP_ACK 0x10U
#define TCP_URG 0x20U
#define TCP_ECE 0x40U
#define TCP_CWR 0x80U
#define TCP_FLAGS 0x3fU
/* Length of the TCP header, excluding options. */
#define TCP_HLEN 20
#ifndef TCP_TMR_INTERVAL
#define TCP_TMR_INTERVAL 250 /* The TCP timer interval in milliseconds. */
#endif /* TCP_TMR_INTERVAL */
#ifndef TCP_FAST_INTERVAL
#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */
#endif /* TCP_FAST_INTERVAL */
#ifndef TCP_SLOW_INTERVAL
#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */
#endif /* TCP_SLOW_INTERVAL */
#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */
#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */
#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */
#ifndef TCP_MSL
#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */
#endif
/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */
#ifndef TCP_KEEPIDLE_DEFAULT
#define TCP_KEEPIDLE_DEFAULT 7200000UL /* Default KEEPALIVE timer in milliseconds */
#endif
#ifndef TCP_KEEPINTVL_DEFAULT
#define TCP_KEEPINTVL_DEFAULT 75000UL /* Default Time between KEEPALIVE probes in milliseconds */
#endif
#ifndef TCP_KEEPCNT_DEFAULT
#define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */
#endif
#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */
/* Fields are (of course) in network byte order.
* Some fields are converted to host byte order in tcp_input().
/** Function prototype for tcp receive callback functions. Called when data has
* been received.
*
* @param arg Additional argument to pass to the callback function (@see tcp_arg())
* @param tpcb The connection pcb which received data
* @param p The received data (or NULL when the connection has been closed!)
* @param err An error code if there has been an error receiving
* Only return ERR_ABRT if you have called tcp_abort from within the
* callback function!
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct tcp_hdr {
PACK_STRUCT_FIELD(u16_t src);
PACK_STRUCT_FIELD(u16_t dest);
PACK_STRUCT_FIELD(u32_t seqno);
PACK_STRUCT_FIELD(u32_t ackno);
PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);
PACK_STRUCT_FIELD(u16_t wnd);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u16_t urgp);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
typedef err_t (*tcp_recv_fn)(void *arg, struct tcp_pcb *tpcb,
struct pbuf *p, err_t err);
#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8)
#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)
#define TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS)
/** Function prototype for tcp sent callback functions. Called when sent data has
* been acknowledged by the remote side. Use it to free corresponding resources.
* This also means that the pcb has now space available to send new data.
*
* @param arg Additional argument to pass to the callback function (@see tcp_arg())
* @param tpcb The connection pcb for which data has been acknowledged
* @param len The amount of bytes acknowledged
* @return ERR_OK: try to send some data by calling tcp_output
* Only return ERR_ABRT if you have called tcp_abort from within the
* callback function!
*/
typedef err_t (*tcp_sent_fn)(void *arg, struct tcp_pcb *tpcb,
u16_t len);
#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr))
#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr))
#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & htons((u16_t)(~(u16_t)(TCP_FLAGS)))) | htons(flags))
#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | htons(flags))
#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) )
/** Function prototype for tcp poll callback functions. Called periodically as
* specified by @see tcp_poll.
*
* @param arg Additional argument to pass to the callback function (@see tcp_arg())
* @param tpcb tcp pcb
* @return ERR_OK: try to send some data by calling tcp_output
* Only return ERR_ABRT if you have called tcp_abort from within the
* callback function!
*/
typedef err_t (*tcp_poll_fn)(void *arg, struct tcp_pcb *tpcb);
#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0))
/** Function prototype for tcp error callback functions. Called when the pcb
* receives a RST or is unexpectedly closed for any other reason.
*
* @note The corresponding pcb is already freed when this callback is called!
*
* @param arg Additional argument to pass to the callback function (@see tcp_arg())
* @param err Error code to indicate why the pcb has been closed
* ERR_ABRT: aborted through tcp_abort or by a TCP timer
* ERR_RST: the connection was reset by the remote host
*/
typedef void (*tcp_err_fn)(void *arg, err_t err);
/** Function prototype for tcp connected callback functions. Called when a pcb
* is connected to the remote side after initiating a connection attempt by
* calling tcp_connect().
*
* @param arg Additional argument to pass to the callback function (@see tcp_arg())
* @param tpcb The connection pcb which is connected
* @param err An unused error code, always ERR_OK currently ;-) TODO!
* Only return ERR_ABRT if you have called tcp_abort from within the
* callback function!
*
* @note When a connection attempt fails, the error callback is currently called!
*/
typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err);
enum tcp_state {
CLOSED = 0,
@ -256,13 +138,6 @@ enum tcp_state {
TIME_WAIT = 10
};
/** Flags used on input processing, not on pcb->flags
*/
#define TF_RESET (u8_t)0x08U /* Connection was reset. */
#define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */
#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */
#if LWIP_CALLBACK_API
/* Function to call when a listener has been connected.
* @param arg user-supplied argument (tcp_pcb.callback_arg)
@ -271,7 +146,7 @@ enum tcp_state {
* @return ERR_OK: accept the new connection,
* any other err_t abortsthe new connection
*/
#define DEF_ACCEPT_CALLBACK err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)
#define DEF_ACCEPT_CALLBACK tcp_accept_fn accept;
#else /* LWIP_CALLBACK_API */
#define DEF_ACCEPT_CALLBACK
#endif /* LWIP_CALLBACK_API */
@ -284,10 +159,10 @@ enum tcp_state {
enum tcp_state state; /* TCP state */ \
u8_t prio; \
void *callback_arg; \
/* ports are in host byte order */ \
u16_t local_port; \
/* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \
DEF_ACCEPT_CALLBACK
DEF_ACCEPT_CALLBACK \
/* ports are in host byte order */ \
u16_t local_port
/* the TCP protocol control block */
@ -305,6 +180,7 @@ struct tcp_pcb {
#define TF_ACK_NOW ((u8_t)0x02U) /* Immediate ACK. */
#define TF_INFR ((u8_t)0x04U) /* In fast recovery. */
#define TF_TIMESTAMP ((u8_t)0x08U) /* Timestamp option enabled */
#define TF_RXCLOSED ((u8_t)0x10U) /* rx closed by tcp_shutdown */
#define TF_FIN ((u8_t)0x20U) /* Connection was closed locally (FIN segment enqueued). */
#define TF_NODELAY ((u8_t)0x40U) /* Disable Nagle algorithm */
#define TF_NAGLEMEMERR ((u8_t)0x80U) /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */
@ -352,10 +228,14 @@ struct tcp_pcb {
u16_t acked;
u16_t snd_buf; /* Available buffer space for sending (in bytes). */
#define TCP_SNDQUEUELEN_OVERFLOW (0xffff-3)
#define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3)
u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */
#if TCP_OVERSIZE
/* Extra bytes available at the end of the last pbuf in unsent. */
u16_t unsent_oversize;
#endif /* TCP_OVERSIZE */
/* These are ordered by sequence number: */
struct tcp_seg *unsent; /* Unsent (queued) segments. */
struct tcp_seg *unacked; /* Sent but unacknowledged segments. */
@ -366,49 +246,16 @@ struct tcp_pcb {
struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */
#if LWIP_CALLBACK_API
/* Function to be called when more send buffer space is available.
* @param arg user-supplied argument (tcp_pcb.callback_arg)
* @param pcb the tcp_pcb which has send buffer space available
* @param space the amount of bytes available
* @return ERR_OK: try to send some data by calling tcp_output
*/
err_t (* sent)(void *arg, struct tcp_pcb *pcb, u16_t space);
/* Function to be called when (in-sequence) data has arrived.
* @param arg user-supplied argument (tcp_pcb.callback_arg)
* @param pcb the tcp_pcb for which data has arrived
* @param p the packet buffer which arrived
* @param err an error argument (TODO: that is current always ERR_OK?)
* @return ERR_OK: try to send some data by calling tcp_output
*/
err_t (* recv)(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
/* Function to be called when a connection has been set up.
* @param arg user-supplied argument (tcp_pcb.callback_arg)
* @param pcb the tcp_pcb that now is connected
* @param err an error argument (TODO: that is current always ERR_OK?)
* @return value is currently ignored
*/
err_t (* connected)(void *arg, struct tcp_pcb *pcb, err_t err);
/* Function which is called periodically.
* The period can be adjusted in multiples of the TCP slow timer interval
* by changing tcp_pcb.polltmr.
* @param arg user-supplied argument (tcp_pcb.callback_arg)
* @param pcb the tcp_pcb to poll for
* @return ERR_OK: try to send some data by calling tcp_output
*/
err_t (* poll)(void *arg, struct tcp_pcb *pcb);
/* Function to be called whenever a fatal error occurs.
* There is no pcb parameter since most of the times, the pcb is
* already deallocated (or there is no pcb) when this function is called.
* @param arg user-supplied argument (tcp_pcb.callback_arg)
* @param err an indication why the error callback is called:
* ERR_ABRT: aborted through tcp_abort or by a TCP timer
* ERR_RST: the connection was reset by the remote host
*/
void (* errf)(void *arg, err_t err);
/* Function to be called when more send buffer space is available. */
tcp_sent_fn sent;
/* Function to be called when (in-sequence) data has arrived. */
tcp_recv_fn recv;
/* Function to be called when a connection has been set up. */
tcp_connected_fn connected;
/* Function which is called periodically. */
tcp_poll_fn poll;
/* Function to be called whenever a fatal error occurs. */
tcp_err_fn errf;
#endif /* LWIP_CALLBACK_API */
#if LWIP_TCP_TIMESTAMPS
@ -461,242 +308,65 @@ err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,
u16_t size,
err_t err);
#define TCP_EVENT_ACCEPT(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_ACCEPT, NULL, 0, err)
#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_SENT, NULL, space, ERR_OK)
#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_RECV, (p), 0, (err))
#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_CONNECTED, NULL, 0, (err))
#define TCP_EVENT_POLL(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_POLL, NULL, 0, ERR_OK)
#define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \
LWIP_EVENT_ERR, NULL, 0, (err))
#else /* LWIP_EVENT_API */
#define TCP_EVENT_ACCEPT(pcb,err,ret) \
do { \
if((pcb)->accept != NULL) \
(ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err)); \
else (ret) = ERR_OK; \
} while (0)
#define TCP_EVENT_SENT(pcb,space,ret) \
do { \
if((pcb)->sent != NULL) \
(ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \
else (ret) = ERR_OK; \
} while (0)
#define TCP_EVENT_RECV(pcb,p,err,ret) \
do { \
if((pcb)->recv != NULL) { \
(ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); \
} else { \
(ret) = tcp_recv_null(NULL, (pcb), (p), (err)); \
} \
} while (0)
#define TCP_EVENT_CONNECTED(pcb,err,ret) \
do { \
if((pcb)->connected != NULL) \
(ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \
else (ret) = ERR_OK; \
} while (0)
#define TCP_EVENT_POLL(pcb,ret) \
do { \
if((pcb)->poll != NULL) \
(ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \
else (ret) = ERR_OK; \
} while (0)
#define TCP_EVENT_ERR(errf,arg,err) \
do { \
if((errf) != NULL) \
(errf)((arg),(err)); \
} while (0)
#endif /* LWIP_EVENT_API */
/* This structure represents a TCP segment on the unsent and unacked queues */
struct tcp_seg {
struct tcp_seg *next; /* used when putting segements on a queue */
struct pbuf *p; /* buffer containing data + TCP header */
void *dataptr; /* pointer to the TCP data in the pbuf */
u16_t len; /* the TCP length of this segment */
u8_t flags;
#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */
#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */
struct tcp_hdr *tcphdr; /* the TCP header */
};
/* Application program's interface: */
struct tcp_pcb * tcp_new (void);
#define LWIP_TCP_OPT_LENGTH(flags) \
(flags & TF_SEG_OPTS_MSS ? 4 : 0) + \
(flags & TF_SEG_OPTS_TS ? 12 : 0)
void tcp_arg (struct tcp_pcb *pcb, void *arg);
void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept);
void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv);
void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent);
void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval);
void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err);
/** This returns a TCP header option for MSS in an u32_t */
#define TCP_BUILD_MSS_OPTION(x) (x) = htonl(((u32_t)2 << 24) | \
((u32_t)4 << 16) | \
(((u32_t)TCP_MSS / 256) << 8) | \
(TCP_MSS & 255))
#define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss)
#define tcp_sndbuf(pcb) ((pcb)->snd_buf)
#define tcp_sndqueuelen(pcb) ((pcb)->snd_queuelen)
#define tcp_nagle_disable(pcb) ((pcb)->flags |= TF_NODELAY)
#define tcp_nagle_enable(pcb) ((pcb)->flags &= ~TF_NODELAY)
#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0)
/* Internal functions and global variables: */
struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb);
void tcp_pcb_purge(struct tcp_pcb *pcb);
void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb);
#if TCP_LISTEN_BACKLOG
#define tcp_accepted(pcb) do { \
LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", pcb->state == LISTEN); \
(((struct tcp_pcb_listen *)(pcb))->accepts_pending--); } while(0)
#else /* TCP_LISTEN_BACKLOG */
#define tcp_accepted(pcb) LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", \
pcb->state == LISTEN)
#endif /* TCP_LISTEN_BACKLOG */
u8_t tcp_segs_free(struct tcp_seg *seg);
u8_t tcp_seg_free(struct tcp_seg *seg);
struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg);
void tcp_recved (struct tcp_pcb *pcb, u16_t len);
err_t tcp_bind (struct tcp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port);
err_t tcp_connect (struct tcp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port, tcp_connected_fn connected);
#define tcp_ack(pcb) \
do { \
if((pcb)->flags & TF_ACK_DELAY) { \
(pcb)->flags &= ~TF_ACK_DELAY; \
(pcb)->flags |= TF_ACK_NOW; \
tcp_output(pcb); \
} \
else { \
(pcb)->flags |= TF_ACK_DELAY; \
} \
} while (0)
struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog);
#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG)
#define tcp_ack_now(pcb) \
do { \
(pcb)->flags |= TF_ACK_NOW; \
tcp_output(pcb); \
} while (0)
void tcp_abort (struct tcp_pcb *pcb);
err_t tcp_close (struct tcp_pcb *pcb);
err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx);
err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags);
err_t tcp_enqueue(struct tcp_pcb *pcb, void *dataptr, u16_t len,
u8_t flags, u8_t apiflags, u8_t optflags);
/* Flags for "apiflags" parameter in tcp_write */
#define TCP_WRITE_FLAG_COPY 0x01
#define TCP_WRITE_FLAG_MORE 0x02
void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg);
err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len,
u8_t apiflags);
void tcp_rst(u32_t seqno, u32_t ackno,
struct ip_addr *local_ip, struct ip_addr *remote_ip,
u16_t local_port, u16_t remote_port);
void tcp_setprio (struct tcp_pcb *pcb, u8_t prio);
u32_t tcp_next_iss(void);
#define TCP_PRIO_MIN 1
#define TCP_PRIO_NORMAL 64
#define TCP_PRIO_MAX 127
void tcp_keepalive(struct tcp_pcb *pcb);
void tcp_zero_window_probe(struct tcp_pcb *pcb);
err_t tcp_output (struct tcp_pcb *pcb);
#if TCP_CALCULATE_EFF_SEND_MSS
u16_t tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr);
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
#if LWIP_CALLBACK_API
err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
#endif /* LWIP_CALLBACK_API */
extern struct tcp_pcb *tcp_input_pcb;
extern u32_t tcp_ticks;
const char* tcp_debug_state_str(enum tcp_state s);
#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
void tcp_debug_print(struct tcp_hdr *tcphdr);
void tcp_debug_print_flags(u8_t flags);
void tcp_debug_print_state(enum tcp_state s);
void tcp_debug_print_pcbs(void);
s16_t tcp_pcbs_sane(void);
#else
# define tcp_debug_print(tcphdr)
# define tcp_debug_print_flags(flags)
# define tcp_debug_print_state(s)
# define tcp_debug_print_pcbs()
# define tcp_pcbs_sane() 1
#endif /* TCP_DEBUG */
#if NO_SYS
#define tcp_timer_needed()
#else
void tcp_timer_needed(void);
#endif
/* The TCP PCB lists. */
union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */
struct tcp_pcb_listen *listen_pcbs;
struct tcp_pcb *pcbs;
};
extern union tcp_listen_pcbs_t tcp_listen_pcbs;
extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a
state in which they accept or send
data. */
extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */
extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */
/* Axioms about the above lists:
1) Every TCP PCB that is not CLOSED is in one of the lists.
2) A PCB is only in one of the lists.
3) All PCBs in the tcp_listen_pcbs list is in LISTEN state.
4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state.
*/
/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB
with a PCB list or removes a PCB from a list, respectively. */
#if 0
#define TCP_REG(pcbs, npcb) do {\
LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", npcb, npcb->local_port)); \
for(tcp_tmp_pcb = *pcbs; \
tcp_tmp_pcb != NULL; \
tcp_tmp_pcb = tcp_tmp_pcb->next) { \
LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != npcb); \
} \
LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", npcb->state != CLOSED); \
npcb->next = *pcbs; \
LWIP_ASSERT("TCP_REG: npcb->next != npcb", npcb->next != npcb); \
*(pcbs) = npcb; \
LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \
tcp_timer_needed(); \
} while(0)
#define TCP_RMV(pcbs, npcb) do { \
LWIP_ASSERT("TCP_RMV: pcbs != NULL", *pcbs != NULL); \
LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", npcb, *pcbs)); \
if(*pcbs == npcb) { \
*pcbs = (*pcbs)->next; \
} else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \
if(tcp_tmp_pcb->next == npcb) { \
tcp_tmp_pcb->next = npcb->next; \
break; \
} \
} \
npcb->next = NULL; \
LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \
LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", npcb, *pcbs)); \
} while(0)
#else /* LWIP_DEBUG */
#define TCP_REG(pcbs, npcb) \
do { \
npcb->next = *pcbs; \
*(pcbs) = npcb; \
tcp_timer_needed(); \
} while (0)
#define TCP_RMV(pcbs, npcb) \
do { \
if(*(pcbs) == npcb) { \
(*(pcbs)) = (*pcbs)->next; \
} \
else { \
for(tcp_tmp_pcb = *pcbs; \
tcp_tmp_pcb != NULL; \
tcp_tmp_pcb = tcp_tmp_pcb->next) { \
if(tcp_tmp_pcb->next == npcb) { \
tcp_tmp_pcb->next = npcb->next; \
break; \
} \
} \
} \
npcb->next = NULL; \
} while(0)
#endif /* LWIP_DEBUG */
#ifdef __cplusplus
}

View file

@ -0,0 +1,471 @@
/*
* Copyright (c) 2001-2004 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>
*
*/
#ifndef __LWIP_TCP_IMPL_H__
#define __LWIP_TCP_IMPL_H__
#include "lwip/opt.h"
#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
#include "lwip/tcp.h"
#include "lwip/sys.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/ip.h"
#include "lwip/icmp.h"
#include "lwip/err.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Functions for interfacing with TCP: */
/* Lower layer interface to TCP: */
#define tcp_init() /* Compatibility define, no init needed. */
void tcp_tmr (void); /* Must be called every
TCP_TMR_INTERVAL
ms. (Typically 250 ms). */
/* It is also possible to call these two functions at the right
intervals (instead of calling tcp_tmr()). */
void tcp_slowtmr (void);
void tcp_fasttmr (void);
/* Only used by IP to pass a TCP segment to TCP: */
void tcp_input (struct pbuf *p, struct netif *inp);
/* Used within the TCP code only: */
struct tcp_pcb * tcp_alloc (u8_t prio);
void tcp_abandon (struct tcp_pcb *pcb, int reset);
err_t tcp_send_empty_ack(struct tcp_pcb *pcb);
void tcp_rexmit (struct tcp_pcb *pcb);
void tcp_rexmit_rto (struct tcp_pcb *pcb);
void tcp_rexmit_fast (struct tcp_pcb *pcb);
u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb);
/**
* This is the Nagle algorithm: try to combine user data to send as few TCP
* segments as possible. Only send if
* - no previously transmitted data on the connection remains unacknowledged or
* - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or
* - the only unsent segment is at least pcb->mss bytes long (or there is more
* than one unsent segment - with lwIP, this can happen although unsent->len < mss)
* - or if we are in fast-retransmit (TF_INFR)
*/
#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \
((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \
(((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \
((tpcb)->unsent->len >= (tpcb)->mss))) \
) ? 1 : 0)
#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK)
#define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0)
#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0)
#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0)
#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0)
/* is b<=a<=c? */
#if 0 /* see bug #10548 */
#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b))
#endif
#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c))
#define TCP_FIN 0x01U
#define TCP_SYN 0x02U
#define TCP_RST 0x04U
#define TCP_PSH 0x08U
#define TCP_ACK 0x10U
#define TCP_URG 0x20U
#define TCP_ECE 0x40U
#define TCP_CWR 0x80U
#define TCP_FLAGS 0x3fU
/* Length of the TCP header, excluding options. */
#define TCP_HLEN 20
#ifndef TCP_TMR_INTERVAL
#define TCP_TMR_INTERVAL 250 /* The TCP timer interval in milliseconds. */
#endif /* TCP_TMR_INTERVAL */
#ifndef TCP_FAST_INTERVAL
#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */
#endif /* TCP_FAST_INTERVAL */
#ifndef TCP_SLOW_INTERVAL
#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */
#endif /* TCP_SLOW_INTERVAL */
#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */
#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */
#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */
#ifndef TCP_MSL
#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */
#endif
/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */
#ifndef TCP_KEEPIDLE_DEFAULT
#define TCP_KEEPIDLE_DEFAULT 7200000UL /* Default KEEPALIVE timer in milliseconds */
#endif
#ifndef TCP_KEEPINTVL_DEFAULT
#define TCP_KEEPINTVL_DEFAULT 75000UL /* Default Time between KEEPALIVE probes in milliseconds */
#endif
#ifndef TCP_KEEPCNT_DEFAULT
#define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */
#endif
#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */
/* Fields are (of course) in network byte order.
* Some fields are converted to host byte order in tcp_input().
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct tcp_hdr {
PACK_STRUCT_FIELD(u16_t src);
PACK_STRUCT_FIELD(u16_t dest);
PACK_STRUCT_FIELD(u32_t seqno);
PACK_STRUCT_FIELD(u32_t ackno);
PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);
PACK_STRUCT_FIELD(u16_t wnd);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u16_t urgp);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8)
#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)
#define TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS)
#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr))
#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr))
#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS((u16_t)(~(u16_t)(TCP_FLAGS)))) | htons(flags))
#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | (flags))
#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | htons(flags))
#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) )
#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0))
/** Flags used on input processing, not on pcb->flags
*/
#define TF_RESET (u8_t)0x08U /* Connection was reset. */
#define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */
#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */
#if LWIP_EVENT_API
#define TCP_EVENT_ACCEPT(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_ACCEPT, NULL, 0, err)
#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_SENT, NULL, space, ERR_OK)
#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_RECV, (p), 0, (err))
#define TCP_EVENT_CLOSED(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_RECV, NULL, 0, ERR_OK)
#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_CONNECTED, NULL, 0, (err))
#define TCP_EVENT_POLL(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\
LWIP_EVENT_POLL, NULL, 0, ERR_OK)
#define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \
LWIP_EVENT_ERR, NULL, 0, (err))
#else /* LWIP_EVENT_API */
#define TCP_EVENT_ACCEPT(pcb,err,ret) \
do { \
if((pcb)->accept != NULL) \
(ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err)); \
else (ret) = ERR_ARG; \
} while (0)
#define TCP_EVENT_SENT(pcb,space,ret) \
do { \
if((pcb)->sent != NULL) \
(ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \
else (ret) = ERR_OK; \
} while (0)
#define TCP_EVENT_RECV(pcb,p,err,ret) \
do { \
if((pcb)->recv != NULL) { \
(ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err));\
} else { \
(ret) = tcp_recv_null(NULL, (pcb), (p), (err)); \
} \
} while (0)
#define TCP_EVENT_CLOSED(pcb,ret) \
do { \
if(((pcb)->recv != NULL)) { \
(ret) = (pcb)->recv((pcb)->callback_arg,(pcb),NULL,ERR_OK);\
} else { \
(ret) = ERR_OK; \
} \
} while (0)
#define TCP_EVENT_CONNECTED(pcb,err,ret) \
do { \
if((pcb)->connected != NULL) \
(ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \
else (ret) = ERR_OK; \
} while (0)
#define TCP_EVENT_POLL(pcb,ret) \
do { \
if((pcb)->poll != NULL) \
(ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \
else (ret) = ERR_OK; \
} while (0)
#define TCP_EVENT_ERR(errf,arg,err) \
do { \
if((errf) != NULL) \
(errf)((arg),(err)); \
} while (0)
#endif /* LWIP_EVENT_API */
/** Enabled extra-check for TCP_OVERSIZE if LWIP_DEBUG is enabled */
#if TCP_OVERSIZE && defined(LWIP_DEBUG)
#define TCP_OVERSIZE_DBGCHECK 1
#else
#define TCP_OVERSIZE_DBGCHECK 0
#endif
/** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */
#define TCP_CHECKSUM_ON_COPY (LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_TCP)
/* This structure represents a TCP segment on the unsent, unacked and ooseq queues */
struct tcp_seg {
struct tcp_seg *next; /* used when putting segements on a queue */
struct pbuf *p; /* buffer containing data + TCP header */
u16_t len; /* the TCP length of this segment */
#if TCP_OVERSIZE_DBGCHECK
u16_t oversize_left; /* Extra bytes available at the end of the last
pbuf in unsent (used for asserting vs.
tcp_pcb.unsent_oversized only) */
#endif /* TCP_OVERSIZE_DBGCHECK */
#if TCP_CHECKSUM_ON_COPY
u16_t chksum;
u8_t chksum_swapped;
#endif /* TCP_CHECKSUM_ON_COPY */
u8_t flags;
#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */
#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */
#define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is
checksummed into 'chksum' */
struct tcp_hdr *tcphdr; /* the TCP header */
};
#define LWIP_TCP_OPT_LENGTH(flags) \
(flags & TF_SEG_OPTS_MSS ? 4 : 0) + \
(flags & TF_SEG_OPTS_TS ? 12 : 0)
/** This returns a TCP header option for MSS in an u32_t */
#define TCP_BUILD_MSS_OPTION(x) (x) = PP_HTONL(((u32_t)2 << 24) | \
((u32_t)4 << 16) | \
(((u32_t)TCP_MSS / 256) << 8) | \
(TCP_MSS & 255))
/* Global variables: */
extern struct tcp_pcb *tcp_input_pcb;
extern u32_t tcp_ticks;
/* The TCP PCB lists. */
union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */
struct tcp_pcb_listen *listen_pcbs;
struct tcp_pcb *pcbs;
};
extern struct tcp_pcb *tcp_bound_pcbs;
extern union tcp_listen_pcbs_t tcp_listen_pcbs;
extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a
state in which they accept or send
data. */
extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */
extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */
/* Axioms about the above lists:
1) Every TCP PCB that is not CLOSED is in one of the lists.
2) A PCB is only in one of the lists.
3) All PCBs in the tcp_listen_pcbs list is in LISTEN state.
4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state.
*/
/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB
with a PCB list or removes a PCB from a list, respectively. */
#ifndef TCP_DEBUG_PCB_LISTS
#define TCP_DEBUG_PCB_LISTS 0
#endif
#if TCP_DEBUG_PCB_LISTS
#define TCP_REG(pcbs, npcb) do {\
LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", (npcb), (npcb)->local_port)); \
for(tcp_tmp_pcb = *(pcbs); \
tcp_tmp_pcb != NULL; \
tcp_tmp_pcb = tcp_tmp_pcb->next) { \
LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != (npcb)); \
} \
LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", ((pcbs) == &tcp_bound_pcbs) || ((npcb)->state != CLOSED)); \
(npcb)->next = *(pcbs); \
LWIP_ASSERT("TCP_REG: npcb->next != npcb", (npcb)->next != (npcb)); \
*(pcbs) = (npcb); \
LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \
tcp_timer_needed(); \
} while(0)
#define TCP_RMV(pcbs, npcb) do { \
LWIP_ASSERT("TCP_RMV: pcbs != NULL", *(pcbs) != NULL); \
LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", (npcb), *(pcbs))); \
if(*(pcbs) == (npcb)) { \
*(pcbs) = (*pcbs)->next; \
} else for(tcp_tmp_pcb = *(pcbs); tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \
if(tcp_tmp_pcb->next == (npcb)) { \
tcp_tmp_pcb->next = (npcb)->next; \
break; \
} \
} \
(npcb)->next = NULL; \
LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \
LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (npcb), *(pcbs))); \
} while(0)
#else /* LWIP_DEBUG */
#define TCP_REG(pcbs, npcb) \
do { \
(npcb)->next = *pcbs; \
*(pcbs) = (npcb); \
tcp_timer_needed(); \
} while (0)
#define TCP_RMV(pcbs, npcb) \
do { \
if(*(pcbs) == (npcb)) { \
(*(pcbs)) = (*pcbs)->next; \
} \
else { \
for(tcp_tmp_pcb = *pcbs; \
tcp_tmp_pcb != NULL; \
tcp_tmp_pcb = tcp_tmp_pcb->next) { \
if(tcp_tmp_pcb->next == (npcb)) { \
tcp_tmp_pcb->next = (npcb)->next; \
break; \
} \
} \
} \
(npcb)->next = NULL; \
} while(0)
#endif /* LWIP_DEBUG */
/* Internal functions: */
struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb);
void tcp_pcb_purge(struct tcp_pcb *pcb);
void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb);
void tcp_segs_free(struct tcp_seg *seg);
void tcp_seg_free(struct tcp_seg *seg);
struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg);
#define tcp_ack(pcb) \
do { \
if((pcb)->flags & TF_ACK_DELAY) { \
(pcb)->flags &= ~TF_ACK_DELAY; \
(pcb)->flags |= TF_ACK_NOW; \
} \
else { \
(pcb)->flags |= TF_ACK_DELAY; \
} \
} while (0)
#define tcp_ack_now(pcb) \
do { \
(pcb)->flags |= TF_ACK_NOW; \
} while (0)
err_t tcp_send_fin(struct tcp_pcb *pcb);
err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags);
void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg);
void tcp_rst(u32_t seqno, u32_t ackno,
ip_addr_t *local_ip, ip_addr_t *remote_ip,
u16_t local_port, u16_t remote_port);
u32_t tcp_next_iss(void);
void tcp_keepalive(struct tcp_pcb *pcb);
void tcp_zero_window_probe(struct tcp_pcb *pcb);
#if TCP_CALCULATE_EFF_SEND_MSS
u16_t tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr);
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
#if LWIP_CALLBACK_API
err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
#endif /* LWIP_CALLBACK_API */
#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
void tcp_debug_print(struct tcp_hdr *tcphdr);
void tcp_debug_print_flags(u8_t flags);
void tcp_debug_print_state(enum tcp_state s);
void tcp_debug_print_pcbs(void);
s16_t tcp_pcbs_sane(void);
#else
# define tcp_debug_print(tcphdr)
# define tcp_debug_print_flags(flags)
# define tcp_debug_print_state(s)
# define tcp_debug_print_pcbs()
# define tcp_pcbs_sane() 1
#endif /* TCP_DEBUG */
/** External function (implemented in timers.c), called when TCP detects
* that a timer is needed (i.e. active- or time-wait-pcb found). */
void tcp_timer_needed(void);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_TCP */
#endif /* __LWIP_TCP_H__ */

View file

@ -41,31 +41,43 @@
#include "lwip/pbuf.h"
#include "lwip/api.h"
#include "lwip/sys.h"
#include "lwip/timers.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Define this to something that triggers a watchdog. This is called from
* tcpip_thread after processing a message. */
#ifndef LWIP_TCPIP_THREAD_ALIVE
#define LWIP_TCPIP_THREAD_ALIVE()
#endif
#if LWIP_TCPIP_CORE_LOCKING
/** The global semaphore to lock the stack. */
extern sys_sem_t lock_tcpip_core;
#define LOCK_TCPIP_CORE() sys_sem_wait(lock_tcpip_core)
#define UNLOCK_TCPIP_CORE() sys_sem_signal(lock_tcpip_core)
extern sys_mutex_t lock_tcpip_core;
#define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core)
#define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core)
#define TCPIP_APIMSG(m) tcpip_apimsg_lock(m)
#define TCPIP_APIMSG_ACK(m)
#define TCPIP_NETIFAPI(m) tcpip_netifapi_lock(m)
#define TCPIP_NETIFAPI_ACK(m)
#else
#else /* LWIP_TCPIP_CORE_LOCKING */
#define LOCK_TCPIP_CORE()
#define UNLOCK_TCPIP_CORE()
#define TCPIP_APIMSG(m) tcpip_apimsg(m)
#define TCPIP_APIMSG_ACK(m) sys_sem_signal(m->conn->op_completed)
#define TCPIP_APIMSG_ACK(m) sys_sem_signal(&m->conn->op_completed)
#define TCPIP_NETIFAPI(m) tcpip_netifapi(m)
#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(m->sem)
#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(&m->sem)
#endif /* LWIP_TCPIP_CORE_LOCKING */
void tcpip_init(void (* tcpip_init_done)(void *), void *arg);
/** Function prototype for the init_done function passed to tcpip_init */
typedef void (*tcpip_init_done_fn)(void *arg);
/** Function prototype for functions passed to tcpip_callback() */
typedef void (*tcpip_callback_fn)(void *ctx);
void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg);
#if LWIP_NETCONN
err_t tcpip_apimsg(struct api_msg *apimsg);
@ -83,15 +95,17 @@ err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg);
#endif /* LWIP_TCPIP_CORE_LOCKING */
#endif /* LWIP_NETIF_API */
err_t tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block);
err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block);
#define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1)
/* free pbufs or heap memory from another context without blocking */
err_t pbuf_free_callback(struct pbuf *p);
err_t mem_free_callback(void *m);
#if LWIP_TCPIP_TIMEOUT
err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg);
err_t tcpip_untimeout(sys_timeout_handler h, void *arg);
#endif /* LWIP_TCPIP_TIMEOUT */
enum tcpip_msg_type {
#if LWIP_NETCONN
@ -101,9 +115,11 @@ enum tcpip_msg_type {
#if LWIP_NETIF_API
TCPIP_MSG_NETIFAPI,
#endif /* LWIP_NETIF_API */
TCPIP_MSG_CALLBACK,
#if LWIP_TCPIP_TIMEOUT
TCPIP_MSG_TIMEOUT,
TCPIP_MSG_UNTIMEOUT
TCPIP_MSG_UNTIMEOUT,
#endif /* LWIP_TCPIP_TIMEOUT */
TCPIP_MSG_CALLBACK
};
struct tcpip_msg {
@ -121,14 +137,16 @@ struct tcpip_msg {
struct netif *netif;
} inp;
struct {
void (*f)(void *ctx);
tcpip_callback_fn function;
void *ctx;
} cb;
#if LWIP_TCPIP_TIMEOUT
struct {
u32_t msecs;
sys_timeout_handler h;
void *arg;
} tmo;
#endif /* LWIP_TCPIP_TIMEOUT */
} msg;
};

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2001-2004 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>
* Simon Goldschmidt
*
*/
#ifndef __LWIP_TIMERS_H__
#define __LWIP_TIMERS_H__
#include "lwip/opt.h"
/* Timers are not supported when NO_SYS==1 and NO_SYS_NO_TIMERS==1 */
#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS))
#if LWIP_TIMERS
#include "lwip/err.h"
#include "lwip/sys.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef LWIP_DEBUG_TIMERNAMES
#ifdef LWIP_DEBUG
#define LWIP_DEBUG_TIMERNAMES SYS_DEBUG
#else /* LWIP_DEBUG */
#define LWIP_DEBUG_TIMERNAMES 0
#endif /* LWIP_DEBUG*/
#endif
/** Function prototype for a timeout callback function. Register such a function
* using sys_timeout().
*
* @param arg Additional argument to pass to the function - set up by sys_timeout()
*/
typedef void (* sys_timeout_handler)(void *arg);
struct sys_timeo {
struct sys_timeo *next;
u32_t time;
sys_timeout_handler h;
void *arg;
#if LWIP_DEBUG_TIMERNAMES
const char* handler_name;
#endif /* LWIP_DEBUG_TIMERNAMES */
};
void sys_timeouts_init(void);
#if LWIP_DEBUG_TIMERNAMES
void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name);
#define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler)
#else /* LWIP_DEBUG_TIMERNAMES */
void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg);
#endif /* LWIP_DEBUG_TIMERNAMES */
void sys_untimeout(sys_timeout_handler handler, void *arg);
#if NO_SYS
void sys_check_timeouts(void);
void sys_restart_timeouts(void);
#else /* NO_SYS */
void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg);
#endif /* NO_SYS */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_TIMERS */
#endif /* __LWIP_TIMERS_H__ */

View file

@ -63,9 +63,30 @@ PACK_STRUCT_END
# include "arch/epstruct.h"
#endif
#define UDP_FLAGS_NOCHKSUM 0x01U
#define UDP_FLAGS_UDPLITE 0x02U
#define UDP_FLAGS_CONNECTED 0x04U
#define UDP_FLAGS_NOCHKSUM 0x01U
#define UDP_FLAGS_UDPLITE 0x02U
#define UDP_FLAGS_CONNECTED 0x04U
#define UDP_FLAGS_MULTICAST_LOOP 0x08U
struct udp_pcb;
/** Function prototype for udp pcb receive callback functions
* addr and port are in same byte order as in the pcb
* The callback is responsible for freeing the pbuf
* if it's not used any more.
*
* ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf
* makes 'addr' invalid, too.
*
* @param arg user supplied argument (udp_pcb.recv_arg)
* @param pcb the udp_pcb which received data
* @param p the packet buffer that was received
* @param addr the remote IP address from which the packet was received
* @param port the remote port from which the packet was received
*/
typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
ip_addr_t *addr, u16_t port);
struct udp_pcb {
/* Common members of all PCB types */
@ -76,36 +97,22 @@ struct udp_pcb {
struct udp_pcb *next;
u8_t flags;
/* ports are in host byte order */
/** ports are in host byte order */
u16_t local_port, remote_port;
#if LWIP_IGMP
/* outgoing network interface for multicast packets */
struct ip_addr multicast_ip;
/** outgoing network interface for multicast packets */
ip_addr_t multicast_ip;
#endif /* LWIP_IGMP */
#if LWIP_UDPLITE
/* used for UDP_LITE only */
/** used for UDP_LITE only */
u16_t chksum_len_rx, chksum_len_tx;
#endif /* LWIP_UDPLITE */
/* receive callback function
* addr and port are in same byte order as in the pcb
* The callback is responsible for freeing the pbuf
* if it's not used any more.
*
* ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf
* makes 'addr' invalid, too.
*
* @param arg user supplied argument (udp_pcb.recv_arg)
* @param pcb the udp_pcb which received data
* @param p the packet buffer that was received
* @param addr the remote IP address from which the packet was received
* @param port the remote port from which the packet was received
*/
void (* recv)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
struct ip_addr *addr, u16_t port);
/* user-supplied argument for the recv callback */
/** receive callback function */
udp_recv_fn recv;
/** user-supplied argument for the recv callback */
void *recv_arg;
};
/* udp_pcbs export for exernal reference (e.g. SNMP agent) */
@ -115,22 +122,33 @@ extern struct udp_pcb *udp_pcbs;
UDP code. */
struct udp_pcb * udp_new (void);
void udp_remove (struct udp_pcb *pcb);
err_t udp_bind (struct udp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port);
err_t udp_connect (struct udp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port);
void udp_disconnect (struct udp_pcb *pcb);
void udp_recv (struct udp_pcb *pcb,
void (* recv)(void *arg, struct udp_pcb *upcb,
struct pbuf *p,
struct ip_addr *addr,
u16_t port),
void *recv_arg);
err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif);
err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port);
err_t udp_bind (struct udp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port);
err_t udp_connect (struct udp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port);
void udp_disconnect (struct udp_pcb *pcb);
void udp_recv (struct udp_pcb *pcb, udp_recv_fn recv,
void *recv_arg);
err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p,
ip_addr_t *dst_ip, u16_t dst_port,
struct netif *netif);
err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p,
ip_addr_t *dst_ip, u16_t dst_port);
err_t udp_send (struct udp_pcb *pcb, struct pbuf *p);
#define udp_flags(pcb) ((pcb)->flags)
#if LWIP_CHECKSUM_ON_COPY
err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p,
ip_addr_t *dst_ip, u16_t dst_port,
struct netif *netif, u8_t have_chksum,
u16_t chksum);
err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p,
ip_addr_t *dst_ip, u16_t dst_port,
u8_t have_chksum, u16_t chksum);
err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
u8_t have_chksum, u16_t chksum);
#endif /* LWIP_CHECKSUM_ON_COPY */
#define udp_flags(pcb) ((pcb)->flags)
#define udp_setflags(pcb, f) ((pcb)->flags = (f))
/* The following functions are the lower layer interface to UDP. */

View file

@ -9,6 +9,12 @@
*/
#define NO_SYS 1
/**
* NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1
* Mainly for compatibility to old versions.
*/
#define NO_SYS_NO_TIMERS 0
/**
* LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)
*/
@ -47,7 +53,25 @@
/**
* LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c
*/
#define LWIP_HAVE_LOOPIF 0
#define LWIP_HAVE_LOOPIF 1
/**
* LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP
* address equal to the netif IP address, looping them back up the stack.
*/
#define LWIP_NETIF_LOOPBACK 1
/**
* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts.
* (requires NO_SYS==0)
*/
#define MEMP_NUM_SYS_TIMEOUT 5
/**
* LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from
* application buffers to pbufs.
*/
#define LWIP_CHECKSUM_ON_COPY 1
/* DEBUG options */
#define LWIP_DEBUG 1
@ -60,5 +84,6 @@
#define IP_DEBUG LWIP_DBG_OFF
#define INET_DEBUG LWIP_DBG_OFF
#define NETIF_DEBUG LWIP_DBG_ON
#define TIMERS_DEBUG LWIP_DBG_ON
#endif

View file

@ -37,7 +37,7 @@
#include "lwip/opt.h"
#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */
#if LWIP_ARP || LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
@ -48,10 +48,6 @@
extern "C" {
#endif
#ifndef ETH_PAD_SIZE
#define ETH_PAD_SIZE 0
#endif
#ifndef ETHARP_HWADDR_LEN
#define ETHARP_HWADDR_LEN 6
#endif
@ -72,6 +68,7 @@ PACK_STRUCT_END
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** Ethernet header */
struct eth_hdr {
#if ETH_PAD_SIZE
PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);
@ -93,9 +90,12 @@ PACK_STRUCT_END
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** VLAN header inserted between ethernet header and payload
* if 'type' in ethernet header is ETHTYPE_VLAN.
* See IEEE802.Q */
struct eth_vlan_hdr {
PACK_STRUCT_FIELD(u16_t tpid);
PACK_STRUCT_FIELD(u16_t prio_vid);
PACK_STRUCT_FIELD(u16_t tpid);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
@ -111,11 +111,12 @@ PACK_STRUCT_END
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** the ARP message */
/** the ARP message, see RFC 826 ("Packet format") */
struct etharp_hdr {
PACK_STRUCT_FIELD(u16_t hwtype);
PACK_STRUCT_FIELD(u16_t proto);
PACK_STRUCT_FIELD(u16_t _hwlen_protolen);
PACK_STRUCT_FIELD(u8_t hwlen);
PACK_STRUCT_FIELD(u8_t protolen);
PACK_STRUCT_FIELD(u16_t opcode);
PACK_STRUCT_FIELD(struct eth_addr shwaddr);
PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);
@ -133,16 +134,40 @@ PACK_STRUCT_END
/** 5 seconds period */
#define ARP_TMR_INTERVAL 5000
#define ETHTYPE_ARP 0x0806
#define ETHTYPE_IP 0x0800
#define ETHTYPE_VLAN 0x8100
#define ETHTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */
#define ETHTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */
#define ETHTYPE_ARP 0x0806U
#define ETHTYPE_IP 0x0800U
#define ETHTYPE_VLAN 0x8100U
#define ETHTYPE_PPPOEDISC 0x8863U /* PPP Over Ethernet Discovery Stage */
#define ETHTYPE_PPPOE 0x8864U /* PPP Over Ethernet Session Stage */
/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables
* or known to be 32-bit aligned within the protocol header. */
#ifndef ETHADDR32_COPY
#define ETHADDR32_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN)
#endif
/** MEMCPY-like macro to copy to/from struct eth_addr's that are no local
* variables and known to be 16-bit aligned within the protocol header. */
#ifndef ETHADDR16_COPY
#define ETHADDR16_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN)
#endif
#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */
/** ARP message types (opcodes) */
#define ARP_REQUEST 1
#define ARP_REPLY 2
/** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type)
* to a filter function that returns the correct netif when using multiple
* netifs on one hardware interface where the netif's low-level receive
* routine cannot decide for the correct netif (e.g. when mapping multiple
* IP addresses to one hardware interface).
*/
#ifndef LWIP_ARP_FILTER_NETIF
#define LWIP_ARP_FILTER_NETIF 0
#endif
#if ARP_QUEUEING
/** struct for queueing outgoing packets for unknown address
* defined here to be accessed by memp.h
@ -155,38 +180,42 @@ struct etharp_q_entry {
#define etharp_init() /* Compatibility define, not init needed. */
void etharp_tmr(void);
s8_t etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr,
struct eth_addr **eth_ret, struct ip_addr **ip_ret);
void etharp_ip_input(struct netif *netif, struct pbuf *p);
void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr,
struct pbuf *p);
err_t etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr);
err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q);
err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr);
s8_t etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,
struct eth_addr **eth_ret, ip_addr_t **ip_ret);
err_t etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr);
err_t etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q);
err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr);
/** For Ethernet network interfaces, we might want to send "gratuitous ARP";
* this is an ARP packet sent by a node in order to spontaneously cause other
* nodes to update an entry in their ARP cache.
* From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */
#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr)
err_t ethernet_input(struct pbuf *p, struct netif *netif);
#if ETHARP_SUPPORT_STATIC_ENTRIES
err_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr);
err_t etharp_remove_static_entry(ip_addr_t *ipaddr);
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
#if LWIP_AUTOIP
err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
const struct eth_addr *ethdst_addr,
const struct eth_addr *hwsrc_addr, const struct ip_addr *ipsrc_addr,
const struct eth_addr *hwdst_addr, const struct ip_addr *ipdst_addr,
const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr,
const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr,
const u16_t opcode);
#endif /* LWIP_AUTOIP */
#endif /* LWIP_ARP */
err_t ethernet_input(struct pbuf *p, struct netif *netif);
#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0)
extern const struct eth_addr ethbroadcast, ethzero;
#endif /* LWIP_ARP || LWIP_ETHERNET */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_ARP */
#endif /* __NETIF_ARP_H__ */

View file

@ -74,15 +74,17 @@
#if PPPOE_SUPPORT > 0
#include "netif/etharp.h"
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct pppoehdr {
PACK_STRUCT_FIELD(u8_t vertype);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t session);
PACK_STRUCT_FIELD(u16_t plen);
PACK_STRUCT_FIELD(u8_t vertype);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t session);
PACK_STRUCT_FIELD(u16_t plen);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
@ -94,8 +96,8 @@ PACK_STRUCT_END
#endif
PACK_STRUCT_BEGIN
struct pppoetag {
PACK_STRUCT_FIELD(u16_t tag);
PACK_STRUCT_FIELD(u16_t len);
PACK_STRUCT_FIELD(u16_t tag);
PACK_STRUCT_FIELD(u16_t len);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
@ -103,45 +105,71 @@ PACK_STRUCT_END
#endif
#define PPPOE_STATE_INITIAL 0
#define PPPOE_STATE_PADI_SENT 1
#define PPPOE_STATE_PADR_SENT 2
#define PPPOE_STATE_SESSION 3
#define PPPOE_STATE_CLOSING 4
#define PPPOE_STATE_INITIAL 0
#define PPPOE_STATE_PADI_SENT 1
#define PPPOE_STATE_PADR_SENT 2
#define PPPOE_STATE_SESSION 3
#define PPPOE_STATE_CLOSING 4
/* passive */
#define PPPOE_STATE_PADO_SENT 1
#define PPPOE_STATE_PADO_SENT 1
#define PPPOE_HEADERLEN sizeof(struct pppoehdr)
#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */
#define PPPOE_HEADERLEN sizeof(struct pppoehdr)
#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */
#define PPPOE_TAG_EOL 0x0000 /* end of list */
#define PPPOE_TAG_SNAME 0x0101 /* service name */
#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */
#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */
#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */
#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */
#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */
#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */
#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */
#define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */
#define PPPOE_TAG_EOL 0x0000 /* end of list */
#define PPPOE_TAG_SNAME 0x0101 /* service name */
#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */
#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */
#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */
#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */
#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */
#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */
#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */
#define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */
#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */
#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */
#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */
#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */
#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */
#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */
#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */
#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */
#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */
#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */
#ifndef ETHERMTU
#define ETHERMTU 1500
#endif
/* two byte PPP protocol discriminator, then IP data */
#define PPPOE_MAXMTU (ETHERMTU-PPPOE_HEADERLEN-2)
#define PPPOE_MAXMTU (ETHERMTU-PPPOE_HEADERLEN-2)
struct pppoe_softc;
#ifndef PPPOE_MAX_AC_COOKIE_LEN
#define PPPOE_MAX_AC_COOKIE_LEN 64
#endif
struct pppoe_softc {
struct pppoe_softc *next;
struct netif *sc_ethif; /* ethernet interface we are using */
int sc_pd; /* ppp unit number */
void (*sc_linkStatusCB)(int pd, int up);
int sc_state; /* discovery phase or session connected */
struct eth_addr sc_dest; /* hardware address of concentrator */
u16_t sc_session; /* PPPoE session id */
#ifdef PPPOE_TODO
char *sc_service_name; /* if != NULL: requested name of service */
char *sc_concentrator_name; /* if != NULL: requested concentrator id */
#endif /* PPPOE_TODO */
u8_t sc_ac_cookie[PPPOE_MAX_AC_COOKIE_LEN]; /* content of AC cookie we must echo back */
size_t sc_ac_cookie_len; /* length of cookie data */
#ifdef PPPOE_SERVER
u8_t *sc_hunique; /* content of host unique we must echo back */
size_t sc_hunique_len; /* length of host unique */
#endif
int sc_padi_retried; /* number of PADI retries already done */
int sc_padr_retried; /* number of PADR retries already done */
};
void pppoe_init(void);
#define pppoe_init() /* compatibility define, no initialization needed */
err_t pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr);
err_t pppoe_destroy(struct netif *ifp);
@ -154,7 +182,8 @@ void pppoe_data_input(struct netif *netif, struct pbuf *p);
err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb);
extern int pppoe_hdrlen;
/** used in ppp.c */
#define PPPOE_HDRLEN (sizeof(struct eth_hdr) + PPPOE_HEADERLEN)
#endif /* PPPOE_SUPPORT */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -97,7 +97,7 @@ void auth_check_options (void);
void auth_reset (int);
/* Check peer-supplied username/password */
int check_passwd (int, char *, int, char *, int, char **, int *);
u_char check_passwd (int, char *, int, char *, int, char **, int *);
/* get "secret" for chap */
int get_secret (int, char *, char *, char *, int *, int);

View file

@ -84,19 +84,25 @@
#include <string.h>
/*************************/
/*** LOCAL DEFINITIONS ***/
/*************************/
#if 0 /* UNUSED */
/*
* Command-line options.
*/
static option_t chap_option_list[] = {
{ "chap-restart", o_int, &chap[0].timeouttime,
"Set timeout for CHAP" },
{ "chap-max-challenge", o_int, &chap[0].max_transmits,
"Set max #xmits for challenge" },
{ "chap-interval", o_int, &chap[0].chal_interval,
"Set interval for rechallenge" },
#ifdef MSLANMAN
{ "ms-lanman", o_bool, &ms_lanman,
"Use LanMan passwd when using MS-CHAP", 1 },
#endif
{ NULL }
};
#endif /* UNUSED */
/************************/
/*** LOCAL DATA TYPES ***/
/************************/
/***********************************/
/*** LOCAL FUNCTION DECLARATIONS ***/
/***********************************/
/*
* Protocol entry points.
*/
@ -105,28 +111,10 @@ static void ChapLowerUp (int);
static void ChapLowerDown (int);
static void ChapInput (int, u_char *, int);
static void ChapProtocolReject (int);
#if 0
#if PPP_ADDITIONAL_CALLBACKS
static int ChapPrintPkt (u_char *, int, void (*) (void *, char *, ...), void *);
#endif
static void ChapChallengeTimeout (void *);
static void ChapResponseTimeout (void *);
static void ChapReceiveChallenge (chap_state *, u_char *, int, int);
static void ChapRechallenge (void *);
static void ChapReceiveResponse (chap_state *, u_char *, int, int);
static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);
static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);
static void ChapSendStatus (chap_state *, int);
static void ChapSendChallenge (chap_state *);
static void ChapSendResponse (chap_state *);
static void ChapGenChallenge (chap_state *);
/******************************/
/*** PUBLIC DATA STRUCTURES ***/
/******************************/
chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
struct protent chap_protent = {
PPP_CHAP,
ChapInit,
@ -136,29 +124,57 @@ struct protent chap_protent = {
ChapLowerDown,
NULL,
NULL,
#if 0
#if PPP_ADDITIONAL_CALLBACKS
ChapPrintPkt,
NULL,
#endif
#endif /* PPP_ADDITIONAL_CALLBACKS */
1,
"CHAP",
#if 0
#if PPP_ADDITIONAL_CALLBACKS
NULL,
NULL,
NULL
#endif
#endif /* PPP_ADDITIONAL_CALLBACKS */
};
chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
static void ChapChallengeTimeout (void *);
static void ChapResponseTimeout (void *);
static void ChapReceiveChallenge (chap_state *, u_char *, u_char, int);
static void ChapRechallenge (void *);
static void ChapReceiveResponse (chap_state *, u_char *, int, int);
static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);
static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);
static void ChapSendStatus (chap_state *, int);
static void ChapSendChallenge (chap_state *);
static void ChapSendResponse (chap_state *);
static void ChapGenChallenge (chap_state *);
/*
* ChapInit - Initialize a CHAP unit.
*/
static void
ChapInit(int unit)
{
chap_state *cstate = &chap[unit];
BZERO(cstate, sizeof(*cstate));
cstate->unit = unit;
cstate->clientstate = CHAPCS_INITIAL;
cstate->serverstate = CHAPSS_INITIAL;
cstate->timeouttime = CHAP_DEFTIMEOUT;
cstate->max_transmits = CHAP_DEFTRANSMITS;
/* random number generator is initialized in magic_init */
}
/***********************************/
/*** PUBLIC FUNCTION DEFINITIONS ***/
/***********************************/
/*
* ChapAuthWithPeer - Authenticate us with our peer (start client).
*
*/
void
ChapAuthWithPeer(int unit, char *our_name, int digest)
ChapAuthWithPeer(int unit, char *our_name, u_char digest)
{
chap_state *cstate = &chap[unit];
@ -185,7 +201,7 @@ ChapAuthWithPeer(int unit, char *our_name, int digest)
* ChapAuthPeer - Authenticate our peer (start server).
*/
void
ChapAuthPeer(int unit, char *our_name, int digest)
ChapAuthPeer(int unit, char *our_name, u_char digest)
{
chap_state *cstate = &chap[unit];
@ -205,27 +221,6 @@ ChapAuthPeer(int unit, char *our_name, int digest)
}
/**********************************/
/*** LOCAL FUNCTION DEFINITIONS ***/
/**********************************/
/*
* ChapInit - Initialize a CHAP unit.
*/
static void
ChapInit(int unit)
{
chap_state *cstate = &chap[unit];
BZERO(cstate, sizeof(*cstate));
cstate->unit = unit;
cstate->clientstate = CHAPCS_INITIAL;
cstate->serverstate = CHAPSS_INITIAL;
cstate->timeouttime = CHAP_DEFTIMEOUT;
cstate->max_transmits = CHAP_DEFTRANSMITS;
/* random number generator is initialized in magic_init */
}
/*
* ChapChallengeTimeout - Timeout expired on sending challenge.
*/
@ -243,7 +238,7 @@ ChapChallengeTimeout(void *arg)
if (cstate->chal_transmits >= cstate->max_transmits) {
/* give up on peer */
CHAPDEBUG((LOG_ERR, "Peer failed to respond to CHAP challenge\n"));
CHAPDEBUG(LOG_ERR, ("Peer failed to respond to CHAP challenge\n"));
cstate->serverstate = CHAPSS_BADAUTH;
auth_peer_fail(cstate->unit, PPP_CHAP);
return;
@ -355,7 +350,7 @@ ChapProtocolReject(int unit)
}
if (cstate->clientstate != CHAPCS_INITIAL &&
cstate->clientstate != CHAPCS_CLOSED) {
auth_withpeer_fail(unit, PPP_CHAP);
auth_withpeer_fail(unit, PPP_CHAP); /* lwip: just sets the PPP error code on this unit to PPPERR_AUTHFAIL */
}
ChapLowerDown(unit); /* shutdown chap */
}
@ -378,18 +373,18 @@ ChapInput(int unit, u_char *inpacket, int packet_len)
*/
inp = inpacket;
if (packet_len < CHAP_HEADERLEN) {
CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.\n"));
CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd short header.\n"));
return;
}
GETCHAR(code, inp);
GETCHAR(id, inp);
GETSHORT(len, inp);
if (len < CHAP_HEADERLEN) {
CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.\n"));
CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd illegal length.\n"));
return;
}
if (len > packet_len) {
CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.\n"));
CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd short packet.\n"));
return;
}
len -= CHAP_HEADERLEN;
@ -415,7 +410,7 @@ ChapInput(int unit, u_char *inpacket, int packet_len)
break;
default: /* Need code reject? */
CHAPDEBUG((LOG_WARNING, "Unknown CHAP code (%d) received.\n", code));
CHAPDEBUG(LOG_WARNING, ("Unknown CHAP code (%d) received.\n", code));
break;
}
}
@ -425,7 +420,7 @@ ChapInput(int unit, u_char *inpacket, int packet_len)
* ChapReceiveChallenge - Receive Challenge and send Response.
*/
static void
ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len)
ChapReceiveChallenge(chap_state *cstate, u_char *inp, u_char id, int len)
{
int rchallenge_len;
u_char *rchallenge;
@ -434,48 +429,52 @@ ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len)
char rhostname[256];
MD5_CTX mdContext;
u_char hash[MD5_SIGNATURE_SIZE];
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.\n", id));
CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: Rcvd id %d.\n", id));
if (cstate->clientstate == CHAPCS_CLOSED ||
cstate->clientstate == CHAPCS_PENDING) {
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d\n",
CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: in state %d\n",
cstate->clientstate));
return;
}
if (len < 2) {
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));
CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: rcvd short packet.\n"));
return;
}
GETCHAR(rchallenge_len, inp);
len -= sizeof (u_char) + rchallenge_len; /* now name field length */
if (len < 0) {
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));
CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: rcvd short packet.\n"));
return;
}
rchallenge = inp;
INCPTR(rchallenge_len, inp);
if (len >= sizeof(rhostname)) {
if (len >= (int)sizeof(rhostname)) {
len = sizeof(rhostname) - 1;
}
BCOPY(inp, rhostname, len);
rhostname[len] = '\000';
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'\n", rhostname));
CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: received name field '%s'\n",
rhostname));
/* Microsoft doesn't send their name back in the PPP packet */
if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) {
strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname));
rhostname[sizeof(rhostname) - 1] = 0;
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name\n", rhostname));
CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: using '%s' as remote name\n",
rhostname));
}
/* get secret for authenticating ourselves with the specified host */
if (!get_secret(cstate->unit, cstate->resp_name, rhostname, secret, &secret_len, 0)) {
if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
secret, &secret_len, 0)) {
secret_len = 0; /* assume null secret if can't find one */
CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating us to %s\n", rhostname));
CHAPDEBUG(LOG_WARNING, ("No CHAP secret found for authenticating us to %s\n",
rhostname));
}
/* cancel response send timeout if necessary */
@ -499,14 +498,14 @@ ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len)
cstate->resp_length = MD5_SIGNATURE_SIZE;
break;
#ifdef CHAPMS
#if MSCHAP_SUPPORT
case CHAP_MICROSOFT:
ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
break;
#endif
default:
CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->resp_type));
CHAPDEBUG(LOG_INFO, ("unknown digest type %d\n", cstate->resp_type));
return;
}
@ -528,12 +527,12 @@ ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
MD5_CTX mdContext;
char secret[MAXSECRETLEN];
u_char hash[MD5_SIGNATURE_SIZE];
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.\n", id));
CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: Rcvd id %d.\n", id));
if (cstate->serverstate == CHAPSS_CLOSED ||
cstate->serverstate == CHAPSS_PENDING) {
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d\n",
CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: in state %d\n",
cstate->serverstate));
return;
}
@ -557,7 +556,7 @@ ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
}
if (len < 2) {
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));
CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: rcvd short packet.\n"));
return;
}
GETCHAR(remmd_len, inp); /* get length of MD */
@ -566,29 +565,30 @@ ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
len -= sizeof (u_char) + remmd_len;
if (len < 0) {
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));
CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: rcvd short packet.\n"));
return;
}
UNTIMEOUT(ChapChallengeTimeout, cstate);
if (len >= sizeof(rhostname)) {
if (len >= (int)sizeof(rhostname)) {
len = sizeof(rhostname) - 1;
}
BCOPY(inp, rhostname, len);
rhostname[len] = '\000';
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s\n", rhostname));
CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: received name field: %s\n",
rhostname));
/*
* Get secret for authenticating them with us,
* do the hash ourselves, and compare the result.
*/
code = CHAP_FAILURE;
if (!get_secret(cstate->unit, rhostname, cstate->chal_name, secret, &secret_len, 1)) {
/* CHAPDEBUG((LOG_WARNING, TL_CHAP, "No CHAP secret found for authenticating %s\n", rhostname)); */
CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating %s\n",
rhostname));
if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
secret, &secret_len, 1)) {
CHAPDEBUG(LOG_WARNING, ("No CHAP secret found for authenticating %s\n",
rhostname));
} else {
/* generate MD based on negotiated type */
switch (cstate->chal_type) {
@ -610,7 +610,7 @@ ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
break;
default:
CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->chal_type));
CHAPDEBUG(LOG_INFO, ("unknown digest type %d\n", cstate->chal_type));
}
}
@ -627,7 +627,7 @@ ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
}
} else {
CHAPDEBUG((LOG_ERR, "CHAP peer authentication failed\n"));
CHAPDEBUG(LOG_ERR, ("CHAP peer authentication failed\n"));
cstate->serverstate = CHAPSS_BADAUTH;
auth_peer_fail(cstate->unit, PPP_CHAP);
}
@ -642,7 +642,7 @@ ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len)
LWIP_UNUSED_ARG(id);
LWIP_UNUSED_ARG(inp);
CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.\n", id));
CHAPDEBUG(LOG_INFO, ("ChapReceiveSuccess: Rcvd id %d.\n", id));
if (cstate->clientstate == CHAPCS_OPEN) {
/* presumably an answer to a duplicate response */
@ -651,7 +651,8 @@ ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len)
if (cstate->clientstate != CHAPCS_RESPONSE) {
/* don't know what this is */
CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n", cstate->clientstate));
CHAPDEBUG(LOG_INFO, ("ChapReceiveSuccess: in state %d\n",
cstate->clientstate));
return;
}
@ -679,11 +680,12 @@ ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)
LWIP_UNUSED_ARG(id);
LWIP_UNUSED_ARG(inp);
CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.\n", id));
CHAPDEBUG(LOG_INFO, ("ChapReceiveFailure: Rcvd id %d.\n", id));
if (cstate->clientstate != CHAPCS_RESPONSE) {
/* don't know what this is */
CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n", cstate->clientstate));
CHAPDEBUG(LOG_INFO, ("ChapReceiveFailure: in state %d\n",
cstate->clientstate));
return;
}
@ -696,8 +698,8 @@ ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)
PRINTMSG(inp, len);
}
CHAPDEBUG((LOG_ERR, "CHAP authentication failed\n"));
auth_withpeer_fail(cstate->unit, PPP_CHAP);
CHAPDEBUG(LOG_ERR, ("CHAP authentication failed\n"));
auth_withpeer_fail(cstate->unit, PPP_CHAP); /* lwip: just sets the PPP error code on this unit to PPPERR_AUTHFAIL */
}
@ -712,25 +714,25 @@ ChapSendChallenge(chap_state *cstate)
int outlen;
chal_len = cstate->chal_len;
name_len = strlen(cstate->chal_name);
name_len = (int)strlen(cstate->chal_name);
outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
outp = outpacket_buf[cstate->unit];
MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */
PUTCHAR(CHAP_CHALLENGE, outp);
PUTCHAR(cstate->chal_id, outp);
PUTSHORT(outlen, outp);
PUTCHAR(chal_len, outp); /* put length of challenge */
BCOPY(cstate->challenge, outp, chal_len);
INCPTR(chal_len, outp);
BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.\n", cstate->chal_id));
CHAPDEBUG(LOG_INFO, ("ChapSendChallenge: Sent id %d.\n", cstate->chal_id));
TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
++cstate->chal_transmits;
@ -745,18 +747,18 @@ ChapSendStatus(chap_state *cstate, int code)
{
u_char *outp;
int outlen, msglen;
char msg[256];
char msg[256]; /* @todo: this can be a char*, no strcpy needed */
if (code == CHAP_SUCCESS) {
strcpy(msg, "Welcome!");
} else {
strcpy(msg, "I don't like you. Go 'way.");
}
msglen = strlen(msg);
msglen = (int)strlen(msg);
outlen = CHAP_HEADERLEN + msglen;
outp = outpacket_buf[cstate->unit];
MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
PUTCHAR(code, outp);
@ -764,8 +766,9 @@ ChapSendStatus(chap_state *cstate, int code)
PUTSHORT(outlen, outp);
BCOPY(msg, outp, msglen);
pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.\n", code, cstate->chal_id));
CHAPDEBUG(LOG_INFO, ("ChapSendStatus: Sent code %d, id %d.\n", code,
cstate->chal_id));
}
/*
@ -781,17 +784,18 @@ ChapGenChallenge(chap_state *cstate)
int chal_len;
u_char *ptr = cstate->challenge;
int i;
/* pick a random challenge length between MIN_CHALLENGE_LENGTH and
MAX_CHALLENGE_LENGTH */
chal_len = (unsigned)
((((magic() >> 16) *
(MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16)
+ MIN_CHALLENGE_LENGTH);
cstate->chal_len = chal_len;
LWIP_ASSERT("chal_len <= 0xff", chal_len <= 0xffff);
cstate->chal_len = (u_char)chal_len;
cstate->chal_id = ++cstate->id;
cstate->chal_transmits = 0;
/* generate a random string */
for (i = 0; i < chal_len; i++ ) {
*ptr++ = (char) (magic() & 0xff);
@ -808,12 +812,12 @@ ChapSendResponse(chap_state *cstate)
{
u_char *outp;
int outlen, md_len, name_len;
md_len = cstate->resp_length;
name_len = strlen(cstate->resp_name);
name_len = (int)strlen(cstate->resp_name);
outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
outp = outpacket_buf[cstate->unit];
MAKEHEADER(outp, PPP_CHAP);
PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
@ -823,18 +827,18 @@ ChapSendResponse(chap_state *cstate)
PUTCHAR(md_len, outp); /* length of MD */
BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */
INCPTR(md_len, outp);
BCOPY(cstate->resp_name, outp, name_len); /* append our name */
/* send the packet */
pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
cstate->clientstate = CHAPCS_RESPONSE;
TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
++cstate->resp_transmits;
}
#if 0
#if PPP_ADDITIONAL_CALLBACKS
static char *ChapCodenames[] = {
"Challenge", "Response", "Success", "Failure"
};
@ -847,7 +851,7 @@ ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *
int code, id, len;
int clen, nlen;
u_char x;
if (plen < CHAP_HEADERLEN) {
return 0;
}
@ -857,6 +861,7 @@ ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *
if (len < CHAP_HEADERLEN || len > plen) {
return 0;
}
if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) {
printer(arg, " %s", ChapCodenames[code-1]);
} else {
@ -896,7 +901,7 @@ ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *
return len + CHAP_HEADERLEN;
}
#endif
#endif /* PPP_ADDITIONAL_CALLBACKS */
#endif /* CHAP_SUPPORT */

View file

@ -62,16 +62,12 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: chap.h,v 1.4 2007/12/19 20:47:22 fbernon Exp $
* $Id: chap.h,v 1.6 2010/01/24 13:19:34 goldsimon Exp $
*/
#ifndef CHAP_H
#define CHAP_H
/*************************
*** PUBLIC DEFINITIONS ***
*************************/
/* Code + ID + length */
#define CHAP_HEADERLEN 4
@ -96,31 +92,6 @@
#define MAX_CHALLENGE_LENGTH 64
#define MAX_RESPONSE_LENGTH 64 /* sufficient for MD5 or MS-CHAP */
/*
* Client (peer) states.
*/
#define CHAPCS_INITIAL 0 /* Lower layer down, not opened */
#define CHAPCS_CLOSED 1 /* Lower layer up, not opened */
#define CHAPCS_PENDING 2 /* Auth us to peer when lower up */
#define CHAPCS_LISTEN 3 /* Listening for a challenge */
#define CHAPCS_RESPONSE 4 /* Sent response, waiting for status */
#define CHAPCS_OPEN 5 /* We've received Success */
/*
* Server (authenticator) states.
*/
#define CHAPSS_INITIAL 0 /* Lower layer down, not opened */
#define CHAPSS_CLOSED 1 /* Lower layer up, not opened */
#define CHAPSS_PENDING 2 /* Auth peer when lower up */
#define CHAPSS_INITIAL_CHAL 3 /* We've sent the first challenge */
#define CHAPSS_OPEN 4 /* We've sent a Success msg */
#define CHAPSS_RECHALLENGE 5 /* We've sent another challenge */
#define CHAPSS_BADAUTH 6 /* We've sent a Failure msg */
/************************
*** PUBLIC DATA TYPES ***
************************/
/*
* Each interface is described by a chap structure.
*/
@ -148,19 +119,32 @@ typedef struct chap_state {
} chap_state;
/******************
*** PUBLIC DATA ***
******************/
/*
* Client (peer) states.
*/
#define CHAPCS_INITIAL 0 /* Lower layer down, not opened */
#define CHAPCS_CLOSED 1 /* Lower layer up, not opened */
#define CHAPCS_PENDING 2 /* Auth us to peer when lower up */
#define CHAPCS_LISTEN 3 /* Listening for a challenge */
#define CHAPCS_RESPONSE 4 /* Sent response, waiting for status */
#define CHAPCS_OPEN 5 /* We've received Success */
/*
* Server (authenticator) states.
*/
#define CHAPSS_INITIAL 0 /* Lower layer down, not opened */
#define CHAPSS_CLOSED 1 /* Lower layer up, not opened */
#define CHAPSS_PENDING 2 /* Auth peer when lower up */
#define CHAPSS_INITIAL_CHAL 3 /* We've sent the first challenge */
#define CHAPSS_OPEN 4 /* We've sent a Success msg */
#define CHAPSS_RECHALLENGE 5 /* We've sent another challenge */
#define CHAPSS_BADAUTH 6 /* We've sent a Failure msg */
extern chap_state chap[];
void ChapAuthWithPeer (int, char *, u_char);
void ChapAuthPeer (int, char *, u_char);
extern struct protent chap_protent;
/***********************
*** PUBLIC FUNCTIONS ***
***********************/
void ChapAuthWithPeer (int, char *, int);
void ChapAuthPeer (int, char *, int);
#endif /* CHAP_H */

View file

@ -85,6 +85,8 @@
#include "chap.h"
#include "chpms.h"
#include <string.h>
/*************************/
/*** LOCAL DEFINITIONS ***/
@ -137,49 +139,12 @@ static u_char Get7Bits(
int startBit
);
/***********************************/
/*** PUBLIC FUNCTION DEFINITIONS ***/
/***********************************/
void
ChapMS( chap_state *cstate, char *rchallenge, int rchallenge_len, char *secret, int secret_len)
{
MS_ChapResponse response;
#ifdef MSLANMAN
extern int ms_lanman;
#endif
#if 0
CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'\n", secret_len, secret));
#endif
BZERO(&response, sizeof(response));
/* Calculate both always */
ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
#ifdef MSLANMAN
ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
/* prefered method is set by option */
response.UseNT = !ms_lanman;
#else
response.UseNT = 1;
#endif
BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
cstate->resp_length = MS_CHAP_RESPONSE_LEN;
}
/**********************************/
/*** LOCAL FUNCTION DEFINITIONS ***/
/**********************************/
static void
ChallengeResponse( u_char *challenge, /* IN 8 octets */
u_char *pwHash, /* IN 16 octets */
u_char *response /* OUT 24 octets */)
{
char ZPasswordHash[21];
u_char ZPasswordHash[21];
BZERO(ZPasswordHash, sizeof(ZPasswordHash));
BCOPY(pwHash, ZPasswordHash, 16);
@ -211,19 +176,19 @@ DesEncrypt( u_char *clear, /* IN 8 octets */
MakeKey(key, des_key);
Expand(des_key, crypt_key);
setkey(crypt_key);
setkey((char*)crypt_key);
#if 0
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
#endif
Expand(clear, des_input);
encrypt(des_input, 0);
encrypt((char*)des_input, 0);
Collapse(des_input, cipher);
#if 0
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
#endif
}
@ -243,14 +208,14 @@ DesEncrypt( u_char *clear, /* IN 8 octets */
des_set_key(&des_key, key_schedule);
#if 0
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
#endif
des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
#if 0
CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
#endif
}
@ -329,9 +294,9 @@ MakeKey( u_char *key, /* IN 56 bit DES key missing parity bits */
#endif
#if 0
CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n",
CHAPDEBUG(LOG_INFO, ("MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n",
key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
CHAPDEBUG(LOG_INFO, ("MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
#endif
}
@ -348,6 +313,8 @@ ChapMS_NT( char *rchallenge,
u_char unicodePassword[MAX_NT_PASSWORD * 2];
static int low_byte_first = -1;
LWIP_UNUSED_ARG(rchallenge_len);
/* Initialize the Unicode version of the secret (== password). */
/* This implicitly supports 8-bit ISO8859/1 characters. */
BZERO(unicodePassword, sizeof(unicodePassword));
@ -358,15 +325,16 @@ ChapMS_NT( char *rchallenge,
MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8); /* Unicode is 2 bytes/char, *8 for bit count */
if (low_byte_first == -1) {
low_byte_first = (htons((unsigned short int)1) != 1);
low_byte_first = (PP_HTONS((unsigned short int)1) != 1);
}
if (low_byte_first == 0) {
MDreverse((u_long *)&md4Context); /* sfb 961105 */
/* @todo: arg type - u_long* or u_int* ? */
MDreverse((unsigned int*)&md4Context); /* sfb 961105 */
}
MDupdate(&md4Context, NULL, 0); /* Tell MD4 we're done */
ChallengeResponse(rchallenge, (char *)md4Context.buffer, response->NTResp);
ChallengeResponse((u_char*)rchallenge, (u_char*)md4Context.buffer, response->NTResp);
}
#ifdef MSLANMAN
@ -394,6 +362,35 @@ ChapMS_LANMan( char *rchallenge,
}
#endif
void
ChapMS( chap_state *cstate, char *rchallenge, int rchallenge_len, char *secret, int secret_len)
{
MS_ChapResponse response;
#ifdef MSLANMAN
extern int ms_lanman;
#endif
#if 0
CHAPDEBUG(LOG_INFO, ("ChapMS: secret is '%.*s'\n", secret_len, secret));
#endif
BZERO(&response, sizeof(response));
/* Calculate both always */
ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
#ifdef MSLANMAN
ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
/* prefered method is set by option */
response.UseNT = !ms_lanman;
#else
response.UseNT = 1;
#endif
BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
cstate->resp_length = MS_CHAP_RESPONSE_LEN;
}
#endif /* MSCHAP_SUPPORT */
#endif /* PPP_SUPPORT */

View file

@ -66,13 +66,7 @@
#include <string.h>
/*************************/
/*** LOCAL DEFINITIONS ***/
/*************************/
#if PPP_DEBUG
static const char *ppperr_strerr[] = {
"LS_INITIAL", /* LS_INITIAL 0 */
"LS_STARTING", /* LS_STARTING 1 */
@ -85,17 +79,8 @@ static const char *ppperr_strerr[] = {
"LS_ACKSENT", /* LS_ACKSENT 8 */
"LS_OPENED" /* LS_OPENED 9 */
};
#endif /* PPP_DEBUG */
/************************/
/*** LOCAL DATA TYPES ***/
/************************/
/***********************************/
/*** LOCAL FUNCTION DECLARATIONS ***/
/***********************************/
static void fsm_timeout (void *);
static void fsm_rconfreq (fsm *, u_char, u_char *, int);
static void fsm_rconfack (fsm *, int, u_char *, int);
@ -107,22 +92,9 @@ static void fsm_sconfreq (fsm *, int);
#define PROTO_NAME(f) ((f)->callbacks->proto_name)
/******************************/
/*** PUBLIC DATA STRUCTURES ***/
/******************************/
/*****************************/
/*** LOCAL DATA STRUCTURES ***/
/*****************************/
int peer_mru[NUM_PPP];
/***********************************/
/*** PUBLIC FUNCTION DEFINITIONS ***/
/***********************************/
/*
* fsm_init - Initialize fsm.
*
@ -168,11 +140,11 @@ fsm_lowerup(fsm *f)
break;
default:
FSMDEBUG((LOG_INFO, "%s: Up event in state %d (%s)!\n",
FSMDEBUG(LOG_INFO, ("%s: Up event in state %d (%s)!\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
}
FSMDEBUG((LOG_INFO, "%s: lowerup state %d (%s) -> %d (%s)\n",
FSMDEBUG(LOG_INFO, ("%s: lowerup state %d (%s) -> %d (%s)\n",
PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
}
@ -222,11 +194,11 @@ fsm_lowerdown(fsm *f)
break;
default:
FSMDEBUG((LOG_INFO, "%s: Down event in state %d (%s)!\n",
FSMDEBUG(LOG_INFO, ("%s: Down event in state %d (%s)!\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
}
FSMDEBUG((LOG_INFO, "%s: lowerdown state %d (%s) -> %d (%s)\n",
FSMDEBUG(LOG_INFO, ("%s: lowerdown state %d (%s) -> %d (%s)\n",
PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
}
@ -271,10 +243,23 @@ fsm_open(fsm *f)
break;
}
FSMDEBUG((LOG_INFO, "%s: open state %d (%s) -> %d (%s)\n",
FSMDEBUG(LOG_INFO, ("%s: open state %d (%s) -> %d (%s)\n",
PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
}
#if 0 /* backport pppd 2.4.4b1; */
/*
* terminate_layer - Start process of shutting down the FSM
*
* Cancel any timeout running, notify upper layers we're done, and
* send a terminate-request message as configured.
*/
static void
terminate_layer(fsm *f, int nextstate)
{
/* @todo */
}
#endif
/*
* fsm_close - Start closing connection.
@ -290,7 +275,7 @@ fsm_close(fsm *f, char *reason)
LWIP_UNUSED_ARG(oldState);
f->term_reason = reason;
f->term_reason_len = (reason == NULL? 0: strlen(reason));
f->term_reason_len = (reason == NULL ? 0 : (int)strlen(reason));
switch( f->state ) {
case LS_STARTING:
f->state = LS_INITIAL;
@ -322,38 +307,71 @@ fsm_close(fsm *f, char *reason)
break;
}
FSMDEBUG((LOG_INFO, "%s: close reason=%s state %d (%s) -> %d (%s)\n",
FSMDEBUG(LOG_INFO, ("%s: close reason=%s state %d (%s) -> %d (%s)\n",
PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
}
/*
* fsm_sdata - Send some data.
*
* Used for all packets sent to our peer by this module.
* fsm_timeout - Timeout expired.
*/
void
fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen)
static void
fsm_timeout(void *arg)
{
u_char *outp;
int outlen;
fsm *f = (fsm *) arg;
/* Adjust length to be smaller than MTU */
outp = outpacket_buf[f->unit];
if (datalen > peer_mru[f->unit] - (int)HEADERLEN) {
datalen = peer_mru[f->unit] - HEADERLEN;
switch (f->state) {
case LS_CLOSING:
case LS_STOPPING:
if( f->retransmits <= 0 ) {
FSMDEBUG(LOG_WARNING, ("%s: timeout sending Terminate-Request state=%d (%s)\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
/*
* We've waited for an ack long enough. Peer probably heard us.
*/
f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED;
if( f->callbacks->finished ) {
(*f->callbacks->finished)(f);
}
} else {
FSMDEBUG(LOG_WARNING, ("%s: timeout resending Terminate-Requests state=%d (%s)\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
/* Send Terminate-Request */
fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
(u_char *) f->term_reason, f->term_reason_len);
TIMEOUT(fsm_timeout, f, f->timeouttime);
--f->retransmits;
}
break;
case LS_REQSENT:
case LS_ACKRCVD:
case LS_ACKSENT:
if (f->retransmits <= 0) {
FSMDEBUG(LOG_WARNING, ("%s: timeout sending Config-Requests state=%d (%s)\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
f->state = LS_STOPPED;
if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) {
(*f->callbacks->finished)(f);
}
} else {
FSMDEBUG(LOG_WARNING, ("%s: timeout resending Config-Request state=%d (%s)\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
/* Retransmit the configure-request */
if (f->callbacks->retransmit) {
(*f->callbacks->retransmit)(f);
}
fsm_sconfreq(f, 1); /* Re-send Configure-Request */
if( f->state == LS_ACKRCVD ) {
f->state = LS_REQSENT;
}
}
break;
default:
FSMDEBUG(LOG_INFO, ("%s: UNHANDLED timeout event in state %d (%s)!\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
}
if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) {
BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
}
outlen = datalen + HEADERLEN;
MAKEHEADER(outp, f->protocol);
PUTCHAR(code, outp);
PUTCHAR(id, outp);
PUTSHORT(outlen, outp);
pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);
FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d,%d,%d.\n",
PROTO_NAME(f), code, id, outlen));
}
@ -372,7 +390,7 @@ fsm_input(fsm *f, u_char *inpacket, int l)
* If packet too short, drop it.
*/
if (l < HEADERLEN) {
FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.\n",
FSMDEBUG(LOG_WARNING, ("fsm_input(%x): Rcvd short header.\n",
f->protocol));
return;
}
@ -380,23 +398,23 @@ fsm_input(fsm *f, u_char *inpacket, int l)
GETCHAR(id, inp);
GETSHORT(len, inp);
if (len < HEADERLEN) {
FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.\n",
FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd illegal length.\n",
f->protocol));
return;
}
if (len > l) {
FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.\n",
FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd short packet.\n",
f->protocol));
return;
}
len -= HEADERLEN; /* subtract header length */
if( f->state == LS_INITIAL || f->state == LS_STARTING ) {
FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d (%s).\n",
FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd packet in state %d (%s).\n",
f->protocol, f->state, ppperr_strerr[f->state]));
return;
}
FSMDEBUG((LOG_INFO, "fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));
FSMDEBUG(LOG_INFO, ("fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));
/*
* Action depends on code.
*/
@ -427,6 +445,7 @@ fsm_input(fsm *f, u_char *inpacket, int l)
break;
default:
FSMDEBUG(LOG_INFO, ("fsm_input(%s): default: \n", PROTO_NAME(f)));
if( !f->callbacks->extcode ||
!(*f->callbacks->extcode)(f, code, id, inp, len) ) {
fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
@ -436,129 +455,6 @@ fsm_input(fsm *f, u_char *inpacket, int l)
}
/*
* fsm_protreject - Peer doesn't speak this protocol.
*
* Treat this as a catastrophic error (RXJ-).
*/
void
fsm_protreject(fsm *f)
{
switch( f->state ) {
case LS_CLOSING:
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
/* fall through */
case LS_CLOSED:
f->state = LS_CLOSED;
if( f->callbacks->finished ) {
(*f->callbacks->finished)(f);
}
break;
case LS_STOPPING:
case LS_REQSENT:
case LS_ACKRCVD:
case LS_ACKSENT:
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
/* fall through */
case LS_STOPPED:
f->state = LS_STOPPED;
if( f->callbacks->finished ) {
(*f->callbacks->finished)(f);
}
break;
case LS_OPENED:
if( f->callbacks->down ) {
(*f->callbacks->down)(f);
}
/* Init restart counter, send Terminate-Request */
f->retransmits = f->maxtermtransmits;
fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
(u_char *) f->term_reason, f->term_reason_len);
TIMEOUT(fsm_timeout, f, f->timeouttime);
--f->retransmits;
f->state = LS_STOPPING;
break;
default:
FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d (%s)!\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
}
}
/**********************************/
/*** LOCAL FUNCTION DEFINITIONS ***/
/**********************************/
/*
* fsm_timeout - Timeout expired.
*/
static void
fsm_timeout(void *arg)
{
fsm *f = (fsm *) arg;
switch (f->state) {
case LS_CLOSING:
case LS_STOPPING:
if( f->retransmits <= 0 ) {
FSMDEBUG((LOG_WARNING, "%s: timeout sending Terminate-Request state=%d (%s)\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
/*
* We've waited for an ack long enough. Peer probably heard us.
*/
f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED;
if( f->callbacks->finished ) {
(*f->callbacks->finished)(f);
}
} else {
FSMDEBUG((LOG_WARNING, "%s: timeout resending Terminate-Requests state=%d (%s)\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
/* Send Terminate-Request */
fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
(u_char *) f->term_reason, f->term_reason_len);
TIMEOUT(fsm_timeout, f, f->timeouttime);
--f->retransmits;
}
break;
case LS_REQSENT:
case LS_ACKRCVD:
case LS_ACKSENT:
if (f->retransmits <= 0) {
FSMDEBUG((LOG_WARNING, "%s: timeout sending Config-Requests state=%d (%s)\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
f->state = LS_STOPPED;
if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) {
(*f->callbacks->finished)(f);
}
} else {
FSMDEBUG((LOG_WARNING, "%s: timeout resending Config-Request state=%d (%s)\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
/* Retransmit the configure-request */
if (f->callbacks->retransmit) {
(*f->callbacks->retransmit)(f);
}
fsm_sconfreq(f, 1); /* Re-send Configure-Request */
if( f->state == LS_ACKRCVD ) {
f->state = LS_REQSENT;
}
}
break;
default:
FSMDEBUG((LOG_INFO, "%s: UNHANDLED timeout event in state %d (%s)!\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
}
}
/*
* fsm_rconfreq - Receive Configure-Request.
*/
@ -567,7 +463,7 @@ fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)
{
int code, reject_if_disagree;
FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n",
FSMDEBUG(LOG_INFO, ("fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n",
PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
switch( f->state ) {
case LS_CLOSED:
@ -638,7 +534,7 @@ fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)
static void
fsm_rconfack(fsm *f, int id, u_char *inp, int len)
{
FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n",
FSMDEBUG(LOG_INFO, ("fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n",
PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
if (id != f->reqid || f->seen_ack) { /* Expected id? */
@ -646,7 +542,7 @@ fsm_rconfack(fsm *f, int id, u_char *inp, int len)
}
if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ) {
/* Ack is bad - ignore it */
FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)\n",
FSMDEBUG(LOG_INFO, ("%s: received bad Ack (length %d)\n",
PROTO_NAME(f), len));
return;
}
@ -700,7 +596,7 @@ fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)
int (*proc) (fsm *, u_char *, int);
int ret;
FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n",
FSMDEBUG(LOG_INFO, ("fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n",
PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
if (id != f->reqid || f->seen_ack) { /* Expected id? */
@ -709,7 +605,7 @@ fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)
proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
if (!proc || !((ret = proc(f, inp, len)))) {
/* Nak/reject is bad - ignore it */
FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)\n",
FSMDEBUG(LOG_INFO, ("%s: received bad %s (length %d)\n",
PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
return;
}
@ -759,7 +655,7 @@ fsm_rtermreq(fsm *f, int id, u_char *p, int len)
{
LWIP_UNUSED_ARG(p);
FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n",
FSMDEBUG(LOG_INFO, ("fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n",
PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
switch (f->state) {
@ -770,9 +666,9 @@ fsm_rtermreq(fsm *f, int id, u_char *p, int len)
case LS_OPENED:
if (len > 0) {
FSMDEBUG((LOG_INFO, "%s terminated by peer (%x)\n", PROTO_NAME(f), p));
FSMDEBUG(LOG_INFO, ("%s terminated by peer (%p)\n", PROTO_NAME(f), p));
} else {
FSMDEBUG((LOG_INFO, "%s terminated by peer\n", PROTO_NAME(f)));
FSMDEBUG(LOG_INFO, ("%s terminated by peer\n", PROTO_NAME(f)));
}
if (f->callbacks->down) {
(*f->callbacks->down)(f); /* Inform upper layers */
@ -793,7 +689,7 @@ fsm_rtermreq(fsm *f, int id, u_char *p, int len)
static void
fsm_rtermack(fsm *f)
{
FSMDEBUG((LOG_INFO, "fsm_rtermack(%s): state=%d (%s)\n",
FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): state=%d (%s)\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
switch (f->state) {
@ -823,6 +719,9 @@ fsm_rtermack(fsm *f)
}
fsm_sconfreq(f, 0);
break;
default:
FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): UNHANDLED state=%d (%s)!!!\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
}
}
@ -835,16 +734,16 @@ fsm_rcoderej(fsm *f, u_char *inp, int len)
{
u_char code, id;
FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s): state=%d (%s)\n",
FSMDEBUG(LOG_INFO, ("fsm_rcoderej(%s): state=%d (%s)\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
if (len < HEADERLEN) {
FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!\n"));
FSMDEBUG(LOG_INFO, ("fsm_rcoderej: Rcvd short Code-Reject packet!\n"));
return;
}
GETCHAR(code, inp);
GETCHAR(id, inp);
FSMDEBUG((LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d\n",
FSMDEBUG(LOG_WARNING, ("%s: Rcvd Code-Reject for code %d, id %d\n",
PROTO_NAME(f), code, id));
if( f->state == LS_ACKRCVD ) {
@ -853,6 +752,59 @@ fsm_rcoderej(fsm *f, u_char *inp, int len)
}
/*
* fsm_protreject - Peer doesn't speak this protocol.
*
* Treat this as a catastrophic error (RXJ-).
*/
void
fsm_protreject(fsm *f)
{
switch( f->state ) {
case LS_CLOSING:
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
/* fall through */
case LS_CLOSED:
f->state = LS_CLOSED;
if( f->callbacks->finished ) {
(*f->callbacks->finished)(f);
}
break;
case LS_STOPPING:
case LS_REQSENT:
case LS_ACKRCVD:
case LS_ACKSENT:
UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
/* fall through */
case LS_STOPPED:
f->state = LS_STOPPED;
if( f->callbacks->finished ) {
(*f->callbacks->finished)(f);
}
break;
case LS_OPENED:
if( f->callbacks->down ) {
(*f->callbacks->down)(f);
}
/* Init restart counter, send Terminate-Request */
f->retransmits = f->maxtermtransmits;
fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
(u_char *) f->term_reason, f->term_reason_len);
TIMEOUT(fsm_timeout, f, f->timeouttime);
--f->retransmits;
f->state = LS_STOPPING;
break;
default:
FSMDEBUG(LOG_INFO, ("%s: Protocol-reject event in state %d (%s)!\n",
PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
}
}
/*
* fsm_sconfreq - Send a Configure-Request.
*/
@ -901,8 +853,38 @@ fsm_sconfreq(fsm *f, int retransmit)
--f->retransmits;
TIMEOUT(fsm_timeout, f, f->timeouttime);
FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d\n",
FSMDEBUG(LOG_INFO, ("%s: sending Configure-Request, id %d\n",
PROTO_NAME(f), f->reqid));
}
/*
* fsm_sdata - Send some data.
*
* Used for all packets sent to our peer by this module.
*/
void
fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen)
{
u_char *outp;
int outlen;
/* Adjust length to be smaller than MTU */
outp = outpacket_buf[f->unit];
if (datalen > peer_mru[f->unit] - (int)HEADERLEN) {
datalen = peer_mru[f->unit] - HEADERLEN;
}
if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) {
BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
}
outlen = datalen + HEADERLEN;
MAKEHEADER(outp, f->protocol);
PUTCHAR(code, outp);
PUTCHAR(id, outp);
PUTSHORT(outlen, outp);
pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);
FSMDEBUG(LOG_INFO, ("fsm_sdata(%s): Sent code %d,%d,%d.\n",
PROTO_NAME(f), code, id, outlen));
}
#endif /* PPP_SUPPORT */

View file

@ -48,15 +48,12 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: fsm.h,v 1.4 2007/12/19 20:47:23 fbernon Exp $
* $Id: fsm.h,v 1.5 2009/12/31 17:08:08 goldsimon Exp $
*/
#ifndef FSM_H
#define FSM_H
/*****************************************************************************
************************* PUBLIC DEFINITIONS *********************************
*****************************************************************************/
/*
* LCP Packet header = Code, id, length.
*/
@ -74,31 +71,7 @@
#define TERMACK 6 /* Termination Ack */
#define CODEREJ 7 /* Code Reject */
/*
* Link states.
*/
#define LS_INITIAL 0 /* Down, hasn't been opened */
#define LS_STARTING 1 /* Down, been opened */
#define LS_CLOSED 2 /* Up, hasn't been opened */
#define LS_STOPPED 3 /* Open, waiting for down event */
#define LS_CLOSING 4 /* Terminating the connection, not open */
#define LS_STOPPING 5 /* Terminating, but open */
#define LS_REQSENT 6 /* We've sent a Config Request */
#define LS_ACKRCVD 7 /* We've received a Config Ack */
#define LS_ACKSENT 8 /* We've sent a Config Ack */
#define LS_OPENED 9 /* Connection available */
/*
* Flags - indicate options controlling FSM operation
*/
#define OPT_PASSIVE 1 /* Don't die if we don't get a response */
#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */
#define OPT_SILENT 4 /* Wait for peer to speak first */
/*****************************************************************************
************************* PUBLIC DATA TYPES **********************************
*****************************************************************************/
/*
* Each FSM is described by an fsm structure and fsm callbacks.
*/
@ -141,18 +114,27 @@ typedef struct fsm_callbacks {
} fsm_callbacks;
/*****************************************************************************
*********************** PUBLIC DATA STRUCTURES *******************************
*****************************************************************************/
/*
* Variables
* Link states.
*/
extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */
#define LS_INITIAL 0 /* Down, hasn't been opened */
#define LS_STARTING 1 /* Down, been opened */
#define LS_CLOSED 2 /* Up, hasn't been opened */
#define LS_STOPPED 3 /* Open, waiting for down event */
#define LS_CLOSING 4 /* Terminating the connection, not open */
#define LS_STOPPING 5 /* Terminating, but open */
#define LS_REQSENT 6 /* We've sent a Config Request */
#define LS_ACKRCVD 7 /* We've received a Config Ack */
#define LS_ACKSENT 8 /* We've sent a Config Ack */
#define LS_OPENED 9 /* Connection available */
/*
* Flags - indicate options controlling FSM operation
*/
#define OPT_PASSIVE 1 /* Don't die if we don't get a response */
#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */
#define OPT_SILENT 4 /* Wait for peer to speak first */
/*****************************************************************************
************************** PUBLIC FUNCTIONS **********************************
*****************************************************************************/
/*
* Prototypes
@ -166,4 +148,10 @@ void fsm_input (fsm*, u_char*, int);
void fsm_protreject (fsm*);
void fsm_sdata (fsm*, u_char, u_char, u_char*, int);
/*
* Variables
*/
extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */
#endif /* FSM_H */

Some files were not shown because too many files have changed in this diff Show more