Merged lwip 2.0.1 stable to mbed-os

* commit '61a7b15741c964dfa1f1a14244de38ea4e2ce22a':
  Squashed 'features/FEATURE_LWIP/lwip-interface/lwip/' changes from d7a6c6d..10f93f4
pull/3721/head
Mika Leppänen 2017-02-21 14:27:32 +02:00
commit b62df0033f
214 changed files with 12921 additions and 4709 deletions

View File

@ -1,4 +1,6 @@
/doc/doxygen/output
*.o
*.a
/doc/doxygen/output/html
/src/apps/snmp/LwipMibCompiler/CCodeGeneration/bin/
/src/apps/snmp/LwipMibCompiler/CCodeGeneration/obj/
/src/apps/snmp/LwipMibCompiler/LwipMibCompiler/bin/
@ -11,3 +13,6 @@
/src/apps/snmp/LwipMibCompiler/SharpSnmpLib/obj/
/src/apps/snmp/LwipMibCompiler/LwipMibCompiler.userprefs
/src/apps/snmp/LwipMibCompiler/*.suo
/test/fuzz/output
/test/fuzz/lwip_fuzz
/test/fuzz/.depend

View File

@ -3,6 +3,77 @@ HISTORY
(git master)
* [Enter new changes just after this line - do not remove this line]
++ New features:
2016-12-31: Simon Goldschmidt
* tcp.h/.c: added function tcp_listen_with_backlog_and_err() to get the error
reason when listening fails (bug #49861)
2016-12-20: Erik Andersen
* Add MQTT client
2016-12-14: Jan Breuer:
* opt.h, ndc.h/.c: add support for RDNSS option (as per RFC 6106)
2016-12-14: David van Moolenbroek
* opt.h, nd6.c: Added LWIP_HOOK_ND6_GET_GW()
2016-12-09: Dirk Ziegelmeier
* ip6_frag.c: Implemented support for LWIP_NETIF_TX_SINGLE_PBUF
2016-12-09: Simon Goldschmidt
* dns.c: added one-shot multicast DNS queries
2016-11-24: Ambroz Bizjak, David van Moolenbroek
* tcp_out.c: Optimize passing contiguous nocopy buffers to tcp_write (bug #46290)
2016-11-16: Dirk Ziegelmeier
* sockets.c: added support for IPv6 mapped IPv4 addresses
++ Bugfixes:
2016-12-16: Thomas Mueller
* api_lib.c: fixed race condition in return value of netconn_gethostbyname()
(and thus also lwip_gethostbyname/_r() and lwip_getaddrinfo())
2016-12-15: David van Moolenbroek
* opt.h, tcp: added LWIP_HOOK_TCP_ISN() to implement less predictable initial
sequence numbers (see contrib/addons/tcp_isn for an example implementation)
2016-12-05: Dirk Ziegelmeier
* fixed compiling with IPv4 disabled (IPv6 only case)
2016-11-28: Simon Goldschmidt
* api_lib.c: fixed bug #49725 (send-timeout: netconn_write() can return
ERR_OK without all bytes being written)
2016-11-28: Ambroz Bizjak
* tcpi_in.c: fixed bug #49717 (window size in received SYN and SYN-ACK
assumed scaled)
2016-11-25: Simon Goldschmidt
* dhcp.c: fixed bug #49676 (Possible endless loop when parsing dhcp options)
2016-11-23: Dirk Ziegelmeier
* udp.c: fixed bug #49662: multicast traffic is now only received on a UDP PCB
(and therefore on a UDP socket/netconn) when the PCB is bound to IP_ADDR_ANY
2016-11-16: Dirk Ziegelmeier
* *: Fixed dual-stack behaviour, IPv6 mapped IPv4 support in socket API
2016-11-14: Joel Cunningham
* tcp_out.c: fixed bug #49533 (start persist timer when unsent seg can't fit
in window)
2016-11-16: Roberto Barbieri Carrera
* autoip.c: fixed bug #49610 (sometimes AutoIP fails to reuse the same address)
2016-11-11: Dirk Ziegelmeier
* sockets.c: fixed bug #49578 (dropping multicast membership does not work
with LWIP_SOCKET_OFFSET)
(STABLE-2.0.0)
++ New features:
@ -328,8 +399,9 @@ HISTORY
++ Bugfixes:
2016-11-25: Simon Goldschmidt
* dhcp.c: fixed bug #49676 (Possible endless loop when parsing dhcp options)
2016-08-23: Simon Goldschmidt
* etharp: removed ETHARP_TRUST_IP_MAC since it is insecure and we don't need
it any more after implementing unicast ARP renewal towards arp entry timeout
2016-07-20: Simon Goldschmidt
* memp.h/.c: fixed bug #48442 (memp stats don't work for MEMP_MEM_MALLOC)

View File

@ -1,4 +1,5 @@
src/ - The source code for the lwIP TCP/IP stack.
doc/ - The documentation for lwIP.
test/ - Some code to test whether the sources do what they should.
See also the FILES file in each subdirectory.

View File

@ -35,6 +35,9 @@ APPLICATIONS
* HTTP server with SSI and CGI
* SNMPv2c agent with MIB compiler (Simple Network Management Protocol)
* SNTP (Simple network time protocol)
* NetBIOS name service responder
* MDNS (Multicast DNS) responder
* iPerf server implementation
LICENSE
@ -77,7 +80,7 @@ Self documentation of the source code is regularly extracted from the current
Git sources and is available from this web page:
http://www.nongnu.org/lwip/
There is now a constantly growin wiki about lwIP at
There is now a constantly growing wiki about lwIP at
http://lwip.wikia.com/wiki/LwIP_Wiki
Also, there are mailing lists you can subscribe at

View File

@ -8,7 +8,14 @@ with newer versions.
* [Enter new changes just after this line - do not remove this line]
* TODO
(2.0.1)
++ Application changes:
* UDP does NOT receive multicast traffic from ALL netifs on an UDP PCB bound to a specific
netif any more. Users need to bind to IP_ADDR_ANY to receive multicast traffic and compare
ip_current_netif() to the desired netif for every packet.
See bug #49662 for an explanation.
(2.0.0)
@ -20,7 +27,7 @@ with newer versions.
* Added IPv6 support (dual-stack or IPv4/IPv6 only)
* Changed ip_addr_t to be a union in dual-stack mode (use ip4_addr_t where referring to IPv4 only).
* Major rewrite of SNMP (added MIB parser that creates code stubs for custom MIBs);
supports SNMP2vc (experimental v3 support)
supports SNMPv2c (experimental v3 support)
* Moved some core applications from contrib repository to src/apps (and include/lwip/apps)
+++ Raw API:
@ -34,7 +41,8 @@ with newer versions.
++ Port changes
+++ new files:
* MANY new and moved files!
* MANY new and moved files!
* Added src/Filelists.mk for use in Makefile projects
* Continued moving stack-internal parts from abc.h to abc_priv.h in sub-folder "priv"
to let abc.h only contain the actual application programmer's API
@ -45,6 +53,13 @@ with newer versions.
* Added LWIP_NETCONN_SEM_PER_THREAD to use one "op_completed" semaphore per thread
instead of using one per netconn (these semaphores are used even with core locking
enabled as some longer lasting functions like big writes still need to delay)
* Added generalized abstraction for itoa(), strnicmp(), stricmp() and strnstr()
in def.h (to be overridden in cc.h) instead of config
options for netbiosns, httpd, dns, etc. ...
* New abstraction for hton* and ntoh* functions in def.h.
To override them, use the following in cc.h:
#define lwip_htons(x) <your_htons>
#define lwip_htonl(x) <your_htonl>
+++ new options:
* TODO
@ -56,6 +71,8 @@ with newer versions.
* added hook LWIP_HOOK_MEMP_AVAILABLE() to get informed when a memp pool was empty and an item
is now available
* Signature of LWIP_HOOK_VLAN_SET macro was changed
* LWIP_DECLARE_MEMORY_ALIGNED() may be used to declare aligned memory buffers (mem/memp)
or to move buffers to dedicated memory using compiler attributes
@ -68,6 +85,7 @@ with newer versions.
* Added IPv6 support (dual-stack or IPv4/IPv6 only)
* Major rewrite of PPP (incl. keep-up with apache pppd)
see doc/ppp.txt for an upgrading how-to
* Major rewrite of SNMP (incl. MIB parser)
* Fixed timing issues that might have lead to losing a DHCP lease
* Made rx processing path more robust against crafted errors
@ -77,7 +95,7 @@ with newer versions.
* support PBUF_REF for RX packets
* LWIP_NETCONN_FULLDUPLEX allows netconn/sockets to be used for reading/writing from separate
threads each (needs LWIP_NETCONN_SEM_PER_THREAD)
* Moved and reorderd stats (mainly memp/mib2)
* Moved and reordered stats (mainly memp/mib2)
(1.4.0)

View File

@ -1,6 +1,9 @@
doxygen/ - Configuration files and scripts to create the lwIP doxygen source
documentation (found at http://www.nongnu.org/lwip/)
savannah.txt - How to obtain the current development source code.
contrib.txt - How to contribute to lwIP as a developer.
rawapi.txt - The documentation for the core API of lwIP.
Also provides an overview about the other APIs and multithreading.
snmp_agent.txt - The documentation for the lwIP SNMP agent.
sys_arch.txt - The documentation for a system abstraction layer of lwIP.
ppp.txt - Documentation of the PPP interface for lwIP.

View File

@ -0,0 +1,117 @@
void eth_mac_irq()
{
/* Service MAC IRQ here */
/* Allocate pbuf from pool (avoid using heap in interrupts) */
struct pbuf* p = pbuf_alloc(PBUF_RAW, eth_data_count, PBUF_POOL);
if(p != NULL) {
/* Copy ethernet frame into pbuf */
pbuf_take(p, eth_data, eth_data_count);
/* Put in a queue which is processed in main loop */
if(!queue_try_put(&queue, p)) {
/* queue is full -> packet loss */
pbuf_free(p);
}
}
}
static err_t netif_output(struct netif *netif, struct pbuf *p)
{
LINK_STATS_INC(link.xmit);
/* Update SNMP stats (only if you use SNMP) */
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
int unicast = ((p->payload[0] & 0x01) == 0);
if (unicast) {
MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
} else {
MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
}
lock_interrupts();
pbuf_copy_partial(p, mac_send_buffer, p->tot_len, 0);
/* Start MAC transmit here */
unlock_interrupts();
return ERR_OK;
}
static void netif_status_callback(struct netif *netif)
{
printf("netif status changed %s\n", ip4addr_ntoa(netif_ip4_addr(netif)));
}
static err_t netif_init(struct netif *netif)
{
netif->linkoutput = netif_output;
netif->output = etharp_output;
netif->output_ip6 = ethip6_output;
netif->mtu = ETHERNET_MTU;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6;
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 100000000);
SMEMCPY(netif->hwaddr, your_mac_address_goes_here, sizeof(netif->hwaddr));
netif->hwaddr_len = sizeof(netif->hwaddr);
return ERR_OK;
}
void main(void)
{
struct netif netif;
lwip_init();
netif_add(&netif, IP4_ADDR_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY, NULL, netif_init, netif_input);
netif.name[0] = 'e';
netif.name[1] = '0';
netif_create_ip6_linklocal_address(&netif, 1);
netif.ip6_autoconfig_enabled = 1;
netif_set_status_callback(&netif, netif_status_callback);
netif_set_default(&netif);
netif_set_up(&netif);
/* Start DHCP and HTTPD */
dhcp_init();
httpd_init();
while(1) {
/* Check link state, e.g. via MDIO communication with PHY */
if(link_state_changed()) {
if(link_is_up()) {
netif_set_link_up(&netif);
} else {
netif_set_link_down(&netif);
}
}
/* Check for received frames, feed them to lwIP */
lock_interrupts();
struct pbuf* p = queue_try_get(&queue);
unlock_interrupts();
if(p != NULL) {
LINK_STATS_INC(link.recv);
/* Update SNMP stats (only if you use SNMP) */
MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
int unicast = ((p->payload[0] & 0x01) == 0);
if (unicast) {
MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
} else {
MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
}
if(netif.input(p, &netif) != ERR_OK) {
pbuf_free(p);
}
}
/* Cyclic lwIP timers check */
sys_check_timeouts();
/* your application goes here */
}
}

View File

@ -39,7 +39,7 @@ features of Savannah help us not lose users' input.
bugtracker at Savannah.
3. If you have a fix put the patch on Savannah. If it is a patch that affects
both core and arch specific stuff please separate them so that the core can
be applied separately while leaving the other patch 'open'. The prefered way
be applied separately while leaving the other patch 'open'. The preferred way
is to NOT touch archs you can't test and let maintainers take care of them.
This is a good way to see if they are used at all - the same goes for unix
netifs except tapif.

View File

@ -1 +1,3 @@
#!/bin/sh
doxygen lwip.Doxyfile

View File

@ -32,19 +32,19 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.
PROJECT_NAME = "lwIP 2.0.0"
PROJECT_NAME = "lwIP"
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = "lwIP 2.0.0"
PROJECT_NUMBER = "2.0.1"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = Lightweight IP stack
PROJECT_BRIEF = "Lightweight IP stack"
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55
@ -162,7 +162,7 @@ FULL_PATH_NAMES = YES
# will be relative from the directory where doxygen is started.
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
STRIP_FROM_PATH =
STRIP_FROM_PATH = ../../
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
# path mentioned in the documentation of a class, which tells the reader which
@ -781,7 +781,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = ../../src main_page.h
INPUT = main_page.h ../../src
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@ -2071,6 +2071,7 @@ INCLUDE_FILE_PATTERNS = *.h
PREDEFINED = __DOXYGEN__=1 \
NO_SYS=0 \
SYS_LIGHTWEIGHT_PROT=1 \
LWIP_TCPIP_CORE_LOCKING=1 \
LWIP_IPV4=1 \
LWIP_IPV6=1 \
LWIP_ICMP=1 \
@ -2080,10 +2081,12 @@ PREDEFINED = __DOXYGEN__=1 \
LWIP_UDP=1 \
LWIP_IGMP=1 \
LWIP_TCP=1 \
TCP_LISTEN_BACKLOG=1 \
LWIP_SNMP=1 \
SNMP_USE_NETCONN=1 \
SNMP_USE_RAW=1 \
MIB2_STATS=1 \
LWIP_MDNS_RESPONDER=1 \
MEMP_OVERFLOW_CHECK=0 \
MEMP_SANITY_CHECK=1 \
LWIP_ARP=1 \
@ -2091,8 +2094,10 @@ PREDEFINED = __DOXYGEN__=1 \
LWIP_NETIF_HOSTNAME=1 \
LWIP_NETIF_API=1 \
LWIP_NETIF_CALLBACK=1 \
LWIP_NETIF_STATUS_CALLBACK=1 \
LWIP_NETIF_REMOVE_CALLBACK=1 \
LWIP_NETIF_LINK_CALLBACK=1 \
LWIP_NUM_NETIF_CLIENT_DATA=1 \
ENABLE_LOOPBACK=1 \
LWIP_AUTOIP=1 \
ARP_QUEUEING=1 \
@ -2110,10 +2115,8 @@ PREDEFINED = __DOXYGEN__=1 \
SO_REUSE=1 \
SO_REUSE_RXTOALL=1 \
LWIP_HAVE_SLIPIF=1 \
LWIP_6LOWPAN=1 \
"LWIP_DNS && LWIP_SOCKET " \
"(LWIP_DNS && LWIP_SOCKET)=1 "
LWIP_6LOWPAN=1
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The
# macro definition that is found in the sources will be used. Use the PREDEFINED

View File

@ -1,4 +1,4 @@
/**
/**
* @defgroup lwip lwIP
*
* @defgroup infrastructure Infrastructure
@ -7,8 +7,8 @@
* Non thread-safe APIs, callback style for maximum performance and minimum
* memory footprint.
*
* @defgroup threadsafe_api Thread-safe APIs
* Thread-safe APIs, blocking functions. More overhead, but can be called
* @defgroup sequential_api Sequential-style APIs
* Sequential-style APIs, blocking functions. More overhead, but can be called
* from any thread except TCPIP thread.
*
* @defgroup addons Addons
@ -30,3 +30,98 @@
* @page contrib How to contribute to lwIP
* @verbinclude "contrib.txt"
*/
/**
* @page pitfalls Common pitfalls
*
* Multiple Execution Contexts in lwIP code
* ========================================
*
* The most common source of lwIP problems is to have multiple execution contexts
* inside the lwIP code.
*
* lwIP can be used in two basic modes: @ref lwip_nosys (no OS/RTOS
* running on target system) or @ref lwip_os (there is an OS running
* on the target system).
*
* Mainloop Mode
* -------------
* In mainloop mode, only @ref callbackstyle_api can be used.
* The user has two possibilities to ensure there is only one
* exection context at a time in lwIP:
*
* 1) Deliver RX ethernet packets directly in interrupt context to lwIP
* by calling netif->input directly in interrupt. This implies all lwIP
* callback functions are called in IRQ context, which may cause further
* problems in application code: IRQ is blocked for a long time, multiple
* execution contexts in application code etc. When the application wants
* to call lwIP, it only needs to disable interrupts during the call.
* If timers are involved, even more locking code is needed to lock out
* timer IRQ and ethernet IRQ from each other, assuming these may be nested.
*
* 2) Run lwIP in a mainloop. There is example code here: @ref lwip_nosys.
* lwIP is _ONLY_ called from mainloop callstacks here. The ethernet IRQ
* has to put received telegrams into a queue which is polled in the
* mainloop. Ensure lwIP is _NEVER_ called from an interrupt, e.g.
* some SPI IRQ wants to forward data to udp_send() or tcp_write()!
*
* OS Mode
* -------
* In OS mode, @ref callbackstyle_api AND @ref sequential_api can be used.
* @ref sequential_api are designed to be called from threads other than
* the TCPIP thread, so there is nothing to consider here.
* But @ref callbackstyle_api functions must _ONLY_ be called from
* TCPIP thread. It is a common error to call these from other threads
* or from IRQ contexts. Ethernet RX needs to deliver incoming packets
* in the correct way by sending a message to TCPIP thread, this is
* implemented in tcpip_input().
* Again, ensure lwIP is _NEVER_ called from an interrupt, e.g.
* some SPI IRQ wants to forward data to udp_send() or tcp_write()!
*
* 1) tcpip_callback() can be used get called back from TCPIP thread,
* it is safe to call any @ref callbackstyle_api from there.
*
* 2) Use @ref LWIP_TCPIP_CORE_LOCKING. All @ref callbackstyle_api
* functions can be called when lwIP core lock is aquired, see
* @ref LOCK_TCPIP_CORE() and @ref UNLOCK_TCPIP_CORE().
* These macros cannot be used in an interrupt context!
* Note the OS must correctly handle priority inversion for this.
*/
/**
* @page bugs Reporting bugs
* Please report bugs in the lwIP bug tracker at savannah.\n
* BEFORE submitting, please check if the bug has already been reported!\n
* https://savannah.nongnu.org/bugs/?group=lwip
*/
/**
* @defgroup lwip_nosys Mainloop mode ("NO_SYS")
* @ingroup lwip
* Use this mode if you do not run an OS on your system. \#define NO_SYS to 1.
* Feed incoming packets to netif->input(pbuf, netif) function from mainloop,
* *not* *from* *interrupt* *context*. You can allocate a @ref pbuf in interrupt
* context and put them into a queue which is processed from mainloop.\n
* Call sys_check_timeouts() periodically in the mainloop.\n
* Porting: implement all functions in @ref sys_time, @ref sys_prot and
* @ref compiler_abstraction.\n
* You can only use @ref callbackstyle_api in this mode.\n
* Sample code:\n
* @include NO_SYS_SampleCode.c
*/
/**
* @defgroup lwip_os OS mode (TCPIP thread)
* @ingroup lwip
* Use this mode if you run an OS on your system. It is recommended to
* use an RTOS that correctly handles priority inversion and
* to use @ref LWIP_TCPIP_CORE_LOCKING.\n
* Porting: implement all functions in @ref sys_layer.\n
* You can use @ref callbackstyle_api together with @ref tcpip_callback,
* and all @ref sequential_api.
*/
/**
* @page raw_api lwIP API
* @verbinclude "rawapi.txt"
*/

View File

@ -0,0 +1,10 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Redirection</title>
<meta http-equiv="refresh" content="0; url=html/index.html" />
</head>
<body>
<a href="html/index.html">index.html</a>
</body>
</html>

View File

@ -0,0 +1,113 @@
Multicast DNS for lwIP
Author: Erik Ekman
Note! The MDNS responder does not have all features required by the standards.
See notes in src/apps/mdns/mdns.c for what is left. It is however usable in normal
cases - but watch out if many devices on the same network try to use the same
host/service instance names.
How to enable:
==============
MDNS support does not depend on DNS.
MDNS supports using IPv4 only, v6 only, or v4+v6.
To enable MDNS responder, set
LWIP_MDNS_RESPONDER = 1
in lwipopts.h and add src/apps/mdns/mdns.c to your list of files to build.
The max number of services supported per netif is defined by MDNS_MAX_SERVICES,
default is 1.
Increase MEMP_NUM_UDP_PCB by 1. MDNS needs one PCB.
Increase LWIP_NUM_NETIF_CLIENT_DATA by 1 (MDNS needs one entry on netif).
MDNS with IPv4 requires LWIP_IGMP = 1, and preferably LWIP_AUTOIP = 1.
MDNS with IPv6 requires LWIP_IPV6_MLD = 1, and that a link-local address is
generated.
The MDNS code puts its structs on the stack where suitable to reduce dynamic
memory allocation. It may use up to 1kB of stack.
MDNS needs a strncasecmp() implementation. If you have one, define
LWIP_MDNS_STRNCASECMP to it. Otherwise the code will provide an implementation
for you.
How to use:
===========
Call mdns_resp_init() during system initialization.
This opens UDP sockets on port 5353 for IPv4 and IPv6.
To start responding on a netif, run
mdns_resp_add_netif(struct netif *netif, char *hostname, u32_t dns_ttl)
The hostname will be copied. If this returns successfully, the netif will join
the multicast groups and any MDNS/legacy DNS requests sent unicast or multicast
to port 5353 will be handled:
- <hostname>.local type A, AAAA or ANY returns relevant IP addresses
- Reverse lookups (PTR in-addr.arpa, ip6.arpa) of netif addresses
returns <hostname>.local
Answers will use the supplied TTL (in seconds)
MDNS allows UTF-8 names, but it is recommended to stay within ASCII,
since the default case-insensitive comparison assumes this.
It is recommended to call this function after an IPv4 address has been set,
since there is currently no check if the v4 address is valid.
Call mdns_resp_netif_settings_changed() every time the IP address
on the netif has changed.
To stop responding on a netif, run
mdns_resp_remove_netif(struct netif *netif)
Adding services:
================
The netif first needs to be registered. Then run
mdns_resp_add_service(struct netif *netif, char *name, char *service,
u16_t proto, u16_t port, u32_t dns_ttl,
service_get_txt_fn_t txt_fn, void *txt_userdata);
The name and service pointers will be copied. Name refers to the name of the
service instance, and service is the type of service, like _http
proto can be DNSSD_PROTO_UDP or DNSSD_PROTO_TCP which represent _udp and _tcp.
If this call returns successfully, the following queries will be answered:
- _services._dns-sd._udp.local type PTR returns <service>.<proto>.local
- <service>.<proto>.local type PTR returns <name>.<service>.<proto>.local
- <name>.<service>.<proto>.local type SRV returns hostname and port of service
- <name>.<service>.<proto>.local type TXT builds text strings by calling txt_fn
with the supplied userdata. The callback adds strings to the reply by calling
mdns_resp_add_service_txtitem(struct mdns_service *service, char *txt,
int txt_len). Example callback method:
static void srv_txt(struct mdns_service *service, void *txt_userdata)
{
res = mdns_resp_add_service_txtitem(service, "path=/", 6);
LWIP_ERROR("mdns add service txt failed\n", (res == ERR_OK), return);
}
Since a hostname struct is used for TXT storage each single item can be max
63 bytes long, and the total max length (including length bytes for each
item) is 255 bytes.
If your device runs a webserver on port 80, an example call might be:
mdns_resp_add_service(netif, "myweb", "_http"
DNSSD_PROTO_TCP, 80, 3600, srv_txt, NULL);
which will publish myweb._http._tcp.local for any hosts looking for web servers,
and point them to <hostname>.local:80
Relevant information will be sent as additional records to reduce number of
requests required from a client.
Removing services is currently not supported. Services are removed when the
netif is removed.

View File

@ -0,0 +1,162 @@
MQTT client for lwIP
Author: Erik Andersson
Details of the MQTT protocol can be found at:
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html
-----------------------------------------------------------------
1. Initial steps, reserve memory and make connection to server:
1.1: Provide storage
Static allocation:
mqtt_client_t static_client;
example_do_connect(&static_client);
Dynamic allocation:
mqtt_client_t *client = mqtt_client_new();
if(client != NULL) {
example_do_connect(&client);
}
1.2: Establish Connection with server
void example_do_connect(mqtt_client_t *client)
{
struct mqtt_connect_client_info_t ci;
err_t err;
/* Setup an empty client info structure */
memset(&ci, 0, sizeof(ci));
/* Minimal amount of information required is client identifier, so set it here */
ci.client_id = "lwip_test";
/* Initiate client and connect to server, if this fails immediately an error code is returned
otherwise mqtt_connection_cb will be called with connection result after attempting
to establish a connection with the server.
For now MQTT version 3.1.1 is always used */
err = mqtt_client_connect(client, ip_addr, MQTT_PORT, mqtt_connection_cb, 0, &ci);
/* For now just print the result code if something goes wrong
if(err != ERR_OK) {
printf("mqtt_connect return %d\n", err);
}
}
Connection to server can also be probed by calling mqtt_client_is_connected(client)
-----------------------------------------------------------------
2. Implementing the connection status callback
static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status)
{
err_t err;
if(status == MQTT_CONNECT_ACCEPTED) {
printf("mqtt_connection_cb: Successfully connected\n");
/* Setup callback for incoming publish requests */
mqtt_set_inpub_callback(client, mqtt_incoming_publish_cb, mqtt_incoming_data_cb, arg);
/* Subscribe to a topic named "subtopic" with QoS level 1, call mqtt_sub_request_cb with result */
err = mqtt_subscribe(client, "subtopic", 1, mqtt_sub_request_cb, arg);
if(err != ERR_OK) {
printf("mqtt_subscribe return: %d\n", err);
}
} else {
printf("mqtt_connection_cb: Disconnected, reason: %d\n", status);
/* Its more nice to be connected, so try to reconnect */
example_do_connect(client);
}
}
static void mqtt_sub_request_cb(void *arg, err_t result)
{
/* Just print the result code here for simplicity,
normal behaviour would be to take some action if subscribe fails like
notifying user, retry subscribe or disconnect from server */
printf("Subscribe result: %d\n", result);
}
-----------------------------------------------------------------
3. Implementing callbacks for incoming publish and data
/* The idea is to demultiplex topic and create some reference to be used in data callbacks
Example here uses a global variable, better would be to use a member in arg
If RAM and CPU budget allows it, the easiest implementation might be to just take a copy of
the topic string and use it in mqtt_incoming_data_cb
*/
static int inpub_id;
static void mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len)
{
printf("Incoming publish at topic %s with total length %u\n", topic, (unsigned int)tot_len);
/* Decode topic string into a user defined reference */
if(strcmp(topic, "print_payload") == 0) {
inpub_id = 0;
} else if(topic[0] == 'A') {
/* All topics starting with 'A' might be handled at the same way */
inpub_id = 1;
} else {
/* For all other topics */
inpub_id = 2;
}
}
static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags)
{
printf("Incoming publish payload with length %d, flags %u\n", len, (unsigned int)flags);
if(flags & MQTT_DATA_FLAG_LAST) {
/* Last fragment of payload received (or whole part if payload fits receive buffer
See MQTT_VAR_HEADER_BUFFER_LEN) */
/* Call function or do action depending on reference, in this case inpub_id */
if(inpub_id == 0) {
/* Don't trust the publisher, check zero termination */
if(data[len-1] == 0) {
printf("mqtt_incoming_data_cb: %s\n", (const char *)data);
}
} else if(inpub_id == 1) {
/* Call an 'A' function... */
} else {
printf("mqtt_incoming_data_cb: Ignoring payload...\n");
}
} else {
/* Handle fragmented payload, store in buffer, write to file or whatever */
}
}
-----------------------------------------------------------------
4. Using outgoing publish
void example_publish(mqtt_client_t *client, void *arg)
{
const char *pub_payload= "PubSubHubLubJub";
err_t err;
u8_t qos = 2; /* 0 1 or 2, see MQTT specification */
u8_t retain = 0; /* No don't retain such crappy payload... */
err = mqtt_publish(client, "pub_topic", pub_payload, strlen(pub_payload), qos, retain, mqtt_pub_request_cb, arg);
if(err != ERR_OK) {
printf("Publish err: %d\n", err);
}
}
/* Called when publish is complete either with sucess or failure */
static void mqtt_pub_request_cb(void *arg, err_t result)
{
if(result != ERR_OK) {
printf("Publish result: %d\n", result);
}
}
-----------------------------------------------------------------
5. Disconnecting
Simply call mqtt_disconnect(client)

View File

@ -79,7 +79,7 @@ static void status_cb(ppp_pcb *pcb, int err_code, void *ctx) {
switch(err_code) {
case PPPERR_NONE: {
#if LWIP_DNS
ip_addr_t ns;
const ip_addr_t *ns;
#endif /* LWIP_DNS */
printf("status_cb: Connected\n");
#if PPP_IPV4_SUPPORT
@ -88,9 +88,9 @@ static void status_cb(ppp_pcb *pcb, int err_code, void *ctx) {
printf(" netmask = %s\n", ipaddr_ntoa(&pppif->netmask));
#if LWIP_DNS
ns = dns_getserver(0);
printf(" dns1 = %s\n", ipaddr_ntoa(&ns));
printf(" dns1 = %s\n", ipaddr_ntoa(ns));
ns = dns_getserver(1);
printf(" dns2 = %s\n", ipaddr_ntoa(&ns));
printf(" dns2 = %s\n", ipaddr_ntoa(ns));
#endif /* LWIP_DNS */
#endif /* PPP_IPV4_SUPPORT */
#if PPP_IPV6_SUPPORT

View File

@ -171,15 +171,6 @@ incoming connections or be explicitly connected to another host.
in the listen queue to the value specified by the backlog argument.
To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h.
- void tcp_accepted(struct tcp_pcb *pcb)
Inform lwIP that an incoming connection has been accepted. This would
usually be called from the accept callback. This allows lwIP to perform
housekeeping tasks, such as allowing further incoming connections to be
queued in the listen backlog.
ATTENTION: the PCB passed in must be the listening pcb, not the pcb passed
into the accept callback!
- void tcp_accept(struct tcp_pcb *pcb,
err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
err_t err))
@ -465,9 +456,11 @@ introduction to this subject.
Other significant improvements can be made by supplying
assembly or inline replacements for htons() and htonl()
if you're using a little-endian architecture.
#define LWIP_PLATFORM_BYTESWAP 1
#define LWIP_PLATFORM_HTONS(x) <your_htons>
#define LWIP_PLATFORM_HTONL(x) <your_htonl>
#define lwip_htons(x) <your_htons>
#define lwip_htonl(x) <your_htonl>
If you #define them to htons() and htonl(), you should
#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from
defining hton*/ntoh* compatibility macros.
Check your network interface driver if it reads at
a higher speed than the maximum wire-speed. If the

View File

@ -1,6 +1,7 @@
sys_arch interface for lwIP 0.6++
sys_arch interface for lwIP
Author: Adam Dunkels
Simon Goldschmidt
The operating system emulation layer provides a common interface
between the lwIP code and the underlying operating system kernel. The
@ -9,12 +10,11 @@ small changes to a few header files and a new sys_arch
implementation. It is also possible to do a sys_arch implementation
that does not rely on any underlying operating system.
The sys_arch provides semaphores and mailboxes to lwIP. For the full
The sys_arch provides semaphores, mailboxes and mutexes to lwIP. For the full
lwIP functionality, multiple threads support can be implemented in the
sys_arch, but this is not required for the basic lwIP
functionality. Previous versions of lwIP required the sys_arch to
implement timer scheduling as well but as of lwIP 0.5 this is
implemented in a higher layer.
functionality. Timer scheduling is implemented in lwIP, but can be implemented
by the sys_arch port (LWIP_TIMERS_CUSTOM==1).
In addition to the source file providing the functionality of sys_arch,
the OS emulation layer must provide several header files defining
@ -22,19 +22,18 @@ macros used throughout lwip. The files required and the macros they
must define are listed below the sys_arch description.
Semaphores can be either counting or binary - lwIP works with both
kinds. Mailboxes are used for message passing and can be implemented
either as a queue which allows multiple messages to be posted to a
mailbox, or as a rendez-vous point where only one message can be
posted at a time. lwIP works with both kinds, but the former type will
be more efficient. A message in a mailbox is just a pointer, nothing
more.
kinds. Mailboxes should be implemented as a queue which allows multiple messages
to be posted (implementing as a rendez-vous point where only one message can be
posted at a time can have a highly negative impact on performance). A message
in a mailbox is just a pointer, nothing more.
Semaphores are represented by the type "sys_sem_t" which is typedef'd
in the sys_arch.h file. Mailboxes are equivalently represented by the
type "sys_mbox_t". lwIP does not place any restrictions on how
sys_sem_t or sys_mbox_t are represented internally.
type "sys_mbox_t". Mutexes are represented by the type "sys_mutex_t".
lwIP does not place any restrictions on how these types are represented
internally.
Since lwIP 1.4.0, semaphore and mailbox functions are prototyped in a way that
Since lwIP 1.4.0, semaphore, mutexes and mailbox functions are prototyped in a way that
allows both using pointers or actual OS structures to be used. This way, memory
required for such types can be either allocated in place (globally or on the
stack) or on the heap (allocated internally in the "*_new()" functions).
@ -94,6 +93,40 @@ The following functions must be implemented by the sys_arch:
sys_sem_free() is always called before calling this function!
This may also be a define, in which case the function is not prototyped.
- void sys_mutex_new(sys_mutex_t *mutex)
Creates a new mutex. The mutex is allocated to the memory that 'mutex'
points to (which can be both a pointer or the actual OS structure).
If the mutex has been created, ERR_OK should be returned. Returning any
other error will provide a hint what went wrong, but except for assertions,
no real error handling is implemented.
- void sys_mutex_free(sys_mutex_t *mutex)
Deallocates a mutex.
- void sys_mutex_lock(sys_mutex_t *mutex)
Blocks the thread until the mutex can be grabbed.
- void sys_mutex_unlock(sys_mutex_t *mutex)
Releases the mutex previously locked through 'sys_mutex_lock()'.
- void sys_mutex_valid(sys_mutex_t *mutex)
Returns 1 if the mutes is valid, 0 if it is not valid.
When using pointers, a simple way is to check the pointer for != NULL.
When directly using OS structures, implementing this may be more complex.
This may also be a define, in which case the function is not prototyped.
- void sys_mutex_set_invalid(sys_mutex_t *mutex)
Invalidate a mutex so that sys_mutex_valid() returns 0.
ATTENTION: This does NOT mean that the mutex shall be deallocated:
sys_mutex_free() is always called before calling this function!
This may also be a define, in which case the function is not prototyped.
- err_t sys_mbox_new(sys_mbox_t *mbox, int size)
Creates an empty mailbox for maximum "size" elements. Elements stored
@ -176,6 +209,9 @@ to be implemented as well:
the "stacksize" parameter. The id of the new thread is returned. Both the id
and the priority are system dependent.
When lwIP is used from more than one context (e.g. from multiple threads OR from
main-loop and from interrupts), the SYS_LIGHTWEIGHT_PROT protection SHOULD be enabled!
- sys_prot_t sys_arch_protect(void)
This optional function does a "fast" critical region protection and returns
@ -209,7 +245,7 @@ For some configurations, you also need:
Note:
Be carefull with using mem_malloc() in sys_arch. When malloc() refers to
Be careful with using mem_malloc() in sys_arch. When malloc() refers to
mem_malloc() you can run into a circular function call problem. In mem.c
mem_init() tries to allcate a semaphore using mem_malloc, which of course
can't be performed when sys_arch uses mem_malloc.

View File

@ -1,13 +1,15 @@
api/ - The code for the high-level wrapper API. Not needed if
you use the lowel-level call-back/raw API.
apps/ - Higher layer applications that are specifically programmed
with the lwIP low-level raw API.
core/ - The core of the TPC/IP stack; protocol implementations,
memory and buffer management, and the low-level raw API.
include/ - lwIP include files.
netif/ - Generic network interface device drivers are kept here,
as well as the ARP module.
netif/ - Generic network interface device drivers are kept here.
For more information on the various subdirectories, check the FILES
file in each directory.

View File

@ -158,12 +158,24 @@ LWIPERFFILES=$(LWIPDIR)/apps/lwiperf/lwiperf.c
# SNTPFILES: SNTP client
SNTPFILES=$(LWIPDIR)/apps/sntp/sntp.c
# MDNSFILES: MDNS responder
MDNSFILES=$(LWIPDIR)/apps/mdns/mdns.c
# NETBIOSNSFILES: NetBIOS name server
NETBIOSNSFILES=$(LWIPDIR)/apps/netbiosns/netbiosns.c
# TFTPFILES: TFTP server files
TFTPFILES=$(LWIPDIR)/apps/tftp/tftp_server.c
# MQTTFILES: MQTT client files
MQTTFILES=$(LWIPDIR)/apps/mqtt/mqtt.c
# LWIPAPPFILES: All LWIP APPs
LWIPAPPFILES=$(SNMPFILES) \
$(HTTPDFILES) \
$(LWIPERFFILES) \
$(SNTPFILES) \
$(NETBIOSNSFILES)
$(MDNSFILES) \
$(NETBIOSNSFILES) \
$(TFTPFILES) \
$(MQTTFILES)

View File

@ -1,6 +1,24 @@
/**
* @file
* Sequential API External module
*
* @defgroup netconn Netconn API
* @ingroup sequential_api
* Thread-safe, to be called from non-TCPIP threads only.
* TX/RX handling based on @ref netbuf (containing @ref pbuf)
* to avoid copying data around.
*
* @defgroup netconn_common Common functions
* @ingroup netconn
* For use with TCP and UDP
*
* @defgroup netconn_tcp TCP only
* @ingroup netconn
* TCP only functions
*
* @defgroup netconn_udp UDP only
* @ingroup netconn
* UDP only functions
*/
/*
@ -34,26 +52,6 @@
* Author: Adam Dunkels <adam@sics.se>
*/
/**
* @defgroup netconn Netconn API
* @ingroup threadsafe_api
* Thread-safe, to be called from non-TCPIP threads only.
* TX/RX handling based on @ref netbuf (containing @ref pbuf)
* to avoid copying data around.
*
* @defgroup netconn_common Common functions
* @ingroup netconn
* For use with TCP and UDP
*
* @defgroup netconn_tcp TCP only
* @ingroup netconn
* TCP only functions
*
* @defgroup netconn_udp UDP only
* @ingroup netconn
* UDP only functions
*/
/* This is the part of the API that is linked with
the application */
@ -243,8 +241,8 @@ netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
* Binding one netconn twice might not always be checked correctly!
*
* @param conn the netconn to bind
* @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY
* to bind to all addresses)
* @param addr the local IP address to bind the netconn to
* (use IP4_ADDR_ANY/IP6_ADDR_ANY to bind to all addresses)
* @param port the local port to bind the netconn to (not used for RAW)
* @return ERR_OK if bound, any other err_t on failure
*/
@ -256,10 +254,22 @@ netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port)
LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
#if LWIP_IPV4
/* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
if (addr == NULL) {
addr = IP_ADDR_ANY;
addr = IP4_ADDR_ANY;
}
#endif /* LWIP_IPV4 */
#if LWIP_IPV4 && LWIP_IPV6
/* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY,
* and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind
*/
if ((netconn_get_ipv6only(conn) == 0) &&
ip_addr_cmp(addr, IP6_ADDR_ANY)) {
addr = IP_ANY_TYPE;
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
API_MSG_VAR_ALLOC(msg);
API_MSG_VAR_REF(msg).conn = conn;
@ -288,10 +298,12 @@ netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port)
LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
#if LWIP_IPV4
/* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
if (addr == NULL) {
addr = IP_ADDR_ANY;
addr = IP4_ADDR_ANY;
}
#endif /* LWIP_IPV4 */
API_MSG_VAR_ALLOC(msg);
API_MSG_VAR_REF(msg).conn = conn;
@ -308,7 +320,7 @@ netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port)
* Disconnect a netconn from its current peer (only valid for UDP netconns).
*
* @param conn the netconn to disconnect
* @return @todo: return value is not set here...
* @return See @ref err_t
*/
err_t
netconn_disconnect(struct netconn *conn)
@ -378,7 +390,6 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn)
#if LWIP_TCP
void *accept_ptr;
struct netconn *newconn;
err_t err;
#if TCP_LISTEN_BACKLOG
API_MSG_VAR_DECLARE(msg);
#endif /* TCP_LISTEN_BACKLOG */
@ -387,11 +398,10 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn)
*new_conn = NULL;
LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
err = conn->last_err;
if (ERR_IS_FATAL(err)) {
if (ERR_IS_FATAL(conn->last_err)) {
/* don't recv on fatal errors: this might block the application task
waiting on acceptmbox forever! */
return err;
return conn->last_err;
}
if (!sys_mbox_valid(&conn->acceptmbox)) {
return ERR_CLSD;
@ -467,7 +477,6 @@ netconn_recv_data(struct netconn *conn, void **new_buf)
{
void *buf = NULL;
u16_t len;
err_t err;
#if LWIP_TCP
API_MSG_VAR_DECLARE(msg);
#if LWIP_MPU_COMPATIBLE
@ -491,13 +500,12 @@ netconn_recv_data(struct netconn *conn, void **new_buf)
#endif /* LWIP_TCP */
LWIP_ERROR("netconn_recv: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
err = conn->last_err;
if (ERR_IS_FATAL(err)) {
if (ERR_IS_FATAL(conn->last_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;
return conn->last_err;
}
#if LWIP_TCP
#if (LWIP_UDP || LWIP_RAW)
@ -546,6 +554,10 @@ netconn_recv_data(struct netconn *conn, void **new_buf)
/* 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);
if (conn->pcb.ip == NULL) {
/* race condition: RST during recv */
return conn->last_err == ERR_OK ? ERR_RST : conn->last_err;
}
/* RX side is closed, so deallocate the recvmbox */
netconn_close_shutdown(conn, NETCONN_SHUT_RD);
/* Don' store ERR_CLSD as conn->err since we are only half-closed */
@ -560,7 +572,7 @@ netconn_recv_data(struct netconn *conn, void **new_buf)
#if (LWIP_UDP || LWIP_RAW)
{
LWIP_ASSERT("buf != NULL", buf != NULL);
len = netbuf_len((struct netbuf *)buf);
len = netbuf_len((struct netbuf*)buf);
}
#endif /* (LWIP_UDP || LWIP_RAW) */
@ -695,6 +707,7 @@ netconn_send(struct netconn *conn, struct netbuf *buf)
LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
API_MSG_VAR_ALLOC(msg);
API_MSG_VAR_REF(msg).conn = conn;
API_MSG_VAR_REF(msg).msg.b = buf;
@ -732,6 +745,11 @@ netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
return ERR_OK;
}
dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
#if LWIP_SO_SNDTIMEO
if (conn->send_timeout != 0) {
dontblock = 1;
}
#endif /* LWIP_SO_SNDTIMEO */
if (dontblock && !bytes_written) {
/* This implies netconn_write() cannot be used for non-blocking send, since
it has no way to return the number of bytes written. */
@ -759,11 +777,7 @@ netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
non-blocking version here. */
err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg));
if ((err == ERR_OK) && (bytes_written != NULL)) {
if (dontblock
#if LWIP_SO_SNDTIMEO
|| (conn->send_timeout != 0)
#endif /* LWIP_SO_SNDTIMEO */
) {
if (dontblock) {
/* nonblocking write: maybe the data has been sent partly */
*bytes_written = API_MSG_VAR_REF(msg).msg.w.len;
} else {
@ -867,13 +881,15 @@ netconn_join_leave_group(struct netconn *conn,
API_MSG_VAR_ALLOC(msg);
#if LWIP_IPV4
/* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
if (multiaddr == NULL) {
multiaddr = IP_ADDR_ANY;
multiaddr = IP4_ADDR_ANY;
}
if (netif_addr == NULL) {
netif_addr = IP_ADDR_ANY;
netif_addr = IP4_ADDR_ANY;
}
#endif /* LWIP_IPV4 */
API_MSG_VAR_REF(msg).conn = conn;
API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
@ -912,6 +928,7 @@ netconn_gethostbyname(const char *name, ip_addr_t *addr)
sys_sem_t sem;
#endif /* LWIP_MPU_COMPATIBLE */
err_t err;
err_t cberr;
LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
@ -944,13 +961,13 @@ netconn_gethostbyname(const char *name, ip_addr_t *addr)
}
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
err = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg));
if (err != ERR_OK) {
cberr = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg));
if (cberr != ERR_OK) {
#if !LWIP_NETCONN_SEM_PER_THREAD
sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
#endif /* !LWIP_NETCONN_SEM_PER_THREAD */
API_VAR_FREE(MEMP_DNS_API_MSG, msg);
return err;
return cberr;
}
sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem));
#if !LWIP_NETCONN_SEM_PER_THREAD

View File

@ -43,6 +43,7 @@
#include "lwip/priv/api_msg.h"
#include "lwip/ip.h"
#include "lwip/ip_addr.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/raw.h"
@ -540,18 +541,26 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
* Called from lwip_netconn_do_newconn().
*
* @param msg the api_msg_msg describing the connection type
* @return msg->conn->err, but the return value is currently ignored
*/
static void
pcb_new(struct api_msg *msg)
{
LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4;
LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
#if LWIP_IPV6 && LWIP_IPV4
/* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */
if(NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) {
iptype = IPADDR_TYPE_ANY;
}
#endif
/* Allocate a PCB for this connection */
switch(NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
case NETCONN_RAW:
msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto);
if (msg->conn->pcb.raw != NULL) {
raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
}
@ -559,7 +568,7 @@ pcb_new(struct api_msg *msg)
#endif /* LWIP_RAW */
#if LWIP_UDP
case NETCONN_UDP:
msg->conn->pcb.udp = udp_new();
msg->conn->pcb.udp = udp_new_ip_type(iptype);
if (msg->conn->pcb.udp != NULL) {
#if LWIP_UDPLITE
if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
@ -575,7 +584,7 @@ pcb_new(struct api_msg *msg)
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
msg->conn->pcb.tcp = tcp_new();
msg->conn->pcb.tcp = tcp_new_ip_type(iptype);
if (msg->conn->pcb.tcp != NULL) {
setup_tcp(msg->conn);
}
@ -589,15 +598,6 @@ pcb_new(struct api_msg *msg)
if (msg->conn->pcb.ip == NULL) {
msg->err = ERR_MEM;
}
#if LWIP_IPV4 && LWIP_IPV6
else {
if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
/* Convert IPv4 PCB manually to an IPv6 PCB */
IP_SET_TYPE_VAL(msg->conn->pcb.ip->local_ip, IPADDR_TYPE_V6);
IP_SET_TYPE_VAL(msg->conn->pcb.ip->remote_ip, IPADDR_TYPE_V6);
}
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
}
/**
@ -781,16 +781,18 @@ netconn_drain(struct netconn *conn)
#if LWIP_TCP
if (sys_mbox_valid(&conn->acceptmbox)) {
while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
struct netconn *newconn = (struct netconn *)mem;
/* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
/* pcb might be set to NULL already by err_tcp() */
/* drain recvmbox */
netconn_drain(newconn);
if (newconn->pcb.tcp != NULL) {
tcp_abort(newconn->pcb.tcp);
newconn->pcb.tcp = NULL;
if (mem != &netconn_aborted) {
struct netconn *newconn = (struct netconn *)mem;
/* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
/* pcb might be set to NULL already by err_tcp() */
/* drain recvmbox */
netconn_drain(newconn);
if (newconn->pcb.tcp != NULL) {
tcp_abort(newconn->pcb.tcp);
newconn->pcb.tcp = NULL;
}
netconn_free(newconn);
}
netconn_free(newconn);
}
sys_mbox_free(&conn->acceptmbox);
sys_mbox_set_invalid(&conn->acceptmbox);
@ -805,7 +807,6 @@ netconn_drain(struct netconn *conn)
* places.
*
* @param conn the TCP netconn to close
* [@param delay 1 if called from sent/poll (wake up calling thread on end)]
*/
static err_t
lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM)
@ -1113,37 +1114,20 @@ lwip_netconn_do_bind(void *m)
} else {
msg->err = ERR_VAL;
if (msg->conn->pcb.tcp != NULL) {
const ip_addr_t *ipaddr = API_EXPR_REF(msg->msg.bc.ipaddr);
#if LWIP_IPV4 && LWIP_IPV6
/* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY,
* and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to bind
*/
if (ip_addr_cmp(ipaddr, IP6_ADDR_ANY) &&
(netconn_get_ipv6only(msg->conn) == 0)) {
/* change PCB type to IPADDR_TYPE_ANY */
IP_SET_TYPE_VAL(msg->conn->pcb.ip->local_ip, IPADDR_TYPE_ANY);
IP_SET_TYPE_VAL(msg->conn->pcb.ip->remote_ip, IPADDR_TYPE_ANY);
/* bind to IPADDR_TYPE_ANY */
ipaddr = IP_ANY_TYPE;
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
case NETCONN_RAW:
msg->err = raw_bind(msg->conn->pcb.raw, ipaddr);
msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
break;
#endif /* LWIP_RAW */
#if LWIP_UDP
case NETCONN_UDP:
msg->err = udp_bind(msg->conn->pcb.udp, ipaddr, msg->msg.bc.port);
msg->err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
msg->err = tcp_bind(msg->conn->pcb.tcp, ipaddr, msg->msg.bc.port);
msg->err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
break;
#endif /* LWIP_TCP */
default:
@ -1323,6 +1307,13 @@ lwip_netconn_do_listen(void *m)
/* connection is not closed, cannot listen */
msg->err = ERR_VAL;
} else {
err_t err;
u8_t backlog;
#if TCP_LISTEN_BACKLOG
backlog = msg->msg.lb.backlog;
#else /* TCP_LISTEN_BACKLOG */
backlog = TCP_DEFAULT_LISTEN_BACKLOG;
#endif /* TCP_LISTEN_BACKLOG */
#if LWIP_IPV4 && LWIP_IPV6
/* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
* and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
@ -1335,15 +1326,11 @@ lwip_netconn_do_listen(void *m)
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
#if TCP_LISTEN_BACKLOG
lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
#else /* TCP_LISTEN_BACKLOG */
lpcb = tcp_listen(msg->conn->pcb.tcp);
#endif /* TCP_LISTEN_BACKLOG */
lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
if (lpcb == NULL) {
/* in this case, the old pcb is still allocated */
msg->err = ERR_MEM;
msg->err = err;
} else {
/* delete the recvmbox and allocate the acceptmbox */
if (sys_mbox_valid(&msg->conn->recvmbox)) {
@ -1400,7 +1387,7 @@ lwip_netconn_do_send(void *m)
switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
case NETCONN_RAW:
if (ip_addr_isany(&msg->msg.b->addr)) {
if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
} else {
msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
@ -1490,7 +1477,6 @@ lwip_netconn_do_accepted(void *m)
* blocking application thread (waiting in netconn_write) is released.
*
* @param conn netconn (that is currently in state NETCONN_WRITE) to process
* [@param delay 1 if called from sent/poll (wake up calling thread on end)]
* @return ERR_OK
* ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
*/
@ -1512,9 +1498,8 @@ lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM)
LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
conn->write_offset < conn->current_msg->msg.w.len);
dontblock = netconn_is_nonblocking(conn) ||
(conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK);
apiflags = conn->current_msg->msg.w.apiflags;
dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
#if LWIP_SO_SNDTIMEO
if ((conn->send_timeout != 0) &&
@ -1590,10 +1575,11 @@ err_mem:
write_finished = 1;
conn->current_msg->msg.w.len = 0;
}
} else if ((err == ERR_MEM) && !dontblock) {
/* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
we do NOT return to the application thread, since ERR_MEM is
only a temporary error! */
} else if (err == ERR_MEM) {
/* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called.
For blocking sockets, we do NOT return to the application
thread, since ERR_MEM is only a temporary error! Non-blocking
will remain non-writable until sent_tcp/poll_tcp is called */
/* tcp_write returned ERR_MEM, try tcp_output anyway */
err_t out_err = tcp_output(conn->pcb.tcp);
@ -1604,7 +1590,11 @@ err_mem:
err = out_err;
write_finished = 1;
conn->current_msg->msg.w.len = 0;
} else {
} else if (dontblock) {
/* non-blocking write is done on ERR_MEM */
err = ERR_WOULDBLOCK;
write_finished = 1;
conn->current_msg->msg.w.len = 0;
}
} else {
/* On errors != ERR_MEM, we don't try writing any more but return
@ -1713,6 +1703,7 @@ lwip_netconn_do_getaddr(void *m)
ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
msg->conn->pcb.ip->remote_ip);
}
msg->err = ERR_OK;
switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW

View File

@ -37,6 +37,43 @@
*/
#include "lwip/err.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/errno.h"
#if !NO_SYS
/** Table to quickly map an lwIP error (err_t) to a socket error
* by using -err as an index */
static const int err_to_errno_table[] = {
0, /* ERR_OK 0 No error, everything OK. */
ENOMEM, /* ERR_MEM -1 Out of memory error. */
ENOBUFS, /* ERR_BUF -2 Buffer error. */
EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
EINVAL, /* ERR_VAL -6 Illegal value. */
EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
EADDRINUSE, /* ERR_USE -8 Address in use. */
EALREADY, /* ERR_ALREADY -9 Already connecting. */
EISCONN, /* ERR_ISCONN -10 Conn already established.*/
ENOTCONN, /* ERR_CONN -11 Not connected. */
-1, /* ERR_IF -12 Low-level netif error */
ECONNABORTED, /* ERR_ABRT -13 Connection aborted. */
ECONNRESET, /* ERR_RST -14 Connection reset. */
ENOTCONN, /* ERR_CLSD -15 Connection closed. */
EIO /* ERR_ARG -16 Illegal argument. */
};
int
err_to_errno(err_t err)
{
if ((err > 0) || (-err >= (err_t)LWIP_ARRAYSIZE(err_to_errno_table))) {
return EIO;
}
return err_to_errno_table[-err];
}
#endif /* !NO_SYS */
#ifdef LWIP_DEBUG
@ -69,6 +106,9 @@ static const char *err_strerr[] = {
const char *
lwip_strerr(err_t err)
{
if ((err > 0) || (-err >= (err_t)LWIP_ARRAYSIZE(err_strerr))) {
return "Unknown error.";
}
return err_strerr[-err];
}

View File

@ -2,6 +2,12 @@
* @file
* Network buffer management
*
* @defgroup netbuf Network buffers
* @ingroup netconn
* Network buffer descriptor for @ref netconn. Based on @ref pbuf internally
* to avoid copying data around.\n
* Buffers must not be shared accross multiple threads, all functions except
* netbuf_new() and netbuf_delete() are not thread-safe.
*/
/*
@ -36,15 +42,6 @@
*
*/
/**
* @defgroup netbuf Network buffers
* @ingroup netconn
* Network buffer descriptor for @ref netconn. Based on @ref pbuf internally
* to avoid copying data around.\n
* Buffers must not be shared accross multiple threads, all functions except
* netbuf_new() and netbuf_delete() are not thread-safe.
*/
#include "lwip/opt.h"
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
@ -69,23 +66,9 @@ netbuf *netbuf_new(void)
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
if (buf != NULL) {
buf->p = NULL;
buf->ptr = NULL;
ip_addr_set_zero(&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
ip_addr_set_zero(&buf->toaddr);
#endif /* LWIP_NETBUF_RECVINFO */
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
return buf;
} else {
return NULL;
memset(buf, 0, sizeof(struct netbuf));
}
return buf;
}
/**
@ -188,7 +171,7 @@ netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
void
netbuf_chain(struct netbuf *head, struct netbuf *tail)
{
LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);
LWIP_ERROR("netbuf_chain: invalid head", (head != NULL), return;);
LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);
pbuf_cat(head->p, tail->p);
head->ptr = head->p;
@ -234,7 +217,7 @@ netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
s8_t
netbuf_next(struct netbuf *buf)
{
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;);
LWIP_ERROR("netbuf_next: invalid buf", (buf != NULL), return -1;);
if (buf->ptr->next == NULL) {
return -1;
}
@ -256,7 +239,7 @@ netbuf_next(struct netbuf *buf)
void
netbuf_first(struct netbuf *buf)
{
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
LWIP_ERROR("netbuf_first: invalid buf", (buf != NULL), return;);
buf->ptr = buf->p;
}

View File

@ -2,6 +2,8 @@
* @file
* API functions for name resolving
*
* @defgroup netdbapi NETDB API
* @ingroup socket
*/
/*
@ -33,12 +35,6 @@
*
*/
/**
* @defgroup netdbapi NETDB API
* @ingroup socket
*/
#include "lwip/netdb.h"
#if LWIP_DNS && LWIP_SOCKET
@ -50,8 +46,8 @@
#include "lwip/api.h"
#include "lwip/dns.h"
#include <string.h>
#include <stdlib.h>
#include <string.h> /* memset */
#include <stdlib.h> /* atoi */
/** helper struct for gethostbyname_r to access the char* buffer */
struct gethostbyname_r_helper {
@ -379,17 +375,17 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr));
sa6->sin6_family = AF_INET6;
sa6->sin6_len = sizeof(struct sockaddr_in6);
sa6->sin6_port = htons((u16_t)port_nr);
sa6->sin6_port = lwip_htons((u16_t)port_nr);
ai->ai_family = AF_INET6;
#endif /* LWIP_IPV6 */
} else {
#if LWIP_IPV4
struct sockaddr_in *sa4 = (struct sockaddr_in*)sa;
/* set up sockaddr */
inet_addr_from_ipaddr(&sa4->sin_addr, ip_2_ip4(&addr));
inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr));
sa4->sin_family = AF_INET;
sa4->sin_len = sizeof(struct sockaddr_in);
sa4->sin_port = htons((u16_t)port_nr);
sa4->sin_port = lwip_htons((u16_t)port_nr);
ai->ai_family = AF_INET;
#endif /* LWIP_IPV4 */
}

View File

@ -2,6 +2,13 @@
* @file
* Network Interface Sequential API module
*
* @defgroup netifapi NETIF API
* @ingroup sequential_api
* Thread-safe functions to be called from non-TCPIP threads
*
* @defgroup netifapi_netif NETIF related
* @ingroup netifapi
* To be called from non-TCPIP threads
*/
/*
@ -31,16 +38,6 @@
*
*/
/**
* @defgroup netifapi NETIF API
* @ingroup threadsafe_api
* Thread-safe functions to be called from non-TCPIP threads
*
* @defgroup netifapi_netif NETIF related
* @ingroup netifapi
* To be called from non-TCPIP threads
*/
#include "lwip/opt.h"
#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */
@ -137,13 +134,13 @@ netifapi_netif_add(struct netif *netif,
#if LWIP_IPV4
if (ipaddr == NULL) {
ipaddr = IP4_ADDR_ANY;
ipaddr = IP4_ADDR_ANY4;
}
if (netmask == NULL) {
netmask = IP4_ADDR_ANY;
netmask = IP4_ADDR_ANY4;
}
if (gw == NULL) {
gw = IP4_ADDR_ANY;
gw = IP4_ADDR_ANY4;
}
#endif /* LWIP_IPV4 */
@ -180,13 +177,13 @@ netifapi_netif_set_addr(struct netif *netif,
NETIFAPI_VAR_ALLOC(msg);
if (ipaddr == NULL) {
ipaddr = IP4_ADDR_ANY;
ipaddr = IP4_ADDR_ANY4;
}
if (netmask == NULL) {
netmask = IP4_ADDR_ANY;
netmask = IP4_ADDR_ANY4;
}
if (gw == NULL) {
gw = IP4_ADDR_ANY;
gw = IP4_ADDR_ANY4;
}
NETIFAPI_VAR_REF(msg).netif = netif;

View File

@ -2,6 +2,12 @@
* @file
* Sockets BSD-Like API module
*
* @defgroup socket Socket API
* @ingroup sequential_api
* BSD-style socket API.\n
* Thread-safe, to be called from non-TCPIP threads only.\n
* Can be activated by defining @ref LWIP_SOCKET to 1.\n
* Header is in posix/sys/socket.h\b
*/
/*
@ -38,15 +44,6 @@
*
*/
/**
* @defgroup socket Socket API
* @ingroup threadsafe_api
* BSD-style socket API.\n
* Thread-safe, to be called from non-TCPIP threads only.\n
* Can be activated by defining LWIP_SOCKET to 1.\n
* Header is in posix/sys/socket.h\b
*/
#include "lwip/opt.h"
#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
@ -84,25 +81,25 @@
#define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \
(sin)->sin_len = sizeof(struct sockaddr_in); \
(sin)->sin_family = AF_INET; \
(sin)->sin_port = htons((port)); \
inet_addr_from_ipaddr(&(sin)->sin_addr, ipaddr); \
(sin)->sin_port = lwip_htons((port)); \
inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \
memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0)
#define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \
inet_addr_to_ipaddr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \
(port) = ntohs((sin)->sin_port); }while(0)
inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \
(port) = lwip_ntohs((sin)->sin_port); }while(0)
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
#define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \
(sin6)->sin6_len = sizeof(struct sockaddr_in6); \
(sin6)->sin6_family = AF_INET6; \
(sin6)->sin6_port = htons((port)); \
(sin6)->sin6_port = lwip_htons((port)); \
(sin6)->sin6_flowinfo = 0; \
inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \
(sin6)->sin6_scope_id = 0; }while(0)
#define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \
inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \
(port) = ntohs((sin6)->sin6_port); }while(0)
(port) = lwip_ntohs((sin6)->sin6_port); }while(0)
#endif /* LWIP_IPV6 */
#if LWIP_IPV4 && LWIP_IPV6
@ -269,8 +266,8 @@ union sockaddr_aligned {
/* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when
a socket is closed */
struct lwip_socket_multicast_pair {
/** the socket (+1 to not require initialization) */
int sa;
/** the socket */
struct lwip_sock* sock;
/** the interface address */
ip4_addr_t if_addr;
/** the group address */
@ -292,34 +289,6 @@ static struct lwip_select_cb *select_cb_list;
and checked in event_callback to see if it has changed. */
static volatile int select_cb_ctr;
/** Table to quickly map an lwIP error (err_t) to a socket error
* by using -err as an index */
static const int err_to_errno_table[] = {
0, /* ERR_OK 0 No error, everything OK. */
ENOMEM, /* ERR_MEM -1 Out of memory error. */
ENOBUFS, /* ERR_BUF -2 Buffer error. */
EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
EINVAL, /* ERR_VAL -6 Illegal value. */
EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
EADDRINUSE, /* ERR_USE -8 Address in use. */
EALREADY, /* ERR_ALREADY -9 Already connecting. */
EISCONN, /* ERR_ISCONN -10 Conn already established.*/
ENOTCONN, /* ERR_CONN -11 Not connected. */
-1, /* ERR_IF -12 Low-level netif error */
ECONNABORTED, /* ERR_ABRT -13 Connection aborted. */
ECONNRESET, /* ERR_RST -14 Connection reset. */
ENOTCONN, /* ERR_CLSD -15 Connection closed. */
EIO /* ERR_ARG -16 Illegal argument. */
};
#define ERR_TO_ERRNO_TABLE_SIZE LWIP_ARRAYSIZE(err_to_errno_table)
#define err_to_errno(err) \
((unsigned)(-(signed)(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
err_to_errno_table[-(signed)(err)] : EIO)
#if LWIP_SOCKET_SET_ERRNO
#ifndef set_errno
#define set_errno(err) do { if (err) { errno = (err); } } while(0)
@ -513,7 +482,7 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
sock_set_errno(sock, EWOULDBLOCK);
set_errno(EWOULDBLOCK);
return -1;
}
@ -615,6 +584,14 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port));
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Unmap IPv6 mapped IPv4 addresses */
if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&local_addr))) {
unmap_ipv6_mapped_ipv4(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr));
IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4);
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
err = netconn_bind(sock->conn, &local_addr, local_port);
if (err != ERR_OK) {
@ -699,6 +676,14 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port));
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Unmap IPv6 mapped IPv4 addresses */
if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&remote_addr))) {
unmap_ipv6_mapped_ipv4(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr));
IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4);
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
err = netconn_connect(sock->conn, &remote_addr, remote_port);
}
@ -786,7 +771,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
return off;
}
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
sock_set_errno(sock, EWOULDBLOCK);
set_errno(EWOULDBLOCK);
return -1;
}
@ -878,6 +863,15 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
port = netbuf_fromport((struct netbuf *)buf);
fromaddr = netbuf_fromaddr((struct netbuf *)buf);
}
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Map IPv4 addresses to IPv6 mapped IPv4 */
if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) && IP_IS_V4(fromaddr)) {
ip4_2_ipv6_mapped_ipv4(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr));
IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6);
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port);
ip_addr_debug_print(SOCKETS_DEBUG, fromaddr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
@ -972,8 +966,6 @@ int
lwip_sendmsg(int s, const struct msghdr *msg, int flags)
{
struct lwip_sock *sock;
struct netbuf *chain_buf;
u16_t remote_port;
int i;
#if LWIP_TCP
u8_t write_flags;
@ -1030,82 +1022,93 @@ lwip_sendmsg(int s, const struct msghdr *msg, int flags)
}
/* else, UDP and RAW NETCONNs */
#if LWIP_UDP || LWIP_RAW
{
struct netbuf *chain_buf;
LWIP_UNUSED_ARG(flags);
LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) ||
IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)) ,
sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
LWIP_UNUSED_ARG(flags);
LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) ||
IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)) ,
sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
/* initialize chain buffer with destination */
chain_buf = netbuf_new();
if (!chain_buf) {
sock_set_errno(sock, err_to_errno(ERR_MEM));
return -1;
}
if (msg->msg_name) {
SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf->addr, remote_port);
netbuf_fromport(chain_buf) = remote_port;
}
/* initialize chain buffer with destination */
chain_buf = netbuf_new();
if (!chain_buf) {
sock_set_errno(sock, err_to_errno(ERR_MEM));
return -1;
}
if (msg->msg_name) {
u16_t remote_port;
SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf->addr, remote_port);
netbuf_fromport(chain_buf) = remote_port;
}
#if LWIP_NETIF_TX_SINGLE_PBUF
for (i = 0; i < msg->msg_iovlen; i++) {
size += msg->msg_iov[i].iov_len;
}
/* Allocate a new netbuf and copy the data into it. */
if (netbuf_alloc(chain_buf, (u16_t)size) == NULL) {
err = ERR_MEM;
}
else {
/* flatten the IO vectors */
size_t offset = 0;
for (i = 0; i < msg->msg_iovlen; i++) {
MEMCPY(&((u8_t*)chain_buf->p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
offset += msg->msg_iov[i].iov_len;
size += msg->msg_iov[i].iov_len;
}
#if LWIP_CHECKSUM_ON_COPY
{
/* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */
u16_t chksum = ~inet_chksum_pbuf(chain_buf->p);
netbuf_set_chksum(chain_buf, chksum);
}
#endif /* LWIP_CHECKSUM_ON_COPY */
err = ERR_OK;
}
#else /* LWIP_NETIF_TX_SINGLE_PBUF */
/* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain
manually to avoid having to allocate, chain, and delete a netbuf for each iov */
for (i = 0; i < msg->msg_iovlen; i++) {
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
if (p == NULL) {
err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */
break;
}
p->payload = msg->msg_iov[i].iov_base;
LWIP_ASSERT("iov_len < u16_t", msg->msg_iov[i].iov_len <= 0xFFFF);
p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len;
/* netbuf empty, add new pbuf */
if (chain_buf->p == NULL) {
chain_buf->p = chain_buf->ptr = p;
/* add pbuf to existing pbuf chain */
/* Allocate a new netbuf and copy the data into it. */
if (netbuf_alloc(chain_buf, (u16_t)size) == NULL) {
err = ERR_MEM;
} else {
pbuf_cat(chain_buf->p, p);
/* flatten the IO vectors */
size_t offset = 0;
for (i = 0; i < msg->msg_iovlen; i++) {
MEMCPY(&((u8_t*)chain_buf->p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
offset += msg->msg_iov[i].iov_len;
}
#if LWIP_CHECKSUM_ON_COPY
{
/* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */
u16_t chksum = ~inet_chksum_pbuf(chain_buf->p);
netbuf_set_chksum(chain_buf, chksum);
}
#endif /* LWIP_CHECKSUM_ON_COPY */
err = ERR_OK;
}
#else /* LWIP_NETIF_TX_SINGLE_PBUF */
/* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain
manually to avoid having to allocate, chain, and delete a netbuf for each iov */
for (i = 0; i < msg->msg_iovlen; i++) {
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
if (p == NULL) {
err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */
break;
}
p->payload = msg->msg_iov[i].iov_base;
LWIP_ASSERT("iov_len < u16_t", msg->msg_iov[i].iov_len <= 0xFFFF);
p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len;
/* netbuf empty, add new pbuf */
if (chain_buf->p == NULL) {
chain_buf->p = chain_buf->ptr = p;
/* add pbuf to existing pbuf chain */
} else {
pbuf_cat(chain_buf->p, p);
}
}
/* save size of total chain */
if (err == ERR_OK) {
size = netbuf_len(chain_buf);
}
}
/* save size of total chain */
if (err == ERR_OK) {
size = netbuf_len(chain_buf);
}
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
if (err == ERR_OK) {
/* send the data */
err = netconn_send(sock->conn, chain_buf);
if (err == ERR_OK) {
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Unmap IPv6 mapped IPv4 addresses */
if (IP_IS_V6_VAL(chain_buf->addr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&chain_buf->addr))) {
unmap_ipv6_mapped_ipv4(ip_2_ip4(&chain_buf->addr), ip_2_ip6(&chain_buf->addr));
IP_SET_TYPE_VAL(chain_buf->addr, IPADDR_TYPE_V4);
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
/* send the data */
err = netconn_send(sock->conn, chain_buf);
}
/* deallocated the buffer */
netbuf_delete(chain_buf);
sock_set_errno(sock, err_to_errno(err));
return (err == ERR_OK ? size : -1);
}
/* deallocated the buffer */
netbuf_delete(chain_buf);
sock_set_errno(sock, err_to_errno(err));
return (err == ERR_OK ? size : -1);
#else /* LWIP_UDP || LWIP_RAW */
sock_set_errno(sock, err_to_errno(ERR_ARG));
return -1;
@ -1137,12 +1140,6 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
#endif /* LWIP_TCP */
}
if ((to != NULL) && !SOCK_ADDR_TYPE_MATCH(to, sock)) {
/* sockaddr does not match socket type (IPv4/IPv6) */
sock_set_errno(sock, err_to_errno(ERR_VAL));
return -1;
}
/* @todo: split into multiple sendto's? */
LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
short_size = (u16_t)size;
@ -1192,6 +1189,14 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
err = netbuf_ref(&buf, data, short_size);
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
if (err == ERR_OK) {
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Unmap IPv6 mapped IPv4 addresses */
if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&buf.addr))) {
unmap_ipv6_mapped_ipv4(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr));
IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4);
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
/* send the data */
err = netconn_send(sock->conn, &buf);
}
@ -1209,9 +1214,7 @@ lwip_socket(int domain, int type, int protocol)
struct netconn *conn;
int i;
#if !LWIP_IPV6
LWIP_UNUSED_ARG(domain); /* @todo: check this */
#endif /* LWIP_IPV6 */
/* create a netconn */
switch (type) {
@ -1274,7 +1277,7 @@ lwip_writev(int s, const struct iovec *iov, int iovcnt)
msg.msg_namelen = 0;
/* Hack: we have to cast via number to cast from 'const' pointer to non-const.
Blame the opengroup standard for this inconsistency. */
msg.msg_iov = (struct iovec *)(size_t)iov;
msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov);
msg.msg_iovlen = iovcnt;
msg.msg_control = NULL;
msg.msg_controllen = 0;
@ -1288,12 +1291,12 @@ lwip_writev(int s, const struct iovec *iov, int iovcnt)
* the sockets enabled that had events.
*
* @param maxfdp1 the highest socket index in the sets
* @param readset_in: set of sockets to check for read events
* @param writeset_in: set of sockets to check for write events
* @param exceptset_in: set of sockets to check for error events
* @param readset_out: set of sockets that had read events
* @param writeset_out: set of sockets that had write events
* @param exceptset_out: set os sockets that had error events
* @param readset_in set of sockets to check for read events
* @param writeset_in set of sockets to check for write events
* @param exceptset_in set of sockets to check for error events
* @param readset_out set of sockets that had read events
* @param writeset_out set of sockets that had write events
* @param exceptset_out set os sockets that had error events
* @return number of sockets that had events (read/write/exception) (>= 0)
*/
static int
@ -1740,12 +1743,21 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
}
/* get the IP address and port */
/* @todo: this does not work for IPv6, yet */
err = netconn_getaddr(sock->conn, &naddr, &port, local);
if (err != ERR_OK) {
sock_set_errno(sock, err_to_errno(err));
return -1;
}
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Map IPv4 addresses to IPv6 mapped IPv4 */
if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) &&
IP_IS_V4_VAL(naddr)) {
ip4_2_ipv6_mapped_ipv4(ip_2_ip6(&naddr), ip_2_ip4(&naddr));
IP_SET_TYPE_VAL(naddr, IPADDR_TYPE_V6);
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
@ -1832,7 +1844,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
/* write back optlen and optval */
*optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen;
#if LWIP_MPU_COMPATIBLE
memcpy(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval,
MEMCPY(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval,
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen);
#endif /* LWIP_MPU_COMPATIBLE */
@ -2022,7 +2034,7 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
return ENOPROTOOPT;
}
*(u8_t*)optval = sock->conn->pcb.udp->mcast_ttl;
*(u8_t*)optval = udp_get_multicast_ttl(sock->conn->pcb.udp);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
s, *(int *)optval));
break;
@ -2031,7 +2043,7 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
return ENOPROTOOPT;
}
inet_addr_from_ipaddr((struct in_addr*)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp));
inet_addr_from_ip4addr((struct in_addr*)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp));
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
s, *(u32_t *)optval));
break;
@ -2059,6 +2071,9 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt
case IPPROTO_TCP:
/* Special case: all IPPROTO_TCP option take an int */
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP);
if (sock->conn->pcb.tcp->state == LISTEN) {
return EINVAL;
}
switch (optname) {
case TCP_NODELAY:
*(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
@ -2103,10 +2118,6 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt
switch (optname) {
case IPV6_V6ONLY:
LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
/* @todo: this does not work for datagram sockets, yet */
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
return ENOPROTOOPT;
}
*(int*)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n",
s, *(int *)optval));
@ -2220,7 +2231,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname;
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen;
#if LWIP_MPU_COMPATIBLE
memcpy(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen);
MEMCPY(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen);
#else /* LWIP_MPU_COMPATIBLE */
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void*)optval;
#endif /* LWIP_MPU_COMPATIBLE */
@ -2389,13 +2400,13 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
#if LWIP_MULTICAST_TX_OPTIONS
case IP_MULTICAST_TTL:
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
sock->conn->pcb.udp->mcast_ttl = (u8_t)(*(const u8_t*)optval);
udp_set_multicast_ttl(sock->conn->pcb.udp, (u8_t)(*(const u8_t*)optval));
break;
case IP_MULTICAST_IF:
{
ip4_addr_t if_addr;
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP);
inet_addr_to_ipaddr(&if_addr, (const struct in_addr*)optval);
inet_addr_to_ip4addr(&if_addr, (const struct in_addr*)optval);
udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr);
}
break;
@ -2419,8 +2430,8 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
ip4_addr_t if_addr;
ip4_addr_t multi_addr;
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP);
inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
inet_addr_to_ip4addr(&if_addr, &imr->imr_interface);
inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr);
if (optname == IP_ADD_MEMBERSHIP) {
if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) {
/* cannot track membership (out of memory) */
@ -2452,6 +2463,9 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
case IPPROTO_TCP:
/* Special case: all IPPROTO_TCP option take an int */
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
if (sock->conn->pcb.tcp->state == LISTEN) {
return EINVAL;
}
switch (optname) {
case TCP_NODELAY:
if (*(const int*)optval) {
@ -2499,7 +2513,6 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
case IPPROTO_IPV6:
switch (optname) {
case IPV6_V6ONLY:
/* @todo: this does not work for datagram sockets, yet */
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
if (*(const int*)optval) {
netconn_set_ipv6only(sock->conn, 1);
@ -2732,14 +2745,16 @@ lwip_fcntl(int s, int cmd, int val)
static int
lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
{
/* s+1 is stored in the array to prevent having to initialize the array
(default initialization is to 0) */
int sa = s + 1;
struct lwip_sock *sock = get_socket(s);
int i;
if (!sock) {
return 0;
}
for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
if (socket_ipv4_multicast_memberships[i].sa == 0) {
socket_ipv4_multicast_memberships[i].sa = sa;
if (socket_ipv4_multicast_memberships[i].sock == NULL) {
socket_ipv4_multicast_memberships[i].sock = sock;
ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr);
ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr);
return 1;
@ -2756,16 +2771,18 @@ lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr
static void
lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
{
/* s+1 is stored in the array to prevent having to initialize the array
(default initialization is to 0) */
int sa = s + 1;
struct lwip_sock *sock = get_socket(s);
int i;
if (!sock) {
return;
}
for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
if ((socket_ipv4_multicast_memberships[i].sa == sa) &&
if ((socket_ipv4_multicast_memberships[i].sock == sock) &&
ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) &&
ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) {
socket_ipv4_multicast_memberships[i].sa = 0;
socket_ipv4_multicast_memberships[i].sock = NULL;
ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
return;
@ -2777,25 +2794,26 @@ lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_ad
*
* ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK).
*/
static void lwip_socket_drop_registered_memberships(int s)
static void
lwip_socket_drop_registered_memberships(int s)
{
/* s+1 is stored in the array to prevent having to initialize the array
(default initialization is to 0) */
int sa = s + 1;
struct lwip_sock *sock = get_socket(s);
int i;
LWIP_ASSERT("socket has no netconn", sockets[s].conn != NULL);
if (!sock) {
return;
}
for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
if (socket_ipv4_multicast_memberships[i].sa == sa) {
if (socket_ipv4_multicast_memberships[i].sock == sock) {
ip_addr_t multi_addr, if_addr;
ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr);
ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr);
socket_ipv4_multicast_memberships[i].sa = 0;
socket_ipv4_multicast_memberships[i].sock = NULL;
ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
netconn_join_leave_group(sockets[s].conn, &multi_addr, &if_addr, NETCONN_LEAVE);
netconn_join_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE);
}
}
}

View File

@ -48,6 +48,7 @@
#include "lwip/ip.h"
#include "lwip/pbuf.h"
#include "lwip/etharp.h"
#include "netif/lwip_ethernet.h"
#define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name)
#define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name)
@ -64,6 +65,13 @@ static sys_mbox_t mbox;
sys_mutex_t lock_tcpip_core;
#endif /* LWIP_TCPIP_CORE_LOCKING */
#if LWIP_TIMERS
/* wait for a message, timeouts are processed while waiting */
#define TCPIP_MBOX_FETCH(mbox, msg) sys_timeouts_mbox_fetch(mbox, msg)
#else /* LWIP_TIMERS */
/* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */
#define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg)
#endif /* LWIP_TIMERS */
/**
* The main lwIP thread. This thread has exclusive access to lwIP core functions
@ -90,7 +98,7 @@ tcpip_thread(void *arg)
UNLOCK_TCPIP_CORE();
LWIP_TCPIP_THREAD_ALIVE();
/* wait for a message, timeouts are processed while waiting */
sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
TCPIP_MBOX_FETCH(&mbox, (void **)&msg);
LOCK_TCPIP_CORE();
if (msg == NULL) {
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n"));
@ -118,7 +126,7 @@ tcpip_thread(void *arg)
break;
#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
#if LWIP_TCPIP_TIMEOUT
#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
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);
@ -129,7 +137,7 @@ 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 */
#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
case TCPIP_MSG_CALLBACK:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
@ -248,11 +256,11 @@ tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
return ERR_OK;
}
#if LWIP_TCPIP_TIMEOUT
#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
/**
* call sys_timeout in tcpip_thread
*
* @param msec time in milliseconds for timeout
* @param msecs 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
@ -280,7 +288,6 @@ tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
/**
* call sys_untimeout in tcpip_thread
*
* @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
@ -303,7 +310,7 @@ tcpip_untimeout(sys_timeout_handler h, void *arg)
sys_mbox_post(&mbox, msg);
return ERR_OK;
}
#endif /* LWIP_TCPIP_TIMEOUT */
#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
/**
@ -374,7 +381,7 @@ tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call)
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
TCPIP_MSG_VAR_ALLOC(msg);
TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL;
TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call;

View File

@ -98,8 +98,8 @@
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include <string.h>
#include <stdlib.h>
#include <string.h> /* memset */
#include <stdlib.h> /* atoi */
#include <stdio.h>
#if LWIP_TCP
@ -337,82 +337,6 @@ char *http_cgi_param_vals[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Values for each ext
static struct http_state *http_connections;
#endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */
#if LWIP_HTTPD_STRNSTR_PRIVATE
/** Like strstr but does not need 'buffer' to be NULL-terminated */
static char*
strnstr(const char* buffer, const char* token, size_t n)
{
const char* p;
int tokenlen = (int)strlen(token);
if (tokenlen == 0) {
return (char *)(size_t)buffer;
}
for (p = buffer; *p && (p + tokenlen <= buffer + n); p++) {
if ((*p == *token) && (strncmp(p, token, tokenlen) == 0)) {
return (char *)(size_t)p;
}
}
return NULL;
}
#endif /* LWIP_HTTPD_STRNSTR_PRIVATE */
#if LWIP_HTTPD_STRICMP_PRIVATE
static int
stricmp(const char* str1, const char* str2)
{
char c1, c2;
do {
c1 = *str1++;
c2 = *str2++;
if (c1 != c2) {
char c1_upc = c1 | 0x20;
if ((c1_upc >= 'a') && (c1_upc <= 'z')) {
/* characters are not equal an one is in the alphabet range:
downcase both chars and check again */
char c2_upc = c2 | 0x20;
if (c1_upc != c2_upc) {
/* still not equal */
/* don't care for < or > */
return 1;
}
} else {
/* characters are not equal but none is in the alphabet range */
return 1;
}
}
} while (c1 != 0);
return 0;
}
#endif /* LWIP_HTTPD_STRICMP_PRIVATE */
#if LWIP_HTTPD_ITOA_PRIVATE && LWIP_HTTPD_DYNAMIC_HEADERS
static void
httpd_itoa(int value, char* result)
{
const int base = 10;
char* ptr = result, *ptr1 = result, tmp_char;
int tmp_value;
do {
tmp_value = value;
value /= base;
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - value * base)];
} while(value);
/* Apply negative sign */
if (tmp_value < 0) {
*ptr++ = '-';
}
*ptr-- = '\0';
while(ptr1 < ptr) {
tmp_char = *ptr;
*ptr--= *ptr1;
*ptr1++ = tmp_char;
}
}
#endif
#if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED
static void
http_kill_oldest_connection(u8_t ssi_required)
@ -964,7 +888,7 @@ get_http_headers(struct http_state *hs, const char *uri)
/* Now determine the content type and add the relevant header for that. */
for (content_type = 0; content_type < NUM_HTTP_HEADERS; content_type++) {
/* Have we found a matching extension? */
if(!stricmp(g_psHTTPHeaders[content_type].extension, ext)) {
if(!lwip_stricmp(g_psHTTPHeaders[content_type].extension, ext)) {
break;
}
}
@ -1012,7 +936,7 @@ get_http_headers(struct http_state *hs, const char *uri)
}
if (add_content_len) {
size_t len;
LWIP_HTTPD_ITOA(hs->hdr_content_len, (size_t)LWIP_HTTPD_MAX_CONTENT_LEN_SIZE,
lwip_itoa(hs->hdr_content_len, (size_t)LWIP_HTTPD_MAX_CONTENT_LEN_SIZE,
hs->handle->len);
len = strlen(hs->hdr_content_len);
if (len <= LWIP_HTTPD_MAX_CONTENT_LEN_SIZE - LWIP_HTTPD_MAX_CONTENT_LEN_OFFSET) {
@ -1112,7 +1036,7 @@ http_send_headers(struct tcp_pcb *pcb, struct http_state *hs)
* (which would happen when sending files from async read). */
if(http_check_eof(pcb, hs)) {
data_to_send = HTTP_DATA_TO_SEND_CONTINUE;
}
}
}
/* If we get here and there are still header bytes to send, we send
* the header information we just wrote immediately. If there are no
@ -1553,6 +1477,8 @@ http_send_data_ssi(struct tcp_pcb *pcb, struct http_state *hs)
}
}
break;
default:
break;
}
}
}
@ -1802,16 +1728,16 @@ http_post_request(struct pbuf *inp, struct http_state *hs,
{
err_t err;
/* search for end-of-header (first double-CRLF) */
char* crlfcrlf = strnstr(uri_end + 1, CRLF CRLF, data_len - (uri_end + 1 - data));
char* crlfcrlf = lwip_strnstr(uri_end + 1, CRLF CRLF, data_len - (uri_end + 1 - data));
if (crlfcrlf != NULL) {
/* search for "Content-Length: " */
#define HTTP_HDR_CONTENT_LEN "Content-Length: "
#define HTTP_HDR_CONTENT_LEN_LEN 16
#define HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN 10
char *scontent_len = strnstr(uri_end + 1, HTTP_HDR_CONTENT_LEN, crlfcrlf - (uri_end + 1));
char *scontent_len = lwip_strnstr(uri_end + 1, HTTP_HDR_CONTENT_LEN, crlfcrlf - (uri_end + 1));
if (scontent_len != NULL) {
char *scontent_len_end = strnstr(scontent_len + HTTP_HDR_CONTENT_LEN_LEN, CRLF, HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN);
char *scontent_len_end = lwip_strnstr(scontent_len + HTTP_HDR_CONTENT_LEN_LEN, CRLF, HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN);
if (scontent_len_end != NULL) {
int content_len;
char *content_len_num = scontent_len + HTTP_HDR_CONTENT_LEN_LEN;
@ -1953,7 +1879,7 @@ http_continue(void *connection)
* When data has been received in the correct state, try to parse it
* as a HTTP request.
*
* @param p the received pbuf
* @param inp the received pbuf
* @param hs the connection state
* @param pcb the tcp_pcb which received this packet
* @return ERR_OK if request was OK and hs has been initialized correctly
@ -2020,7 +1946,7 @@ http_parse_request(struct pbuf *inp, struct http_state *hs, struct tcp_pcb *pcb)
/* received enough data for minimal request? */
if (data_len >= MIN_REQ_LEN) {
/* wait for CRLF before parsing anything */
crlf = strnstr(data, CRLF, data_len);
crlf = lwip_strnstr(data, CRLF, data_len);
if (crlf != NULL) {
#if LWIP_HTTPD_SUPPORT_POST
int is_post = 0;
@ -2052,11 +1978,11 @@ http_parse_request(struct pbuf *inp, struct http_state *hs, struct tcp_pcb *pcb)
}
/* if we come here, method is OK, parse URI */
left_len = (u16_t)(data_len - ((sp1 +1) - data));
sp2 = strnstr(sp1 + 1, " ", left_len);
sp2 = lwip_strnstr(sp1 + 1, " ", left_len);
#if LWIP_HTTPD_SUPPORT_V09
if (sp2 == NULL) {
/* HTTP 0.9: respond with correct protocol version */
sp2 = strnstr(sp1 + 1, CRLF, left_len);
sp2 = lwip_strnstr(sp1 + 1, CRLF, left_len);
is_09 = 1;
#if LWIP_HTTPD_SUPPORT_POST
if (is_post) {
@ -2069,13 +1995,13 @@ http_parse_request(struct pbuf *inp, struct http_state *hs, struct tcp_pcb *pcb)
uri_len = (u16_t)(sp2 - (sp1 + 1));
if ((sp2 != 0) && (sp2 > sp1)) {
/* wait for CRLFCRLF (indicating end of HTTP headers) before parsing anything */
if (strnstr(data, CRLF CRLF, data_len) != NULL) {
if (lwip_strnstr(data, CRLF CRLF, data_len) != NULL) {
char *uri = sp1 + 1;
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
/* This is HTTP/1.0 compatible: for strict 1.1, a connection
would always be persistent unless "close" was specified. */
if (!is_09 && (strnstr(data, HTTP11_CONNECTIONKEEPALIVE, data_len) ||
strnstr(data, HTTP11_CONNECTIONKEEPALIVE2, data_len))) {
if (!is_09 && (lwip_strnstr(data, HTTP11_CONNECTIONKEEPALIVE, data_len) ||
lwip_strnstr(data, HTTP11_CONNECTIONKEEPALIVE2, data_len))) {
hs->keepalive = 1;
} else {
hs->keepalive = 0;
@ -2259,7 +2185,7 @@ http_find_file(struct http_state *hs, const char *uri, int is_09)
}
tag_check = 0;
for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) {
if (!stricmp(ext, g_pcSSIExtensions[loop])) {
if (!lwip_stricmp(ext, g_pcSSIExtensions[loop])) {
tag_check = 1;
break;
}
@ -2285,7 +2211,7 @@ http_find_file(struct http_state *hs, const char *uri, int is_09)
* @param is_09 1 if the request is HTTP/0.9 (no HTTP headers in response)
* @param uri the HTTP header URI
* @param tag_check enable SSI tag checking
* @param uri_has_params != NULL if URI has parameters (separated by '?')
* @param params != NULL if URI has parameters (separated by '?')
* @return ERR_OK if file was found and hs has been initialized correctly
* another err_t otherwise
*/
@ -2334,7 +2260,7 @@ http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const cha
if (is_09 && ((hs->handle->flags & FS_FILE_FLAGS_HEADER_INCLUDED) != 0)) {
/* HTTP/0.9 responses are sent without HTTP header,
search for the end of the header. */
char *file_start = strnstr(hs->file, CRLF CRLF, hs->left);
char *file_start = lwip_strnstr(hs->file, CRLF CRLF, hs->left);
if (file_start != NULL) {
size_t diff = file_start + 4 - hs->file;
hs->file += diff;
@ -2584,7 +2510,7 @@ http_accept(void *arg, struct tcp_pcb *pcb, err_t err)
LWIP_UNUSED_ARG(err);
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(HTTPD_DEBUG, ("http_accept %p / %p\n", (void*)pcb, arg));
if ((err != ERR_OK) || (pcb == NULL)) {
return ERR_VAL;
}
@ -2637,6 +2563,7 @@ httpd_init(void)
tcp_setprio(pcb, HTTPD_TCP_PRIO);
/* set SOF_REUSEADDR here to explicitly bind httpd to multiple interfaces */
err = tcp_bind(pcb, IP_ANY_TYPE, HTTPD_SERVER_PORT);
LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("httpd_init: tcp_bind failed", err == ERR_OK);
pcb = tcp_listen(pcb);
LWIP_ASSERT("httpd_init: tcp_listen failed", pcb != NULL);
@ -2684,7 +2611,7 @@ http_set_cgi_handlers(const tCGI *cgis, int num_handlers)
{
LWIP_ASSERT("no cgis given", cgis != NULL);
LWIP_ASSERT("invalid number of handlers", num_handlers > 0);
g_pCGIs = cgis;
g_iNumCGIs = num_handlers;
}

View File

@ -2,7 +2,7 @@
* makefsdata: Converts a directory structure for use with the lwIP httpd.
*
* This file is part of the lwIP TCP/IP stack.
*
*
* Author: Jim Pettinato
* Simon Goldschmidt
*
@ -818,7 +818,7 @@ int file_write_http_header(FILE *data_file, const char *filename, int file_size,
u8_t provide_last_modified = includeLastModified;
memset(hdr_buf, 0, sizeof(hdr_buf));
if (useHttp11) {
response_type = HTTP_HDR_OK_11;
}

View File

@ -262,7 +262,7 @@ lwiperf_tcp_client_send_more(lwiperf_state_tcp_t* conn)
/* this session is time-limited */
u32_t now = sys_now();
u32_t diff_ms = now - conn->time_started;
u32_t time = (u32_t)-(s32_t)htonl(conn->settings.amount);
u32_t time = (u32_t)-(s32_t)lwip_htonl(conn->settings.amount);
u32_t time_ms = time * 10;
if (diff_ms >= time_ms) {
/* time specified by the client is over -> close the connection */
@ -271,7 +271,7 @@ lwiperf_tcp_client_send_more(lwiperf_state_tcp_t* conn)
}
} else {
/* this session is byte-limited */
u32_t amount_bytes = htonl(conn->settings.amount);
u32_t amount_bytes = lwip_htonl(conn->settings.amount);
/* @todo: this can send up to 1*MSS more than requested... */
if (amount_bytes >= conn->bytes_transferred) {
/* all requested bytes transferred -> close the connection */
@ -294,7 +294,7 @@ lwiperf_tcp_client_send_more(lwiperf_state_tcp_t* conn)
} else {
/* transmit data */
/* @todo: every x bytes, transmit the settings again */
txptr = (void*)(size_t)&lwiperf_txbuf_const[conn->bytes_transferred % 10];
txptr = LWIP_CONST_CAST(void*, &lwiperf_txbuf_const[conn->bytes_transferred % 10]);
txlen_max = TCP_MSS;
if (conn->bytes_transferred == 48) { /* @todo: fix this for intermediate settings, too */
txlen_max = TCP_MSS - 24;
@ -374,7 +374,7 @@ lwiperf_tx_start(lwiperf_state_tcp_t* conn)
return ERR_MEM;
}
memcpy(client_conn, conn, sizeof(lwiperf_state_tcp_t));
MEMCPY(client_conn, conn, sizeof(lwiperf_state_tcp_t));
client_conn->base.server = 0;
client_conn->server_pcb = NULL;
client_conn->conn_pcb = newpcb;
@ -390,7 +390,7 @@ lwiperf_tx_start(lwiperf_state_tcp_t* conn)
tcp_err(newpcb, lwiperf_tcp_err);
ip_addr_copy(remote_addr, conn->conn_pcb->remote_ip);
remote_port = (u16_t)htonl(client_conn->settings.remote_port);
remote_port = (u16_t)lwip_htonl(client_conn->settings.remote_port);
err = tcp_connect(newpcb, &remote_addr, remote_port, lwiperf_tcp_client_connected);
if (err != ERR_OK) {
@ -405,6 +405,7 @@ lwiperf_tx_start(lwiperf_state_tcp_t* conn)
static err_t
lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
u8_t tmp;
u16_t tot_len;
u32_t packet_idx;
struct pbuf* q;
@ -470,8 +471,8 @@ lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
return ERR_OK;
}
conn->next_num = 4; /* 24 bytes received... */
err = pbuf_header(p, -24);
LWIP_ASSERT("pbuf_header failed", err == ERR_OK);
tmp = pbuf_header(p, -24);
LWIP_ASSERT("pbuf_header failed", tmp == 0);
}
packet_idx = 0;
@ -493,10 +494,8 @@ lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
return ERR_VAL;
}
}
packet_idx += i;
#else
packet_idx += q->len;
#endif
packet_idx += q->len;
}
LWIP_ASSERT("count mismatch", packet_idx == p->tot_len);
conn->bytes_transferred += packet_idx;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -46,6 +46,7 @@
#if LWIP_IPV4 && LWIP_UDP /* don't build if not configured for use in lwipopts.h */
#include "lwip/def.h"
#include "lwip/udp.h"
#include "lwip/netif.h"
@ -270,7 +271,7 @@ netbiosns_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t
/* decode the NetBIOS name */
netbiosns_name_decode((char*)(netbios_name_hdr->encname), netbios_name, sizeof(netbios_name));
/* if the packet is for us */
if (NETBIOS_STRCMP(netbios_name, NETBIOS_LOCAL_NAME) == 0) {
if (lwip_strnicmp(netbios_name, NETBIOS_LOCAL_NAME, sizeof(NETBIOS_LOCAL_NAME)) == 0) {
struct pbuf *q;
struct netbios_resp *resp;
@ -327,7 +328,7 @@ netbiosns_init(void)
netbiosns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
if (netbiosns_pcb != NULL) {
/* we have to be allowed to send broadcast packets! */
netbiosns_pcb->so_options |= SOF_BROADCAST;
ip_set_option(netbiosns_pcb, SOF_BROADCAST);
udp_bind(netbiosns_pcb, IP_ANY_TYPE, NETBIOS_PORT);
udp_recv(netbiosns_pcb, netbiosns_recv, netbiosns_pcb);
}
@ -346,7 +347,7 @@ netbiosns_set_name(const char* hostname)
if (copy_len >= NETBIOS_NAME_LEN) {
copy_len = NETBIOS_NAME_LEN - 1;
}
memcpy(netbiosns_local_name, hostname, copy_len + 1);
MEMCPY(netbiosns_local_name, hostname, copy_len + 1);
}
#endif

View File

@ -1,38 +0,0 @@
lwIP SNMPv2c agent
==================
Based on SNMP stack written by Christiaan Simons <christiaan.simons@axon.tv>
Rewritten by Martin Hentschel <info@cl-soft.de> and
Dirk Ziegelmeier <dziegel@gmx.de>
Features:
- SNMPv2c support.
- Low RAM usage - no memory pools, stack only.
- MIB2 implementation is separated from SNMP stack.
- Support for multiple MIBs (snmp_set_mibs() call) - e.g. for private MIB.
- Simple and generic API for MIB implementation.
- Comfortable node types and helper functions for scalar arrays and tables.
- Counter64, bit and truthvalue datatype support.
- Callbacks for SNMP writes e.g. to implement persistency.
- Runs on two APIs: RAW and netconn.
- Async API is gone - the stack now supports netconn API instead,
so blocking operations can be done in MIB calls.
SNMP runs in a worker thread when netconn API is used.
- Simplified thread sync support for MIBs - useful when MIBs
need to access variables shared with other threads where no locking is
possible. Used in MIB2 to access lwIP stats from lwIP thread.
MIB compiler (code generator):
- Written in C#. MIB viewer used Windows Forms.
- Developed on Windows with Visual Studio 2010.
- Can be compiled and used under Linux with http://www.monodevelop.com/.
- Based on a heavily modified version of of SharpSnmpLib (a4bd05c6afb4)
(https://sharpsnmplib.codeplex.com/SourceControl/network/forks/Nemo157/MIBParserUpdate).
- MIB parser, C file generation framework and LWIP code generation are cleanly
separated, which means the code may be useful as a base for code generation
of other SNMP agents.
Notes:
- Stack and MIB compiler were used to implement a Profinet device.
Compiled/implemented MIBs: LLDP-MIB, LLDP-EXT-DOT3-MIB, LLDP-EXT-PNO-MIB.

View File

@ -196,10 +196,10 @@ snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, co
octets_needed--;
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> ((octets_needed-4) << 3))));
}
/* skip to low u32 */
value++;
while (octets_needed > 1) {
octets_needed--;
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> (octets_needed << 3))));
@ -288,7 +288,7 @@ snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t
/**
* Returns octet count for length.
*
* @param length
* @param length parameter length
* @param octets_needed points to the return value
*/
void
@ -306,7 +306,7 @@ snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
/**
* Returns octet count for an u32_t.
*
* @param value
* @param value value to be encoded
* @param octets_needed points to the return value
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
@ -332,7 +332,7 @@ snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
/**
* Returns octet count for an u64_t.
*
* @param value
* @param value value to be encoded
* @param octets_needed points to the return value
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
@ -357,7 +357,7 @@ snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed)
/**
* Returns octet count for an s32_t.
*
* @param value
* @param value value to be encoded
* @param octets_needed points to the return value
*
* @note ASN coded integers are _always_ signed.
@ -367,7 +367,7 @@ snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
{
if (value < 0) {
value = ~value;
}
}
if (value < 0x80L) {
*octets_needed = 1;
} else if (value < 0x8000L) {
@ -453,7 +453,7 @@ snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tl
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
tlv->value_len <<= 8;
tlv->value_len |= data;
/* take care for special value used for indefinite length */
if (tlv->value_len == 0xFFFF) {
return ERR_VAL;
@ -551,7 +551,7 @@ snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value
} else {
*value <<= 8;
}
*value |= data;
len--;
}
@ -588,7 +588,7 @@ snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value
if ((len > 0) && (len < 5)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
if (data & 0x80) {
/* negative, start from -1 */
*value = -1;
@ -649,7 +649,7 @@ snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u
if (oid_max_len < 2) {
return ERR_MEM;
}
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
@ -736,7 +736,7 @@ snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u1
return ERR_MEM;
}
*buf_len = len;
while (len > 0) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, buf));
buf++;

View File

@ -42,11 +42,48 @@
* The agent implements the most important MIB2 MIBs including IPv6 support
* (interfaces, UDP, TCP, SNMP, ICMP, SYSTEM). IP MIB is an older version
* whithout IPv6 statistics (TODO).\n
* Work on SNMPv3 has started, but is not finished.
* Rewritten by Martin Hentschel <info@cl-soft.de> and
* Dirk Ziegelmeier <dziegel@gmx.de>\n
* Work on SNMPv3 has started, but is not finished.\n
*
* 0 Agent Capabilities
* ====================
*
* Features:
* ---------
* - SNMPv2c support.
* - Low RAM usage - no memory pools, stack only.
* - MIB2 implementation is separated from SNMP stack.
* - Support for multiple MIBs (snmp_set_mibs() call) - e.g. for private MIB.
* - Simple and generic API for MIB implementation.
* - Comfortable node types and helper functions for scalar arrays and tables.
* - Counter64, bit and truthvalue datatype support.
* - Callbacks for SNMP writes e.g. to implement persistency.
* - Runs on two APIs: RAW and netconn.
* - Async API is gone - the stack now supports netconn API instead,
* so blocking operations can be done in MIB calls.
* SNMP runs in a worker thread when netconn API is used.
* - Simplified thread sync support for MIBs - useful when MIBs
* need to access variables shared with other threads where no locking is
* possible. Used in MIB2 to access lwIP stats from lwIP thread.
*
* MIB compiler (code generator):
* ------------------------------
* - Provided in lwIP contrib repository.
* - Written in C#. MIB viewer used Windows Forms.
* - Developed on Windows with Visual Studio 2010.
* - Can be compiled and used on all platforms with http://www.monodevelop.com/.
* - Based on a heavily modified version of of SharpSnmpLib (a4bd05c6afb4)
* (https://sharpsnmplib.codeplex.com/SourceControl/network/forks/Nemo157/MIBParserUpdate).
* - MIB parser, C file generation framework and LWIP code generation are cleanly
* separated, which means the code may be useful as a base for code generation
* of other SNMP agents.
*
* Notes:
* ------
* - Stack and MIB compiler were used to implement a Profinet device.
* Compiled/implemented MIBs: LLDP-MIB, LLDP-EXT-DOT3-MIB, LLDP-EXT-PNO-MIB.
*
* SNMPv1 per RFC1157 and SNMPv2c per RFC 3416
* -------------------------------------------
* Note the S in SNMP stands for "Simple". Note that "Simple" is
@ -233,7 +270,7 @@ snmp_oid_to_ip4(const u32_t *oid, ip4_addr_t *ip)
(oid[1] > 0xFF) ||
(oid[2] > 0xFF) ||
(oid[3] > 0xFF)) {
ip4_addr_copy(*ip, *IP4_ADDR_ANY);
ip4_addr_copy(*ip, *IP4_ADDR_ANY4);
return 0;
}
@ -285,10 +322,10 @@ snmp_oid_to_ip6(const u32_t *oid, ip6_addr_t *ip)
return 0;
}
ip->addr[0] = (oid[0] << 24) | (oid[1] << 16) | (oid[2] << 8) | (oid[3] << 0);
ip->addr[1] = (oid[4] << 24) | (oid[5] << 16) | (oid[6] << 8) | (oid[7] << 0);
ip->addr[2] = (oid[8] << 24) | (oid[9] << 16) | (oid[10] << 8) | (oid[11] << 0);
ip->addr[3] = (oid[12] << 24) | (oid[13] << 16) | (oid[14] << 8) | (oid[15] << 0);
ip->addr[0] = (oid[0] << 24) | (oid[1] << 16) | (oid[2] << 8) | (oid[3] << 0);
ip->addr[1] = (oid[4] << 24) | (oid[5] << 16) | (oid[6] << 8) | (oid[7] << 0);
ip->addr[2] = (oid[8] << 24) | (oid[9] << 16) | (oid[10] << 8) | (oid[11] << 0);
ip->addr[3] = (oid[12] << 24) | (oid[13] << 16) | (oid[14] << 8) | (oid[15] << 0);
return 1;
}
@ -322,9 +359,9 @@ snmp_ip6_to_oid(const ip6_addr_t *ip, u32_t *oid)
#if LWIP_IPV4 || LWIP_IPV6
/**
* Convert to InetAddressType+InetAddress+InetPortNumber
* @param ip
* @param port
* @param oid
* @param ip IP address
* @param port Port
* @param oid OID
* @return OID length
*/
u8_t
@ -335,14 +372,14 @@ snmp_ip_port_to_oid(const ip_addr_t *ip, u16_t port, u32_t *oid)
idx = snmp_ip_to_oid(ip, oid);
oid[idx] = port;
idx++;
return idx;
}
/**
* Convert to InetAddressType+InetAddress
* @param ip
* @param oid
* @param ip IP address
* @param oid OID
* @return OID length
*/
u8_t
@ -375,9 +412,9 @@ snmp_ip_to_oid(const ip_addr_t *ip, u32_t *oid)
/**
* Convert from InetAddressType+InetAddress to ip_addr_t
* @param oid
* @param oid_len
* @param ip
* @param oid OID
* @param oid_len OID length
* @param ip IP address
* @return Parsed OID length
*/
u8_t
@ -387,7 +424,7 @@ snmp_oid_to_ip(const u32_t *oid, u8_t oid_len, ip_addr_t *ip)
if (oid_len < 1) {
return 0;
}
if (oid[0] == 0) { /* any */
/* 1x InetAddressType, 1x OID len */
if (oid_len < 2) {
@ -417,7 +454,7 @@ snmp_oid_to_ip(const u32_t *oid, u8_t oid_len, ip_addr_t *ip)
if (!snmp_oid_to_ip4(&oid[2], ip_2_ip4(ip))) {
return 0;
}
return 6;
#else /* LWIP_IPV4 */
return 0;
@ -450,17 +487,17 @@ snmp_oid_to_ip(const u32_t *oid, u8_t oid_len, ip_addr_t *ip)
/**
* Convert from InetAddressType+InetAddress+InetPortNumber to ip_addr_t and u16_t
* @param oid
* @param oid_len
* @param ip
* @param port
* @param oid OID
* @param oid_len OID length
* @param ip IP address
* @param port Port
* @return Parsed OID length
*/
u8_t
snmp_oid_to_ip_port(const u32_t *oid, u8_t oid_len, ip_addr_t *ip, u16_t *port)
{
u8_t idx = 0;
/* InetAddressType + InetAddress */
idx += snmp_oid_to_ip(&oid[idx], oid_len-idx, ip);
if (idx == 0) {
@ -483,10 +520,10 @@ snmp_oid_to_ip_port(const u32_t *oid, u8_t oid_len, ip_addr_t *ip, u16_t *port)
#endif /* LWIP_IPV4 || LWIP_IPV6 */
/**
* Assign an OID to \struct snmp_obj_id
* @param target
* @param oid
* @param oid_len
* Assign an OID to struct snmp_obj_id
* @param target Assignment target
* @param oid OID
* @param oid_len OID length
*/
void
snmp_oid_assign(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
@ -501,10 +538,10 @@ snmp_oid_assign(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
}
/**
* Prefix an OID to OID in \struct snmp_obj_id
* @param target
* @param oid
* @param oid_len
* Prefix an OID to OID in struct snmp_obj_id
* @param target Assignment target to prefix
* @param oid OID
* @param oid_len OID length
*/
void
snmp_oid_prefix(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
@ -524,12 +561,12 @@ snmp_oid_prefix(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
}
/**
* Combine two OIDs into \struct snmp_obj_id
* @param target
* @param oid1
* @param oid1_len
* @param oid2
* @param oid2_len
* Combine two OIDs into struct snmp_obj_id
* @param target Assignmet target
* @param oid1 OID 1
* @param oid1_len OID 1 length
* @param oid2 OID 2
* @param oid2_len OID 2 length
*/
void
snmp_oid_combine(struct snmp_obj_id* target, const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len)
@ -539,12 +576,12 @@ snmp_oid_combine(struct snmp_obj_id* target, const u32_t *oid1, u8_t oid1_len, c
}
/**
* Append OIDs to \struct snmp_obj_id
* @param target
* @param oid
* @param oid_len
* Append OIDs to struct snmp_obj_id
* @param target Assignment target to append to
* @param oid OID
* @param oid_len OID length
*/
void
void
snmp_oid_append(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
{
LWIP_ASSERT("offset + oid_len <= LWIP_SNMP_OBJ_ID_LEN", (target->len + oid_len) <= SNMP_MAX_OBJ_ID_LEN);
@ -557,11 +594,11 @@ snmp_oid_append(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len)
/**
* Compare two OIDs
* @param oid1
* @param oid1_len
* @param oid2
* @param oid2_len
* @return
* @param oid1 OID 1
* @param oid1_len OID 1 length
* @param oid2 OID 2
* @param oid2_len OID 2 length
* @return -1: OID1&lt;OID2 1: OID1 &gt;OID2 0: equal
*/
s8_t
snmp_oid_compare(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len)
@ -592,17 +629,17 @@ snmp_oid_compare(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_
}
/* they are equal */
return 0;
return 0;
}
/**
* Check of two OIDs are equal
* @param oid1
* @param oid1_len
* @param oid2
* @param oid2_len
* @return
* @param oid1 OID 1
* @param oid1_len OID 1 length
* @param oid2 OID 2
* @param oid2_len OID 2 length
* @return 1: equal 0: non-equal
*/
u8_t
snmp_oid_equal(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len)
@ -612,7 +649,7 @@ snmp_oid_equal(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_le
/**
* Convert netif to interface index
* @param netif
* @param netif netif
* @return index
*/
u8_t
@ -735,7 +772,7 @@ snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node
mib = snmp_get_mib_from_oid(oid, oid_len);
if (mib != NULL) {
u8_t oid_instance_len;
mn = snmp_mib_tree_resolve_exact(mib, oid, oid_len, &oid_instance_len);
if ((mn != NULL) && (mn->node_type != SNMP_NODE_TREE)) {
/* get instance */
@ -765,7 +802,7 @@ snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node
return result;
}
u8_t
u8_t
snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_validate_node_instance_method validate_node_instance_method, void* validate_node_instance_arg, struct snmp_obj_id* node_oid, struct snmp_node_instance* node_instance)
{
const struct snmp_mib *mib;
@ -791,7 +828,7 @@ snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_valida
/* resolve target node from MIB, skip to next MIB if no suitable node is found in current MIB */
while ((mib != NULL) && (mn == NULL)) {
u8_t oid_instance_len;
/* check if OID directly references a node inside current MIB, in this case we have to ask this node for the next instance */
mn = snmp_mib_tree_resolve_exact(mib, start_oid, start_oid_len, &oid_instance_len);
if (mn != NULL) {
@ -844,9 +881,9 @@ snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_valida
if (node_instance->release_instance != NULL) {
node_instance->release_instance(node_instance);
}
/*
/*
the instance itself is not valid, ask for next instance from same node.
we don't have to change any variables because node_instance->instance_oid is used as input (starting point)
we don't have to change any variables because node_instance->instance_oid is used as input (starting point)
as well as output (resulting next OID), so we have to simply call get_next_instance method again
*/
} else {
@ -889,7 +926,7 @@ snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_valida
}
/* else { we found out target node } */
} else {
/*
/*
there is no further (suitable) node inside this MIB, search for the next MIB with following priority
1. search for inner MIB's (whose root is located inside tree of current MIB)
2. search for surrouding MIB's (where the current MIB is the inner MIB) and continue there if any
@ -967,11 +1004,11 @@ snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t o
*oid_instance_len = oid_len - oid_offset;
return (*node);
}
return NULL;
}
const struct snmp_node*
const struct snmp_node*
snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, struct snmp_obj_id* oidret)
{
u8_t oid_offset = mib->base_oid_len;
@ -1062,7 +1099,7 @@ snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oi
}
}
}
return NULL;
}
@ -1103,7 +1140,7 @@ snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, cons
}
/** checks the passed OID if it is a candidate to be the next one (get_next); returns !=0 if passed oid is currently closest, otherwise 0 */
u8_t
u8_t
snmp_next_oid_check(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len, void* reference)
{
/* do not overwrite a fail result */

View File

@ -58,7 +58,7 @@
/* --- interfaces .1.3.6.1.2.1.2 ----------------------------------------------------- */
static s16_t
static s16_t
interfaces_get_value(struct snmp_node_instance* instance, void* value)
{
if (instance->node->oid == 1) {
@ -131,7 +131,7 @@ interfaces_Table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id*
u32_t result_temp[LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)];
LWIP_UNUSED_ARG(column);
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges));
@ -289,11 +289,10 @@ interfaces_Table_set_test(struct snmp_node_instance* instance, u16_t len, void *
LWIP_ASSERT("Invalid column", (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id) == 7));
LWIP_UNUSED_ARG(len);
if (*sint_ptr == 1 || *sint_ptr == 2)
{
if (*sint_ptr == 1 || *sint_ptr == 2) {
return SNMP_ERR_NOERROR;
}
return SNMP_ERR_WRONGVALUE;
}
@ -352,17 +351,17 @@ static const struct snmp_table_col_def interfaces_Table_columns[] = {
#if !SNMP_SAFE_REQUESTS
static const struct snmp_table_node interfaces_Table = SNMP_TABLE_CREATE(
2, interfaces_Table_columns,
interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance,
2, interfaces_Table_columns,
interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance,
interfaces_Table_get_value, interfaces_Table_set_test, interfaces_Table_set_value);
#else
static const struct snmp_table_node interfaces_Table = SNMP_TABLE_CREATE(
2, interfaces_Table_columns,
interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance,
2, interfaces_Table_columns,
interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance,
interfaces_Table_get_value, NULL, NULL);
#endif
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
CREATE_LWIP_SYNC_NODE(1, interfaces_Number)
CREATE_LWIP_SYNC_NODE(2, interfaces_Table)

View File

@ -58,7 +58,7 @@
#if LWIP_IPV4
/* --- ip .1.3.6.1.2.1.4 ----------------------------------------------------- */
static s16_t
static s16_t
ip_get_value(struct snmp_node_instance* instance, void* value)
{
s32_t* sint_ptr = (s32_t*)value;
@ -146,7 +146,7 @@ ip_get_value(struct snmp_node_instance* instance, void* value)
/**
* Test ip object value before setting.
*
* @param od is the object definition
* @param instance node instance
* @param len return value space (in bytes)
* @param value points to (varbind) space to copy value from.
*
@ -304,7 +304,7 @@ ip_AddrTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_o
/* fill in object properties */
return ip_AddrTable_get_cell_value_core((struct netif*)state.reference, column, value, value_len);
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
@ -326,7 +326,7 @@ ip_RouteTable_get_cell_value_core(struct netif *netif, u8_t default_route, const
case 1: /* ipRouteDest */
if (default_route) {
/* default rte has 0.0.0.0 dest */
value->u32 = IP4_ADDR_ANY->addr;
value->u32 = IP4_ADDR_ANY4->addr;
} else {
/* netifs have netaddress dest */
ip4_addr_t tmp;
@ -378,7 +378,7 @@ ip_RouteTable_get_cell_value_core(struct netif *netif, u8_t default_route, const
case 11: /* ipRouteMask */
if (default_route) {
/* default rte use 0.0.0.0 mask */
value->u32 = IP4_ADDR_ANY->addr;
value->u32 = IP4_ADDR_ANY4->addr;
} else {
/* other rtes use netmask */
value->u32 = netif_ip4_netmask(netif)->addr;
@ -449,7 +449,7 @@ ip_RouteTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_
/* check default route */
if (netif_default != NULL) {
snmp_ip4_to_oid(IP4_ADDR_ANY, &test_oid[0]);
snmp_ip4_to_oid(IP4_ADDR_ANY4, &test_oid[0]);
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges), netif_default);
}
@ -464,7 +464,7 @@ ip_RouteTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_
snmp_ip4_to_oid(&dst, &test_oid[0]);
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges), netif);
}
netif = netif->next;
}
@ -581,7 +581,7 @@ ip_NetToMediaTable_get_next_cell_instance_and_value(const u32_t* column, struct
snmp_ip4_to_oid(ip, &test_oid[1]);
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges), (void*)(size_t)i);
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges), LWIP_PTR_NUMERIC_CAST(void*, i));
}
}
@ -589,7 +589,7 @@ ip_NetToMediaTable_get_next_cell_instance_and_value(const u32_t* column, struct
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
/* fill in object properties */
return ip_NetToMediaTable_get_cell_value_core((u8_t)(size_t)state.reference, column, value, value_len);
return ip_NetToMediaTable_get_cell_value_core(LWIP_PTR_NUMERIC_CAST(u8_t, state.reference), column, value, value_len);
}
/* not found */
@ -660,7 +660,7 @@ static const struct snmp_table_simple_node ip_NetToMediaTable = SNMP_TABLE_CREAT
#endif /* LWIP_ARP && LWIP_IPV4 */
#if LWIP_IPV4
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
CREATE_LWIP_SYNC_NODE( 1, ip_Forwarding)
CREATE_LWIP_SYNC_NODE( 2, ip_DefaultTTL)
CREATE_LWIP_SYNC_NODE( 3, ip_InReceives)
@ -730,7 +730,7 @@ static const struct snmp_table_simple_col_def at_Table_columns[] = {
static const struct snmp_table_simple_node at_Table = SNMP_TABLE_CREATE_SIMPLE(1, at_Table_columns, ip_NetToMediaTable_get_cell_value, ip_NetToMediaTable_get_next_cell_instance_and_value);
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
CREATE_LWIP_SYNC_NODE(1, at_Table)
static const struct snmp_node* const at_nodes[] = {

View File

@ -188,7 +188,7 @@ snmp_set_value(const struct snmp_scalar_array_node_def *node, u16_t len, void *v
return SNMP_ERR_NOERROR;
}
/* the following nodes access variables in SNMP stack (snmp_stats) from SNMP worker thread -> OK, no sync needed */
/* the following nodes access variables in SNMP stack (snmp_stats) from SNMP worker thread -> OK, no sync needed */
static const struct snmp_scalar_array_node_def snmp_nodes[] = {
{ 1, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInPkts */
{ 2, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutPkts */

View File

@ -106,7 +106,7 @@ snmp_mib2_set_sysdescr(const u8_t *str, const u16_t *len)
* Initializes sysContact pointers
*
* @param ocstr if non-NULL then copy str pointer
* @param ocstrlen points to string length, excluding zero terminator.
* @param ocstrlen points to string length, excluding zero terminator.
* if set to NULL it is assumed that ocstr is NULL-terminated.
* @param bufsize size of the buffer in bytes.
* (this is required because the buffer can be overwritten by snmp-set)
@ -148,7 +148,7 @@ snmp_mib2_set_syscontact_readonly(const u8_t *ocstr, const u16_t *ocstrlen)
* Initializes sysName pointers
*
* @param ocstr if non-NULL then copy str pointer
* @param ocstrlen points to string length, excluding zero terminator.
* @param ocstrlen points to string length, excluding zero terminator.
* if set to NULL it is assumed that ocstr is NULL-terminated.
* @param bufsize size of the buffer in bytes.
* (this is required because the buffer can be overwritten by snmp-set)
@ -189,7 +189,7 @@ snmp_mib2_set_sysname_readonly(const u8_t *ocstr, const u16_t *ocstrlen)
* Initializes sysLocation pointers
*
* @param ocstr if non-NULL then copy str pointer
* @param ocstrlen points to string length, excluding zero terminator.
* @param ocstrlen points to string length, excluding zero terminator.
* if set to NULL it is assumed that ocstr is NULL-terminated.
* @param bufsize size of the buffer in bytes.
* (this is required because the buffer can be overwritten by snmp-set)
@ -278,7 +278,7 @@ system_get_value(const struct snmp_scalar_array_node_def *node, void *value)
return result;
}
static snmp_err_t
static snmp_err_t
system_set_test(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
{
snmp_err_t ret = SNMP_ERR_WRONGVALUE;
@ -324,7 +324,7 @@ system_set_test(const struct snmp_scalar_array_node_def *node, u16_t len, void *
return ret;
}
static snmp_err_t
static snmp_err_t
system_set_value(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
{
u8_t* var_wr = NULL;

View File

@ -58,7 +58,7 @@
/* --- tcp .1.3.6.1.2.1.6 ----------------------------------------------------- */
static s16_t
static s16_t
tcp_get_value(struct snmp_node_instance* instance, void* value)
{
u32_t *uint_ptr = (u32_t*)value;
@ -154,7 +154,7 @@ static const struct snmp_oid_range tcp_ConnTable_oid_ranges[] = {
{ 0, 0xffff } /* Port */
};
static snmp_err_t
static snmp_err_t
tcp_ConnTable_get_cell_value_core(struct tcp_pcb *pcb, const u32_t* column, union snmp_variant_value* value, u32_t* value_len)
{
LWIP_UNUSED_ARG(value_len);
@ -172,7 +172,7 @@ tcp_ConnTable_get_cell_value_core(struct tcp_pcb *pcb, const u32_t* column, unio
break;
case 4: /* tcpConnRemAddress */
if (pcb->state == LISTEN) {
value->u32 = IP4_ADDR_ANY->addr;
value->u32 = IP4_ADDR_ANY4->addr;
} else {
value->u32 = ip_2_ip4(&pcb->remote_ip)->addr;
}
@ -212,7 +212,7 @@ tcp_ConnTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row
local_port = (u16_t)row_oid[4];
snmp_oid_to_ip4(&row_oid[5], &remote_ip); /* we know it succeeds because of oid_in_range check above */
remote_port = (u16_t)row_oid[9];
/* find tcp_pcb with requested ips and ports */
for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) {
pcb = *tcp_pcb_lists[i];
@ -224,7 +224,7 @@ tcp_ConnTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row
/* PCBs in state LISTEN are not connected and have no remote_ip or remote_port */
if (pcb->state == LISTEN) {
if (ip4_addr_cmp(&remote_ip, IP4_ADDR_ANY) && (remote_port == 0)) {
if (ip4_addr_cmp(&remote_ip, IP4_ADDR_ANY4) && (remote_port == 0)) {
/* fill in object properties */
return tcp_ConnTable_get_cell_value_core(pcb, column, value, value_len);
}
@ -261,14 +261,14 @@ tcp_ConnTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_
pcb = *tcp_pcb_lists[i];
while (pcb != NULL) {
u32_t test_oid[LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)];
if (IP_IS_V4_VAL(pcb->local_ip)) {
snmp_ip4_to_oid(ip_2_ip4(&pcb->local_ip), &test_oid[0]);
test_oid[4] = pcb->local_port;
/* PCBs in state LISTEN are not connected and have no remote_ip or remote_port */
if (pcb->state == LISTEN) {
snmp_ip4_to_oid(IP4_ADDR_ANY, &test_oid[5]);
snmp_ip4_to_oid(IP4_ADDR_ANY4, &test_oid[5]);
test_oid[9] = 0;
} else {
if (IP_IS_V6_VAL(pcb->remote_ip)) { /* should never happen */
@ -281,7 +281,7 @@ tcp_ConnTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges), pcb);
}
pcb = pcb->next;
}
}
@ -301,10 +301,10 @@ tcp_ConnTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_
/* --- tcpConnectionTable --- */
static snmp_err_t
static snmp_err_t
tcp_ConnectionTable_get_cell_value_core(const u32_t* column, struct tcp_pcb *pcb, union snmp_variant_value* value)
{
/* all items except tcpConnectionState and tcpConnectionProcess are declared as not-accessible */
/* all items except tcpConnectionState and tcpConnectionProcess are declared as not-accessible */
switch (*column) {
case 7: /* tcpConnectionState */
value->u32 = pcb->state + 1;
@ -336,7 +336,7 @@ tcp_ConnectionTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8
if (idx == 0) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* tcpConnectionRemAddressType + tcpConnectionRemAddress + tcpConnectionRemPort */
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &remote_ip, &remote_port);
if (idx == 0) {
@ -346,7 +346,7 @@ tcp_ConnectionTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8
/* find tcp_pcb with requested ip and port*/
for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_nonlisten_lists); i++) {
pcb = *tcp_pcb_nonlisten_lists[i];
while (pcb != NULL) {
if (ip_addr_cmp(&local_ip, &pcb->local_ip) &&
(local_port == pcb->local_port) &&
@ -358,9 +358,9 @@ tcp_ConnectionTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8
pcb = pcb->next;
}
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
@ -395,11 +395,11 @@ tcp_ConnectionTable_get_next_cell_instance_and_value(const u32_t* column, struct
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, idx, pcb);
pcb = pcb->next;
}
}
/* did we find a next one? */
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
@ -413,10 +413,10 @@ tcp_ConnectionTable_get_next_cell_instance_and_value(const u32_t* column, struct
/* --- tcpListenerTable --- */
static snmp_err_t
static snmp_err_t
tcp_ListenerTable_get_cell_value_core(const u32_t* column, union snmp_variant_value* value)
{
/* all items except tcpListenerProcess are declared as not-accessible */
/* all items except tcpListenerProcess are declared as not-accessible */
switch (*column) {
case 4: /* tcpListenerProcess */
value->u32 = 0; /* not supported */
@ -443,7 +443,7 @@ tcp_ListenerTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t
if (idx == 0) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* find tcp_pcb with requested ip and port*/
pcb = tcp_listen_pcbs.listen_pcbs;
while (pcb != NULL) {
@ -456,7 +456,7 @@ tcp_ListenerTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
@ -477,13 +477,13 @@ tcp_ListenerTable_get_next_cell_instance_and_value(const u32_t* column, struct s
while (pcb != NULL) {
u8_t idx = 0;
u32_t test_oid[LWIP_ARRAYSIZE(result_temp)];
/* tcpListenerLocalAddressType + tcpListenerLocalAddress + tcpListenerLocalPort */
idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]);
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, idx, NULL);
pcb = pcb->next;
}
@ -528,7 +528,7 @@ static const struct snmp_table_simple_node tcp_ConnTable = SNMP_TABLE_CREATE_SIM
#endif /* LWIP_IPV4 */
static const struct snmp_table_simple_col_def tcp_ConnectionTable_columns[] = {
/* all items except tcpConnectionState and tcpConnectionProcess are declared as not-accessible */
/* all items except tcpConnectionState and tcpConnectionProcess are declared as not-accessible */
{ 7, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnectionState */
{ 8, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpConnectionProcess */
};
@ -537,13 +537,13 @@ static const struct snmp_table_simple_node tcp_ConnectionTable = SNMP_TABLE_CREA
static const struct snmp_table_simple_col_def tcp_ListenerTable_columns[] = {
/* all items except tcpListenerProcess are declared as not-accessible */
/* all items except tcpListenerProcess are declared as not-accessible */
{ 4, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpListenerProcess */
};
static const struct snmp_table_simple_node tcp_ListenerTable = SNMP_TABLE_CREATE_SIMPLE(20, tcp_ListenerTable_columns, tcp_ListenerTable_get_cell_value, tcp_ListenerTable_get_next_cell_instance_and_value);
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */
CREATE_LWIP_SYNC_NODE( 1, tcp_RtoAlgorithm)
CREATE_LWIP_SYNC_NODE( 2, tcp_RtoMin)
CREATE_LWIP_SYNC_NODE( 3, tcp_RtoMax)

View File

@ -57,7 +57,7 @@
/* --- udp .1.3.6.1.2.1.7 ----------------------------------------------------- */
static s16_t
static s16_t
udp_get_value(struct snmp_node_instance* instance, void* value)
{
u32_t *uint_ptr = (u32_t*)value;
@ -91,10 +91,10 @@ udp_get_value(struct snmp_node_instance* instance, void* value)
/* --- udpEndpointTable --- */
static snmp_err_t
static snmp_err_t
udp_endpointTable_get_cell_value_core(const u32_t* column, union snmp_variant_value* value)
{
/* all items except udpEndpointProcess are declared as not-accessible */
/* all items except udpEndpointProcess are declared as not-accessible */
switch (*column) {
case 8: /* udpEndpointProcess */
value->u32 = 0; /* not supported */
@ -106,7 +106,7 @@ udp_endpointTable_get_cell_value_core(const u32_t* column, union snmp_variant_va
return SNMP_ERR_NOERROR;
}
static snmp_err_t
static snmp_err_t
udp_endpointTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len)
{
ip_addr_t local_ip, remote_ip;

View File

@ -125,6 +125,7 @@ snmp_get_community_trap(void)
void
snmp_set_community_write(const char * const community)
{
LWIP_ASSERT("community string must not be NULL", community != NULL);
LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
snmp_community_write = community;
}
@ -272,8 +273,7 @@ snmp_process_varbind(struct snmp_request *request, struct snmp_varbind *vb, u8_t
}
}
if (request->error_status != SNMP_ERR_NOERROR)
{
if (request->error_status != SNMP_ERR_NOERROR) {
if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) {
if ((request->version == SNMP_VERSION_2c) || request->version == SNMP_VERSION_3) {
/* in SNMP v2c a varbind related exception is stored in varbind and not in frame header */
@ -323,7 +323,7 @@ snmp_process_varbind(struct snmp_request *request, struct snmp_varbind *vb, u8_t
/**
* Service an internal or external event for SNMP GET.
*
* @param msg_ps points to the associated message process state
* @param request points to the associated message process state
*/
static err_t
snmp_process_get_request(struct snmp_request *request)
@ -359,7 +359,7 @@ snmp_process_get_request(struct snmp_request *request)
/**
* Service an internal or external event for SNMP GET.
*
* @param msg_ps points to the associated message process state
* @param request points to the associated message process state
*/
static err_t
snmp_process_getnext_request(struct snmp_request *request)
@ -395,7 +395,7 @@ snmp_process_getnext_request(struct snmp_request *request)
/**
* Service an internal or external event for SNMP GETBULKT.
*
* @param msg_ps points to the associated message process state
* @param request points to the associated message process state
*/
static err_t
snmp_process_getbulk_request(struct snmp_request *request)
@ -493,7 +493,7 @@ snmp_process_getbulk_request(struct snmp_request *request)
/**
* Service an internal or external event for SNMP SET.
*
* @param msg_ps points to the associated message process state
* @param request points to the associated message process state
*/
static err_t
snmp_process_set_request(struct snmp_request *request)
@ -512,8 +512,7 @@ snmp_process_set_request(struct snmp_request *request)
memset(&node_instance, 0, sizeof(node_instance));
request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance);
if (request->error_status == SNMP_ERR_NOERROR)
{
if (request->error_status == SNMP_ERR_NOERROR) {
if (node_instance.asn1_type != vb.type) {
request->error_status = SNMP_ERR_WRONGTYPE;
} else if (((node_instance.access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != SNMP_NODE_INSTANCE_ACCESS_WRITE) || (node_instance.set_value == NULL)) {
@ -528,8 +527,7 @@ snmp_process_set_request(struct snmp_request *request)
node_instance.release_instance(&node_instance);
}
}
}
else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
} else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
/* no more varbinds in request */
break;
} else if (err == SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH) {
@ -551,10 +549,8 @@ snmp_process_set_request(struct snmp_request *request)
struct snmp_node_instance node_instance;
memset(&node_instance, 0, sizeof(node_instance));
request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance);
if (request->error_status == SNMP_ERR_NOERROR)
{
if (node_instance.set_value(&node_instance, vb.value_len, vb.value) != SNMP_ERR_NOERROR)
{
if (request->error_status == SNMP_ERR_NOERROR) {
if (node_instance.set_value(&node_instance, vb.value_len, vb.value) != SNMP_ERR_NOERROR) {
if (request->inbound_varbind_enumerator.varbind_count == 1) {
request->error_status = SNMP_ERR_COMMITFAILED;
} else {
@ -650,11 +646,12 @@ snmp_parse_inbound_frame(struct snmp_request *request)
#if LWIP_SNMP_V3
if (request->version == SNMP_VERSION_3) {
u16_t u16_value;
u16_t inbound_msgAuthenticationParameters_offset;
/* SNMPv3 doesn't use communities */
/* @todo: Differentiate read/write access */
strcpy((char*)request->community, snmp_community);
request->community_strlen = strlen(snmp_community);
request->community_strlen = (u16_t)strlen(snmp_community);
/* RFC3414 globalData */
IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
@ -687,7 +684,7 @@ snmp_parse_inbound_frame(struct snmp_request *request)
IF_PARSE_ASSERT(parent_tlv_value_len > 0);
IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
request->msg_flags = s32_value;
request->msg_flags = (u8_t)s32_value;
/* decode msgSecurityModel */
IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
@ -724,7 +721,7 @@ snmp_parse_inbound_frame(struct snmp_request *request)
IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authoritative_engine_id,
&u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
request->msg_authoritative_engine_id_len = u16_value;
request->msg_authoritative_engine_id_len = (u8_t)u16_value;
/* msgAuthoritativeEngineBoots */
IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
@ -749,7 +746,7 @@ snmp_parse_inbound_frame(struct snmp_request *request)
IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_user_name,
&u16_value, SNMP_V3_MAX_USER_LENGTH));
request->msg_user_name_len = u16_value;
request->msg_user_name_len = (u8_t)u16_value;
/* @todo: Implement unknown user error response */
IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, NULL, NULL));
@ -760,7 +757,7 @@ snmp_parse_inbound_frame(struct snmp_request *request)
parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
IF_PARSE_ASSERT(parent_tlv_value_len > 0);
/* Remember position */
u16_t inbound_msgAuthenticationParameters_offset = pbuf_stream.offset;
inbound_msgAuthenticationParameters_offset = pbuf_stream.offset;
LWIP_UNUSED_ARG(inbound_msgAuthenticationParameters_offset);
/* Read auth parameters */
IF_PARSE_ASSERT(tlv.value_len <= SNMP_V3_MAX_AUTH_PARAM_LENGTH);
@ -769,18 +766,19 @@ snmp_parse_inbound_frame(struct snmp_request *request)
#if LWIP_SNMP_V3_CRYPTO
if (request->msg_flags & SNMP_V3_AUTH_FLAG) {
/* Rewind stream */
IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
IF_PARSE_EXEC(snmp_pbuf_stream_seek_abs(&pbuf_stream, inbound_msgAuthenticationParameters_offset));
/* Set auth parameters to zero for verification */
const u8_t zero_arr[SNMP_V3_MAX_AUTH_PARAM_LENGTH] = { 0 };
IF_PARSE_EXEC(snmp_asn1_enc_raw(&pbuf_stream, zero_arr, tlv.value_len));
/* Verify authentication */
u8_t key[20];
u8_t algo;
u8_t hmac[LWIP_MAX(SNMP_V3_SHA_LEN, SNMP_V3_MD5_LEN)];
struct snmp_pbuf_stream auth_stream;
/* Rewind stream */
IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
IF_PARSE_EXEC(snmp_pbuf_stream_seek_abs(&pbuf_stream, inbound_msgAuthenticationParameters_offset));
/* Set auth parameters to zero for verification */
IF_PARSE_EXEC(snmp_asn1_enc_raw(&pbuf_stream, zero_arr, tlv.value_len));
/* Verify authentication */
IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, &algo, key, NULL, NULL));
@ -839,7 +837,7 @@ snmp_parse_inbound_frame(struct snmp_request *request)
IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_engine_id,
&u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
request->context_engine_id_len = u16_value;
request->context_engine_id_len = (u8_t)u16_value;
/* contextName */
IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
@ -849,7 +847,7 @@ snmp_parse_inbound_frame(struct snmp_request *request)
IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_name,
&u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
request->context_name_len = u16_value;
request->context_name_len = (u8_t)u16_value;
} else
#endif
{
@ -913,7 +911,7 @@ snmp_parse_inbound_frame(struct snmp_request *request)
snmp_authfail_trap();
return ERR_ARG;
} else if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
if (strnlen(snmp_community_write, SNMP_MAX_COMMUNITY_STR_LEN) == 0) {
if (snmp_community_write[0] == 0) {
/* our write community is empty, that means all our objects are readonly */
request->error_status = SNMP_ERR_NOTWRITABLE;
request->error_index = 1;
@ -1065,7 +1063,7 @@ snmp_prepare_outbound_frame(struct snmp_request *request)
/* msgAuthoritativeEngineID */
snmpv3_get_engine_id(&id, &request->msg_authoritative_engine_id_len);
memcpy(request->msg_authoritative_engine_id, id, request->msg_authoritative_engine_id_len);
MEMCPY(request->msg_authoritative_engine_id, id, request->msg_authoritative_engine_id_len);
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_authoritative_engine_id_len);
OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authoritative_engine_id, request->msg_authoritative_engine_id_len));
@ -1140,7 +1138,7 @@ snmp_prepare_outbound_frame(struct snmp_request *request)
/* contextEngineID */
snmpv3_get_engine_id(&id, &request->context_engine_id_len);
memcpy(request->context_engine_id, id, request->context_engine_id_len);
MEMCPY(request->context_engine_id, id, request->context_engine_id_len);
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_engine_id_len);
OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_engine_id, request->context_engine_id_len));
@ -1361,6 +1359,19 @@ snmp_complete_outbound_frame(struct snmp_request *request)
}
}
} else {
if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
/* map error codes to according to RFC 1905 (4.2.5. The SetRequest-PDU) return 'NotWritable' for unknown OIDs) */
switch (request->error_status) {
case SNMP_ERR_NOSUCHINSTANCE:
case SNMP_ERR_NOSUCHOBJECT:
case SNMP_ERR_ENDOFMIBVIEW:
request->error_status = SNMP_ERR_NOTWRITABLE;
break;
default:
break;
}
}
if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) {
/* should never occur because v2 frames store exceptions directly inside varbinds and not as frame error_status */
LWIP_DEBUGF(SNMP_DEBUG, ("snmp_complete_outbound_frame() > Found v2 request with varbind exception code stored as error status!\n"));
@ -1382,7 +1393,7 @@ snmp_complete_outbound_frame(struct snmp_request *request)
/* Calculate padding for encryption */
if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) {
u8_t i;
outbound_padding = (u8_t)((frame_size - request->outbound_scoped_pdu_seq_offset) & 0x03);
outbound_padding = (8 - (u8_t)((frame_size - request->outbound_scoped_pdu_seq_offset) & 0x07)) & 0x07;
for (i = 0; i < outbound_padding; i++) {
snmp_pbuf_stream_write(&request->outbound_pbuf_stream, 0);
}
@ -1517,7 +1528,7 @@ snmp_complete_outbound_frame(struct snmp_request *request)
request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
OF_BUILD_EXEC(snmpv3_auth(&request->outbound_pbuf_stream, frame_size + outbound_padding, key, algo, hmac));
memcpy(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
MEMCPY(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream,
request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&request->outbound_pbuf_stream,
@ -1547,7 +1558,7 @@ snmp_execute_write_callbacks(struct snmp_request *request)
snmp_vb_enumerator_init(&inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned, which we don't need here) */
while (snmp_vb_enumerator_get_next(&inbound_varbind_enumerator, &vb) == ERR_OK) {
while (snmp_vb_enumerator_get_next(&inbound_varbind_enumerator, &vb) == SNMP_VB_ENUMERATOR_ERR_OK) {
snmp_write_callback(vb.oid.id, vb.oid.len, snmp_write_callback_arg);
}
}

View File

@ -36,6 +36,7 @@
#if LWIP_SNMP && SNMP_USE_NETCONN
#include <string.h>
#include "lwip/api.h"
#include "lwip/ip.h"
#include "lwip/udp.h"
@ -52,12 +53,12 @@ snmp_netconn_thread(void *arg)
LWIP_UNUSED_ARG(arg);
/* Bind to SNMP port with default IP address */
#if LWIP_IPV6
#if LWIP_IPV6
conn = netconn_new(NETCONN_UDP_IPV6);
netconn_bind(conn, IP6_ADDR_ANY, SNMP_IN_PORT);
#else /* LWIP_IPV6 */
conn = netconn_new(NETCONN_UDP);
netconn_bind(conn, IP_ADDR_ANY, SNMP_IN_PORT);
netconn_bind(conn, IP4_ADDR_ANY, SNMP_IN_PORT);
#endif /* LWIP_IPV6 */
LWIP_ERROR("snmp_netconn: invalid conn", (conn != NULL), return;);

View File

@ -80,7 +80,7 @@ snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result)
/**
* @ingroup snmp_core
* Starts SNMP Agent.
* Allocates UDP pcb and binds it to IP_ADDR_ANY port 161.
* Allocates UDP pcb and binds it to IP_ANY_TYPE port 161.
*/
void
snmp_init(void)

View File

@ -211,6 +211,7 @@ void snmp_threadsync_init(struct snmp_threadsync_instance *instance, snmp_thread
err_t err = sys_mutex_new(&instance->sem_usage_mutex);
LWIP_ASSERT("Failed to set up mutex", err == ERR_OK);
err = sys_sem_new(&instance->sem, 0);
LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("Failed to set up semaphore", err == ERR_OK);
instance->sync_fn = sync_fn;
}

View File

@ -147,11 +147,13 @@ snmp_get_auth_traps_enabled(void)
/**
* Sends an generic or enterprise specific trap message.
* @ingroup snmp_traps
* Sends a generic or enterprise specific trap message.
*
* @param generic_trap is the trap code
* @param eoid points to enterprise object identifier
* @param generic_trap is the trap code
* @param specific_trap used for enterprise traps when generic_trap == 6
* @param varbinds linked list of varbinds to be sent
* @return ERR_OK when success, ERR_MEM if we're out of memory
*
* @note the use of the enterprise identifier field
@ -160,8 +162,8 @@ snmp_get_auth_traps_enabled(void)
* and .iso.org.dod.internet.private.enterprises.yourenterprise
* (sysObjectID) for specific traps.
*/
static err_t
snmp_send_trap(const struct snmp_obj_id *device_enterprise_oid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds)
err_t
snmp_send_trap(const struct snmp_obj_id* eoid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds)
{
struct snmp_msg_trap trap_msg;
struct snmp_trap_dst *td;
@ -175,10 +177,10 @@ snmp_send_trap(const struct snmp_obj_id *device_enterprise_oid, s32_t generic_tr
if ((td->enable != 0) && !ip_addr_isany(&td->dip)) {
/* lookup current source address for this dst */
if (snmp_get_local_ip_for_dst(snmp_traps_handle, &td->dip, &trap_msg.sip)) {
if (device_enterprise_oid == NULL) {
if (eoid == NULL) {
trap_msg.enterprise = snmp_get_device_enterprise_oid();
} else {
trap_msg.enterprise = device_enterprise_oid;
trap_msg.enterprise = eoid;
}
trap_msg.gen_trap = generic_trap;
@ -224,7 +226,7 @@ snmp_send_trap(const struct snmp_obj_id *device_enterprise_oid, s32_t generic_tr
/**
* @ingroup snmp_traps
* Send generic SNMP trap
* Send generic SNMP trap
*/
err_t
snmp_send_trap_generic(s32_t generic_trap)
@ -234,7 +236,7 @@ snmp_send_trap_generic(s32_t generic_trap)
}
/**
*@ingroup snmp_traps
* @ingroup snmp_traps
* Send specific SNMP trap with variable bindings
*/
err_t
@ -295,8 +297,8 @@ snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds)
* Sums trap header field lengths from tail to head and
* returns trap_header_lengths for second encoding pass.
*
* @param trap Trap message
* @param vb_len varbind-list length
* @param thl points to returned header lengths
* @return the required length for encoding the trap header
*/
static u16_t

View File

@ -114,8 +114,8 @@ snmpv3_build_priv_param(u8_t* priv_param)
priv2 = LWIP_RAND();
}
memcpy(&priv_param[0], &priv1, sizeof(priv1));
memcpy(&priv_param[4], &priv2, sizeof(priv2));
SMEMCPY(&priv_param[0], &priv1, sizeof(priv1));
SMEMCPY(&priv_param[4], &priv2, sizeof(priv2));
/* Emulate 64bit increment */
priv1++;
@ -125,8 +125,8 @@ snmpv3_build_priv_param(u8_t* priv_param)
#else /* Based on RFC3414 */
static u32_t ctr;
u32_t boots = LWIP_SNMPV3_GET_ENGINE_BOOTS();
memcpy(&priv_param[0], &boots, 4);
memcpy(&priv_param[4], &ctr, 4);
SMEMCPY(&priv_param[0], &boots, 4);
SMEMCPY(&priv_param[4], &ctr, 4);
ctr++;
#endif
return ERR_OK;

View File

@ -192,7 +192,7 @@ snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length,
iv_local[4 + 1] = (engine_time >> 16) & 0xFF;
iv_local[4 + 2] = (engine_time >> 8) & 0xFF;
iv_local[4 + 3] = (engine_time >> 0) & 0xFF;
memcpy(iv_local + 8, priv_param, 8);
SMEMCPY(iv_local + 8, priv_param, 8);
if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) {
goto error;
}
@ -263,9 +263,9 @@ snmpv3_password_to_key_md5(
/* May want to ensure that engineLength <= 32, */
/* otherwise need to use a buffer larger than 64 */
/*****************************************************/
memcpy(password_buf, key, 16);
memcpy(password_buf + 16, engineID, engineLength);
memcpy(password_buf + 16 + engineLength, key, 16);
SMEMCPY(password_buf, key, 16);
MEMCPY(password_buf + 16, engineID, engineLength);
SMEMCPY(password_buf + 16 + engineLength, key, 16);
mbedtls_md5_starts(&MD);
mbedtls_md5_update(&MD, password_buf, 32 + engineLength);
@ -316,9 +316,9 @@ snmpv3_password_to_key_sha(
/* May want to ensure that engineLength <= 32, */
/* otherwise need to use a buffer larger than 72 */
/*****************************************************/
memcpy(password_buf, key, 20);
memcpy(password_buf + 20, engineID, engineLength);
memcpy(password_buf + 20 + engineLength, key, 20);
SMEMCPY(password_buf, key, 20);
MEMCPY(password_buf + 20, engineID, engineLength);
SMEMCPY(password_buf + 20 + engineLength, key, 20);
mbedtls_sha1_starts(&SH);
mbedtls_sha1_update(&SH, password_buf, 40 + engineLength);

View File

@ -79,11 +79,12 @@ struct snmp_varbind_enumerator
u16_t varbind_count;
};
typedef u8_t snmp_vb_enumerator_err_t;
#define SNMP_VB_ENUMERATOR_ERR_OK 0
#define SNMP_VB_ENUMERATOR_ERR_EOVB 1
#define SNMP_VB_ENUMERATOR_ERR_ASN1ERROR 2
#define SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH 3
typedef enum {
SNMP_VB_ENUMERATOR_ERR_OK = 0,
SNMP_VB_ENUMERATOR_ERR_EOVB = 1,
SNMP_VB_ENUMERATOR_ERR_ASN1ERROR = 2,
SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH = 3
} snmp_vb_enumerator_err_t;
void snmp_vb_enumerator_init(struct snmp_varbind_enumerator* enumerator, struct pbuf* p, u16_t offset, u16_t length);
snmp_vb_enumerator_err_t snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind);

View File

@ -212,13 +212,13 @@ sntp_process(u32_t *receive_timestamp)
/* convert SNTP time (1900-based) to unix GMT time (1970-based)
* if MSB is 0, SNTP time is 2036-based!
*/
u32_t rx_secs = ntohl(receive_timestamp[0]);
u32_t rx_secs = lwip_ntohl(receive_timestamp[0]);
int is_1900_based = ((rx_secs & 0x80000000) != 0);
u32_t t = is_1900_based ? (rx_secs - DIFF_SEC_1900_1970) : (rx_secs + DIFF_SEC_1970_2036);
time_t tim = t;
#if SNTP_CALC_TIME_US
u32_t us = ntohl(receive_timestamp[1]) / 4295;
u32_t us = lwip_ntohl(receive_timestamp[1]) / 4295;
SNTP_SET_SYSTEM_TIME_US(t, us);
/* display local time from GMT time */
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&tim), us));
@ -247,10 +247,10 @@ sntp_initialize_request(struct sntp_msg *req)
u32_t sntp_time_sec, sntp_time_us;
/* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */
SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us);
sntp_last_timestamp_sent[0] = htonl(sntp_time_sec + DIFF_SEC_1900_1970);
sntp_last_timestamp_sent[0] = lwip_htonl(sntp_time_sec + DIFF_SEC_1900_1970);
req->transmit_timestamp[0] = sntp_last_timestamp_sent[0];
/* we send/save us instead of fraction to be faster... */
sntp_last_timestamp_sent[1] = htonl(sntp_time_us);
sntp_last_timestamp_sent[1] = lwip_htonl(sntp_time_us);
req->transmit_timestamp[1] = sntp_last_timestamp_sent[1];
}
#endif /* SNTP_CHECK_RESPONSE >= 2 */
@ -573,6 +573,7 @@ sntp_stop(void)
{
if (sntp_pcb != NULL) {
sys_untimeout(sntp_request, NULL);
sys_untimeout(sntp_try_next_server, NULL);
udp_remove(sntp_pcb);
sntp_pcb = NULL;
}

View File

@ -0,0 +1,417 @@
/****************************************************************//**
*
* @file tftp_server.c
*
* @author Logan Gunthorpe <logang@deltatee.com>
* Dirk Ziegelmeier <dziegel@gmx.de>
*
* @brief Trivial File Transfer Protocol (RFC 1350)
*
* Copyright (c) Deltatee Enterprises Ltd. 2013
* 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.
*
* Author: Logan Gunthorpe <logang@deltatee.com>
* Dirk Ziegelmeier <dziegel@gmx.de>
*
*/
/**
* @defgroup tftp TFTP server
* @ingroup apps
*
* This is simple TFTP server for the lwIP raw API.
*/
#include "lwip/apps/tftp_server.h"
#if LWIP_UDP
#include "lwip/udp.h"
#include "lwip/timeouts.h"
#include "lwip/debug.h"
#define TFTP_MAX_PAYLOAD_SIZE 512
#define TFTP_HEADER_LENGTH 4
#define TFTP_RRQ 1
#define TFTP_WRQ 2
#define TFTP_DATA 3
#define TFTP_ACK 4
#define TFTP_ERROR 5
enum tftp_error {
TFTP_ERROR_FILE_NOT_FOUND = 1,
TFTP_ERROR_ACCESS_VIOLATION = 2,
TFTP_ERROR_DISK_FULL = 3,
TFTP_ERROR_ILLEGAL_OPERATION = 4,
TFTP_ERROR_UNKNOWN_TRFR_ID = 5,
TFTP_ERROR_FILE_EXISTS = 6,
TFTP_ERROR_NO_SUCH_USER = 7
};
#include <string.h>
struct tftp_state {
const struct tftp_context *ctx;
void *handle;
struct pbuf *last_data;
struct udp_pcb *upcb;
ip_addr_t addr;
u16_t port;
int timer;
int last_pkt;
u16_t blknum;
u8_t retries;
u8_t mode_write;
};
static struct tftp_state tftp_state;
static void tftp_tmr(void* arg);
static void
close_handle(void)
{
tftp_state.port = 0;
ip_addr_set_any(0, &tftp_state.addr);
if(tftp_state.last_data != NULL) {
pbuf_free(tftp_state.last_data);
tftp_state.last_data = NULL;
}
sys_untimeout(tftp_tmr, NULL);
if (tftp_state.handle) {
tftp_state.ctx->close(tftp_state.handle);
tftp_state.handle = NULL;
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: closing\n"));
}
}
static void
send_error(const ip_addr_t *addr, u16_t port, enum tftp_error code, const char *str)
{
int str_length = strlen(str);
struct pbuf* p;
u16_t* payload;
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(TFTP_HEADER_LENGTH + str_length + 1), PBUF_RAM);
if(p == NULL) {
return;
}
payload = (u16_t*) p->payload;
payload[0] = PP_HTONS(TFTP_ERROR);
payload[1] = lwip_htons(code);
MEMCPY(&payload[2], str, str_length + 1);
udp_sendto(tftp_state.upcb, p, addr, port);
pbuf_free(p);
}
static void
send_ack(u16_t blknum)
{
struct pbuf* p;
u16_t* payload;
p = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH, PBUF_RAM);
if(p == NULL) {
return;
}
payload = (u16_t*) p->payload;
payload[0] = PP_HTONS(TFTP_ACK);
payload[1] = lwip_htons(blknum);
udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port);
pbuf_free(p);
}
static void
resend_data(void)
{
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, tftp_state.last_data->len, PBUF_RAM);
if(p == NULL) {
return;
}
if(pbuf_copy(p, tftp_state.last_data) != ERR_OK) {
pbuf_free(p);
return;
}
udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port);
pbuf_free(p);
}
static void
send_data(void)
{
u16_t *payload;
int ret;
if(tftp_state.last_data != NULL) {
pbuf_free(tftp_state.last_data);
}
tftp_state.last_data = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH + TFTP_MAX_PAYLOAD_SIZE, PBUF_RAM);
if(tftp_state.last_data == NULL) {
return;
}
payload = (u16_t *) tftp_state.last_data->payload;
payload[0] = PP_HTONS(TFTP_DATA);
payload[1] = lwip_htons(tftp_state.blknum);
ret = tftp_state.ctx->read(tftp_state.handle, &payload[2], TFTP_MAX_PAYLOAD_SIZE);
if (ret < 0) {
send_error(&tftp_state.addr, tftp_state.port, TFTP_ERROR_ACCESS_VIOLATION, "Error occured while reading the file.");
close_handle();
return;
}
pbuf_realloc(tftp_state.last_data, (u16_t)(TFTP_HEADER_LENGTH + ret));
resend_data();
}
static void
recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
u16_t *sbuf = (u16_t *) p->payload;
int opcode;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(upcb);
if (((tftp_state.port != 0) && (port != tftp_state.port)) ||
(!ip_addr_isany_val(tftp_state.addr) && !ip_addr_cmp(&tftp_state.addr, addr))) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
pbuf_free(p);
return;
}
opcode = sbuf[0];
tftp_state.last_pkt = tftp_state.timer;
tftp_state.retries = 0;
switch (opcode) {
case PP_HTONS(TFTP_RRQ): /* fall through */
case PP_HTONS(TFTP_WRQ):
{
const char tftp_null = 0;
char filename[TFTP_MAX_FILENAME_LEN];
char mode[TFTP_MAX_MODE_LEN];
u16_t filename_end_offset;
u16_t mode_end_offset;
if(tftp_state.handle != NULL) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
break;
}
sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);
/* find \0 in pbuf -> end of filename string */
filename_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), 2);
if((u16_t)(filename_end_offset-2) > sizeof(filename)) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Filename too long/not NULL terminated");
break;
}
pbuf_copy_partial(p, filename, filename_end_offset-2, 2);
/* find \0 in pbuf -> end of mode string */
mode_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), filename_end_offset+1);
if((u16_t)(mode_end_offset-filename_end_offset) > sizeof(mode)) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Mode too long/not NULL terminated");
break;
}
pbuf_copy_partial(p, mode, mode_end_offset-filename_end_offset, filename_end_offset+1);
tftp_state.handle = tftp_state.ctx->open(filename, mode, opcode == PP_HTONS(TFTP_WRQ));
tftp_state.blknum = 1;
if (!tftp_state.handle) {
send_error(addr, port, TFTP_ERROR_FILE_NOT_FOUND, "Unable to open requested file.");
break;
}
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: %s request from ", (opcode == PP_HTONS(TFTP_WRQ)) ? "write" : "read"));
ip_addr_debug_print(TFTP_DEBUG | LWIP_DBG_STATE, addr);
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, (" for '%s' mode '%s'\n", filename, mode));
ip_addr_copy(tftp_state.addr, *addr);
tftp_state.port = port;
if (opcode == PP_HTONS(TFTP_WRQ)) {
tftp_state.mode_write = 1;
send_ack(0);
} else {
tftp_state.mode_write = 0;
send_data();
}
break;
}
case PP_HTONS(TFTP_DATA):
{
int ret;
u16_t blknum;
if (tftp_state.handle == NULL) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
break;
}
if (tftp_state.mode_write != 1) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a write connection");
break;
}
blknum = lwip_ntohs(sbuf[1]);
pbuf_header(p, -TFTP_HEADER_LENGTH);
ret = tftp_state.ctx->write(tftp_state.handle, p);
if (ret < 0) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "error writing file");
close_handle();
} else {
send_ack(blknum);
}
if (p->tot_len < TFTP_MAX_PAYLOAD_SIZE) {
close_handle();
}
break;
}
case PP_HTONS(TFTP_ACK):
{
u16_t blknum;
int lastpkt;
if (tftp_state.handle == NULL) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
break;
}
if (tftp_state.mode_write != 0) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a read connection");
break;
}
blknum = lwip_ntohs(sbuf[1]);
if (blknum != tftp_state.blknum) {
send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number");
break;
}
lastpkt = 0;
if (tftp_state.last_data != NULL) {
lastpkt = tftp_state.last_data->tot_len != (TFTP_MAX_PAYLOAD_SIZE + TFTP_HEADER_LENGTH);
}
if (!lastpkt) {
tftp_state.blknum++;
send_data();
} else {
close_handle();
}
break;
}
default:
send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "Unknown operation");
break;
}
pbuf_free(p);
}
static void
tftp_tmr(void* arg)
{
LWIP_UNUSED_ARG(arg);
tftp_state.timer++;
if (tftp_state.handle == NULL) {
return;
}
sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);
if ((tftp_state.timer - tftp_state.last_pkt) > (TFTP_TIMEOUT_MSECS / TFTP_TIMER_MSECS)) {
if ((tftp_state.last_data != NULL) && (tftp_state.retries < TFTP_MAX_RETRIES)) {
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout, retrying\n"));
resend_data();
tftp_state.retries++;
} else {
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout\n"));
close_handle();
}
}
}
/** @ingroup tftp
* Initialize TFTP server.
* @param ctx TFTP callback struct
*/
err_t
tftp_init(const struct tftp_context *ctx)
{
err_t ret;
struct udp_pcb *pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
if (pcb == NULL) {
return ERR_MEM;
}
ret = udp_bind(pcb, IP_ANY_TYPE, TFTP_PORT);
if (ret != ERR_OK) {
udp_remove(pcb);
return ret;
}
tftp_state.handle = NULL;
tftp_state.port = 0;
tftp_state.ctx = ctx;
tftp_state.timer = 0;
tftp_state.last_data = NULL;
tftp_state.upcb = pcb;
udp_recv(pcb, recv, NULL);
return ERR_OK;
}
#endif /* LWIP_UDP */

View File

@ -2,6 +2,28 @@
* @file
* AutoIP Automatic LinkLocal IP Configuration
*
* This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
* with RFC 3927.
*
* @defgroup autoip AUTOIP
* @ingroup ip4
* AUTOIP related functions
* USAGE:
*
* define @ref LWIP_AUTOIP 1 in your lwipopts.h
* Options:
* AUTOIP_TMR_INTERVAL msecs,
* I recommend a value of 100. The value must divide 1000 with a remainder almost 0.
* Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....
*
* Without DHCP:
* - Call autoip_start() after netif_add().
*
* With DHCP:
* - define @ref LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.
* - Configure your DHCP Client.
*
* @see netifapi_autoip
*/
/*
@ -32,41 +54,6 @@
* OF SUCH DAMAGE.
*
* Author: Dominik Spies <kontakt@dspies.de>
*
* This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
* with RFC 3927.
*
*
* Please coordinate changes and requests with Dominik Spies
* <kontakt@dspies.de>
*/
/*******************************************************************************
* USAGE:
*
* define LWIP_AUTOIP 1 in your lwipopts.h
*
* If you don't use tcpip.c (so, don't call, you don't call tcpip_init):
* - First, call autoip_init().
* - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces,
* that should be defined in autoip.h.
* I recommend a value of 100. The value must divide 1000 with a remainder almost 0.
* Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....
*
* Without DHCP:
* - Call autoip_start() after netif_add().
*
* With DHCP:
* - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.
* - Configure your DHCP Client.
*
*/
/**
* @defgroup autoip AUTOIP
* @ingroup ip4
* AUTOIP related functions
* @see netifapi_autoip
*/
#include "lwip/opt.h"
@ -79,35 +66,10 @@
#include "lwip/netif.h"
#include "lwip/autoip.h"
#include "lwip/etharp.h"
#include "lwip/prot/autoip.h"
#include <stdlib.h>
#include <string.h>
/* 169.254.0.0 */
#define AUTOIP_NET 0xA9FE0000
/* 169.254.1.0 */
#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100)
/* 169.254.254.255 */
#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF)
/* RFC 3927 Constants */
#define PROBE_WAIT 1 /* second (initial random delay) */
#define PROBE_MIN 1 /* second (minimum delay till repeated probe) */
#define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */
#define PROBE_NUM 3 /* (number of probe packets) */
#define ANNOUNCE_NUM 2 /* (number of announcement packets) */
#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */
#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */
#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */
#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */
#define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */
/* AutoIP client states */
#define AUTOIP_STATE_OFF 0
#define AUTOIP_STATE_PROBING 1
#define AUTOIP_STATE_ANNOUNCING 2
#define AUTOIP_STATE_BOUND 3
/** Pseudo random macro based on netif informations.
* You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */
#ifndef LWIP_AUTOIP_RAND
@ -115,7 +77,7 @@
((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \
((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \
((u32_t)((netif->hwaddr[4]) & 0xff))) + \
(netif->autoip?netif->autoip->tried_llipaddr:0))
(netif_autoip_data(netif)? netif_autoip_data(netif)->tried_llipaddr : 0))
#endif /* LWIP_AUTOIP_RAND */
/**
@ -124,7 +86,7 @@
*/
#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
lwip_htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))
#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */
@ -132,7 +94,6 @@
static err_t autoip_arp_announce(struct netif *netif);
static void autoip_start_probing(struct netif *netif);
/**
* @ingroup autoip
* Set a statically allocated struct autoip to work with.
@ -146,12 +107,13 @@ 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);
LWIP_ASSERT("netif already has a struct autoip set",
netif_autoip_data(netif) == NULL);
/* clear data structure */
memset(autoip, 0, sizeof(struct autoip));
/* autoip->state = AUTOIP_STATE_OFF; */
netif->autoip = autoip;
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip);
}
/** Restart AutoIP client and check the next address (conflict detected)
@ -161,7 +123,8 @@ autoip_set_struct(struct netif *netif, struct autoip *autoip)
static void
autoip_restart(struct netif *netif)
{
netif->autoip->tried_llipaddr++;
struct autoip* autoip = netif_autoip_data(netif);
autoip->tried_llipaddr++;
autoip_start(netif);
}
@ -171,6 +134,8 @@ autoip_restart(struct netif *netif)
static void
autoip_handle_arp_conflict(struct netif *netif)
{
struct autoip* autoip = netif_autoip_data(netif);
/* RFC3927, 2.5 "Conflict Detection and Defense" allows two options where
a) means retreat on the first conflict and
b) allows to keep an already configured address when having only one
@ -178,7 +143,7 @@ autoip_handle_arp_conflict(struct netif *netif)
We use option b) since it helps to improve the chance that one of the two
conflicting hosts may be able to retain its address. */
if (netif->autoip->lastconflict > 0) {
if (autoip->lastconflict > 0) {
/* retreat, there was a conflicting ARP in the last DEFEND_INTERVAL seconds */
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
@ -189,7 +154,7 @@ autoip_handle_arp_conflict(struct netif *netif)
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
autoip_arp_announce(netif);
netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
}
}
@ -202,12 +167,14 @@ autoip_handle_arp_conflict(struct netif *netif)
static void
autoip_create_addr(struct netif *netif, ip4_addr_t *ipaddr)
{
struct autoip* autoip = netif_autoip_data(netif);
/* 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
* We have 254 * 256 possibilities */
u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
addr += netif->autoip->tried_llipaddr;
u32_t addr = lwip_ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
addr += autoip->tried_llipaddr;
addr = AUTOIP_NET | (addr & 0xffff);
/* Now, 169.254.0.0 <= addr <= 169.254.255.255 */
@ -219,11 +186,11 @@ autoip_create_addr(struct netif *netif, ip4_addr_t *ipaddr)
}
LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
(addr <= AUTOIP_RANGE_END));
ip4_addr_set_u32(ipaddr, htonl(addr));
ip4_addr_set_u32(ipaddr, lwip_htonl(addr));
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("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),
(u16_t)(autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr),
ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
}
@ -235,8 +202,9 @@ autoip_create_addr(struct netif *netif, ip4_addr_t *ipaddr)
static err_t
autoip_arp_probe(struct netif *netif)
{
struct autoip* autoip = netif_autoip_data(netif);
/* this works because netif->ip_addr is ANY */
return etharp_request(netif, &netif->autoip->llipaddr);
return etharp_request(netif, &autoip->llipaddr);
}
/**
@ -258,7 +226,7 @@ autoip_arp_announce(struct netif *netif)
static err_t
autoip_bind(struct netif *netif)
{
struct autoip *autoip = netif->autoip;
struct autoip* autoip = netif_autoip_data(netif);
ip4_addr_t sn_mask, gw_addr;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
@ -285,7 +253,7 @@ autoip_bind(struct netif *netif)
err_t
autoip_start(struct netif *netif)
{
struct autoip *autoip = netif->autoip;
struct autoip* autoip = netif_autoip_data(netif);
err_t result = ERR_OK;
LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;);
@ -293,7 +261,7 @@ autoip_start(struct netif *netif)
/* Set IP-Address, Netmask and Gateway to 0 to make sure that
* ARP Packets are formed correctly
*/
netif_set_addr(netif, IP4_ADDR_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY);
netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0],
@ -310,7 +278,7 @@ autoip_start(struct netif *netif)
}
memset(autoip, 0, sizeof(struct autoip));
/* store this AutoIP client in the netif */
netif->autoip = autoip;
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));
} else {
autoip->state = AUTOIP_STATE_OFF;
@ -329,14 +297,14 @@ autoip_start(struct netif *netif)
static void
autoip_start_probing(struct netif *netif)
{
struct autoip *autoip = netif->autoip;
struct autoip* autoip = netif_autoip_data(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)));
ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
/* time to wait to first probe, this is randomly
* chosen out of 0 to PROBE_WAIT seconds.
@ -363,7 +331,9 @@ autoip_start_probing(struct netif *netif)
void
autoip_network_changed(struct netif *netif)
{
if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {
struct autoip* autoip = netif_autoip_data(netif);
if (autoip && (autoip->state != AUTOIP_STATE_OFF)) {
autoip_start_probing(netif);
}
}
@ -377,10 +347,12 @@ autoip_network_changed(struct netif *netif)
err_t
autoip_stop(struct netif *netif)
{
if (netif->autoip) {
netif->autoip->state = AUTOIP_STATE_OFF;
struct autoip* autoip = netif_autoip_data(netif);
if (autoip != NULL) {
autoip->state = AUTOIP_STATE_OFF;
if (ip4_addr_islinklocal(netif_ip4_addr(netif))) {
netif_set_addr(netif, IP4_ADDR_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY);
netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
}
}
return ERR_OK;
@ -395,45 +367,46 @@ autoip_tmr(void)
struct netif *netif = netif_list;
/* loop through netif's */
while (netif != NULL) {
struct autoip* autoip = netif_autoip_data(netif);
/* only act on AutoIP configured interfaces */
if (netif->autoip != NULL) {
if (netif->autoip->lastconflict > 0) {
netif->autoip->lastconflict--;
if (autoip != NULL) {
if (autoip->lastconflict > 0) {
autoip->lastconflict--;
}
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n",
(u16_t)(netif->autoip->state), netif->autoip->ttw));
(u16_t)(autoip->state), autoip->ttw));
if (netif->autoip->ttw > 0) {
netif->autoip->ttw--;
if (autoip->ttw > 0) {
autoip->ttw--;
}
switch(netif->autoip->state) {
switch(autoip->state) {
case AUTOIP_STATE_PROBING:
if (netif->autoip->ttw == 0) {
if (netif->autoip->sent_num >= PROBE_NUM) {
if (autoip->ttw == 0) {
if (autoip->sent_num >= PROBE_NUM) {
/* Switch to ANNOUNCING: now we can bind to an IP address and use it */
netif->autoip->state = AUTOIP_STATE_ANNOUNCING;
autoip->state = AUTOIP_STATE_ANNOUNCING;
autoip_bind(netif);
/* autoip_bind() calls netif_set_addr(): this triggers a gratuitous ARP
which counts as an announcement */
netif->autoip->sent_num = 1;
netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
autoip->sent_num = 1;
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)));
ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
} else {
autoip_arp_probe(netif);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() PROBING Sent Probe\n"));
netif->autoip->sent_num++;
if (netif->autoip->sent_num == PROBE_NUM) {
autoip->sent_num++;
if (autoip->sent_num == PROBE_NUM) {
/* calculate time to wait to for announce */
netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
} else {
/* calculate time to wait to next probe */
netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %
autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %
((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +
PROBE_MIN * AUTOIP_TICKS_PER_SECOND);
}
@ -442,20 +415,20 @@ autoip_tmr(void)
break;
case AUTOIP_STATE_ANNOUNCING:
if (netif->autoip->ttw == 0) {
if (autoip->ttw == 0) {
autoip_arp_announce(netif);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() ANNOUNCING Sent Announce\n"));
netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
netif->autoip->sent_num++;
autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
autoip->sent_num++;
if (netif->autoip->sent_num >= ANNOUNCE_NUM) {
netif->autoip->state = AUTOIP_STATE_BOUND;
netif->autoip->sent_num = 0;
netif->autoip->ttw = 0;
if (autoip->sent_num >= ANNOUNCE_NUM) {
autoip->state = AUTOIP_STATE_BOUND;
autoip->sent_num = 0;
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)));
ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
}
}
break;
@ -471,7 +444,7 @@ autoip_tmr(void)
}
/**
* Handles every incoming ARP Packet, called by etharp_arp_input.
* Handles every incoming ARP Packet, called by etharp_input().
*
* @param netif network interface to use for autoip processing
* @param hdr Incoming ARP packet
@ -479,8 +452,10 @@ autoip_tmr(void)
void
autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
{
struct autoip* autoip = netif_autoip_data(netif);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n"));
if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) {
if ((autoip != NULL) && (autoip->state != AUTOIP_STATE_OFF)) {
/* when ip.src == llipaddr && hw.src != netif->hwaddr
*
* when probing ip.dst == llipaddr && hw.src != netif->hwaddr
@ -496,15 +471,16 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
if (netif->autoip->state == AUTOIP_STATE_PROBING) {
if (autoip->state == AUTOIP_STATE_PROBING) {
/* RFC 3927 Section 2.2.1:
* from beginning to after ANNOUNCE_WAIT
* seconds we have a conflict if
* ip.src == llipaddr OR
* ip.dst == llipaddr && hw.src != own hwaddr
*/
if ((ip4_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||
(ip4_addr_cmp(&dipaddr, &netif->autoip->llipaddr) &&
if ((ip4_addr_cmp(&sipaddr, &autoip->llipaddr)) ||
(ip4_addr_isany_val(sipaddr) &&
ip4_addr_cmp(&dipaddr, &autoip->llipaddr) &&
!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"));
@ -515,7 +491,7 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
* in any state we have a conflict if
* ip.src == llipaddr && hw.src != own hwaddr
*/
if (ip4_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&
if (ip4_addr_cmp(&sipaddr, &autoip->llipaddr) &&
!eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
@ -534,13 +510,18 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
u8_t
autoip_supplied_address(const struct netif *netif)
{
if ((netif != NULL) && (netif->autoip != NULL)) {
if ((netif->autoip->state == AUTOIP_STATE_BOUND) ||
(netif->autoip->state == AUTOIP_STATE_ANNOUNCING)) {
return 1;
}
if ((netif != NULL) && (netif_autoip_data(netif) != NULL)) {
struct autoip* autoip = netif_autoip_data(netif);
return (autoip->state == AUTOIP_STATE_BOUND) || (autoip->state == AUTOIP_STATE_ANNOUNCING);
}
return 0;
}
u8_t
autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr)
{
struct autoip* autoip = netif_autoip_data(netif);
return (autoip != NULL) && ip4_addr_cmp(addr, &(autoip->llipaddr));
}
#endif /* LWIP_IPV4 && LWIP_AUTOIP */

View File

@ -2,6 +2,26 @@
* @file
* Dynamic Host Configuration Protocol client
*
* @defgroup dhcp4 DHCPv4
* @ingroup ip4
* DHCP (IPv4) related functions
* This is a DHCP client for the lwIP TCP/IP stack. It aims to conform
* with RFC 2131 and RFC 2132.
*
* @todo:
* - Support for interfaces other than Ethernet (SLIP, PPP, ...)
*
* Options:
* @ref DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute)
* @ref DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer)
*
* dhcp_start() starts a DHCP client instance which
* configures the interface by obtaining an IP address lease and maintaining it.
*
* Use dhcp_release() to end the lease and use dhcp_stop()
* to remove the DHCP client.
*
* @see netifapi_dhcp4
*/
/*
@ -38,38 +58,6 @@
*
* Author: Leon Woestenberg <leon.woestenberg@gmx.net>
*
* This is a DHCP client for the lwIP TCP/IP stack. It aims to conform
* with RFC 2131 and RFC 2132.
*
* @todo:
* - Support for interfaces other than Ethernet (SLIP, PPP, ...)
*
* Please coordinate changes and requests with Leon Woestenberg
* <leon.woestenberg@gmx.net>
*
* Integration with your code:
*
* In lwip/dhcp.h
* #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute)
* #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer)
*
* Then have your application call dhcp_coarse_tmr() and
* dhcp_fine_tmr() on the defined intervals.
*
* dhcp_start(struct netif *netif);
* starts a DHCP client instance which configures the interface by
* obtaining an IP address lease and maintaining it.
*
* Use dhcp_release(netif) to end the lease and use dhcp_stop(netif)
* to remove the DHCP client.
*
*/
/**
* @defgroup dhcp4 DHCPv4
* @ingroup ip4
* DHCP (IPv4) related functions
* @see netifapi_dhcp4
*/
#include "lwip/opt.h"
@ -86,6 +74,7 @@
#include "lwip/autoip.h"
#include "lwip/dns.h"
#include "lwip/etharp.h"
#include "lwip/prot/dhcp.h"
#include <string.h>
@ -114,26 +103,40 @@
#define REBOOT_TRIES 2
#if LWIP_DNS && LWIP_DHCP_MAX_DNS_SERVERS
#if DNS_MAX_SERVERS > LWIP_DHCP_MAX_DNS_SERVERS
#define LWIP_DHCP_PROVIDE_DNS_SERVERS LWIP_DHCP_MAX_DNS_SERVERS
#else
#define LWIP_DHCP_PROVIDE_DNS_SERVERS DNS_MAX_SERVERS
#endif
#else
#define LWIP_DHCP_PROVIDE_DNS_SERVERS 0
#endif
/** Option handling: options are parsed in dhcp_parse_reply
* and saved in an array where other functions can load them from.
* This might be moved into the struct dhcp (not necessarily since
* lwIP is single-threaded and the array is only used while in recv
* callback). */
#define DHCP_OPTION_IDX_OVERLOAD 0
#define DHCP_OPTION_IDX_MSG_TYPE 1
#define DHCP_OPTION_IDX_SERVER_ID 2
#define DHCP_OPTION_IDX_LEASE_TIME 3
#define DHCP_OPTION_IDX_T1 4
#define DHCP_OPTION_IDX_T2 5
#define DHCP_OPTION_IDX_SUBNET_MASK 6
#define DHCP_OPTION_IDX_ROUTER 7
#define DHCP_OPTION_IDX_DNS_SERVER 8
enum dhcp_option_idx {
DHCP_OPTION_IDX_OVERLOAD = 0,
DHCP_OPTION_IDX_MSG_TYPE,
DHCP_OPTION_IDX_SERVER_ID,
DHCP_OPTION_IDX_LEASE_TIME,
DHCP_OPTION_IDX_T1,
DHCP_OPTION_IDX_T2,
DHCP_OPTION_IDX_SUBNET_MASK,
DHCP_OPTION_IDX_ROUTER,
#if LWIP_DHCP_PROVIDE_DNS_SERVERS
DHCP_OPTION_IDX_DNS_SERVER,
DHCP_OPTION_IDX_DNS_SERVER_LAST = DHCP_OPTION_IDX_DNS_SERVER + LWIP_DHCP_PROVIDE_DNS_SERVERS - 1,
#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
#if LWIP_DHCP_GET_NTP_SRV
#define DHCP_OPTION_IDX_NTP_SERVER (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS)
#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_NTP_SERVER + LWIP_DHCP_MAX_NTP_SERVERS)
#else /* LWIP_DHCP_GET_NTP_SRV */
#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS)
DHCP_OPTION_IDX_NTP_SERVER,
DHCP_OPTION_IDX_NTP_SERVER_LAST = DHCP_OPTION_IDX_NTP_SERVER + LWIP_DHCP_MAX_NTP_SERVERS - 1,
#endif /* LWIP_DHCP_GET_NTP_SRV */
DHCP_OPTION_IDX_MAX
};
/** Holds the decoded option values, only valid while in dhcp_recv.
@todo: move this into struct dhcp? */
@ -146,8 +149,10 @@ u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX];
static u8_t dhcp_discover_request_options[] = {
DHCP_OPTION_SUBNET_MASK,
DHCP_OPTION_ROUTER,
DHCP_OPTION_BROADCAST,
DHCP_OPTION_DNS_SERVER
DHCP_OPTION_BROADCAST
#if LWIP_DHCP_PROVIDE_DNS_SERVERS
, DHCP_OPTION_DNS_SERVER
#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
#if LWIP_DHCP_GET_NTP_SRV
, DHCP_OPTION_NTP
#endif /* LWIP_DHCP_GET_NTP_SRV */
@ -221,13 +226,13 @@ dhcp_inc_pcb_refcount(void)
ip_set_option(dhcp_pcb, SOF_BROADCAST);
/* set up local and remote port for the pcb -> listen on all interfaces on all src/dest IPs */
udp_bind(dhcp_pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
udp_connect(dhcp_pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
udp_recv(dhcp_pcb, dhcp_recv, NULL);
udp_bind(dhcp_pcb, IP4_ADDR_ANY, DHCP_CLIENT_PORT);
udp_connect(dhcp_pcb, IP4_ADDR_ANY, DHCP_SERVER_PORT);
udp_recv(dhcp_pcb, dhcp_recv, NULL);
}
dhcp_pcb_refcount++;
return ERR_OK;
}
@ -237,7 +242,7 @@ dhcp_dec_pcb_refcount(void)
{
LWIP_ASSERT("dhcp_pcb_refcount(): refcount error", (dhcp_pcb_refcount > 0));
dhcp_pcb_refcount--;
if (dhcp_pcb_refcount == 0) {
udp_remove(dhcp_pcb);
dhcp_pcb = NULL;
@ -259,14 +264,15 @@ dhcp_dec_pcb_refcount(void)
static void
dhcp_handle_nak(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n",
(void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
/* Change to a defined state - set this before assigning the address
to ensure the callback can use dhcp_supplied_address() */
dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF);
/* remove IP address from interface (must no longer be used, as per RFC2131) */
netif_set_addr(netif, IP4_ADDR_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY);
netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
/* We can immediately restart discovery */
dhcp_discover(netif);
}
@ -284,7 +290,7 @@ dhcp_handle_nak(struct netif *netif)
static void
dhcp_check(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result;
u16_t msecs;
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],
@ -313,12 +319,13 @@ dhcp_check(struct netif *netif)
static void
dhcp_handle_offer(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",
(void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
/* obtain the server address */
if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) {
ip_addr_set_ip4_u32(&dhcp->server_ip_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID)));
ip_addr_set_ip4_u32(&dhcp->server_ip_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID)));
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n",
ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr))));
/* remember offered address */
@ -344,7 +351,7 @@ dhcp_handle_offer(struct netif *netif)
static err_t
dhcp_select(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result;
u16_t msecs;
u8_t i;
@ -360,10 +367,10 @@ dhcp_select(struct netif *netif)
/* MUST request the offered IP address */
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
dhcp_option_long(dhcp, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr))));
dhcp_option_long(dhcp, lwip_ntohl(ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr))));
dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options));
for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) {
@ -379,7 +386,7 @@ dhcp_select(struct netif *netif)
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
/* send broadcast to any DHCP server */
udp_sendto_if_src(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP_ADDR_ANY);
udp_sendto_if_src(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP4_ADDR_ANY);
dhcp_delete_msg(dhcp);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n"));
} else {
@ -396,6 +403,7 @@ dhcp_select(struct netif *netif)
/**
* The DHCP timer that checks for lease renewal/rebind timeouts.
* Must be called once a minute (see @ref DHCP_COARSE_TIMER_SECS).
*/
void
dhcp_coarse_tmr(void)
@ -405,7 +413,7 @@ dhcp_coarse_tmr(void)
/* iterate through all network interfaces */
while (netif != NULL) {
/* only act on DHCP configured interfaces */
struct dhcp* dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
if ((dhcp != NULL) && (dhcp->state != DHCP_STATE_OFF)) {
/* compare lease time to expire timeout */
if (dhcp->t0_timeout && (++dhcp->lease_used == dhcp->t0_timeout)) {
@ -431,7 +439,8 @@ dhcp_coarse_tmr(void)
}
/**
* DHCP transaction timeout handling
* DHCP transaction timeout handling (this function must be called every 500ms,
* see @ref DHCP_FINE_TIMER_MSECS).
*
* A DHCP server is expected to respond within a short period of time.
* This timer checks whether an outstanding DHCP request is timed out.
@ -442,14 +451,15 @@ dhcp_fine_tmr(void)
struct netif *netif = netif_list;
/* loop through netif's */
while (netif != NULL) {
struct dhcp *dhcp = netif_dhcp_data(netif);
/* only act on DHCP configured interfaces */
if (netif->dhcp != NULL) {
if (dhcp != NULL) {
/* timer is active (non zero), and is about to trigger now */
if (netif->dhcp->request_timeout > 1) {
netif->dhcp->request_timeout--;
if (dhcp->request_timeout > 1) {
dhcp->request_timeout--;
}
else if (netif->dhcp->request_timeout == 1) {
netif->dhcp->request_timeout--;
else if (dhcp->request_timeout == 1) {
dhcp->request_timeout--;
/* { netif->dhcp->request_timeout == 0 } */
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));
/* this client's request timeout triggered */
@ -472,7 +482,8 @@ dhcp_fine_tmr(void)
static void
dhcp_timeout(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n"));
/* back-off period has passed, or server selection timed out */
if ((dhcp->state == DHCP_STATE_BACKING_OFF) || (dhcp->state == DHCP_STATE_SELECTING)) {
@ -518,7 +529,8 @@ dhcp_timeout(struct netif *netif)
static void
dhcp_t1_timeout(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n"));
if ((dhcp->state == DHCP_STATE_REQUESTING) || (dhcp->state == DHCP_STATE_BOUND) ||
(dhcp->state == DHCP_STATE_RENEWING)) {
@ -530,9 +542,9 @@ dhcp_t1_timeout(struct netif *netif)
DHCP_STATE_RENEWING, not DHCP_STATE_BOUND */
dhcp_renew(netif);
/* Calculate next timeout */
if (((netif->dhcp->t2_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS))
if (((dhcp->t2_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS))
{
netif->dhcp->t1_renew_time = ((netif->dhcp->t2_timeout - dhcp->lease_used) / 2);
dhcp->t1_renew_time = ((dhcp->t2_timeout - dhcp->lease_used) / 2);
}
}
}
@ -545,7 +557,8 @@ dhcp_t1_timeout(struct netif *netif)
static void
dhcp_t2_timeout(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n"));
if ((dhcp->state == DHCP_STATE_REQUESTING) || (dhcp->state == DHCP_STATE_BOUND) ||
(dhcp->state == DHCP_STATE_RENEWING) || (dhcp->state == DHCP_STATE_REBINDING)) {
@ -556,9 +569,9 @@ dhcp_t2_timeout(struct netif *netif)
DHCP_STATE_REBINDING, not DHCP_STATE_BOUND */
dhcp_rebind(netif);
/* Calculate next timeout */
if (((netif->dhcp->t0_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS))
if (((dhcp->t0_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS))
{
netif->dhcp->t2_rebind_time = ((netif->dhcp->t0_timeout - dhcp->lease_used) / 2);
dhcp->t2_rebind_time = ((dhcp->t0_timeout - dhcp->lease_used) / 2);
}
}
}
@ -571,10 +584,11 @@ dhcp_t2_timeout(struct netif *netif)
static void
dhcp_handle_ack(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
#if LWIP_DNS || LWIP_DHCP_GET_NTP_SRV
struct dhcp *dhcp = netif_dhcp_data(netif);
#if LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV
u8_t n;
#endif /* LWIP_DNS || LWIP_DHCP_GET_NTP_SRV */
#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV */
#if LWIP_DHCP_GET_NTP_SRV
ip4_addr_t ntp_server_addrs[LWIP_DHCP_MAX_NTP_SERVERS];
#endif
@ -615,13 +629,13 @@ dhcp_handle_ack(struct netif *netif)
#if LWIP_DHCP_BOOTP_FILE
/* copy boot server address,
boot file name copied in dhcp_parse_reply if not overloaded */
ip_addr_copy(dhcp->offered_si_addr, dhcp->msg_in->siaddr);
ip4_addr_copy(dhcp->offered_si_addr, dhcp->msg_in->siaddr);
#endif /* LWIP_DHCP_BOOTP_FILE */
/* subnet mask given? */
if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) {
/* remember given subnet mask */
ip4_addr_set_u32(&dhcp->offered_sn_mask, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)));
ip4_addr_set_u32(&dhcp->offered_sn_mask, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)));
dhcp->subnet_mask_given = 1;
} else {
dhcp->subnet_mask_given = 0;
@ -629,25 +643,25 @@ dhcp_handle_ack(struct netif *netif)
/* gateway router */
if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) {
ip4_addr_set_u32(&dhcp->offered_gw_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER)));
ip4_addr_set_u32(&dhcp->offered_gw_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER)));
}
#if LWIP_DHCP_GET_NTP_SRV
/* NTP servers */
for (n = 0; (n < LWIP_DHCP_MAX_NTP_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n); n++) {
ip4_addr_set_u32(&ntp_server_addrs[n], htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n)));
ip4_addr_set_u32(&ntp_server_addrs[n], lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n)));
}
dhcp_set_ntp_servers(n, ntp_server_addrs);
#endif /* LWIP_DHCP_GET_NTP_SRV */
#if LWIP_DNS
#if LWIP_DHCP_PROVIDE_DNS_SERVERS
/* DNS servers */
for (n = 0; (n < DNS_MAX_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) {
for (n = 0; (n < LWIP_DHCP_PROVIDE_DNS_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) {
ip_addr_t dns_addr;
ip_addr_set_ip4_u32(&dns_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n)));
ip_addr_set_ip4_u32(&dns_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n)));
dns_setserver(n, &dns_addr);
}
#endif /* LWIP_DNS */
#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
}
/**
@ -663,12 +677,12 @@ dhcp_set_struct(struct netif *netif, struct dhcp *dhcp)
{
LWIP_ASSERT("netif != NULL", netif != NULL);
LWIP_ASSERT("dhcp != NULL", dhcp != NULL);
LWIP_ASSERT("netif already has a struct dhcp set", netif->dhcp == NULL);
LWIP_ASSERT("netif already has a struct dhcp set", netif_dhcp_data(netif) == NULL);
/* clear data structure */
memset(dhcp, 0, sizeof(struct dhcp));
/* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */
netif->dhcp = dhcp;
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp);
}
/**
@ -684,9 +698,9 @@ void dhcp_cleanup(struct netif *netif)
{
LWIP_ASSERT("netif != NULL", netif != NULL);
if (netif->dhcp != NULL) {
mem_free(netif->dhcp);
netif->dhcp = NULL;
if (netif_dhcp_data(netif) != NULL) {
mem_free(netif_dhcp_data(netif));
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, NULL);
}
}
@ -711,7 +725,7 @@ dhcp_start(struct netif *netif)
LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);
LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;);
dhcp = netif->dhcp;
dhcp = netif_dhcp_data(netif);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
/* check MTU of the netif */
@ -728,9 +742,9 @@ dhcp_start(struct netif *netif)
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));
return ERR_MEM;
}
/* store this dhcp client in the netif */
netif->dhcp = dhcp;
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp"));
/* already has DHCP client attached */
} else {
@ -748,7 +762,7 @@ dhcp_start(struct netif *netif)
memset(dhcp, 0, sizeof(struct dhcp));
/* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));
if (dhcp_inc_pcb_refcount() != ERR_OK) { /* ensure DHCP PCB is allocated */
return ERR_MEM;
@ -810,7 +824,7 @@ dhcp_inform(struct netif *netif)
pbuf_realloc(dhcp.p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp.options_out_len);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n"));
udp_sendto_if(dhcp_pcb, dhcp.p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
dhcp_delete_msg(&dhcp);
@ -829,7 +843,8 @@ dhcp_inform(struct netif *netif)
void
dhcp_network_changed(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
if (!dhcp)
return;
switch (dhcp->state) {
@ -862,7 +877,8 @@ dhcp_network_changed(struct netif *netif)
#if DHCP_DOES_ARP_CHECK
/**
* Match an ARP reply with the offered IP address.
* Match an ARP reply with the offered IP address:
* check whether the offered IP address is not in use using ARP
*
* @param netif the network interface on which the reply was received
* @param addr The IP address we received a reply from
@ -870,15 +886,18 @@ dhcp_network_changed(struct netif *netif)
void
dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr)
{
struct dhcp *dhcp;
LWIP_ERROR("netif != NULL", (netif != NULL), return;);
dhcp = netif_dhcp_data(netif);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n"));
/* is a DHCP client doing an ARP check? */
if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_STATE_CHECKING)) {
if ((dhcp != NULL) && (dhcp->state == DHCP_STATE_CHECKING)) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n",
ip4_addr_get_u32(addr)));
/* did a host respond with the address we
were offered by the DHCP server? */
if (ip4_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) {
if (ip4_addr_cmp(addr, &dhcp->offered_ip_addr)) {
/* we will not accept the offered address */
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));
@ -899,7 +918,7 @@ dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr)
static err_t
dhcp_decline(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result = ERR_OK;
u16_t msecs;
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n"));
@ -908,14 +927,14 @@ dhcp_decline(struct netif *netif)
result = dhcp_create_msg(netif, dhcp, DHCP_DECLINE);
if (result == ERR_OK) {
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
dhcp_option_long(dhcp, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
dhcp_option_trailer(dhcp);
/* resize pbuf to reflect true size of options */
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
/* per section 4.4.4, broadcast DECLINE messages */
udp_sendto_if_src(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP_ADDR_ANY);
udp_sendto_if_src(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP4_ADDR_ANY);
dhcp_delete_msg(dhcp);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
} else {
@ -941,7 +960,7 @@ dhcp_decline(struct netif *netif)
static err_t
dhcp_discover(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result = ERR_OK;
u16_t msecs;
u8_t i;
@ -966,7 +985,7 @@ dhcp_discover(struct netif *netif)
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));
udp_sendto_if_src(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP_ADDR_ANY);
udp_sendto_if_src(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP4_ADDR_ANY);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
dhcp_delete_msg(dhcp);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n"));
@ -1001,7 +1020,7 @@ dhcp_bind(struct netif *netif)
struct dhcp *dhcp;
ip4_addr_t sn_mask, gw_addr;
LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;);
dhcp = netif->dhcp;
dhcp = netif_dhcp_data(netif);
LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
@ -1107,7 +1126,7 @@ dhcp_bind(struct netif *netif)
err_t
dhcp_renew(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result;
u16_t msecs;
u8_t i;
@ -1159,7 +1178,7 @@ dhcp_renew(struct netif *netif)
static err_t
dhcp_rebind(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result;
u16_t msecs;
u8_t i;
@ -1209,7 +1228,7 @@ dhcp_rebind(struct netif *netif)
static err_t
dhcp_reboot(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result;
u16_t msecs;
u8_t i;
@ -1220,10 +1239,10 @@ dhcp_reboot(struct netif *netif)
result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);
if (result == ERR_OK) {
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
dhcp_option_short(dhcp, 576);
dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN_MIN_REQUIRED);
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
dhcp_option_long(dhcp, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));
dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options));
for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) {
@ -1253,14 +1272,14 @@ dhcp_reboot(struct netif *netif)
/**
* @ingroup dhcp4
* Release a DHCP lease.
* Release a DHCP lease (usually called before @ref dhcp_stop).
*
* @param netif network interface which must release its lease
*/
err_t
dhcp_release(struct netif *netif)
{
struct dhcp *dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result;
ip_addr_t server_ip_addr;
u8_t is_dhcp_supplied_address;
@ -1295,7 +1314,7 @@ dhcp_release(struct netif *netif)
result = dhcp_create_msg(netif, dhcp, DHCP_RELEASE);
if (result == ERR_OK) {
dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(ip_2_ip4(&server_ip_addr))));
dhcp_option_long(dhcp, lwip_ntohl(ip4_addr_get_u32(ip_2_ip4(&server_ip_addr))));
dhcp_option_trailer(dhcp);
@ -1309,7 +1328,7 @@ dhcp_release(struct netif *netif)
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n"));
}
/* remove IP address from interface (prevents routing from selecting this interface) */
netif_set_addr(netif, IP4_ADDR_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY);
netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
return result;
}
@ -1325,7 +1344,7 @@ dhcp_stop(struct netif *netif)
{
struct dhcp *dhcp;
LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;);
dhcp = netif->dhcp;
dhcp = netif_dhcp_data(netif);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_stop()\n"));
/* netif is DHCP configured? */
@ -1410,14 +1429,15 @@ dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif)
if (netif->hostname != NULL) {
size_t namelen = strlen(netif->hostname);
if (namelen > 0) {
u8_t len;
size_t len;
const char *p = netif->hostname;
/* Shrink len to available bytes (need 2 bytes for OPTION_HOSTNAME
and 1 byte for trailer) */
size_t available = DHCP_OPTIONS_LEN - dhcp->options_out_len - 3;
LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available);
len = LWIP_MIN(namelen, available);
dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, len);
LWIP_ASSERT("DHCP: hostname is too long!", len <= 0xFF);
dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, (u8_t)len);
while (len--) {
dhcp_option_byte(dhcp, *p++);
}
@ -1487,7 +1507,7 @@ again:
int decode_idx = -1;
u16_t val_offset = offset + 2;
/* len byte might be in the next pbuf */
if (offset + 1 < q->len) {
if ((offset + 1) < q->len) {
len = options[offset + 1];
} else {
len = (q->next != NULL ? ((u8_t*)q->next->payload)[0] : 0);
@ -1511,14 +1531,16 @@ again:
LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_ROUTER;
break;
#if LWIP_DHCP_PROVIDE_DNS_SERVERS
case(DHCP_OPTION_DNS_SERVER):
/* special case: there might be more than one server */
LWIP_ERROR("len % 4 == 0", len % 4 == 0, return ERR_VAL;);
LWIP_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;);
/* limit number of DNS servers */
decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS);
LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_DNS_SERVER;
break;
#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
case(DHCP_OPTION_LEASE_TIME):
LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_LEASE_TIME;
@ -1526,7 +1548,7 @@ again:
#if LWIP_DHCP_GET_NTP_SRV
case(DHCP_OPTION_NTP):
/* special case: there might be more than one server */
LWIP_ERROR("len % 4 == 0", len % 4 == 0, return ERR_VAL;);
LWIP_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;);
/* limit number of NTP servers */
decode_len = LWIP_MIN(len, 4 * LWIP_DHCP_MAX_NTP_SERVERS);
LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
@ -1568,18 +1590,20 @@ decode_next:
LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX);
if (!dhcp_option_given(dhcp, decode_idx)) {
copy_len = LWIP_MIN(decode_len, 4);
pbuf_copy_partial(q, &value, copy_len, val_offset);
if (pbuf_copy_partial(q, &value, copy_len, val_offset) != copy_len) {
return ERR_BUF;
}
if (decode_len > 4) {
/* decode more than one u32_t */
LWIP_ERROR("decode_len % 4 == 0", decode_len % 4 == 0, return ERR_VAL;);
LWIP_ERROR("decode_len %% 4 == 0", decode_len % 4 == 0, return ERR_VAL;);
dhcp_got_option(dhcp, decode_idx);
dhcp_set_option_value(dhcp, decode_idx, htonl(value));
dhcp_set_option_value(dhcp, decode_idx, lwip_htonl(value));
decode_len -= 4;
val_offset += 4;
decode_idx++;
goto decode_next;
} else if (decode_len == 4) {
value = ntohl(value);
value = lwip_ntohl(value);
} else {
LWIP_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL;);
value = ((u8_t*)&value)[0];
@ -1624,7 +1648,9 @@ decode_next:
if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) &&
(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK))
/* copy bootp file name, don't care for sname (server hostname) */
pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS);
if (pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS) != (DHCP_FILE_LEN-1)) {
return ERR_BUF;
}
/* make sure the string is really NULL-terminated */
dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0;
}
@ -1652,11 +1678,11 @@ static void
dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
struct netif *netif = ip_current_input_netif();
struct dhcp *dhcp = netif->dhcp;
struct dhcp *dhcp = netif_dhcp_data(netif);
struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;
u8_t msg_type;
u8_t i;
LWIP_UNUSED_ARG(arg);
/* Caught DHCP message from netif that does not have DHCP enabled? -> not interested */
@ -1665,7 +1691,7 @@ dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
}
LWIP_ASSERT("invalid server address type", IP_IS_V4(addr));
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,
ip4_addr1_16(ip_2_ip4(addr)), ip4_addr2_16(ip_2_ip4(addr)), ip4_addr3_16(ip_2_ip4(addr)), ip4_addr4_16(ip_2_ip4(addr)), port));
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
@ -1696,9 +1722,9 @@ dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
}
}
/* match transaction ID against what we expected */
if (ntohl(reply_msg->xid) != dhcp->xid) {
if (lwip_ntohl(reply_msg->xid) != dhcp->xid) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid));
("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",lwip_ntohl(reply_msg->xid),dhcp->xid));
goto free_pbuf_and_return;
}
/* option fields could be unfold? */
@ -1827,7 +1853,7 @@ dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type)
dhcp->msg_out->htype = DHCP_HTYPE_ETH;
dhcp->msg_out->hlen = netif->hwaddr_len;
dhcp->msg_out->hops = 0;
dhcp->msg_out->xid = htonl(dhcp->xid);
dhcp->msg_out->xid = lwip_htonl(dhcp->xid);
dhcp->msg_out->secs = 0;
/* we don't need the broadcast flag since we can receive unicast traffic
before being fully configured! */
@ -1914,11 +1940,9 @@ dhcp_option_trailer(struct dhcp *dhcp)
u8_t
dhcp_supplied_address(const struct netif *netif)
{
if ((netif != NULL) && (netif->dhcp != NULL)) {
if ((netif->dhcp->state == DHCP_STATE_BOUND) ||
(netif->dhcp->state == DHCP_STATE_RENEWING)) {
return 1;
}
if ((netif != NULL) && (netif_dhcp_data(netif) != NULL)) {
struct dhcp* dhcp = netif_dhcp_data(netif);
return (dhcp->state == DHCP_STATE_BOUND) || (dhcp->state == DHCP_STATE_RENEWING);
}
return 0;
}

View File

@ -52,6 +52,7 @@
#include "lwip/snmp.h"
#include "lwip/dhcp.h"
#include "lwip/autoip.h"
#include "netif/lwip_ethernet.h"
#include <string.h>
@ -71,8 +72,7 @@
*/
#define ARP_MAXPENDING 5
#define HWTYPE_ETHERNET 1
/** ARP states */
enum etharp_state {
ETHARP_STATE_EMPTY = 0,
ETHARP_STATE_PENDING,
@ -240,7 +240,7 @@ etharp_tmr(void)
* old entries. Heuristic choose the least important entry for recycling.
*
* @param ipaddr IP address to find in ARP cache, or to add if not found.
* @param flags @see definition of ETHARP_FLAG_*
* @param flags See @ref etharp_state
* @param netif netif related to this address (used for NETIF_HWADDRHINT)
*
* @return The ARP entry index that matched or is created, ERR_MEM if no
@ -394,47 +394,6 @@ etharp_find_entry(const ip4_addr_t *ipaddr, u8_t flags, struct netif* netif)
return (err_t)i;
}
/**
* Send an IP packet on the network using netif->linkoutput
* The ethernet header is filled in before sending.
*
* @params netif the lwIP network interface on which to send the packet
* @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header
* @params src the source MAC address to be copied into the ethernet header
* @params dst the destination MAC address to be copied into the ethernet header
* @return ERR_OK if the packet was sent, any other err_t on failure
*/
static err_t
etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, const struct eth_addr *dst)
{
struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload;
#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET)
struct eth_vlan_hdr *vlanhdr;
#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
LWIP_ASSERT("netif->hwaddr_len must be the same as ETH_HWADDR_LEN for etharp!",
(netif->hwaddr_len == ETH_HWADDR_LEN));
#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET)
ethhdr->type = PP_HTONS(ETHTYPE_VLAN);
vlanhdr = (struct eth_vlan_hdr*)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR);
vlanhdr->prio_vid = 0;
vlanhdr->tpid = PP_HTONS(ETHTYPE_IP);
if (!LWIP_HOOK_VLAN_SET(netif, ethhdr, vlanhdr)) {
/* packet shall not contain VLAN header, so hide it and set correct ethertype */
pbuf_header(p, -SIZEOF_VLAN_HDR);
ethhdr = (struct eth_hdr *)p->payload;
#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
ethhdr->type = PP_HTONS(ETHTYPE_IP);
#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET)
}
#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
ETHADDR32_COPY(&ethhdr->dest, dst);
ETHADDR16_COPY(&ethhdr->src, src);
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_send_ip: sending packet %p\n", (void *)p));
/* send the packet */
return netif->linkoutput(netif, p);
}
/**
* Update (or insert) a IP/MAC address pair in the ARP cache.
*
@ -444,7 +403,7 @@ etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, const
* @param netif netif related to this entry (used for NETIF_ADDRHINT)
* @param ipaddr IP address of the inserted ARP entry.
* @param ethaddr Ethernet address of the inserted ARP entry.
* @param flags @see definition of ETHARP_FLAG_*
* @param flags See @ref etharp_state
*
* @return
* - ERR_OK Successfully updated ARP cache.
@ -518,7 +477,7 @@ etharp_update_arp_entry(struct netif *netif, const ip4_addr_t *ipaddr, struct et
arp_table[i].q = NULL;
#endif /* ARP_QUEUEING */
/* send the queued IP packet */
etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr);
ethernet_output(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr, ETHTYPE_IP);
/* free the queued IP packet */
pbuf_free(p);
}
@ -532,7 +491,7 @@ etharp_update_arp_entry(struct netif *netif, const ip4_addr_t *ipaddr, struct et
*
* @param ipaddr IP address for the new static entry
* @param ethaddr ethernet address for the new static entry
* @return @see return values of etharp_add_static_entry
* @return See return values of etharp_add_static_entry
*/
err_t
etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr)
@ -658,56 +617,6 @@ etharp_get_entry(u8_t i, ip4_addr_t **ipaddr, struct netif **netif, struct eth_a
}
}
#if ETHARP_TRUST_IP_MAC
/**
* Updates the ARP table using the given IP packet.
*
* Uses the incoming IP packet's source address to update the
* ARP cache for the local network. The function does not alter
* or free the packet. This function must be called before the
* packet p is passed to the IP layer.
*
* @param netif The lwIP network interface on which the IP packet pbuf arrived.
* @param p The IP packet that arrived on netif.
*
* @return NULL
*
* @see pbuf_free()
*/
void
etharp_ip_input(struct netif *netif, struct pbuf *p)
{
struct eth_hdr *ethhdr;
struct ip_hdr *iphdr;
ip4_addr_t iphdr_src;
LWIP_ERROR("netif != NULL", (netif != NULL), return;);
/* Only insert an entry if the source IP address of the
incoming IP packet comes from a host on the local network. */
ethhdr = (struct eth_hdr *)p->payload;
iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
#if ETHARP_SUPPORT_VLAN
if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) {
iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
}
#endif /* ETHARP_SUPPORT_VLAN */
ip4_addr_copy(iphdr_src, iphdr->src);
/* source is not on the local network? */
if (!ip4_addr_netcmp(&iphdr_src, netif_ip4_addr(netif), netif_ip4_netmask(netif))) {
/* do nothing */
return;
}
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));
/* update the source IP address in the cache, if present */
/* @todo We could use ETHARP_FLAG_TRY_HARD if we think we are going to talk
* back soon (for example, if the destination IP address is ours. */
etharp_update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY);
}
#endif /* ETHARP_TRUST_IP_MAC */
/**
* Responds to ARP requests to us. Upon ARP replies to us, add entry to cache
* send out queued IP packets. Updates cache with snooped address pairs.
@ -715,47 +624,22 @@ etharp_ip_input(struct netif *netif, struct pbuf *p)
* Should be called for incoming ARP packets. The pbuf in the argument
* is freed by this function.
*
* @param netif The lwIP network interface on which the ARP packet pbuf arrived.
* @param ethaddr Ethernet address of netif.
* @param p The ARP packet that arrived on netif. Is freed by this function.
*
* @return NULL
* @param netif The lwIP network interface on which the ARP packet pbuf arrived.
*
* @see pbuf_free()
*/
void
etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
etharp_input(struct pbuf *p, struct netif *netif)
{
struct etharp_hdr *hdr;
struct eth_hdr *ethhdr;
/* these are aligned properly, whereas the ARP header fields might not be */
ip4_addr_t sipaddr, dipaddr;
u8_t for_us;
#if LWIP_AUTOIP
const u8_t * ethdst_hwaddr;
#endif /* LWIP_AUTOIP */
LWIP_ERROR("netif != NULL", (netif != NULL), return;);
/* drop short ARP packets: we have to check for p->len instead of p->tot_len here
since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */
if (p->len < SIZEOF_ETHARP_PACKET) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len,
(s16_t)SIZEOF_ETHARP_PACKET));
ETHARP_STATS_INC(etharp.lenerr);
ETHARP_STATS_INC(etharp.drop);
pbuf_free(p);
return;
}
ethhdr = (struct eth_hdr *)p->payload;
hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
#if ETHARP_SUPPORT_VLAN
if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) {
hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
}
#endif /* ETHARP_SUPPORT_VLAN */
hdr = (struct etharp_hdr *)p->payload;
/* RFC 826 "Packet Reception": */
if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) ||
@ -763,7 +647,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
(hdr->protolen != sizeof(ip4_addr_t)) ||
(hdr->proto != PP_HTONS(ETHTYPE_IP))) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n",
("etharp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n",
hdr->hwtype, (u16_t)hdr->hwlen, hdr->proto, (u16_t)hdr->protolen));
ETHARP_STATS_INC(etharp.proterr);
ETHARP_STATS_INC(etharp.drop);
@ -808,55 +692,54 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
* reply. In any case, we time-stamp any existing ARP entry,
* and possibly send out an IP packet that was queued on it. */
LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP request\n"));
LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: incoming ARP request\n"));
/* ARP request for our address? */
if (for_us) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n"));
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: replying to ARP request for our IP address\n"));
/* Re-use pbuf to send ARP reply.
Since we are re-using an existing pbuf, we can't call etharp_raw since
that would allocate a new pbuf. */
hdr->opcode = htons(ARP_REPLY);
hdr->opcode = lwip_htons(ARP_REPLY);
IPADDR2_COPY(&hdr->dipaddr, &hdr->sipaddr);
IPADDR2_COPY(&hdr->sipaddr, netif_ip4_addr(netif));
LWIP_ASSERT("netif->hwaddr_len must be the same as ETH_HWADDR_LEN for etharp!",
(netif->hwaddr_len == ETH_HWADDR_LEN));
#if LWIP_AUTOIP
/* If we are using Link-Local, all ARP packets that contain a Link-Local
* 'sender IP address' MUST be sent using link-layer broadcast instead of
* link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */
ethdst_hwaddr = ip4_addr_islinklocal(netif_ip4_addr(netif)) ? (const u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr;
#endif /* LWIP_AUTOIP */
ETHADDR16_COPY(&hdr->dhwaddr, &hdr->shwaddr);
#if LWIP_AUTOIP
ETHADDR16_COPY(&ethhdr->dest, ethdst_hwaddr);
#else /* LWIP_AUTOIP */
ETHADDR16_COPY(&ethhdr->dest, &hdr->shwaddr);
#endif /* LWIP_AUTOIP */
ETHADDR16_COPY(&hdr->shwaddr, ethaddr);
ETHADDR16_COPY(&ethhdr->src, ethaddr);
/* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header
are already correct, we tested that before */
ETHADDR16_COPY(&hdr->dhwaddr, &hdr->shwaddr);
ETHADDR16_COPY(&hdr->shwaddr, netif->hwaddr);
/* return ARP reply */
netif->linkoutput(netif, p);
#if LWIP_AUTOIP
/* If we are using Link-Local, all ARP packets that contain a Link-Local
* 'sender IP address' MUST be sent using link-layer broadcast instead of
* link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */
if (ip4_addr_islinklocal(netif_ip4_addr(netif))) {
ethernet_output(netif, p, &hdr->shwaddr, &ethbroadcast, ETHTYPE_ARP);
} else
#endif /* LWIP_AUTOIP */
{
ethernet_output(netif, p, &hdr->shwaddr, &hdr->dhwaddr, ETHTYPE_ARP);
}
/* we are not configured? */
} else if (ip4_addr_isany_val(*netif_ip4_addr(netif))) {
/* { for_us == 0 and netif->ip_addr.addr == 0 } */
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n"));
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: we are unconfigured, ARP request ignored.\n"));
/* request was not directed to us */
} else {
/* { for_us == 0 and netif->ip_addr.addr != 0 } */
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n"));
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: ARP request was not for us.\n"));
}
break;
case PP_HTONS(ARP_REPLY):
/* ARP reply. We already updated the ARP cache earlier. */
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: incoming ARP reply\n"));
#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
/* DHCP wants to know about ARP replies from any host with an
* IP address also offered to us by the DHCP server. We do not
@ -866,7 +749,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
#endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */
break;
default:
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode)));
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: ARP unknown opcode type %"S16_F"\n", lwip_htons(hdr->opcode)));
ETHARP_STATS_INC(etharp.err);
break;
}
@ -899,8 +782,7 @@ etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx)
}
}
return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr),
&arp_table[arp_idx].ethaddr);
return ethernet_output(netif, q, (struct eth_addr*)(netif->hwaddr), &arp_table[arp_idx].ethaddr, ETHTYPE_IP);
}
/**
@ -919,7 +801,7 @@ etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx)
*
* @return
* - ERR_RTE No route to destination (no gateway to external networks),
* or the return type of either etharp_query() or etharp_send_ip().
* or the return type of either etharp_query() or ethernet_output().
*/
err_t
etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
@ -932,19 +814,6 @@ etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
LWIP_ASSERT("q != NULL", q != NULL);
LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL);
/* make room for Ethernet header - should not fail */
#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET)
if (pbuf_header(q, sizeof(struct eth_hdr) + SIZEOF_VLAN_HDR) != 0) {
#else /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
/* bail out */
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
("etharp_output: could not allocate room for header.\n"));
LINK_STATS_INC(link.lenerr);
return ERR_BUF;
}
/* Determine on destination hardware address. Broadcasts and multicasts
* are special, other IP addresses are looked up in the ARP table. */
@ -971,11 +840,7 @@ etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
if (!ip4_addr_netcmp(ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif)) &&
!ip4_addr_islinklocal(ipaddr)) {
#if LWIP_AUTOIP
struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload +
#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET)
SIZEOF_VLAN_HDR +
#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
sizeof(struct eth_hdr));
struct ip_hdr *iphdr = LWIP_ALIGNMENT_CAST(struct ip_hdr*, q->payload);
/* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with
a link-local source address must always be "directly to its destination
on the same physical link. The host MUST NOT send the packet to any
@ -1009,6 +874,9 @@ etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
if (etharp_cached_entry < ARP_TABLE_SIZE) {
#endif /* LWIP_NETIF_HWADDRHINT */
if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) &&
#if ETHARP_TABLE_MATCH_NETIF
(arp_table[etharp_cached_entry].netif == netif) &&
#endif
(ip4_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) {
/* the per-pcb-cached entry is stable and the right one! */
ETHARP_STATS_INC(etharp.cachehit);
@ -1023,6 +891,9 @@ etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
throughput and etharp_find_entry() is kind of slow */
for (i = 0; i < ARP_TABLE_SIZE; i++) {
if ((arp_table[i].state >= ETHARP_STATE_STABLE) &&
#if ETHARP_TABLE_MATCH_NETIF
(arp_table[i].netif == netif) &&
#endif
(ip4_addr_cmp(dst_addr, &arp_table[i].ipaddr))) {
/* found an existing, stable entry */
ETHARP_SET_HINT(netif, i);
@ -1037,7 +908,7 @@ etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
/* continuation for multicast/broadcast destinations */
/* obtain source Ethernet address of the given interface */
/* send packet directly on the link */
return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest);
return ethernet_output(netif, q, (struct eth_addr*)(netif->hwaddr), dest, ETHTYPE_IP);
}
/**
@ -1137,7 +1008,7 @@ etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q)
/* we have a valid IP->Ethernet address mapping */
ETHARP_SET_HINT(netif, i);
/* send the packet */
result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));
result = ethernet_output(netif, q, srcaddr, &(arp_table[i].ethaddr), ETHTYPE_IP);
/* pending entry? (either just created or already pending */
} else if (arp_table[i].state == ETHARP_STATE_PENDING) {
/* entry is still pending, queue the given packet 'q' */
@ -1157,7 +1028,7 @@ etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q)
}
if (copy_needed) {
/* copy the whole packet into new pbufs */
p = pbuf_alloc(PBUF_RAW_TX, p->tot_len, PBUF_RAM);
p = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
if (p != NULL) {
if (pbuf_copy(p, q) != ERR_OK) {
pbuf_free(p);
@ -1245,10 +1116,7 @@ etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q)
* ERR_MEM if the ARP packet couldn't be allocated
* any other err_t on failure
*/
#if !LWIP_AUTOIP
static
#endif /* LWIP_AUTOIP */
err_t
static 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 ip4_addr_t *ipsrc_addr,
@ -1257,19 +1125,12 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
{
struct pbuf *p;
err_t result = ERR_OK;
struct eth_hdr *ethhdr;
#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET)
struct eth_vlan_hdr *vlanhdr;
#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
struct etharp_hdr *hdr;
#if LWIP_AUTOIP
const u8_t * ethdst_hwaddr;
#endif /* LWIP_AUTOIP */
LWIP_ASSERT("netif != NULL", netif != NULL);
/* allocate a pbuf for the outgoing ARP request packet */
p = pbuf_alloc(PBUF_RAW_TX, SIZEOF_ETHARP_PACKET_TX, PBUF_RAM);
p = pbuf_alloc(PBUF_LINK, SIZEOF_ETHARP_HDR, PBUF_RAM);
/* could allocate a pbuf for an ARP request? */
if (p == NULL) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
@ -1278,26 +1139,15 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
return ERR_MEM;
}
LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr",
(p->len >= SIZEOF_ETHARP_PACKET_TX));
(p->len >= SIZEOF_ETHARP_HDR));
ethhdr = (struct eth_hdr *)p->payload;
#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET)
vlanhdr = (struct eth_vlan_hdr*)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR);
hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
#else /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
hdr = (struct etharp_hdr *)p->payload;
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n"));
hdr->opcode = htons(opcode);
hdr->opcode = lwip_htons(opcode);
LWIP_ASSERT("netif->hwaddr_len must be the same as ETH_HWADDR_LEN for etharp!",
(netif->hwaddr_len == ETH_HWADDR_LEN));
#if LWIP_AUTOIP
/* If we are using Link-Local, all ARP packets that contain a Link-Local
* 'sender IP address' MUST be sent using link-layer broadcast instead of
* link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */
ethdst_hwaddr = ip4_addr_islinklocal(ipsrc_addr) ? (const u8_t*)(ethbroadcast.addr) : ethdst_addr->addr;
#endif /* LWIP_AUTOIP */
/* Write the ARP MAC-Addresses */
ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr);
ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr);
@ -1312,30 +1162,19 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
hdr->hwlen = ETH_HWADDR_LEN;
hdr->protolen = sizeof(ip4_addr_t);
#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET)
ethhdr->type = PP_HTONS(ETHTYPE_VLAN);
vlanhdr->tpid = PP_HTONS(ETHTYPE_ARP);
vlanhdr->prio_vid = 0;
if (!LWIP_HOOK_VLAN_SET(netif, ethhdr, vlanhdr)) {
/* packet shall not contain VLAN header, so hide it and set correct ethertype */
pbuf_header(p, -SIZEOF_VLAN_HDR);
ethhdr = (struct eth_hdr *)p->payload;
#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
ethhdr->type = PP_HTONS(ETHTYPE_ARP);
#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET)
}
#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
/* Write the Ethernet MAC-Addresses */
#if LWIP_AUTOIP
ETHADDR16_COPY(&ethhdr->dest, ethdst_hwaddr);
#else /* LWIP_AUTOIP */
ETHADDR16_COPY(&ethhdr->dest, ethdst_addr);
#endif /* LWIP_AUTOIP */
ETHADDR16_COPY(&ethhdr->src, ethsrc_addr);
/* send ARP query */
result = netif->linkoutput(netif, p);
#if LWIP_AUTOIP
/* If we are using Link-Local, all ARP packets that contain a Link-Local
* 'sender IP address' MUST be sent using link-layer broadcast instead of
* link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */
if(ip4_addr_islinklocal(ipsrc_addr)) {
ethernet_output(netif, p, ethsrc_addr, &ethbroadcast, ETHTYPE_ARP);
} else
#endif /* LWIP_AUTOIP */
{
ethernet_output(netif, p, ethsrc_addr, ethdst_addr, ETHTYPE_ARP);
}
ETHARP_STATS_INC(etharp.xmit);
/* free ARP query packet */
pbuf_free(p);

View File

@ -81,7 +81,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
#endif /* LWIP_DEBUG */
struct icmp_echo_hdr *iecho;
const struct ip_hdr *iphdr_in;
s16_t hlen;
u16_t hlen;
const ip4_addr_t* src;
ICMP_STATS_INC(icmp.recv);
@ -148,7 +148,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
}
#endif
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
if (pbuf_header(p, (hlen + PBUF_LINK_HLEN + PBUF_LINK_ENCAPSULATION_HLEN))) {
if (pbuf_header(p, (s16_t)(hlen + PBUF_LINK_HLEN + PBUF_LINK_ENCAPSULATION_HLEN))) {
/* p is not big enough to contain link headers
* allocate a new one and copy p into it
*/
@ -167,7 +167,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
/* copy the ip header */
MEMCPY(r->payload, iphdr_in, hlen);
/* switch r->payload back to icmp header (cannot fail) */
if (pbuf_header(r, -hlen)) {
if (pbuf_header(r, (s16_t)-hlen)) {
LWIP_ASSERT("icmp_input: moving r->payload to icmp header failed\n", 0);
pbuf_free(r);
goto icmperr;
@ -194,7 +194,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
/* We generate an answer by switching the dest and src ip addresses,
* setting the icmp type to ECHO_RESPONSE and updating the checksum. */
iecho = (struct icmp_echo_hdr *)p->payload;
if (pbuf_header(p, hlen)) {
if (pbuf_header(p, (s16_t)hlen)) {
LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Can't move over header in packet"));
} else {
err_t ret;
@ -236,7 +236,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
MIB2_STATS_INC(mib2.icmpoutechoreps);
/* send an ICMP packet */
ret = ip4_output_if(p, src, IP_HDRINCL,
ret = ip4_output_if(p, src, LWIP_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: %s\n", lwip_strerr(ret)));
@ -247,7 +247,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
if (type == ICMP_DUR) {
MIB2_STATS_INC(mib2.icmpindestunreachs);
} else if (type == ICMP_TE) {
MIB2_STATS_INC(mib2.icmpindestunreachs);
MIB2_STATS_INC(mib2.icmpintimeexcds);
} else if (type == ICMP_PP) {
MIB2_STATS_INC(mib2.icmpinparmprobs);
} else if (type == ICMP_SQ) {

View File

@ -2,6 +2,9 @@
* @file
* IGMP - Internet Group Management Protocol
*
* @defgroup igmp IGMP
* @ingroup ip4
* To be called from TCPIP thread
*/
/*
@ -38,12 +41,6 @@
* source code.
*/
/**
* @defgroup igmp IGMP
* @ingroup ip4
* To be called from TCPIP thread
*/
/*-------------------------------------------------------------
Note 1)
Although the rfc requires V1 AND V2 capability
@ -95,63 +92,21 @@ Steve Reynolds
#include "lwip/inet_chksum.h"
#include "lwip/netif.h"
#include "lwip/stats.h"
#include "lwip/prot/igmp.h"
#include "string.h"
/*
* 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_FLD_8(u8_t igmp_msgtype);
PACK_STRUCT_FLD_8(u8_t igmp_maxresp);
PACK_STRUCT_FIELD(u16_t igmp_checksum);
PACK_STRUCT_FLD_S(ip4_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, const ip4_addr_t *addr);
static err_t igmp_remove_group(struct igmp_group *group);
static void igmp_timeout( struct igmp_group *group);
static err_t igmp_remove_group(struct netif* netif, struct igmp_group *group);
static void igmp_timeout(struct netif *netif, struct igmp_group *group);
static void igmp_start_timer(struct igmp_group *group, u8_t max_time);
static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
static err_t igmp_ip_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif);
static void igmp_send(struct igmp_group *group, u8_t type);
static void igmp_send(struct netif *netif, struct igmp_group *group, u8_t type);
static struct igmp_group* igmp_group_list;
static ip4_addr_t allsystems;
static ip4_addr_t allrouters;
/**
* Initialize the IGMP module
*/
@ -187,7 +142,7 @@ igmp_start(struct netif *netif)
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
ip4_addr_debug_print_val(IGMP_DEBUG, allsystems);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif));
netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);
netif->igmp_mac_filter(netif, &allsystems, NETIF_ADD_MAC_FILTER);
}
return ERR_OK;
@ -204,36 +159,24 @@ igmp_start(struct netif *netif)
err_t
igmp_stop(struct netif *netif)
{
struct igmp_group *group = igmp_group_list;
struct igmp_group *prev = NULL;
struct igmp_group *next;
struct igmp_group *group = netif_igmp_data(netif);
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, NULL);
/* look for groups joined on this interface further down the list */
while (group != NULL) {
next = group->next;
/* is it a group joined on this interface? */
if (group->netif == netif) {
/* is it the first group of the list? */
if (group == igmp_group_list) {
igmp_group_list = next;
}
/* is there a "previous" group defined? */
if (prev != NULL) {
prev->next = next;
}
/* disable the group at the MAC level */
if (netif->igmp_mac_filter != NULL) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
ip4_addr_debug_print(IGMP_DEBUG, &group->group_address);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif));
netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
}
/* free group */
memp_free(MEMP_IGMP_GROUP, group);
} else {
/* change the "previous" */
prev = group;
struct igmp_group *next = group->next; /* avoid use-after-free below */
/* disable the group at the MAC level */
if (netif->igmp_mac_filter != NULL) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
ip4_addr_debug_print(IGMP_DEBUG, &group->group_address);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif));
netif->igmp_mac_filter(netif, &(group->group_address), NETIF_DEL_MAC_FILTER);
}
/* free group */
memp_free(MEMP_IGMP_GROUP, group);
/* move to "next" */
group = next;
}
@ -248,14 +191,17 @@ igmp_stop(struct netif *netif)
void
igmp_report_groups(struct netif *netif)
{
struct igmp_group *group = igmp_group_list;
struct igmp_group *group = netif_igmp_data(netif);
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", (void*)netif));
/* Skip the first group in the list, it is always the allsystems group added in igmp_start() */
if(group != NULL) {
group = group->next;
}
while (group != NULL) {
if ((group->netif == netif) && (!(ip4_addr_cmp(&(group->group_address), &allsystems)))) {
igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
}
igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
group = group->next;
}
}
@ -271,10 +217,10 @@ igmp_report_groups(struct netif *netif)
struct igmp_group *
igmp_lookfor_group(struct netif *ifp, const ip4_addr_t *addr)
{
struct igmp_group *group = igmp_group_list;
struct igmp_group *group = netif_igmp_data(ifp);
while (group != NULL) {
if ((group->netif == ifp) && (ip4_addr_cmp(&(group->group_address), addr))) {
if (ip4_addr_cmp(&(group->group_address), addr)) {
return group;
}
group = group->next;
@ -298,6 +244,7 @@ struct igmp_group *
igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr)
{
struct igmp_group *group;
struct igmp_group *list_head = netif_igmp_data(ifp);
/* Search if the group already exists */
group = igmp_lookfor_group(ifp, addr);
@ -305,19 +252,30 @@ igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr)
/* Group already exists. */
return group;
}
/* Group doesn't exist yet, create a new one */
group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
if (group != NULL) {
group->netif = ifp;
ip4_addr_set(&(group->group_address), addr);
group->timer = 0; /* Not running */
group->group_state = IGMP_GROUP_NON_MEMBER;
group->last_reporter_flag = 0;
group->use = 0;
group->next = igmp_group_list;
igmp_group_list = group;
/* Ensure allsystems group is always first in list */
if (list_head == NULL) {
/* this is the first entry in linked list */
LWIP_ASSERT("igmp_lookup_group: first group must be allsystems",
(ip4_addr_cmp(addr, &allsystems) != 0));
group->next = NULL;
netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, group);
} else {
/* append _after_ first entry */
LWIP_ASSERT("igmp_lookup_group: all except first group must not be allsystems",
(ip4_addr_cmp(addr, &allsystems) == 0));
group->next = list_head->next;
list_head->next = group;
}
}
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
@ -328,35 +286,28 @@ igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr)
}
/**
* Remove a group in the global igmp_group_list
* Remove a group in the global igmp_group_list, but don't free it yet
*
* @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
*/
static err_t
igmp_remove_group(struct igmp_group *group)
igmp_remove_group(struct netif* netif, struct igmp_group *group)
{
err_t err = ERR_OK;
struct igmp_group *tmp_group;
/* Is it the first group? */
if (igmp_group_list == group) {
igmp_group_list = group->next;
} else {
/* look for group further down the list */
struct igmp_group *tmpGroup;
for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
if (tmpGroup->next == group) {
tmpGroup->next = group->next;
break;
}
}
/* Group not found in the global igmp_group_list */
if (tmpGroup == NULL) {
err = ERR_ARG;
/* Skip the first group in the list, it is always the allsystems group added in igmp_start() */
for (tmp_group = netif_igmp_data(netif); tmp_group != NULL; tmp_group = tmp_group->next) {
if (tmp_group->next == group) {
tmp_group->next = group->next;
break;
}
}
/* free group */
memp_free(MEMP_IGMP_GROUP, group);
/* Group not found in the global igmp_group_list */
if (tmp_group == NULL) {
err = ERR_ARG;
}
return err;
}
@ -427,12 +378,16 @@ igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest)
IGMP_STATS_INC(igmp.rx_general);
}
groupref = igmp_group_list;
groupref = netif_igmp_data(inp);
/* Do not send messages on the all systems group address! */
/* Skip the first group in the list, it is always the allsystems group added in igmp_start() */
if(groupref != NULL) {
groupref = groupref->next;
}
while (groupref) {
/* Do not send messages on the all systems group address! */
if ((groupref->netif == inp) && (!(ip4_addr_cmp(&(groupref->group_address), &allsystems)))) {
igmp_delaying_member(groupref, igmp->igmp_maxresp);
}
igmp_delaying_member(groupref, igmp->igmp_maxresp);
groupref = groupref->next;
}
} else {
@ -473,7 +428,7 @@ igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest)
break;
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, (void*)&group, (void*)group->netif));
igmp->igmp_msgtype, group->group_state, (void*)&group, (void*)inp));
IGMP_STATS_INC(igmp.proterr);
break;
}
@ -557,11 +512,11 @@ igmp_joingroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: igmp_mac_filter(ADD "));
ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif));
netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
netif->igmp_mac_filter(netif, groupaddr, NETIF_ADD_MAC_FILTER);
}
IGMP_STATS_INC(igmp.tx_join);
igmp_send(group, IGMP_V2_MEMB_REPORT);
igmp_send(netif, group, IGMP_V2_MEMB_REPORT);
igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
@ -645,11 +600,14 @@ igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
/* If there is no other use of the group */
if (group->use <= 1) {
/* Remove the group from the list */
igmp_remove_group(netif, group);
/* If we are the last reporter for this group */
if (group->last_reporter_flag) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: sending leaving group\n"));
IGMP_STATS_INC(igmp.tx_leave);
igmp_send(group, IGMP_LEAVE_GROUP);
igmp_send(netif, group, IGMP_LEAVE_GROUP);
}
/* Disable the group at the MAC level */
@ -657,15 +615,11 @@ igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: igmp_mac_filter(DEL "));
ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif));
netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
netif->igmp_mac_filter(netif, groupaddr, NETIF_DEL_MAC_FILTER);
}
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: remove group: "));
ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
/* Free the group */
igmp_remove_group(group);
/* Free group struct */
memp_free(MEMP_IGMP_GROUP, group);
} else {
/* Decrement group use */
group->use--;
@ -684,16 +638,21 @@ igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
void
igmp_tmr(void)
{
struct igmp_group *group = igmp_group_list;
struct netif *netif = netif_list;
while (group != NULL) {
if (group->timer > 0) {
group->timer--;
if (group->timer == 0) {
igmp_timeout(group);
while (netif != NULL) {
struct igmp_group *group = netif_igmp_data(netif);
while (group != NULL) {
if (group->timer > 0) {
group->timer--;
if (group->timer == 0) {
igmp_timeout(netif, group);
}
}
group = group->next;
}
group = group->next;
netif = netif->next;
}
}
@ -704,7 +663,7 @@ igmp_tmr(void)
* @param group an igmp_group for which a timeout is reached
*/
static void
igmp_timeout(struct igmp_group *group)
igmp_timeout(struct netif *netif, struct igmp_group *group)
{
/* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group
(unless it is the allsystems group) */
@ -712,10 +671,12 @@ igmp_timeout(struct igmp_group *group)
(!(ip4_addr_cmp(&(group->group_address), &allsystems)))) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
ip4_addr_debug_print(IGMP_DEBUG, &(group->group_address));
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void*)group->netif));
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void*)netif));
group->group_state = IGMP_GROUP_IDLE_MEMBER;
IGMP_STATS_INC(igmp.tx_report);
igmp_send(group, IGMP_V2_MEMB_REPORT);
igmp_send(netif, group, IGMP_V2_MEMB_REPORT);
}
}
@ -765,13 +726,11 @@ igmp_delaying_member(struct igmp_group *group, u8_t maxresp)
* the IP address of the outgoing network interface is filled in as source address.
*
* @param p the packet to send (p->payload points to the data, e.g. next
protocol header; if dest == IP_HDRINCL, p already includes an IP
header and p->payload points to that IP header)
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
protocol header; if dest == LWIP_IP_HDRINCL, p already includes an
IP header and p->payload points to that IP header)
* @param src the source IP address to send from (if src == IP4_ADDR_ANY, the
* IP address of the netif used to send is used as source address)
* @param dest the destination IP address to send the packet to
* @param ttl the TTL value to be set in the IP header
* @param proto the PROTOCOL to be set in the IP header
* @param netif the netif on which to send this packet
* @return ERR_OK if the packet was sent OK
* ERR_BUF if p doesn't have enough space for IP/LINK headers
@ -795,11 +754,11 @@ igmp_ip_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
* @param type the type of igmp packet to send
*/
static void
igmp_send(struct igmp_group *group, u8_t type)
igmp_send(struct netif *netif, struct igmp_group *group, u8_t type)
{
struct pbuf* p = NULL;
struct igmp_msg* igmp = NULL;
ip4_addr_t src = *IP4_ADDR_ANY;
ip4_addr_t src = *IP4_ADDR_ANY4;
ip4_addr_t* dest = NULL;
/* IP header + "router alert" option + IGMP header */
@ -809,7 +768,7 @@ igmp_send(struct igmp_group *group, u8_t type)
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)));
ip4_addr_copy(src, *netif_ip4_addr(group->netif));
ip4_addr_copy(src, *netif_ip4_addr(netif));
if (type == IGMP_V2_MEMB_REPORT) {
dest = &(group->group_address);
@ -828,7 +787,7 @@ igmp_send(struct igmp_group *group, u8_t type)
igmp->igmp_checksum = 0;
igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
igmp_ip_output_if(p, &src, dest, group->netif);
igmp_ip_output_if(p, &src, dest, netif);
}
pbuf_free(p);

View File

@ -53,9 +53,9 @@
#include "lwip/raw.h"
#include "lwip/udp.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/dhcp.h"
#include "lwip/autoip.h"
#include "lwip/stats.h"
#include "lwip/prot/dhcp.h"
#include <string.h>
@ -106,7 +106,9 @@ static u16_t ip_id;
/** The default netif used for multicast */
static struct netif* ip4_default_multicast_netif;
/** Set a default netif for IPv4 multicast. */
/**
* @ingroup ip4
* Set a default netif for IPv4 multicast. */
void
ip4_set_default_multicast_netif(struct netif* default_multicast_netif)
{
@ -175,7 +177,7 @@ ip4_route(const ip4_addr_t *dest)
/* loopif is disabled, looopback traffic is passed through any netif */
if (ip4_addr_isloopback(dest)) {
/* don't check for link on loopback traffic */
if (netif_is_up(netif_default)) {
if (netif_default != NULL && netif_is_up(netif_default)) {
return netif_default;
}
/* default netif is not up, just use any netif for loopback traffic */
@ -220,13 +222,12 @@ ip4_route(const ip4_addr_t *dest)
* that may not be forwarded, or whether datagrams to that destination
* may be forwarded.
* @param p the packet to forward
* @param dest the destination IP address
* @return 1: can forward 0: discard
*/
static int
ip4_canforward(struct pbuf *p)
{
u32_t addr = htonl(ip4_addr_get_u32(ip4_current_dest_addr()));
u32_t addr = lwip_htonl(ip4_addr_get_u32(ip4_current_dest_addr()));
if (p->flags & PBUF_FLAG_LLBCAST) {
/* don't route link-layer broadcasts */
@ -265,6 +266,7 @@ ip4_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
struct netif *netif;
PERF_START;
LWIP_UNUSED_ARG(inp);
if (!ip4_canforward(p)) {
goto return_noroute;
@ -402,7 +404,7 @@ ip4_input(struct pbuf *p, struct netif *inp)
/* calculate IP header length in bytes */
iphdr_hlen *= 4;
/* obtain ip length in bytes */
iphdr_len = ntohs(IPH_LEN(iphdr));
iphdr_len = lwip_ntohs(IPH_LEN(iphdr));
/* Trim pbuf. This is especially required for packets < 60 bytes. */
if (iphdr_len < p->tot_len) {
@ -507,8 +509,7 @@ ip4_input(struct pbuf *p, struct netif *inp)
#if LWIP_AUTOIP
/* connections to link-local addresses must persist after changing
the netif's address (RFC3927 ch. 1.9) */
if ((netif->autoip != NULL) &&
ip4_addr_cmp(ip4_current_dest_addr(), &(netif->autoip->llipaddr))) {
if (autoip_accept_packet(netif, ip4_current_dest_addr())) {
LWIP_DEBUGF(IP_DEBUG, ("ip4_input: LLA packet accepted on interface %c%c\n",
netif->name[0], netif->name[1]));
/* break out of for loop */
@ -517,6 +518,15 @@ ip4_input(struct pbuf *p, struct netif *inp)
#endif /* LWIP_AUTOIP */
}
if (first) {
#if !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF
/* Packets sent to the loopback address must not be accepted on an
* interface that does not have the loopback address assigned to it,
* unless a non-loopback interface is used for loopback traffic. */
if (ip4_addr_isloopback(ip4_current_dest_addr())) {
netif = NULL;
break;
}
#endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */
first = 0;
netif = netif_list;
} else {
@ -543,7 +553,7 @@ ip4_input(struct pbuf *p, struct netif *inp)
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, ("ip4_input: UDP packet to DHCP client port %"U16_F"\n",
ntohs(udphdr->dest)));
lwip_ntohs(udphdr->dest)));
if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: DHCP packet accepted.\n"));
netif = inp;
@ -588,6 +598,7 @@ ip4_input(struct pbuf *p, struct netif *inp)
} else
#endif /* IP_FORWARD */
{
IP_STATS_INC(ip.drop);
MIB2_STATS_INC(mib2.ipinaddrerrors);
MIB2_STATS_INC(mib2.ipindiscards);
}
@ -598,7 +609,7 @@ ip4_input(struct pbuf *p, struct netif *inp)
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 ip4_reass()\n",
ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), (u16_t)!!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (u16_t)((ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)));
lwip_ntohs(IPH_ID(iphdr)), p->tot_len, lwip_ntohs(IPH_LEN(iphdr)), (u16_t)!!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (u16_t)((lwip_ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)));
/* reassemble the packet*/
p = ip4_reass(p);
/* packet not fully reassembled yet? */
@ -609,7 +620,7 @@ ip4_input(struct pbuf *p, struct netif *inp)
#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",
ntohs(IPH_OFFSET(iphdr))));
lwip_ntohs(IPH_OFFSET(iphdr))));
IP_STATS_INC(ip.opterr);
IP_STATS_INC(ip.drop);
/* unsupported protocol feature */
@ -716,13 +727,13 @@ ip4_input(struct pbuf *p, struct netif *inp)
* the IP header and calculates the IP header checksum. If the source
* IP address is NULL, the IP address of the outgoing network
* interface is filled in as source address.
* If the destination IP address is IP_HDRINCL, p is assumed to already
* If the destination IP address is LWIP_IP_HDRINCL, p is assumed to already
* include an IP header and p->payload points to it instead of the data.
*
* @param p the packet to send (p->payload points to the data, e.g. next
protocol header; if dest == IP_HDRINCL, p already includes an IP
header and p->payload points to that IP header)
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
protocol header; if dest == LWIP_IP_HDRINCL, p already includes an
IP header and p->payload points to that IP header)
* @param src the source IP address to send from (if src == IP4_ADDR_ANY, the
* IP address of the netif used to send is used as source address)
* @param dest the destination IP address to send the packet to
* @param ttl the TTL value to be set in the IP header
@ -758,7 +769,7 @@ ip4_output_if_opt(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
{
#endif /* IP_OPTIONS_SEND */
const ip4_addr_t *src_used = src;
if (dest != IP_HDRINCL) {
if (dest != LWIP_IP_HDRINCL) {
if (ip4_addr_isany(src)) {
src_used = netif_ip4_addr(netif);
}
@ -806,7 +817,7 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d
MIB2_STATS_INC(mib2.ipoutrequests);
/* Should the IP header be generated or is it already included in p? */
if (dest != IP_HDRINCL) {
if (dest != LWIP_IP_HDRINCL) {
u16_t ip_hlen = IP_HLEN;
#if IP_OPTIONS_SEND
u16_t optlen_aligned = 0;
@ -852,7 +863,7 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d
IPH_TTL_SET(iphdr, ttl);
IPH_PROTO_SET(iphdr, proto);
#if CHECKSUM_GEN_IP_INLINE
chk_sum += LWIP_MAKE_U16(proto, ttl);
chk_sum += PP_NTOHS(proto | (ttl << 8));
#endif /* CHECKSUM_GEN_IP_INLINE */
/* dest cannot be NULL here */
@ -865,21 +876,21 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d
IPH_VHL_SET(iphdr, 4, ip_hlen / 4);
IPH_TOS_SET(iphdr, tos);
#if CHECKSUM_GEN_IP_INLINE
chk_sum += LWIP_MAKE_U16(tos, iphdr->_v_hl);
chk_sum += PP_NTOHS(tos | (iphdr->_v_hl << 8));
#endif /* CHECKSUM_GEN_IP_INLINE */
IPH_LEN_SET(iphdr, htons(p->tot_len));
IPH_LEN_SET(iphdr, lwip_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));
IPH_ID_SET(iphdr, lwip_htons(ip_id));
#if CHECKSUM_GEN_IP_INLINE
chk_sum += iphdr->_id;
#endif /* CHECKSUM_GEN_IP_INLINE */
++ip_id;
if (src == NULL) {
ip4_addr_copy(iphdr->src, *IP4_ADDR_ANY);
ip4_addr_copy(iphdr->src, *IP4_ADDR_ANY4);
} else {
/* src cannot be NULL here */
ip4_addr_copy(iphdr->src, *src);
@ -951,9 +962,9 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d
* interface and calls upon ip_output_if to do the actual work.
*
* @param p the packet to send (p->payload points to the data, e.g. next
protocol header; if dest == IP_HDRINCL, p already includes an IP
header and p->payload points to that IP header)
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
protocol header; if dest == LWIP_IP_HDRINCL, p already includes an
IP header and p->payload points to that IP header)
* @param src the source IP address to send from (if src == IP4_ADDR_ANY, the
* IP address of the netif used to send is used as source address)
* @param dest the destination IP address to send the packet to
* @param ttl the TTL value to be set in the IP header
@ -986,9 +997,9 @@ ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
* before calling ip_output_if.
*
* @param p the packet to send (p->payload points to the data, e.g. next
protocol header; if dest == IP_HDRINCL, p already includes an IP
header and p->payload points to that IP header)
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
protocol header; if dest == LWIP_IP_HDRINCL, p already includes an
IP header and p->payload points to that IP header)
* @param src the source IP address to send from (if src == IP4_ADDR_ANY, the
* IP address of the netif used to send is used as source address)
* @param dest the destination IP address to send the packet to
* @param ttl the TTL value to be set in the IP header
@ -1039,19 +1050,19 @@ ip4_debug_print(struct pbuf *p)
(u16_t)IPH_V(iphdr),
(u16_t)IPH_HL(iphdr),
(u16_t)IPH_TOS(iphdr),
ntohs(IPH_LEN(iphdr))));
lwip_ntohs(IPH_LEN(iphdr))));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n",
ntohs(IPH_ID(iphdr)),
(u16_t)(ntohs(IPH_OFFSET(iphdr)) >> 15 & 1),
(u16_t)(ntohs(IPH_OFFSET(iphdr)) >> 14 & 1),
(u16_t)(ntohs(IPH_OFFSET(iphdr)) >> 13 & 1),
(u16_t)(ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)));
lwip_ntohs(IPH_ID(iphdr)),
(u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) >> 15 & 1),
(u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) >> 14 & 1),
(u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) >> 13 & 1),
(u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n",
(u16_t)IPH_TTL(iphdr),
(u16_t)IPH_PROTO(iphdr),
ntohs(IPH_CHKSUM(iphdr))));
lwip_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_16(&iphdr->src),

View File

@ -43,7 +43,7 @@
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
/* used by IP4_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
const ip_addr_t ip_addr_any = IPADDR4_INIT(IPADDR_ANY);
const ip_addr_t ip_addr_broadcast = IPADDR4_INIT(IPADDR_BROADCAST);
@ -183,10 +183,10 @@ ip4addr_aton(const char *cp, ip4_addr_t *addr)
}
for (;;) {
if (isdigit(c)) {
val = (val * base) + (int)(c - '0');
val = (val * base) + (u32_t)(c - '0');
c = *++cp;
} else if (base == 16 && isxdigit(c)) {
val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));
val = (val << 4) | (u32_t)(c + 10 - (islower(c) ? 'a' : 'A'));
c = *++cp;
} else {
break;
@ -260,7 +260,7 @@ ip4addr_aton(const char *cp, ip4_addr_t *addr)
break;
}
if (addr) {
ip4_addr_set_u32(addr, htonl(val));
ip4_addr_set_u32(addr, lwip_htonl(val));
}
return 1;
}
@ -310,7 +310,7 @@ ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen)
do {
rem = *ap % (u8_t)10;
*ap /= (u8_t)10;
inv[i++] = '0' + rem;
inv[i++] = (char)('0' + rem);
} while (*ap);
while (i--) {
if (len++ >= buflen) {

View File

@ -160,7 +160,7 @@ static int
ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
{
u16_t pbufs_freed = 0;
u8_t clen;
u16_t clen;
struct pbuf *p;
struct ip_reass_helper *iprh;
@ -331,7 +331,7 @@ ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
* will grow over time as new pbufs are rx.
* Also checks that the datagram passes basic continuity checks (if the last
* fragment was received at least once).
* @param root_p points to the 'root' pbuf for the current datagram being assembled.
* @param ipr points to the reassembly state
* @param new_p points to the pbuf for the current fragment
* @return 0 if invalid, >0 otherwise
*/
@ -340,14 +340,14 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct
{
struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
struct pbuf *q;
u16_t offset,len;
u16_t offset, len;
struct ip_hdr *fraghdr;
int valid = 1;
/* Extract length and fragment offset from current fragment */
fraghdr = (struct ip_hdr*)new_p->payload;
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
len = lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
offset = (lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
/* overwrite the fragment's ip header from the pbuf with our helper struct,
* and setup the embedded helper structure. */
@ -487,8 +487,7 @@ ip4_reass(struct pbuf *p)
struct ip_hdr *fraghdr;
struct ip_reassdata *ipr;
struct ip_reass_helper *iprh;
u16_t offset, len;
u8_t clen;
u16_t offset, len, clen;
IPFRAG_STATS_INC(ip_frag.recv);
MIB2_STATS_INC(mib2.ipreasmreqds);
@ -501,8 +500,8 @@ ip4_reass(struct pbuf *p)
goto nullreturn;
}
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
offset = (lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
len = lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
/* Check if we are allowed to enqueue more datagrams. */
clen = pbuf_clen(p);
@ -530,7 +529,7 @@ ip4_reass(struct pbuf *p)
fragment into the buffer. */
if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip4_reass: matching previous fragment ID=%"X16_F"\n",
ntohs(IPH_ID(fraghdr))));
lwip_ntohs(IPH_ID(fraghdr))));
IPFRAG_STATS_INC(ip_frag.cachehit);
break;
}
@ -544,8 +543,8 @@ ip4_reass(struct pbuf *p)
goto nullreturn;
}
} else {
if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
if (((lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
((lwip_ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
/* ipr->iphdr is not the header from the first fragment, but fraghdr is
* -> copy fraghdr into ipr->iphdr since we want to have the header
* of the first fragment (for ICMP time exceeded and later, for copying
@ -582,7 +581,7 @@ ip4_reass(struct pbuf *p)
/* copy the original ip header back to the first pbuf */
fraghdr = (struct ip_hdr*)(ipr->p->payload);
SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));
IPH_LEN_SET(fraghdr, lwip_htons(ipr->datagram_len));
IPH_OFFSET_SET(fraghdr, 0);
IPH_CHKSUM_SET(fraghdr, 0);
/* @todo: do we need to set/calculate the correct checksum? */
@ -639,10 +638,6 @@ nullreturn:
#endif /* IP_REASSEMBLY */
#if IP_FRAG
#if IP_FRAG_USES_STATIC_BUF
static LWIP_DECLARE_MEMORY_ALIGNED(buf, IP_FRAG_MAX_MTU);
#else /* IP_FRAG_USES_STATIC_BUF */
#if !LWIP_NETIF_TX_SINGLE_PBUF
/** Allocate a new struct pbuf_custom_ref */
static struct pbuf_custom_ref*
@ -673,14 +668,12 @@ ipfrag_free_pbuf_custom(struct pbuf *p)
ip_frag_free_pbuf_custom_ref(pcr);
}
#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
#endif /* IP_FRAG_USES_STATIC_BUF */
/**
* Fragment an IP datagram if too large for the netif.
*
* Chop the datagram in MTU sized chunks and send them in order
* by using a fixed size static memory buffer (PBUF_REF) or
* point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).
* by pointing PBUF_REFs into p.
*
* @param p ip packet to send
* @param netif the netif on which to send
@ -692,81 +685,43 @@ err_t
ip4_frag(struct pbuf *p, struct netif *netif, const ip4_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;
u16_t nfb;
u16_t left, cop;
u16_t mtu = netif->mtu;
u16_t ofo, omf;
u16_t last;
u16_t poff = IP_HLEN;
u16_t tmp;
#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
u16_t newpbuflen = 0;
u16_t left_to_copy;
#endif
struct ip_hdr *original_iphdr;
struct ip_hdr *iphdr;
const u16_t nfb = (netif->mtu - IP_HLEN) / 8;
u16_t left, fragsize;
u16_t ofo;
int last;
u16_t poff = IP_HLEN;
u16_t tmp;
/* Get a RAM based MTU sized pbuf */
#if IP_FRAG_USES_STATIC_BUF
/* When using a static buffer, we use a PBUF_REF, which we will
* use to reference the packet (without link header).
* Layer and length is irrelevant.
*/
rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
if (rambuf == NULL) {
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));
goto memerr;
}
rambuf->tot_len = rambuf->len = mtu;
rambuf->payload = LWIP_MEM_ALIGN((void *)buf);
/* Copy the IP header in it */
iphdr = (struct ip_hdr *)rambuf->payload;
SMEMCPY(iphdr, p->payload, IP_HLEN);
#else /* IP_FRAG_USES_STATIC_BUF */
original_iphdr = (struct ip_hdr *)p->payload;
iphdr = original_iphdr;
#endif /* IP_FRAG_USES_STATIC_BUF */
LWIP_ERROR("ip4_frag() does not support IP options", IPH_HL(iphdr) * 4 == IP_HLEN, return ERR_VAL);
/* Save original offset */
tmp = ntohs(IPH_OFFSET(iphdr));
tmp = lwip_ntohs(IPH_OFFSET(iphdr));
ofo = tmp & IP_OFFMASK;
omf = tmp & IP_MF;
LWIP_ERROR("ip_frag(): MF already set", (tmp & IP_MF) == 0, return ERR_VAL);
left = p->tot_len - IP_HLEN;
nfb = (mtu - IP_HLEN) / 8;
while (left) {
last = (left <= mtu - IP_HLEN);
/* Set new offset and MF flag */
tmp = omf | (IP_OFFMASK & (ofo));
if (!last) {
tmp = tmp | IP_MF;
}
/* Fill this fragment */
cop = last ? left : nfb * 8;
fragsize = LWIP_MIN(left, nfb * 8);
#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);
rambuf = pbuf_alloc(PBUF_IP, fragsize, PBUF_RAM);
if (rambuf == NULL) {
goto memerr;
}
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);
poff += pbuf_copy_partial(p, rambuf->payload, fragsize, poff);
/* make room for the IP header */
if (pbuf_header(rambuf, IP_HLEN)) {
pbuf_free(rambuf);
@ -790,16 +745,14 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
iphdr = (struct ip_hdr *)rambuf->payload;
/* Can just adjust p directly for needed offset. */
p->payload = (u8_t *)p->payload + poff;
p->len -= poff;
left_to_copy = cop;
left_to_copy = fragsize;
while (left_to_copy) {
struct pbuf_custom_ref *pcr;
newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
u16_t plen = p->len - poff;
newpbuflen = LWIP_MIN(left_to_copy, plen);
/* Is this pbuf already empty? */
if (!newpbuflen) {
poff = 0;
p = p->next;
continue;
}
@ -809,7 +762,8 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
goto memerr;
}
/* Mirror this pbuf, although we might not need all of it. */
newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc,
(u8_t*)p->payload + poff, newpbuflen);
if (newpbuf == NULL) {
ip_frag_free_pbuf_custom_ref(pcr);
pbuf_free(rambuf);
@ -825,16 +779,23 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
pbuf_cat(rambuf, newpbuf);
left_to_copy -= newpbuflen;
if (left_to_copy) {
poff = 0;
p = p->next;
}
}
poff = newpbuflen;
poff += newpbuflen;
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
#endif /* IP_FRAG_USES_STATIC_BUF */
/* Correct header */
IPH_OFFSET_SET(iphdr, htons(tmp));
IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
last = (left <= netif->mtu - IP_HLEN);
/* Set new offset and MF flag */
tmp = (IP_OFFMASK & (ofo));
if (!last) {
tmp = tmp | IP_MF;
}
IPH_OFFSET_SET(iphdr, lwip_htons(tmp));
IPH_LEN_SET(iphdr, lwip_htons(fragsize + IP_HLEN));
IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) {
@ -842,29 +803,6 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
}
#endif /* CHECKSUM_GEN_IP */
#if IP_FRAG_USES_STATIC_BUF
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
* free it. A PBUF_ROM style pbuf for which pbuf_header
* worked would make things simpler.
*/
header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
if (header != NULL) {
pbuf_chain(header, rambuf);
netif->output(netif, header, dest);
IPFRAG_STATS_INC(ip_frag.xmit);
MIB2_STATS_INC(mib2.ipfragcreates);
pbuf_free(header);
} else {
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));
pbuf_free(rambuf);
goto memerr;
}
#else /* IP_FRAG_USES_STATIC_BUF */
/* No need for separate header pbuf - we allowed room for it in rambuf
* when allocated.
*/
@ -879,13 +817,9 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
*/
pbuf_free(rambuf);
#endif /* IP_FRAG_USES_STATIC_BUF */
left -= cop;
left -= fragsize;
ofo += nfb;
}
#if IP_FRAG_USES_STATIC_BUF
pbuf_free(rambuf);
#endif /* IP_FRAG_USES_STATIC_BUF */
MIB2_STATS_INC(mib2.ipfragoks);
return ERR_OK;
memerr:

View File

@ -1 +0,0 @@
IPv6 support in lwIP is very experimental.

View File

@ -51,42 +51,20 @@
#include "lwip/inet_chksum.h"
#include "lwip/netif.h"
#include "lwip/icmp6.h"
#include "lwip/prot/lwip_ethernet.h"
#include "netif/lwip_ethernet.h"
#include <string.h>
/**
* Send an IPv6 packet on the network using netif->linkoutput
* The ethernet header is filled in before sending.
*
* @params netif the lwIP network interface on which to send the packet
* @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header
* @params src the source MAC address to be copied into the ethernet header
* @params dst the destination MAC address to be copied into the ethernet header
* @return ERR_OK if the packet was sent, any other err_t on failure
*/
static err_t
ethip6_send(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst)
{
struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload;
LWIP_ASSERT("netif->hwaddr_len must be 6 for ethip6!",
(netif->hwaddr_len == 6));
SMEMCPY(&ethhdr->dest, dst, 6);
SMEMCPY(&ethhdr->src, src, 6);
ethhdr->type = PP_HTONS(ETHTYPE_IPV6);
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethip6_send: sending packet %p\n", (void *)p));
/* send the packet */
return netif->linkoutput(netif, p);
}
/**
* Resolve and fill-in Ethernet address header for outgoing IPv6 packet.
*
* For IPv6 multicast, corresponding Ethernet addresses
* are selected and the packet is transmitted on the link.
*
* For unicast addresses, ...
* For unicast addresses, ask the ND6 module what to do. It will either let us
* send the the packet right away, or queue the packet for later itself, unless
* an error occurs.
*
* @todo anycast addresses
*
@ -95,22 +73,14 @@ ethip6_send(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct et
* @param ip6addr The IP address of the packet destination.
*
* @return
* - ERR_RTE No route to destination (no gateway to external networks),
* or the return type of either etharp_query() or etharp_send_ip().
* - ERR_OK or the return value of @ref nd6_get_next_hop_addr_or_queue.
*/
err_t
ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr)
{
struct eth_addr dest;
s8_t i;
/* make room for Ethernet header - should not fail */
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
/* bail out */
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
("etharp_output: could not allocate room for header.\n"));
return ERR_BUF;
}
const u8_t *hwaddr;
err_t result;
/* multicast destination IP address? */
if (ip6_addr_ismulticast(ip6addr)) {
@ -123,37 +93,26 @@ ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr)
dest.addr[5] = ((const u8_t *)(&(ip6addr->addr[3])))[3];
/* Send out. */
return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest);
return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6);
}
/* We have a unicast destination IP address */
/* @todo anycast? */
/* Get next hop record. */
i = nd6_get_next_hop_entry(ip6addr, netif);
if (i < 0) {
/* failed to get a next hop neighbor record. */
return ERR_MEM;
/* Ask ND6 what to do with the packet. */
result = nd6_get_next_hop_addr_or_queue(netif, q, ip6addr, &hwaddr);
if (result != ERR_OK) {
return result;
}
/* Now that we have a destination record, send or queue the packet. */
if (neighbor_cache[i].state == ND6_STALE) {
/* Switch to delay state. */
neighbor_cache[i].state = ND6_DELAY;
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME;
}
/* @todo should we send or queue if PROBE? send for now, to let unicast NS pass. */
if ((neighbor_cache[i].state == ND6_REACHABLE) ||
(neighbor_cache[i].state == ND6_DELAY) ||
(neighbor_cache[i].state == ND6_PROBE)) {
/* Send out. */
SMEMCPY(dest.addr, neighbor_cache[i].lladdr, 6);
return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest);
/* If no hardware address is returned, nd6 has queued the packet for later. */
if (hwaddr == NULL) {
return ERR_OK;
}
/* We should queue packet on this interface. */
pbuf_header(q, -(s16_t)SIZEOF_ETH_HDR);
return nd6_queue_packet(i, q);
/* Send out the packet using the returned hardware address. */
SMEMCPY(dest.addr, hwaddr, 6);
return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6);
}
#endif /* LWIP_IPV6 && LWIP_ETHERNET */

View File

@ -44,6 +44,7 @@
#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/icmp6.h"
#include "lwip/prot/icmp6.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/inet_chksum.h"
@ -80,8 +81,8 @@ void
icmp6_input(struct pbuf *p, struct netif *inp)
{
struct icmp6_hdr *icmp6hdr;
struct pbuf * r;
const ip6_addr_t * reply_src;
struct pbuf *r;
const ip6_addr_t *reply_src;
ICMP6_STATS_INC(icmp6.recv);

View File

@ -46,6 +46,7 @@
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/ip6_frag.h"
@ -93,7 +94,8 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
if (ip6_addr_islinklocal(dest)) {
if (ip6_addr_isany(src)) {
/* Use default netif, if Up. */
if (!netif_is_up(netif_default) || !netif_is_link_up(netif_default)) {
if (netif_default == NULL || !netif_is_up(netif_default) ||
!netif_is_link_up(netif_default)) {
return NULL;
}
return netif_default;
@ -113,7 +115,8 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
}
/* netif not found, use default netif, if up */
if (!netif_is_up(netif_default) || !netif_is_link_up(netif_default)) {
if (netif_default == NULL || !netif_is_up(netif_default) ||
!netif_is_link_up(netif_default)) {
return NULL;
}
return netif_default;
@ -141,15 +144,9 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
}
/* Get the netif for a suitable router. */
i = nd6_select_router(dest, NULL);
if (i >= 0) {
if (default_router_list[i].neighbor_entry != NULL) {
if (default_router_list[i].neighbor_entry->netif != NULL) {
if (netif_is_up(default_router_list[i].neighbor_entry->netif) && netif_is_link_up(default_router_list[i].neighbor_entry->netif)) {
return default_router_list[i].neighbor_entry->netif;
}
}
}
netif = nd6_find_route(dest);
if ((netif != NULL) && netif_is_up(netif) && netif_is_link_up(netif)) {
return netif;
}
/* try with the netif that matches the source address. */
@ -171,7 +168,7 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
/* loopif is disabled, loopback traffic is passed through any netif */
if (ip6_addr_isloopback(dest)) {
/* don't check for link on loopback traffic */
if (netif_is_up(netif_default)) {
if (netif_default != NULL && netif_is_up(netif_default)) {
return netif_default;
}
/* default netif is not up, just use any netif for loopback traffic */
@ -192,6 +189,7 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
}
/**
* @ingroup ip6
* Select the best IPv6 source address for a given destination
* IPv6 address. Loosely follows RFC 3484. "Strong host" behavior
* is assumed.
@ -202,7 +200,7 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
* source address is found
*/
const ip_addr_t *
ip6_select_source_address(struct netif *netif, const ip6_addr_t * dest)
ip6_select_source_address(struct netif *netif, const ip6_addr_t *dest)
{
const ip_addr_t *src = NULL;
u8_t i;
@ -288,8 +286,9 @@ ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp)
{
struct netif *netif;
/* do not forward link-local addresses */
if (ip6_addr_islinklocal(ip6_current_dest_addr())) {
/* do not forward link-local or loopback addresses */
if (ip6_addr_islinklocal(ip6_current_dest_addr()) ||
ip6_addr_isloopback(ip6_current_dest_addr())) {
LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n"));
IP6_STATS_INC(ip6.rterr);
IP6_STATS_INC(ip6.drop);
@ -451,7 +450,7 @@ ip6_input(struct pbuf *p, struct netif *inp)
IP6_STATS_INC(ip6.drop);
return ERR_OK;
}
/* current header pointer. */
ip_data.current_ip6_header = ip6hdr;
@ -507,12 +506,21 @@ ip6_input(struct pbuf *p, struct netif *inp)
}
}
}
if (ip6_addr_islinklocal(ip6_current_dest_addr())) {
/* Do not match link-local addresses to other netifs. */
netif = NULL;
break;
}
if (first) {
if (ip6_addr_islinklocal(ip6_current_dest_addr())
#if !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF
|| ip6_addr_isloopback(ip6_current_dest_addr())
#endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */
) {
/* Do not match link-local addresses to other netifs. The loopback
* address is to be considered link-local and packets to it should be
* dropped on other interfaces, as per RFC 4291 Sec. 2.5.3. This
* requirement cannot be implemented in the case that loopback
* traffic is sent across a non-loopback interface, however.
*/
netif = NULL;
break;
}
first = 0;
netif = netif_list;
} else {
@ -641,7 +649,7 @@ netif_found:
case IP6_NEXTH_FRAGMENT:
{
struct ip6_frag_hdr * frag_hdr;
struct ip6_frag_hdr *frag_hdr;
LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header\n"));
frag_hdr = (struct ip6_frag_hdr *)p->payload;
@ -707,7 +715,7 @@ netif_found:
options_done:
/* p points to IPv6 header again. */
pbuf_header_force(p, ip_data.current_ip_header_tot_len);
pbuf_header_force(p, (s16_t)ip_data.current_ip_header_tot_len);
/* send to upper layers */
LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n"));
@ -781,11 +789,11 @@ ip6_input_cleanup:
* used as source (usually during network startup). If the source IPv6 address it
* IP6_ADDR_ANY, the most appropriate IPv6 address of the outgoing network
* interface is filled in as source address. If the destination IPv6 address is
* IP_HDRINCL, p is assumed to already include an IPv6 header and p->payload points
* to it instead of the data.
* LWIP_IP_HDRINCL, p is assumed to already include an IPv6 header and
* p->payload points to it instead of the data.
*
* @param p the packet to send (p->payload points to the data, e.g. next
protocol header; if dest == IP_HDRINCL, p already includes an
protocol header; if dest == LWIP_IP_HDRINCL, p already includes an
IPv6 header and p->payload points to that IPv6 header)
* @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an
* IP address of the netif is selected and used as source address.
@ -805,7 +813,7 @@ ip6_output_if(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
u8_t nexth, struct netif *netif)
{
const ip6_addr_t *src_used = src;
if (dest != IP_HDRINCL) {
if (dest != LWIP_IP_HDRINCL) {
if (src != NULL && ip6_addr_isany(src)) {
src = ip_2_ip6(ip6_select_source_address(netif, dest));
if ((src == NULL) || ip6_addr_isany(src)) {
@ -834,7 +842,7 @@ ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);
/* Should the IPv6 header be generated or is it already included in p? */
if (dest != IP_HDRINCL) {
if (dest != LWIP_IP_HDRINCL) {
/* generate IPv6 header */
if (pbuf_header(p, IP6_HLEN)) {
LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: not enough room for IPv6 header in pbuf\n"));
@ -907,7 +915,7 @@ ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
* interface and calls upon ip6_output_if to do the actual work.
*
* @param p the packet to send (p->payload points to the data, e.g. next
protocol header; if dest == IP_HDRINCL, p already includes an
protocol header; if dest == LWIP_IP_HDRINCL, p already includes an
IPv6 header and p->payload points to that IPv6 header)
* @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an
* IP address of the netif is selected and used as source address.
@ -930,7 +938,7 @@ ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);
if (dest != IP_HDRINCL) {
if (dest != LWIP_IP_HDRINCL) {
netif = ip6_route(src, dest);
} else {
/* IP header included in p, read addresses. */
@ -963,7 +971,7 @@ ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
* before calling ip6_output_if.
*
* @param p the packet to send (p->payload points to the data, e.g. next
protocol header; if dest == IP_HDRINCL, p already includes an
protocol header; if dest == LWIP_IP_HDRINCL, p already includes an
IPv6 header and p->payload points to that IPv6 header)
* @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an
* IP address of the netif is selected and used as source address.
@ -989,7 +997,7 @@ ip6_output_hinted(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);
if (dest != IP_HDRINCL) {
if (dest != LWIP_IP_HDRINCL) {
netif = ip6_route(src, dest);
} else {
/* IP header included in p, read addresses. */
@ -1033,9 +1041,9 @@ ip6_output_hinted(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
* @return ERR_OK if hop-by-hop header was added, ERR_* otherwise
*/
err_t
ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value)
ip6_options_add_hbh_ra(struct pbuf *p, u8_t nexth, u8_t value)
{
struct ip6_hbh_hdr * hbh_hdr;
struct ip6_hbh_hdr *hbh_hdr;
/* Move pointer to make room for hop-by-hop options header. */
if (pbuf_header(p, sizeof(struct ip6_hbh_hdr))) {

View File

@ -73,7 +73,7 @@ int
ip6addr_aton(const char *cp, ip6_addr_t *addr)
{
u32_t addr_index, zero_blocks, current_block_index, current_block_value;
const char * s;
const char *s;
/* Count the number of colons, to count the number of blocks in a "::" sequence
zero_blocks may be 1 even if there are no :: sequences */
@ -132,8 +132,8 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr)
} else if (isxdigit(*s)) {
/* add current digit */
current_block_value = (current_block_value << 4) +
(isdigit(*s) ? *s - '0' :
10 + (islower(*s) ? *s - 'a' : *s - 'A'));
(isdigit(*s) ? (u32_t)(*s - '0') :
(u32_t)(10 + (islower(*s) ? *s - 'a' : *s - 'A')));
} else {
/* unexpected digit, space? CRLF? */
break;
@ -152,7 +152,7 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr)
/* convert to network byte order. */
if (addr) {
for (addr_index = 0; addr_index < 4; addr_index++) {
addr->addr[addr_index] = htonl(addr->addr[addr_index]);
addr->addr[addr_index] = lwip_htonl(addr->addr[addr_index]);
}
}
@ -199,7 +199,7 @@ ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen)
for (current_block_index = 0; current_block_index < 8; current_block_index++) {
/* get the current 16-bit block */
current_block_value = htonl(addr->addr[current_block_index >> 1]);
current_block_value = lwip_htonl(addr->addr[current_block_index >> 1]);
if ((current_block_index & 0x1) == 0) {
current_block_value = current_block_value >> 16;
}
@ -218,7 +218,7 @@ ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen)
if (empty_block_flag == 0) {
/* generate empty block "::", but only if more than one contiguous zero block,
* according to current formatting suggestions RFC 5952. */
next_block_value = htonl(addr->addr[(current_block_index + 1) >> 1]);
next_block_value = lwip_htonl(addr->addr[(current_block_index + 1) >> 1]);
if ((current_block_index & 0x1) == 0x01) {
next_block_value = next_block_value >> 16;
}

View File

@ -147,7 +147,7 @@ ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr)
{
struct ip6_reassdata *prev;
u16_t pbufs_freed = 0;
u8_t clen;
u16_t clen;
struct pbuf *p;
struct ip6_reass_helper *iprh;
@ -260,9 +260,10 @@ ip6_reass(struct pbuf *p)
{
struct ip6_reassdata *ipr, *ipr_prev;
struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
struct ip6_frag_hdr * frag_hdr;
struct ip6_frag_hdr *frag_hdr;
u16_t offset, len;
u8_t clen, valid = 1;
u16_t clen;
u8_t valid = 1;
struct pbuf *q;
IP6_FRAG_STATS_INC(ip6_frag.recv);
@ -278,12 +279,12 @@ ip6_reass(struct pbuf *p)
clen = pbuf_clen(p);
offset = ntohs(frag_hdr->_fragment_offset);
offset = lwip_ntohs(frag_hdr->_fragment_offset);
/* Calculate fragment length from IPv6 payload length.
* Adjust for headers before Fragment Header.
* And finally adjust by Fragment Header length. */
len = ntohs(ip6_current_header()->_plen);
len = lwip_ntohs(ip6_current_header()->_plen);
len -= (u16_t)(((u8_t*)p->payload - (const u8_t*)ip6_current_header()) - IP6_HLEN);
len -= IP6_FRAG_HLEN;
@ -377,8 +378,9 @@ ip6_reass(struct pbuf *p)
if (IPV6_FRAG_REQROOM > 0) {
/* Make room for struct ip6_reass_helper (only required if sizeof(void*) > 4).
This cannot fail since we already checked when receiving this fragment. */
err_t hdrerr = pbuf_header_force(p, IPV6_FRAG_REQROOM);
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == ERR_OK);
u8_t hdrerr = pbuf_header_force(p, IPV6_FRAG_REQROOM);
LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0);
}
#else /* IPV6_FRAG_COPYHEADER */
LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1",
@ -528,8 +530,9 @@ ip6_reass(struct pbuf *p)
#if IPV6_FRAG_COPYHEADER
if (IPV6_FRAG_REQROOM > 0) {
/* hide the extra bytes borrowed from ip6_hdr for struct ip6_reass_helper */
err_t hdrerr = pbuf_header(next_pbuf, -(s16_t)(IPV6_FRAG_REQROOM));
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == ERR_OK);
u8_t hdrerr = pbuf_header(next_pbuf, -(s16_t)(IPV6_FRAG_REQROOM));
LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0);
}
#endif
pbuf_cat(ipr->p, next_pbuf);
@ -544,8 +547,9 @@ ip6_reass(struct pbuf *p)
#if IPV6_FRAG_COPYHEADER
if (IPV6_FRAG_REQROOM > 0) {
/* get back room for struct ip6_reass_helper (only required if sizeof(void*) > 4) */
err_t hdrerr = pbuf_header(ipr->p, -(s16_t)(IPV6_FRAG_REQROOM));
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == ERR_OK);
u8_t hdrerr = pbuf_header(ipr->p, -(s16_t)(IPV6_FRAG_REQROOM));
LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0);
}
iphdr_ptr = (struct ip6_hdr*)((u8_t*)ipr->p->payload - IP6_HLEN);
MEMCPY(iphdr_ptr, &ipr->iphdr, IP6_HLEN);
@ -559,7 +563,7 @@ ip6_reass(struct pbuf *p)
- IP6_HLEN);
/* Set payload length in ip header. */
iphdr_ptr->_plen = htons(ipr->datagram_len);
iphdr_ptr->_plen = lwip_htons(ipr->datagram_len);
/* Get the first pbuf. */
p = ipr->p;
@ -609,6 +613,7 @@ nullreturn:
#if LWIP_IPV6 && LWIP_IPV6_FRAG
#if !LWIP_NETIF_TX_SINGLE_PBUF
/** Allocate a new struct pbuf_custom_ref */
static struct pbuf_custom_ref*
ip6_frag_alloc_pbuf_custom_ref(void)
@ -637,6 +642,7 @@ ip6_frag_free_pbuf_custom(struct pbuf *p)
}
ip6_frag_free_pbuf_custom_ref(pcr);
}
#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
/**
* Fragment an IPv6 datagram if too large for the netif or path MTU.
@ -655,9 +661,13 @@ ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest)
{
struct ip6_hdr *original_ip6hdr;
struct ip6_hdr *ip6hdr;
struct ip6_frag_hdr * frag_hdr;
struct ip6_frag_hdr *frag_hdr;
struct pbuf *rambuf;
#if !LWIP_NETIF_TX_SINGLE_PBUF
struct pbuf *newpbuf;
u16_t newpbuflen = 0;
u16_t left_to_copy;
#endif
static u32_t identification;
u16_t nfb;
u16_t left, cop;
@ -665,8 +675,6 @@ ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest)
u16_t fragment_offset = 0;
u16_t last;
u16_t poff = IP6_HLEN;
u16_t newpbuflen = 0;
u16_t left_to_copy;
identification++;
@ -685,6 +693,26 @@ ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest)
/* Fill this fragment */
cop = last ? left : nfb;
#if LWIP_NETIF_TX_SINGLE_PBUF
rambuf = pbuf_alloc(PBUF_IP, cop + IP6_FRAG_HLEN, PBUF_RAM);
if (rambuf == NULL) {
IP6_FRAG_STATS_INC(ip6_frag.memerr);
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, (u8_t*)rambuf->payload + IP6_FRAG_HLEN, cop, poff);
/* make room for the IP header */
if (pbuf_header(rambuf, IP6_HLEN)) {
pbuf_free(rambuf);
IP6_FRAG_STATS_INC(ip6_frag.memerr);
return ERR_MEM;
}
/* fill in the IP header */
SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN);
ip6hdr = (struct ip6_hdr *)rambuf->payload;
frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN);
#else
/* When not using a static buffer, create a chain of pbufs.
* The first will be a PBUF_RAM holding the link, IPv6, and Fragment header.
* The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
@ -696,7 +724,7 @@ ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest)
return ERR_MEM;
}
LWIP_ASSERT("this needs a pbuf in one piece!",
(p->len >= (IP6_HLEN + IP6_FRAG_HLEN)));
(p->len >= (IP6_HLEN)));
SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN);
ip6hdr = (struct ip6_hdr *)rambuf->payload;
frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN);
@ -743,12 +771,13 @@ ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest)
}
}
poff = newpbuflen;
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
/* Set headers */
frag_hdr->_nexth = original_ip6hdr->_nexth;
frag_hdr->reserved = 0;
frag_hdr->_fragment_offset = htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG));
frag_hdr->_identification = htonl(identification);
frag_hdr->_fragment_offset = lwip_htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG));
frag_hdr->_identification = lwip_htonl(identification);
IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT);
IP6H_PLEN_SET(ip6hdr, cop + IP6_FRAG_HLEN);

View File

@ -1,5 +1,12 @@
/**
* @file
* Multicast listener discovery
*
* @defgroup mld6 MLD6
* @ingroup ip6
* Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710.
* No support for MLDv2.\n
* To be called from TCPIP thread
*/
/*
@ -37,14 +44,6 @@
* <delamer@inicotech.com>
*/
/**
* @defgroup mld6 MLD6
* @ingroup ip6
* Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710.
* No support for MLDv2.\n
* To be called from TCPIP thread
*/
/* Based on igmp.c implementation of igmp v2 protocol */
#include "lwip/opt.h"
@ -52,6 +51,7 @@
#if LWIP_IPV6 && LWIP_IPV6_MLD /* don't build if not configured for use in lwipopts.h */
#include "lwip/mld6.h"
#include "lwip/prot/mld6.h"
#include "lwip/icmp6.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
@ -75,16 +75,11 @@
#define MLD6_GROUP_DELAYING_MEMBER 1
#define MLD6_GROUP_IDLE_MEMBER 2
/* The list of joined groups. */
static struct mld_group* mld_group_list;
/* Forward declarations. */
static struct mld_group * mld6_new_group(struct netif *ifp, const ip6_addr_t *addr);
static err_t mld6_free_group(struct mld_group *group);
static struct mld_group *mld6_new_group(struct netif *ifp, const ip6_addr_t *addr);
static err_t mld6_remove_group(struct netif *netif, struct mld_group *group);
static void mld6_delayed_report(struct mld_group *group, u16_t maxresp);
static void mld6_send(struct mld_group *group, u8_t type);
static void mld6_send(struct netif *netif, struct mld_group *group, u8_t type);
/**
@ -95,33 +90,21 @@ static void mld6_send(struct mld_group *group, u8_t type);
err_t
mld6_stop(struct netif *netif)
{
struct mld_group *group = mld_group_list;
struct mld_group *prev = NULL;
struct mld_group *next;
struct mld_group *group = netif_mld6_data(netif);
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, NULL);
/* look for groups joined on this interface further down the list */
while (group != NULL) {
next = group->next;
/* is it a group joined on this interface? */
if (group->netif == netif) {
/* is it the first group of the list? */
if (group == mld_group_list) {
mld_group_list = next;
}
/* is there a "previous" group defined? */
if (prev != NULL) {
prev->next = next;
}
/* disable the group at the MAC level */
if (netif->mld_mac_filter != NULL) {
netif->mld_mac_filter(netif, &(group->group_address), MLD6_DEL_MAC_FILTER);
}
/* free group */
memp_free(MEMP_MLD6_GROUP, group);
} else {
/* change the "previous" */
prev = group;
struct mld_group *next = group->next; /* avoid use-after-free below */
/* disable the group at the MAC level */
if (netif->mld_mac_filter != NULL) {
netif->mld_mac_filter(netif, &(group->group_address), NETIF_DEL_MAC_FILTER);
}
/* free group */
memp_free(MEMP_MLD6_GROUP, group);
/* move to "next" */
group = next;
}
@ -136,12 +119,10 @@ mld6_stop(struct netif *netif)
void
mld6_report_groups(struct netif *netif)
{
struct mld_group *group = mld_group_list;
struct mld_group *group = netif_mld6_data(netif);
while (group != NULL) {
if (group->netif == netif) {
mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
}
mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
group = group->next;
}
}
@ -157,10 +138,10 @@ mld6_report_groups(struct netif *netif)
struct mld_group *
mld6_lookfor_group(struct netif *ifp, const ip6_addr_t *addr)
{
struct mld_group *group = mld_group_list;
struct mld_group *group = netif_mld6_data(ifp);
while (group != NULL) {
if ((group->netif == ifp) && (ip6_addr_cmp(&(group->group_address), addr))) {
if (ip6_addr_cmp(&(group->group_address), addr)) {
return group;
}
group = group->next;
@ -185,38 +166,37 @@ mld6_new_group(struct netif *ifp, const ip6_addr_t *addr)
group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP);
if (group != NULL) {
group->netif = ifp;
ip6_addr_set(&(group->group_address), addr);
group->timer = 0; /* Not running */
group->group_state = MLD6_GROUP_IDLE_MEMBER;
group->last_reporter_flag = 0;
group->use = 0;
group->next = mld_group_list;
group->next = netif_mld6_data(ifp);
mld_group_list = group;
netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, group);
}
return group;
}
/**
* Remove a group in the mld_group_list and free
* Remove a group from the mld_group_list, but do not free it yet
*
* @param group the group to remove
* @return ERR_OK if group was removed from the list, an err_t otherwise
*/
static err_t
mld6_free_group(struct mld_group *group)
mld6_remove_group(struct netif *netif, struct mld_group *group)
{
err_t err = ERR_OK;
/* Is it the first group? */
if (mld_group_list == group) {
mld_group_list = group->next;
if (netif_mld6_data(netif) == group) {
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, group->next);
} else {
/* look for group further down the list */
struct mld_group *tmpGroup;
for (tmpGroup = mld_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
for (tmpGroup = netif_mld6_data(netif); tmpGroup != NULL; tmpGroup = tmpGroup->next) {
if (tmpGroup->next == group) {
tmpGroup->next = group->next;
break;
@ -227,8 +207,6 @@ mld6_free_group(struct mld_group *group)
err = ERR_ARG;
}
}
/* free group */
memp_free(MEMP_MLD6_GROUP, group);
return err;
}
@ -243,8 +221,8 @@ mld6_free_group(struct mld_group *group)
void
mld6_input(struct pbuf *p, struct netif *inp)
{
struct mld_header * mld_hdr;
struct mld_group* group;
struct mld_header *mld_hdr;
struct mld_group *group;
MLD6_STATS_INC(mld6.recv);
@ -266,10 +244,9 @@ mld6_input(struct pbuf *p, struct netif *inp)
ip6_addr_isany(&(mld_hdr->multicast_address))) {
MLD6_STATS_INC(mld6.rx_general);
/* Report all groups, except all nodes group, and if-local groups. */
group = mld_group_list;
group = netif_mld6_data(inp);
while (group != NULL) {
if ((group->netif == inp) &&
(!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) &&
if ((!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) &&
(!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) {
mld6_delayed_report(group, mld_hdr->max_resp_delay);
}
@ -373,12 +350,12 @@ mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr)
/* Activate this address on the MAC layer. */
if (netif->mld_mac_filter != NULL) {
netif->mld_mac_filter(netif, groupaddr, MLD6_ADD_MAC_FILTER);
netif->mld_mac_filter(netif, groupaddr, NETIF_ADD_MAC_FILTER);
}
/* Report our membership. */
MLD6_STATS_INC(mld6.tx_report);
mld6_send(group, ICMP6_TYPE_MLR);
mld6_send(netif, group, ICMP6_TYPE_MLR);
mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
}
@ -440,19 +417,22 @@ mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr)
if (group != NULL) {
/* Leave if there is no other use of the group */
if (group->use <= 1) {
/* Remove the group from the list */
mld6_remove_group(netif, group);
/* If we are the last reporter for this group */
if (group->last_reporter_flag) {
MLD6_STATS_INC(mld6.tx_leave);
mld6_send(group, ICMP6_TYPE_MLD);
mld6_send(netif, group, ICMP6_TYPE_MLD);
}
/* Disable the group at the MAC level */
if (netif->mld_mac_filter != NULL) {
netif->mld_mac_filter(netif, groupaddr, MLD6_DEL_MAC_FILTER);
netif->mld_mac_filter(netif, groupaddr, NETIF_DEL_MAC_FILTER);
}
/* Free the group */
mld6_free_group(group);
/* free group struct */
memp_free(MEMP_MLD6_GROUP, group);
} else {
/* Decrement group use */
group->use--;
@ -476,21 +456,26 @@ mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr)
void
mld6_tmr(void)
{
struct mld_group *group = mld_group_list;
struct netif *netif = netif_list;
while (group != NULL) {
if (group->timer > 0) {
group->timer--;
if (group->timer == 0) {
/* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */
if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) {
MLD6_STATS_INC(mld6.tx_report);
mld6_send(group, ICMP6_TYPE_MLR);
group->group_state = MLD6_GROUP_IDLE_MEMBER;
while (netif != NULL) {
struct mld_group *group = netif_mld6_data(netif);
while (group != NULL) {
if (group->timer > 0) {
group->timer--;
if (group->timer == 0) {
/* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */
if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) {
MLD6_STATS_INC(mld6.tx_report);
mld6_send(netif, group, ICMP6_TYPE_MLR);
group->group_state = MLD6_GROUP_IDLE_MEMBER;
}
}
}
group = group->next;
}
group = group->next;
netif = netif->next;
}
}
@ -537,11 +522,11 @@ mld6_delayed_report(struct mld_group *group, u16_t maxresp)
* @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done)
*/
static void
mld6_send(struct mld_group *group, u8_t type)
mld6_send(struct netif *netif, struct mld_group *group, u8_t type)
{
struct mld_header * mld_hdr;
struct pbuf * p;
const ip6_addr_t * src_addr;
struct mld_header *mld_hdr;
struct pbuf *p;
const ip6_addr_t *src_addr;
/* Allocate a packet. Size is MLD header + IPv6 Hop-by-hop options header. */
p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr), PBUF_RAM);
@ -558,13 +543,13 @@ mld6_send(struct mld_group *group, u8_t type)
}
/* Select our source address. */
if (!ip6_addr_isvalid(netif_ip6_addr_state(group->netif, 0))) {
if (!ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) {
/* This is a special case, when we are performing duplicate address detection.
* We must join the multicast group, but we don't have a valid address yet. */
src_addr = IP6_ADDR_ANY6;
} else {
/* Use link-local address as source address. */
src_addr = netif_ip6_addr(group->netif, 0);
src_addr = netif_ip6_addr(netif, 0);
}
/* MLD message header pointer. */
@ -579,7 +564,7 @@ mld6_send(struct mld_group *group, u8_t type)
ip6_addr_set(&(mld_hdr->multicast_address), &(group->group_address));
#if CHECKSUM_GEN_ICMP6
IF__NETIF_CHECKSUM_ENABLED(group->netif, NETIF_CHECKSUM_GEN_ICMP6) {
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) {
mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len,
src_addr, &(group->group_address));
}
@ -591,7 +576,7 @@ mld6_send(struct mld_group *group, u8_t type)
/* Send the packet out. */
MLD6_STATS_INC(mld6.xmit);
ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address),
MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, group->netif);
MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, netif);
pbuf_free(p);
}

View File

@ -46,6 +46,9 @@
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/nd6.h"
#include "lwip/priv/nd6_priv.h"
#include "lwip/prot/nd6.h"
#include "lwip/prot/icmp6.h"
#include "lwip/pbuf.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
@ -57,9 +60,13 @@
#include "lwip/mld6.h"
#include "lwip/ip.h"
#include "lwip/stats.h"
#include "lwip/dns.h"
#include <string.h>
#if LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK
#error LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK
#endif
/* Router tables. */
struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS];
@ -82,23 +89,27 @@ static ip6_addr_t multicast_address;
static u8_t nd6_ra_buffer[sizeof(struct prefix_option)];
/* Forward declarations. */
static s8_t nd6_find_neighbor_cache_entry(const ip6_addr_t * ip6addr);
static s8_t nd6_find_neighbor_cache_entry(const ip6_addr_t *ip6addr);
static s8_t nd6_new_neighbor_cache_entry(void);
static void nd6_free_neighbor_cache_entry(s8_t i);
static s8_t nd6_find_destination_cache_entry(const ip6_addr_t * ip6addr);
static s8_t nd6_find_destination_cache_entry(const ip6_addr_t *ip6addr);
static s8_t nd6_new_destination_cache_entry(void);
static s8_t nd6_is_prefix_in_netif(const ip6_addr_t * ip6addr, struct netif * netif);
static s8_t nd6_get_router(const ip6_addr_t * router_addr, struct netif * netif);
static s8_t nd6_new_router(const ip6_addr_t * router_addr, struct netif * netif);
static s8_t nd6_get_onlink_prefix(ip6_addr_t * prefix, struct netif * netif);
static s8_t nd6_new_onlink_prefix(ip6_addr_t * prefix, struct netif * netif);
static s8_t nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif);
static s8_t nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif);
static s8_t nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif);
static s8_t nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif);
static s8_t nd6_get_onlink_prefix(ip6_addr_t *prefix, struct netif *netif);
static s8_t nd6_new_onlink_prefix(ip6_addr_t *prefix, struct netif *netif);
static s8_t nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif);
static err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf *q);
#define ND6_SEND_FLAG_MULTICAST_DEST 0x01
#define ND6_SEND_FLAG_ALLNODES_DEST 0x02
static void nd6_send_ns(struct netif * netif, const ip6_addr_t * target_addr, u8_t flags);
static void nd6_send_na(struct netif * netif, const ip6_addr_t * target_addr, u8_t flags);
static void nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags);
static void nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags);
static void nd6_send_neighbor_cache_probe(struct nd6_neighbor_cache_entry *entry, u8_t flags);
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
static err_t nd6_send_rs(struct netif * netif);
static err_t nd6_send_rs(struct netif *netif);
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
#if LWIP_ND6_QUEUEING
@ -127,8 +138,8 @@ nd6_input(struct pbuf *p, struct netif *inp)
switch (msg_type) {
case ICMP6_TYPE_NA: /* Neighbor Advertisement. */
{
struct na_header * na_hdr;
struct lladdr_option * lladdr_opt;
struct na_header *na_hdr;
struct lladdr_option *lladdr_opt;
/* Check that na header fits in packet. */
if (p->len < (sizeof(struct na_header))) {
@ -143,10 +154,41 @@ nd6_input(struct pbuf *p, struct netif *inp)
/* Unsolicited NA?*/
if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
ip6_addr_t target_address;
/* This is an unsolicited NA.
* link-layer changed?
* part of DAD mechanism? */
/* Create an aligned copy. */
ip6_addr_set(&target_address, &(na_hdr->target_address));
#if LWIP_IPV6_DUP_DETECT_ATTEMPTS
/* If the target address matches this netif, it is a DAD response. */
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) &&
ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) {
/* We are using a duplicate address. */
netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID);
#if LWIP_IPV6_AUTOCONFIG
/* Check to see if this address was autoconfigured. */
if (!ip6_addr_islinklocal(&target_address)) {
i = nd6_get_onlink_prefix(&target_address, inp);
if (i >= 0) {
/* Mark this prefix as duplicate, so that we don't use it
* to generate this address again. */
prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE;
}
}
#endif /* LWIP_IPV6_AUTOCONFIG */
pbuf_free(p);
return;
}
}
#endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */
/* Check that link-layer address option also fits in packet. */
if (p->len < (sizeof(struct na_header) + 2)) {
/* @todo debug message */
@ -166,58 +208,25 @@ nd6_input(struct pbuf *p, struct netif *inp)
return;
}
/* Override ip6_current_dest_addr() so that we have an aligned copy. */
ip6_addr_set(ip6_current_dest_addr(), &(na_hdr->target_address));
#if LWIP_IPV6_DUP_DETECT_ATTEMPTS
/* If the target address matches this netif, it is a DAD response. */
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) &&
ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) {
/* We are using a duplicate address. */
netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID);
#if LWIP_IPV6_MLD
/* Leave solicited node multicast group. */
ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(inp, i)->addr[3]);
mld6_leavegroup(netif_ip6_addr(inp, i), &multicast_address);
#endif /* LWIP_IPV6_MLD */
#if LWIP_IPV6_AUTOCONFIG
/* Check to see if this address was autoconfigured. */
if (!ip6_addr_islinklocal(ip6_current_dest_addr())) {
i = nd6_get_onlink_prefix(ip6_current_dest_addr(), inp);
if (i >= 0) {
/* Mark this prefix as duplicate, so that we don't use it
* to generate this address again. */
prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE;
}
}
#endif /* LWIP_IPV6_AUTOCONFIG */
pbuf_free(p);
return;
}
}
#endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */
/* This is an unsolicited NA, most likely there was a LLADDR change. */
i = nd6_find_neighbor_cache_entry(ip6_current_dest_addr());
i = nd6_find_neighbor_cache_entry(&target_address);
if (i >= 0) {
if (na_hdr->flags & ND6_FLAG_OVERRIDE) {
MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
}
}
} else {
ip6_addr_t target_address;
/* This is a solicited NA.
* neighbor address resolution response?
* neighbor unreachability detection response? */
/* Override ip6_current_dest_addr() so that we have an aligned copy. */
ip6_addr_set(ip6_current_dest_addr(), &(na_hdr->target_address));
/* Create an aligned copy. */
ip6_addr_set(&target_address, &(na_hdr->target_address));
/* Find the cache entry corresponding to this na. */
i = nd6_find_neighbor_cache_entry(ip6_current_dest_addr());
i = nd6_find_neighbor_cache_entry(&target_address);
if (i < 0) {
/* We no longer care about this target address. drop it. */
pbuf_free(p);
@ -225,8 +234,6 @@ nd6_input(struct pbuf *p, struct netif *inp)
}
/* Update cache entry. */
neighbor_cache[i].netif = inp;
neighbor_cache[i].counter.reachable_time = reachable_time;
if ((na_hdr->flags & ND6_FLAG_OVERRIDE) ||
(neighbor_cache[i].state == ND6_INCOMPLETE)) {
/* Check that link-layer address option also fits in packet. */
@ -250,7 +257,10 @@ nd6_input(struct pbuf *p, struct netif *inp)
MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
}
neighbor_cache[i].netif = inp;
neighbor_cache[i].state = ND6_REACHABLE;
neighbor_cache[i].counter.reachable_time = reachable_time;
/* Send queued packets, if any. */
if (neighbor_cache[i].q != NULL) {
@ -262,8 +272,8 @@ nd6_input(struct pbuf *p, struct netif *inp)
}
case ICMP6_TYPE_NS: /* Neighbor solicitation. */
{
struct ns_header * ns_hdr;
struct lladdr_option * lladdr_opt;
struct ns_header *ns_hdr;
struct lladdr_option *lladdr_opt;
u8_t accepted;
/* Check that ns header fits in packet. */
@ -320,6 +330,8 @@ nd6_input(struct pbuf *p, struct netif *inp)
}
}
} else {
ip6_addr_t target_address;
/* Sender is trying to resolve our address. */
/* Verify that they included their own link-layer address. */
if (lladdr_opt == NULL) {
@ -339,7 +351,7 @@ nd6_input(struct pbuf *p, struct netif *inp)
/* Delay probe in case we get confirmation of reachability from upper layer (TCP). */
neighbor_cache[i].state = ND6_DELAY;
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME;
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL;
}
} else {
/* Add their IPv6 address and link-layer address to neighbor cache.
@ -360,23 +372,27 @@ nd6_input(struct pbuf *p, struct netif *inp)
/* Receiving a message does not prove reachability: only in one direction.
* Delay probe in case we get confirmation of reachability from upper layer (TCP). */
neighbor_cache[i].state = ND6_DELAY;
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME;
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL;
}
/* Override ip6_current_dest_addr() so that we have an aligned copy. */
ip6_addr_set(ip6_current_dest_addr(), &(ns_hdr->target_address));
/* Create an aligned copy. */
ip6_addr_set(&target_address, &(ns_hdr->target_address));
/* Send back a NA for us. Allocate the reply pbuf. */
nd6_send_na(inp, ip6_current_dest_addr(), ND6_FLAG_SOLICITED | ND6_FLAG_OVERRIDE);
nd6_send_na(inp, &target_address, ND6_FLAG_SOLICITED | ND6_FLAG_OVERRIDE);
}
break; /* ICMP6_TYPE_NS */
}
case ICMP6_TYPE_RA: /* Router Advertisement. */
{
struct ra_header * ra_hdr;
u8_t * buffer; /* Used to copy options. */
struct ra_header *ra_hdr;
u8_t *buffer; /* Used to copy options. */
u16_t offset;
#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS
/* There can by multiple RDNSS options per RA */
u8_t rdnss_server_idx = 0;
#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */
/* Check that RA header fits in packet. */
if (p->len < sizeof(struct ra_header)) {
@ -413,15 +429,15 @@ nd6_input(struct pbuf *p, struct netif *inp)
}
/* Re-set invalidation timer. */
default_router_list[i].invalidation_timer = htons(ra_hdr->router_lifetime);
default_router_list[i].invalidation_timer = lwip_htons(ra_hdr->router_lifetime);
/* Re-set default timer values. */
#if LWIP_ND6_ALLOW_RA_UPDATES
if (ra_hdr->retrans_timer > 0) {
retrans_timer = htonl(ra_hdr->retrans_timer);
retrans_timer = lwip_htonl(ra_hdr->retrans_timer);
}
if (ra_hdr->reachable_time > 0) {
reachable_time = htonl(ra_hdr->reachable_time);
reachable_time = lwip_htonl(ra_hdr->reachable_time);
}
#endif /* LWIP_ND6_ALLOW_RA_UPDATES */
@ -441,7 +457,12 @@ nd6_input(struct pbuf *p, struct netif *inp)
buffer = &((u8_t*)p->payload)[offset];
} else {
buffer = nd6_ra_buffer;
pbuf_copy_partial(p, buffer, sizeof(struct prefix_option), offset);
if (pbuf_copy_partial(p, buffer, sizeof(struct prefix_option), offset) != sizeof(struct prefix_option)) {
pbuf_free(p);
ND6_STATS_INC(nd6.lenerr);
ND6_STATS_INC(nd6.drop);
return;
}
}
if (buffer[1] == 0) {
/* zero-length extension. drop packet */
@ -453,7 +474,7 @@ nd6_input(struct pbuf *p, struct netif *inp)
switch (buffer[0]) {
case ND6_OPTION_TYPE_SOURCE_LLADDR:
{
struct lladdr_option * lladdr_opt;
struct lladdr_option *lladdr_opt;
lladdr_opt = (struct lladdr_option *)buffer;
if ((default_router_list[i].neighbor_entry != NULL) &&
(default_router_list[i].neighbor_entry->state == ND6_INCOMPLETE)) {
@ -465,35 +486,38 @@ nd6_input(struct pbuf *p, struct netif *inp)
}
case ND6_OPTION_TYPE_MTU:
{
struct mtu_option * mtu_opt;
struct mtu_option *mtu_opt;
mtu_opt = (struct mtu_option *)buffer;
if (htonl(mtu_opt->mtu) >= 1280) {
if (lwip_htonl(mtu_opt->mtu) >= 1280) {
#if LWIP_ND6_ALLOW_RA_UPDATES
inp->mtu = (u16_t)htonl(mtu_opt->mtu);
inp->mtu = (u16_t)lwip_htonl(mtu_opt->mtu);
#endif /* LWIP_ND6_ALLOW_RA_UPDATES */
}
break;
}
case ND6_OPTION_TYPE_PREFIX_INFO:
{
struct prefix_option * prefix_opt;
struct prefix_option *prefix_opt;
prefix_opt = (struct prefix_option *)buffer;
if (prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) {
if ((prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) &&
(prefix_opt->prefix_length == 64) &&
!ip6_addr_islinklocal(&(prefix_opt->prefix))) {
/* Add to on-link prefix list. */
s8_t prefix;
ip6_addr_t prefix_addr;
/* Get a memory-aligned copy of the prefix. */
ip6_addr_set(ip6_current_dest_addr(), &(prefix_opt->prefix));
ip6_addr_set(&prefix_addr, &(prefix_opt->prefix));
/* find cache entry for this prefix. */
prefix = nd6_get_onlink_prefix(ip6_current_dest_addr(), inp);
prefix = nd6_get_onlink_prefix(&prefix_addr, inp);
if (prefix < 0) {
/* Create a new cache entry. */
prefix = nd6_new_onlink_prefix(ip6_current_dest_addr(), inp);
prefix = nd6_new_onlink_prefix(&prefix_addr, inp);
}
if (prefix >= 0) {
prefix_list[prefix].invalidation_timer = htonl(prefix_opt->valid_lifetime);
prefix_list[prefix].invalidation_timer = lwip_htonl(prefix_opt->valid_lifetime);
#if LWIP_IPV6_AUTOCONFIG
if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) {
@ -513,6 +537,37 @@ nd6_input(struct pbuf *p, struct netif *inp)
route_opt = (struct route_option *)buffer;*/
break;
#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS
case ND6_OPTION_TYPE_RDNSS:
{
u8_t num, n;
struct rdnss_option * rdnss_opt;
rdnss_opt = (struct rdnss_option *)buffer;
num = (rdnss_opt->length - 1) / 2;
for (n = 0; (rdnss_server_idx < DNS_MAX_SERVERS) && (n < num); n++) {
ip_addr_t rdnss_address;
/* Get a memory-aligned copy of the prefix. */
ip_addr_copy_from_ip6(rdnss_address, rdnss_opt->rdnss_address[n]);
if (htonl(rdnss_opt->lifetime) > 0) {
/* TODO implement Lifetime > 0 */
dns_setserver(rdnss_server_idx++, &rdnss_address);
} else {
/* TODO implement DNS removal in dns.c */
u8_t s;
for (s = 0; s < DNS_MAX_SERVERS; s++) {
const ip_addr_t *addr = dns_getserver(s);
if(ip_addr_cmp(addr, &rdnss_address)) {
dns_setserver(s, NULL);
}
}
}
}
break;
}
#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */
default:
/* Unrecognized option, abort. */
ND6_STATS_INC(nd6.proterr);
@ -526,8 +581,9 @@ nd6_input(struct pbuf *p, struct netif *inp)
}
case ICMP6_TYPE_RD: /* Redirect */
{
struct redirect_header * redir_hdr;
struct lladdr_option * lladdr_opt;
struct redirect_header *redir_hdr;
struct lladdr_option *lladdr_opt;
ip6_addr_t tmp;
/* Check that Redir header fits in packet. */
if (p->len < sizeof(struct redirect_header)) {
@ -550,10 +606,10 @@ nd6_input(struct pbuf *p, struct netif *inp)
}
/* Copy original destination address to current source address, to have an aligned copy. */
ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->destination_address));
ip6_addr_set(&tmp, &(redir_hdr->destination_address));
/* Find dest address in cache */
i = nd6_find_destination_cache_entry(ip6_current_src_addr());
i = nd6_find_destination_cache_entry(&tmp);
if (i < 0) {
/* Destination not in cache, drop packet. */
pbuf_free(p);
@ -567,20 +623,20 @@ nd6_input(struct pbuf *p, struct netif *inp)
if (lladdr_opt != NULL) {
if (lladdr_opt->type == ND6_OPTION_TYPE_TARGET_LLADDR) {
/* Copy target address to current source address, to have an aligned copy. */
ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->target_address));
ip6_addr_set(&tmp, &(redir_hdr->target_address));
i = nd6_find_neighbor_cache_entry(ip6_current_src_addr());
i = nd6_find_neighbor_cache_entry(&tmp);
if (i < 0) {
i = nd6_new_neighbor_cache_entry();
if (i >= 0) {
neighbor_cache[i].netif = inp;
MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr());
ip6_addr_set(&(neighbor_cache[i].next_hop_address), &tmp);
/* Receiving a message does not prove reachability: only in one direction.
* Delay probe in case we get confirmation of reachability from upper layer (TCP). */
neighbor_cache[i].state = ND6_DELAY;
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME;
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL;
}
}
if (i >= 0) {
@ -589,7 +645,7 @@ nd6_input(struct pbuf *p, struct netif *inp)
/* Receiving a message does not prove reachability: only in one direction.
* Delay probe in case we get confirmation of reachability from upper layer (TCP). */
neighbor_cache[i].state = ND6_DELAY;
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME;
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL;
}
}
}
@ -599,8 +655,9 @@ nd6_input(struct pbuf *p, struct netif *inp)
case ICMP6_TYPE_PTB: /* Packet too big */
{
struct icmp6_hdr *icmp6hdr; /* Packet too big message */
struct ip6_hdr * ip6hdr; /* IPv6 header of the packet which caused the error */
struct ip6_hdr *ip6hdr; /* IPv6 header of the packet which caused the error */
u32_t pmtu;
ip6_addr_t tmp;
/* Check that ICMPv6 header + IPv6 header fit in payload */
if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) {
@ -615,10 +672,10 @@ nd6_input(struct pbuf *p, struct netif *inp)
ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr));
/* Copy original destination address to current source address, to have an aligned copy. */
ip6_addr_set(ip6_current_src_addr(), &(ip6hdr->dest));
ip6_addr_set(&tmp, &(ip6hdr->dest));
/* Look for entry in destination cache. */
i = nd6_find_destination_cache_entry(ip6_current_src_addr());
i = nd6_find_destination_cache_entry(&tmp);
if (i < 0) {
/* Destination not in cache, drop packet. */
pbuf_free(p);
@ -626,7 +683,7 @@ nd6_input(struct pbuf *p, struct netif *inp)
}
/* Change the Path MTU. */
pmtu = htonl(icmp6hdr->data);
pmtu = lwip_htonl(icmp6hdr->data);
destination_cache[i].pmtu = (u16_t)LWIP_MIN(pmtu, 0xFFFF);
break; /* ICMP6_TYPE_PTB */
@ -655,7 +712,7 @@ void
nd6_tmr(void)
{
s8_t i;
struct netif * netif;
struct netif *netif;
/* Process neighbor entries. */
for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
@ -668,7 +725,7 @@ nd6_tmr(void)
} else {
/* Send a NS for this entry. */
neighbor_cache[i].counter.probes_sent++;
nd6_send_ns(neighbor_cache[i].netif, &(neighbor_cache[i].next_hop_address), ND6_SEND_FLAG_MULTICAST_DEST);
nd6_send_neighbor_cache_probe(&neighbor_cache[i], ND6_SEND_FLAG_MULTICAST_DEST);
}
break;
case ND6_REACHABLE:
@ -685,15 +742,15 @@ nd6_tmr(void)
}
break;
case ND6_STALE:
neighbor_cache[i].counter.stale_time += ND6_TMR_INTERVAL;
neighbor_cache[i].counter.stale_time++;
break;
case ND6_DELAY:
if (neighbor_cache[i].counter.delay_time <= ND6_TMR_INTERVAL) {
if (neighbor_cache[i].counter.delay_time <= 1) {
/* Change to PROBE state. */
neighbor_cache[i].state = ND6_PROBE;
neighbor_cache[i].counter.probes_sent = 0;
} else {
neighbor_cache[i].counter.delay_time -= ND6_TMR_INTERVAL;
neighbor_cache[i].counter.delay_time--;
}
break;
case ND6_PROBE:
@ -704,7 +761,7 @@ nd6_tmr(void)
} else {
/* Send a NS for this entry. */
neighbor_cache[i].counter.probes_sent++;
nd6_send_ns(neighbor_cache[i].netif, &(neighbor_cache[i].next_hop_address), 0);
nd6_send_neighbor_cache_probe(&neighbor_cache[i], 0);
}
break;
case ND6_NO_ENTRY:
@ -738,7 +795,7 @@ nd6_tmr(void)
/* Process prefix entries. */
for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) {
if (prefix_list[i].netif != NULL) {
if (prefix_list[i].netif != NULL) {
if (prefix_list[i].invalidation_timer < ND6_TMR_INTERVAL / 1000) {
/* Entry timed out, remove it */
prefix_list[i].invalidation_timer = 0;
@ -794,7 +851,7 @@ nd6_tmr(void)
}
#endif /* LWIP_IPV6_AUTOCONFIG */
}
}
}
}
@ -803,18 +860,11 @@ nd6_tmr(void)
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) {
u8_t addr_state = netif_ip6_addr_state(netif, i);
if (ip6_addr_istentative(addr_state)) {
if ((addr_state & 0x07) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) {
if ((addr_state & IP6_ADDR_TENTATIVE_COUNT_MASK) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) {
/* No NA received in response. Mark address as valid. */
netif_ip6_addr_set_state(netif, i, IP6_ADDR_PREFERRED);
/* @todo implement preferred and valid lifetimes. */
} else if (netif->flags & NETIF_FLAG_UP) {
#if LWIP_IPV6_MLD
if ((addr_state & 0x07) == 0) {
/* Join solicited node multicast group. */
ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, i)->addr[3]);
mld6_joingroup(netif_ip6_addr(netif, i), &multicast_address);
}
#endif /* LWIP_IPV6_MLD */
/* Send a NS for this address. */
nd6_send_ns(netif, netif_ip6_addr(netif, i), ND6_SEND_FLAG_MULTICAST_DEST);
/* tentative: set next state by increasing by one */
@ -840,6 +890,17 @@ nd6_tmr(void)
}
/** Send a neighbor solicitation message for a specific neighbor cache entry
*
* @param entry the neightbor cache entry for wich to send the message
* @param flags one of ND6_SEND_FLAG_*
*/
static void
nd6_send_neighbor_cache_probe(struct nd6_neighbor_cache_entry *entry, u8_t flags)
{
nd6_send_ns(entry->netif, &entry->next_hop_address, flags);
}
/**
* Send a neighbor solicitation message
*
@ -848,11 +909,11 @@ nd6_tmr(void)
* @param flags one of ND6_SEND_FLAG_*
*/
static void
nd6_send_ns(struct netif * netif, const ip6_addr_t * target_addr, u8_t flags)
nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags)
{
struct ns_header * ns_hdr;
struct pbuf * p;
const ip6_addr_t * src_addr;
struct ns_header *ns_hdr;
struct pbuf *p;
const ip6_addr_t *src_addr;
u16_t lladdr_opt_len;
if (ip6_addr_isvalid(netif_ip6_addr_state(netif,0))) {
@ -917,13 +978,13 @@ nd6_send_ns(struct netif * netif, const ip6_addr_t * target_addr, u8_t flags)
* @param flags one of ND6_SEND_FLAG_*
*/
static void
nd6_send_na(struct netif * netif, const ip6_addr_t * target_addr, u8_t flags)
nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags)
{
struct na_header * na_hdr;
struct lladdr_option * lladdr_opt;
struct pbuf * p;
const ip6_addr_t * src_addr;
const ip6_addr_t * dest_addr;
struct na_header *na_hdr;
struct lladdr_option *lladdr_opt;
struct pbuf *p;
const ip6_addr_t *src_addr;
const ip6_addr_t *dest_addr;
u16_t lladdr_opt_len;
/* Use link-local address as source address. */
@ -988,12 +1049,12 @@ nd6_send_na(struct netif * netif, const ip6_addr_t * target_addr, u8_t flags)
* @param netif the netif on which to send the message
*/
static err_t
nd6_send_rs(struct netif * netif)
nd6_send_rs(struct netif *netif)
{
struct rs_header * rs_hdr;
struct lladdr_option * lladdr_opt;
struct pbuf * p;
const ip6_addr_t * src_addr;
struct rs_header *rs_hdr;
struct lladdr_option *lladdr_opt;
struct pbuf *p;
const ip6_addr_t *src_addr;
err_t err;
u16_t lladdr_opt_len = 0;
@ -1059,7 +1120,7 @@ nd6_send_rs(struct netif * netif)
* entry is found
*/
static s8_t
nd6_find_neighbor_cache_entry(const ip6_addr_t * ip6addr)
nd6_find_neighbor_cache_entry(const ip6_addr_t *ip6addr)
{
s8_t i;
for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
@ -1218,7 +1279,7 @@ nd6_free_neighbor_cache_entry(s8_t i)
* entry is found
*/
static s8_t
nd6_find_destination_cache_entry(const ip6_addr_t * ip6addr)
nd6_find_destination_cache_entry(const ip6_addr_t *ip6addr)
{
s8_t i;
for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) {
@ -1261,6 +1322,22 @@ nd6_new_destination_cache_entry(void)
return j;
}
/**
* Clear the destination cache.
*
* This operation may be necessary for consistency in the light of changing
* local addresses and/or use of the gateway hook.
*/
void
nd6_clear_destination_cache(void)
{
int i;
for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) {
ip6_addr_set_any(&destination_cache[i].destination_addr);
}
}
/**
* Determine whether an address matches an on-link prefix.
*
@ -1268,7 +1345,7 @@ nd6_new_destination_cache_entry(void)
* @return 1 if the address is on-link, 0 otherwise
*/
static s8_t
nd6_is_prefix_in_netif(const ip6_addr_t * ip6addr, struct netif * netif)
nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif)
{
s8_t i;
for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) {
@ -1296,8 +1373,8 @@ nd6_is_prefix_in_netif(const ip6_addr_t * ip6addr, struct netif * netif)
* @return the default router entry index, or -1 if no suitable
* router is found
*/
s8_t
nd6_select_router(const ip6_addr_t * ip6addr, struct netif * netif)
static s8_t
nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif)
{
s8_t i;
/* last_router is used for round-robin router selection (as recommended
@ -1348,6 +1425,30 @@ nd6_select_router(const ip6_addr_t * ip6addr, struct netif * netif)
return -1;
}
/**
* Find a router-announced route to the given destination.
*
* The caller is responsible for checking whether the returned netif, if any,
* is in a suitable state (up, link up) to be used for packet transmission.
*
* @param ip6addr the destination IPv6 address
* @return the netif to use for the destination, or NULL if none found
*/
struct netif *
nd6_find_route(const ip6_addr_t *ip6addr)
{
s8_t i;
i = nd6_select_router(ip6addr, NULL);
if (i >= 0) {
if (default_router_list[i].neighbor_entry != NULL) {
return default_router_list[i].neighbor_entry->netif; /* may be NULL */
}
}
return NULL;
}
/**
* Find an entry for a default router.
*
@ -1356,7 +1457,7 @@ nd6_select_router(const ip6_addr_t * ip6addr, struct netif * netif)
* @return the index of the router entry, or -1 if not found
*/
static s8_t
nd6_get_router(const ip6_addr_t * router_addr, struct netif * netif)
nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif)
{
s8_t i;
@ -1381,9 +1482,10 @@ nd6_get_router(const ip6_addr_t * router_addr, struct netif * netif)
* @return the index on the router table, or -1 if could not be created
*/
static s8_t
nd6_new_router(const ip6_addr_t * router_addr, struct netif * netif)
nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif)
{
s8_t router_index;
s8_t free_router_index;
s8_t neighbor_index;
/* Do we have a neighbor entry for this router? */
@ -1399,19 +1501,30 @@ nd6_new_router(const ip6_addr_t * router_addr, struct netif * netif)
neighbor_cache[neighbor_index].netif = netif;
neighbor_cache[neighbor_index].q = NULL;
neighbor_cache[neighbor_index].state = ND6_INCOMPLETE;
neighbor_cache[neighbor_index].counter.probes_sent = 0;
neighbor_cache[neighbor_index].counter.probes_sent = 1;
nd6_send_neighbor_cache_probe(&neighbor_cache[neighbor_index], ND6_SEND_FLAG_MULTICAST_DEST);
}
/* Mark neighbor as router. */
neighbor_cache[neighbor_index].isrouter = 1;
/* Look for empty entry. */
for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) {
free_router_index = LWIP_ND6_NUM_ROUTERS;
for (router_index = LWIP_ND6_NUM_ROUTERS - 1; router_index >= 0; router_index--) {
/* check if router already exists (this is a special case for 2 netifs on the same subnet
- e.g. wifi and cable) */
if(default_router_list[router_index].neighbor_entry == &(neighbor_cache[neighbor_index])){
return router_index;
}
if (default_router_list[router_index].neighbor_entry == NULL) {
default_router_list[router_index].neighbor_entry = &(neighbor_cache[neighbor_index]);
return router_index;
/* remember lowest free index to create a new entry */
free_router_index = router_index;
}
}
if (free_router_index < LWIP_ND6_NUM_ROUTERS) {
default_router_list[free_router_index].neighbor_entry = &(neighbor_cache[neighbor_index]);
return free_router_index;
}
/* Could not create a router entry. */
@ -1430,7 +1543,7 @@ nd6_new_router(const ip6_addr_t * router_addr, struct netif * netif)
* @return the index on the prefix table, or -1 if not found
*/
static s8_t
nd6_get_onlink_prefix(ip6_addr_t * prefix, struct netif * netif)
nd6_get_onlink_prefix(ip6_addr_t *prefix, struct netif *netif)
{
s8_t i;
@ -1454,7 +1567,7 @@ nd6_get_onlink_prefix(ip6_addr_t * prefix, struct netif * netif)
* @return the index on the prefix table, or -1 if not created
*/
static s8_t
nd6_new_onlink_prefix(ip6_addr_t * prefix, struct netif * netif)
nd6_new_onlink_prefix(ip6_addr_t *prefix, struct netif *netif)
{
s8_t i;
@ -1488,9 +1601,12 @@ nd6_new_onlink_prefix(ip6_addr_t * prefix, struct netif * netif)
* suitable next hop was found, ERR_MEM if no cache entry
* could be created
*/
s8_t
nd6_get_next_hop_entry(const ip6_addr_t * ip6addr, struct netif * netif)
static s8_t
nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif)
{
#ifdef LWIP_HOOK_ND6_GET_GW
const ip6_addr_t *next_hop_addr;
#endif /* LWIP_HOOK_ND6_GET_GW */
s8_t i;
#if LWIP_NETIF_HWADDRHINT
@ -1534,6 +1650,12 @@ nd6_get_next_hop_entry(const ip6_addr_t * ip6addr, struct netif * netif)
/* Destination in local link. */
destination_cache[nd6_cached_destination_index].pmtu = netif->mtu;
ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, destination_cache[nd6_cached_destination_index].destination_addr);
#ifdef LWIP_HOOK_ND6_GET_GW
} else if ((next_hop_addr = LWIP_HOOK_ND6_GET_GW(netif, ip6addr)) != NULL) {
/* Next hop for destination provided by hook function. */
destination_cache[nd6_cached_destination_index].pmtu = netif->mtu;
ip6_addr_set(&destination_cache[nd6_cached_destination_index].next_hop_addr, next_hop_addr);
#endif /* LWIP_HOOK_ND6_GET_GW */
} else {
/* We need to select a router. */
i = nd6_select_router(ip6addr, netif);
@ -1583,7 +1705,8 @@ nd6_get_next_hop_entry(const ip6_addr_t * ip6addr, struct netif * netif)
neighbor_cache[i].isrouter = 0;
neighbor_cache[i].netif = netif;
neighbor_cache[i].state = ND6_INCOMPLETE;
neighbor_cache[i].counter.probes_sent = 0;
neighbor_cache[i].counter.probes_sent = 1;
nd6_send_neighbor_cache_probe(&neighbor_cache[i], ND6_SEND_FLAG_MULTICAST_DEST);
}
}
@ -1600,8 +1723,8 @@ nd6_get_next_hop_entry(const ip6_addr_t * ip6addr, struct netif * netif)
* @param q packet to be queued
* @return ERR_OK if succeeded, ERR_MEM if out of memory
*/
err_t
nd6_queue_packet(s8_t neighbor_index, struct pbuf * q)
static err_t
nd6_queue_packet(s8_t neighbor_index, struct pbuf *q)
{
err_t result = ERR_MEM;
struct pbuf *p;
@ -1736,6 +1859,7 @@ static void
nd6_send_q(s8_t i)
{
struct ip6_hdr *ip6hdr;
ip6_addr_t dest;
#if LWIP_ND6_QUEUEING
struct nd6_q_entry *q;
#endif /* LWIP_ND6_QUEUEING */
@ -1752,10 +1876,10 @@ nd6_send_q(s8_t i)
neighbor_cache[i].q = q->next;
/* Get ipv6 header. */
ip6hdr = (struct ip6_hdr *)(q->p->payload);
/* Override ip6_current_dest_addr() so that we have an aligned copy. */
ip6_addr_set(ip6_current_dest_addr(), &(ip6hdr->dest));
/* Create an aligned copy. */
ip6_addr_set(&dest, &(ip6hdr->dest));
/* send the queued IPv6 packet */
(neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, q->p, ip6_current_dest_addr());
(neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, q->p, &dest);
/* free the queued IP packet */
pbuf_free(q->p);
/* now queue entry can be freed */
@ -1765,10 +1889,10 @@ nd6_send_q(s8_t i)
if (neighbor_cache[i].q != NULL) {
/* Get ipv6 header. */
ip6hdr = (struct ip6_hdr *)(neighbor_cache[i].q->payload);
/* Override ip6_current_dest_addr() so that we have an aligned copy. */
ip6_addr_set(ip6_current_dest_addr(), &(ip6hdr->dest));
/* Create an aligned copy. */
ip6_addr_set(&dest, &(ip6hdr->dest));
/* send the queued IPv6 packet */
(neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, neighbor_cache[i].q, ip6_current_dest_addr());
(neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, neighbor_cache[i].q, &dest);
/* free the queued IP packet */
pbuf_free(neighbor_cache[i].q);
neighbor_cache[i].q = NULL;
@ -1776,6 +1900,61 @@ nd6_send_q(s8_t i)
#endif /* LWIP_ND6_QUEUEING */
}
/**
* A packet is to be transmitted to a specific IPv6 destination on a specific
* interface. Check if we can find the hardware address of the next hop to use
* for the packet. If so, give the hardware address to the caller, which should
* use it to send the packet right away. Otherwise, enqueue the packet for
* later transmission while looking up the hardware address, if possible.
*
* As such, this function returns one of three different possible results:
*
* - ERR_OK with a non-NULL 'hwaddrp': the caller should send the packet now.
* - ERR_OK with a NULL 'hwaddrp': the packet has been enqueued for later.
* - not ERR_OK: something went wrong; forward the error upward in the stack.
*
* @param netif The lwIP network interface on which the IP packet will be sent.
* @param q The pbuf(s) containing the IP packet to be sent.
* @param ip6addr The destination IPv6 address of the packet.
* @param hwaddrp On success, filled with a pointer to a HW address or NULL (meaning
* the packet has been queued).
* @return
* - ERR_OK on success, ERR_RTE if no route was found for the packet,
* or ERR_MEM if low memory conditions prohibit sending the packet at all.
*/
err_t
nd6_get_next_hop_addr_or_queue(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr, const u8_t **hwaddrp)
{
s8_t i;
/* Get next hop record. */
i = nd6_get_next_hop_entry(ip6addr, netif);
if (i < 0) {
/* failed to get a next hop neighbor record. */
return i;
}
/* Now that we have a destination record, send or queue the packet. */
if (neighbor_cache[i].state == ND6_STALE) {
/* Switch to delay state. */
neighbor_cache[i].state = ND6_DELAY;
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL;
}
/* @todo should we send or queue if PROBE? send for now, to let unicast NS pass. */
if ((neighbor_cache[i].state == ND6_REACHABLE) ||
(neighbor_cache[i].state == ND6_DELAY) ||
(neighbor_cache[i].state == ND6_PROBE)) {
/* Tell the caller to send out the packet now. */
*hwaddrp = neighbor_cache[i].lladdr;
return ERR_OK;
}
/* We should queue packet on this interface. */
*hwaddrp = NULL;
return nd6_queue_packet(i, q);
}
/**
* Get the Path MTU for a destination.
@ -1785,7 +1964,7 @@ nd6_send_q(s8_t i)
* @return the Path MTU, if known, or the netif default MTU
*/
u16_t
nd6_get_destination_mtu(const ip6_addr_t * ip6addr, struct netif * netif)
nd6_get_destination_mtu(const ip6_addr_t *ip6addr, struct netif *netif)
{
s8_t i;
@ -1815,7 +1994,7 @@ nd6_get_destination_mtu(const ip6_addr_t * ip6addr, struct netif * netif)
* by an upper layer protocol (TCP)
*/
void
nd6_reachability_hint(const ip6_addr_t * ip6addr)
nd6_reachability_hint(const ip6_addr_t *ip6addr)
{
s8_t i;
@ -1858,7 +2037,7 @@ nd6_reachability_hint(const ip6_addr_t * ip6addr)
* @param netif points to a network interface
*/
void
nd6_cleanup_netif(struct netif * netif)
nd6_cleanup_netif(struct netif *netif)
{
u8_t i;
s8_t router_index;
@ -1882,4 +2061,38 @@ nd6_cleanup_netif(struct netif * netif)
}
}
#if LWIP_IPV6_MLD
/**
* The state of a local IPv6 address entry is about to change. If needed, join
* or leave the solicited-node multicast group for the address.
*
* @param netif The netif that owns the address.
* @param addr_idx The index of the address.
* @param new_state The new (IP6_ADDR_) state for the address.
*/
void
nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state)
{
u8_t old_state, old_member, new_member;
old_state = netif_ip6_addr_state(netif, addr_idx);
/* Determine whether we were, and should be, a member of the solicited-node
* multicast group for this address. For tentative addresses, the group is
* not joined until the address enters the TENTATIVE_1 (or VALID) state. */
old_member = (old_state != IP6_ADDR_INVALID && old_state != IP6_ADDR_TENTATIVE);
new_member = (new_state != IP6_ADDR_INVALID && new_state != IP6_ADDR_TENTATIVE);
if (old_member != new_member) {
ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, addr_idx)->addr[3]);
if (new_member) {
mld6_joingroup_netif(netif, &multicast_address);
} else {
mld6_leavegroup_netif(netif, &multicast_address);
}
}
}
#endif /* LWIP_IPV6_MLD */
#endif /* LWIP_IPV6 */

View File

@ -2,6 +2,28 @@
* @file
* Common functions used throughout the stack.
*
* 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_htons(x) your_htons
* \#define lwip_htonl(x) your_htonl
*
* Note lwip_ntohs() and lwip_ntohl() are merely references to the htonx counterparts.
*
* If you \#define them to htons() and htonl(), you should
* \#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from
* defining htonx/ntohx compatibility macros.
* @defgroup sys_nonstandard Non-standard functions
* @ingroup sys_layer
* lwIP provides default implementations for non-standard functions.
* These can be mapped to OS functions to reduce code footprint if desired.
* All defines related to this section must not be placed in lwipopts.h,
* but in arch/cc.h!
* These options cannot be \#defined in lwipopts.h since they are not options
* of lwIP itself, but options of the lwIP port to your system.
*/
/*
@ -39,21 +61,11 @@
#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.
*/
#include <string.h>
#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)
#if BYTE_ORDER == LITTLE_ENDIAN
#if !defined(lwip_htons)
/**
* Convert an u16_t from host- to network byte order.
*
@ -63,21 +75,11 @@
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);
return (u16_t)PP_HTONS(n);
}
#endif /* lwip_htons */
#if !defined(lwip_htonl)
/**
* Convert an u32_t from host- to network byte order.
*
@ -87,22 +89,134 @@ lwip_ntohs(u16_t n)
u32_t
lwip_htonl(u32_t n)
{
return ((n & 0xff) << 24) |
((n & 0xff00) << 8) |
((n & 0xff0000UL) >> 8) |
((n & 0xff000000UL) >> 24);
return (u32_t)PP_HTONL(n);
}
#endif /* lwip_htonl */
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
#ifndef lwip_strnstr
/**
* Convert an u32_t from network- to host byte order.
*
* @param n u32_t in network byte order
* @return n in host byte order
* @ingroup sys_nonstandard
* lwIP default implementation for strnstr() non-standard function.
* This can be \#defined to strnstr() depending on your platform port.
*/
u32_t
lwip_ntohl(u32_t n)
char*
lwip_strnstr(const char* buffer, const char* token, size_t n)
{
return lwip_htonl(n);
const char* p;
size_t tokenlen = strlen(token);
if (tokenlen == 0) {
return LWIP_CONST_CAST(char *, buffer);
}
for (p = buffer; *p && (p + tokenlen <= buffer + n); p++) {
if ((*p == *token) && (strncmp(p, token, tokenlen) == 0)) {
return LWIP_CONST_CAST(char *, p);
}
}
return NULL;
}
#endif
#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */
#ifndef lwip_stricmp
/**
* @ingroup sys_nonstandard
* lwIP default implementation for stricmp() non-standard function.
* This can be \#defined to stricmp() depending on your platform port.
*/
int
lwip_stricmp(const char* str1, const char* str2)
{
char c1, c2;
do {
c1 = *str1++;
c2 = *str2++;
if (c1 != c2) {
char c1_upc = c1 | 0x20;
if ((c1_upc >= 'a') && (c1_upc <= 'z')) {
/* characters are not equal an one is in the alphabet range:
downcase both chars and check again */
char c2_upc = c2 | 0x20;
if (c1_upc != c2_upc) {
/* still not equal */
/* don't care for < or > */
return 1;
}
} else {
/* characters are not equal but none is in the alphabet range */
return 1;
}
}
} while (c1 != 0);
return 0;
}
#endif
#ifndef lwip_strnicmp
/**
* @ingroup sys_nonstandard
* lwIP default implementation for strnicmp() non-standard function.
* This can be \#defined to strnicmp() depending on your platform port.
*/
int
lwip_strnicmp(const char* str1, const char* str2, size_t len)
{
char c1, c2;
do {
c1 = *str1++;
c2 = *str2++;
if (c1 != c2) {
char c1_upc = c1 | 0x20;
if ((c1_upc >= 'a') && (c1_upc <= 'z')) {
/* characters are not equal an one is in the alphabet range:
downcase both chars and check again */
char c2_upc = c2 | 0x20;
if (c1_upc != c2_upc) {
/* still not equal */
/* don't care for < or > */
return 1;
}
} else {
/* characters are not equal but none is in the alphabet range */
return 1;
}
}
} while (len-- && c1 != 0);
return 0;
}
#endif
#ifndef lwip_itoa
/**
* @ingroup sys_nonstandard
* lwIP default implementation for itoa() non-standard function.
* This can be \#defined to itoa() or snprintf(result, bufsize, "%d", number) depending on your platform port.
*/
void
lwip_itoa(char* result, size_t bufsize, int number)
{
const int base = 10;
char* ptr = result, *ptr1 = result, tmp_char;
int tmp_value;
LWIP_UNUSED_ARG(bufsize);
do {
tmp_value = number;
number /= base;
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - number * base)];
} while(number);
/* Apply negative sign */
if (tmp_value < 0) {
*ptr++ = '-';
}
*ptr-- = '\0';
while(ptr1 < ptr) {
tmp_char = *ptr;
*ptr--= *ptr1;
*ptr1++ = tmp_char;
}
}
#endif

View File

@ -1,6 +1,37 @@
/**
* @file
* DNS - host name to IP address resolver.
*
* @defgroup dns DNS
* @ingroup callbackstyle_api
*
* Implements a DNS host name to IP address resolver.
*
* The lwIP DNS resolver functions are used to lookup a host name and
* map it to a numerical IP address. It maintains a list of resolved
* hostnames that can be queried with the dns_lookup() function.
* New hostnames can be resolved using the dns_query() function.
*
* The lwIP version of the resolver also adds a non-blocking version of
* gethostbyname() that will work with a raw API application. This function
* checks for an IP address string first and converts it if it is valid.
* gethostbyname() then does a dns_lookup() to see if the name is
* already in the table. If so, the IP is returned. If not, a query is
* issued and the function returns with a ERR_INPROGRESS status. The app
* using the dns client must then go into a waiting state.
*
* Once a hostname has been resolved (or found to be non-existent),
* the resolver code calls a specified callback function (which
* must be implemented by the module that uses the resolver).
*
* Multicast DNS queries are supported for names ending on ".local".
* However, only "One-Shot Multicast DNS Queries" are supported (RFC 6762
* chapter 5.1), this is not a fully compliant implementation of continuous
* mDNS querying!
*
* All functions must be called from TCPIP thread.
*
* @see @ref netconn_common for thread-safe access.
*/
/*
@ -37,34 +68,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @defgroup dns DNS
* @ingroup callbackstyle_api
*
* Implements a DNS host name to IP address resolver.
*
* The lwIP DNS resolver functions are used to lookup a host name and
* map it to a numerical IP address. It maintains a list of resolved
* hostnames that can be queried with the dns_lookup() function.
* New hostnames can be resolved using the dns_query() function.
*
* The lwIP version of the resolver also adds a non-blocking version of
* gethostbyname() that will work with a raw API application. This function
* checks for an IP address string first and converts it if it is valid.
* gethostbyname() then does a dns_lookup() to see if the name is
* already in the table. If so, the IP is returned. If not, a query is
* issued and the function returns with a ERR_INPROGRESS status. The app
* using the dns client must then go into a waiting state.
*
* Once a hostname has been resolved (or found to be non-existent),
* the resolver code calls a specified callback function (which
* must be implemented by the module that uses the resolver).
*
* All functions must be called from TCPIP thread.
*
* @see @ref netconn_common for thread-safe access.
*/
/*-----------------------------------------------------------------------------
* RFC 1035 - Domain names - implementation and specification
* RFC 2181 - Clarifications to the DNS Specification
@ -73,6 +76,7 @@
/** @todo: define good default values (rfc compliance) */
/** @todo: improve answer parsing, more checkings... */
/** @todo: check RFC1035 - 7.3. Processing responses */
/** @todo: one-shot mDNS: dual-stack fallback to another IP version */
/*-----------------------------------------------------------------------------
* Includes
@ -82,10 +86,12 @@
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
#include "lwip/def.h"
#include "lwip/udp.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/dns.h"
#include "lwip/prot/dns.h"
#include <string.h>
@ -104,11 +110,6 @@ static u16_t dns_txid;
#define DNS_PORT_ALLOWED(port) ((port) >= 1024)
#endif
/** DNS server port address */
#ifndef DNS_SERVER_PORT
#define DNS_SERVER_PORT 53
#endif
/** DNS maximum number of retries when asking for a name, before "timeout". */
#ifndef DNS_MAX_RETRIES
#define DNS_MAX_RETRIES 4
@ -121,6 +122,13 @@ static u16_t dns_txid;
#error DNS_MAX_TTL must be a positive 32-bit value
#endif
#if DNS_TABLE_SIZE > 255
#error DNS_TABLE_SIZE must fit into an u8_t
#endif
#if DNS_MAX_SERVERS > 255
#error DNS_MAX_SERVERS must fit into an u8_t
#endif
/* The number of parallel requests (i.e. calls to dns_gethostbyname
* that cannot be answered from the DNS table.
* This is set to the table size by default.
@ -128,6 +136,10 @@ static u16_t dns_txid;
#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
#ifndef DNS_MAX_REQUESTS
#define DNS_MAX_REQUESTS DNS_TABLE_SIZE
#else
#if DNS_MAX_REQUESTS > 255
#error DNS_MAX_REQUESTS must fit into an u8_t
#endif
#endif
#else
/* In this configuration, both arrays have to have the same size and are used
@ -139,6 +151,10 @@ static u16_t dns_txid;
#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
#ifndef DNS_MAX_SOURCE_PORTS
#define DNS_MAX_SOURCE_PORTS DNS_MAX_REQUESTS
#else
#if DNS_MAX_SOURCE_PORTS > 255
#error DNS_MAX_SOURCE_PORTS must fit into an u8_t
#endif
#endif
#else
#ifdef DNS_MAX_SOURCE_PORTS
@ -165,70 +181,11 @@ static u16_t dns_txid;
#define LWIP_DNS_SET_ADDRTYPE(x, y)
#endif /* LWIP_IPV4 && LWIP_IPV6 */
/** DNS field TYPE used for "Resource Records" */
#define DNS_RRTYPE_A 1 /* a host address */
#define DNS_RRTYPE_NS 2 /* an authoritative name server */
#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */
#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */
#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */
#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */
#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */
#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */
#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */
#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */
#define DNS_RRTYPE_WKS 11 /* a well known service description */
#define DNS_RRTYPE_PTR 12 /* a domain name pointer */
#define DNS_RRTYPE_HINFO 13 /* host information */
#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */
#define DNS_RRTYPE_MX 15 /* mail exchange */
#define DNS_RRTYPE_TXT 16 /* text strings */
#define DNS_RRTYPE_AAAA 28 /* IPv6 address */
/** DNS field CLASS used for "Resource Records" */
#define DNS_RRCLASS_IN 1 /* the Internet */
#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */
#define DNS_RRCLASS_CH 3 /* the CHAOS class */
#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */
#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */
/* DNS protocol flags */
#define DNS_FLAG1_RESPONSE 0x80
#define DNS_FLAG1_OPCODE_STATUS 0x10
#define DNS_FLAG1_OPCODE_INVERSE 0x08
#define DNS_FLAG1_OPCODE_STANDARD 0x00
#define DNS_FLAG1_AUTHORATIVE 0x04
#define DNS_FLAG1_TRUNC 0x02
#define DNS_FLAG1_RD 0x01
#define DNS_FLAG2_RA 0x80
#define DNS_FLAG2_ERR_MASK 0x0f
#define DNS_FLAG2_ERR_NONE 0x00
#define DNS_FLAG2_ERR_NAME 0x03
/* DNS protocol states */
#define DNS_STATE_UNUSED 0
#define DNS_STATE_NEW 1
#define DNS_STATE_ASKING 2
#define DNS_STATE_DONE 3
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
#define LWIP_DNS_ISMDNS_ARG(x) , x
#else
#define LWIP_DNS_ISMDNS_ARG(x)
#endif
PACK_STRUCT_BEGIN
/** DNS message header */
struct dns_hdr {
PACK_STRUCT_FIELD(u16_t id);
PACK_STRUCT_FLD_8(u8_t flags1);
PACK_STRUCT_FLD_8(u8_t flags2);
PACK_STRUCT_FIELD(u16_t numquestions);
PACK_STRUCT_FIELD(u16_t numanswers);
PACK_STRUCT_FIELD(u16_t numauthrr);
PACK_STRUCT_FIELD(u16_t numextrarr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define SIZEOF_DNS_HDR 12
/** DNS query message structure.
No packing needed: only used locally on the stack. */
@ -254,6 +211,14 @@ struct dns_answer {
/* maximum allowed size for the struct due to non-packed */
#define SIZEOF_DNS_ANSWER_ASSERT 12
/* DNS table entry states */
typedef enum {
DNS_STATE_UNUSED = 0,
DNS_STATE_NEW = 1,
DNS_STATE_ASKING = 2,
DNS_STATE_DONE = 3
} dns_state_enum_t;
/** DNS table entry */
struct dns_table_entry {
u32_t ttl;
@ -271,6 +236,9 @@ struct dns_table_entry {
#if LWIP_IPV4 && LWIP_IPV6
u8_t reqaddrtype;
#endif /* LWIP_IPV4 && LWIP_IPV6 */
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
u8_t is_mdns;
#endif
};
/** DNS request table entry: used when dns_gehostbyname cannot answer the
@ -334,39 +302,12 @@ static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS];
static ip_addr_t dns_servers[DNS_MAX_SERVERS];
#ifndef LWIP_DNS_STRICMP
#define LWIP_DNS_STRICMP(str1, str2) dns_stricmp(str1, str2)
/**
* A small but sufficient implementation for case insensitive strcmp.
* This can be defined to e.g. stricmp for windows or strcasecmp for linux. */
static int
dns_stricmp(const char* str1, const char* str2)
{
char c1, c2;
do {
c1 = *str1++;
c2 = *str2++;
if (c1 != c2) {
char c1_upc = c1 | 0x20;
if ((c1_upc >= 'a') && (c1_upc <= 'z')) {
/* characters are not equal an one is in the alphabet range:
downcase both chars and check again */
char c2_upc = c2 | 0x20;
if (c1_upc != c2_upc) {
/* still not equal */
/* don't care for < or > */
return 1;
}
} else {
/* characters are not equal but none is in the alphabet range */
return 1;
}
}
} while (c1 != 0);
return 0;
}
#endif /* LWIP_DNS_STRICMP */
#if LWIP_IPV4
const ip_addr_t dns_mquery_v4group = DNS_MQUERY_IPV4_GROUP_INIT;
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
const ip_addr_t dns_mquery_v6group = DNS_MQUERY_IPV6_GROUP_INIT;
#endif /* LWIP_IPV6 */
/**
* Initialize the resolver: set up the UDP pcb and configure the default server
@ -504,7 +445,7 @@ dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
struct local_hostlist_entry *entry = local_hostlist_dynamic;
while (entry != NULL) {
if ((LWIP_DNS_STRICMP(entry->name, hostname) == 0) &&
if ((lwip_stricmp(entry->name, hostname) == 0) &&
LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, entry->addr)) {
if (addr) {
ip_addr_copy(*addr, entry->addr);
@ -516,7 +457,7 @@ dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
size_t i;
for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) {
if ((LWIP_DNS_STRICMP(local_hostlist_static[i].name, hostname) == 0) &&
if ((lwip_stricmp(local_hostlist_static[i].name, hostname) == 0) &&
LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, local_hostlist_static[i].addr)) {
if (addr) {
ip_addr_copy(*addr, local_hostlist_static[i].addr);
@ -546,7 +487,7 @@ dns_local_removehost(const char *hostname, const ip_addr_t *addr)
struct local_hostlist_entry *entry = local_hostlist_dynamic;
struct local_hostlist_entry *last_entry = NULL;
while (entry != NULL) {
if (((hostname == NULL) || !LWIP_DNS_STRICMP(entry->name, hostname)) &&
if (((hostname == NULL) || !lwip_stricmp(entry->name, hostname)) &&
((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
struct local_hostlist_entry *free_entry;
if (last_entry != NULL) {
@ -635,7 +576,7 @@ dns_lookup(const char *name, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addr
/* Walk through name list, return entry if found. If not, return NULL. */
for (i = 0; i < DNS_TABLE_SIZE; ++i) {
if ((dns_table[i].state == DNS_STATE_DONE) &&
(LWIP_DNS_STRICMP(name, dns_table[i].name) == 0) &&
(lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0) &&
LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, dns_table[i].ipaddr)) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
@ -664,11 +605,14 @@ dns_lookup(const char *name, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addr
static u16_t
dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset)
{
unsigned char n;
int n;
u16_t response_offset = start_offset;
do {
n = pbuf_get_at(p, response_offset++);
n = pbuf_try_get_at(p, response_offset++);
if (n < 0) {
return 0xFFFF;
}
/** @see RFC 1035 - 4.1.4. Message compression */
if ((n & 0xc0) == 0xc0) {
/* Compressed name: cannot be equal since we don't send them */
@ -676,7 +620,11 @@ dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset)
} else {
/* Not compressed name */
while (n > 0) {
if ((*query) != pbuf_get_at(p, response_offset)) {
int c = pbuf_try_get_at(p, response_offset);
if (c < 0) {
return 0xFFFF;
}
if ((*query) != (u8_t)c) {
return 0xFFFF;
}
++response_offset;
@ -685,7 +633,11 @@ dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset)
}
++query;
}
} while (pbuf_get_at(p, response_offset) != 0);
n = pbuf_try_get_at(p, response_offset);
if (n < 0) {
return 0xFFFF;
}
} while (n != 0);
return response_offset + 1;
}
@ -698,26 +650,34 @@ dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset)
* @return index to end of the name
*/
static u16_t
dns_parse_name(struct pbuf* p, u16_t query_idx)
dns_skip_name(struct pbuf* p, u16_t query_idx)
{
unsigned char n;
int n;
u16_t offset = query_idx;
do {
n = pbuf_get_at(p, query_idx++);
n = pbuf_try_get_at(p, offset++);
if (n < 0) {
return 0xFFFF;
}
/** @see RFC 1035 - 4.1.4. Message compression */
if ((n & 0xc0) == 0xc0) {
/* Compressed name */
/* Compressed name: since we only want to skip it (not check it), stop here */
break;
} else {
/* Not compressed name */
while (n > 0) {
++query_idx;
--n;
if (offset + n >= p->tot_len) {
return 0xFFFF;
}
offset = (u16_t)(offset + n);
}
} while (pbuf_get_at(p, query_idx) != 0);
n = pbuf_try_get_at(p, offset);
if (n < 0) {
return 0xFFFF;
}
} while (n != 0);
return query_idx + 1;
return offset + 1;
}
/**
@ -742,7 +702,11 @@ dns_send(u8_t idx)
LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
(u16_t)(entry->server_idx), entry->name));
LWIP_ASSERT("dns server out of array", entry->server_idx < DNS_MAX_SERVERS);
if (ip_addr_isany_val(dns_servers[entry->server_idx])) {
if (ip_addr_isany_val(dns_servers[entry->server_idx])
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
&& !entry->is_mdns
#endif
) {
/* DNS server not valid anymore, e.g. PPP netif has been shut down */
/* call specified callback function if provided */
dns_call_found(idx, NULL);
@ -755,9 +719,11 @@ dns_send(u8_t idx)
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 +
SIZEOF_DNS_QUERY), PBUF_RAM);
if (p != NULL) {
const ip_addr_t* dst;
u16_t dst_port;
/* fill dns header */
memset(&hdr, 0, SIZEOF_DNS_HDR);
hdr.id = htons(entry->txid);
hdr.id = lwip_htons(entry->txid);
hdr.flags1 = DNS_FLAG1_RD;
hdr.numquestions = PP_HTONS(1);
pbuf_take(p, &hdr, SIZEOF_DNS_HDR);
@ -797,7 +763,30 @@ dns_send(u8_t idx)
/* send dns packet */
LWIP_DEBUGF(DNS_DEBUG, ("sending DNS request ID %d for name \"%s\" to server %d\r\n",
entry->txid, entry->name, entry->server_idx));
err = udp_sendto(dns_pcbs[pcb_idx], p, &dns_servers[entry->server_idx], DNS_SERVER_PORT);
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
if (entry->is_mdns) {
dst_port = DNS_MQUERY_PORT;
#if LWIP_IPV6
if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype))
{
dst = &dns_mquery_v6group;
}
#endif
#if LWIP_IPV4 && LWIP_IPV6
else
#endif
#if LWIP_IPV4
{
dst = &dns_mquery_v4group;
}
#endif
} else
#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
{
dst_port = DNS_SERVER_PORT;
dst = &dns_servers[entry->server_idx];
}
err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port);
/* free pbuf */
pbuf_free(p);
@ -982,12 +971,9 @@ dns_check_entry(u8_t i)
LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
switch (entry->state) {
case DNS_STATE_NEW: {
u16_t txid;
case DNS_STATE_NEW:
/* initialize new entry */
txid = dns_create_txid();
entry->txid = txid;
entry->txid = dns_create_txid();
entry->state = DNS_STATE_ASKING;
entry->server_idx = 0;
entry->tmr = 1;
@ -1000,12 +986,14 @@ dns_check_entry(u8_t i)
("dns_send returned error: %s\n", lwip_strerr(err)));
}
break;
}
case DNS_STATE_ASKING:
if (--entry->tmr == 0) {
if (++entry->retries == DNS_MAX_RETRIES) {
if ((entry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[entry->server_idx + 1])) {
if ((entry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[entry->server_idx + 1])
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
&& !entry->is_mdns
#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
) {
/* change of server */
entry->server_idx++;
entry->tmr = 1;
@ -1095,8 +1083,6 @@ dns_correct_response(u8_t idx, u32_t ttl)
}
/**
* Receive input function for DNS response packets arriving for the dns UDP pcb.
*
* @params see udp.h
*/
static void
dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
@ -1123,7 +1109,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
/* copy dns payload inside static buffer for processing */
if (pbuf_copy_partial(p, &hdr, SIZEOF_DNS_HDR, 0) == SIZEOF_DNS_HDR) {
/* Match the ID in the DNS header with the name table. */
txid = htons(hdr.id);
txid = lwip_htons(hdr.id);
for (i = 0; i < DNS_TABLE_SIZE; i++) {
const struct dns_table_entry *entry = &dns_table[i];
if ((entry->state == DNS_STATE_ASKING) &&
@ -1131,8 +1117,8 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
/* We only care about the question(s) and the answers. The authrr
and the extrarr are simply discarded. */
nquestions = htons(hdr.numquestions);
nanswers = htons(hdr.numanswers);
nquestions = lwip_htons(hdr.numquestions);
nanswers = lwip_htons(hdr.numanswers);
/* Check for correct response. */
if ((hdr.flags1 & DNS_FLAG1_RESPONSE) == 0) {
@ -1144,10 +1130,15 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
goto memerr; /* ignore this packet */
}
/* Check whether response comes from the same network address to which the
question was sent. (RFC 5452) */
if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) {
goto memerr; /* ignore this packet */
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
if (!entry->is_mdns)
#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
{
/* Check whether response comes from the same network address to which the
question was sent. (RFC 5452) */
if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) {
goto memerr; /* ignore this packet */
}
}
/* Check if the name in the "question" part match with the name in the entry and
@ -1159,7 +1150,9 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
}
/* check if "question" part matches the request */
pbuf_copy_partial(p, &qry, SIZEOF_DNS_QUERY, res_idx);
if (pbuf_copy_partial(p, &qry, SIZEOF_DNS_QUERY, res_idx) != SIZEOF_DNS_QUERY) {
goto memerr; /* ignore this packet */
}
if ((qry.cls != PP_HTONS(DNS_RRCLASS_IN)) ||
(LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_AAAA))) ||
(!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_A)))) {
@ -1175,11 +1168,17 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
} else {
while ((nanswers > 0) && (res_idx < p->tot_len)) {
/* skip answer resource record's host name */
res_idx = dns_parse_name(p, res_idx);
res_idx = dns_skip_name(p, res_idx);
if (res_idx == 0xFFFF) {
goto memerr; /* ignore this packet */
}
/* Check for IP address type and Internet class. Others are discarded. */
pbuf_copy_partial(p, &ans, SIZEOF_DNS_ANSWER, res_idx);
if (pbuf_copy_partial(p, &ans, SIZEOF_DNS_ANSWER, res_idx) != SIZEOF_DNS_ANSWER) {
goto memerr; /* ignore this packet */
}
res_idx += SIZEOF_DNS_ANSWER;
if (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) {
#if LWIP_IPV4
if ((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.len == PP_HTONS(sizeof(ip4_addr_t)))) {
@ -1189,11 +1188,13 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
{
ip4_addr_t ip4addr;
/* read the IP address after answer resource record's header */
pbuf_copy_partial(p, &ip4addr, sizeof(ip4_addr_t), res_idx);
if (pbuf_copy_partial(p, &ip4addr, sizeof(ip4_addr_t), res_idx) != sizeof(ip4_addr_t)) {
goto memerr; /* ignore this packet */
}
ip_addr_copy_from_ip4(dns_table[i].ipaddr, ip4addr);
pbuf_free(p);
/* handle correct response */
dns_correct_response(i, ntohl(ans.ttl));
dns_correct_response(i, lwip_ntohl(ans.ttl));
return;
}
}
@ -1206,18 +1207,23 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
{
ip6_addr_t ip6addr;
/* read the IP address after answer resource record's header */
pbuf_copy_partial(p, &ip6addr, sizeof(ip6_addr_t), res_idx);
if (pbuf_copy_partial(p, &ip6addr, sizeof(ip6_addr_t), res_idx) != sizeof(ip6_addr_t)) {
goto memerr; /* ignore this packet */
}
ip_addr_copy_from_ip6(dns_table[i].ipaddr, ip6addr);
pbuf_free(p);
/* handle correct response */
dns_correct_response(i, ntohl(ans.ttl));
dns_correct_response(i, lwip_ntohl(ans.ttl));
return;
}
}
#endif /* LWIP_IPV6 */
}
/* skip this answer */
res_idx += htons(ans.len);
if ((int)(res_idx + lwip_htons(ans.len)) > 0xFFFF) {
goto memerr; /* ignore this packet */
}
res_idx += lwip_htons(ans.len);
--nanswers;
}
#if LWIP_IPV4 && LWIP_IPV6
@ -1260,11 +1266,11 @@ memerr:
* @param hostnamelen length of the hostname
* @param found a callback function to be called on success, failure or timeout
* @param callback_arg argument to pass to the callback function
* @return @return a err_t return code.
* @return err_t return code.
*/
static err_t
dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found,
void *callback_arg LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype))
void *callback_arg LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype) LWIP_DNS_ISMDNS_ARG(u8_t is_mdns))
{
u8_t i;
u8_t lseq, lseqi;
@ -1277,7 +1283,7 @@ dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found,
/* check for duplicate entries */
for (i = 0; i < DNS_TABLE_SIZE; i++) {
if ((dns_table[i].state == DNS_STATE_ASKING) &&
(LWIP_DNS_STRICMP(name, dns_table[i].name) == 0)) {
(lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0)) {
#if LWIP_IPV4 && LWIP_IPV6
if (dns_table[i].reqaddrtype != dns_addrtype) {
/* requested address types don't match
@ -1313,8 +1319,9 @@ dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found,
}
/* check if this is the oldest completed entry */
if (entry->state == DNS_STATE_DONE) {
if ((u8_t)(dns_seqno - entry->seqno) > lseq) {
lseq = dns_seqno - entry->seqno;
u8_t age = dns_seqno - entry->seqno;
if (age > lseq) {
lseq = age;
lseqi = i;
}
}
@ -1379,6 +1386,10 @@ dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found,
LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS pcb %"U16_F"\n", name, (u16_t)(entry->pcb_idx)));
#endif
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
entry->is_mdns = is_mdns;
#endif
dns_seqno++;
/* force to send query without waiting timer */
@ -1424,7 +1435,7 @@ dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback foun
* @param found a callback function to be called on success, failure or timeout (only if
* ERR_INPROGRESS is returned!)
* @param callback_arg argument to pass to the callback function
* @param dns_addrtype: - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 first, try IPv6 if IPv4 fails only
* @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 first, try IPv6 if IPv4 fails only
* - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 first, try IPv4 if IPv6 fails only
* - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only
* - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only
@ -1434,6 +1445,9 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call
void *callback_arg, u8_t dns_addrtype)
{
size_t hostnamelen;
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
u8_t is_mdns;
#endif
/* not initialized or no valid server yet, or invalid addr pointer
* or invalid hostname or invalid hostname length */
if ((addr == NULL) ||
@ -1490,13 +1504,25 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call
LWIP_UNUSED_ARG(dns_addrtype);
#endif /* LWIP_IPV4 && LWIP_IPV6 */
/* prevent calling found callback if no server is set, return error instead */
if (ip_addr_isany_val(dns_servers[0])) {
return ERR_VAL;
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
if (strstr(hostname, ".local") == &hostname[hostnamelen] - 6) {
is_mdns = 1;
} else {
is_mdns = 0;
}
if (!is_mdns)
#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
{
/* prevent calling found callback if no server is set, return error instead */
if (ip_addr_isany_val(dns_servers[0])) {
return ERR_VAL;
}
}
/* queue query with specified callback */
return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype));
return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)
LWIP_DNS_ISMDNS_ARG(is_mdns));
}
#endif /* LWIP_DNS */

View File

@ -1,7 +1,16 @@
/**
* @file
* Incluse internet checksum functions.
* Incluse internet checksum functions.\n
*
* These are some reference implementations of the checksum algorithm, with the
* aim of being simple, correct and fully portable. Checksumming is the
* first thing you would want to optimize for your platform. If you create
* your own version, link it in and in your cc.h put:
*
* \#define LWIP_CHKSUM your_checksum_routine
*
* Or you can select from the implementations below by defining
* LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
*/
/*
@ -42,20 +51,8 @@
#include "lwip/def.h"
#include "lwip/ip_addr.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
* first thing you would want to optimize for your platform. If you create
* your own version, link it in and in your cc.h put:
*
* #define LWIP_CHKSUM <your_checksum_routine>
*
* Or you can select from the implementations below by defining
* LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
*/
#ifndef LWIP_CHKSUM
# define LWIP_CHKSUM lwip_standard_chksum
# ifndef LWIP_CHKSUM_ALGORITHM
@ -110,10 +107,10 @@ lwip_standard_chksum(const void *dataptr, int len)
if ((acc & 0xffff0000UL) != 0) {
acc = (acc >> 16) + (acc & 0x0000ffffUL);
}
/* This maybe a little confusing: reorder sum using htons()
instead of ntohs() since it has a little less call overhead.
/* This maybe a little confusing: reorder sum using lwip_htons()
instead of lwip_ntohs() since it has a little less call overhead.
The caller must invert bits for Internet sum ! */
return htons((u16_t)acc);
return lwip_htons((u16_t)acc);
}
#endif
@ -285,8 +282,8 @@ inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc)
acc = SWAP_BYTES_IN_WORD(acc);
}
acc += (u32_t)htons((u16_t)proto);
acc += (u32_t)htons(proto_len);
acc += (u32_t)lwip_htons((u16_t)proto);
acc += (u32_t)lwip_htons(proto_len);
/* Fold 32-bit sum to 16 bits
calling this twice is probably faster than if statements... */
@ -431,8 +428,8 @@ inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len,
acc = SWAP_BYTES_IN_WORD(acc);
}
acc += (u32_t)htons((u16_t)proto);
acc += (u32_t)htons(proto_len);
acc += (u32_t)lwip_htons((u16_t)proto);
acc += (u32_t)lwip_htons(proto_len);
/* Fold 32-bit sum to 16 bits
calling this twice is probably faster than if statements... */

View File

@ -35,27 +35,6 @@
* Author: Adam Dunkels <adam@sics.se>
*/
/**
* @defgroup lwip_nosys Mainloop mode ("NO_SYS")
* @ingroup lwip
* Use this mode if you do not run an OS on your system. \#define NO_SYS to 1.
* Feed incoming packets to netif->input(pbuf, netif) function from mainloop,
* *not* *from* *interrupt* *context*. You can allocate a @ref pbuf in interrupt
* context and put them into a queue which is processed from mainloop.\n
* Call sys_check_timeouts() periodically in the mainloop.\n
* Porting: implement all functions in @ref sys_time and @ref sys_prot.\n
* You can only use @ref callbackstyle_api in this mode.
*
* @defgroup lwip_os OS mode (TCPIP thread)
* @ingroup lwip
* Use this mode if you run an OS on your system. It is recommended to
* use an RTOS that correctly handles priority inversion and
* to use LWIP_TCPIP_CORE_LOCKING.\n
* Porting: implement all functions in @ref sys_layer.\n
* You can use @ref callbackstyle_api together with \#define tcpip_callback,
* and all @ref threadsafe_api.
*/
#include "lwip/opt.h"
#include "lwip/init.h"
@ -70,7 +49,6 @@
#include "lwip/raw.h"
#include "lwip/udp.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/autoip.h"
#include "lwip/igmp.h"
#include "lwip/dns.h"
#include "lwip/timeouts.h"
@ -83,6 +61,25 @@
#include "netif/ppp/ppp_opts.h"
#include "netif/ppp/ppp_impl.h"
#ifndef LWIP_SKIP_PACKING_CHECK
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct packed_struct_test
{
PACK_STRUCT_FLD_8(u8_t dummy1);
PACK_STRUCT_FIELD(u32_t dummy2);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define PACKED_STRUCT_TEST_EXPECTED_SIZE 5
#endif
/* Compile-time sanity checks for configuration errors.
* These can be done independently of LWIP_DEBUG, without penalty.
*/
@ -144,7 +141,7 @@
#if (LWIP_TCP && (TCP_WND > 0xffffffff))
#error "If you want to use TCP, TCP_WND must fit in an u32_t, so, you have to reduce it in your lwipopts.h"
#endif
#if (LWIP_TCP && LWIP_WND_SCALE && (TCP_RCV_SCALE > 14))
#if (LWIP_TCP && (TCP_RCV_SCALE > 14))
#error "The maximum valid window scale value is 14!"
#endif
#if (LWIP_TCP && (TCP_WND > (0xFFFFU << TCP_RCV_SCALE)))
@ -222,7 +219,7 @@
#error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT"
#endif
#if (LWIP_IGMP || LWIP_IPV6) && !defined(LWIP_RAND)
#error "When using IGMP or IPv6, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value"
#error "When using IGMP or IPv6, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value (in arch/cc.h)"
#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"
@ -230,9 +227,6 @@
#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
#if LWIP_NETCONN && LWIP_TCP
#if NETCONN_COPY != TCP_WRITE_FLAG_COPY
#error "NETCONN_COPY != TCP_WRITE_FLAG_COPY"
@ -325,10 +319,10 @@
#if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN
#error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if !MEMP_MEM_MALLOC && (PBUF_POOL_BUFSIZE <= (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))
#if !MEMP_MEM_MALLOC && PBUF_POOL_SIZE && (PBUF_POOL_BUFSIZE <= (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))
#error "lwip_sanity_check: WARNING: PBUF_POOL_BUFSIZE does not provide enough space for protocol headers. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if !MEMP_MEM_MALLOC && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))))
#if !MEMP_MEM_MALLOC && PBUF_POOL_SIZE && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))))
#error "lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - protocol headers). If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if TCP_WND < TCP_MSS
@ -345,6 +339,15 @@
void
lwip_init(void)
{
#ifndef LWIP_SKIP_CONST_CHECK
int a;
LWIP_UNUSED_ARG(a);
LWIP_ASSERT("LWIP_CONST_CAST not implemented correctly. Check your lwIP port.", LWIP_CONST_CAST(void*, &a) == &a);
#endif
#ifndef LWIP_SKIP_PACKING_CHECK
LWIP_ASSERT("Struct packing not implemented correctly. Check your lwIP port.", sizeof(struct packed_struct_test) == PACKED_STRUCT_TEST_EXPECTED_SIZE);
#endif
/* Modules initialization */
stats_init();
#if !NO_SYS
@ -369,9 +372,6 @@ lwip_init(void)
#if LWIP_TCP
tcp_init();
#endif /* LWIP_TCP */
#if LWIP_AUTOIP
autoip_init();
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
igmp_init();
#endif /* LWIP_IGMP */

View File

@ -1,7 +1,24 @@
/**
* @file ip.c
* @file
* Common IPv4 and IPv6 code
*
* @defgroup ip IP
* @ingroup callbackstyle_api
*
* @defgroup ip4 IPv4
* @ingroup ip
*
* @defgroup ip6 IPv6
* @ingroup ip
*
* @defgroup ipaddr IP address handling
* @ingroup infrastructure
*
* @defgroup ip4addr IPv4 only
* @ingroup ipaddr
*
* @defgroup ip6addr IPv6 only
* @ingroup ipaddr
*/
/*
@ -36,23 +53,6 @@
*
*/
/**
* @defgroup ip4 IPv4
* @ingroup callbackstyle_api
*
* @defgroup ip6 IPv6
* @ingroup callbackstyle_api
*
* @defgroup ipaddr IP address handling
* @ingroup infrastructure
*
* @defgroup ip4addr IPv4 only
* @ingroup ipaddr
*
* @defgroup ip6addr IPv6 only
* @ingroup ipaddr
*/
#include "lwip/opt.h"
#if LWIP_IPV4 || LWIP_IPV6

View File

@ -9,7 +9,7 @@
*
* To let mem_malloc() use pools (prevents fragmentation and is much faster than
* a heap but might waste some memory), define MEM_USE_POOLS to 1, define
* MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list
* MEMP_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list
* of pools like this (more pools can be added between _START and _END):
*
* Define three pools with sizes 256, 512, and 1512 bytes
@ -54,15 +54,20 @@
*/
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/stats.h"
#include "lwip/err.h"
#include <string.h>
#if MEM_LIBC_MALLOC
#include <stdlib.h> /* for malloc()/free() */
#endif
#if MEM_LIBC_MALLOC || MEM_USE_POOLS
/** mem_init is not used when using pools instead of a heap or using
* C library malloc().
*/
@ -161,17 +166,26 @@ void *
mem_malloc(mem_size_t size)
{
void *ret;
struct memp_malloc_helper *element;
struct memp_malloc_helper *element = NULL;
memp_t poolnr;
mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));
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 */
/* is this pool big enough to hold an element of the required size
plus a struct memp_malloc_helper that saves the pool this element came from? */
if (required_size <= memp_pools[poolnr]->size) {
element = (struct memp_malloc_helper*)memp_malloc(poolnr);
if (element == NULL) {
/* No need to DEBUGF or ASSERT: This error is already taken care of in memp.c */
#if MEM_USE_POOLS_TRY_BIGGER_POOL
/** Try a bigger pool if this one is empty! */
if (poolnr < MEMP_POOL_LAST) {
continue;
}
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
MEM_STATS_INC(err);
return NULL;
}
break;
}
}
@ -180,20 +194,6 @@ again:
MEM_STATS_INC(err);
return NULL;
}
element = (struct memp_malloc_helper*)memp_malloc(poolnr);
if (element == NULL) {
/* No need to DEBUGF or ASSERT: This error is already
taken care of in memp.c */
#if MEM_USE_POOLS_TRY_BIGGER_POOL
/** Try a bigger pool if this one is empty! */
if (poolnr < MEMP_POOL_LAST) {
poolnr++;
goto again;
}
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
MEM_STATS_INC(err);
return NULL;
}
/* save the pool number this element came from */
element->poolnr = poolnr;

View File

@ -4,6 +4,11 @@
*
* lwIP has dedicated pools for many structures (netconn, protocol control blocks,
* packet buffers, ...). All these pools are managed here.
*
* @defgroup mempool Memory pools
* @ingroup infrastructure
* Custom memory pools
*/
/*
@ -38,12 +43,6 @@
*
*/
/**
* @defgroup mempool Memory pools
* @ingroup infrastructure
* Custom memory pools
*/
#include "lwip/opt.h"
#include "lwip/memp.h"
@ -72,7 +71,7 @@
#include "netif/ppp/ppp_opts.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "lwip/nd6.h"
#include "lwip/priv/nd6_priv.h"
#include "lwip/ip6_frag.h"
#include "lwip/mld6.h"
@ -120,14 +119,14 @@ memp_sanity(const struct memp_desc *desc)
* (e.g. the restricted area after it has been altered)
*
* @param p the memp element to check
* @param memp_type the pool p comes from
* @param desc the pool p comes from
*/
static void
memp_overflow_check_element_overflow(struct memp *p, const struct memp_desc *desc)
{
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
u16_t k;
u8_t *m;
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE + desc->size;
for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
if (m[k] != 0xcd) {
@ -136,7 +135,10 @@ memp_overflow_check_element_overflow(struct memp *p, const struct memp_desc *des
LWIP_ASSERT(errstr, 0);
}
}
#endif
#else /* MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
LWIP_UNUSED_ARG(p);
LWIP_UNUSED_ARG(desc);
#endif /* MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
}
/**
@ -144,14 +146,14 @@ memp_overflow_check_element_overflow(struct memp *p, const struct memp_desc *des
* (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
* @param desc the pool p comes from
*/
static void
memp_overflow_check_element_underflow(struct memp *p, const struct memp_desc *desc)
{
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
u16_t k;
u8_t *m;
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
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) {
@ -160,7 +162,10 @@ memp_overflow_check_element_underflow(struct memp *p, const struct memp_desc *de
LWIP_ASSERT(errstr, 0);
}
}
#endif
#else /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 */
LWIP_UNUSED_ARG(p);
LWIP_UNUSED_ARG(desc);
#endif /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 */
}
/**
@ -169,6 +174,7 @@ memp_overflow_check_element_underflow(struct memp *p, const struct memp_desc *de
static void
memp_overflow_init_element(struct memp *p, const struct memp_desc *desc)
{
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 || MEMP_SANITY_REGION_AFTER_ALIGNED > 0
u8_t *m;
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
@ -178,6 +184,10 @@ memp_overflow_init_element(struct memp *p, const struct memp_desc *desc)
m = (u8_t*)p + MEMP_SIZE + desc->size;
memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
#endif
#else /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 || MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
LWIP_UNUSED_ARG(p);
LWIP_UNUSED_ARG(desc);
#endif /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 || MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
}
#if MEMP_OVERFLOW_CHECK >= 2
@ -195,34 +205,16 @@ memp_overflow_check_all(void)
SYS_ARCH_PROTECT(old_level);
for (i = 0; i < MEMP_MAX; ++i) {
p = (struct memp *)(size_t)(memp_pools[i]->base);
p = (struct memp*)LWIP_MEM_ALIGN(memp_pools[i]->base);
for (j = 0; j < memp_pools[i]->num; ++j) {
memp_overflow_check_element_overflow(p, memp_pools[i]);
memp_overflow_check_element_underflow(p, memp_pools[i]);
p = (struct memp*)(size_t)((u8_t*)p + MEMP_SIZE + memp_pools[i]->size + MEMP_SANITY_REGION_AFTER_ALIGNED);
p = LWIP_ALIGNMENT_CAST(struct memp*, ((u8_t*)p + MEMP_SIZE + memp_pools[i]->size + MEMP_SANITY_REGION_AFTER_ALIGNED));
}
}
SYS_ARCH_UNPROTECT(old_level);
}
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
#if !MEMP_MEM_MALLOC
/**
* Initialize the restricted areas of all memp elements in a pool.
*/
static void
memp_overflow_init(const struct memp_desc *desc)
{
u16_t i;
struct memp *p;
p = (struct memp*)LWIP_MEM_ALIGN(desc->base);
for (i = 0; i < desc->num; ++i) {
memp_overflow_init_element(p, desc);
p = (struct memp*)(size_t)((u8_t*)p + MEMP_SIZE + desc->size + MEMP_SANITY_REGION_AFTER_ALIGNED);
}
}
#endif /* !MEMP_MEM_MALLOC */
#endif /* MEMP_OVERFLOW_CHECK */
/**
@ -246,6 +238,9 @@ memp_init_pool(const struct memp_desc *desc)
for (i = 0; i < desc->num; ++i) {
memp->next = *desc->tab;
*desc->tab = memp;
#if MEMP_OVERFLOW_CHECK
memp_overflow_init_element(memp, desc);
#endif /* MEMP_OVERFLOW_CHECK */
/* cast through void* to get rid of alignment warnings */
memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size
#if MEMP_OVERFLOW_CHECK
@ -253,21 +248,14 @@ memp_init_pool(const struct memp_desc *desc)
#endif
);
}
#if MEMP_OVERFLOW_CHECK
memp_overflow_init(desc);
#endif /* MEMP_OVERFLOW_CHECK */
#endif /* !MEMP_MEM_MALLOC */
#if MEMP_STATS
#if !MEMP_MEM_MALLOC
desc->stats->avail = desc->num;
#endif /* MEMP_STATS */
#endif /* !MEMP_MEM_MALLOC */
#if defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY
#if MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY)
desc->stats->name = desc->desc;
#endif /* defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY */
#endif /* MEMP_STATS */
#endif /* MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY) */
}
/**
@ -313,15 +301,15 @@ do_memp_malloc_pool_fn(const struct memp_desc *desc, const char* file, const int
SYS_ARCH_PROTECT(old_level);
memp = *desc->tab;
#if MEMP_OVERFLOW_CHECK == 1
memp_overflow_check_element_overflow(memp, desc);
memp_overflow_check_element_underflow(memp, desc);
#endif /* MEMP_OVERFLOW_CHECK */
#endif /* MEMP_MEM_MALLOC */
if (memp != NULL) {
#if !MEMP_MEM_MALLOC
#if MEMP_OVERFLOW_CHECK == 1
memp_overflow_check_element_overflow(memp, desc);
memp_overflow_check_element_underflow(memp, desc);
#endif /* MEMP_OVERFLOW_CHECK */
*desc->tab = memp->next;
#if MEMP_OVERFLOW_CHECK
memp->next = NULL;
@ -483,12 +471,16 @@ memp_free(memp_t type, void *mem)
LWIP_ERROR("memp_free: type < MEMP_MAX", (type < MEMP_MAX), return;);
if (mem == NULL) {
return;
}
#if MEMP_OVERFLOW_CHECK >= 2
memp_overflow_check_all();
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
#ifdef LWIP_HOOK_MEMP_AVAILABLE
old_first = memp_pools[type].tab;
old_first = *memp_pools[type]->tab;
#endif
do_memp_free_pool(memp_pools[type], mem);

View File

@ -1,6 +1,20 @@
/**
* @file
* lwIP network interface abstraction
*
* @defgroup netif Network interface (NETIF)
* @ingroup callbackstyle_api
*
* @defgroup netif_ip4 IPv4 address handling
* @ingroup netif
*
* @defgroup netif_ip6 IPv6 address handling
* @ingroup netif
*
* @defgroup netif_cd Client data handling
* Store data (void*) on a netif for application usage.
* @see @ref LWIP_NUM_NETIF_CLIENT_DATA
* @ingroup netif
*/
/*
@ -34,31 +48,31 @@
* Author: Adam Dunkels <adam@sics.se>
*/
/**
* @defgroup netif Network interface (NETIF)
* @ingroup callbackstyle_api
*/
#include "lwip/opt.h"
#include <string.h>
#include "lwip/def.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/udp.h"
#include "lwip/raw.h"
#include "lwip/snmp.h"
#include "lwip/igmp.h"
#include "lwip/etharp.h"
#include "lwip/stats.h"
#include "lwip/sys.h"
#include "lwip/ip.h"
#if ENABLE_LOOPBACK
#include "lwip/sys.h"
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
#include "lwip/tcpip.h"
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
#endif /* ENABLE_LOOPBACK */
#include "netif/lwip_ethernet.h"
#if LWIP_AUTOIP
#include "lwip/autoip.h"
#endif /* LWIP_AUTOIP */
@ -92,6 +106,10 @@ struct netif *netif_default;
static u8_t netif_num;
#if LWIP_NUM_NETIF_CLIENT_DATA > 0
static u8_t netif_client_id;
#endif
#define NETIF_REPORT_TYPE_IPV4 0x01
#define NETIF_REPORT_TYPE_IPV6 0x02
static void netif_issue_reports(struct netif* netif, u8_t report_type);
@ -162,7 +180,7 @@ netif_init(void)
#endif /* NO_SYS */
#if LWIP_IPV6
IP_ADDR6(loop_netif.ip6_addr, 0, 0, 0, PP_HTONL(0x00000001UL));
IP_ADDR6_HOST(loop_netif.ip6_addr, 0, 0, 0, 0x00000001UL);
loop_netif.ip6_addr_state[0] = IP6_ADDR_VALID;
#endif /* LWIP_IPV6 */
@ -210,8 +228,13 @@ netif_input(struct pbuf *p, struct netif *inp)
* These functions use netif flags NETIF_FLAG_ETHARP and NETIF_FLAG_ETHERNET
* to decide whether to forward to ethernet_input() or ip_input().
* In other words, the functions only work when the netif
* driver is implemented correctly!
*
* driver is implemented correctly!\n
* Most members of struct netif should be be initialized by the
* netif init function = netif driver (init parameter of this function).\n
* IPv6: Don't forget to call netif_create_ip6_linklocal_address() after
* setting the MAC address in struct netif.hwaddr
* (IPv6 requires a link-local address).
*
* @return netif, or NULL if failed.
*/
struct netif *
@ -236,20 +259,15 @@ netif_add(struct netif *netif,
#if LWIP_IPV6
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
ip_addr_set_zero_ip6(&netif->ip6_addr[i]);
netif->ip6_addr_state[0] = IP6_ADDR_INVALID;
netif->ip6_addr_state[i] = IP6_ADDR_INVALID;
}
netif->output_ip6 = netif_null_output_ip6;
#endif /* LWIP_IPV6 */
NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL);
netif->flags = 0;
#if LWIP_DHCP
/* netif not under DHCP control by default */
netif->dhcp = NULL;
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
/* netif not under AutoIP control by default */
netif->autoip = NULL;
#endif /* LWIP_AUTOIP */
#ifdef netif_get_client_data
memset(netif->client_data, 0, sizeof(netif->client_data));
#endif /* LWIP_NUM_NETIF_CLIENT_DATA */
#if LWIP_IPV6_AUTOCONFIG
/* IPv6 address autoconfiguration not enabled by default */
netif->ip6_autoconfig_enabled = 0;
@ -257,10 +275,6 @@ netif_add(struct netif *netif,
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT;
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
#if LWIP_IPV6_DHCP6
/* netif not under DHCPv6 control by default */
netif->dhcp6 = NULL;
#endif /* LWIP_IPV6_DHCP6 */
#if LWIP_NETIF_STATUS_CALLBACK
netif->status_callback = NULL;
#endif /* LWIP_NETIF_STATUS_CALLBACK */
@ -325,7 +339,7 @@ netif_add(struct netif *netif,
#if LWIP_IPV4
/**
* @ingroup netif
* @ingroup netif_ip4
* Change IP address configuration for a network interface (including netmask
* and default gateway).
*
@ -362,6 +376,10 @@ netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *
void
netif_remove(struct netif *netif)
{
#if LWIP_IPV6
int i;
#endif
if (netif == NULL) {
return;
}
@ -369,9 +387,14 @@ netif_remove(struct netif *netif)
#if LWIP_IPV4
if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) {
#if LWIP_TCP
tcp_netif_ipv4_addr_changed(netif_ip4_addr(netif), NULL);
tcp_netif_ip_addr_changed(netif_ip_addr4(netif), NULL);
#endif /* LWIP_TCP */
/* cannot do this for UDP, as there is no 'err' callback in udp pcbs */
#if LWIP_UDP
udp_netif_ip_addr_changed(netif_ip_addr4(netif), NULL);
#endif /* LWIP_UDP */
#if LWIP_RAW
raw_netif_ip_addr_changed(netif_ip_addr4(netif), NULL);
#endif /* LWIP_RAW */
}
#if LWIP_IGMP
@ -382,10 +405,25 @@ netif_remove(struct netif *netif)
#endif /* LWIP_IGMP */
#endif /* LWIP_IPV4*/
#if LWIP_IPV6 && LWIP_IPV6_MLD
#if LWIP_IPV6
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) {
#if LWIP_TCP
tcp_netif_ip_addr_changed(netif_ip_addr6(netif, i), NULL);
#endif /* LWIP_TCP */
#if LWIP_UDP
udp_netif_ip_addr_changed(netif_ip_addr6(netif, i), NULL);
#endif /* LWIP_UDP */
#if LWIP_RAW
raw_netif_ip_addr_changed(netif_ip_addr6(netif, i), NULL);
#endif /* LWIP_RAW */
}
}
#if LWIP_IPV6_MLD
/* stop MLD processing */
mld6_stop(netif);
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
#endif /* LWIP_IPV6_MLD */
#endif /* LWIP_IPV6 */
if (netif_is_up(netif)) {
/* set netif down before removing (call callback function) */
netif_set_down(netif);
@ -440,7 +478,7 @@ netif_find(const char *name)
return NULL;
}
num = name[2] - '0';
num = (u8_t)(name[2] - '0');
for (netif = netif_list; netif != NULL; netif = netif->next) {
if (num == netif->num &&
@ -456,7 +494,7 @@ netif_find(const char *name)
#if LWIP_IPV4
/**
* @ingroup netif
* @ingroup netif_ip4
* Change the IP address of a network interface
*
* @param netif the network interface to change
@ -468,16 +506,22 @@ netif_find(const char *name)
void
netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr)
{
ip4_addr_t new_addr = (ipaddr ? *ipaddr : *IP4_ADDR_ANY);
ip_addr_t new_addr;
*ip_2_ip4(&new_addr) = (ipaddr ? *ipaddr : *IP4_ADDR_ANY4);
IP_SET_TYPE_VAL(new_addr, IPADDR_TYPE_V4);
/* address is actually being changed? */
if (ip4_addr_cmp(&new_addr, netif_ip4_addr(netif)) == 0) {
if (ip4_addr_cmp(ip_2_ip4(&new_addr), netif_ip4_addr(netif)) == 0) {
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
#if LWIP_TCP
tcp_netif_ipv4_addr_changed(netif_ip4_addr(netif), ipaddr);
tcp_netif_ip_addr_changed(netif_ip_addr4(netif), &new_addr);
#endif /* LWIP_TCP */
#if LWIP_UDP
udp_netif_ipv4_addr_changed(netif_ip4_addr(netif), ipaddr);
udp_netif_ip_addr_changed(netif_ip_addr4(netif), &new_addr);
#endif /* LWIP_UDP */
#if LWIP_RAW
raw_netif_ip_addr_changed(netif_ip_addr4(netif), &new_addr);
#endif /* LWIP_RAW */
mib2_remove_ip4(netif);
mib2_remove_route_ip4(0, netif);
@ -501,7 +545,7 @@ netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr)
}
/**
* @ingroup netif
* @ingroup netif_ip4
* Change the default gateway for a network interface
*
* @param netif the network interface to change
@ -523,7 +567,7 @@ netif_set_gw(struct netif *netif, const ip4_addr_t *gw)
}
/**
* @ingroup netif
* @ingroup netif_ip4
* Change the netmask of a network interface
*
* @param netif the network interface to change
@ -694,15 +738,11 @@ netif_set_link_up(struct netif *netif)
netif->flags |= NETIF_FLAG_LINK_UP;
#if LWIP_DHCP
if (netif->dhcp) {
dhcp_network_changed(netif);
}
dhcp_network_changed(netif);
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
if (netif->autoip) {
autoip_network_changed(netif);
}
autoip_network_changed(netif);
#endif /* LWIP_AUTOIP */
if (netif->flags & NETIF_FLAG_UP) {
@ -761,7 +801,7 @@ netif_loop_output(struct netif *netif, struct pbuf *p)
err_t err;
struct pbuf *last;
#if LWIP_LOOPBACK_MAX_PBUFS
u8_t clen = 0;
u16_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'. */
@ -864,7 +904,6 @@ netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t* ad
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 MIB2_STATS
@ -876,56 +915,52 @@ netif_poll(struct netif *netif)
#endif /* MIB2_STATS */
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) {
struct pbuf *in_end = in;
/* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
SYS_ARCH_PROTECT(lev);
while (netif->loop_first != NULL) {
struct pbuf *in, *in_end;
#if LWIP_LOOPBACK_MAX_PBUFS
u8_t clen = 1;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
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;
#if LWIP_LOOPBACK_MAX_PBUFS
clen++;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
}
#if LWIP_LOOPBACK_MAX_PBUFS
/* adjust the number of pbufs on queue */
LWIP_ASSERT("netif->loop_cnt_current underflow",
((netif->loop_cnt_current - clen) < netif->loop_cnt_current));
netif->loop_cnt_current -= clen;
u8_t clen = 1;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
/* 'in_end' now points to the last pbuf from 'in' */
if (in_end == netif->loop_last) {
/* this was the last pbuf in the list */
netif->loop_first = netif->loop_last = NULL;
} else {
/* pop the pbuf off the list */
netif->loop_first = in_end->next;
LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL);
}
/* De-queue the pbuf from its successors on the 'loop_' list. */
in_end->next = NULL;
in = in_end = netif->loop_first;
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;
#if LWIP_LOOPBACK_MAX_PBUFS
clen++;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
}
#if LWIP_LOOPBACK_MAX_PBUFS
/* adjust the number of pbufs on queue */
LWIP_ASSERT("netif->loop_cnt_current underflow",
((netif->loop_cnt_current - clen) < netif->loop_cnt_current));
netif->loop_cnt_current -= clen;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
/* 'in_end' now points to the last pbuf from 'in' */
if (in_end == netif->loop_last) {
/* this was the last pbuf in the list */
netif->loop_first = netif->loop_last = NULL;
} else {
/* pop the pbuf off the list */
netif->loop_first = in_end->next;
LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL);
}
/* De-queue the pbuf from its successors on the 'loop_' list. */
in_end->next = NULL;
SYS_ARCH_UNPROTECT(lev);
if (in != NULL) {
LINK_STATS_INC(link.recv);
MIB2_STATS_NETIF_ADD(stats_if, ifinoctets, in->tot_len);
MIB2_STATS_NETIF_INC(stats_if, ifinucastpkts);
/* loopback packets are always IP packets! */
if (ip_input(in, netif) != ERR_OK) {
pbuf_free(in);
}
/* Don't reference the packet any more! */
in = NULL;
LINK_STATS_INC(link.recv);
MIB2_STATS_NETIF_ADD(stats_if, ifinoctets, in->tot_len);
MIB2_STATS_NETIF_INC(stats_if, ifinucastpkts);
/* loopback packets are always IP packets! */
if (ip_input(in, netif) != ERR_OK) {
pbuf_free(in);
}
/* go on while there is a packet on the list */
} while (netif->loop_first != NULL);
SYS_ARCH_PROTECT(lev);
}
SYS_ARCH_UNPROTECT(lev);
}
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
@ -946,15 +981,53 @@ netif_poll_all(void)
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
#endif /* ENABLE_LOOPBACK */
#if LWIP_NUM_NETIF_CLIENT_DATA > 0
/**
* @ingroup netif_cd
* Allocate an index to store data in client_data member of struct netif.
* Returned value is an index in mentioned array.
* @see LWIP_NUM_NETIF_CLIENT_DATA
*/
u8_t
netif_alloc_client_data_id(void)
{
u8_t result = netif_client_id;
netif_client_id++;
LWIP_ASSERT("Increase LWIP_NUM_NETIF_CLIENT_DATA in lwipopts.h", result < LWIP_NUM_NETIF_CLIENT_DATA);
return result + LWIP_NETIF_CLIENT_DATA_INDEX_MAX;
}
#endif
#if LWIP_IPV6
/**
* @ingroup netif_ip6
* Change an IPv6 address of a network interface
*
* @param netif the network interface to change
* @param addr_idx index of the IPv6 address
* @param addr6 the new IPv6 address
*
* @note call netif_ip6_addr_set_state() to set the address valid/temptative
*/
void
netif_ip6_addr_set(struct netif *netif, s8_t addr_idx, ip6_addr_t *addr6)
netif_ip6_addr_set(struct netif *netif, s8_t addr_idx, const ip6_addr_t *addr6)
{
LWIP_ASSERT("addr6 != NULL", addr6 != NULL);
netif_ip6_addr_set_parts(netif, addr_idx, addr6->addr[0], addr6->addr[1],
addr6->addr[2], addr6->addr[3]);
}
/*
* Change an IPv6 address of a network interface (internal version taking 4 * u32_t)
*
* @param netif the network interface to change
* @param addr_idx index of the IPv6 address
* @param i0 word0 of the new IPv6 address
* @param i1 word1 of the new IPv6 address
* @param i2 word2 of the new IPv6 address
* @param i3 word3 of the new IPv6 address
*/
void
netif_ip6_addr_set_parts(struct netif *netif, s8_t addr_idx, u32_t i0, u32_t i1, u32_t i2, u32_t i3)
{
@ -968,7 +1041,21 @@ netif_ip6_addr_set_parts(struct netif *netif, s8_t addr_idx, u32_t i0, u32_t i1,
(old_addr->addr[2] != i2) || (old_addr->addr[3] != i3)) {
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set: netif address being changed\n"));
/* @todo: tcp_netif_ipv6_addr_changed()/udp_netif_ipv6_addr_changed() */
if (netif_ip6_addr_state(netif, addr_idx) & IP6_ADDR_VALID) {
#if LWIP_TCP || LWIP_UDP
ip_addr_t new_ipaddr;
IP_ADDR6(&new_ipaddr, i0, i1, i2, i3);
#endif /* LWIP_TCP || LWIP_UDP */
#if LWIP_TCP
tcp_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), &new_ipaddr);
#endif /* LWIP_TCP */
#if LWIP_UDP
udp_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), &new_ipaddr);
#endif /* LWIP_UDP */
#if LWIP_RAW
raw_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), &new_ipaddr);
#endif /* LWIP_RAW */
}
/* @todo: remove/readd mib2 ip6 entries? */
IP6_ADDR(ip_2_ip6(&(netif->ip6_addr[addr_idx])), i0, i1, i2, i3);
@ -985,6 +1072,16 @@ netif_ip6_addr_set_parts(struct netif *netif, s8_t addr_idx, u32_t i0, u32_t i1,
netif_ip6_addr_state(netif, addr_idx)));
}
/**
* @ingroup netif_ip6
* Change the state of an IPv6 address of a network interface
* (INVALID, TEMPTATIVE, PREFERRED, DEPRECATED, where TEMPTATIVE
* includes the number of checks done, see ip6_addr.h)
*
* @param netif the network interface to change
* @param addr_idx index of the IPv6 address
* @param state the new IPv6 address state
*/
void
netif_ip6_addr_set_state(struct netif* netif, s8_t addr_idx, u8_t state)
{
@ -999,9 +1096,24 @@ netif_ip6_addr_set_state(struct netif* netif, s8_t addr_idx, u8_t state)
u8_t new_valid = state & IP6_ADDR_VALID;
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set_state: netif address state being changed\n"));
#if LWIP_IPV6_MLD
/* Reevaluate solicited-node multicast group membership. */
if (netif->flags & NETIF_FLAG_MLD6) {
nd6_adjust_mld_membership(netif, addr_idx, state);
}
#endif /* LWIP_IPV6_MLD */
if (old_valid && !new_valid) {
/* address about to be removed by setting invalid */
/* @todo: tcp_netif_ipv6_addr_changed()/udp_netif_ipv6_addr_changed() */
#if LWIP_TCP
tcp_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), NULL);
#endif /* LWIP_TCP */
#if LWIP_UDP
udp_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), NULL);
#endif /* LWIP_UDP */
#if LWIP_RAW
raw_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), NULL);
#endif /* LWIP_RAW */
/* @todo: remove mib2 ip6 entries? */
}
netif->ip6_addr_state[addr_idx] = state;
@ -1046,7 +1158,7 @@ netif_get_ip6_addr_match(struct netif *netif, const ip6_addr_t *ip6addr)
}
/**
* @ingroup netif
* @ingroup netif_ip6
* Create a link-local IPv6 address on a netif (stored in slot 0)
*
* @param netif the netif to create the address on
@ -1065,11 +1177,11 @@ netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit)
/* Generate interface ID. */
if (from_mac_48bit) {
/* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */
ip_2_ip6(&netif->ip6_addr[0])->addr[2] = htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) |
ip_2_ip6(&netif->ip6_addr[0])->addr[2] = lwip_htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) |
((u32_t)(netif->hwaddr[1]) << 16) |
((u32_t)(netif->hwaddr[2]) << 8) |
(0xff));
ip_2_ip6(&netif->ip6_addr[0])->addr[3] = htonl((0xfeul << 24) |
ip_2_ip6(&netif->ip6_addr[0])->addr[3] = lwip_htonl((0xfeul << 24) |
((u32_t)(netif->hwaddr[3]) << 16) |
((u32_t)(netif->hwaddr[4]) << 8) |
(netif->hwaddr[5]));
@ -1090,15 +1202,15 @@ netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit)
/* Set address state. */
#if LWIP_IPV6_DUP_DETECT_ATTEMPTS
/* Will perform duplicate address detection (DAD). */
netif->ip6_addr_state[0] = IP6_ADDR_TENTATIVE;
netif_ip6_addr_set_state(netif, 0, IP6_ADDR_TENTATIVE);
#else
/* Consider address valid. */
netif->ip6_addr_state[0] = IP6_ADDR_PREFERRED;
netif_ip6_addr_set_state(netif, 0, IP6_ADDR_PREFERRED);
#endif /* LWIP_IPV6_AUTOCONFIG */
}
/**
* @ingroup netif
* @ingroup netif_ip6
* This function allows for the easy addition of a new IPv6 address to an interface.
* It takes care of finding an empty slot and then sets the address tentative
* (to make sure that all the subsequent processing happens).
@ -1123,7 +1235,7 @@ netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chos
/* Find a free slot -- musn't be the first one (reserved for link local) */
for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (!ip6_addr_isvalid(netif->ip6_addr_state[i])) {
if (ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) {
ip_addr_copy_from_ip6(netif->ip6_addr[i], *ip6addr);
netif_ip6_addr_set_state(netif, i, IP6_ADDR_TENTATIVE);
if (chosen_idx != NULL) {

View File

@ -32,6 +32,49 @@
*
* Therefore, looping through a pbuf of a single packet, has an
* loop end condition (tot_len == p->len), NOT (next == NULL).
*
* Example of custom pbuf usage for zero-copy RX:
@code{.c}
typedef struct my_custom_pbuf
{
struct pbuf_custom p;
void* dma_descriptor;
} my_custom_pbuf_t;
LWIP_MEMPOOL_DECLARE(RX_POOL, 10, sizeof(my_custom_pbuf_t), "Zero-copy RX PBUF pool");
void my_pbuf_free_custom(void* p)
{
my_custom_pbuf_t* my_puf = (my_custom_pbuf_t*)p;
LOCK_INTERRUPTS();
free_rx_dma_descriptor(my_pbuf->dma_descriptor);
LWIP_MEMPOOL_FREE(RX_POOL, my_pbuf);
UNLOCK_INTERRUPTS();
}
void eth_rx_irq()
{
dma_descriptor* dma_desc = get_RX_DMA_descriptor_from_ethernet();
my_custom_pbuf_t* my_pbuf = (my_custom_pbuf_t*)LWIP_MEMPOOL_ALLOC(RX_POOL);
my_pbuf->p.custom_free_function = my_pbuf_free_custom;
my_pbuf->dma_descriptor = dma_desc;
invalidate_cpu_cache(dma_desc->rx_data, dma_desc->rx_length);
struct pbuf* p = pbuf_alloced_custom(PBUF_RAW,
dma_desc->rx_length,
PBUF_REF,
&my_pbuf->p,
dma_desc->rx_data,
dma_desc->max_buffer_size);
if(netif->input(p, netif) != ERR_OK) {
pbuf_free(p);
}
}
@endcode
*/
/*
@ -525,11 +568,11 @@ pbuf_header_impl(struct pbuf *p, s16_t header_size_increment, u8_t force)
}
if (header_size_increment < 0) {
increment_magnitude = -header_size_increment;
increment_magnitude = (u16_t)-header_size_increment;
/* Check that we aren't going to move off the end of the pbuf */
LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);
} else {
increment_magnitude = header_size_increment;
increment_magnitude = (u16_t)header_size_increment;
#if 0
/* Can't assert these as some callers speculatively call
pbuf_header() to see if it's OK. Will return 1 below instead. */
@ -743,10 +786,10 @@ pbuf_free(struct pbuf *p)
* @param p first pbuf of chain
* @return the number of pbufs in a chain
*/
u8_t
pbuf_clen(struct pbuf *p)
u16_t
pbuf_clen(const struct pbuf *p)
{
u8_t len;
u16_t len;
len = 0;
while (p != NULL) {
@ -766,12 +809,9 @@ pbuf_clen(struct pbuf *p)
void
pbuf_ref(struct pbuf *p)
{
SYS_ARCH_DECL_PROTECT(old_level);
/* pbuf given? */
if (p != NULL) {
SYS_ARCH_PROTECT(old_level);
++(p->ref);
SYS_ARCH_UNPROTECT(old_level);
SYS_ARCH_INC(p->ref, 1);
}
}
@ -894,12 +934,12 @@ pbuf_dechain(struct pbuf *p)
* enough to hold p_from
*/
err_t
pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from)
{
u16_t offset_to=0, offset_from=0, len;
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
(void*)p_to, (void*)p_from));
(const void*)p_to, (const void*)p_from));
/* is the target big enough to hold the source? */
LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&
@ -961,9 +1001,9 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
* @return the number of bytes copied, or 0 on failure
*/
u16_t
pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
{
struct pbuf *p;
const struct pbuf *p;
u16_t left;
u16_t buf_copy_len;
u16_t copied_total = 0;
@ -985,8 +1025,9 @@ pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
} else {
/* copy from this buffer. maybe only partially. */
buf_copy_len = p->len - offset;
if (buf_copy_len > len)
buf_copy_len = len;
if (buf_copy_len > len) {
buf_copy_len = len;
}
/* copy the necessary parts of the buffer */
MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
copied_total += buf_copy_len;
@ -1048,6 +1089,24 @@ void pbuf_split_64k(struct pbuf *p, struct pbuf **rest)
}
#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */
/* Actual implementation of pbuf_skip() but returning const pointer... */
static const struct pbuf*
pbuf_skip_const(const struct pbuf* in, u16_t in_offset, u16_t* out_offset)
{
u16_t offset_left = in_offset;
const struct pbuf* q = in;
/* get the correct pbuf */
while ((q != NULL) && (q->len <= offset_left)) {
offset_left -= q->len;
q = q->next;
}
if (out_offset != NULL) {
*out_offset = offset_left;
}
return q;
}
/**
* @ingroup pbuf
* Skip a number of bytes at the start of a pbuf
@ -1060,18 +1119,8 @@ void pbuf_split_64k(struct pbuf *p, struct pbuf **rest)
struct pbuf*
pbuf_skip(struct pbuf* in, u16_t in_offset, u16_t* out_offset)
{
u16_t offset_left = in_offset;
struct pbuf* q = in;
/* get the correct pbuf */
while ((q != NULL) && (q->len <= offset_left)) {
offset_left -= q->len;
q = q->next;
}
if (out_offset != NULL) {
*out_offset = offset_left;
}
return q;
const struct pbuf* out = pbuf_skip_const(in, in_offset, out_offset);
return LWIP_CONST_CAST(struct pbuf*, out);
}
/**
@ -1179,7 +1228,7 @@ pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
return p;
}
err = pbuf_copy(q, p);
LWIP_UNUSED_ARG(err);
LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
pbuf_free(p);
return q;
@ -1226,7 +1275,7 @@ pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
}
#endif /* LWIP_CHECKSUM_ON_COPY */
/**
/**
* @ingroup pbuf
* Get one byte from the specified position in a pbuf
* WARNING: returns zero for offset >= p->tot_len
@ -1236,16 +1285,34 @@ pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
* @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)
pbuf_get_at(const struct pbuf* p, u16_t offset)
{
int ret = pbuf_try_get_at(p, offset);
if (ret >= 0) {
return (u8_t)ret;
}
return 0;
}
/**
* @ingroup pbuf
* Get one byte from the specified position in a pbuf
*
* @param p pbuf to parse
* @param offset offset into p of the byte to return
* @return byte at an offset into p [0..0xFF] OR negative if 'offset' >= p->tot_len
*/
int
pbuf_try_get_at(const struct pbuf* p, u16_t offset)
{
u16_t q_idx;
struct pbuf* q = pbuf_skip(p, offset, &q_idx);
const struct pbuf* q = pbuf_skip_const(p, offset, &q_idx);
/* return requested data if pbuf is OK */
if ((q != NULL) && (q->len > q_idx)) {
return ((u8_t*)q->payload)[q_idx];
}
return 0;
return -1;
}
/**
@ -1281,29 +1348,33 @@ pbuf_put_at(struct pbuf* p, u16_t offset, u8_t data)
* (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)
pbuf_memcmp(const struct pbuf* p, u16_t offset, const void* s2, u16_t n)
{
u16_t start = offset;
struct pbuf* q = p;
/* get the correct pbuf */
const struct pbuf* q = p;
u16_t i;
/* pbuf long enough to perform check? */
if(p->tot_len < (offset + n)) {
return 0xffff;
}
/* get the correct pbuf from chain. We know it succeeds because of p->tot_len check above. */
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 = ((const u8_t*)s2)[i];
if (a != b) {
return i+1;
}
for (i = 0; i < n; i++) {
/* We know pbuf_get_at() succeeds because of p->tot_len check above. */
u8_t a = pbuf_get_at(q, start + i);
u8_t b = ((const u8_t*)s2)[i];
if (a != b) {
return i+1;
}
return 0;
}
return 0xffff;
return 0;
}
/**
@ -1319,7 +1390,7 @@ pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)
* @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)
pbuf_memfind(const 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;
@ -1346,7 +1417,7 @@ pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)
* @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)
pbuf_strstr(const struct pbuf* p, const char* substr)
{
size_t substr_len;
if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) {

View File

@ -4,6 +4,13 @@
* different types of protocols besides (or overriding) those
* already available in lwIP.\n
* See also @ref raw_raw
*
* @defgroup raw_raw RAW
* @ingroup callbackstyle_api
* Implementation of raw protocol PCBs for low-level handling of
* different types of protocols besides (or overriding) those
* already available in lwIP.\n
* @see @ref raw_api
*/
/*
@ -38,21 +45,6 @@
*
*/
/**
* @defgroup raw_api RAW API
* @ingroup callbackstyle_api
* @verbinclude "rawapi.txt"
*/
/**
* @defgroup raw_raw RAW
* @ingroup raw_api
* Implementation of raw protocol PCBs for low-level handling of
* different types of protocols besides (or overriding) those
* already available in lwIP.\n
* @see @ref raw_api
*/
#include "lwip/opt.h"
#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
@ -88,7 +80,7 @@ raw_input_match(struct raw_pcb *pcb, u8_t broadcast)
return 1;
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
/* Only need to check PCB if incoming IP version matches PCB IP version */
if (IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) {
#if LWIP_IPV4
@ -111,7 +103,7 @@ raw_input_match(struct raw_pcb *pcb, u8_t broadcast)
return 1;
}
}
return 0;
}
@ -204,7 +196,7 @@ raw_input(struct pbuf *p, struct netif *inp)
* Bind a RAW PCB.
*
* @param pcb RAW PCB to be bound with a local address ipaddr.
* @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
* @param ipaddr local IP address to bind with. Use IP4_ADDR_ANY to
* bind to all local interfaces.
*
* @return lwIP error code.
@ -217,7 +209,7 @@ raw_input(struct pbuf *p, struct netif *inp)
err_t
raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
{
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
return ERR_VAL;
}
ip_addr_set_ipaddr(&pcb->local_ip, ipaddr);
@ -241,7 +233,7 @@ raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
err_t
raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
{
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
return ERR_VAL;
}
ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr);
@ -258,9 +250,6 @@ raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
* packet will not be passed to other raw PCBs or other protocol layers.
* - not free the packet, and return zero. The packet will be matched
* against further PCBs and/or forwarded to another protocol layers.
*
* @return non-zero if the packet was free()d, zero if the packet remains
* available for others.
*/
void
raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
@ -291,7 +280,6 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr)
const ip_addr_t *src_ip;
struct pbuf *q; /* q will be sent down the stack */
s16_t header_size;
const ip_addr_t *dst_ip = ipaddr;
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
return ERR_VAL;
@ -332,10 +320,16 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr)
}
}
netif = ip_route(&pcb->local_ip, dst_ip);
if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
/* Don't call ip_route() with IP_ANY_TYPE */
netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(ipaddr)), ipaddr);
} else {
netif = ip_route(&pcb->local_ip, ipaddr);
}
if (netif == NULL) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to "));
ip_addr_debug_print(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip);
ip_addr_debug_print(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ipaddr);
/* free any temporary header pbuf allocated by pbuf_header() */
if (q != p) {
pbuf_free(q);
@ -360,7 +354,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr)
if (ip_addr_isany(&pcb->local_ip)) {
/* use outgoing network interface IP address as source address */
src_ip = ip_netif_get_local_ip(netif, dst_ip);
src_ip = ip_netif_get_local_ip(netif, ipaddr);
#if LWIP_IPV6
if (src_ip == NULL) {
if (q != p) {
@ -377,15 +371,15 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr)
#if LWIP_IPV6
/* If requested, based on the IPV6_CHECKSUM socket option per RFC3542,
compute the checksum and update the checksum in the payload. */
if (IP_IS_V6(dst_ip) && pcb->chksum_reqd) {
u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ip_2_ip6(src_ip), ip_2_ip6(dst_ip));
if (IP_IS_V6(ipaddr) && pcb->chksum_reqd) {
u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ip_2_ip6(src_ip), ip_2_ip6(ipaddr));
LWIP_ASSERT("Checksum must fit into first pbuf", p->len >= (pcb->chksum_offset + 2));
SMEMCPY(((u8_t *)p->payload) + pcb->chksum_offset, &chksum, sizeof(u16_t));
}
#endif
NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, pcb->protocol, netif);
err = ip_output_if(q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
NETIF_SET_HWADDRHINT(netif, NULL);
/* did we chain a header earlier? */
@ -479,7 +473,9 @@ raw_new(u8_t proto)
* @return The RAW PCB which was created. NULL if the PCB data structure
* could not be allocated.
*
* @param type IP address type, see IPADDR_TYPE_XX definitions.
* @param type IP address type, see @ref lwip_ip_addr_type definitions.
* If you want to listen to IPv4 and IPv6 (dual-stack) packets,
* supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE.
* @param proto the protocol number (next header) of the IPv6 packet payload
* (e.g. IP6_NEXTH_ICMP6)
*
@ -501,4 +497,25 @@ raw_new_ip_type(u8_t type, u8_t proto)
return pcb;
}
/** This function is called from netif.c when address is changed
*
* @param old_addr IP address of the netif before change
* @param new_addr IP address of the netif after change
*/
void raw_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr)
{
struct raw_pcb* rpcb;
if (!ip_addr_isany(old_addr) && !ip_addr_isany(new_addr)) {
for (rpcb = raw_pcbs; rpcb != NULL; rpcb = rpcb->next) {
/* PCB bound to current local interface address? */
if (ip_addr_cmp(&rpcb->local_ip, old_addr)) {
/* The PCB is bound to the old ipaddr and
* is set to bound to the new one instead */
ip_addr_copy(rpcb->local_ip, *new_addr);
}
}
}
}
#endif /* LWIP_RAW */

View File

@ -36,6 +36,44 @@
*
*/
/**
* @defgroup sys_layer Porting (system abstraction layer)
* @ingroup lwip
* @verbinclude "sys_arch.txt"
*
* @defgroup sys_os OS abstraction layer
* @ingroup sys_layer
* No need to implement functions in this section in NO_SYS mode.
*
* @defgroup sys_sem Semaphores
* @ingroup sys_os
*
* @defgroup sys_mutex Mutexes
* @ingroup sys_os
* Mutexes are recommended to correctly handle priority inversion,
* especially if you use LWIP_CORE_LOCKING .
*
* @defgroup sys_mbox Mailboxes
* @ingroup sys_os
*
* @defgroup sys_time Time
* @ingroup sys_layer
*
* @defgroup sys_prot Critical sections
* @ingroup sys_layer
* Used to protect short regions of code against concurrent access.
* - Your system is a bare-metal system (probably with an RTOS)
* and interrupts are under your control:
* Implement this as LockInterrupts() / UnlockInterrupts()
* - Your system uses an RTOS with deferred interrupt handling from a
* worker thread: Implement as a global mutex or lock/unlock scheduler
* - Your system uses a high-level OS with e.g. POSIX signals:
* Implement as a global mutex
*
* @defgroup sys_misc Misc
* @ingroup sys_os
*/
#include "lwip/opt.h"
#include "lwip/sys.h"

View File

@ -2,6 +2,15 @@
* @file
* Transmission Control Protocol for IP
* See also @ref tcp_raw
*
* @defgroup tcp_raw TCP
* @ingroup callbackstyle_api
* Transmission Control Protocol for IP\n
* @see @ref raw_api and @ref netconn
*
* Common functions for the TCP implementation, such as functinos
* for manipulating the data structures and the TCP timer functions. TCP functions
* related to input and output is found in tcp_in.c and tcp_out.c respectively.\n
*/
/*
@ -36,17 +45,6 @@
*
*/
/**
* @defgroup tcp_raw TCP
* @ingroup raw_api
* Transmission Control Protocol for IP\n
* @see @ref raw_api and @ref netconn
*
* Common functions for the TCP implementation, such as functinos
* for manipulating the data structures and the TCP timer functions. TCP functions
* related to input and output is found in tcp_in.c and tcp_out.c respectively.\n
*/
#include "lwip/opt.h"
#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
@ -87,7 +85,7 @@
#define INITIAL_MSS TCP_MSS
#endif
const char * const tcp_state_str[] = {
static const char * const tcp_state_str[] = {
"CLOSED",
"LISTEN",
"SYN_SENT",
@ -106,10 +104,10 @@ static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START;
/* Incremented every coarse grained timer shot (typically every 500 ms). */
u32_t tcp_ticks;
const u8_t tcp_backoff[13] =
static const u8_t tcp_backoff[13] =
{ 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
/* Times per slowtmr hits */
const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 };
static const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 };
/* The TCP PCB lists. */
@ -531,7 +529,7 @@ tcp_abort(struct tcp_pcb *pcb)
*
* @param pcb the tcp_pcb to bind (no check is done whether this pcb is
* already bound!)
* @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind
* @param ipaddr the local ip address to bind to (use IP4_ADDR_ANY to bind
* to any local address
* @param port the local port to bind to
* @return ERR_USE if the port is already in use
@ -548,12 +546,12 @@ tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port)
#if LWIP_IPV4
/* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */
if (ipaddr == NULL) {
ipaddr = IP_ADDR_ANY;
ipaddr = IP4_ADDR_ANY;
}
#endif /* LWIP_IPV4 */
/* still need to check for ipaddr == NULL in IPv6 only case */
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
return ERR_VAL;
}
@ -638,19 +636,44 @@ tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)
*
* @note The original tcp_pcb is freed. This function therefore has to be
* called like this:
* tpcb = tcp_listen(tpcb);
* tpcb = tcp_listen_with_backlog(tpcb, backlog);
*/
struct tcp_pcb *
tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
{
struct tcp_pcb_listen *lpcb;
return tcp_listen_with_backlog_and_err(pcb, backlog, NULL);
}
/**
* @ingroup tcp_raw
* Set the state of the connection to be LISTEN, which means that it
* is able to accept incoming connections. The protocol control block
* is reallocated in order to consume less memory. Setting the
* connection to LISTEN is an irreversible process.
*
* @param pcb the original tcp_pcb
* @param backlog the incoming connections queue limit
* @param err when NULL is returned, this contains the error reason
* @return tcp_pcb used for listening, consumes less memory.
*
* @note The original tcp_pcb is freed. This function therefore has to be
* called like this:
* tpcb = tcp_listen_with_backlog_and_err(tpcb, backlog, &err);
*/
struct tcp_pcb *
tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err)
{
struct tcp_pcb_listen *lpcb = NULL;
err_t res;
LWIP_UNUSED_ARG(backlog);
LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL);
LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, res = ERR_CLSD; goto done);
/* already listening? */
if (pcb->state == LISTEN) {
return pcb;
lpcb = (struct tcp_pcb_listen*)pcb;
res = ERR_ALREADY;
goto done;
}
#if SO_REUSE
if (ip_get_option(pcb, SOF_REUSEADDR)) {
@ -661,14 +684,17 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
if ((lpcb->local_port == pcb->local_port) &&
ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) {
/* this address/port is already used */
return NULL;
lpcb = NULL;
res = ERR_USE;
goto done;
}
}
}
#endif /* SO_REUSE */
lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN);
if (lpcb == NULL) {
return NULL;
res = ERR_MEM;
goto done;
}
lpcb->callback_arg = pcb->callback_arg;
lpcb->local_port = pcb->local_port;
@ -690,9 +716,14 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
#endif /* LWIP_CALLBACK_API */
#if TCP_LISTEN_BACKLOG
lpcb->accepts_pending = 0;
lpcb->backlog = backlog;
tcp_backlog_set(lpcb, backlog);
#endif /* TCP_LISTEN_BACKLOG */
TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb);
res = ERR_OK;
done:
if (err != NULL) {
*err = res;
}
return (struct tcp_pcb *)lpcb;
}
@ -828,7 +859,7 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port,
u32_t iss;
u16_t old_local_port;
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
return ERR_VAL;
}
@ -882,10 +913,11 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port,
#endif /* SO_REUSE */
}
iss = tcp_next_iss();
iss = tcp_next_iss(pcb);
pcb->rcv_nxt = 0;
pcb->snd_nxt = iss;
pcb->lastack = iss - 1;
pcb->snd_wl2 = iss - 1;
pcb->snd_lbb = iss - 1;
/* Start with a window that does not need scaling. When window scaling is
enabled and used, the window is enlarged when both sides agree on scaling. */
@ -1096,7 +1128,9 @@ tcp_slowtmr_start:
/* If the PCB should be removed, do it. */
if (pcb_remove) {
struct tcp_pcb *pcb2;
tcp_err_fn err_fn;
#if LWIP_CALLBACK_API
tcp_err_fn err_fn = pcb->errf;
#endif /* LWIP_CALLBACK_API */
void *err_arg;
tcp_pcb_purge(pcb);
/* Remove PCB from tcp_active_pcbs list. */
@ -1114,7 +1148,6 @@ tcp_slowtmr_start:
pcb->local_port, pcb->remote_port);
}
err_fn = pcb->errf;
err_arg = pcb->callback_arg;
pcb2 = pcb;
pcb = pcb->next;
@ -1492,7 +1525,6 @@ struct tcp_pcb *
tcp_alloc(u8_t prio)
{
struct tcp_pcb *pcb;
u32_t iss;
pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);
if (pcb == NULL) {
@ -1555,11 +1587,6 @@ tcp_alloc(u8_t prio)
pcb->sv = 3000 / TCP_SLOW_INTERVAL;
pcb->rtime = -1;
pcb->cwnd = 1;
iss = tcp_next_iss();
pcb->snd_wl2 = iss;
pcb->snd_nxt = iss;
pcb->lastack = iss;
pcb->snd_lbb = iss;
pcb->tmr = tcp_ticks;
pcb->last_timer = tcp_timer_ctr;
@ -1603,7 +1630,9 @@ tcp_new(void)
* place it on any of the TCP PCB lists.
* The pcb is not put on any list until binding using tcp_bind().
*
* @param type IP address type, see IPADDR_TYPE_XX definitions.
* @param type IP address type, see @ref lwip_ip_addr_type definitions.
* If you want to listen to IPv4 and IPv6 (dual-stack) connections,
* supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE.
* @return a new tcp_pcb that initially is in state CLOSED
*/
struct tcp_pcb *
@ -1680,6 +1709,8 @@ tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent)
* Used to specify the function that should be called when a fatal error
* has occurred on the connection.
*
* @note The corresponding pcb is already freed when this callback is called!
*
* @param pcb tcp_pcb to set the err callback
* @param err callback function to call for this pcb when a fatal error
* has occurred on the connection
@ -1823,12 +1854,18 @@ tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
* @return u32_t pseudo random sequence number
*/
u32_t
tcp_next_iss(void)
tcp_next_iss(struct tcp_pcb *pcb)
{
#ifdef LWIP_HOOK_TCP_ISN
return LWIP_HOOK_TCP_ISN(&pcb->local_ip, pcb->local_port, &pcb->remote_ip, pcb->remote_port);
#else /* LWIP_HOOK_TCP_ISN */
static u32_t iss = 6510;
LWIP_UNUSED_ARG(pcb);
iss += tcp_ticks; /* XXX */
return iss;
#endif /* LWIP_HOOK_TCP_ISN */
}
#if TCP_CALCULATE_EFF_SEND_MSS
@ -1897,19 +1934,18 @@ tcp_eff_send_mss_impl(u16_t sendmss, const ip_addr_t *dest
}
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
#if LWIP_IPV4
/** Helper function for tcp_netif_ipv4_addr_changed() that iterates a pcb list */
/** Helper function for tcp_netif_ip_addr_changed() that iterates a pcb list */
static void
tcp_netif_ipv4_addr_changed_pcblist(const ip4_addr_t* old_addr, struct tcp_pcb* pcb_list)
tcp_netif_ip_addr_changed_pcblist(const ip_addr_t* old_addr, struct tcp_pcb* pcb_list)
{
struct tcp_pcb *pcb;
pcb = pcb_list;
while (pcb != NULL) {
/* PCB bound to current local interface address? */
if (IP_IS_V4_VAL(pcb->local_ip) && ip4_addr_cmp(ip_2_ip4(&pcb->local_ip), old_addr)
if (ip_addr_cmp(&pcb->local_ip, old_addr)
#if LWIP_AUTOIP
/* connections to link-local addresses must persist (RFC3927 ch. 1.9) */
&& !ip4_addr_islinklocal(ip_2_ip4(&pcb->local_ip))
&& (!IP_IS_V4_VAL(pcb->local_ip) || !ip4_addr_islinklocal(ip_2_ip4(&pcb->local_ip)))
#endif /* LWIP_AUTOIP */
) {
/* this connection must be aborted */
@ -1925,35 +1961,32 @@ tcp_netif_ipv4_addr_changed_pcblist(const ip4_addr_t* old_addr, struct tcp_pcb*
/** This function is called from netif.c when address is changed or netif is removed
*
* @param old_addr IPv4 address of the netif before change
* @param new_addr IPv4 address of the netif after change or NULL if netif has been removed
* @param old_addr IP address of the netif before change
* @param new_addr IP address of the netif after change or NULL if netif has been removed
*/
void
tcp_netif_ipv4_addr_changed(const ip4_addr_t* old_addr, const ip4_addr_t* new_addr)
tcp_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr)
{
struct tcp_pcb_listen *lpcb, *next;
tcp_netif_ipv4_addr_changed_pcblist(old_addr, tcp_active_pcbs);
tcp_netif_ipv4_addr_changed_pcblist(old_addr, tcp_bound_pcbs);
if (!ip_addr_isany(old_addr)) {
tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_active_pcbs);
tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_bound_pcbs);
if (!ip4_addr_isany(new_addr)) {
/* PCB bound to current local interface address? */
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = next) {
next = lpcb->next;
/* Is this an IPv4 pcb? */
if (IP_IS_V4_VAL(lpcb->local_ip)) {
if (!ip_addr_isany(new_addr)) {
/* PCB bound to current local interface address? */
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = next) {
next = lpcb->next;
/* PCB bound to current local interface address? */
if ((!(ip4_addr_isany(ip_2_ip4(&lpcb->local_ip)))) &&
(ip4_addr_cmp(ip_2_ip4(&lpcb->local_ip), old_addr))) {
if (ip_addr_cmp(&lpcb->local_ip, old_addr)) {
/* The PCB is listening to the old ipaddr and
* is set to listen to the new one instead */
ip_addr_copy_from_ip4(lpcb->local_ip, *new_addr);
* is set to listen to the new one instead */
ip_addr_copy(lpcb->local_ip, *new_addr);
}
}
}
}
}
#endif /* LWIP_IPV4 */
const char*
tcp_debug_state_str(enum tcp_state s)
@ -1973,13 +2006,13 @@ tcp_debug_print(struct tcp_hdr *tcphdr)
LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n"));
LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(TCP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n",
ntohs(tcphdr->src), ntohs(tcphdr->dest)));
lwip_ntohs(tcphdr->src), lwip_ntohs(tcphdr->dest)));
LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n",
ntohl(tcphdr->seqno)));
lwip_ntohl(tcphdr->seqno)));
LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n",
ntohl(tcphdr->ackno)));
lwip_ntohl(tcphdr->ackno)));
LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (",
TCPH_HDRLEN(tcphdr),
@ -1989,12 +2022,12 @@ tcp_debug_print(struct tcp_hdr *tcphdr)
(u16_t)(TCPH_FLAGS(tcphdr) >> 2 & 1),
(u16_t)(TCPH_FLAGS(tcphdr) >> 1 & 1),
(u16_t)(TCPH_FLAGS(tcphdr) & 1),
ntohs(tcphdr->wnd)));
lwip_ntohs(tcphdr->wnd)));
tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
LWIP_DEBUGF(TCP_DEBUG, ("), win)\n"));
LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04"X16_F" | %5"U16_F" | (chksum, urgp)\n",
ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));
lwip_ntohs(tcphdr->chksum), lwip_ntohs(tcphdr->urgp)));
LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
}

View File

@ -55,7 +55,6 @@
#include "lwip/stats.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/inet_chksum.h"
#if LWIP_ND6_TCP_REACHABILITY_HINTS
#include "lwip/nd6.h"
#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */
@ -199,7 +198,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
/* remember the pointer to the second part of the options */
tcphdr_opt2 = (u8_t*)p->next->payload;
/* advance p->next to point after the options, and manually
adjust p->tot_len to keep it consistent with the changed p->next */
pbuf_header(p->next, -(s16_t)opt2len);
@ -210,11 +209,11 @@ tcp_input(struct pbuf *p, struct netif *inp)
}
/* Convert fields in TCP header to host byte order. */
tcphdr->src = ntohs(tcphdr->src);
tcphdr->dest = ntohs(tcphdr->dest);
seqno = tcphdr->seqno = ntohl(tcphdr->seqno);
ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
tcphdr->wnd = ntohs(tcphdr->wnd);
tcphdr->src = lwip_ntohs(tcphdr->src);
tcphdr->dest = lwip_ntohs(tcphdr->dest);
seqno = tcphdr->seqno = lwip_ntohl(tcphdr->seqno);
ackno = tcphdr->ackno = lwip_ntohl(tcphdr->ackno);
tcphdr->wnd = lwip_ntohs(tcphdr->wnd);
flags = TCPH_FLAGS(tcphdr);
tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);
@ -359,6 +358,11 @@ tcp_input(struct pbuf *p, struct netif *inp)
((pcb->refused_data != NULL) && (tcplen > 0))) {
/* pcb has been aborted or refused data is still refused and the new
segment contains data */
if (pcb->rcv_ann_wnd == 0) {
/* this is a zero-window probe, we respond to it with current RCV.NXT
and drop the data segment */
tcp_send_empty_ack(pcb);
}
TCP_STATS_INC(tcp.drop);
MIB2_STATS_INC(mib2.tcpinerrs);
goto aborted;
@ -535,10 +539,7 @@ dropped:
* connection (from tcp_input()).
*
* @param pcb the tcp_pcb_listen for which a segment arrived
* @return ERR_OK if the segment was processed
* another err_t on error
*
* @note the return value is not (yet?) used in tcp_input()
* @note the segment which arrived is saved in global variables, therefore only the pcb
* involved is passed as a parameter to this function
*/
@ -546,6 +547,7 @@ static void
tcp_listen_input(struct tcp_pcb_listen *pcb)
{
struct tcp_pcb *npcb;
u32_t iss;
err_t rc;
if (flags & TCP_RST) {
@ -593,6 +595,11 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
npcb->state = SYN_RCVD;
npcb->rcv_nxt = seqno + 1;
npcb->rcv_ann_right_edge = npcb->rcv_nxt;
iss = tcp_next_iss(npcb);
npcb->snd_wl2 = iss;
npcb->snd_nxt = iss;
npcb->lastack = iss;
npcb->snd_lbb = iss;
npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
npcb->callback_arg = pcb->callback_arg;
#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG
@ -606,7 +613,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
/* Parse any options in the SYN. */
tcp_parseopt(npcb);
npcb->snd_wnd = SND_WND_SCALE(npcb, tcphdr->wnd);
npcb->snd_wnd = tcphdr->wnd;
npcb->snd_wnd_max = npcb->snd_wnd;
npcb->ssthresh = LWIP_TCP_INITIAL_SSTHRESH(npcb);
@ -748,14 +755,14 @@ tcp_process(struct tcp_pcb *pcb)
switch (pcb->state) {
case SYN_SENT:
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
pcb->snd_nxt, lwip_ntohl(pcb->unacked->tcphdr->seqno)));
/* received SYN ACK with expected sequence number? */
if ((flags & TCP_ACK) && (flags & TCP_SYN)
&& (ackno == pcb->lastack + 1)) {
pcb->rcv_nxt = seqno + 1;
pcb->rcv_ann_right_edge = pcb->rcv_nxt;
pcb->lastack = ackno;
pcb->snd_wnd = SND_WND_SCALE(pcb, tcphdr->wnd);
pcb->snd_wnd = tcphdr->wnd;
pcb->snd_wnd_max = pcb->snd_wnd;
pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
pcb->state = ESTABLISHED;
@ -887,7 +894,8 @@ tcp_process(struct tcp_pcb *pcb)
case FIN_WAIT_1:
tcp_receive(pcb);
if (recv_flags & TF_GOT_FIN) {
if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) &&
pcb->unsent == NULL) {
LWIP_DEBUGF(TCP_DEBUG,
("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
tcp_ack_now(pcb);
@ -899,7 +907,8 @@ tcp_process(struct tcp_pcb *pcb)
tcp_ack_now(pcb);
pcb->state = CLOSING;
}
} else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
} else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) &&
pcb->unsent == NULL) {
pcb->state = FIN_WAIT_2;
}
break;
@ -916,7 +925,7 @@ tcp_process(struct tcp_pcb *pcb)
break;
case CLOSING:
tcp_receive(pcb);
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
if (flags & TCP_ACK && ackno == pcb->snd_nxt && pcb->unsent == NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
tcp_pcb_purge(pcb);
TCP_RMV_ACTIVE(pcb);
@ -926,7 +935,7 @@ tcp_process(struct tcp_pcb *pcb)
break;
case LAST_ACK:
tcp_receive(pcb);
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
if (flags & TCP_ACK && ackno == pcb->snd_nxt && pcb->unsent == NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
/* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
recv_flags |= TF_CLOSED;
@ -997,7 +1006,6 @@ tcp_receive(struct tcp_pcb *pcb)
#if TCP_QUEUE_OOSEQ
struct tcp_seg *prev, *cseg;
#endif /* TCP_QUEUE_OOSEQ */
struct pbuf *p;
s32_t off;
s16_t m;
u32_t right_wnd_edge;
@ -1140,18 +1148,18 @@ tcp_receive(struct tcp_pcb *pcb)
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",
ackno,
pcb->unacked != NULL?
ntohl(pcb->unacked->tcphdr->seqno): 0,
lwip_ntohl(pcb->unacked->tcphdr->seqno): 0,
pcb->unacked != NULL?
ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
lwip_ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
/* Remove segment from the unacknowledged list if the incoming
ACK acknowledges them. */
while (pcb->unacked != NULL &&
TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
TCP_SEQ_LEQ(lwip_ntohl(pcb->unacked->tcphdr->seqno) +
TCP_TCPLEN(pcb->unacked), ackno)) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",
ntohl(pcb->unacked->tcphdr->seqno),
ntohl(pcb->unacked->tcphdr->seqno) +
lwip_ntohl(pcb->unacked->tcphdr->seqno),
lwip_ntohl(pcb->unacked->tcphdr->seqno) +
TCP_TCPLEN(pcb->unacked)));
next = pcb->unacked;
@ -1199,10 +1207,10 @@ tcp_receive(struct tcp_pcb *pcb)
->unsent list after a retransmission, so these segments may
in fact have been sent once. */
while (pcb->unsent != NULL &&
TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) +
TCP_SEQ_BETWEEN(ackno, lwip_ntohl(pcb->unsent->tcphdr->seqno) +
TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
lwip_ntohl(pcb->unsent->tcphdr->seqno), lwip_ntohl(pcb->unsent->tcphdr->seqno) +
TCP_TCPLEN(pcb->unsent)));
next = pcb->unsent;
@ -1314,8 +1322,8 @@ tcp_receive(struct tcp_pcb *pcb)
adjust the ->data pointer in the seg and the segment
length.*/
struct pbuf *p = inseg.p;
off = pcb->rcv_nxt - seqno;
p = inseg.p;
LWIP_ASSERT("inseg.p != NULL", inseg.p);
LWIP_ASSERT("insane offset!", (off < 0x7fff));
if (inseg.p->len < off) {
@ -1779,12 +1787,12 @@ tcp_parseopt(struct tcp_pcb *pcb)
tsval |= (tcp_getoptbyte() << 16);
tsval |= (tcp_getoptbyte() << 24);
if (flags & TCP_SYN) {
pcb->ts_recent = ntohl(tsval);
pcb->ts_recent = lwip_ntohl(tsval);
/* Enable sending timestamps in every segment now that we know
the remote host supports it. */
pcb->flags |= TF_TIMESTAMP;
} else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) {
pcb->ts_recent = ntohl(tsval);
pcb->ts_recent = lwip_ntohl(tsval);
}
/* Advance to next option (6 bytes already read) */
tcp_optidx += LWIP_TCP_OPT_LEN_TS - 6;

View File

@ -52,7 +52,6 @@
#include "lwip/stats.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/inet_chksum.h"
#if LWIP_TCP_TIMESTAMPS
#include "lwip/sys.h"
#endif
@ -115,12 +114,12 @@ tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen,
LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
(p->len >= TCP_HLEN + optlen));
tcphdr = (struct tcp_hdr *)p->payload;
tcphdr->src = htons(pcb->local_port);
tcphdr->dest = htons(pcb->remote_port);
tcphdr->src = lwip_htons(pcb->local_port);
tcphdr->dest = lwip_htons(pcb->remote_port);
tcphdr->seqno = seqno_be;
tcphdr->ackno = htonl(pcb->rcv_nxt);
tcphdr->ackno = lwip_htonl(pcb->rcv_nxt);
TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK);
tcphdr->wnd = htons(TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd)));
tcphdr->wnd = lwip_htons(TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd)));
tcphdr->chksum = 0;
tcphdr->urgp = 0;
@ -205,9 +204,9 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno,
return NULL;
}
seg->tcphdr = (struct tcp_hdr *)seg->p->payload;
seg->tcphdr->src = htons(pcb->local_port);
seg->tcphdr->dest = htons(pcb->remote_port);
seg->tcphdr->seqno = htonl(seqno);
seg->tcphdr->src = lwip_htons(pcb->local_port);
seg->tcphdr->dest = lwip_htons(pcb->remote_port);
seg->tcphdr->seqno = lwip_htonl(seqno);
/* ackno is set in tcp_output */
TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), flags);
/* wnd and chksum are set in tcp_output */
@ -225,7 +224,7 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno,
* @param length size of the pbuf's payload.
* @param max_length maximum usable size of payload+oversize.
* @param oversize pointer to a u16_t that will receive the number of usable tail bytes.
* @param pcb The TCP connection that willo enqueue the pbuf.
* @param pcb The TCP connection that will enqueue the pbuf.
* @param apiflags API flags given to tcp_write.
* @param first_seg true when this pbuf will be used in the first enqueued segment.
*/
@ -243,7 +242,6 @@ tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length,
LWIP_UNUSED_ARG(pcb);
LWIP_UNUSED_ARG(apiflags);
LWIP_UNUSED_ARG(first_seg);
/* always create MSS-sized pbufs */
alloc = max_length;
#else /* LWIP_NETIF_TX_SINGLE_PBUF */
if (length < max_length) {
@ -350,6 +348,7 @@ tcp_write_checks(struct tcp_pcb *pcb, u16_t len)
}
/**
* @ingroup tcp_raw
* Write data for sending (but does not send it immediately).
*
* It waits in the expectation of more data being sent soon (as
@ -378,6 +377,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
u16_t oversize = 0;
u16_t oversize_used = 0;
#endif /* TCP_OVERSIZE */
u16_t extendlen = 0;
#if TCP_CHECKSUM_ON_COPY
u16_t concat_chksum = 0;
u8_t concat_chksum_swapped = 0;
@ -481,6 +481,10 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
/*
* Phase 2: Chain a new pbuf to the end of pcb->unsent.
*
* As an exception when NOT copying the data, if the given data buffer
* directly follows the last unsent data buffer in memory, extend the last
* ROM pbuf reference to the buffer, thus saving a ROM pbuf allocation.
*
* We don't extend segments containing SYN/FIN flags or options
* (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at
* the end.
@ -507,12 +511,24 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
#if TCP_CHECKSUM_ON_COPY
concat_chksummed += seglen;
#endif /* TCP_CHECKSUM_ON_COPY */
queuelen += pbuf_clen(concat_p);
} else {
/* Data is not copied */
if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("tcp_write: could not allocate memory for zero-copy pbuf\n"));
goto memerr;
/* If the last unsent pbuf is of type PBUF_ROM, try to extend it. */
struct pbuf *p;
for (p = last_unsent->p; p->next != NULL; p = p->next);
if (p->type == PBUF_ROM && (const u8_t *)p->payload + p->len == (const u8_t *)arg) {
LWIP_ASSERT("tcp_write: ROM pbufs cannot be oversized", pos == 0);
extendlen = seglen;
} else {
if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("tcp_write: could not allocate memory for zero-copy pbuf\n"));
goto memerr;
}
/* reference the non-volatile payload data */
((struct pbuf_rom*)concat_p)->payload = (const u8_t*)arg + pos;
queuelen += pbuf_clen(concat_p);
}
#if TCP_CHECKSUM_ON_COPY
/* calculate the checksum of nocopy-data */
@ -520,12 +536,9 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
&concat_chksum, &concat_chksum_swapped);
concat_chksummed += seglen;
#endif /* TCP_CHECKSUM_ON_COPY */
/* reference the non-volatile payload data */
((struct pbuf_rom*)concat_p)->payload = (const u8_t*)arg + pos;
}
pos += seglen;
queuelen += pbuf_clen(concat_p);
}
} else {
#if TCP_OVERSIZE
@ -633,8 +646,8 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
prev_seg = seg;
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_write: queueing %"U32_F":%"U32_F"\n",
ntohl(seg->tcphdr->seqno),
ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg)));
lwip_ntohl(seg->tcphdr->seqno),
lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg)));
pos += seglen;
}
@ -670,26 +683,40 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
#endif /* TCP_OVERSIZE */
/*
* Phase 2: concat_p can be concatenated onto last_unsent->p
* Phase 2: concat_p can be concatenated onto last_unsent->p, unless we
* determined that the last ROM pbuf can be extended to include the new data.
*/
if (concat_p != NULL) {
LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty",
(last_unsent != NULL));
pbuf_cat(last_unsent->p, concat_p);
last_unsent->len += concat_p->tot_len;
#if TCP_CHECKSUM_ON_COPY
if (concat_chksummed) {
/*if concat checksumm swapped - swap it back */
if (concat_chksum_swapped) {
concat_chksum = SWAP_BYTES_IN_WORD(concat_chksum);
}
tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum,
&last_unsent->chksum_swapped);
last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED;
} else if (extendlen > 0) {
struct pbuf *p;
LWIP_ASSERT("tcp_write: extension of reference requires reference",
last_unsent != NULL && last_unsent->p != NULL);
for (p = last_unsent->p; p->next != NULL; p = p->next) {
p->tot_len += extendlen;
}
#endif /* TCP_CHECKSUM_ON_COPY */
p->tot_len += extendlen;
p->len += extendlen;
last_unsent->len += extendlen;
}
#if TCP_CHECKSUM_ON_COPY
if (concat_chksummed) {
LWIP_ASSERT("tcp_write: concat checksum needs concatenated data",
concat_p != NULL || extendlen > 0);
/*if concat checksumm swapped - swap it back */
if (concat_chksum_swapped) {
concat_chksum = SWAP_BYTES_IN_WORD(concat_chksum);
}
tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum,
&last_unsent->chksum_swapped);
last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED;
}
#endif /* TCP_CHECKSUM_ON_COPY */
/*
* Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that
* is harmless
@ -808,8 +835,8 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE,
("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",
ntohl(seg->tcphdr->seqno),
ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
lwip_ntohl(seg->tcphdr->seqno),
lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
(u16_t)flags));
/* Now append seg to pcb->unsent queue */
@ -856,8 +883,8 @@ tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)
{
/* Pad with two NOP options to make everything nicely aligned */
opts[0] = PP_HTONL(0x0101080A);
opts[1] = htonl(sys_now());
opts[2] = htonl(pcb->ts_recent);
opts[1] = lwip_htonl(sys_now());
opts[2] = lwip_htonl(pcb->ts_recent);
}
#endif
@ -874,7 +901,8 @@ tcp_build_wnd_scale_option(u32_t *opts)
}
#endif
/** Send an ACK without data.
/**
* Send an ACK without data.
*
* @param pcb Protocol control block for the TCP connection to send the ACK
*/
@ -895,7 +923,7 @@ tcp_send_empty_ack(struct tcp_pcb *pcb)
}
#endif
p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt));
p = tcp_output_alloc_header(pcb, optlen, 0, lwip_htonl(pcb->snd_nxt));
if (p == NULL) {
/* let tcp_fasttmr retry sending this ACK */
pcb->flags |= (TF_ACK_DELAY | TF_ACK_NOW);
@ -946,6 +974,7 @@ tcp_send_empty_ack(struct tcp_pcb *pcb)
}
/**
* @ingroup tcp_raw
* Find out what we can send and send it
*
* @param pcb Protocol control block for the TCP connection to send data
@ -987,7 +1016,7 @@ tcp_output(struct tcp_pcb *pcb)
*/
if (pcb->flags & TF_ACK_NOW &&
(seg == NULL ||
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
return tcp_send_empty_ack(pcb);
}
@ -1028,13 +1057,31 @@ tcp_output(struct tcp_pcb *pcb)
("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F
", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",
pcb->snd_wnd, pcb->cwnd, wnd,
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
ntohl(seg->tcphdr->seqno), pcb->lastack));
lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
lwip_ntohl(seg->tcphdr->seqno), pcb->lastack));
}
#endif /* TCP_CWND_DEBUG */
/* Check if we need to start the persistent timer when the next unsent segment
* does not fit within the remaining send window and RTO timer is not running (we
* have no in-flight data). A traditional approach would fill the remaining window
* with part of the unsent segment (which will engage zero-window probing upon
* reception of the zero window update from the receiver). This ensures the
* subsequent window update is reliably received. With the goal of being lightweight,
* we avoid splitting the unsent segment and treat the window as already zero.
*/
if (seg != NULL &&
lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd &&
wnd > 0 && wnd == pcb->snd_wnd && pcb->unacked == NULL) {
/* Start the persist timer */
if (pcb->persist_backoff == 0) {
pcb->persist_cnt = 0;
pcb->persist_backoff = 1;
}
goto output_done;
}
/* data available and window allows it to be sent? */
while (seg != NULL &&
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
LWIP_ASSERT("RST not expected here!",
(TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);
/* Stop sending if the nagle algorithm would prevent it
@ -1051,9 +1098,9 @@ tcp_output(struct tcp_pcb *pcb)
#if TCP_CWND_DEBUG
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",
pcb->snd_wnd, pcb->cwnd, wnd,
ntohl(seg->tcphdr->seqno) + seg->len -
lwip_ntohl(seg->tcphdr->seqno) + seg->len -
pcb->lastack,
ntohl(seg->tcphdr->seqno), pcb->lastack, i));
lwip_ntohl(seg->tcphdr->seqno), pcb->lastack, i));
++i;
#endif /* TCP_CWND_DEBUG */
@ -1074,7 +1121,7 @@ tcp_output(struct tcp_pcb *pcb)
if (pcb->state != SYN_SENT) {
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
}
snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
snd_nxt = lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
pcb->snd_nxt = snd_nxt;
}
@ -1090,11 +1137,11 @@ tcp_output(struct tcp_pcb *pcb)
/* In the case of fast retransmit, the packet should not go to the tail
* of the unacked queue, but rather somewhere before it. We need to check for
* this case. -STJ Jul 27, 2004 */
if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) {
if (TCP_SEQ_LT(lwip_ntohl(seg->tcphdr->seqno), lwip_ntohl(useg->tcphdr->seqno))) {
/* add segment to before tail of unacked list, keeping the list sorted */
struct tcp_seg **cur_seg = &(pcb->unacked);
while (*cur_seg &&
TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
TCP_SEQ_LT(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_ntohl(seg->tcphdr->seqno))) {
cur_seg = &((*cur_seg)->next );
}
seg->next = (*cur_seg);
@ -1111,6 +1158,7 @@ tcp_output(struct tcp_pcb *pcb)
}
seg = pcb->unsent;
}
output_done:
#if TCP_OVERSIZE
if (pcb->unsent == NULL) {
/* last unsent has been removed, reset unsent_oversize */
@ -1145,18 +1193,18 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif
/* The TCP header has already been constructed, but the ackno and
wnd fields remain. */
seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
seg->tcphdr->ackno = lwip_htonl(pcb->rcv_nxt);
/* advertise our receive window size in this TCP segment */
#if LWIP_WND_SCALE
if (seg->flags & TF_SEG_OPTS_WND_SCALE) {
/* The Window field in a SYN segment itself (the only type where we send
the window scale option) is never scaled. */
seg->tcphdr->wnd = htons(TCPWND_MIN16(pcb->rcv_ann_wnd));
seg->tcphdr->wnd = lwip_htons(TCPWND_MIN16(pcb->rcv_ann_wnd));
} else
#endif /* LWIP_WND_SCALE */
{
seg->tcphdr->wnd = htons(TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd)));
seg->tcphdr->wnd = lwip_htons(TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd)));
}
pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
@ -1198,12 +1246,12 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif
if (pcb->rttest == 0) {
pcb->rttest = tcp_ticks;
pcb->rtseq = ntohl(seg->tcphdr->seqno);
pcb->rtseq = lwip_ntohl(seg->tcphdr->seqno);
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));
}
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",
htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
lwip_htonl(seg->tcphdr->seqno), lwip_htonl(seg->tcphdr->seqno) +
seg->len));
len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
@ -1301,10 +1349,10 @@ tcp_rst(u32_t seqno, u32_t ackno,
(p->len >= sizeof(struct tcp_hdr)));
tcphdr = (struct tcp_hdr *)p->payload;
tcphdr->src = htons(local_port);
tcphdr->dest = htons(remote_port);
tcphdr->seqno = htonl(seqno);
tcphdr->ackno = htonl(ackno);
tcphdr->src = lwip_htons(local_port);
tcphdr->dest = lwip_htons(remote_port);
tcphdr->seqno = lwip_htonl(seqno);
tcphdr->ackno = lwip_htonl(ackno);
TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK);
#if LWIP_WND_SCALE
tcphdr->wnd = PP_HTONS(((TCP_WND >> TCP_RCV_SCALE) & 0xFFFF));
@ -1376,7 +1424,7 @@ tcp_rexmit_rto(struct tcp_pcb *pcb)
/**
* Requeue the first unacked segment for retransmission
*
* Called by tcp_receive() for fast retramsmit.
* Called by tcp_receive() for fast retransmit.
*
* @param pcb the tcp_pcb for which to retransmit the first unacked segment
*/
@ -1397,7 +1445,7 @@ tcp_rexmit(struct tcp_pcb *pcb)
cur_seg = &(pcb->unsent);
while (*cur_seg &&
TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
TCP_SEQ_LT(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_ntohl(seg->tcphdr->seqno))) {
cur_seg = &((*cur_seg)->next );
}
seg->next = *cur_seg;
@ -1435,7 +1483,7 @@ tcp_rexmit_fast(struct tcp_pcb *pcb)
("tcp_receive: dupacks %"U16_F" (%"U32_F
"), fast retransmit %"U32_F"\n",
(u16_t)pcb->dupacks, pcb->lastack,
ntohl(pcb->unacked->tcphdr->seqno)));
lwip_ntohl(pcb->unacked->tcphdr->seqno)));
tcp_rexmit(pcb);
/* Set ssthresh to half of the minimum of the current
@ -1486,7 +1534,7 @@ tcp_keepalive(struct tcp_pcb *pcb)
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
tcp_ticks, pcb->tmr, (u16_t)pcb->keep_cnt_sent));
p = tcp_output_alloc_header(pcb, 0, 0, htonl(pcb->snd_nxt - 1));
p = tcp_output_alloc_header(pcb, 0, 0, lwip_htonl(pcb->snd_nxt - 1));
if (p == NULL) {
LWIP_DEBUGF(TCP_DEBUG,
("tcp_keepalive: could not allocate memory for pbuf\n"));
@ -1535,6 +1583,7 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
struct tcp_seg *seg;
u16_t len;
u8_t is_fin;
u32_t snd_nxt;
struct netif *netif;
LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to "));
@ -1579,6 +1628,12 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
pbuf_copy_partial(seg->p, d, 1, seg->p->tot_len - seg->len);
}
/* The byte may be acknowledged without the window being opened. */
snd_nxt = lwip_ntohl(seg->tcphdr->seqno) + 1;
if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
pcb->snd_nxt = snd_nxt;
}
netif = ip_route(&pcb->local_ip, &pcb->remote_ip);
if (netif == NULL) {
err = ERR_RTE;

View File

@ -179,7 +179,7 @@ void sys_timeouts_init(void)
for (i = 1; i < LWIP_ARRAYSIZE(lwip_cyclic_timers); i++) {
/* we have to cast via size_t to get rid of const warning
(this is OK as cyclic_timer() casts back to const* */
sys_timeout(lwip_cyclic_timers[i].interval_ms, cyclic_timer, (void*)(size_t)&lwip_cyclic_timers[i]);
sys_timeout(lwip_cyclic_timers[i].interval_ms, cyclic_timer, LWIP_CONST_CAST(void*, &lwip_cyclic_timers[i]));
}
/* Initialise timestamp for sys_check_timeouts */
@ -360,7 +360,6 @@ sys_check_timeouts(void)
}
}
#if NO_SYS
/** 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
@ -371,7 +370,6 @@ sys_restart_timeouts(void)
{
timeouts_last_time = sys_now();
}
#endif /* NO_SYS */
/** Return the time left before the next timeout is due. If no timeouts are
* enqueued, returns 0xffffffff

View File

@ -1,7 +1,13 @@
/**
* @file
* User Datagram Protocol module\n
* The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).\n
* See also @ref udp_raw
*
* @defgroup udp_raw UDP
* @ingroup callbackstyle_api
* User Datagram Protocol module\n
* @see @ref raw_api and @ref netconn
*/
/*
@ -36,19 +42,6 @@
*
*/
/**
* @defgroup udp_raw UDP
* @ingroup raw_api
* User Datagram Protocol module\n
* @see @ref raw_api and @ref netconn
*/
/* udp.c
*
* The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).
*
*/
/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'!
*/
@ -63,7 +56,6 @@
#include "lwip/ip_addr.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/inet_chksum.h"
#include "lwip/netif.h"
#include "lwip/icmp.h"
#include "lwip/icmp6.h"
@ -124,24 +116,6 @@ again:
}
}
return udp_port;
#if 0
struct udp_pcb *ipcb = udp_pcbs;
while ((ipcb != NULL) && (udp_port != UDP_LOCAL_PORT_RANGE_END)) {
if (ipcb->local_port == udp_port) {
/* port is already used by another udp_pcb */
udp_port++;
/* restart scanning all udp pcbs */
ipcb = udp_pcbs;
} else {
/* go on with next udp pcb */
ipcb = ipcb->next;
}
}
if (ipcb != NULL) {
return 0;
}
return udp_port;
#endif
}
/** Common code to see if the current input packet matches the pcb
@ -186,19 +160,12 @@ udp_input_local_match(struct udp_pcb *pcb, struct netif *inp, u8_t broadcast)
}
} else
#endif /* LWIP_IPV4 */
/* Handle IPv4 and IPv6: all, multicast or exact match */
if (ip_addr_isany(&pcb->local_ip) ||
#if LWIP_IPV6_MLD
(ip_current_is_v6() && ip6_addr_ismulticast(ip6_current_dest_addr())) ||
#endif /* LWIP_IPV6_MLD */
#if LWIP_IGMP
(!ip_current_is_v6() && ip4_addr_ismulticast(ip4_current_dest_addr())) ||
#endif /* LWIP_IGMP */
ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) {
/* Handle IPv4 and IPv6: all or exact match */
if (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) {
return 1;
}
}
return 0;
}
@ -250,17 +217,17 @@ udp_input(struct pbuf *p, struct netif *inp)
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));
/* convert src and dest ports to host byte order */
src = ntohs(udphdr->src);
dest = ntohs(udphdr->dest);
src = lwip_ntohs(udphdr->src);
dest = lwip_ntohs(udphdr->dest);
udp_debug_print(udphdr);
/* print the UDP source and destination */
LWIP_DEBUGF(UDP_DEBUG, ("udp ("));
ip_addr_debug_print(UDP_DEBUG, ip_current_dest_addr());
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", ntohs(udphdr->dest)));
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", lwip_ntohs(udphdr->dest)));
ip_addr_debug_print(UDP_DEBUG, ip_current_src_addr());
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", ntohs(udphdr->src)));
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", lwip_ntohs(udphdr->src)));
pcb = NULL;
prev = NULL;
@ -339,7 +306,7 @@ udp_input(struct pbuf *p, struct netif *inp)
#if LWIP_UDPLITE
if (ip_current_header_proto() == IP_PROTO_UDPLITE) {
/* Do the UDP Lite checksum */
u16_t chklen = ntohs(udphdr->len);
u16_t chklen = lwip_ntohs(udphdr->len);
if (chklen < sizeof(struct udp_hdr)) {
if (chklen == 0) {
/* For UDP-Lite, checksum length of 0 means checksum
@ -437,7 +404,7 @@ udp_input(struct pbuf *p, struct netif *inp)
destination address was broadcast/multicast. */
if (!broadcast && !ip_addr_ismulticast(ip_current_dest_addr())) {
/* move payload pointer back to ip header */
pbuf_header_force(p, ip_current_header_tot_len() + UDP_HLEN);
pbuf_header_force(p, (s16_t)(ip_current_header_tot_len() + UDP_HLEN));
icmp_port_unreach(ip_current_is_v6(), p);
}
#endif /* LWIP_ICMP || LWIP_ICMP6 */
@ -579,7 +546,12 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip,
#endif /* LWIP_IPV6 || (LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS) */
/* find the outgoing network interface for this packet */
netif = ip_route(&pcb->local_ip, dst_ip_route);
if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
/* Don't call ip_route() with IP_ANY_TYPE */
netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(dst_ip_route)), dst_ip_route);
} else {
netif = ip_route(&pcb->local_ip, dst_ip_route);
}
/* no outgoing network interface could be found? */
if (netif == NULL) {
@ -670,7 +642,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_i
* this could be an old address if netif->ip_addr has changed */
if (!ip4_addr_cmp(ip_2_ip4(&(pcb->local_ip)), netif_ip4_addr(netif))) {
/* local_ip doesn't match, drop the packet */
return ERR_VAL;
return ERR_RTE;
}
/* use UDP PCB local IP address as source address */
src_ip = &pcb->local_ip;
@ -760,8 +732,8 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d
(q->len >= sizeof(struct udp_hdr)));
/* q now represents the packet to be sent */
udphdr = (struct udp_hdr *)q->payload;
udphdr->src = htons(pcb->local_port);
udphdr->dest = htons(dst_port);
udphdr->src = lwip_htons(pcb->local_port);
udphdr->dest = lwip_htons(dst_port);
/* in UDP, 0 checksum means 'no checksum' */
udphdr->chksum = 0x0000;
@ -794,7 +766,7 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d
chklen_hdr = 0;
chklen = q->tot_len;
}
udphdr->len = htons(chklen_hdr);
udphdr->len = lwip_htons(chklen_hdr);
/* calculate checksum */
#if CHECKSUM_GEN_UDP
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_UDP) {
@ -825,7 +797,7 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d
#endif /* LWIP_UDPLITE */
{ /* UDP */
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len));
udphdr->len = htons(q->tot_len);
udphdr->len = lwip_htons(q->tot_len);
/* calculate checksum */
#if CHECKSUM_GEN_UDP
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_UDP) {
@ -859,7 +831,7 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d
/* Determine TTL to use */
#if LWIP_MULTICAST_TX_OPTIONS
ttl = (ip_addr_ismulticast(dst_ip) ? pcb->mcast_ttl : pcb->ttl);
ttl = (ip_addr_ismulticast(dst_ip) ? udp_get_multicast_ttl(pcb) : pcb->ttl);
#else /* LWIP_MULTICAST_TX_OPTIONS */
ttl = pcb->ttl;
#endif /* LWIP_MULTICAST_TX_OPTIONS */
@ -891,7 +863,7 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d
* Bind an UDP PCB.
*
* @param pcb UDP PCB to be bound with a local address ipaddr and port.
* @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
* @param ipaddr local IP address to bind with. Use IP4_ADDR_ANY to
* bind to all local interfaces.
* @param port local UDP port to bind with. Use 0 to automatically bind
* to a random port between UDP_LOCAL_PORT_RANGE_START and
@ -915,12 +887,12 @@ udp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port)
#if LWIP_IPV4
/* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */
if (ipaddr == NULL) {
ipaddr = IP_ADDR_ANY;
ipaddr = IP4_ADDR_ANY;
}
#endif /* LWIP_IPV4 */
/* still need to check for ipaddr == NULL in IPv6 only case */
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
return ERR_VAL;
}
@ -1141,7 +1113,7 @@ udp_new(void)
memset(pcb, 0, sizeof(struct udp_pcb));
pcb->ttl = UDP_TTL;
#if LWIP_MULTICAST_TX_OPTIONS
pcb->mcast_ttl = UDP_TTL;
udp_set_multicast_ttl(pcb, UDP_TTL);
#endif /* LWIP_MULTICAST_TX_OPTIONS */
}
return pcb;
@ -1151,7 +1123,9 @@ udp_new(void)
* @ingroup udp_raw
* Create a UDP PCB for specific IP type.
*
* @param type IP address type, see IPADDR_TYPE_XX definitions.
* @param type IP address type, see @ref lwip_ip_addr_type definitions.
* If you want to listen to IPv4 and IPv6 (dual-stack) packets,
* supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE.
* @return The UDP PCB which was created. NULL if the PCB data structure
* could not be allocated.
*
@ -1173,32 +1147,26 @@ udp_new_ip_type(u8_t type)
return pcb;
}
#if LWIP_IPV4
/** This function is called from netif.c when address is changed
*
* @param old_addr IPv4 address of the netif before change
* @param new_addr IPv4 address of the netif after change
* @param old_addr IP address of the netif before change
* @param new_addr IP address of the netif after change
*/
void udp_netif_ipv4_addr_changed(const ip4_addr_t* old_addr, const ip4_addr_t* new_addr)
void udp_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr)
{
struct udp_pcb* upcb;
if (!ip4_addr_isany(new_addr)) {
if (!ip_addr_isany(old_addr) && !ip_addr_isany(new_addr)) {
for (upcb = udp_pcbs; upcb != NULL; upcb = upcb->next) {
/* Is this an IPv4 pcb? */
if (IP_IS_V4_VAL(upcb->local_ip)) {
/* PCB bound to current local interface address? */
if (!ip4_addr_isany(ip_2_ip4(&upcb->local_ip)) &&
ip4_addr_cmp(ip_2_ip4(&upcb->local_ip), old_addr)) {
/* The PCB is bound to the old ipaddr and
* is set to bound to the new one instead */
ip_addr_copy_from_ip4(upcb->local_ip, *new_addr);
}
/* PCB bound to current local interface address? */
if (ip_addr_cmp(&upcb->local_ip, old_addr)) {
/* The PCB is bound to the old ipaddr and
* is set to bound to the new one instead */
ip_addr_copy(upcb->local_ip, *new_addr);
}
}
}
}
#endif /* LWIP_IPV4 */
#if UDP_DEBUG
/**
@ -1212,10 +1180,10 @@ udp_debug_print(struct udp_hdr *udphdr)
LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n"));
LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n",
ntohs(udphdr->src), ntohs(udphdr->dest)));
lwip_ntohs(udphdr->src), lwip_ntohs(udphdr->dest)));
LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n",
ntohs(udphdr->len), ntohs(udphdr->chksum)));
lwip_ntohs(udphdr->len), lwip_ntohs(udphdr->chksum)));
LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
}
#endif /* UDP_DEBUG */

View File

@ -43,8 +43,7 @@
/* Note: Netconn API is always available when sockets are enabled -
* sockets are implemented on top of them */
#include <stddef.h> /* for size_t */
#include "lwip/arch.h"
#include "lwip/netbuf.h"
#include "lwip/sys.h"
#include "lwip/ip_addr.h"
@ -90,6 +89,7 @@ extern "C" {
#define NETCONNTYPE_ISUDPLITE(t) (((t)&0xF3) == NETCONN_UDPLITE)
#define NETCONNTYPE_ISUDPNOCHKSUM(t) (((t)&0xF3) == NETCONN_UDPNOCHKSUM)
#else /* LWIP_IPV6 */
#define NETCONNTYPE_ISIPV6(t) (0)
#define NETCONNTYPE_ISUDPLITE(t) ((t) == NETCONN_UDPLITE)
#define NETCONNTYPE_ISUDPNOCHKSUM(t) ((t) == NETCONN_UDPNOCHKSUM)
#endif /* LWIP_IPV6 */
@ -139,7 +139,32 @@ enum netconn_state {
NETCONN_CLOSE
};
/** Use to inform the callback function about changes */
/** Used to inform the callback function about changes
*
* Event explanation:
*
* In the netconn implementation, there are three ways to block a client:
*
* - accept mbox (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); in netconn_accept())
* - receive mbox (sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); in netconn_recv_data())
* - send queue is full (sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); in lwip_netconn_do_write())
*
* The events have to be seen as events signaling the state of these mboxes/semaphores. For non-blocking
* connections, you need to know in advance whether a call to a netconn function call would block or not,
* and these events tell you about that.
*
* RCVPLUS events say: Safe to perform a potentially blocking call call once more.
* They are counted in sockets - three RCVPLUS events for accept mbox means you are safe
* to call netconn_accept 3 times without being blocked.
* Same thing for receive mbox.
*
* RCVMINUS events say: Your call to to a possibly blocking function is "acknowledged".
* Socket implementation decrements the counter.
*
* For TX, there is no need to count, its merely a flag. SENDPLUS means you may send something.
* SENDPLUS occurs when enough data was delivered to peer so netconn_send() can be called again.
* A SENDMINUS event occurs when the next call to a netconn_send() would be blocking.
*/
enum netconn_evt {
NETCONN_EVT_RCVPLUS,
NETCONN_EVT_RCVMINUS,
@ -327,7 +352,7 @@ err_t netconn_gethostbyname(const char *name, ip_addr_t *addr);
#if LWIP_IPV6
/** @ingroup netconn_common
* TCP: Set the IPv6 ONLY status of netconn calls (see NETCONN_FLAG_IPV6_V6ONLY)
* TCP: Set the IPv6 ONLY status of netconn calls (see NETCONN_FLAG_IPV6_V6ONLY)
*/
#define netconn_set_ipv6only(conn, val) do { if(val) { \
(conn)->flags |= NETCONN_FLAG_IPV6_V6ONLY; \

View File

@ -161,28 +161,6 @@
#define HTTPD_DEBUG_TIMING LWIP_DBG_OFF
#endif
/** Set this to 1 on platforms where strnstr is not available */
#if !defined LWIP_HTTPD_STRNSTR_PRIVATE || defined __DOXYGEN__
#define LWIP_HTTPD_STRNSTR_PRIVATE 1
#endif
/** Set this to 1 on platforms where stricmp is not available */
#if !defined LWIP_HTTPD_STRICMP_PRIVATE || defined __DOXYGEN__
#define LWIP_HTTPD_STRICMP_PRIVATE 0
#endif
/** Define this to a smaller function if you have itoa() at hand... */
#if !defined LWIP_HTTPD_ITOA || defined __DOXYGEN__
#if !defined LWIP_HTTPD_ITOA_PRIVATE || defined __DOXYGEN__
#define LWIP_HTTPD_ITOA_PRIVATE 1
#endif
#if LWIP_HTTPD_ITOA_PRIVATE
#define LWIP_HTTPD_ITOA(buffer, bufsize, number) httpd_itoa(number, buffer)
#else
#define LWIP_HTTPD_ITOA(buffer, bufsize, number) snprintf(buffer, bufsize, "%d", number)
#endif
#endif
/** Set this to one to show error pages when parsing a request fails instead
of simply closing the connection. */
#if !defined LWIP_HTTPD_SUPPORT_EXTSTATUS || defined __DOXYGEN__

View File

@ -0,0 +1,69 @@
/**
* @file
* MDNS responder
*/
/*
* Copyright (c) 2015 Verisure Innovation AB
* 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: Erik Ekman <erik@kryo.se>
*
*/
#ifndef LWIP_HDR_MDNS_H
#define LWIP_HDR_MDNS_H
#include "lwip/apps/mdns_opts.h"
#include "lwip/netif.h"
#if LWIP_MDNS_RESPONDER
enum mdns_sd_proto {
DNSSD_PROTO_UDP = 0,
DNSSD_PROTO_TCP = 1
};
#define MDNS_LABEL_MAXLEN 63
struct mdns_host;
struct mdns_service;
/** Callback function to add text to a reply, called when generating the reply */
typedef void (*service_get_txt_fn_t)(struct mdns_service *service, void *txt_userdata);
void mdns_resp_init(void);
err_t mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl);
err_t mdns_resp_remove_netif(struct netif *netif);
err_t mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, u32_t dns_ttl, service_get_txt_fn_t txt_fn, void *txt_userdata);
err_t mdns_resp_add_service_txtitem(struct mdns_service *service, const char *txt, u8_t txt_len);
void mdns_resp_netif_settings_changed(struct netif *netif);
#endif /* LWIP_MDNS_RESPONDER */
#endif /* LWIP_HDR_MDNS_H */

View File

@ -0,0 +1,74 @@
/**
* @file
* MDNS responder
*/
/*
* Copyright (c) 2015 Verisure Innovation AB
* 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: Erik Ekman <erik@kryo.se>
*
*/
#ifndef LWIP_HDR_APPS_MDNS_OPTS_H
#define LWIP_HDR_APPS_MDNS_OPTS_H
#include "lwip/opt.h"
/**
* @defgroup mdns_opts Options
* @ingroup mdns
* @{
*/
/**
* LWIP_MDNS_RESPONDER==1: Turn on multicast DNS module. UDP must be available for MDNS
* transport. IGMP is needed for IPv4 multicast.
*/
#ifndef LWIP_MDNS_RESPONDER
#define LWIP_MDNS_RESPONDER 0
#endif /* LWIP_MDNS_RESPONDER */
/** The maximum number of services per netif */
#ifndef MDNS_MAX_SERVICES
#define MDNS_MAX_SERVICES 1
#endif
/**
* MDNS_DEBUG: Enable debugging for multicast DNS.
*/
#ifndef MDNS_DEBUG
#define MDNS_DEBUG LWIP_DBG_OFF
#endif
/**
* @}
*/
#endif /* LWIP_HDR_APPS_MDNS_OPTS_H */

View File

@ -0,0 +1,66 @@
/**
* @file
* MDNS responder private definitions
*/
/*
* Copyright (c) 2015 Verisure Innovation AB
* 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: Erik Ekman <erik@kryo.se>
*
*/
#ifndef LWIP_HDR_MDNS_PRIV_H
#define LWIP_HDR_MDNS_PRIV_H
#include "lwip/apps/mdns_opts.h"
#include "lwip/pbuf.h"
#if LWIP_MDNS_RESPONDER
/* Domain struct and methods - visible for unit tests */
#define MDNS_DOMAIN_MAXLEN 256
#define MDNS_READNAME_ERROR 0xFFFF
struct mdns_domain {
/* Encoded domain name */
u8_t name[MDNS_DOMAIN_MAXLEN];
/* Total length of domain name, including zero */
u16_t length;
/* Set if compression of this domain is not allowed */
u8_t skip_compression;
};
err_t mdns_domain_add_label(struct mdns_domain *domain, const char *label, u8_t len);
u16_t mdns_readname(struct pbuf *p, u16_t offset, struct mdns_domain *domain);
int mdns_domain_eq(struct mdns_domain *a, struct mdns_domain *b);
u16_t mdns_compress_domain(struct pbuf *pbuf, u16_t *offset, struct mdns_domain *domain);
#endif /* LWIP_MDNS_RESPONDER */
#endif /* LWIP_HDR_MDNS_PRIV_H */

View File

@ -0,0 +1,243 @@
/**
* @file
* MQTT client
*/
/*
* Copyright (c) 2016 Erik Andersson
* 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: Erik Andersson
*
*/
#ifndef LWIP_HDR_APPS_MQTT_CLIENT_H
#define LWIP_HDR_APPS_MQTT_CLIENT_H
#include "lwip/apps/mqtt_opts.h"
#include "lwip/err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct mqtt_client_t mqtt_client_t;
/** @ingroup mqtt
* Default MQTT port */
#define MQTT_PORT 1883
/*---------------------------------------------------------------------------------------------- */
/* Connection with server */
/**
* @ingroup mqtt
* Client information and connection parameters */
struct mqtt_connect_client_info_t {
/** Client identifier, must be set by caller */
const char *client_id;
/** User name and password, set to NULL if not used */
const char* client_user;
const char* client_pass;
/** keep alive time in seconds, 0 to disable keep alive functionality*/
u16_t keep_alive;
/** will topic, set to NULL if will is not to be used,
will_msg, will_qos and will retain are then ignored */
const char* will_topic;
const char* will_msg;
u8_t will_qos;
u8_t will_retain;
};
/**
* @ingroup mqtt
* Connection status codes */
typedef enum
{
MQTT_CONNECT_ACCEPTED = 0,
MQTT_CONNECT_REFUSED_PROTOCOL_VERSION = 1,
MQTT_CONNECT_REFUSED_IDENTIFIER = 2,
MQTT_CONNECT_REFUSED_SERVER = 3,
MQTT_CONNECT_REFUSED_USERNAME_PASS = 4,
MQTT_CONNECT_REFUSED_NOT_AUTHORIZED_ = 5,
MQTT_CONNECT_DISCONNECTED = 256,
MQTT_CONNECT_TIMEOUT = 257
} mqtt_connection_status_t;
/**
* @ingroup mqtt
* Function prototype for mqtt connection status callback. Called when
* client has connected to the server after initiating a mqtt connection attempt by
* calling mqtt_connect() or when connection is closed by server or an error
*
* @param client MQTT client itself
* @param arg Additional argument to pass to the callback function
* @param status Connect result code or disconnection notification @see mqtt_connection_status_t
*
*/
typedef void (*mqtt_connection_cb_t)(mqtt_client_t *client, void *arg, mqtt_connection_status_t status);
/**
* @ingroup mqtt
* Data callback flags */
enum {
/** Flag set when last fragment of data arrives in data callback */
MQTT_DATA_FLAG_LAST = 1
};
/**
* @ingroup mqtt
* Function prototype for MQTT incoming publish data callback function. Called when data
* arrives to a subscribed topic @see mqtt_subscribe
*
* @param arg Additional argument to pass to the callback function
* @param data User data, pointed object, data may not be referenced after callback return,
NULL is passed when all publish data are delivered
* @param len Length of publish data fragment
* @param flags MQTT_DATA_FLAG_LAST set when this call contains the last part of data from publish message
*
*/
typedef void (*mqtt_incoming_data_cb_t)(void *arg, const u8_t *data, u16_t len, u8_t flags);
/**
* @ingroup mqtt
* Function prototype for MQTT incoming publish function. Called when an incoming publish
* arrives to a subscribed topic @see mqtt_subscribe
*
* @param arg Additional argument to pass to the callback function
* @param topic Zero terminated Topic text string, topic may not be referenced after callback return
* @param tot_len Total length of publish data, if set to 0 (no publish payload) data callback will not be invoked
*/
typedef void (*mqtt_incoming_publish_cb_t)(void *arg, const char *topic, u32_t tot_len);
/**
* @ingroup mqtt
* Function prototype for mqtt request callback. Called when a subscribe, unsubscribe
* or publish request has completed
* @param arg Pointer to user data supplied when invoking request
* @param err ERR_OK on success
* ERR_TIMEOUT if no response was received within timeout,
* ERR_ABRT if (un)subscribe was denied
*/
typedef void (*mqtt_request_cb_t)(void *arg, err_t err);
/**
* Pending request item, binds application callback to pending server requests
*/
struct mqtt_request_t
{
/** Next item in list, NULL means this is the last in chain,
next pointing at itself means request is unallocated */
struct mqtt_request_t *next;
/** Callback to upper layer */
mqtt_request_cb_t cb;
void *arg;
/** MQTT packet identifier */
u16_t pkt_id;
/** Expire time relative to element before this */
u16_t timeout_diff;
};
/** Ring buffer */
struct mqtt_ringbuf_t {
u16_t put;
u16_t get;
u8_t buf[MQTT_OUTPUT_RINGBUF_SIZE];
};
/** MQTT client */
struct mqtt_client_t
{
/** Timers and timeouts */
u16_t cyclic_tick;
u16_t keep_alive;
u16_t server_watchdog;
/** Packet identifier generator*/
u16_t pkt_id_seq;
/** Packet identifier of pending incoming publish */
u16_t inpub_pkt_id;
/** Connection state */
u8_t conn_state;
struct tcp_pcb *conn;
/** Connection callback */
void *connect_arg;
mqtt_connection_cb_t connect_cb;
/** Pending requests to server */
struct mqtt_request_t *pend_req_queue;
struct mqtt_request_t req_list[MQTT_REQ_MAX_IN_FLIGHT];
void *inpub_arg;
/** Incoming data callback */
mqtt_incoming_data_cb_t data_cb;
mqtt_incoming_publish_cb_t pub_cb;
/** Input */
u32_t msg_idx;
u8_t rx_buffer[MQTT_VAR_HEADER_BUFFER_LEN];
/** Output ring-buffer */
struct mqtt_ringbuf_t output;
};
/** Connect to server */
err_t mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ipaddr, u16_t port, mqtt_connection_cb_t cb, void *arg,
const struct mqtt_connect_client_info_t *client_info);
/** Disconnect from server */
void mqtt_disconnect(mqtt_client_t *client);
/** Create new client */
mqtt_client_t *mqtt_client_new(void);
/** Check connection status */
u8_t mqtt_client_is_connected(mqtt_client_t *client);
/** Set callback to call for incoming publish */
void mqtt_set_inpub_callback(mqtt_client_t *client, mqtt_incoming_publish_cb_t,
mqtt_incoming_data_cb_t data_cb, void *arg);
/** Common function for subscribe and unsubscribe */
err_t mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_request_cb_t cb, void *arg, u8_t sub);
/** @ingroup mqtt
*Subscribe to topic */
#define mqtt_subscribe(client, topic, qos, cb, arg) mqtt_sub_unsub(client, topic, qos, cb, arg, 1)
/** @ingroup mqtt
* Unsubscribe to topic */
#define mqtt_unsubscribe(client, topic, cb, arg) mqtt_sub_unsub(client, topic, 0, cb, arg, 0)
/** Publish data to topic */
err_t mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_t payload_length, u8_t qos, u8_t retain,
mqtt_request_cb_t cb, void *arg);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_HDR_APPS_MQTT_CLIENT_H */

View File

@ -0,0 +1,103 @@
/**
* @file
* MQTT client options
*/
/*
* Copyright (c) 2016 Erik Andersson
* 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: Erik Andersson
*
*/
#ifndef LWIP_HDR_APPS_MQTT_OPTS_H
#define LWIP_HDR_APPS_MQTT_OPTS_H
#include "lwip/opt.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup mqtt_opts Options
* @ingroup mqtt
* @{
*/
/**
* Output ring-buffer size, must be able to fit largest outgoing publish message topic+payloads
*/
#ifndef MQTT_OUTPUT_RINGBUF_SIZE
#define MQTT_OUTPUT_RINGBUF_SIZE 256
#endif
/**
* Number of bytes in receive buffer, must be at least the size of the longest incoming topic + 8
* If one wants to avoid fragmented incoming publish, set length to max incoming topic length + max payload length + 8
*/
#ifndef MQTT_VAR_HEADER_BUFFER_LEN
#define MQTT_VAR_HEADER_BUFFER_LEN 128
#endif
/**
* Maximum number of pending subscribe, unsubscribe and publish requests to server .
*/
#ifndef MQTT_REQ_MAX_IN_FLIGHT
#define MQTT_REQ_MAX_IN_FLIGHT 4
#endif
/**
* Seconds between each cyclic timer call.
*/
#ifndef MQTT_CYCLIC_TIMER_INTERVAL
#define MQTT_CYCLIC_TIMER_INTERVAL 5
#endif
/**
* Publish, subscribe and unsubscribe request timeout in seconds.
*/
#ifndef MQTT_REQ_TIMEOUT
#define MQTT_REQ_TIMEOUT 30
#endif
/**
* Seconds for MQTT connect response timeout after sending connect request
*/
#ifndef MQTT_CONNECT_TIMOUT
#define MQTT_CONNECT_TIMOUT 100
#endif
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* LWIP_HDR_APPS_MQTT_OPTS_H */

View File

@ -40,16 +40,6 @@
* @{
*/
/** Since there's no standard function for case-insensitive string comparision,
* we need another define here:
* define this to stricmp() for windows or strcasecmp() for linux.
* If not defined, comparision is case sensitive and the provided hostname must be
* uppercase.
*/
#if !defined NETBIOS_STRCMP || defined __DOXYGEN__
#define NETBIOS_STRCMP(str1, str2) strcmp(str1, str2)
#endif
/** NetBIOS name of lwip device
* This must be uppercase until NETBIOS_STRCMP() is defined to a string
* comparision function that is case insensitive.

View File

@ -99,6 +99,7 @@ void snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst);
err_t snmp_send_trap_generic(s32_t generic_trap);
err_t snmp_send_trap_specific(s32_t specific_trap, struct snmp_varbind *varbinds);
err_t snmp_send_trap(const struct snmp_obj_id* oid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds);
#define SNMP_AUTH_TRAPS_DISABLED 0
#define SNMP_AUTH_TRAPS_ENABLED 1

View File

@ -200,7 +200,7 @@ struct snmp_node_instance
u8_t asn1_type;
/** one out of instance access types defined above (SNMP_NODE_INSTANCE_READ_ONLY,...) */
snmp_access_t access;
/** returns object value for the given object identifier. Return values <0 to indicate an error */
node_instance_get_value_method get_value;
/** tests length and/or range BEFORE setting */
@ -278,7 +278,7 @@ struct snmp_next_oid_state
u32_t* next_oid;
u8_t next_oid_len;
u8_t next_oid_max_len;
snmp_next_oid_status_t status;
void* reference;
};

View File

@ -283,7 +283,11 @@
#endif
#ifndef LWIP_SNMP_V3_CRYPTO
#define LWIP_SNMP_V3_CRYPTO LWIP_SNMP_V3
#define LWIP_SNMP_V3_CRYPTO LWIP_SNMP_V3
#endif
#ifndef LWIP_SNMP_V3_MBEDTLS
#define LWIP_SNMP_V3_MBEDTLS LWIP_SNMP_V3
#endif
#endif /* LWIP_HDR_SNMP_OPTS_H */

View File

@ -85,7 +85,7 @@ snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len
#define SNMP_TABLE_GET_COLUMN_FROM_OID(oid) ((oid)[1]) /* first array value is (fixed) row entry (fixed to 1) and 2nd value is column, follow3ed by instance */
/** simple read-only table */
typedef enum {
SNMP_VARIANT_VALUE_TYPE_U32,

View File

@ -0,0 +1,105 @@
/****************************************************************//**
*
* @file tftp_opts.h
*
* @author Logan Gunthorpe <logang@deltatee.com>
*
* @brief Trivial File Transfer Protocol (RFC 1350) implementation options
*
* Copyright (c) Deltatee Enterprises Ltd. 2013
* 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.
*
* Author: Logan Gunthorpe <logang@deltatee.com>
*
*/
#ifndef LWIP_HDR_APPS_TFTP_OPTS_H
#define LWIP_HDR_APPS_TFTP_OPTS_H
#include "lwip/opt.h"
/**
* @defgroup tftp_opts Options
* @ingroup tftp
* @{
*/
/**
* Enable TFTP debug messages
*/
#if !defined TFTP_DEBUG || defined __DOXYGEN__
#define TFTP_DEBUG LWIP_DBG_ON
#endif
/**
* TFTP server port
*/
#if !defined TFTP_PORT || defined __DOXYGEN__
#define TFTP_PORT 69
#endif
/**
* TFTP timeout
*/
#if !defined TFTP_TIMEOUT_MSECS || defined __DOXYGEN__
#define TFTP_TIMEOUT_MSECS 10000
#endif
/**
* Max. number of retries when a file is read from server
*/
#if !defined TFTP_MAX_RETRIES || defined __DOXYGEN__
#define TFTP_MAX_RETRIES 5
#endif
/**
* TFTP timer cyclic interval
*/
#if !defined TFTP_TIMER_MSECS || defined __DOXYGEN__
#define TFTP_TIMER_MSECS 50
#endif
/**
* Max. length of TFTP filename
*/
#if !defined TFTP_MAX_FILENAME_LEN || defined __DOXYGEN__
#define TFTP_MAX_FILENAME_LEN 20
#endif
/**
* Max. length of TFTP mode
*/
#if !defined TFTP_MAX_MODE_LEN || defined __DOXYGEN__
#define TFTP_MAX_MODE_LEN 7
#endif
/**
* @}
*/
#endif /* LWIP_HDR_APPS_TFTP_OPTS_H */

View File

@ -0,0 +1,94 @@
/****************************************************************//**
*
* @file tftp_server.h
*
* @author Logan Gunthorpe <logang@deltatee.com>
*
* @brief Trivial File Transfer Protocol (RFC 1350)
*
* Copyright (c) Deltatee Enterprises Ltd. 2013
* 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.
*
* Author: Logan Gunthorpe <logang@deltatee.com>
*
*/
#ifndef LWIP_HDR_APPS_TFTP_SERVER_H
#define LWIP_HDR_APPS_TFTP_SERVER_H
#include "lwip/apps/tftp_opts.h"
#include "lwip/err.h"
#include "lwip/pbuf.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @ingroup tftp
* TFTP context containing callback functions for TFTP transfers
*/
struct tftp_context {
/**
* Open file for read/write.
* @param fname Filename
* @param mode Mode string from TFTP RFC 1350 (netascii, octet, mail)
* @param write Flag indicating read (0) or write (!= 0) access
* @returns File handle supplied to other functions
*/
void* (*open)(const char* fname, const char* mode, u8_t write);
/**
* Close file handle
* @param handle File handle returned by open()
*/
void (*close)(void* handle);
/**
* Read from file
* @param handle File handle returned by open()
* @param buf Target buffer to copy read data to
* @param bytes Number of bytes to copy to buf
* @returns &gt;= 0: Success; &lt; 0: Error
*/
int (*read)(void* handle, void* buf, int bytes);
/**
* Write to file
* @param handle File handle returned by open()
* @param pbuf PBUF adjusted such that payload pointer points
* to the beginning of write data. In other words,
* TFTP headers are stripped off.
* @returns &gt;= 0: Success; &lt; 0: Error
*/
int (*write)(void* handle, struct pbuf* p);
};
err_t tftp_init(const struct tftp_context* ctx);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_HDR_APPS_TFTP_SERVER_H */

View File

@ -47,12 +47,67 @@
#include "arch/cc.h"
/**
* @defgroup compiler_abstraction Compiler/platform abstraction
* @ingroup sys_layer
* All defines related to this section must not be placed in lwipopts.h,
* but in arch/cc.h!
* These options cannot be \#defined in lwipopts.h since they are not options
* of lwIP itself, but options of the lwIP port to your system.
* @{
*/
/** Define the byte order of the system.
* Needed for conversion of network data to host byte order.
* Allowed values: LITTLE_ENDIAN and BIG_ENDIAN
*/
#ifndef BYTE_ORDER
#define BYTE_ORDER LITTLE_ENDIAN
#endif
/** Define random number generator function of your system */
#ifndef LWIP_RAND
#define LWIP_RAND() ((u32_t)rand())
#endif
/** Platform specific diagnostic output.\n
* Note the default implementation pulls in printf, which may
* in turn pull in a lot of standard libary code. In resource-constrained
* systems, this should be defined to something less resource-consuming.
*/
#ifndef LWIP_PLATFORM_DIAG
#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#include <stdio.h>
#include <stdlib.h>
#endif
/** Platform specific assertion handling.\n
* Note the default implementation pulls in printf, fflush and abort, which may
* in turn pull in a lot of standard libary code. In resource-constrained
* systems, this should be defined to something less resource-consuming.
*/
#ifndef LWIP_PLATFORM_ASSERT
#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \
x, __LINE__, __FILE__); fflush(NULL); abort();} while(0)
#include <stdio.h>
#include <stdlib.h>
#endif
/** Define this to 1 in arch/cc.h of your port if you do not want to
* include stddef.h header to get size_t. You need to typedef size_t
* by yourself in this case.
*/
#ifndef LWIP_NO_STDDEF_H
#define LWIP_NO_STDDEF_H 0
#endif
#if !LWIP_NO_STDDEF_H
#include <stddef.h> /* for size_t */
#endif
/** Define this to 1 in arch/cc.h of your port if your compiler does not provide
* the stdint.h header. This cannot be \#defined in lwipopts.h since
* this is not an option of lwIP itself, but an option of the lwIP port
* to your system.
* Additionally, this header is meant to be \#included in lwipopts.h
* (you may need to declare function prototypes in there).
* the stdint.h header. You need to typedef the generic types listed in
* lwip/arch.h yourself in this case (u8_t, u16_t...).
*/
#ifndef LWIP_NO_STDINT_H
#define LWIP_NO_STDINT_H 0
@ -71,11 +126,8 @@ typedef uintptr_t mem_ptr_t;
#endif
/** Define this to 1 in arch/cc.h of your port if your compiler does not provide
* the inttypes.h header. This cannot be \#defined in lwipopts.h since
* this is not an option of lwIP itself, but an option of the lwIP port
* to your system.
* Additionally, this header is meant to be \#included in lwipopts.h
* (you may need to declare function prototypes in there).
* the inttypes.h header. You need to define the format strings listed in
* lwip/arch.h yourself in this case (X8_F, U16_F...).
*/
#ifndef LWIP_NO_INTTYPES_H
#define LWIP_NO_INTTYPES_H 0
@ -85,7 +137,7 @@ typedef uintptr_t mem_ptr_t;
#if !LWIP_NO_INTTYPES_H
#include <inttypes.h>
#ifndef X8_F
#define X8_F "02"PRIx8
#define X8_F "02" PRIx8
#endif
#ifndef U16_F
#define U16_F PRIu16
@ -110,14 +162,31 @@ typedef uintptr_t mem_ptr_t;
#endif
#endif
/** C++ const_cast<target_type>(val) equivalent to remove constness from a value (GCC -Wcast-qual) */
#ifndef LWIP_CONST_CAST
#define LWIP_CONST_CAST(target_type, val) ((target_type)((ptrdiff_t)val))
#endif
/** Get rid of alignment cast warnings (GCC -Wcast-align) */
#ifndef LWIP_ALIGNMENT_CAST
#define LWIP_ALIGNMENT_CAST(target_type, val) LWIP_CONST_CAST(target_type, val)
#endif
/** Get rid of warnings related to pointer-to-numeric and vice-versa casts,
* e.g. "conversion from 'u8_t' to 'void *' of greater size"
*/
#ifndef LWIP_PTR_NUMERIC_CAST
#define LWIP_PTR_NUMERIC_CAST(target_type, val) LWIP_CONST_CAST(target_type, val)
#endif
/** Allocates a memory buffer of specified size that is of sufficient size to align
* its start address using LWIP_MEM_ALIGN.
* You can declare your own version here e.g. to enforce alignment without adding
* trailing padding bytes (see LWIP_MEM_ALIGN_BUFFER) or your own section placement
* requirements.
* e.g. if you use gcc and need 32 bit alignment:
* \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[size] __attribute__((aligned(4)))
* or more portable:
* requirements.\n
* e.g. if you use gcc and need 32 bit alignment:\n
* \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[size] \_\_attribute\_\_((aligned(4)))\n
* or more portable:\n
* \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u32_t variable_name[(size + sizeof(u32_t) - 1) / sizeof(u32_t)]
*/
#ifndef LWIP_DECLARE_MEMORY_ALIGNED
@ -151,175 +220,84 @@ typedef uintptr_t mem_ptr_t;
extern "C" {
#endif
/** Packed structs support.
* Placed BEFORE declaration of a packed struct.\n
* For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n
* A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here.
*/
#ifndef PACK_STRUCT_BEGIN
#define PACK_STRUCT_BEGIN
#endif /* PACK_STRUCT_BEGIN */
/** Packed structs support.
* Placed AFTER declaration of a packed struct.\n
* For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n
* A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here.
*/
#ifndef PACK_STRUCT_END
#define PACK_STRUCT_END
#endif /* PACK_STRUCT_END */
/** Packed structs support.
* Placed between end of declaration of a packed struct and trailing semicolon.\n
* For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n
* A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here.
*/
#ifndef PACK_STRUCT_STRUCT
#if defined(__GNUC__) || defined(__clang__)
#define PACK_STRUCT_STRUCT __attribute__((packed))
#else
#define PACK_STRUCT_STRUCT
#endif
#endif /* PACK_STRUCT_STRUCT */
/** Packed structs support.
* Wraps u32_t and u16_t members.\n
* For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n
* A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here.
*/
#ifndef PACK_STRUCT_FIELD
#define PACK_STRUCT_FIELD(x) x
#endif /* PACK_STRUCT_FIELD */
/* Used for struct fields of u8_t,
* where some compilers warn that packing is not necessary */
/** Packed structs support.
* Wraps u8_t members, where some compilers warn that packing is not necessary.\n
* For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n
* A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here.
*/
#ifndef PACK_STRUCT_FLD_8
#define PACK_STRUCT_FLD_8(x) PACK_STRUCT_FIELD(x)
#endif /* PACK_STRUCT_FLD_8 */
/* Used for struct fields of that are packed structs themself,
* where some compilers warn that packing is not necessary */
/** Packed structs support.
* Wraps members that are packed structs themselves, where some compilers warn that packing is not necessary.\n
* For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n
* A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here.
*/
#ifndef PACK_STRUCT_FLD_S
#define PACK_STRUCT_FLD_S(x) PACK_STRUCT_FIELD(x)
#endif /* PACK_STRUCT_FLD_S */
/** Packed structs support using \#include files before and after struct to be packed.\n
* The file included BEFORE the struct is "arch/bpstruct.h".\n
* The file included AFTER the struct is "arch/epstruct.h".\n
* This can be used to implement struct packing on MS Visual C compilers, see
* the Win32 port in the lwIP contrib repository for reference.
* For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n
* A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here.
*/
#ifdef __DOXYGEN__
#define PACK_STRUCT_USE_INCLUDES
#endif
/** Eliminates compiler warning about unused arguments (GCC -Wextra -Wunused). */
#ifndef LWIP_UNUSED_ARG
#define LWIP_UNUSED_ARG(x) (void)x
#endif /* LWIP_UNUSED_ARG */
#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 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 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 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 ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#ifndef errno
extern int errno;
#endif
#endif /* LWIP_PROVIDE_ERRNO */
/**
* @}
*/
#ifdef __cplusplus
}

View File

@ -36,9 +36,6 @@
* This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
* with RFC 3927.
*
*
* Please coordinate changes and requests with Dominik Spies
* <kontakt@dspies.de>
*/
#ifndef LWIP_HDR_AUTOIP_H
@ -78,7 +75,6 @@ struct autoip
};
#define autoip_init() /* Compatibility define, no init needed. */
void autoip_set_struct(struct netif *netif, struct autoip *autoip);
/** Remove a struct autoip previously set to the netif using autoip_set_struct() */
#define autoip_remove_struct(netif) do { (netif)->autoip = NULL; } while (0)
@ -89,6 +85,11 @@ void autoip_tmr(void);
void autoip_network_changed(struct netif *netif);
u8_t autoip_supplied_address(const struct netif *netif);
/* for lwIP internal use by ip4.c */
u8_t autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr);
#define netif_autoip_data(netif) ((struct autoip*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP))
#ifdef __cplusplus
}
#endif

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