Upgraded lwIP to 2.0.2-STABLE

This commit is contained in:
Joseph Henry
2017-09-14 13:20:49 -07:00
parent cc468fe8fe
commit 709fc40483
309 changed files with 120411 additions and 96057 deletions

150
ext/lwip/CHANGELOG Normal file → Executable file
View File

@@ -4,6 +4,152 @@ HISTORY
* [Enter new changes just after this line - do not remove this line] * [Enter new changes just after this line - do not remove this line]
(STABLE-2.0.2)
++ New features:
2017-02-10: Dirk Ziegelmeier
* Implement task #14367: Hooks need a better place to be defined:
We now have a #define for a header file name that is #included in every .c
file that provides hooks.
++ Bugfixes:
2017-03-08
* tcp: do not keep sending SYNs when getting ACKs
2017-03-08: Joel Cunningham
* tcp: Initialize ssthresh to TCP_SND_BUF (bug #50476)
2017-03-01: Simon Goldschmidt
* httpd: LWIP_HTTPD_POST_MANUAL_WND: fixed double-free when httpd_post_data_recved
is called nested from httpd_post_receive_data() (bug #50424)
2017-02-28: David van Moolenbroek/Simon Goldschmidt
* tcp: fixed bug #50418: LWIP_EVENT_API: fix invalid calbacks for SYN_RCVD pcb
2017-02-17: Simon Goldschmidt
* dns: Improved DNS_LOCAL_HOSTLIST interface (bug #50325)
2017-02-16: Simon Goldschmidt
* LWIP_NETCONN_FULLDUPLEX: fixed shutdown during write (bug #50274)
2017-02-13: Simon Goldschmidt/Dirk Ziegelmeier
* For tiny targtes, LWIP_RAND is optional (fix compile time checks)
2017-02-10: Simon Goldschmidt
* tcp: Fixed bug #47485 (tcp_close() should not fail on memory error) by retrying
to send FIN from tcp_fasttmr
2017-02-09: Simon Goldschmidt
* sockets: Fixed bug #44032 (LWIP_NETCONN_FULLDUPLEX: select might work on
invalid/reused socket) by not allowing to reallocate a socket that has
"select_waiting != 0"
2017-02-09: Simon Goldschmidt
* httpd: Fixed bug #50059 (httpd LWIP_HTTPD_SUPPORT_11_KEEPALIVE vs.
LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED)
2017-02-08: Dirk Ziegelmeier
* Rename "IPv6 mapped IPv4 addresses" to their correct name from RFC4191:
"IPv4-mapped IPv6 address"
2017-02-08: Luc Revardel
* mld6.c: Fix bug #50220 (mld6_leavegroup does not send ICMP6_TYPE_MLD, even
if last reporter)
2017-02-08: David van Moolenbroek
* ip6.c: Patch #9250: fix source substitution in ip6_output_if()
2017-02-08: Simon Goldschmidt
* tcp_out.c: Fixed bug #50090 (last_unsent->oversize_left can become wrong value
in tcp_write error path)
2017-02-02: Dirk Ziegelmeier
* Fix bug #50206: UDP Netconn bind to IP6_ADDR_ANY fails
2017-01-18: Dirk Ziegelmeier
* Fix zero-copy RX, see bug bug #50064. PBUF_REFs were not supported as ARP requests.
2017-01-15: Axel Lin, Dirk Ziegelmeier
* minor bug fixes in mqtt
2017-01-11: Knut Andre Tidemann
* sockets/netconn: fix broken default ICMPv6 handling of checksums
(STABLE-2.0.1)
++ 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: ++ New features:
2016-07-27: Simon Goldschmidt 2016-07-27: Simon Goldschmidt
@@ -328,6 +474,10 @@ HISTORY
++ Bugfixes: ++ Bugfixes:
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 2016-07-20: Simon Goldschmidt
* memp.h/.c: fixed bug #48442 (memp stats don't work for MEMP_MEM_MALLOC) * memp.h/.c: fixed bug #48442 (memp stats don't work for MEMP_MEM_MALLOC)

0
ext/lwip/COPYING Normal file → Executable file
View File

1
ext/lwip/FILES Normal file → Executable file
View File

@@ -1,4 +1,5 @@
src/ - The source code for the lwIP TCP/IP stack. src/ - The source code for the lwIP TCP/IP stack.
doc/ - The documentation for lwIP. 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. See also the FILES file in each subdirectory.

5
ext/lwip/README Normal file → Executable file
View File

@@ -35,6 +35,9 @@ APPLICATIONS
* HTTP server with SSI and CGI * HTTP server with SSI and CGI
* SNMPv2c agent with MIB compiler (Simple Network Management Protocol) * SNMPv2c agent with MIB compiler (Simple Network Management Protocol)
* SNTP (Simple network time protocol) * SNTP (Simple network time protocol)
* NetBIOS name service responder
* MDNS (Multicast DNS) responder
* iPerf server implementation
LICENSE 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: Git sources and is available from this web page:
http://www.nongnu.org/lwip/ 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 http://lwip.wikia.com/wiki/LwIP_Wiki
Also, there are mailing lists you can subscribe at Also, there are mailing lists you can subscribe at

24
ext/lwip/UPGRADING Normal file → Executable file
View File

@@ -8,7 +8,14 @@ with newer versions.
* [Enter new changes just after this line - do not remove this line] * [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) (2.0.0)
@@ -20,7 +27,7 @@ with newer versions.
* Added IPv6 support (dual-stack or IPv4/IPv6 only) * 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). * 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); * 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) * Moved some core applications from contrib repository to src/apps (and include/lwip/apps)
+++ Raw API: +++ Raw API:
@@ -35,6 +42,7 @@ with newer versions.
+++ new files: +++ 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" * 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 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 * 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 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) 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: +++ new options:
* TODO * 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 * added hook LWIP_HOOK_MEMP_AVAILABLE() to get informed when a memp pool was empty and an item
is now available 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) * LWIP_DECLARE_MEMORY_ALIGNED() may be used to declare aligned memory buffers (mem/memp)
or to move buffers to dedicated memory using compiler attributes 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) * Added IPv6 support (dual-stack or IPv4/IPv6 only)
* Major rewrite of PPP (incl. keep-up with apache pppd) * 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) * Major rewrite of SNMP (incl. MIB parser)
* Fixed timing issues that might have lead to losing a DHCP lease * Fixed timing issues that might have lead to losing a DHCP lease
* Made rx processing path more robust against crafted errors * Made rx processing path more robust against crafted errors
@@ -77,7 +95,7 @@ with newer versions.
* support PBUF_REF for RX packets * support PBUF_REF for RX packets
* LWIP_NETCONN_FULLDUPLEX allows netconn/sockets to be used for reading/writing from separate * LWIP_NETCONN_FULLDUPLEX allows netconn/sockets to be used for reading/writing from separate
threads each (needs LWIP_NETCONN_SEM_PER_THREAD) 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) (1.4.0)

5
ext/lwip/doc/FILES Normal file → Executable file
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. savannah.txt - How to obtain the current development source code.
contrib.txt - How to contribute to lwIP as a developer. contrib.txt - How to contribute to lwIP as a developer.
rawapi.txt - The documentation for the core API of lwIP. rawapi.txt - The documentation for the core API of lwIP.
Also provides an overview about the other APIs and multithreading. 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. sys_arch.txt - The documentation for a system abstraction layer of lwIP.
ppp.txt - Documentation of the PPP interface for lwIP.

117
ext/lwip/doc/NO_SYS_SampleCode.c Executable file
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 */
}
}

2
ext/lwip/doc/contrib.txt Normal file → Executable file
View File

@@ -39,7 +39,7 @@ features of Savannah help us not lose users' input.
bugtracker at Savannah. bugtracker at Savannah.
3. If you have a fix put the patch on Savannah. If it is a patch that affects 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 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. 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 This is a good way to see if they are used at all - the same goes for unix
netifs except tapif. netifs except tapif.

0
ext/lwip/doc/doxygen/generate.bat Normal file → Executable file
View File

View File

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

106
ext/lwip/doc/doxygen/main_page.h Normal file → Executable file
View File

@@ -1,4 +1,4 @@
/** /**
* @defgroup lwip lwIP * @defgroup lwip lwIP
* *
* @defgroup infrastructure Infrastructure * @defgroup infrastructure Infrastructure
@@ -7,8 +7,8 @@
* Non thread-safe APIs, callback style for maximum performance and minimum * Non thread-safe APIs, callback style for maximum performance and minimum
* memory footprint. * memory footprint.
* *
* @defgroup threadsafe_api Thread-safe APIs * @defgroup sequential_api Sequential-style APIs
* Thread-safe APIs, blocking functions. More overhead, but can be called * Sequential-style APIs, blocking functions. More overhead, but can be called
* from any thread except TCPIP thread. * from any thread except TCPIP thread.
* *
* @defgroup addons Addons * @defgroup addons Addons
@@ -26,7 +26,107 @@
* @verbinclude "UPGRADING" * @verbinclude "UPGRADING"
*/ */
/**
* @page changelog Changelog
* @verbinclude "CHANGELOG"
*/
/** /**
* @page contrib How to contribute to lwIP * @page contrib How to contribute to lwIP
* @verbinclude "contrib.txt" * @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>

113
ext/lwip/doc/mdns.txt Executable file
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.

162
ext/lwip/doc/mqtt_client.txt Executable file
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)

6
ext/lwip/doc/ppp.txt Normal file → Executable file
View File

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

17
ext/lwip/doc/rawapi.txt Normal file → Executable file
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. 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. 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, - void tcp_accept(struct tcp_pcb *pcb,
err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
err_t err)) err_t err))
@@ -465,9 +456,11 @@ introduction to this subject.
Other significant improvements can be made by supplying Other significant improvements can be made by supplying
assembly or inline replacements for htons() and htonl() assembly or inline replacements for htons() and htonl()
if you're using a little-endian architecture. if you're using a little-endian architecture.
#define LWIP_PLATFORM_BYTESWAP 1 #define lwip_htons(x) <your_htons>
#define LWIP_PLATFORM_HTONS(x) <your_htons> #define lwip_htonl(x) <your_htonl>
#define LWIP_PLATFORM_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 Check your network interface driver if it reads at
a higher speed than the maximum wire-speed. If the a higher speed than the maximum wire-speed. If the

0
ext/lwip/doc/savannah.txt Normal file → Executable file
View File

66
ext/lwip/doc/sys_arch.txt Normal file → Executable file
View File

@@ -1,6 +1,7 @@
sys_arch interface for lwIP 0.6++ sys_arch interface for lwIP
Author: Adam Dunkels Author: Adam Dunkels
Simon Goldschmidt
The operating system emulation layer provides a common interface The operating system emulation layer provides a common interface
between the lwIP code and the underlying operating system kernel. The 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 implementation. It is also possible to do a sys_arch implementation
that does not rely on any underlying operating system. 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 lwIP functionality, multiple threads support can be implemented in the
sys_arch, but this is not required for the basic lwIP sys_arch, but this is not required for the basic lwIP
functionality. Previous versions of lwIP required the sys_arch to functionality. Timer scheduling is implemented in lwIP, but can be implemented
implement timer scheduling as well but as of lwIP 0.5 this is by the sys_arch port (LWIP_TIMERS_CUSTOM==1).
implemented in a higher layer.
In addition to the source file providing the functionality of sys_arch, In addition to the source file providing the functionality of sys_arch,
the OS emulation layer must provide several header files defining 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. must define are listed below the sys_arch description.
Semaphores can be either counting or binary - lwIP works with both Semaphores can be either counting or binary - lwIP works with both
kinds. Mailboxes are used for message passing and can be implemented kinds. Mailboxes should be implemented as a queue which allows multiple messages
either as a queue which allows multiple messages to be posted to a to be posted (implementing as a rendez-vous point where only one message can be
mailbox, or 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
posted at a time. lwIP works with both kinds, but the former type will in a mailbox is just a pointer, nothing more.
be more efficient. A message in a mailbox is just a pointer, nothing
more.
Semaphores are represented by the type "sys_sem_t" which is typedef'd 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 in the sys_arch.h file. Mailboxes are equivalently represented by the
type "sys_mbox_t". lwIP does not place any restrictions on how type "sys_mbox_t". Mutexes are represented by the type "sys_mutex_t".
sys_sem_t or sys_mbox_t are represented internally. 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 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 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). 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! sys_sem_free() is always called before calling this function!
This may also be a define, in which case the function is not prototyped. 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) - err_t sys_mbox_new(sys_mbox_t *mbox, int size)
Creates an empty mailbox for maximum "size" elements. Elements stored 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 the "stacksize" parameter. The id of the new thread is returned. Both the id
and the priority are system dependent. 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) - sys_prot_t sys_arch_protect(void)
This optional function does a "fast" critical region protection and returns This optional function does a "fast" critical region protection and returns
@@ -209,7 +245,7 @@ For some configurations, you also need:
Note: 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_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 mem_init() tries to allcate a semaphore using mem_malloc, which of course
can't be performed when sys_arch uses mem_malloc. can't be performed when sys_arch uses mem_malloc.

6
ext/lwip/src/FILES Normal file → Executable file
View File

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

14
ext/lwip/src/Filelists.mk Normal file → Executable file
View File

@@ -158,12 +158,24 @@ LWIPERFFILES=$(LWIPDIR)/apps/lwiperf/lwiperf.c
# SNTPFILES: SNTP client # SNTPFILES: SNTP client
SNTPFILES=$(LWIPDIR)/apps/sntp/sntp.c SNTPFILES=$(LWIPDIR)/apps/sntp/sntp.c
# MDNSFILES: MDNS responder
MDNSFILES=$(LWIPDIR)/apps/mdns/mdns.c
# NETBIOSNSFILES: NetBIOS name server # NETBIOSNSFILES: NetBIOS name server
NETBIOSNSFILES=$(LWIPDIR)/apps/netbiosns/netbiosns.c 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: All LWIP APPs
LWIPAPPFILES=$(SNMPFILES) \ LWIPAPPFILES=$(SNMPFILES) \
$(HTTPDFILES) \ $(HTTPDFILES) \
$(LWIPERFFILES) \ $(LWIPERFFILES) \
$(SNTPFILES) \ $(SNTPFILES) \
$(NETBIOSNSFILES) $(MDNSFILES) \
$(NETBIOSNSFILES) \
$(TFTPFILES) \
$(MQTTFILES)

103
ext/lwip/src/api/api_lib.c Normal file → Executable file
View File

@@ -1,6 +1,24 @@
/** /**
* @file * @file
* Sequential API External module * 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> * 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 /* This is the part of the API that is linked with
the application */ 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! * Binding one netconn twice might not always be checked correctly!
* *
* @param conn the netconn to bind * @param conn the netconn to bind
* @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY * @param addr the local IP address to bind the netconn to
* to bind to all addresses) * (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) * @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 * @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;); 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 */ /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
if (addr == NULL) { 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_ALLOC(msg);
API_MSG_VAR_REF(msg).conn = conn; 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;); 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 */ /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
if (addr == NULL) { if (addr == NULL) {
addr = IP_ADDR_ANY; addr = IP4_ADDR_ANY;
} }
#endif /* LWIP_IPV4 */
API_MSG_VAR_ALLOC(msg); API_MSG_VAR_ALLOC(msg);
API_MSG_VAR_REF(msg).conn = conn; 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). * Disconnect a netconn from its current peer (only valid for UDP netconns).
* *
* @param conn the netconn to disconnect * @param conn the netconn to disconnect
* @return @todo: return value is not set here... * @return See @ref err_t
*/ */
err_t err_t
netconn_disconnect(struct netconn *conn) netconn_disconnect(struct netconn *conn)
@@ -378,7 +390,6 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn)
#if LWIP_TCP #if LWIP_TCP
void *accept_ptr; void *accept_ptr;
struct netconn *newconn; struct netconn *newconn;
err_t err;
#if TCP_LISTEN_BACKLOG #if TCP_LISTEN_BACKLOG
API_MSG_VAR_DECLARE(msg); API_MSG_VAR_DECLARE(msg);
#endif /* TCP_LISTEN_BACKLOG */ #endif /* TCP_LISTEN_BACKLOG */
@@ -387,11 +398,10 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn)
*new_conn = NULL; *new_conn = NULL;
LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
err = conn->last_err; if (ERR_IS_FATAL(conn->last_err)) {
if (ERR_IS_FATAL(err)) {
/* don't recv on fatal errors: this might block the application task /* don't recv on fatal errors: this might block the application task
waiting on acceptmbox forever! */ waiting on acceptmbox forever! */
return err; return conn->last_err;
} }
if (!sys_mbox_valid(&conn->acceptmbox)) { if (!sys_mbox_valid(&conn->acceptmbox)) {
return ERR_CLSD; return ERR_CLSD;
@@ -467,7 +477,6 @@ netconn_recv_data(struct netconn *conn, void **new_buf)
{ {
void *buf = NULL; void *buf = NULL;
u16_t len; u16_t len;
err_t err;
#if LWIP_TCP #if LWIP_TCP
API_MSG_VAR_DECLARE(msg); API_MSG_VAR_DECLARE(msg);
#if LWIP_MPU_COMPATIBLE #if LWIP_MPU_COMPATIBLE
@@ -491,13 +500,12 @@ netconn_recv_data(struct netconn *conn, void **new_buf)
#endif /* LWIP_TCP */ #endif /* LWIP_TCP */
LWIP_ERROR("netconn_recv: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;); LWIP_ERROR("netconn_recv: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
err = conn->last_err; if (ERR_IS_FATAL(conn->last_err)) {
if (ERR_IS_FATAL(err)) {
/* don't recv on fatal errors: this might block the application task /* don't recv on fatal errors: this might block the application task
waiting on recvmbox forever! */ waiting on recvmbox forever! */
/* @todo: this does not allow us to fetch data that has been put into recvmbox /* @todo: this does not allow us to fetch data that has been put into recvmbox
before the fatal error occurred - is that a problem? */ before the fatal error occurred - is that a problem? */
return err; return conn->last_err;
} }
#if LWIP_TCP #if LWIP_TCP
#if (LWIP_UDP || LWIP_RAW) #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 we are closed, we indicate that we no longer wish to use the socket */
if (buf == NULL) { if (buf == NULL) {
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); 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 */ /* RX side is closed, so deallocate the recvmbox */
netconn_close_shutdown(conn, NETCONN_SHUT_RD); netconn_close_shutdown(conn, NETCONN_SHUT_RD);
/* Don' store ERR_CLSD as conn->err since we are only half-closed */ /* Don' store ERR_CLSD as conn->err since we are only half-closed */
@@ -695,6 +707,7 @@ netconn_send(struct netconn *conn, struct netbuf *buf)
LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); 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)); LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
API_MSG_VAR_ALLOC(msg); API_MSG_VAR_ALLOC(msg);
API_MSG_VAR_REF(msg).conn = conn; API_MSG_VAR_REF(msg).conn = conn;
API_MSG_VAR_REF(msg).msg.b = buf; 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; return ERR_OK;
} }
dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); 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) { if (dontblock && !bytes_written) {
/* This implies netconn_write() cannot be used for non-blocking send, since /* This implies netconn_write() cannot be used for non-blocking send, since
it has no way to return the number of bytes written. */ 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. */ non-blocking version here. */
err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg)); err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg));
if ((err == ERR_OK) && (bytes_written != NULL)) { if ((err == ERR_OK) && (bytes_written != NULL)) {
if (dontblock if (dontblock) {
#if LWIP_SO_SNDTIMEO
|| (conn->send_timeout != 0)
#endif /* LWIP_SO_SNDTIMEO */
) {
/* nonblocking write: maybe the data has been sent partly */ /* nonblocking write: maybe the data has been sent partly */
*bytes_written = API_MSG_VAR_REF(msg).msg.w.len; *bytes_written = API_MSG_VAR_REF(msg).msg.w.len;
} else { } else {
@@ -867,13 +881,15 @@ netconn_join_leave_group(struct netconn *conn,
API_MSG_VAR_ALLOC(msg); API_MSG_VAR_ALLOC(msg);
#if LWIP_IPV4
/* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
if (multiaddr == NULL) { if (multiaddr == NULL) {
multiaddr = IP_ADDR_ANY; multiaddr = IP4_ADDR_ANY;
} }
if (netif_addr == NULL) { 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).conn = conn;
API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr); 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; sys_sem_t sem;
#endif /* LWIP_MPU_COMPATIBLE */ #endif /* LWIP_MPU_COMPATIBLE */
err_t err; err_t err;
err_t cberr;
LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != 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 */ #endif /* LWIP_NETCONN_SEM_PER_THREAD */
err = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg)); cberr = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg));
if (err != ERR_OK) { if (cberr != ERR_OK) {
#if !LWIP_NETCONN_SEM_PER_THREAD #if !LWIP_NETCONN_SEM_PER_THREAD
sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
#endif /* !LWIP_NETCONN_SEM_PER_THREAD */ #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
API_VAR_FREE(MEMP_DNS_API_MSG, msg); API_VAR_FREE(MEMP_DNS_API_MSG, msg);
return err; return cberr;
} }
sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem)); sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem));
#if !LWIP_NETCONN_SEM_PER_THREAD #if !LWIP_NETCONN_SEM_PER_THREAD

107
ext/lwip/src/api/api_msg.c Normal file → Executable file
View File

@@ -43,6 +43,7 @@
#include "lwip/priv/api_msg.h" #include "lwip/priv/api_msg.h"
#include "lwip/ip.h" #include "lwip/ip.h"
#include "lwip/ip_addr.h"
#include "lwip/udp.h" #include "lwip/udp.h"
#include "lwip/tcp.h" #include "lwip/tcp.h"
#include "lwip/raw.h" #include "lwip/raw.h"
@@ -540,26 +541,41 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
* Called from lwip_netconn_do_newconn(). * Called from lwip_netconn_do_newconn().
* *
* @param msg the api_msg_msg describing the connection type * @param msg the api_msg_msg describing the connection type
* @return msg->conn->err, but the return value is currently ignored
*/ */
static void static void
pcb_new(struct api_msg *msg) pcb_new(struct api_msg *msg)
{ {
enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4;
LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); 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 */ /* Allocate a PCB for this connection */
switch(NETCONNTYPE_GROUP(msg->conn->type)) { switch(NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW #if LWIP_RAW
case NETCONN_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) { if (msg->conn->pcb.raw != NULL) {
#if LWIP_IPV6
/* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */
if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) {
msg->conn->pcb.raw->chksum_reqd = 1;
msg->conn->pcb.raw->chksum_offset = 2;
}
#endif /* LWIP_IPV6 */
raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
} }
break; break;
#endif /* LWIP_RAW */ #endif /* LWIP_RAW */
#if LWIP_UDP #if LWIP_UDP
case NETCONN_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 (msg->conn->pcb.udp != NULL) {
#if LWIP_UDPLITE #if LWIP_UDPLITE
if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) { if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
@@ -575,7 +591,7 @@ pcb_new(struct api_msg *msg)
#endif /* LWIP_UDP */ #endif /* LWIP_UDP */
#if LWIP_TCP #if LWIP_TCP
case NETCONN_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) { if (msg->conn->pcb.tcp != NULL) {
setup_tcp(msg->conn); setup_tcp(msg->conn);
} }
@@ -589,15 +605,6 @@ pcb_new(struct api_msg *msg)
if (msg->conn->pcb.ip == NULL) { if (msg->conn->pcb.ip == NULL) {
msg->err = ERR_MEM; 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,6 +788,7 @@ netconn_drain(struct netconn *conn)
#if LWIP_TCP #if LWIP_TCP
if (sys_mbox_valid(&conn->acceptmbox)) { if (sys_mbox_valid(&conn->acceptmbox)) {
while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
if (mem != &netconn_aborted) {
struct netconn *newconn = (struct netconn *)mem; struct netconn *newconn = (struct netconn *)mem;
/* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
/* pcb might be set to NULL already by err_tcp() */ /* pcb might be set to NULL already by err_tcp() */
@@ -792,6 +800,7 @@ netconn_drain(struct netconn *conn)
} }
netconn_free(newconn); netconn_free(newconn);
} }
}
sys_mbox_free(&conn->acceptmbox); sys_mbox_free(&conn->acceptmbox);
sys_mbox_set_invalid(&conn->acceptmbox); sys_mbox_set_invalid(&conn->acceptmbox);
} }
@@ -805,7 +814,6 @@ netconn_drain(struct netconn *conn)
* places. * places.
* *
* @param conn the TCP netconn to close * @param conn the TCP netconn to close
* [@param delay 1 if called from sent/poll (wake up calling thread on end)]
*/ */
static err_t static err_t
lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM) lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM)
@@ -1113,37 +1121,20 @@ lwip_netconn_do_bind(void *m)
} else { } else {
msg->err = ERR_VAL; msg->err = ERR_VAL;
if (msg->conn->pcb.tcp != NULL) { 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)) { switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW #if LWIP_RAW
case NETCONN_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; break;
#endif /* LWIP_RAW */ #endif /* LWIP_RAW */
#if LWIP_UDP #if LWIP_UDP
case NETCONN_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; break;
#endif /* LWIP_UDP */ #endif /* LWIP_UDP */
#if LWIP_TCP #if LWIP_TCP
case NETCONN_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; break;
#endif /* LWIP_TCP */ #endif /* LWIP_TCP */
default: default:
@@ -1323,6 +1314,13 @@ lwip_netconn_do_listen(void *m)
/* connection is not closed, cannot listen */ /* connection is not closed, cannot listen */
msg->err = ERR_VAL; msg->err = ERR_VAL;
} else { } 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 #if LWIP_IPV4 && LWIP_IPV6
/* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY, /* "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 * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
@@ -1335,15 +1333,11 @@ lwip_netconn_do_listen(void *m)
} }
#endif /* LWIP_IPV4 && LWIP_IPV6 */ #endif /* LWIP_IPV4 && LWIP_IPV6 */
#if TCP_LISTEN_BACKLOG lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
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 */
if (lpcb == NULL) { if (lpcb == NULL) {
/* in this case, the old pcb is still allocated */ /* in this case, the old pcb is still allocated */
msg->err = ERR_MEM; msg->err = err;
} else { } else {
/* delete the recvmbox and allocate the acceptmbox */ /* delete the recvmbox and allocate the acceptmbox */
if (sys_mbox_valid(&msg->conn->recvmbox)) { if (sys_mbox_valid(&msg->conn->recvmbox)) {
@@ -1400,7 +1394,7 @@ lwip_netconn_do_send(void *m)
switch (NETCONNTYPE_GROUP(msg->conn->type)) { switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW #if LWIP_RAW
case NETCONN_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); msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
} else { } else {
msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
@@ -1490,7 +1484,6 @@ lwip_netconn_do_accepted(void *m)
* blocking application thread (waiting in netconn_write) is released. * blocking application thread (waiting in netconn_write) is released.
* *
* @param conn netconn (that is currently in state NETCONN_WRITE) to process * @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 * @return ERR_OK
* ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
*/ */
@@ -1512,9 +1505,8 @@ lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM)
LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len", LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
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; apiflags = conn->current_msg->msg.w.apiflags;
dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
#if LWIP_SO_SNDTIMEO #if LWIP_SO_SNDTIMEO
if ((conn->send_timeout != 0) && if ((conn->send_timeout != 0) &&
@@ -1590,10 +1582,11 @@ err_mem:
write_finished = 1; write_finished = 1;
conn->current_msg->msg.w.len = 0; conn->current_msg->msg.w.len = 0;
} }
} else if ((err == ERR_MEM) && !dontblock) { } else if (err == ERR_MEM) {
/* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called /* 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 For blocking sockets, we do NOT return to the application
only a temporary error! */ 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 */ /* tcp_write returned ERR_MEM, try tcp_output anyway */
err_t out_err = tcp_output(conn->pcb.tcp); err_t out_err = tcp_output(conn->pcb.tcp);
@@ -1604,7 +1597,11 @@ err_mem:
err = out_err; err = out_err;
write_finished = 1; write_finished = 1;
conn->current_msg->msg.w.len = 0; 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 { } else {
/* On errors != ERR_MEM, we don't try writing any more but return /* On errors != ERR_MEM, we don't try writing any more but return
@@ -1713,6 +1710,7 @@ lwip_netconn_do_getaddr(void *m)
ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
msg->conn->pcb.ip->remote_ip); msg->conn->pcb.ip->remote_ip);
} }
msg->err = ERR_OK; msg->err = ERR_OK;
switch (NETCONNTYPE_GROUP(msg->conn->type)) { switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW #if LWIP_RAW
@@ -1786,25 +1784,28 @@ lwip_netconn_do_close(void *m)
#if LWIP_NETCONN_FULLDUPLEX #if LWIP_NETCONN_FULLDUPLEX
if (msg->msg.sd.shut & NETCONN_SHUT_WR) { if (msg->msg.sd.shut & NETCONN_SHUT_WR) {
/* close requested, abort running write */ /* close requested, abort running write */
sys_sem_t* op_completed_sem; sys_sem_t* write_completed_sem;
LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL); LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg); write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
msg->conn->current_msg->err = ERR_CLSD; msg->conn->current_msg->err = ERR_CLSD;
msg->conn->current_msg = NULL; msg->conn->current_msg = NULL;
msg->conn->write_offset = 0; msg->conn->write_offset = 0;
msg->conn->state = NETCONN_NONE; msg->conn->state = NETCONN_NONE;
state = NETCONN_NONE;
NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD); NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD);
sys_sem_signal(op_completed_sem); sys_sem_signal(write_completed_sem);
} else { } else {
LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD); LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD);
/* In this case, let the write continue and do not interfere with /* In this case, let the write continue and do not interfere with
conn->current_msg or conn->state! */ conn->current_msg or conn->state! */
msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0); msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0);
} }
}
if (state == NETCONN_NONE) {
#else /* LWIP_NETCONN_FULLDUPLEX */ #else /* LWIP_NETCONN_FULLDUPLEX */
msg->err = ERR_INPROGRESS; msg->err = ERR_INPROGRESS;
#endif /* LWIP_NETCONN_FULLDUPLEX */
} else { } else {
#endif /* LWIP_NETCONN_FULLDUPLEX */
if (msg->msg.sd.shut & NETCONN_SHUT_RD) { if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
/* Drain and delete mboxes */ /* Drain and delete mboxes */
netconn_drain(msg->conn); netconn_drain(msg->conn);

40
ext/lwip/src/api/err.c Normal file → Executable file
View File

@@ -37,6 +37,43 @@
*/ */
#include "lwip/err.h" #include "lwip/err.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include <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 #ifdef LWIP_DEBUG
@@ -69,6 +106,9 @@ static const char *err_strerr[] = {
const char * const char *
lwip_strerr(err_t err) lwip_strerr(err_t err)
{ {
if ((err > 0) || (-err >= (err_t)LWIP_ARRAYSIZE(err_strerr))) {
return "Unknown error.";
}
return err_strerr[-err]; return err_strerr[-err];
} }

39
ext/lwip/src/api/netbuf.c Normal file → Executable file
View File

@@ -2,6 +2,12 @@
* @file * @file
* Network buffer management * 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" #include "lwip/opt.h"
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.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); buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
if (buf != NULL) { if (buf != NULL) {
buf->p = NULL; memset(buf, 0, sizeof(struct netbuf));
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;
} }
return buf;
} }
/** /**
@@ -188,7 +171,7 @@ netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
void void
netbuf_chain(struct netbuf *head, struct netbuf *tail) 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;); LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);
pbuf_cat(head->p, tail->p); pbuf_cat(head->p, tail->p);
head->ptr = head->p; head->ptr = head->p;
@@ -234,7 +217,7 @@ netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
s8_t s8_t
netbuf_next(struct netbuf *buf) 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) { if (buf->ptr->next == NULL) {
return -1; return -1;
} }
@@ -256,7 +239,7 @@ netbuf_next(struct netbuf *buf)
void void
netbuf_first(struct netbuf *buf) 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; buf->ptr = buf->p;
} }

18
ext/lwip/src/api/netdb.c Normal file → Executable file
View File

@@ -2,6 +2,8 @@
* @file * @file
* API functions for name resolving * 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" #include "lwip/netdb.h"
#if LWIP_DNS && LWIP_SOCKET #if LWIP_DNS && LWIP_SOCKET
@@ -50,8 +46,8 @@
#include "lwip/api.h" #include "lwip/api.h"
#include "lwip/dns.h" #include "lwip/dns.h"
#include <string.h> #include <string.h> /* memset */
#include <stdlib.h> #include <stdlib.h> /* atoi */
/** helper struct for gethostbyname_r to access the char* buffer */ /** helper struct for gethostbyname_r to access the char* buffer */
struct gethostbyname_r_helper { 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)); inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr));
sa6->sin6_family = AF_INET6; sa6->sin6_family = AF_INET6;
sa6->sin6_len = sizeof(struct sockaddr_in6); 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; ai->ai_family = AF_INET6;
#endif /* LWIP_IPV6 */ #endif /* LWIP_IPV6 */
} else { } else {
#if LWIP_IPV4 #if LWIP_IPV4
struct sockaddr_in *sa4 = (struct sockaddr_in*)sa; struct sockaddr_in *sa4 = (struct sockaddr_in*)sa;
/* set up sockaddr */ /* 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_family = AF_INET;
sa4->sin_len = sizeof(struct sockaddr_in); 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; ai->ai_family = AF_INET;
#endif /* LWIP_IPV4 */ #endif /* LWIP_IPV4 */
} }

29
ext/lwip/src/api/netifapi.c Normal file → Executable file
View File

@@ -2,6 +2,13 @@
* @file * @file
* Network Interface Sequential API module * 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" #include "lwip/opt.h"
#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.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 LWIP_IPV4
if (ipaddr == NULL) { if (ipaddr == NULL) {
ipaddr = IP4_ADDR_ANY; ipaddr = IP4_ADDR_ANY4;
} }
if (netmask == NULL) { if (netmask == NULL) {
netmask = IP4_ADDR_ANY; netmask = IP4_ADDR_ANY4;
} }
if (gw == NULL) { if (gw == NULL) {
gw = IP4_ADDR_ANY; gw = IP4_ADDR_ANY4;
} }
#endif /* LWIP_IPV4 */ #endif /* LWIP_IPV4 */
@@ -180,13 +177,13 @@ netifapi_netif_set_addr(struct netif *netif,
NETIFAPI_VAR_ALLOC(msg); NETIFAPI_VAR_ALLOC(msg);
if (ipaddr == NULL) { if (ipaddr == NULL) {
ipaddr = IP4_ADDR_ANY; ipaddr = IP4_ADDR_ANY4;
} }
if (netmask == NULL) { if (netmask == NULL) {
netmask = IP4_ADDR_ANY; netmask = IP4_ADDR_ANY4;
} }
if (gw == NULL) { if (gw == NULL) {
gw = IP4_ADDR_ANY; gw = IP4_ADDR_ANY4;
} }
NETIFAPI_VAR_REF(msg).netif = netif; NETIFAPI_VAR_REF(msg).netif = netif;

234
ext/lwip/src/api/sockets.c Normal file → Executable file
View File

@@ -2,6 +2,12 @@
* @file * @file
* Sockets BSD-Like API module * 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" #include "lwip/opt.h"
#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.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 { \ #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \
(sin)->sin_len = sizeof(struct sockaddr_in); \ (sin)->sin_len = sizeof(struct sockaddr_in); \
(sin)->sin_family = AF_INET; \ (sin)->sin_family = AF_INET; \
(sin)->sin_port = htons((port)); \ (sin)->sin_port = lwip_htons((port)); \
inet_addr_from_ipaddr(&(sin)->sin_addr, ipaddr); \ inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \
memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0)
#define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \ #define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \
inet_addr_to_ipaddr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \ inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \
(port) = ntohs((sin)->sin_port); }while(0) (port) = lwip_ntohs((sin)->sin_port); }while(0)
#endif /* LWIP_IPV4 */ #endif /* LWIP_IPV4 */
#if LWIP_IPV6 #if LWIP_IPV6
#define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \ #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \
(sin6)->sin6_len = sizeof(struct sockaddr_in6); \ (sin6)->sin6_len = sizeof(struct sockaddr_in6); \
(sin6)->sin6_family = AF_INET6; \ (sin6)->sin6_family = AF_INET6; \
(sin6)->sin6_port = htons((port)); \ (sin6)->sin6_port = lwip_htons((port)); \
(sin6)->sin6_flowinfo = 0; \ (sin6)->sin6_flowinfo = 0; \
inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \ inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \
(sin6)->sin6_scope_id = 0; }while(0) (sin6)->sin6_scope_id = 0; }while(0)
#define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \ #define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \
inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \ 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 */ #endif /* LWIP_IPV6 */
#if LWIP_IPV4 && 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 /* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when
a socket is closed */ a socket is closed */
struct lwip_socket_multicast_pair { struct lwip_socket_multicast_pair {
/** the socket (+1 to not require initialization) */ /** the socket */
int sa; struct lwip_sock* sock;
/** the interface address */ /** the interface address */
ip4_addr_t if_addr; ip4_addr_t if_addr;
/** the group address */ /** 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. */ and checked in event_callback to see if it has changed. */
static volatile int select_cb_ctr; 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 #if LWIP_SOCKET_SET_ERRNO
#ifndef set_errno #ifndef set_errno
#define set_errno(err) do { if (err) { errno = (err); } } while(0) #define set_errno(err) do { if (err) { errno = (err); } } while(0)
@@ -438,7 +407,7 @@ alloc_socket(struct netconn *newconn, int accepted)
for (i = 0; i < NUM_SOCKETS; ++i) { for (i = 0; i < NUM_SOCKETS; ++i) {
/* Protect socket array */ /* Protect socket array */
SYS_ARCH_PROTECT(lev); SYS_ARCH_PROTECT(lev);
if (!sockets[i].conn) { if (!sockets[i].conn && (sockets[i].select_waiting == 0)) {
sockets[i].conn = newconn; sockets[i].conn = newconn;
/* The socket is not yet known to anyone, so no need to protect /* The socket is not yet known to anyone, so no need to protect
after having marked it as used. */ after having marked it as used. */
@@ -451,7 +420,6 @@ alloc_socket(struct netconn *newconn, int accepted)
sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1);
sockets[i].errevent = 0; sockets[i].errevent = 0;
sockets[i].err = 0; sockets[i].err = 0;
sockets[i].select_waiting = 0;
return i + LWIP_SOCKET_OFFSET; return i + LWIP_SOCKET_OFFSET;
} }
SYS_ARCH_UNPROTECT(lev); SYS_ARCH_UNPROTECT(lev);
@@ -513,7 +481,7 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) { if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s)); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
sock_set_errno(sock, EWOULDBLOCK); set_errno(EWOULDBLOCK);
return -1; return -1;
} }
@@ -615,6 +583,14 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr); ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port));
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) {
unmap_ipv4_mapped_ipv6(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); err = netconn_bind(sock->conn, &local_addr, local_port);
if (err != ERR_OK) { if (err != ERR_OK) {
@@ -699,6 +675,14 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr); ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port)); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port));
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr))) {
unmap_ipv4_mapped_ipv6(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); err = netconn_connect(sock->conn, &remote_addr, remote_port);
} }
@@ -786,7 +770,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
return off; return off;
} }
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
sock_set_errno(sock, EWOULDBLOCK); set_errno(EWOULDBLOCK);
return -1; return -1;
} }
@@ -878,6 +862,15 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
port = netbuf_fromport((struct netbuf *)buf); port = netbuf_fromport((struct netbuf *)buf);
fromaddr = netbuf_fromaddr((struct netbuf *)buf); fromaddr = netbuf_fromaddr((struct netbuf *)buf);
} }
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) && IP_IS_V4(fromaddr)) {
ip4_2_ipv4_mapped_ipv6(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); IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port);
ip_addr_debug_print(SOCKETS_DEBUG, fromaddr); ip_addr_debug_print(SOCKETS_DEBUG, fromaddr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
@@ -972,8 +965,6 @@ int
lwip_sendmsg(int s, const struct msghdr *msg, int flags) lwip_sendmsg(int s, const struct msghdr *msg, int flags)
{ {
struct lwip_sock *sock; struct lwip_sock *sock;
struct netbuf *chain_buf;
u16_t remote_port;
int i; int i;
#if LWIP_TCP #if LWIP_TCP
u8_t write_flags; u8_t write_flags;
@@ -1003,6 +994,10 @@ lwip_sendmsg(int s, const struct msghdr *msg, int flags)
((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
for (i = 0; i < msg->msg_iovlen; i++) { for (i = 0; i < msg->msg_iovlen; i++) {
u8_t apiflags = write_flags;
if (i + 1 < msg->msg_iovlen) {
apiflags |= NETCONN_MORE;
}
written = 0; written = 0;
err = netconn_write_partly(sock->conn, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len, write_flags, &written); err = netconn_write_partly(sock->conn, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len, write_flags, &written);
if (err == ERR_OK) { if (err == ERR_OK) {
@@ -1030,6 +1025,8 @@ lwip_sendmsg(int s, const struct msghdr *msg, int flags)
} }
/* else, UDP and RAW NETCONNs */ /* else, UDP and RAW NETCONNs */
#if LWIP_UDP || LWIP_RAW #if LWIP_UDP || LWIP_RAW
{
struct netbuf *chain_buf;
LWIP_UNUSED_ARG(flags); LWIP_UNUSED_ARG(flags);
LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) || LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) ||
@@ -1043,6 +1040,7 @@ lwip_sendmsg(int s, const struct msghdr *msg, int flags)
return -1; return -1;
} }
if (msg->msg_name) { if (msg->msg_name) {
u16_t remote_port;
SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf->addr, remote_port); SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf->addr, remote_port);
netbuf_fromport(chain_buf) = remote_port; netbuf_fromport(chain_buf) = remote_port;
} }
@@ -1053,8 +1051,7 @@ lwip_sendmsg(int s, const struct msghdr *msg, int flags)
/* Allocate a new netbuf and copy the data into it. */ /* Allocate a new netbuf and copy the data into it. */
if (netbuf_alloc(chain_buf, (u16_t)size) == NULL) { if (netbuf_alloc(chain_buf, (u16_t)size) == NULL) {
err = ERR_MEM; err = ERR_MEM;
} } else {
else {
/* flatten the IO vectors */ /* flatten the IO vectors */
size_t offset = 0; size_t offset = 0;
for (i = 0; i < msg->msg_iovlen; i++) { for (i = 0; i < msg->msg_iovlen; i++) {
@@ -1097,6 +1094,14 @@ lwip_sendmsg(int s, const struct msghdr *msg, int flags)
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
if (err == ERR_OK) { if (err == ERR_OK) {
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
if (IP_IS_V6_VAL(chain_buf->addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&chain_buf->addr))) {
unmap_ipv4_mapped_ipv6(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 */ /* send the data */
err = netconn_send(sock->conn, chain_buf); err = netconn_send(sock->conn, chain_buf);
} }
@@ -1106,6 +1111,7 @@ lwip_sendmsg(int s, const struct msghdr *msg, int flags)
sock_set_errno(sock, err_to_errno(err)); sock_set_errno(sock, err_to_errno(err));
return (err == ERR_OK ? size : -1); return (err == ERR_OK ? size : -1);
}
#else /* LWIP_UDP || LWIP_RAW */ #else /* LWIP_UDP || LWIP_RAW */
sock_set_errno(sock, err_to_errno(ERR_ARG)); sock_set_errno(sock, err_to_errno(ERR_ARG));
return -1; return -1;
@@ -1137,12 +1143,6 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
#endif /* LWIP_TCP */ #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? */ /* @todo: split into multiple sendto's? */
LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
short_size = (u16_t)size; short_size = (u16_t)size;
@@ -1192,6 +1192,14 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
err = netbuf_ref(&buf, data, short_size); err = netbuf_ref(&buf, data, short_size);
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
if (err == ERR_OK) { if (err == ERR_OK) {
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) {
unmap_ipv4_mapped_ipv6(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 */ /* send the data */
err = netconn_send(sock->conn, &buf); err = netconn_send(sock->conn, &buf);
} }
@@ -1209,9 +1217,7 @@ lwip_socket(int domain, int type, int protocol)
struct netconn *conn; struct netconn *conn;
int i; int i;
#if !LWIP_IPV6
LWIP_UNUSED_ARG(domain); /* @todo: check this */ LWIP_UNUSED_ARG(domain); /* @todo: check this */
#endif /* LWIP_IPV6 */
/* create a netconn */ /* create a netconn */
switch (type) { switch (type) {
@@ -1274,7 +1280,7 @@ lwip_writev(int s, const struct iovec *iov, int iovcnt)
msg.msg_namelen = 0; msg.msg_namelen = 0;
/* Hack: we have to cast via number to cast from 'const' pointer to non-const. /* Hack: we have to cast via number to cast from 'const' pointer to non-const.
Blame the opengroup standard for this inconsistency. */ 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_iovlen = iovcnt;
msg.msg_control = NULL; msg.msg_control = NULL;
msg.msg_controllen = 0; msg.msg_controllen = 0;
@@ -1288,12 +1294,12 @@ lwip_writev(int s, const struct iovec *iov, int iovcnt)
* the sockets enabled that had events. * the sockets enabled that had events.
* *
* @param maxfdp1 the highest socket index in the sets * @param maxfdp1 the highest socket index in the sets
* @param readset_in: set of sockets to check for read events * @param readset_in set of sockets to check for read events
* @param writeset_in: set of sockets to check for write events * @param writeset_in set of sockets to check for write events
* @param exceptset_in: set of sockets to check for error events * @param exceptset_in set of sockets to check for error events
* @param readset_out: set of sockets that had read events * @param readset_out set of sockets that had read events
* @param writeset_out: set of sockets that had write events * @param writeset_out set of sockets that had write events
* @param exceptset_out: set os sockets that had error events * @param exceptset_out set os sockets that had error events
* @return number of sockets that had events (read/write/exception) (>= 0) * @return number of sockets that had events (read/write/exception) (>= 0)
*/ */
static int static int
@@ -1487,9 +1493,7 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
SYS_ARCH_PROTECT(lev); SYS_ARCH_PROTECT(lev);
sock = tryget_socket(i); sock = tryget_socket(i);
if (sock != NULL) { if (sock != NULL) {
/* @todo: what if this is a new socket (reallocated?) in this case, /* for now, handle select_waiting==0... */
select_waiting-- would be wrong (a global 'sockalloc' counter,
stored per socket could help) */
LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
if (sock->select_waiting > 0) { if (sock->select_waiting > 0) {
sock->select_waiting--; sock->select_waiting--;
@@ -1681,8 +1685,7 @@ again:
} }
/** /**
* Unimplemented: Close one end of a full-duplex connection. * Close one end of a full-duplex connection.
* Currently, the full connection is closed.
*/ */
int int
lwip_shutdown(int s, int how) lwip_shutdown(int s, int how)
@@ -1740,12 +1743,21 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
} }
/* get the IP address and port */ /* get the IP address and port */
/* @todo: this does not work for IPv6, yet */
err = netconn_getaddr(sock->conn, &naddr, &port, local); err = netconn_getaddr(sock->conn, &naddr, &port, local);
if (err != ERR_OK) { if (err != ERR_OK) {
sock_set_errno(sock, err_to_errno(err)); sock_set_errno(sock, err_to_errno(err));
return -1; return -1;
} }
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) &&
IP_IS_V4_VAL(naddr)) {
ip4_2_ipv4_mapped_ipv6(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); IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); 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 */ /* write back optlen and optval */
*optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen; *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen;
#if LWIP_MPU_COMPATIBLE #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); LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen);
#endif /* LWIP_MPU_COMPATIBLE */ #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) { if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
return ENOPROTOOPT; 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", LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
s, *(int *)optval)); s, *(int *)optval));
break; 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) { if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
return ENOPROTOOPT; 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", LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
s, *(u32_t *)optval)); s, *(u32_t *)optval));
break; break;
@@ -2059,6 +2071,9 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt
case IPPROTO_TCP: case IPPROTO_TCP:
/* Special case: all IPPROTO_TCP option take an int */ /* Special case: all IPPROTO_TCP option take an int */
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP); LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP);
if (sock->conn->pcb.tcp->state == LISTEN) {
return EINVAL;
}
switch (optname) { switch (optname) {
case TCP_NODELAY: case TCP_NODELAY:
*(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp); *(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) { switch (optname) {
case IPV6_V6ONLY: case IPV6_V6ONLY:
LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); 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); *(int*)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n", LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n",
s, *(int *)optval)); 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).optname = optname;
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen;
#if LWIP_MPU_COMPATIBLE #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 */ #else /* LWIP_MPU_COMPATIBLE */
LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void*)optval; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void*)optval;
#endif /* LWIP_MPU_COMPATIBLE */ #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 #if LWIP_MULTICAST_TX_OPTIONS
case IP_MULTICAST_TTL: case IP_MULTICAST_TTL:
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); 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; break;
case IP_MULTICAST_IF: case IP_MULTICAST_IF:
{ {
ip4_addr_t if_addr; ip4_addr_t if_addr;
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP); 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); udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr);
} }
break; 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 if_addr;
ip4_addr_t multi_addr; ip4_addr_t multi_addr;
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP); 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_ip4addr(&if_addr, &imr->imr_interface);
inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr); inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr);
if (optname == IP_ADD_MEMBERSHIP) { if (optname == IP_ADD_MEMBERSHIP) {
if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) { if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) {
/* cannot track membership (out of memory) */ /* 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: case IPPROTO_TCP:
/* Special case: all IPPROTO_TCP option take an int */ /* Special case: all IPPROTO_TCP option take an int */
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP); LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
if (sock->conn->pcb.tcp->state == LISTEN) {
return EINVAL;
}
switch (optname) { switch (optname) {
case TCP_NODELAY: case TCP_NODELAY:
if (*(const int*)optval) { if (*(const int*)optval) {
@@ -2499,7 +2513,6 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
case IPPROTO_IPV6: case IPPROTO_IPV6:
switch (optname) { switch (optname) {
case IPV6_V6ONLY: case IPV6_V6ONLY:
/* @todo: this does not work for datagram sockets, yet */
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP); LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
if (*(const int*)optval) { if (*(const int*)optval) {
netconn_set_ipv6only(sock->conn, 1); netconn_set_ipv6only(sock->conn, 1);
@@ -2561,6 +2574,12 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
switch (optname) { switch (optname) {
#if LWIP_IPV6 && LWIP_RAW #if LWIP_IPV6 && LWIP_RAW
case IPV6_CHECKSUM: case IPV6_CHECKSUM:
/* It should not be possible to disable the checksum generation with ICMPv6
* as per RFC 3542 chapter 3.1 */
if(sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) {
return EINVAL;
}
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW); LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW);
if (*(const int *)optval < 0) { if (*(const int *)optval < 0) {
sock->conn->pcb.raw->chksum_reqd = 0; sock->conn->pcb.raw->chksum_reqd = 0;
@@ -2732,14 +2751,16 @@ lwip_fcntl(int s, int cmd, int val)
static int static int
lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) 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 struct lwip_sock *sock = get_socket(s);
(default initialization is to 0) */
int sa = s + 1;
int i; int i;
if (!sock) {
return 0;
}
for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
if (socket_ipv4_multicast_memberships[i].sa == 0) { if (socket_ipv4_multicast_memberships[i].sock == NULL) {
socket_ipv4_multicast_memberships[i].sa = sa; 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].if_addr, *if_addr);
ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr); ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr);
return 1; return 1;
@@ -2756,16 +2777,18 @@ lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr
static void static void
lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) 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 struct lwip_sock *sock = get_socket(s);
(default initialization is to 0) */
int sa = s + 1;
int i; int i;
if (!sock) {
return;
}
for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 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].if_addr, if_addr) &&
ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_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].if_addr);
ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
return; return;
@@ -2777,25 +2800,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). * 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 struct lwip_sock *sock = get_socket(s);
(default initialization is to 0) */
int sa = s + 1;
int i; int i;
LWIP_ASSERT("socket has no netconn", sockets[s].conn != NULL); if (!sock) {
return;
}
for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 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_t multi_addr, if_addr;
ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_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); 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].if_addr);
ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_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);
} }
} }
} }

21
ext/lwip/src/api/tcpip.c Normal file → Executable file
View File

@@ -48,6 +48,7 @@
#include "lwip/ip.h" #include "lwip/ip.h"
#include "lwip/pbuf.h" #include "lwip/pbuf.h"
#include "lwip/etharp.h" #include "lwip/etharp.h"
#include "netif/ethernet.h"
#define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name) #define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name)
#define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, 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; sys_mutex_t lock_tcpip_core;
#endif /* LWIP_TCPIP_CORE_LOCKING */ #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 * The main lwIP thread. This thread has exclusive access to lwIP core functions
@@ -90,7 +98,7 @@ tcpip_thread(void *arg)
UNLOCK_TCPIP_CORE(); UNLOCK_TCPIP_CORE();
LWIP_TCPIP_THREAD_ALIVE(); LWIP_TCPIP_THREAD_ALIVE();
/* wait for a message, timeouts are processed while waiting */ /* 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(); LOCK_TCPIP_CORE();
if (msg == NULL) { if (msg == NULL) {
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n")); LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n"));
@@ -118,7 +126,7 @@ tcpip_thread(void *arg)
break; break;
#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ #endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
#if LWIP_TCPIP_TIMEOUT #if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
case TCPIP_MSG_TIMEOUT: case TCPIP_MSG_TIMEOUT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); 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); 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); sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
memp_free(MEMP_TCPIP_MSG_API, msg); memp_free(MEMP_TCPIP_MSG_API, msg);
break; break;
#endif /* LWIP_TCPIP_TIMEOUT */ #endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
case TCPIP_MSG_CALLBACK: case TCPIP_MSG_CALLBACK:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); 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; return ERR_OK;
} }
#if LWIP_TCPIP_TIMEOUT #if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
/** /**
* call sys_timeout in tcpip_thread * 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 h function to be called on timeout
* @param arg argument to pass to timeout function h * @param arg argument to pass to timeout function h
* @return ERR_MEM on memory error, ERR_OK otherwise * @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 * call sys_untimeout in tcpip_thread
* *
* @param msec time in milliseconds for timeout
* @param h function to be called on timeout * @param h function to be called on timeout
* @param arg argument to pass to timeout function h * @param arg argument to pass to timeout function h
* @return ERR_MEM on memory error, ERR_OK otherwise * @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); sys_mbox_post(&mbox, msg);
return ERR_OK; return ERR_OK;
} }
#endif /* LWIP_TCPIP_TIMEOUT */ #endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
/** /**

179
ext/lwip/src/apps/httpd/fs.c Executable file
View File

@@ -0,0 +1,179 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/apps/httpd_opts.h"
#include "lwip/def.h"
#include "lwip/apps/fs.h"
#include "fsdata.h"
#include <string.h>
#if HTTPD_USE_CUSTOM_FSDATA
#include "fsdata_custom.c"
#else /* HTTPD_USE_CUSTOM_FSDATA */
#include "fsdata.c"
#endif /* HTTPD_USE_CUSTOM_FSDATA */
/*-----------------------------------------------------------------------------------*/
#if LWIP_HTTPD_CUSTOM_FILES
int fs_open_custom(struct fs_file *file, const char *name);
void fs_close_custom(struct fs_file *file);
#if LWIP_HTTPD_FS_ASYNC_READ
u8_t fs_canread_custom(struct fs_file *file);
u8_t fs_wait_read_custom(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg);
int fs_read_async_custom(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg);
#else /* LWIP_HTTPD_FS_ASYNC_READ */
int fs_read_custom(struct fs_file *file, char *buffer, int count);
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
#endif /* LWIP_HTTPD_CUSTOM_FILES */
/*-----------------------------------------------------------------------------------*/
err_t
fs_open(struct fs_file *file, const char *name)
{
const struct fsdata_file *f;
if ((file == NULL) || (name == NULL)) {
return ERR_ARG;
}
#if LWIP_HTTPD_CUSTOM_FILES
if (fs_open_custom(file, name)) {
file->is_custom_file = 1;
return ERR_OK;
}
file->is_custom_file = 0;
#endif /* LWIP_HTTPD_CUSTOM_FILES */
for (f = FS_ROOT; f != NULL; f = f->next) {
if (!strcmp(name, (const char *)f->name)) {
file->data = (const char *)f->data;
file->len = f->len;
file->index = f->len;
file->pextension = NULL;
file->flags = f->flags;
#if HTTPD_PRECALCULATED_CHECKSUM
file->chksum_count = f->chksum_count;
file->chksum = f->chksum;
#endif /* HTTPD_PRECALCULATED_CHECKSUM */
#if LWIP_HTTPD_FILE_STATE
file->state = fs_state_init(file, name);
#endif /* #if LWIP_HTTPD_FILE_STATE */
return ERR_OK;
}
}
/* file not found */
return ERR_VAL;
}
/*-----------------------------------------------------------------------------------*/
void
fs_close(struct fs_file *file)
{
#if LWIP_HTTPD_CUSTOM_FILES
if (file->is_custom_file) {
fs_close_custom(file);
}
#endif /* LWIP_HTTPD_CUSTOM_FILES */
#if LWIP_HTTPD_FILE_STATE
fs_state_free(file, file->state);
#endif /* #if LWIP_HTTPD_FILE_STATE */
LWIP_UNUSED_ARG(file);
}
/*-----------------------------------------------------------------------------------*/
#if LWIP_HTTPD_DYNAMIC_FILE_READ
#if LWIP_HTTPD_FS_ASYNC_READ
int
fs_read_async(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg)
#else /* LWIP_HTTPD_FS_ASYNC_READ */
int
fs_read(struct fs_file *file, char *buffer, int count)
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
{
int read;
if(file->index == file->len) {
return FS_READ_EOF;
}
#if LWIP_HTTPD_FS_ASYNC_READ
LWIP_UNUSED_ARG(callback_fn);
LWIP_UNUSED_ARG(callback_arg);
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
#if LWIP_HTTPD_CUSTOM_FILES
if (file->is_custom_file) {
#if LWIP_HTTPD_FS_ASYNC_READ
return fs_read_async_custom(file, buffer, count, callback_fn, callback_arg);
#else /* LWIP_HTTPD_FS_ASYNC_READ */
return fs_read_custom(file, buffer, count);
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
}
#endif /* LWIP_HTTPD_CUSTOM_FILES */
read = file->len - file->index;
if(read > count) {
read = count;
}
MEMCPY(buffer, (file->data + file->index), read);
file->index += read;
return(read);
}
#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */
/*-----------------------------------------------------------------------------------*/
#if LWIP_HTTPD_FS_ASYNC_READ
int
fs_is_file_ready(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg)
{
if (file != NULL) {
#if LWIP_HTTPD_FS_ASYNC_READ
#if LWIP_HTTPD_CUSTOM_FILES
if (!fs_canread_custom(file)) {
if (fs_wait_read_custom(file, callback_fn, callback_arg)) {
return 0;
}
}
#else /* LWIP_HTTPD_CUSTOM_FILES */
LWIP_UNUSED_ARG(callback_fn);
LWIP_UNUSED_ARG(callback_arg);
#endif /* LWIP_HTTPD_CUSTOM_FILES */
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
}
return 1;
}
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
/*-----------------------------------------------------------------------------------*/
int
fs_bytes_left(struct fs_file *file)
{
return file->len - file->index;
}

View File

@@ -0,0 +1,21 @@
<html>
<head><title>lwIP - A Lightweight TCP/IP Stack</title></head>
<body bgcolor="white" text="black">
<table width="100%">
<tr valign="top"><td width="80">
<a href="http://www.sics.se/"><img src="/img/sics.gif"
border="0" alt="SICS logo" title="SICS logo"></a>
</td><td width="500">
<h1>lwIP - A Lightweight TCP/IP Stack</h1>
<h2>404 - Page not found</h2>
<p>
Sorry, the page you are requesting was not found on this
server.
</p>
</td><td>
&nbsp;
</td></tr>
</table>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

View File

@@ -0,0 +1,47 @@
<html>
<head><title>lwIP - A Lightweight TCP/IP Stack</title></head>
<body bgcolor="white" text="black">
<table width="100%">
<tr valign="top"><td width="80">
<a href="http://www.sics.se/"><img src="/img/sics.gif"
border="0" alt="SICS logo" title="SICS logo"></a>
</td><td width="500">
<h1>lwIP - A Lightweight TCP/IP Stack</h1>
<p>
The web page you are watching was served by a simple web
server running on top of the lightweight TCP/IP stack <a
href="http://www.sics.se/~adam/lwip/">lwIP</a>.
</p>
<p>
lwIP is an open source implementation of the TCP/IP
protocol suite that was originally written by <a
href="http://www.sics.se/~adam/lwip/">Adam Dunkels
of the Swedish Institute of Computer Science</a> but now is
being actively developed by a team of developers
distributed world-wide. Since it's release, lwIP has
spurred a lot of interest and has been ported to several
platforms and operating systems. lwIP can be used either
with or without an underlying OS.
</p>
<p>
The focus of the lwIP TCP/IP implementation is to reduce
the RAM usage while still having a full scale TCP. This
makes lwIP suitable for use in embedded systems with tens
of kilobytes of free RAM and room for around 40 kilobytes
of code ROM.
</p>
<p>
More information about lwIP can be found at the lwIP
homepage at <a
href="http://savannah.nongnu.org/projects/lwip/">http://savannah.nongnu.org/projects/lwip/</a>
or at the lwIP wiki at <a
href="http://lwip.wikia.com/">http://lwip.wikia.com/</a>.
</p>
</td><td>
&nbsp;
</td></tr>
</table>
</body>
</html>

298
ext/lwip/src/apps/httpd/fsdata.c Executable file
View File

@@ -0,0 +1,298 @@
#include "lwip/apps/fs.h"
#include "lwip/def.h"
#include "fsdata.h"
#define file_NULL (struct fsdata_file *) NULL
static const unsigned int dummy_align__img_sics_gif = 0;
static const unsigned char data__img_sics_gif[] = {
/* /img/sics.gif (14 chars) */
0x2f,0x69,0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x00,0x00,0x00,
/* HTTP header */
/* "HTTP/1.0 200 OK
" (17 bytes) */
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d,
0x0a,
/* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip)
" (63 bytes) */
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33,
0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,
0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,
0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
/* "Content-type: image/gif
" (27 bytes) */
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x69,0x6d,
0x61,0x67,0x65,0x2f,0x67,0x69,0x66,0x0d,0x0a,0x0d,0x0a,
/* raw file data (724 bytes) */
0x47,0x49,0x46,0x38,0x39,0x61,0x46,0x00,0x22,0x00,0xa5,0x00,0x00,0xd9,0x2b,0x39,
0x6a,0x6a,0x6a,0xbf,0xbf,0xbf,0x93,0x93,0x93,0x0f,0x0f,0x0f,0xb0,0xb0,0xb0,0xa6,
0xa6,0xa6,0x80,0x80,0x80,0x76,0x76,0x76,0x1e,0x1e,0x1e,0x9d,0x9d,0x9d,0x2e,0x2e,
0x2e,0x49,0x49,0x49,0x54,0x54,0x54,0x8a,0x8a,0x8a,0x60,0x60,0x60,0xc6,0xa6,0x99,
0xbd,0xb5,0xb2,0xc2,0xab,0xa1,0xd9,0x41,0x40,0xd5,0x67,0x55,0xc0,0xb0,0xaa,0xd5,
0x5e,0x4e,0xd6,0x50,0x45,0xcc,0x93,0x7d,0xc8,0xa1,0x90,0xce,0x8b,0x76,0xd2,0x7b,
0x65,0xd1,0x84,0x6d,0xc9,0x99,0x86,0x3a,0x3a,0x3a,0x00,0x00,0x00,0xb8,0xb8,0xb8,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2c,0x00,0x00,
0x00,0x00,0x46,0x00,0x22,0x00,0x00,0x06,0xfe,0x40,0x90,0x70,0x48,0x2c,0x1a,0x8f,
0xc8,0xa4,0x72,0xc9,0x6c,0x3a,0x9f,0xd0,0xa8,0x74,0x4a,0xad,0x5a,0xaf,0xd8,0xac,
0x76,0xa9,0x40,0x04,0xbe,0x83,0xe2,0x60,0x3c,0x50,0x20,0x0d,0x8e,0x6f,0x00,0x31,
0x28,0x1c,0x0d,0x07,0xb5,0xc3,0x60,0x75,0x24,0x3e,0xf8,0xfc,0x87,0x11,0x06,0xe9,
0x3d,0x46,0x07,0x0b,0x7a,0x7a,0x7c,0x43,0x06,0x1e,0x84,0x78,0x0b,0x07,0x6e,0x51,
0x01,0x8a,0x84,0x08,0x7e,0x79,0x80,0x87,0x89,0x91,0x7a,0x93,0x0a,0x04,0x99,0x78,
0x96,0x4f,0x03,0x9e,0x79,0x01,0x94,0x9f,0x43,0x9c,0xa3,0xa4,0x05,0x77,0xa3,0xa0,
0x4e,0x98,0x79,0x0b,0x1e,0x83,0xa4,0xa6,0x1f,0x96,0x05,0x9d,0xaa,0x78,0x01,0x07,
0x84,0x04,0x1e,0x1e,0xbb,0xb8,0x51,0x84,0x0e,0x43,0x05,0x07,0x77,0xa5,0x7f,0x42,
0xb1,0xb2,0x01,0x63,0x08,0x0d,0xbb,0x01,0x0c,0x7a,0x0d,0x44,0x0e,0xd8,0xaf,0x4c,
0x05,0x7a,0x04,0x47,0x07,0x07,0xb7,0x80,0xa2,0xe1,0x7d,0x44,0x05,0x01,0x04,0x01,
0xd0,0xea,0x87,0x93,0x4f,0xe0,0x9a,0x49,0xce,0xd8,0x79,0x04,0x66,0x20,0x15,0x10,
0x10,0x11,0x92,0x29,0x80,0xb6,0xc0,0x91,0x15,0x45,0x1e,0x90,0x19,0x71,0x46,0xa8,
0x5c,0x04,0x0e,0x00,0x22,0x4e,0xe8,0x40,0x24,0x9f,0x3e,0x04,0x06,0xa7,0x58,0xd4,
0x93,0xa0,0x1c,0x91,0x3f,0xe8,0xf0,0x88,0x03,0xb1,0x21,0xa2,0x49,0x00,0x19,0x86,
0xfc,0x52,0x44,0xe0,0x01,0x9d,0x29,0x21,0x15,0x25,0x50,0xf7,0x67,0x25,0x1e,0x06,
0xfd,0x4e,0x9a,0xb4,0x90,0xac,0x15,0xfa,0xcb,0x52,0x53,0x1e,0x8c,0xf2,0xf8,0x07,
0x92,0x2d,0x08,0x3a,0x4d,0x12,0x49,0x95,0x49,0xdb,0x14,0x04,0xc4,0x14,0x85,0x29,
0xaa,0xe7,0x01,0x08,0xa4,0x49,0x01,0x14,0x51,0xe0,0x53,0x91,0xd5,0x29,0x06,0x1a,
0x64,0x02,0xf4,0xc7,0x81,0x9e,0x05,0x20,0x22,0x64,0xa5,0x30,0xae,0xab,0x9e,0x97,
0x53,0xd8,0xb9,0xfd,0x50,0xef,0x93,0x02,0x42,0x74,0x34,0xe8,0x9c,0x20,0x21,0xc9,
0x01,0x68,0x78,0xe6,0x55,0x29,0x20,0x56,0x4f,0x4c,0x40,0x51,0x71,0x82,0xc0,0x70,
0x21,0x22,0x85,0xbe,0x4b,0x1c,0x44,0x05,0xea,0xa4,0x01,0xbf,0x22,0xb5,0xf0,0x1c,
0x06,0x51,0x38,0x8f,0xe0,0x22,0xec,0x18,0xac,0x39,0x22,0xd4,0xd6,0x93,0x44,0x01,
0x32,0x82,0xc8,0xfc,0x61,0xb3,0x01,0x45,0x0c,0x2e,0x83,0x30,0xd0,0x0e,0x17,0x24,
0x0f,0x70,0x85,0x94,0xee,0x05,0x05,0x53,0x4b,0x32,0x1b,0x3f,0x98,0xd3,0x1d,0x29,
0x81,0xb0,0xae,0x1e,0x8c,0x7e,0x68,0xe0,0x60,0x5a,0x54,0x8f,0xb0,0x78,0x69,0x73,
0x06,0xa2,0x00,0x6b,0x57,0xca,0x3d,0x11,0x50,0xbd,0x04,0x30,0x4b,0x3a,0xd4,0xab,
0x5f,0x1f,0x9b,0x3d,0x13,0x74,0x27,0x88,0x3c,0x25,0xe0,0x17,0xbe,0x7a,0x79,0x45,
0x0d,0x0c,0xb0,0x8b,0xda,0x90,0xca,0x80,0x06,0x5d,0x17,0x60,0x1c,0x22,0x4c,0xd8,
0x57,0x22,0x06,0x20,0x00,0x98,0x07,0x08,0xe4,0x56,0x80,0x80,0x1c,0xc5,0xb7,0xc5,
0x82,0x0c,0x36,0xe8,0xe0,0x83,0x10,0x46,0x28,0xe1,0x84,0x14,0x56,0x68,0xa1,0x10,
0x41,0x00,0x00,0x3b,};
static const unsigned int dummy_align__404_html = 1;
static const unsigned char data__404_html[] = {
/* /404.html (10 chars) */
0x2f,0x34,0x30,0x34,0x2e,0x68,0x74,0x6d,0x6c,0x00,0x00,0x00,
/* HTTP header */
/* "HTTP/1.0 404 File not found
" (29 bytes) */
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x34,0x30,0x34,0x20,0x46,0x69,0x6c,
0x65,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x0d,0x0a,
/* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip)
" (63 bytes) */
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33,
0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,
0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,
0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
/* "Content-type: text/html
" (27 bytes) */
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,
0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a,
/* raw file data (565 bytes) */
0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74,
0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69,
0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,
0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f,
0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63,
0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78,
0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20,
0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,
0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74,
0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c,
0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20,
0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,
0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,
0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69,
0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20,
0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d,
0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c,
0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f,
0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69,
0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09,
0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,
0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,
0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20,
0x20,0x3c,0x68,0x32,0x3e,0x34,0x30,0x34,0x20,0x2d,0x20,0x50,0x61,0x67,0x65,0x20,
0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x3c,0x2f,0x68,0x32,0x3e,0x0d,0x0a,
0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x53,0x6f,0x72,
0x72,0x79,0x2c,0x20,0x74,0x68,0x65,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75,
0x20,0x61,0x72,0x65,0x20,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x69,0x6e,0x67,0x20,
0x77,0x61,0x73,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x6f,0x6e,
0x20,0x74,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76,
0x65,0x72,0x2e,0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,
0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e,
0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72,
0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65,
0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74,
0x6d,0x6c,0x3e,0x0d,0x0a,};
static const unsigned int dummy_align__index_html = 2;
static const unsigned char data__index_html[] = {
/* /index.html (12 chars) */
0x2f,0x69,0x6e,0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,0x00,
/* HTTP header */
/* "HTTP/1.0 200 OK
" (17 bytes) */
0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d,
0x0a,
/* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip)
" (63 bytes) */
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33,
0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,
0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,
0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
/* "Content-type: text/html
" (27 bytes) */
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,
0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a,
/* raw file data (1751 bytes) */
0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74,
0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69,
0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,
0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f,
0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63,
0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78,
0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20,
0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,
0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74,
0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c,
0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20,
0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,
0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,
0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69,
0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20,
0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d,
0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c,
0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f,
0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69,
0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09,
0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,
0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,
0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20,
0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x77,
0x65,0x62,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75,0x20,0x61,0x72,0x65,0x20,
0x77,0x61,0x74,0x63,0x68,0x69,0x6e,0x67,0x20,0x77,0x61,0x73,0x20,0x73,0x65,0x72,
0x76,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x73,0x69,0x6d,0x70,0x6c,0x65,0x20,
0x77,0x65,0x62,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76,0x65,0x72,
0x20,0x72,0x75,0x6e,0x6e,0x69,0x6e,0x67,0x20,0x6f,0x6e,0x20,0x74,0x6f,0x70,0x20,
0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,
0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x20,0x73,0x74,0x61,0x63,0x6b,0x20,
0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,
0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,
0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x6c,
0x77,0x49,0x50,0x3c,0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,
0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,
0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20,
0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,
0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50,
0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63,
0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61,
0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69,
0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,
0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,
0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,
0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b,
0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,
0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75,
0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53,
0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e,
0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e,
0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c,
0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f,
0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20,
0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77,
0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65,
0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c,
0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70,
0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69,
0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20,
0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73,
0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61,
0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61,
0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77,
0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65,
0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68,
0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75,
0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09,
0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,
0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x66,0x6f,0x63,0x75,0x73,0x20,0x6f,
0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x54,0x43,0x50,0x2f,0x49,
0x50,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,
0x20,0x69,0x73,0x20,0x74,0x6f,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x0d,0x0a,0x09,
0x20,0x20,0x20,0x20,0x74,0x68,0x65,0x20,0x52,0x41,0x4d,0x20,0x75,0x73,0x61,0x67,
0x65,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x73,0x74,0x69,0x6c,0x6c,0x20,0x68,0x61,
0x76,0x69,0x6e,0x67,0x20,0x61,0x20,0x66,0x75,0x6c,0x6c,0x20,0x73,0x63,0x61,0x6c,
0x65,0x20,0x54,0x43,0x50,0x2e,0x20,0x54,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,
0x20,0x20,0x6d,0x61,0x6b,0x65,0x73,0x20,0x6c,0x77,0x49,0x50,0x20,0x73,0x75,0x69,
0x74,0x61,0x62,0x6c,0x65,0x20,0x66,0x6f,0x72,0x20,0x75,0x73,0x65,0x20,0x69,0x6e,
0x20,0x65,0x6d,0x62,0x65,0x64,0x64,0x65,0x64,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,
0x73,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x65,0x6e,0x73,0x0d,0x0a,0x09,0x20,0x20,
0x20,0x20,0x6f,0x66,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x20,0x6f,
0x66,0x20,0x66,0x72,0x65,0x65,0x20,0x52,0x41,0x4d,0x20,0x61,0x6e,0x64,0x20,0x72,
0x6f,0x6f,0x6d,0x20,0x66,0x6f,0x72,0x20,0x61,0x72,0x6f,0x75,0x6e,0x64,0x20,0x34,
0x30,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x0d,0x0a,0x09,0x20,0x20,
0x20,0x20,0x6f,0x66,0x20,0x63,0x6f,0x64,0x65,0x20,0x52,0x4f,0x4d,0x2e,0x0d,0x0a,
0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,
0x0a,0x09,0x20,0x20,0x20,0x20,0x4d,0x6f,0x72,0x65,0x20,0x69,0x6e,0x66,0x6f,0x72,
0x6d,0x61,0x74,0x69,0x6f,0x6e,0x20,0x61,0x62,0x6f,0x75,0x74,0x20,0x6c,0x77,0x49,
0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x61,
0x74,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,
0x20,0x68,0x6f,0x6d,0x65,0x70,0x61,0x67,0x65,0x20,0x61,0x74,0x20,0x3c,0x61,0x0d,
0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,
0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,
0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,
0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,
0x76,0x61,0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,
0x67,0x2f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x2f,
0x3c,0x2f,0x61,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x72,0x20,0x61,0x74,
0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x77,0x69,0x6b,0x69,0x20,0x61,
0x74,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,
0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b,
0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x22,0x3e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b,0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x3c,
0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,
0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e,
0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72,
0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65,
0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74,
0x6d,0x6c,0x3e,0x0d,0x0a,0x0d,0x0a,};
const struct fsdata_file file__img_sics_gif[] = { {
file_NULL,
data__img_sics_gif,
data__img_sics_gif + 16,
sizeof(data__img_sics_gif) - 16,
1,
}};
const struct fsdata_file file__404_html[] = { {
file__img_sics_gif,
data__404_html,
data__404_html + 12,
sizeof(data__404_html) - 12,
1,
}};
const struct fsdata_file file__index_html[] = { {
file__404_html,
data__index_html,
data__index_html + 12,
sizeof(data__index_html) - 12,
1,
}};
#define FS_ROOT file__index_html
#define FS_NUMFILES 3

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_FSDATA_H
#define LWIP_FSDATA_H
#include "lwip/apps/httpd_opts.h"
#include "lwip/apps/fs.h"
struct fsdata_file {
const struct fsdata_file *next;
const unsigned char *name;
const unsigned char *data;
int len;
u8_t flags;
#if HTTPD_PRECALCULATED_CHECKSUM
u16_t chksum_count;
const struct fsdata_chksum *chksum;
#endif /* HTTPD_PRECALCULATED_CHECKSUM */
};
#endif /* LWIP_FSDATA_H */

2629
ext/lwip/src/apps/httpd/httpd.c Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,114 @@
#ifndef LWIP_HTTPD_STRUCTS_H
#define LWIP_HTTPD_STRUCTS_H
#include "lwip/apps/httpd.h"
#if LWIP_HTTPD_DYNAMIC_HEADERS
/** This struct is used for a list of HTTP header strings for various
* filename extensions. */
typedef struct
{
const char *extension;
const char *content_type;
} tHTTPHeader;
/** A list of strings used in HTTP headers (see RFC 1945 HTTP/1.0 and
* RFC 2616 HTTP/1.1 for header field definitions) */
static const char * const g_psHTTPHeaderStrings[] =
{
"HTTP/1.0 200 OK\r\n",
"HTTP/1.0 404 File not found\r\n",
"HTTP/1.0 400 Bad Request\r\n",
"HTTP/1.0 501 Not Implemented\r\n",
"HTTP/1.1 200 OK\r\n",
"HTTP/1.1 404 File not found\r\n",
"HTTP/1.1 400 Bad Request\r\n",
"HTTP/1.1 501 Not Implemented\r\n",
"Content-Length: ",
"Connection: Close\r\n",
"Connection: keep-alive\r\n",
"Connection: keep-alive\r\nContent-Length: ",
"Server: "HTTPD_SERVER_AGENT"\r\n",
"\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
,"Connection: keep-alive\r\nContent-Length: 77\r\n\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
#endif
};
/* Indexes into the g_psHTTPHeaderStrings array */
#define HTTP_HDR_OK 0 /* 200 OK */
#define HTTP_HDR_NOT_FOUND 1 /* 404 File not found */
#define HTTP_HDR_BAD_REQUEST 2 /* 400 Bad request */
#define HTTP_HDR_NOT_IMPL 3 /* 501 Not Implemented */
#define HTTP_HDR_OK_11 4 /* 200 OK */
#define HTTP_HDR_NOT_FOUND_11 5 /* 404 File not found */
#define HTTP_HDR_BAD_REQUEST_11 6 /* 400 Bad request */
#define HTTP_HDR_NOT_IMPL_11 7 /* 501 Not Implemented */
#define HTTP_HDR_CONTENT_LENGTH 8 /* Content-Length: (HTTP 1.0)*/
#define HTTP_HDR_CONN_CLOSE 9 /* Connection: Close (HTTP 1.1) */
#define HTTP_HDR_CONN_KEEPALIVE 10 /* Connection: keep-alive (HTTP 1.1) */
#define HTTP_HDR_KEEPALIVE_LEN 11 /* Connection: keep-alive + Content-Length: (HTTP 1.1)*/
#define HTTP_HDR_SERVER 12 /* Server: HTTPD_SERVER_AGENT */
#define DEFAULT_404_HTML 13 /* default 404 body */
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
#define DEFAULT_404_HTML_PERSISTENT 14 /* default 404 body, but including Connection: keep-alive */
#endif
#define HTTP_HDR_HTML "Content-type: text/html\r\n\r\n"
#define HTTP_HDR_SSI "Content-type: text/html\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\nPragma: no-cache\r\n\r\n"
#define HTTP_HDR_GIF "Content-type: image/gif\r\n\r\n"
#define HTTP_HDR_PNG "Content-type: image/png\r\n\r\n"
#define HTTP_HDR_JPG "Content-type: image/jpeg\r\n\r\n"
#define HTTP_HDR_BMP "Content-type: image/bmp\r\n\r\n"
#define HTTP_HDR_ICO "Content-type: image/x-icon\r\n\r\n"
#define HTTP_HDR_APP "Content-type: application/octet-stream\r\n\r\n"
#define HTTP_HDR_JS "Content-type: application/javascript\r\n\r\n"
#define HTTP_HDR_RA "Content-type: application/javascript\r\n\r\n"
#define HTTP_HDR_CSS "Content-type: text/css\r\n\r\n"
#define HTTP_HDR_SWF "Content-type: application/x-shockwave-flash\r\n\r\n"
#define HTTP_HDR_XML "Content-type: text/xml\r\n\r\n"
#define HTTP_HDR_PDF "Content-type: application/pdf\r\n\r\n"
#define HTTP_HDR_JSON "Content-type: application/json\r\n\r\n"
#define HTTP_HDR_DEFAULT_TYPE "Content-type: text/plain\r\n\r\n"
/** A list of extension-to-HTTP header strings (see outdated RFC 1700 MEDIA TYPES
* and http://www.iana.org/assignments/media-types for registered content types
* and subtypes) */
static const tHTTPHeader g_psHTTPHeaders[] =
{
{ "html", HTTP_HDR_HTML},
{ "htm", HTTP_HDR_HTML},
{ "shtml",HTTP_HDR_SSI},
{ "shtm", HTTP_HDR_SSI},
{ "ssi", HTTP_HDR_SSI},
{ "gif", HTTP_HDR_GIF},
{ "png", HTTP_HDR_PNG},
{ "jpg", HTTP_HDR_JPG},
{ "bmp", HTTP_HDR_BMP},
{ "ico", HTTP_HDR_ICO},
{ "class",HTTP_HDR_APP},
{ "cls", HTTP_HDR_APP},
{ "js", HTTP_HDR_JS},
{ "ram", HTTP_HDR_RA},
{ "css", HTTP_HDR_CSS},
{ "swf", HTTP_HDR_SWF},
{ "xml", HTTP_HDR_XML},
{ "xsl", HTTP_HDR_XML},
{ "pdf", HTTP_HDR_PDF},
{ "json", HTTP_HDR_JSON}
};
#define NUM_HTTP_HEADERS (sizeof(g_psHTTPHeaders) / sizeof(tHTTPHeader))
#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
#if LWIP_HTTPD_SSI
static const char * const g_pcSSIExtensions[] = {
".shtml", ".shtm", ".ssi", ".xml"
};
#define NUM_SHTML_EXTENSIONS (sizeof(g_pcSSIExtensions) / sizeof(const char *))
#endif /* LWIP_HTTPD_SSI */
#endif /* LWIP_HTTPD_STRUCTS_H */

View File

@@ -0,0 +1,97 @@
#!/usr/bin/perl
open(OUTPUT, "> fsdata.c");
chdir("fs");
open(FILES, "find . -type f |");
while($file = <FILES>) {
# Do not include files in CVS directories nor backup files.
if($file =~ /(CVS|~)/) {
next;
}
chop($file);
open(HEADER, "> /tmp/header") || die $!;
if($file =~ /404/) {
print(HEADER "HTTP/1.0 404 File not found\r\n");
} else {
print(HEADER "HTTP/1.0 200 OK\r\n");
}
print(HEADER "Server: lwIP/pre-0.6 (http://www.sics.se/~adam/lwip/)\r\n");
if($file =~ /\.html$/) {
print(HEADER "Content-type: text/html\r\n");
} elsif($file =~ /\.gif$/) {
print(HEADER "Content-type: image/gif\r\n");
} elsif($file =~ /\.png$/) {
print(HEADER "Content-type: image/png\r\n");
} elsif($file =~ /\.jpg$/) {
print(HEADER "Content-type: image/jpeg\r\n");
} elsif($file =~ /\.class$/) {
print(HEADER "Content-type: application/octet-stream\r\n");
} elsif($file =~ /\.ram$/) {
print(HEADER "Content-type: audio/x-pn-realaudio\r\n");
} else {
print(HEADER "Content-type: text/plain\r\n");
}
print(HEADER "\r\n");
close(HEADER);
unless($file =~ /\.plain$/ || $file =~ /cgi/) {
system("cat /tmp/header $file > /tmp/file");
} else {
system("cp $file /tmp/file");
}
open(FILE, "/tmp/file");
unlink("/tmp/file");
unlink("/tmp/header");
$file =~ s/\.//;
$fvar = $file;
$fvar =~ s-/-_-g;
$fvar =~ s-\.-_-g;
print(OUTPUT "static const unsigned char data".$fvar."[] = {\n");
print(OUTPUT "\t/* $file */\n\t");
for($j = 0; $j < length($file); $j++) {
printf(OUTPUT "%#02x, ", unpack("C", substr($file, $j, 1)));
}
printf(OUTPUT "0,\n");
$i = 0;
while(read(FILE, $data, 1)) {
if($i == 0) {
print(OUTPUT "\t");
}
printf(OUTPUT "%#02x, ", unpack("C", $data));
$i++;
if($i == 10) {
print(OUTPUT "\n");
$i = 0;
}
}
print(OUTPUT "};\n\n");
close(FILE);
push(@fvars, $fvar);
push(@files, $file);
}
for($i = 0; $i < @fvars; $i++) {
$file = $files[$i];
$fvar = $fvars[$i];
if($i == 0) {
$prevfile = "NULL";
} else {
$prevfile = "file" . $fvars[$i - 1];
}
print(OUTPUT "const struct fsdata_file file".$fvar."[] = {{$prevfile, data$fvar, ");
print(OUTPUT "data$fvar + ". (length($file) + 1) .", ");
print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n");
}
print(OUTPUT "#define FS_ROOT file$fvars[$i - 1]\n\n");
print(OUTPUT "#define FS_NUMFILES $i\n");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
This directory contains a script ('makefsdata') to create C code suitable for
httpd for given html pages (or other files) in a directory.
There is also a plain C console application doing the same and extended a bit.
Usage: htmlgen [targetdir] [-s] [-i]s
targetdir: relative or absolute path to files to convert
switch -s: toggle processing of subdirectories (default is on)
switch -e: exclude HTTP header from file (header is created at runtime, default is on)
switch -11: include HTTP 1.1 header (1.0 is default)
if targetdir not specified, makefsdata will attempt to
process files in subdirectory 'fs'.

View File

@@ -0,0 +1,661 @@
/**
* @file
* lwIP iPerf server implementation
*/
/**
* @defgroup iperf Iperf server
* @ingroup apps
*
* This is a simple performance measuring server to check your bandwith using
* iPerf2 on a PC as client.
* It is currently a minimal implementation providing an IPv4 TCP server only.
*
* @todo: implement UDP mode and IPv6
*/
/*
* Copyright (c) 2014 Simon Goldschmidt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Simon Goldschmidt
*/
#include "lwip/apps/lwiperf.h"
#include "lwip/tcp.h"
#include "lwip/sys.h"
#include <string.h>
/* Currently, only TCP-over-IPv4 is implemented (does iperf support IPv6 anyway?) */
#if LWIP_IPV4 && LWIP_TCP && LWIP_CALLBACK_API
/** Specify the idle timeout (in seconds) after that the test fails */
#ifndef LWIPERF_TCP_MAX_IDLE_SEC
#define LWIPERF_TCP_MAX_IDLE_SEC 10U
#endif
#if LWIPERF_TCP_MAX_IDLE_SEC > 255
#error LWIPERF_TCP_MAX_IDLE_SEC must fit into an u8_t
#endif
/* File internal memory allocation (struct lwiperf_*): this defaults to
the heap */
#ifndef LWIPERF_ALLOC
#define LWIPERF_ALLOC(type) mem_malloc(sizeof(type))
#define LWIPERF_FREE(type, item) mem_free(item)
#endif
/** If this is 1, check that received data has the correct format */
#ifndef LWIPERF_CHECK_RX_DATA
#define LWIPERF_CHECK_RX_DATA 0
#endif
/** This is the Iperf settings struct sent from the client */
typedef struct _lwiperf_settings {
#define LWIPERF_FLAGS_ANSWER_TEST 0x80000000
#define LWIPERF_FLAGS_ANSWER_NOW 0x00000001
u32_t flags;
u32_t num_threads; /* unused for now */
u32_t remote_port;
u32_t buffer_len; /* unused for now */
u32_t win_band; /* TCP window / UDP rate: unused for now */
u32_t amount; /* pos. value: bytes?; neg. values: time (unit is 10ms: 1/100 second) */
} lwiperf_settings_t;
/** Basic connection handle */
struct _lwiperf_state_base;
typedef struct _lwiperf_state_base lwiperf_state_base_t;
struct _lwiperf_state_base {
/* 1=tcp, 0=udp */
u8_t tcp;
/* 1=server, 0=client */
u8_t server;
lwiperf_state_base_t* next;
lwiperf_state_base_t* related_server_state;
};
/** Connection handle for a TCP iperf session */
typedef struct _lwiperf_state_tcp {
lwiperf_state_base_t base;
struct tcp_pcb* server_pcb;
struct tcp_pcb* conn_pcb;
u32_t time_started;
lwiperf_report_fn report_fn;
void* report_arg;
u8_t poll_count;
u8_t next_num;
u32_t bytes_transferred;
lwiperf_settings_t settings;
u8_t have_settings_buf;
} lwiperf_state_tcp_t;
/** List of active iperf sessions */
static lwiperf_state_base_t* lwiperf_all_connections;
/** A const buffer to send from: we want to measure sending, not copying! */
static const u8_t lwiperf_txbuf_const[1600] = {
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9',
};
static err_t lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb);
static void lwiperf_tcp_err(void *arg, err_t err);
/** Add an iperf session to the 'active' list */
static void
lwiperf_list_add(lwiperf_state_base_t* item)
{
if (lwiperf_all_connections == NULL) {
lwiperf_all_connections = item;
} else {
item = lwiperf_all_connections;
}
}
/** Remove an iperf session from the 'active' list */
static void
lwiperf_list_remove(lwiperf_state_base_t* item)
{
lwiperf_state_base_t* prev = NULL;
lwiperf_state_base_t* iter;
for (iter = lwiperf_all_connections; iter != NULL; prev = iter, iter = iter->next) {
if (iter == item) {
if (prev == NULL) {
lwiperf_all_connections = iter->next;
} else {
prev->next = item;
}
/* @debug: ensure this item is listed only once */
for (iter = iter->next; iter != NULL; iter = iter->next) {
LWIP_ASSERT("duplicate entry", iter != item);
}
break;
}
}
}
/** Call the report function of an iperf tcp session */
static void
lwip_tcp_conn_report(lwiperf_state_tcp_t* conn, enum lwiperf_report_type report_type)
{
if ((conn != NULL) && (conn->report_fn != NULL)) {
u32_t now, duration_ms, bandwidth_kbitpsec;
now = sys_now();
duration_ms = now - conn->time_started;
if (duration_ms == 0) {
bandwidth_kbitpsec = 0;
} else {
bandwidth_kbitpsec = (conn->bytes_transferred / duration_ms) * 8U;
}
conn->report_fn(conn->report_arg, report_type,
&conn->conn_pcb->local_ip, conn->conn_pcb->local_port,
&conn->conn_pcb->remote_ip, conn->conn_pcb->remote_port,
conn->bytes_transferred, duration_ms, bandwidth_kbitpsec);
}
}
/** Close an iperf tcp session */
static void
lwiperf_tcp_close(lwiperf_state_tcp_t* conn, enum lwiperf_report_type report_type)
{
err_t err;
lwip_tcp_conn_report(conn, report_type);
lwiperf_list_remove(&conn->base);
if (conn->conn_pcb != NULL) {
tcp_arg(conn->conn_pcb, NULL);
tcp_poll(conn->conn_pcb, NULL, 0);
tcp_sent(conn->conn_pcb, NULL);
tcp_recv(conn->conn_pcb, NULL);
tcp_err(conn->conn_pcb, NULL);
err = tcp_close(conn->conn_pcb);
if (err != ERR_OK) {
/* don't want to wait for free memory here... */
tcp_abort(conn->conn_pcb);
}
} else {
/* no conn pcb, this is the server pcb */
err = tcp_close(conn->server_pcb);
LWIP_ASSERT("error", err != ERR_OK);
}
LWIPERF_FREE(lwiperf_state_tcp_t, conn);
}
/** Try to send more data on an iperf tcp session */
static err_t
lwiperf_tcp_client_send_more(lwiperf_state_tcp_t* conn)
{
int send_more;
err_t err;
u16_t txlen;
u16_t txlen_max;
void* txptr;
u8_t apiflags;
LWIP_ASSERT("conn invalid", (conn != NULL) && conn->base.tcp && (conn->base.server == 0));
do {
send_more = 0;
if (conn->settings.amount & PP_HTONL(0x80000000)) {
/* 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)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 */
lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT);
return ERR_OK;
}
} else {
/* this session is byte-limited */
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 */
lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT);
return ERR_OK;
}
}
if (conn->bytes_transferred < 24) {
/* transmit the settings a first time */
txptr = &((u8_t*)&conn->settings)[conn->bytes_transferred];
txlen_max = (u16_t)(24 - conn->bytes_transferred);
apiflags = TCP_WRITE_FLAG_COPY;
} else if (conn->bytes_transferred < 48) {
/* transmit the settings a second time */
txptr = &((u8_t*)&conn->settings)[conn->bytes_transferred - 24];
txlen_max = (u16_t)(48 - conn->bytes_transferred);
apiflags = TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE;
send_more = 1;
} else {
/* transmit data */
/* @todo: every x bytes, transmit the settings again */
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;
}
apiflags = 0; /* no copying needed */
send_more = 1;
}
txlen = txlen_max;
do {
err = tcp_write(conn->conn_pcb, txptr, txlen, apiflags);
if (err == ERR_MEM) {
txlen /= 2;
}
} while ((err == ERR_MEM) && (txlen >= (TCP_MSS/2)));
if (err == ERR_OK) {
conn->bytes_transferred += txlen;
} else {
send_more = 0;
}
} while(send_more);
tcp_output(conn->conn_pcb);
return ERR_OK;
}
/** TCP sent callback, try to send more data */
static err_t
lwiperf_tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg;
/* @todo: check 'len' (e.g. to time ACK of all data)? for now, we just send more... */
LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb);
LWIP_UNUSED_ARG(tpcb);
LWIP_UNUSED_ARG(len);
conn->poll_count = 0;
return lwiperf_tcp_client_send_more(conn);
}
/** TCP connected callback (active connection), send data now */
static err_t
lwiperf_tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
{
lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg;
LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb);
LWIP_UNUSED_ARG(tpcb);
if (err != ERR_OK) {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
return ERR_OK;
}
conn->poll_count = 0;
conn->time_started = sys_now();
return lwiperf_tcp_client_send_more(conn);
}
/** Start TCP connection back to the client (either parallel or after the
* receive test has finished.
*/
static err_t
lwiperf_tx_start(lwiperf_state_tcp_t* conn)
{
err_t err;
lwiperf_state_tcp_t* client_conn;
struct tcp_pcb* newpcb;
ip_addr_t remote_addr;
u16_t remote_port;
client_conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t);
if (client_conn == NULL) {
return ERR_MEM;
}
newpcb = tcp_new();
if (newpcb == NULL) {
LWIPERF_FREE(lwiperf_state_tcp_t, client_conn);
return ERR_MEM;
}
MEMCPY(client_conn, conn, sizeof(lwiperf_state_tcp_t));
client_conn->base.server = 0;
client_conn->server_pcb = NULL;
client_conn->conn_pcb = newpcb;
client_conn->time_started = sys_now(); /* @todo: set this again on 'connected' */
client_conn->poll_count = 0;
client_conn->next_num = 4; /* initial nr is '4' since the header has 24 byte */
client_conn->bytes_transferred = 0;
client_conn->settings.flags = 0; /* prevent the remote side starting back as client again */
tcp_arg(newpcb, client_conn);
tcp_sent(newpcb, lwiperf_tcp_client_sent);
tcp_poll(newpcb, lwiperf_tcp_poll, 2U);
tcp_err(newpcb, lwiperf_tcp_err);
ip_addr_copy(remote_addr, conn->conn_pcb->remote_ip);
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) {
lwiperf_tcp_close(client_conn, LWIPERF_TCP_ABORTED_LOCAL);
return err;
}
lwiperf_list_add(&client_conn->base);
return ERR_OK;
}
/** Receive data on an iperf tcp session */
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;
lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg;
LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb);
LWIP_UNUSED_ARG(tpcb);
if (err != ERR_OK) {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
return ERR_OK;
}
if (p == NULL) {
/* connection closed -> test done */
if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) ==
PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) {
/* client requested transmission after end of test */
lwiperf_tx_start(conn);
}
lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_SERVER);
return ERR_OK;
}
tot_len = p->tot_len;
conn->poll_count = 0;
if ((!conn->have_settings_buf) || ((conn->bytes_transferred -24) % (1024*128) == 0)) {
/* wait for 24-byte header */
if (p->tot_len < sizeof(lwiperf_settings_t)) {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
pbuf_free(p);
return ERR_VAL;
}
if (!conn->have_settings_buf) {
if (pbuf_copy_partial(p, &conn->settings, sizeof(lwiperf_settings_t), 0) != sizeof(lwiperf_settings_t)) {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL);
pbuf_free(p);
return ERR_VAL;
}
conn->have_settings_buf = 1;
if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) ==
PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) {
/* client requested parallel transmission test */
err_t err2 = lwiperf_tx_start(conn);
if (err2 != ERR_OK) {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_TXERROR);
pbuf_free(p);
return err2;
}
}
} else {
if (pbuf_memcmp(p, 0, &conn->settings, sizeof(lwiperf_settings_t)) != 0) {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
pbuf_free(p);
return ERR_VAL;
}
}
conn->bytes_transferred += sizeof(lwiperf_settings_t);
if (conn->bytes_transferred <= 24) {
conn->time_started = sys_now();
tcp_recved(tpcb, p->tot_len);
pbuf_free(p);
return ERR_OK;
}
conn->next_num = 4; /* 24 bytes received... */
tmp = pbuf_header(p, -24);
LWIP_ASSERT("pbuf_header failed", tmp == 0);
}
packet_idx = 0;
for (q = p; q != NULL; q = q->next) {
#if LWIPERF_CHECK_RX_DATA
const u8_t* payload = (const u8_t*)q->payload;
u16_t i;
for (i = 0; i < q->len; i++) {
u8_t val = payload[i];
u8_t num = val - '0';
if (num == conn->next_num) {
conn->next_num++;
if (conn->next_num == 10) {
conn->next_num = 0;
}
} else {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
pbuf_free(p);
return ERR_VAL;
}
}
#endif
packet_idx += q->len;
}
LWIP_ASSERT("count mismatch", packet_idx == p->tot_len);
conn->bytes_transferred += packet_idx;
tcp_recved(tpcb, tot_len);
pbuf_free(p);
return ERR_OK;
}
/** Error callback, iperf tcp session aborted */
static void
lwiperf_tcp_err(void *arg, err_t err)
{
lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg;
LWIP_UNUSED_ARG(err);
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
}
/** TCP poll callback, try to send more data */
static err_t
lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb)
{
lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg;
LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb);
LWIP_UNUSED_ARG(tpcb);
if (++conn->poll_count >= LWIPERF_TCP_MAX_IDLE_SEC) {
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL);
return ERR_OK; /* lwiperf_tcp_close frees conn */
}
if (!conn->base.server) {
lwiperf_tcp_client_send_more(conn);
}
return ERR_OK;
}
/** This is called when a new client connects for an iperf tcp session */
static err_t
lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
lwiperf_state_tcp_t *s, *conn;
if ((err != ERR_OK) || (newpcb == NULL) || (arg == NULL)) {
return ERR_VAL;
}
s = (lwiperf_state_tcp_t*)arg;
conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t);
if (conn == NULL) {
return ERR_MEM;
}
memset(conn, 0, sizeof(lwiperf_state_tcp_t));
conn->base.tcp = 1;
conn->base.server = 1;
conn->base.related_server_state = &s->base;
conn->server_pcb = s->server_pcb;
conn->conn_pcb = newpcb;
conn->time_started = sys_now();
conn->report_fn = s->report_fn;
conn->report_arg = s->report_arg;
/* setup the tcp rx connection */
tcp_arg(newpcb, conn);
tcp_recv(newpcb, lwiperf_tcp_recv);
tcp_poll(newpcb, lwiperf_tcp_poll, 2U);
tcp_err(conn->conn_pcb, lwiperf_tcp_err);
lwiperf_list_add(&conn->base);
return ERR_OK;
}
/**
* @ingroup iperf
* Start a TCP iperf server on the default TCP port (5001) and listen for
* incoming connections from iperf clients.
*
* @returns a connection handle that can be used to abort the server
* by calling @ref lwiperf_abort()
*/
void*
lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void* report_arg)
{
return lwiperf_start_tcp_server(IP_ADDR_ANY, LWIPERF_TCP_PORT_DEFAULT,
report_fn, report_arg);
}
/**
* @ingroup iperf
* Start a TCP iperf server on a specific IP address and port and listen for
* incoming connections from iperf clients.
*
* @returns a connection handle that can be used to abort the server
* by calling @ref lwiperf_abort()
*/
void*
lwiperf_start_tcp_server(const ip_addr_t* local_addr, u16_t local_port,
lwiperf_report_fn report_fn, void* report_arg)
{
err_t err;
struct tcp_pcb* pcb;
lwiperf_state_tcp_t* s;
if (local_addr == NULL) {
return NULL;
}
s = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t);
if (s == NULL) {
return NULL;
}
memset(s, 0, sizeof(lwiperf_state_tcp_t));
s->base.tcp = 1;
s->base.server = 1;
s->report_fn = report_fn;
s->report_arg = report_arg;
pcb = tcp_new();
if (pcb != NULL) {
err = tcp_bind(pcb, local_addr, local_port);
if (err == ERR_OK) {
s->server_pcb = tcp_listen_with_backlog(pcb, 1);
}
}
if (s->server_pcb == NULL) {
if (pcb != NULL) {
tcp_close(pcb);
}
LWIPERF_FREE(lwiperf_state_tcp_t, s);
return NULL;
}
pcb = NULL;
tcp_arg(s->server_pcb, s);
tcp_accept(s->server_pcb, lwiperf_tcp_accept);
lwiperf_list_add(&s->base);
return s;
}
/**
* @ingroup iperf
* Abort an iperf session (handle returned by lwiperf_start_tcp_server*())
*/
void
lwiperf_abort(void* lwiperf_session)
{
lwiperf_state_base_t* i, *dealloc, *last = NULL;
for (i = lwiperf_all_connections; i != NULL; ) {
if ((i == lwiperf_session) || (i->related_server_state == lwiperf_session)) {
dealloc = i;
i = i->next;
if (last != NULL) {
last->next = i;
}
LWIPERF_FREE(lwiperf_state_tcp_t, dealloc); /* @todo: type? */
} else {
last = i;
i = i->next;
}
}
}
#endif /* LWIP_IPV4 && LWIP_TCP && LWIP_CALLBACK_API */

2028
ext/lwip/src/apps/mdns/mdns.c Executable file

File diff suppressed because it is too large Load Diff

1341
ext/lwip/src/apps/mqtt/mqtt.c Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,367 @@
/**
* @file
* NetBIOS name service responder
*/
/**
* @defgroup netbiosns NETBIOS responder
* @ingroup apps
*
* This is an example implementation of a NetBIOS name server.
* It responds to name queries for a configurable name.
* Name resolving is not supported.
*
* Note that the device doesn't broadcast it's own name so can't
* detect duplicate names!
*/
/*
* 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.
*
*/
#include "lwip/apps/netbiosns.h"
#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"
#include <string.h>
/** default port number for "NetBIOS Name service */
#define NETBIOS_PORT 137
/** size of a NetBIOS name */
#define NETBIOS_NAME_LEN 16
/** The Time-To-Live for NetBIOS name responds (in seconds)
* Default is 300000 seconds (3 days, 11 hours, 20 minutes) */
#define NETBIOS_NAME_TTL 300000u
/** NetBIOS header flags */
#define NETB_HFLAG_RESPONSE 0x8000U
#define NETB_HFLAG_OPCODE 0x7800U
#define NETB_HFLAG_OPCODE_NAME_QUERY 0x0000U
#define NETB_HFLAG_AUTHORATIVE 0x0400U
#define NETB_HFLAG_TRUNCATED 0x0200U
#define NETB_HFLAG_RECURS_DESIRED 0x0100U
#define NETB_HFLAG_RECURS_AVAILABLE 0x0080U
#define NETB_HFLAG_BROADCAST 0x0010U
#define NETB_HFLAG_REPLYCODE 0x0008U
#define NETB_HFLAG_REPLYCODE_NOERROR 0x0000U
/** NetBIOS name flags */
#define NETB_NFLAG_UNIQUE 0x8000U
#define NETB_NFLAG_NODETYPE 0x6000U
#define NETB_NFLAG_NODETYPE_HNODE 0x6000U
#define NETB_NFLAG_NODETYPE_MNODE 0x4000U
#define NETB_NFLAG_NODETYPE_PNODE 0x2000U
#define NETB_NFLAG_NODETYPE_BNODE 0x0000U
/** NetBIOS message header */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct netbios_hdr {
PACK_STRUCT_FIELD(u16_t trans_id);
PACK_STRUCT_FIELD(u16_t flags);
PACK_STRUCT_FIELD(u16_t questions);
PACK_STRUCT_FIELD(u16_t answerRRs);
PACK_STRUCT_FIELD(u16_t authorityRRs);
PACK_STRUCT_FIELD(u16_t additionalRRs);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** NetBIOS message name part */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct netbios_name_hdr {
PACK_STRUCT_FLD_8(u8_t nametype);
PACK_STRUCT_FLD_8(u8_t encname[(NETBIOS_NAME_LEN*2)+1]);
PACK_STRUCT_FIELD(u16_t type);
PACK_STRUCT_FIELD(u16_t cls);
PACK_STRUCT_FIELD(u32_t ttl);
PACK_STRUCT_FIELD(u16_t datalen);
PACK_STRUCT_FIELD(u16_t flags);
PACK_STRUCT_FLD_S(ip4_addr_p_t addr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** NetBIOS message */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct netbios_resp
{
struct netbios_hdr resp_hdr;
struct netbios_name_hdr resp_name;
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#ifdef NETBIOS_LWIP_NAME
#define NETBIOS_LOCAL_NAME NETBIOS_LWIP_NAME
#else
static char netbiosns_local_name[NETBIOS_NAME_LEN];
#define NETBIOS_LOCAL_NAME netbiosns_local_name
#endif
struct udp_pcb *netbiosns_pcb;
/** Decode a NetBIOS name (from packet to string) */
static int
netbiosns_name_decode(char *name_enc, char *name_dec, int name_dec_len)
{
char *pname;
char cname;
char cnbname;
int idx = 0;
LWIP_UNUSED_ARG(name_dec_len);
/* Start decoding netbios name. */
pname = name_enc;
for (;;) {
/* Every two characters of the first level-encoded name
* turn into one character in the decoded name. */
cname = *pname;
if (cname == '\0')
break; /* no more characters */
if (cname == '.')
break; /* scope ID follows */
if (cname < 'A' || cname > 'Z') {
/* Not legal. */
return -1;
}
cname -= 'A';
cnbname = cname << 4;
pname++;
cname = *pname;
if (cname == '\0' || cname == '.') {
/* No more characters in the name - but we're in
* the middle of a pair. Not legal. */
return -1;
}
if (cname < 'A' || cname > 'Z') {
/* Not legal. */
return -1;
}
cname -= 'A';
cnbname |= cname;
pname++;
/* Do we have room to store the character? */
if (idx < NETBIOS_NAME_LEN) {
/* Yes - store the character. */
name_dec[idx++] = (cnbname!=' '?cnbname:'\0');
}
}
return 0;
}
#if 0 /* function currently unused */
/** Encode a NetBIOS name (from string to packet) - currently unused because
we don't ask for names. */
static int
netbiosns_name_encode(char *name_enc, char *name_dec, int name_dec_len)
{
char *pname;
char cname;
unsigned char ucname;
int idx = 0;
/* Start encoding netbios name. */
pname = name_enc;
for (;;) {
/* Every two characters of the first level-encoded name
* turn into one character in the decoded name. */
cname = *pname;
if (cname == '\0')
break; /* no more characters */
if (cname == '.')
break; /* scope ID follows */
if ((cname < 'A' || cname > 'Z') && (cname < '0' || cname > '9')) {
/* Not legal. */
return -1;
}
/* Do we have room to store the character? */
if (idx >= name_dec_len) {
return -1;
}
/* Yes - store the character. */
ucname = cname;
name_dec[idx++] = ('A'+((ucname>>4) & 0x0F));
name_dec[idx++] = ('A'+( ucname & 0x0F));
pname++;
}
/* Fill with "space" coding */
for (;idx < name_dec_len - 1;) {
name_dec[idx++] = 'C';
name_dec[idx++] = 'A';
}
/* Terminate string */
name_dec[idx] = '\0';
return 0;
}
#endif /* 0 */
/** NetBIOS Name service recv callback */
static void
netbiosns_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
LWIP_UNUSED_ARG(arg);
/* if packet is valid */
if (p != NULL) {
char netbios_name[NETBIOS_NAME_LEN+1];
struct netbios_hdr* netbios_hdr = (struct netbios_hdr*)p->payload;
struct netbios_name_hdr* netbios_name_hdr = (struct netbios_name_hdr*)(netbios_hdr+1);
/* we only answer if we got a default interface */
if (netif_default != NULL) {
/* @todo: do we need to check answerRRs/authorityRRs/additionalRRs? */
/* if the packet is a NetBIOS name query question */
if (((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_OPCODE)) == PP_NTOHS(NETB_HFLAG_OPCODE_NAME_QUERY)) &&
((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_RESPONSE)) == 0) &&
(netbios_hdr->questions == PP_NTOHS(1))) {
/* decode the NetBIOS name */
netbiosns_name_decode((char*)(netbios_name_hdr->encname), netbios_name, sizeof(netbios_name));
/* if the packet is for us */
if (lwip_strnicmp(netbios_name, NETBIOS_LOCAL_NAME, sizeof(NETBIOS_LOCAL_NAME)) == 0) {
struct pbuf *q;
struct netbios_resp *resp;
q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_resp), PBUF_RAM);
if (q != NULL) {
resp = (struct netbios_resp*)q->payload;
/* prepare NetBIOS header response */
resp->resp_hdr.trans_id = netbios_hdr->trans_id;
resp->resp_hdr.flags = PP_HTONS(NETB_HFLAG_RESPONSE |
NETB_HFLAG_OPCODE_NAME_QUERY |
NETB_HFLAG_AUTHORATIVE |
NETB_HFLAG_RECURS_DESIRED);
resp->resp_hdr.questions = 0;
resp->resp_hdr.answerRRs = PP_HTONS(1);
resp->resp_hdr.authorityRRs = 0;
resp->resp_hdr.additionalRRs = 0;
/* prepare NetBIOS header datas */
MEMCPY( resp->resp_name.encname, netbios_name_hdr->encname, sizeof(netbios_name_hdr->encname));
resp->resp_name.nametype = netbios_name_hdr->nametype;
resp->resp_name.type = netbios_name_hdr->type;
resp->resp_name.cls = netbios_name_hdr->cls;
resp->resp_name.ttl = PP_HTONL(NETBIOS_NAME_TTL);
resp->resp_name.datalen = PP_HTONS(sizeof(resp->resp_name.flags)+sizeof(resp->resp_name.addr));
resp->resp_name.flags = PP_HTONS(NETB_NFLAG_NODETYPE_BNODE);
ip4_addr_copy(resp->resp_name.addr, *netif_ip4_addr(netif_default));
/* send the NetBIOS response */
udp_sendto(upcb, q, addr, port);
/* free the "reference" pbuf */
pbuf_free(q);
}
}
}
}
/* free the pbuf */
pbuf_free(p);
}
}
/**
* @ingroup netbiosns
* Init netbios responder
*/
void
netbiosns_init(void)
{
#ifdef NETBIOS_LWIP_NAME
LWIP_ASSERT("NetBIOS name is too long!", strlen(NETBIOS_LWIP_NAME) < NETBIOS_NAME_LEN);
#endif
netbiosns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
if (netbiosns_pcb != NULL) {
/* we have to be allowed to send broadcast packets! */
ip_set_option(netbiosns_pcb, SOF_BROADCAST);
udp_bind(netbiosns_pcb, IP_ANY_TYPE, NETBIOS_PORT);
udp_recv(netbiosns_pcb, netbiosns_recv, netbiosns_pcb);
}
}
#ifndef NETBIOS_LWIP_NAME
/**
* @ingroup netbiosns
* Set netbios name. ATTENTION: the hostname must be less than 15 characters!
*/
void
netbiosns_set_name(const char* hostname)
{
size_t copy_len = strlen(hostname);
LWIP_ASSERT("NetBIOS name is too long!", copy_len < NETBIOS_NAME_LEN);
if (copy_len >= NETBIOS_NAME_LEN) {
copy_len = NETBIOS_NAME_LEN - 1;
}
MEMCPY(netbiosns_local_name, hostname, copy_len + 1);
}
#endif
/**
* @ingroup netbiosns
* Stop netbios responder
*/
void
netbiosns_stop(void)
{
if (netbiosns_pcb != NULL) {
udp_remove(netbiosns_pcb);
netbiosns_pcb = NULL;
}
}
#endif /* LWIP_IPV4 && LWIP_UDP */

View File

@@ -0,0 +1,749 @@
/**
* @file
* Abstract Syntax Notation One (ISO 8824, 8825) encoding
*
* @todo not optimised (yet), favor correctness over speed, favor speed over size
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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: Christiaan Simons <christiaan.simons@axon.tv>
* Martin Hentschel <info@cl-soft.de>
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "snmp_asn1.h"
#define PBUF_OP_EXEC(code) \
if ((code) != ERR_OK) { \
return ERR_BUF; \
}
/**
* Encodes a TLV into a pbuf stream.
*
* @param pbuf_stream points to a pbuf stream
* @param tlv TLV to encode
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv)
{
u8_t data;
u8_t length_bytes_required;
/* write type */
if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
/* extended format is not used by SNMP so we do not accept those values */
return ERR_ARG;
}
if (tlv->type_len != 0) {
/* any other value as auto is not accepted for type (we always use one byte because extended syntax is prohibited) */
return ERR_ARG;
}
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, tlv->type));
tlv->type_len = 1;
/* write length */
if (tlv->value_len <= 127) {
length_bytes_required = 1;
} else if (tlv->value_len <= 255) {
length_bytes_required = 2;
} else {
length_bytes_required = 3;
}
/* check for forced min length */
if (tlv->length_len > 0) {
if (tlv->length_len < length_bytes_required) {
/* unable to code requested length in requested number of bytes */
return ERR_ARG;
}
length_bytes_required = tlv->length_len;
} else {
tlv->length_len = length_bytes_required;
}
if (length_bytes_required > 1) {
/* multi byte representation required */
length_bytes_required--;
data = 0x80 | length_bytes_required; /* extended length definition, 1 length byte follows */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
while (length_bytes_required > 1) {
if (length_bytes_required == 2) {
/* append high byte */
data = (u8_t)(tlv->value_len >> 8);
} else {
/* append leading 0x00 */
data = 0x00;
}
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
length_bytes_required--;
}
}
/* append low byte */
data = (u8_t)(tlv->value_len & 0xFF);
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data));
return ERR_OK;
}
/**
* Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.
*
* @param pbuf_stream points to a pbuf stream
* @param raw_len raw data length
* @param raw points raw data
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len)
{
PBUF_OP_EXEC(snmp_pbuf_stream_writebuf(pbuf_stream, raw, raw_len));
return ERR_OK;
}
/**
* Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.
*
* @param pbuf_stream points to a pbuf stream
* @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
* @param value is the host order u32_t value to be encoded
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*
* @see snmp_asn1_enc_u32t_cnt()
*/
err_t
snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value)
{
if (octets_needed > 5) {
return ERR_ARG;
}
if (octets_needed == 5) {
/* not enough bits in 'value' add leading 0x00 */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
octets_needed--;
}
while (octets_needed > 1) {
octets_needed--;
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
}
/* (only) one least significant octet */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
return ERR_OK;
}
/**
* Encodes u64_t (counter64) into a pbuf chained ASN1 msg.
*
* @param pbuf_stream points to a pbuf stream
* @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
* @param value is the host order u32_t value to be encoded
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*
* @see snmp_asn1_enc_u64t_cnt()
*/
err_t
snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value)
{
if (octets_needed > 9) {
return ERR_ARG;
}
if (octets_needed == 9) {
/* not enough bits in 'value' add leading 0x00 */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
octets_needed--;
}
while (octets_needed > 4) {
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))));
}
/* always write at least one octet (also in case of value == 0) */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value)));
return ERR_OK;
}
/**
* Encodes s32_t integer into a pbuf chained ASN1 msg.
*
* @param pbuf_stream points to a pbuf stream
* @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())
* @param value is the host order s32_t value to be encoded
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*
* @see snmp_asn1_enc_s32t_cnt()
*/
err_t
snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value)
{
while (octets_needed > 1) {
octets_needed--;
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3))));
}
/* (only) one least significant octet */
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value));
return ERR_OK;
}
/**
* Encodes object identifier into a pbuf chained ASN1 msg.
*
* @param pbuf_stream points to a pbuf stream
* @param oid points to object identifier array
* @param oid_len object identifier array length
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len)
{
if (oid_len > 1) {
/* write compressed first two sub id's */
u32_t compressed_byte = ((oid[0] * 40) + oid[1]);
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)compressed_byte));
oid_len -= 2;
oid += 2;
} else {
/* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */
/* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
return ERR_ARG;
}
while (oid_len > 0) {
u32_t sub_id;
u8_t shift, tail;
oid_len--;
sub_id = *oid;
tail = 0;
shift = 28;
while (shift > 0) {
u8_t code;
code = (u8_t)(sub_id >> shift);
if ((code != 0) || (tail != 0)) {
tail = 1;
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, code | 0x80));
}
shift -= 7;
}
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)sub_id & 0x7F));
/* proceed to next sub-identifier */
oid++;
}
return ERR_OK;
}
/**
* Returns octet count for length.
*
* @param length parameter length
* @param octets_needed points to the return value
*/
void
snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
{
if (length < 0x80U) {
*octets_needed = 1;
} else if (length < 0x100U) {
*octets_needed = 2;
} else {
*octets_needed = 3;
}
}
/**
* Returns octet count for an u32_t.
*
* @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
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
void
snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
{
if (value < 0x80UL) {
*octets_needed = 1;
} else if (value < 0x8000UL) {
*octets_needed = 2;
} else if (value < 0x800000UL) {
*octets_needed = 3;
} else if (value < 0x80000000UL) {
*octets_needed = 4;
} else {
*octets_needed = 5;
}
}
/**
* Returns octet count for an u64_t.
*
* @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
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
void
snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed)
{
/* check if high u32 is 0 */
if (*value == 0x00) {
/* only low u32 is important */
value++;
snmp_asn1_enc_u32t_cnt(*value, octets_needed);
} else {
/* low u32 does not matter for length determination */
snmp_asn1_enc_u32t_cnt(*value, octets_needed);
*octets_needed = *octets_needed + 4; /* add the 4 bytes of low u32 */
}
}
/**
* Returns octet count for an s32_t.
*
* @param value value to be encoded
* @param octets_needed points to the return value
*
* @note ASN coded integers are _always_ signed.
*/
void
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) {
*octets_needed = 2;
} else if (value < 0x800000L) {
*octets_needed = 3;
} else {
*octets_needed = 4;
}
}
/**
* Returns octet count for an object identifier.
*
* @param oid points to object identifier array
* @param oid_len object identifier array length
* @param octets_needed points to the return value
*/
void
snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed)
{
u32_t sub_id;
*octets_needed = 0;
if (oid_len > 1) {
/* compressed prefix in one octet */
(*octets_needed)++;
oid_len -= 2;
oid += 2;
}
while (oid_len > 0) {
oid_len--;
sub_id = *oid;
sub_id >>= 7;
(*octets_needed)++;
while (sub_id > 0) {
sub_id >>= 7;
(*octets_needed)++;
}
oid++;
}
}
/**
* Decodes a TLV from a pbuf stream.
*
* @param pbuf_stream points to a pbuf stream
* @param tlv returns decoded TLV
* @return ERR_OK if successful, ERR_VAL if we can't decode
*/
err_t
snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv)
{
u8_t data;
/* decode type first */
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
tlv->type = data;
if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) {
/* extended format is not used by SNMP so we do not accept those values */
return ERR_VAL;
}
tlv->type_len = 1;
/* now, decode length */
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
if (data < 0x80) { /* short form */
tlv->length_len = 1;
tlv->value_len = data;
} else if (data > 0x80) { /* long form */
u8_t length_bytes = data - 0x80;
tlv->length_len = length_bytes + 1; /* this byte + defined number of length bytes following */
tlv->value_len = 0;
while (length_bytes > 0) {
/* we only support up to u16.maxvalue-1 (2 bytes) but have to accept leading zero bytes */
if (tlv->value_len > 0xFF) {
return ERR_VAL;
}
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;
}
length_bytes--;
}
} else { /* data == 0x80 indefinite length form */
/* (not allowed for SNMP; RFC 1157, 3.2.2) */
return ERR_VAL;
}
return ERR_OK;
}
/**
* Decodes positive integer (counter, gauge, timeticks) into u32_t.
*
* @param pbuf_stream points to a pbuf stream
* @param len length of the coded integer field
* @param value return host order integer
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
err_t
snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
{
u8_t data;
if ((len > 0) && (len <= 5)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
/* expecting sign bit to be zero, only unsigned please! */
if (((len == 5) && (data == 0x00)) || ((len < 5) && ((data & 0x80) == 0))) {
*value = data;
len--;
while (len > 0) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
*value <<= 8;
*value |= data;
}
return ERR_OK;
}
}
return ERR_VAL;
}
/**
* Decodes large positive integer (counter64) into 2x u32_t.
*
* @param pbuf_stream points to a pbuf stream
* @param len length of the coded integer field
* @param value return host order integer
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
err_t
snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
{
u8_t data;
if (len <= 4) {
/* high u32 is 0 */
*value = 0;
/* directly skip to low u32 */
value++;
}
if ((len > 0) && (len <= 9)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
/* expecting sign bit to be zero, only unsigned please! */
if (((len == 9) && (data == 0x00)) || ((len < 9) && ((data & 0x80) == 0))) {
*value = data;
len--;
while (len > 0) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
if (len == 4) {
/* skip to low u32 */
value++;
*value = 0;
} else {
*value <<= 8;
}
*value |= data;
len--;
}
return ERR_OK;
}
}
return ERR_VAL;
}
/**
* Decodes integer into s32_t.
*
* @param pbuf_stream points to a pbuf stream
* @param len length of the coded integer field
* @param value return host order integer
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*
* @note ASN coded integers are _always_ signed!
*/
err_t
snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value)
{
#if BYTE_ORDER == LITTLE_ENDIAN
u8_t *lsb_ptr = (u8_t*)value;
#endif
#if BYTE_ORDER == BIG_ENDIAN
u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;
#endif
u8_t sign;
u8_t data;
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;
sign = 1;
*lsb_ptr &= data;
} else {
/* positive, start from 0 */
*value = 0;
sign = 0;
*lsb_ptr |= data;
}
/* OR/AND octets with value */
while (len > 0) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
#if BYTE_ORDER == LITTLE_ENDIAN
*value <<= 8;
#endif
#if BYTE_ORDER == BIG_ENDIAN
*value >>= 8;
#endif
if (sign) {
*lsb_ptr |= 255;
*lsb_ptr &= data;
} else {
*lsb_ptr |= data;
}
}
return ERR_OK;
}
return ERR_VAL;
}
/**
* Decodes object identifier from incoming message into array of u32_t.
*
* @param pbuf_stream points to a pbuf stream
* @param len length of the coded object identifier
* @param oid return decoded object identifier
* @param oid_len return decoded object identifier length
* @param oid_max_len size of oid buffer
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*/
err_t
snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len)
{
u32_t *oid_ptr;
u8_t data;
*oid_len = 0;
oid_ptr = oid;
if (len > 0) {
if (oid_max_len < 2) {
return ERR_MEM;
}
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
/* first compressed octet */
if (data == 0x2B) {
/* (most) common case 1.3 (iso.org) */
*oid_ptr = 1;
oid_ptr++;
*oid_ptr = 3;
oid_ptr++;
} else if (data < 40) {
*oid_ptr = 0;
oid_ptr++;
*oid_ptr = data;
oid_ptr++;
} else if (data < 80) {
*oid_ptr = 1;
oid_ptr++;
*oid_ptr = data - 40;
oid_ptr++;
} else {
*oid_ptr = 2;
oid_ptr++;
*oid_ptr = data - 80;
oid_ptr++;
}
*oid_len = 2;
} else {
/* accepting zero length identifiers e.g. for getnext operation. uncommon but valid */
return ERR_OK;
}
while ((len > 0) && (*oid_len < oid_max_len)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
if ((data & 0x80) == 0x00) {
/* sub-identifier uses single octet */
*oid_ptr = data;
} else {
/* sub-identifier uses multiple octets */
u32_t sub_id = (data & ~0x80);
while ((len > 0) && ((data & 0x80) != 0)) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
len--;
sub_id = (sub_id << 7) + (data & ~0x80);
}
if ((data & 0x80) != 0) {
/* "more bytes following" bit still set at end of len */
return ERR_VAL;
}
*oid_ptr = sub_id;
}
oid_ptr++;
(*oid_len)++;
}
if (len > 0) {
/* OID to long to fit in our buffer */
return ERR_MEM;
}
return ERR_OK;
}
/**
* Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
* from incoming message into array.
*
* @param pbuf_stream points to a pbuf stream
* @param len length of the coded raw data (zero is valid, e.g. empty string!)
* @param buf return raw bytes
* @param buf_len returns length of the raw return value
* @param buf_max_len buffer size
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
*/
err_t
snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len)
{
if (len > buf_max_len) {
/* not enough dst space */
return ERR_MEM;
}
*buf_len = len;
while (len > 0) {
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, buf));
buf++;
len--;
}
return ERR_OK;
}
#endif /* LWIP_SNMP */

View File

@@ -0,0 +1,108 @@
/**
* @file
* Abstract Syntax Notation One (ISO 8824, 8825) codec.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* Copyright (c) 2016 Elias Oenal.
* 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: Christiaan Simons <christiaan.simons@axon.tv>
* Martin Hentschel <info@cl-soft.de>
* Elias Oenal <lwip@eliasoenal.com>
*/
#ifndef LWIP_HDR_APPS_SNMP_ASN1_H
#define LWIP_HDR_APPS_SNMP_ASN1_H
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP
#include "lwip/err.h"
#include "lwip/apps/snmp_core.h"
#include "snmp_pbuf_stream.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SNMP_ASN1_TLV_INDEFINITE_LENGTH 0x80
#define SNMP_ASN1_CLASS_MASK 0xC0
#define SNMP_ASN1_CONTENTTYPE_MASK 0x20
#define SNMP_ASN1_DATATYPE_MASK 0x1F
#define SNMP_ASN1_DATATYPE_EXTENDED 0x1F /* DataType indicating that datatype is encoded in following bytes */
/* context specific (SNMP) tags (from SNMP spec. RFC1157) */
#define SNMP_ASN1_CONTEXT_PDU_GET_REQ 0
#define SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ 1
#define SNMP_ASN1_CONTEXT_PDU_GET_RESP 2
#define SNMP_ASN1_CONTEXT_PDU_SET_REQ 3
#define SNMP_ASN1_CONTEXT_PDU_TRAP 4
#define SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ 5
#define SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_OBJECT 0
#define SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW 2
struct snmp_asn1_tlv
{
u8_t type; /* only U8 because extended types are not specified by SNMP */
u8_t type_len; /* encoded length of 'type' field (normally 1) */
u8_t length_len; /* indicates how many bytes are required to encode the 'value_len' field */
u16_t value_len; /* encoded length of the value */
};
#define SNMP_ASN1_TLV_HDR_LENGTH(tlv) ((tlv).type_len + (tlv).length_len)
#define SNMP_ASN1_TLV_LENGTH(tlv) ((tlv).type_len + (tlv).length_len + (tlv).value_len)
#define SNMP_ASN1_SET_TLV_PARAMS(tlv, type_, length_len_, value_len_) do { (tlv).type = (type_); (tlv).type_len = 0; (tlv).length_len = (length_len_); (tlv).value_len = (value_len_); } while (0);
err_t snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv);
err_t snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value);
err_t snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value);
err_t snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value);
err_t snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len);
err_t snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len);
err_t snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv);
void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed);
void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed);
void snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed);
void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);
void snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed);
err_t snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len);
err_t snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value);
err_t snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value);
err_t snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value);
err_t snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_SNMP */
#endif /* LWIP_HDR_APPS_SNMP_ASN1_H */

1349
ext/lwip/src/apps/snmp/snmp_core.c Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
#ifndef LWIP_HDR_APPS_SNMP_CORE_PRIV_H
#define LWIP_HDR_APPS_SNMP_CORE_PRIV_H
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_core.h"
#include "snmp_asn1.h"
#ifdef __cplusplus
extern "C" {
#endif
/* (outdated) SNMPv1 error codes
* shall not be used by MIBS anymore, nevertheless required from core for properly answering a v1 request
*/
#define SNMP_ERR_NOSUCHNAME 2
#define SNMP_ERR_BADVALUE 3
#define SNMP_ERR_READONLY 4
/* error codes which are internal and shall not be used by MIBS
* shall not be used by MIBS anymore, nevertheless required from core for properly answering a v1 request
*/
#define SNMP_ERR_TOOBIG 1
#define SNMP_ERR_AUTHORIZATIONERROR 16
#define SNMP_ERR_NOSUCHOBJECT SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_OBJECT
#define SNMP_ERR_ENDOFMIBVIEW SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW
const struct snmp_node* snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, u8_t* oid_instance_len);
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);
typedef u8_t (*snmp_validate_node_instance_method)(struct snmp_node_instance*, void*);
u8_t snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node_instance* node_instance);
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);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_SNMP */
#endif /* LWIP_HDR_APPS_SNMP_CORE_PRIV_H */

View File

@@ -0,0 +1,116 @@
/**
* @file
* Management Information Base II (RFC1213) objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
/**
* @defgroup snmp_mib2 MIB2
* @ingroup snmp
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP && SNMP_LWIP_MIB2 /* don't build if not configured for use in lwipopts.h */
#if !LWIP_STATS
#error LWIP_SNMP MIB2 needs LWIP_STATS (for MIB2)
#endif
#if !MIB2_STATS
#error LWIP_SNMP MIB2 needs MIB2_STATS (for MIB2)
#endif
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_scalar.h"
#if SNMP_USE_NETCONN
#include "lwip/tcpip.h"
#include "lwip/priv/tcpip_priv.h"
void
snmp_mib2_lwip_synchronizer(snmp_threadsync_called_fn fn, void* arg)
{
#if LWIP_TCPIP_CORE_LOCKING
LOCK_TCPIP_CORE();
fn(arg);
UNLOCK_TCPIP_CORE();
#else
tcpip_callback(fn, arg);
#endif
}
struct snmp_threadsync_instance snmp_mib2_lwip_locks;
#endif
/* dot3 and EtherLike MIB not planned. (transmission .1.3.6.1.2.1.10) */
/* historical (some say hysterical). (cmot .1.3.6.1.2.1.9) */
/* lwIP has no EGP, thus may not implement it. (egp .1.3.6.1.2.1.8) */
/* --- mib-2 .1.3.6.1.2.1 ----------------------------------------------------- */
extern const struct snmp_scalar_array_node snmp_mib2_snmp_root;
extern const struct snmp_tree_node snmp_mib2_udp_root;
extern const struct snmp_tree_node snmp_mib2_tcp_root;
extern const struct snmp_scalar_array_node snmp_mib2_icmp_root;
extern const struct snmp_tree_node snmp_mib2_interface_root;
extern const struct snmp_scalar_array_node snmp_mib2_system_node;
extern const struct snmp_tree_node snmp_mib2_at_root;
extern const struct snmp_tree_node snmp_mib2_ip_root;
static const struct snmp_node* const mib2_nodes[] = {
&snmp_mib2_system_node.node.node,
&snmp_mib2_interface_root.node,
#if LWIP_ARP && LWIP_IPV4
&snmp_mib2_at_root.node,
#endif /* LWIP_ARP && LWIP_IPV4 */
#if LWIP_IPV4
&snmp_mib2_ip_root.node,
#endif /* LWIP_IPV4 */
#if LWIP_ICMP
&snmp_mib2_icmp_root.node.node,
#endif /* LWIP_ICMP */
#if LWIP_TCP
&snmp_mib2_tcp_root.node,
#endif /* LWIP_TCP */
#if LWIP_UDP
&snmp_mib2_udp_root.node,
#endif /* LWIP_UDP */
&snmp_mib2_snmp_root.node.node
};
static const struct snmp_tree_node mib2_root = SNMP_CREATE_TREE_NODE(1, mib2_nodes);
static const u32_t mib2_base_oid_arr[] = { 1,3,6,1,2,1 };
const struct snmp_mib mib2 = SNMP_MIB_CREATE(mib2_base_oid_arr, &mib2_root.node);
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */

View File

@@ -0,0 +1,182 @@
/**
* @file
* Management Information Base II (RFC1213) ICMP objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_table.h"
#include "lwip/apps/snmp_scalar.h"
#include "lwip/icmp.h"
#include "lwip/stats.h"
#if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_ICMP
#if SNMP_USE_NETCONN
#define SYNC_NODE_NAME(node_name) node_name ## _synced
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
#else
#define SYNC_NODE_NAME(node_name) node_name
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
#endif
/* --- icmp .1.3.6.1.2.1.5 ----------------------------------------------------- */
static s16_t
icmp_get_value(const struct snmp_scalar_array_node_def *node, void *value)
{
u32_t *uint_ptr = (u32_t*)value;
switch (node->oid) {
case 1: /* icmpInMsgs */
*uint_ptr = STATS_GET(mib2.icmpinmsgs);
return sizeof(*uint_ptr);
case 2: /* icmpInErrors */
*uint_ptr = STATS_GET(mib2.icmpinerrors);
return sizeof(*uint_ptr);
case 3: /* icmpInDestUnreachs */
*uint_ptr = STATS_GET(mib2.icmpindestunreachs);
return sizeof(*uint_ptr);
case 4: /* icmpInTimeExcds */
*uint_ptr = STATS_GET(mib2.icmpintimeexcds);
return sizeof(*uint_ptr);
case 5: /* icmpInParmProbs */
*uint_ptr = STATS_GET(mib2.icmpinparmprobs);
return sizeof(*uint_ptr);
case 6: /* icmpInSrcQuenchs */
*uint_ptr = STATS_GET(mib2.icmpinsrcquenchs);
return sizeof(*uint_ptr);
case 7: /* icmpInRedirects */
*uint_ptr = STATS_GET(mib2.icmpinredirects);
return sizeof(*uint_ptr);
case 8: /* icmpInEchos */
*uint_ptr = STATS_GET(mib2.icmpinechos);
return sizeof(*uint_ptr);
case 9: /* icmpInEchoReps */
*uint_ptr = STATS_GET(mib2.icmpinechoreps);
return sizeof(*uint_ptr);
case 10: /* icmpInTimestamps */
*uint_ptr = STATS_GET(mib2.icmpintimestamps);
return sizeof(*uint_ptr);
case 11: /* icmpInTimestampReps */
*uint_ptr = STATS_GET(mib2.icmpintimestampreps);
return sizeof(*uint_ptr);
case 12: /* icmpInAddrMasks */
*uint_ptr = STATS_GET(mib2.icmpinaddrmasks);
return sizeof(*uint_ptr);
case 13: /* icmpInAddrMaskReps */
*uint_ptr = STATS_GET(mib2.icmpinaddrmaskreps);
return sizeof(*uint_ptr);
case 14: /* icmpOutMsgs */
*uint_ptr = STATS_GET(mib2.icmpoutmsgs);
return sizeof(*uint_ptr);
case 15: /* icmpOutErrors */
*uint_ptr = STATS_GET(mib2.icmpouterrors);
return sizeof(*uint_ptr);
case 16: /* icmpOutDestUnreachs */
*uint_ptr = STATS_GET(mib2.icmpoutdestunreachs);
return sizeof(*uint_ptr);
case 17: /* icmpOutTimeExcds */
*uint_ptr = STATS_GET(mib2.icmpouttimeexcds);
return sizeof(*uint_ptr);
case 18: /* icmpOutParmProbs: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
case 19: /* icmpOutSrcQuenchs: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
case 20: /* icmpOutRedirects: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
case 21: /* icmpOutEchos */
*uint_ptr = STATS_GET(mib2.icmpoutechos);
return sizeof(*uint_ptr);
case 22: /* icmpOutEchoReps */
*uint_ptr = STATS_GET(mib2.icmpoutechoreps);
return sizeof(*uint_ptr);
case 23: /* icmpOutTimestamps: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
case 24: /* icmpOutTimestampReps: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
case 25: /* icmpOutAddrMasks: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
case 26: /* icmpOutAddrMaskReps: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_value(): unknown id: %"S32_F"\n", node->oid));
break;
}
return 0;
}
static const struct snmp_scalar_array_node_def icmp_nodes[] = {
{ 1, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 2, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 3, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 4, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 5, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 6, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 7, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 8, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{ 9, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{21, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{22, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{23, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{24, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{25, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY},
{26, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}
};
const struct snmp_scalar_array_node snmp_mib2_icmp_root = SNMP_SCALAR_CREATE_ARRAY_NODE(5, icmp_nodes, icmp_get_value, NULL, NULL);
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_ICMP */

View File

@@ -0,0 +1,375 @@
/**
* @file
* Management Information Base II (RFC1213) INTERFACES objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_table.h"
#include "lwip/apps/snmp_scalar.h"
#include "lwip/netif.h"
#include "lwip/stats.h"
#include <string.h>
#if LWIP_SNMP && SNMP_LWIP_MIB2
#if SNMP_USE_NETCONN
#define SYNC_NODE_NAME(node_name) node_name ## _synced
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
#else
#define SYNC_NODE_NAME(node_name) node_name
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
#endif
/* --- interfaces .1.3.6.1.2.1.2 ----------------------------------------------------- */
static s16_t
interfaces_get_value(struct snmp_node_instance* instance, void* value)
{
if (instance->node->oid == 1) {
s32_t *sint_ptr = (s32_t*)value;
s32_t num_netifs = 0;
struct netif *netif = netif_list;
while (netif != NULL) {
num_netifs++;
netif = netif->next;
}
*sint_ptr = num_netifs;
return sizeof(*sint_ptr);
}
return 0;
}
/* list of allowed value ranges for incoming OID */
static const struct snmp_oid_range interfaces_Table_oid_ranges[] = {
{ 1, 0xff } /* netif->num is u8_t */
};
static const u8_t iftable_ifOutQLen = 0;
static const u8_t iftable_ifOperStatus_up = 1;
static const u8_t iftable_ifOperStatus_down = 2;
static const u8_t iftable_ifAdminStatus_up = 1;
static const u8_t iftable_ifAdminStatus_lowerLayerDown = 7;
static const u8_t iftable_ifAdminStatus_down = 2;
static snmp_err_t
interfaces_Table_get_cell_instance(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance)
{
u32_t ifIndex;
struct netif *netif;
LWIP_UNUSED_ARG(column);
/* check if incoming OID length and if values are in plausible range */
if (!snmp_oid_in_range(row_oid, row_oid_len, interfaces_Table_oid_ranges, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges))) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* get netif index from incoming OID */
ifIndex = row_oid[0];
/* find netif with index */
netif = netif_list;
while (netif != NULL) {
if (netif_to_num(netif) == ifIndex) {
/* store netif pointer for subsequent operations (get/test/set) */
cell_instance->reference.ptr = netif;
return SNMP_ERR_NOERROR;
}
netif = netif->next;
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
interfaces_Table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance)
{
struct netif *netif;
struct snmp_next_oid_state state;
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));
/* iterate over all possible OIDs to find the next one */
netif = netif_list;
while (netif != NULL) {
u32_t test_oid[LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)];
test_oid[0] = netif_to_num(netif);
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges), netif);
netif = netif->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);
/* store netif pointer for subsequent operations (get/test/set) */
cell_instance->reference.ptr = /* (struct netif*) */state.reference;
return SNMP_ERR_NOERROR;
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static s16_t
interfaces_Table_get_value(struct snmp_node_instance* instance, void* value)
{
struct netif *netif = (struct netif*)instance->reference.ptr;
u32_t* value_u32 = (u32_t*)value;
s32_t* value_s32 = (s32_t*)value;
u16_t value_len;
switch (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id))
{
case 1: /* ifIndex */
*value_s32 = netif_to_num(netif);
value_len = sizeof(*value_s32);
break;
case 2: /* ifDescr */
value_len = sizeof(netif->name);
MEMCPY(value, netif->name, value_len);
break;
case 3: /* ifType */
*value_s32 = netif->link_type;
value_len = sizeof(*value_s32);
break;
case 4: /* ifMtu */
*value_s32 = netif->mtu;
value_len = sizeof(*value_s32);
break;
case 5: /* ifSpeed */
*value_u32 = netif->link_speed;
value_len = sizeof(*value_u32);
break;
case 6: /* ifPhysAddress */
value_len = sizeof(netif->hwaddr);
MEMCPY(value, &netif->hwaddr, value_len);
break;
case 7: /* ifAdminStatus */
if (netif_is_up(netif)) {
*value_s32 = iftable_ifOperStatus_up;
} else {
*value_s32 = iftable_ifOperStatus_down;
}
value_len = sizeof(*value_s32);
break;
case 8: /* ifOperStatus */
if (netif_is_up(netif)) {
if (netif_is_link_up(netif)) {
*value_s32 = iftable_ifAdminStatus_up;
} else {
*value_s32 = iftable_ifAdminStatus_lowerLayerDown;
}
} else {
*value_s32 = iftable_ifAdminStatus_down;
}
value_len = sizeof(*value_s32);
break;
case 9: /* ifLastChange */
*value_u32 = netif->ts;
value_len = sizeof(*value_u32);
break;
case 10: /* ifInOctets */
*value_u32 = netif->mib2_counters.ifinoctets;
value_len = sizeof(*value_u32);
break;
case 11: /* ifInUcastPkts */
*value_u32 = netif->mib2_counters.ifinucastpkts;
value_len = sizeof(*value_u32);
break;
case 12: /* ifInNUcastPkts */
*value_u32 = netif->mib2_counters.ifinnucastpkts;
value_len = sizeof(*value_u32);
break;
case 13: /* ifInDiscards */
*value_u32 = netif->mib2_counters.ifindiscards;
value_len = sizeof(*value_u32);
break;
case 14: /* ifInErrors */
*value_u32 = netif->mib2_counters.ifinerrors;
value_len = sizeof(*value_u32);
break;
case 15: /* ifInUnkownProtos */
*value_u32 = netif->mib2_counters.ifinunknownprotos;
value_len = sizeof(*value_u32);
break;
case 16: /* ifOutOctets */
*value_u32 = netif->mib2_counters.ifoutoctets;
value_len = sizeof(*value_u32);
break;
case 17: /* ifOutUcastPkts */
*value_u32 = netif->mib2_counters.ifoutucastpkts;
value_len = sizeof(*value_u32);
break;
case 18: /* ifOutNUcastPkts */
*value_u32 = netif->mib2_counters.ifoutnucastpkts;
value_len = sizeof(*value_u32);
break;
case 19: /* ifOutDiscarts */
*value_u32 = netif->mib2_counters.ifoutdiscards;
value_len = sizeof(*value_u32);
break;
case 20: /* ifOutErrors */
*value_u32 = netif->mib2_counters.ifouterrors;
value_len = sizeof(*value_u32);
break;
case 21: /* ifOutQLen */
*value_u32 = iftable_ifOutQLen;
value_len = sizeof(*value_u32);
break;
/** @note returning zeroDotZero (0.0) no media specific MIB support */
case 22: /* ifSpecific */
value_len = snmp_zero_dot_zero.len * sizeof(u32_t);
MEMCPY(value, snmp_zero_dot_zero.id, value_len);
break;
default:
return 0;
}
return value_len;
}
#if !SNMP_SAFE_REQUESTS
static snmp_err_t
interfaces_Table_set_test(struct snmp_node_instance* instance, u16_t len, void *value)
{
s32_t *sint_ptr = (s32_t*)value;
/* stack should never call this method for another column,
because all other columns are set to readonly */
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) {
return SNMP_ERR_NOERROR;
}
return SNMP_ERR_WRONGVALUE;
}
static snmp_err_t
interfaces_Table_set_value(struct snmp_node_instance* instance, u16_t len, void *value)
{
struct netif *netif = (struct netif*)instance->reference.ptr;
s32_t *sint_ptr = (s32_t*)value;
/* stack should never call this method for another column,
because all other columns are set to readonly */
LWIP_ASSERT("Invalid column", (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id) == 7));
LWIP_UNUSED_ARG(len);
if (*sint_ptr == 1) {
netif_set_up(netif);
} else if (*sint_ptr == 2) {
netif_set_down(netif);
}
return SNMP_ERR_NOERROR;
}
#endif /* SNMP_SAFE_REQUESTS */
static const struct snmp_scalar_node interfaces_Number = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_INTEGER, interfaces_get_value);
static const struct snmp_table_col_def interfaces_Table_columns[] = {
{ 1, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifIndex */
{ 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifDescr */
{ 3, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifType */
{ 4, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifMtu */
{ 5, SNMP_ASN1_TYPE_GAUGE, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifSpeed */
{ 6, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifPhysAddress */
#if !SNMP_SAFE_REQUESTS
{ 7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE }, /* ifAdminStatus */
#else
{ 7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifAdminStatus */
#endif
{ 8, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOperStatus */
{ 9, SNMP_ASN1_TYPE_TIMETICKS, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifLastChange */
{ 10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInOctets */
{ 11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInUcastPkts */
{ 12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInNUcastPkts */
{ 13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInDiscarts */
{ 14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInErrors */
{ 15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInUnkownProtos */
{ 16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutOctets */
{ 17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutUcastPkts */
{ 18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutNUcastPkts */
{ 19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutDiscarts */
{ 20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutErrors */
{ 21, SNMP_ASN1_TYPE_GAUGE, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutQLen */
{ 22, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_NODE_INSTANCE_READ_ONLY } /* ifSpecific */
};
#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,
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,
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 */
CREATE_LWIP_SYNC_NODE(1, interfaces_Number)
CREATE_LWIP_SYNC_NODE(2, interfaces_Table)
static const struct snmp_node* const interface_nodes[] = {
&SYNC_NODE_NAME(interfaces_Number).node.node,
&SYNC_NODE_NAME(interfaces_Table).node.node
};
const struct snmp_tree_node snmp_mib2_interface_root = SNMP_CREATE_TREE_NODE(2, interface_nodes);
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */

View File

@@ -0,0 +1,743 @@
/**
* @file
* Management Information Base II (RFC1213) IP objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_table.h"
#include "lwip/apps/snmp_scalar.h"
#include "lwip/stats.h"
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/etharp.h"
#if LWIP_SNMP && SNMP_LWIP_MIB2
#if SNMP_USE_NETCONN
#define SYNC_NODE_NAME(node_name) node_name ## _synced
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
#else
#define SYNC_NODE_NAME(node_name) node_name
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
#endif
#if LWIP_IPV4
/* --- ip .1.3.6.1.2.1.4 ----------------------------------------------------- */
static s16_t
ip_get_value(struct snmp_node_instance* instance, void* value)
{
s32_t* sint_ptr = (s32_t*)value;
u32_t* uint_ptr = (u32_t*)value;
switch (instance->node->oid) {
case 1: /* ipForwarding */
#if IP_FORWARD
/* forwarding */
*sint_ptr = 1;
#else
/* not-forwarding */
*sint_ptr = 2;
#endif
return sizeof(*sint_ptr);
case 2: /* ipDefaultTTL */
*sint_ptr = IP_DEFAULT_TTL;
return sizeof(*sint_ptr);
case 3: /* ipInReceives */
*uint_ptr = STATS_GET(mib2.ipinreceives);
return sizeof(*uint_ptr);
case 4: /* ipInHdrErrors */
*uint_ptr = STATS_GET(mib2.ipinhdrerrors);
return sizeof(*uint_ptr);
case 5: /* ipInAddrErrors */
*uint_ptr = STATS_GET(mib2.ipinaddrerrors);
return sizeof(*uint_ptr);
case 6: /* ipForwDatagrams */
*uint_ptr = STATS_GET(mib2.ipforwdatagrams);
return sizeof(*uint_ptr);
case 7: /* ipInUnknownProtos */
*uint_ptr = STATS_GET(mib2.ipinunknownprotos);
return sizeof(*uint_ptr);
case 8: /* ipInDiscards */
*uint_ptr = STATS_GET(mib2.ipindiscards);
return sizeof(*uint_ptr);
case 9: /* ipInDelivers */
*uint_ptr = STATS_GET(mib2.ipindelivers);
return sizeof(*uint_ptr);
case 10: /* ipOutRequests */
*uint_ptr = STATS_GET(mib2.ipoutrequests);
return sizeof(*uint_ptr);
case 11: /* ipOutDiscards */
*uint_ptr = STATS_GET(mib2.ipoutdiscards);
return sizeof(*uint_ptr);
case 12: /* ipOutNoRoutes */
*uint_ptr = STATS_GET(mib2.ipoutnoroutes);
return sizeof(*uint_ptr);
case 13: /* ipReasmTimeout */
#if IP_REASSEMBLY
*sint_ptr = IP_REASS_MAXAGE;
#else
*sint_ptr = 0;
#endif
return sizeof(*sint_ptr);
case 14: /* ipReasmReqds */
*uint_ptr = STATS_GET(mib2.ipreasmreqds);
return sizeof(*uint_ptr);
case 15: /* ipReasmOKs */
*uint_ptr = STATS_GET(mib2.ipreasmoks);
return sizeof(*uint_ptr);
case 16: /* ipReasmFails */
*uint_ptr = STATS_GET(mib2.ipreasmfails);
return sizeof(*uint_ptr);
case 17: /* ipFragOKs */
*uint_ptr = STATS_GET(mib2.ipfragoks);
return sizeof(*uint_ptr);
case 18: /* ipFragFails */
*uint_ptr = STATS_GET(mib2.ipfragfails);
return sizeof(*uint_ptr);
case 19: /* ipFragCreates */
*uint_ptr = STATS_GET(mib2.ipfragcreates);
return sizeof(*uint_ptr);
case 23: /* ipRoutingDiscards: not supported -> always 0 */
*uint_ptr = 0;
return sizeof(*uint_ptr);
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_value(): unknown id: %"S32_F"\n", instance->node->oid));
break;
}
return 0;
}
/**
* Test ip object value before setting.
*
* @param instance node instance
* @param len return value space (in bytes)
* @param value points to (varbind) space to copy value from.
*
* @note we allow set if the value matches the hardwired value,
* otherwise return badvalue.
*/
static snmp_err_t
ip_set_test(struct snmp_node_instance* instance, u16_t len, void *value)
{
snmp_err_t ret = SNMP_ERR_WRONGVALUE;
s32_t *sint_ptr = (s32_t*)value;
LWIP_UNUSED_ARG(len);
switch (instance->node->oid) {
case 1: /* ipForwarding */
#if IP_FORWARD
/* forwarding */
if (*sint_ptr == 1)
#else
/* not-forwarding */
if (*sint_ptr == 2)
#endif
{
ret = SNMP_ERR_NOERROR;
}
break;
case 2: /* ipDefaultTTL */
if (*sint_ptr == IP_DEFAULT_TTL) {
ret = SNMP_ERR_NOERROR;
}
break;
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_set_test(): unknown id: %"S32_F"\n", instance->node->oid));
break;
}
return ret;
}
static snmp_err_t
ip_set_value(struct snmp_node_instance* instance, u16_t len, void *value)
{
LWIP_UNUSED_ARG(instance);
LWIP_UNUSED_ARG(len);
LWIP_UNUSED_ARG(value);
/* nothing to do here because in set_test we only accept values being the same as our own stored value -> no need to store anything */
return SNMP_ERR_NOERROR;
}
/* --- ipAddrTable --- */
/* list of allowed value ranges for incoming OID */
static const struct snmp_oid_range ip_AddrTable_oid_ranges[] = {
{ 0, 0xff }, /* IP A */
{ 0, 0xff }, /* IP B */
{ 0, 0xff }, /* IP C */
{ 0, 0xff } /* IP D */
};
static snmp_err_t
ip_AddrTable_get_cell_value_core(struct netif *netif, const u32_t* column, union snmp_variant_value* value, u32_t* value_len)
{
LWIP_UNUSED_ARG(value_len);
switch (*column) {
case 1: /* ipAdEntAddr */
value->u32 = netif_ip4_addr(netif)->addr;
break;
case 2: /* ipAdEntIfIndex */
value->u32 = netif_to_num(netif);
break;
case 3: /* ipAdEntNetMask */
value->u32 = netif_ip4_netmask(netif)->addr;
break;
case 4: /* ipAdEntBcastAddr */
/* lwIP oddity, there's no broadcast
address in the netif we can rely on */
value->u32 = IPADDR_BROADCAST & 1;
break;
case 5: /* ipAdEntReasmMaxSize */
#if IP_REASSEMBLY
/* @todo The theoretical maximum is IP_REASS_MAX_PBUFS * size of the pbufs,
* but only if receiving one fragmented packet at a time.
* The current solution is to calculate for 2 simultaneous packets...
*/
value->u32 = (IP_HLEN + ((IP_REASS_MAX_PBUFS/2) *
(PBUF_POOL_BUFSIZE - PBUF_LINK_ENCAPSULATION_HLEN - PBUF_LINK_HLEN - IP_HLEN)));
#else
/** @todo returning MTU would be a bad thing and
returning a wild guess like '576' isn't good either */
value->u32 = 0;
#endif
break;
default:
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
static snmp_err_t
ip_AddrTable_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)
{
ip4_addr_t ip;
struct netif *netif;
/* check if incoming OID length and if values are in plausible range */
if (!snmp_oid_in_range(row_oid, row_oid_len, ip_AddrTable_oid_ranges, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges))) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* get IP from incoming OID */
snmp_oid_to_ip4(&row_oid[0], &ip); /* we know it succeeds because of oid_in_range check above */
/* find netif with requested ip */
netif = netif_list;
while (netif != NULL) {
if (ip4_addr_cmp(&ip, netif_ip4_addr(netif))) {
/* fill in object properties */
return ip_AddrTable_get_cell_value_core(netif, column, value, value_len);
}
netif = netif->next;
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
ip_AddrTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
struct netif *netif;
struct snmp_next_oid_state state;
u32_t result_temp[LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges)];
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges));
/* iterate over all possible OIDs to find the next one */
netif = netif_list;
while (netif != NULL) {
u32_t test_oid[LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges)];
snmp_ip4_to_oid(netif_ip4_addr(netif), &test_oid[0]);
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges), netif);
netif = netif->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);
/* 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;
}
/* --- ipRouteTable --- */
/* list of allowed value ranges for incoming OID */
static const struct snmp_oid_range ip_RouteTable_oid_ranges[] = {
{ 0, 0xff }, /* IP A */
{ 0, 0xff }, /* IP B */
{ 0, 0xff }, /* IP C */
{ 0, 0xff }, /* IP D */
};
static snmp_err_t
ip_RouteTable_get_cell_value_core(struct netif *netif, u8_t default_route, const u32_t* column, union snmp_variant_value* value, u32_t* value_len)
{
switch (*column) {
case 1: /* ipRouteDest */
if (default_route) {
/* default rte has 0.0.0.0 dest */
value->u32 = IP4_ADDR_ANY4->addr;
} else {
/* netifs have netaddress dest */
ip4_addr_t tmp;
ip4_addr_get_network(&tmp, netif_ip4_addr(netif), netif_ip4_netmask(netif));
value->u32 = tmp.addr;
}
break;
case 2: /* ipRouteIfIndex */
value->u32 = netif_to_num(netif);
break;
case 3: /* ipRouteMetric1 */
if (default_route) {
value->s32 = 1; /* default */
} else {
value->s32 = 0; /* normal */
}
break;
case 4: /* ipRouteMetric2 */
case 5: /* ipRouteMetric3 */
case 6: /* ipRouteMetric4 */
value->s32 = -1; /* none */
break;
case 7: /* ipRouteNextHop */
if (default_route) {
/* default rte: gateway */
value->u32 = netif_ip4_gw(netif)->addr;
} else {
/* other rtes: netif ip_addr */
value->u32 = netif_ip4_addr(netif)->addr;
}
break;
case 8: /* ipRouteType */
if (default_route) {
/* default rte is indirect */
value->u32 = 4; /* indirect */
} else {
/* other rtes are direct */
value->u32 = 3; /* direct */
}
break;
case 9: /* ipRouteProto */
/* locally defined routes */
value->u32 = 2; /* local */
break;
case 10: /* ipRouteAge */
/* @todo (sysuptime - timestamp last change) / 100 */
value->u32 = 0;
break;
case 11: /* ipRouteMask */
if (default_route) {
/* default rte use 0.0.0.0 mask */
value->u32 = IP4_ADDR_ANY4->addr;
} else {
/* other rtes use netmask */
value->u32 = netif_ip4_netmask(netif)->addr;
}
break;
case 12: /* ipRouteMetric5 */
value->s32 = -1; /* none */
break;
case 13: /* ipRouteInfo */
value->const_ptr = snmp_zero_dot_zero.id;
*value_len = snmp_zero_dot_zero.len * sizeof(u32_t);
break;
default:
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
static snmp_err_t
ip_RouteTable_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)
{
ip4_addr_t test_ip;
struct netif *netif;
/* check if incoming OID length and if values are in plausible range */
if (!snmp_oid_in_range(row_oid, row_oid_len, ip_RouteTable_oid_ranges, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges))) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* get IP and port from incoming OID */
snmp_oid_to_ip4(&row_oid[0], &test_ip); /* we know it succeeds because of oid_in_range check above */
/* default route is on default netif */
if (ip4_addr_isany_val(test_ip) && (netif_default != NULL)) {
/* fill in object properties */
return ip_RouteTable_get_cell_value_core(netif_default, 1, column, value, value_len);
}
/* find netif with requested route */
netif = netif_list;
while (netif != NULL) {
ip4_addr_t dst;
ip4_addr_get_network(&dst, netif_ip4_addr(netif), netif_ip4_netmask(netif));
if (ip4_addr_cmp(&dst, &test_ip)) {
/* fill in object properties */
return ip_RouteTable_get_cell_value_core(netif, 0, column, value, value_len);
}
netif = netif->next;
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
ip_RouteTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
struct netif *netif;
struct snmp_next_oid_state state;
u32_t result_temp[LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges)];
u32_t test_oid[LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges)];
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges));
/* check default route */
if (netif_default != NULL) {
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);
}
/* iterate over all possible OIDs to find the next one */
netif = netif_list;
while (netif != NULL) {
ip4_addr_t dst;
ip4_addr_get_network(&dst, netif_ip4_addr(netif), netif_ip4_netmask(netif));
/* check generated OID: is it a candidate for the next one? */
if (!ip4_addr_isany_val(dst)) {
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;
}
/* did we find a next one? */
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
ip4_addr_t dst;
snmp_oid_to_ip4(&result_temp[0], &dst);
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
/* fill in object properties */
return ip_RouteTable_get_cell_value_core((struct netif*)state.reference, ip4_addr_isany_val(dst), column, value, value_len);
} else {
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
}
#if LWIP_ARP && LWIP_IPV4
/* --- ipNetToMediaTable --- */
/* list of allowed value ranges for incoming OID */
static const struct snmp_oid_range ip_NetToMediaTable_oid_ranges[] = {
{ 1, 0xff }, /* IfIndex */
{ 0, 0xff }, /* IP A */
{ 0, 0xff }, /* IP B */
{ 0, 0xff }, /* IP C */
{ 0, 0xff } /* IP D */
};
static snmp_err_t
ip_NetToMediaTable_get_cell_value_core(u8_t arp_table_index, const u32_t* column, union snmp_variant_value* value, u32_t* value_len)
{
ip4_addr_t *ip;
struct netif *netif;
struct eth_addr *ethaddr;
etharp_get_entry(arp_table_index, &ip, &netif, &ethaddr);
/* value */
switch (*column) {
case 1: /* atIfIndex / ipNetToMediaIfIndex */
value->u32 = netif_to_num(netif);
break;
case 2: /* atPhysAddress / ipNetToMediaPhysAddress */
value->ptr = ethaddr;
*value_len = sizeof(*ethaddr);
break;
case 3: /* atNetAddress / ipNetToMediaNetAddress */
value->u32 = ip->addr;
break;
case 4: /* ipNetToMediaType */
value->u32 = 3; /* dynamic*/
break;
default:
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
static snmp_err_t
ip_NetToMediaTable_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)
{
ip4_addr_t ip_in;
u8_t netif_index;
u8_t i;
/* check if incoming OID length and if values are in plausible range */
if (!snmp_oid_in_range(row_oid, row_oid_len, ip_NetToMediaTable_oid_ranges, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges))) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* get IP from incoming OID */
netif_index = (u8_t)row_oid[0];
snmp_oid_to_ip4(&row_oid[1], &ip_in); /* we know it succeeds because of oid_in_range check above */
/* find requested entry */
for (i=0; i<ARP_TABLE_SIZE; i++) {
ip4_addr_t *ip;
struct netif *netif;
struct eth_addr *ethaddr;
if (etharp_get_entry(i, &ip, &netif, &ethaddr)) {
if ((netif_index == netif_to_num(netif)) && ip4_addr_cmp(&ip_in, ip)) {
/* fill in object properties */
return ip_NetToMediaTable_get_cell_value_core(i, column, value, value_len);
}
}
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
ip_NetToMediaTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
u8_t i;
struct snmp_next_oid_state state;
u32_t result_temp[LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges)];
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges));
/* iterate over all possible OIDs to find the next one */
for (i=0; i<ARP_TABLE_SIZE; i++) {
ip4_addr_t *ip;
struct netif *netif;
struct eth_addr *ethaddr;
if (etharp_get_entry(i, &ip, &netif, &ethaddr)) {
u32_t test_oid[LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges)];
test_oid[0] = netif_to_num(netif);
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), LWIP_PTR_NUMERIC_CAST(void*, i));
}
}
/* 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);
/* fill in object properties */
return ip_NetToMediaTable_get_cell_value_core(LWIP_PTR_NUMERIC_CAST(u8_t, state.reference), column, value, value_len);
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
#endif /* LWIP_ARP && LWIP_IPV4 */
static const struct snmp_scalar_node ip_Forwarding = SNMP_SCALAR_CREATE_NODE(1, SNMP_NODE_INSTANCE_READ_WRITE, SNMP_ASN1_TYPE_INTEGER, ip_get_value, ip_set_test, ip_set_value);
static const struct snmp_scalar_node ip_DefaultTTL = SNMP_SCALAR_CREATE_NODE(2, SNMP_NODE_INSTANCE_READ_WRITE, SNMP_ASN1_TYPE_INTEGER, ip_get_value, ip_set_test, ip_set_value);
static const struct snmp_scalar_node ip_InReceives = SNMP_SCALAR_CREATE_NODE_READONLY(3, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_InHdrErrors = SNMP_SCALAR_CREATE_NODE_READONLY(4, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_InAddrErrors = SNMP_SCALAR_CREATE_NODE_READONLY(5, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_ForwDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(6, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_InUnknownProtos = SNMP_SCALAR_CREATE_NODE_READONLY(7, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_InDiscards = SNMP_SCALAR_CREATE_NODE_READONLY(8, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_InDelivers = SNMP_SCALAR_CREATE_NODE_READONLY(9, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_OutRequests = SNMP_SCALAR_CREATE_NODE_READONLY(10, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_OutDiscards = SNMP_SCALAR_CREATE_NODE_READONLY(11, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_OutNoRoutes = SNMP_SCALAR_CREATE_NODE_READONLY(12, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_ReasmTimeout = SNMP_SCALAR_CREATE_NODE_READONLY(13, SNMP_ASN1_TYPE_INTEGER, ip_get_value);
static const struct snmp_scalar_node ip_ReasmReqds = SNMP_SCALAR_CREATE_NODE_READONLY(14, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_ReasmOKs = SNMP_SCALAR_CREATE_NODE_READONLY(15, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_ReasmFails = SNMP_SCALAR_CREATE_NODE_READONLY(16, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_FragOKs = SNMP_SCALAR_CREATE_NODE_READONLY(17, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_FragFails = SNMP_SCALAR_CREATE_NODE_READONLY(18, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_FragCreates = SNMP_SCALAR_CREATE_NODE_READONLY(19, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_scalar_node ip_RoutingDiscards = SNMP_SCALAR_CREATE_NODE_READONLY(23, SNMP_ASN1_TYPE_COUNTER, ip_get_value);
static const struct snmp_table_simple_col_def ip_AddrTable_columns[] = {
{ 1, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipAdEntAddr */
{ 2, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipAdEntIfIndex */
{ 3, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipAdEntNetMask */
{ 4, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipAdEntBcastAddr */
{ 5, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* ipAdEntReasmMaxSize */
};
static const struct snmp_table_simple_node ip_AddrTable = SNMP_TABLE_CREATE_SIMPLE(20, ip_AddrTable_columns, ip_AddrTable_get_cell_value, ip_AddrTable_get_next_cell_instance_and_value);
static const struct snmp_table_simple_col_def ip_RouteTable_columns[] = {
{ 1, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteDest */
{ 2, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteIfIndex */
{ 3, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_S32 }, /* ipRouteMetric1 */
{ 4, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_S32 }, /* ipRouteMetric2 */
{ 5, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_S32 }, /* ipRouteMetric3 */
{ 6, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_S32 }, /* ipRouteMetric4 */
{ 7, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteNextHop */
{ 8, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteType */
{ 9, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteProto */
{ 10, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteAge */
{ 11, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipRouteMask */
{ 12, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_S32 }, /* ipRouteMetric5 */
{ 13, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_VARIANT_VALUE_TYPE_PTR } /* ipRouteInfo */
};
static const struct snmp_table_simple_node ip_RouteTable = SNMP_TABLE_CREATE_SIMPLE(21, ip_RouteTable_columns, ip_RouteTable_get_cell_value, ip_RouteTable_get_next_cell_instance_and_value);
#endif /* LWIP_IPV4 */
#if LWIP_ARP && LWIP_IPV4
static const struct snmp_table_simple_col_def ip_NetToMediaTable_columns[] = {
{ 1, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipNetToMediaIfIndex */
{ 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_VARIANT_VALUE_TYPE_PTR }, /* ipNetToMediaPhysAddress */
{ 3, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* ipNetToMediaNetAddress */
{ 4, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* ipNetToMediaType */
};
static const struct snmp_table_simple_node ip_NetToMediaTable = SNMP_TABLE_CREATE_SIMPLE(22, ip_NetToMediaTable_columns, ip_NetToMediaTable_get_cell_value, ip_NetToMediaTable_get_next_cell_instance_and_value);
#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 */
CREATE_LWIP_SYNC_NODE( 1, ip_Forwarding)
CREATE_LWIP_SYNC_NODE( 2, ip_DefaultTTL)
CREATE_LWIP_SYNC_NODE( 3, ip_InReceives)
CREATE_LWIP_SYNC_NODE( 4, ip_InHdrErrors)
CREATE_LWIP_SYNC_NODE( 5, ip_InAddrErrors)
CREATE_LWIP_SYNC_NODE( 6, ip_ForwDatagrams)
CREATE_LWIP_SYNC_NODE( 7, ip_InUnknownProtos)
CREATE_LWIP_SYNC_NODE( 8, ip_InDiscards)
CREATE_LWIP_SYNC_NODE( 9, ip_InDelivers)
CREATE_LWIP_SYNC_NODE(10, ip_OutRequests)
CREATE_LWIP_SYNC_NODE(11, ip_OutDiscards)
CREATE_LWIP_SYNC_NODE(12, ip_OutNoRoutes)
CREATE_LWIP_SYNC_NODE(13, ip_ReasmTimeout)
CREATE_LWIP_SYNC_NODE(14, ip_ReasmReqds)
CREATE_LWIP_SYNC_NODE(15, ip_ReasmOKs)
CREATE_LWIP_SYNC_NODE(15, ip_ReasmFails)
CREATE_LWIP_SYNC_NODE(17, ip_FragOKs)
CREATE_LWIP_SYNC_NODE(18, ip_FragFails)
CREATE_LWIP_SYNC_NODE(19, ip_FragCreates)
CREATE_LWIP_SYNC_NODE(20, ip_AddrTable)
CREATE_LWIP_SYNC_NODE(21, ip_RouteTable)
#if LWIP_ARP
CREATE_LWIP_SYNC_NODE(22, ip_NetToMediaTable)
#endif /* LWIP_ARP */
CREATE_LWIP_SYNC_NODE(23, ip_RoutingDiscards)
static const struct snmp_node* const ip_nodes[] = {
&SYNC_NODE_NAME(ip_Forwarding).node.node,
&SYNC_NODE_NAME(ip_DefaultTTL).node.node,
&SYNC_NODE_NAME(ip_InReceives).node.node,
&SYNC_NODE_NAME(ip_InHdrErrors).node.node,
&SYNC_NODE_NAME(ip_InAddrErrors).node.node,
&SYNC_NODE_NAME(ip_ForwDatagrams).node.node,
&SYNC_NODE_NAME(ip_InUnknownProtos).node.node,
&SYNC_NODE_NAME(ip_InDiscards).node.node,
&SYNC_NODE_NAME(ip_InDelivers).node.node,
&SYNC_NODE_NAME(ip_OutRequests).node.node,
&SYNC_NODE_NAME(ip_OutDiscards).node.node,
&SYNC_NODE_NAME(ip_OutNoRoutes).node.node,
&SYNC_NODE_NAME(ip_ReasmTimeout).node.node,
&SYNC_NODE_NAME(ip_ReasmReqds).node.node,
&SYNC_NODE_NAME(ip_ReasmOKs).node.node,
&SYNC_NODE_NAME(ip_ReasmFails).node.node,
&SYNC_NODE_NAME(ip_FragOKs).node.node,
&SYNC_NODE_NAME(ip_FragFails).node.node,
&SYNC_NODE_NAME(ip_FragCreates).node.node,
&SYNC_NODE_NAME(ip_AddrTable).node.node,
&SYNC_NODE_NAME(ip_RouteTable).node.node,
#if LWIP_ARP
&SYNC_NODE_NAME(ip_NetToMediaTable).node.node,
#endif /* LWIP_ARP */
&SYNC_NODE_NAME(ip_RoutingDiscards).node.node
};
const struct snmp_tree_node snmp_mib2_ip_root = SNMP_CREATE_TREE_NODE(4, ip_nodes);
#endif /* LWIP_IPV4 */
/* --- at .1.3.6.1.2.1.3 ----------------------------------------------------- */
#if LWIP_ARP && LWIP_IPV4
/* at node table is a subset of ip_nettomedia table (same rows but less columns) */
static const struct snmp_table_simple_col_def at_Table_columns[] = {
{ 1, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* atIfIndex */
{ 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_VARIANT_VALUE_TYPE_PTR }, /* atPhysAddress */
{ 3, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 } /* atNetAddress */
};
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 */
CREATE_LWIP_SYNC_NODE(1, at_Table)
static const struct snmp_node* const at_nodes[] = {
&SYNC_NODE_NAME(at_Table).node.node
};
const struct snmp_tree_node snmp_mib2_at_root = SNMP_CREATE_TREE_NODE(3, at_nodes);
#endif /* LWIP_ARP && LWIP_IPV4 */
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */

View File

@@ -0,0 +1,227 @@
/**
* @file
* Management Information Base II (RFC1213) SNMP objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_scalar.h"
#if LWIP_SNMP && SNMP_LWIP_MIB2
#define MIB2_AUTH_TRAPS_ENABLED 1
#define MIB2_AUTH_TRAPS_DISABLED 2
/* --- snmp .1.3.6.1.2.1.11 ----------------------------------------------------- */
static s16_t
snmp_get_value(const struct snmp_scalar_array_node_def *node, void *value)
{
u32_t *uint_ptr = (u32_t*)value;
switch (node->oid) {
case 1: /* snmpInPkts */
*uint_ptr = snmp_stats.inpkts;
break;
case 2: /* snmpOutPkts */
*uint_ptr = snmp_stats.outpkts;
break;
case 3: /* snmpInBadVersions */
*uint_ptr = snmp_stats.inbadversions;
break;
case 4: /* snmpInBadCommunityNames */
*uint_ptr = snmp_stats.inbadcommunitynames;
break;
case 5: /* snmpInBadCommunityUses */
*uint_ptr = snmp_stats.inbadcommunityuses;
break;
case 6: /* snmpInASNParseErrs */
*uint_ptr = snmp_stats.inasnparseerrs;
break;
case 8: /* snmpInTooBigs */
*uint_ptr = snmp_stats.intoobigs;
break;
case 9: /* snmpInNoSuchNames */
*uint_ptr = snmp_stats.innosuchnames;
break;
case 10: /* snmpInBadValues */
*uint_ptr = snmp_stats.inbadvalues;
break;
case 11: /* snmpInReadOnlys */
*uint_ptr = snmp_stats.inreadonlys;
break;
case 12: /* snmpInGenErrs */
*uint_ptr = snmp_stats.ingenerrs;
break;
case 13: /* snmpInTotalReqVars */
*uint_ptr = snmp_stats.intotalreqvars;
break;
case 14: /* snmpInTotalSetVars */
*uint_ptr = snmp_stats.intotalsetvars;
break;
case 15: /* snmpInGetRequests */
*uint_ptr = snmp_stats.ingetrequests;
break;
case 16: /* snmpInGetNexts */
*uint_ptr = snmp_stats.ingetnexts;
break;
case 17: /* snmpInSetRequests */
*uint_ptr = snmp_stats.insetrequests;
break;
case 18: /* snmpInGetResponses */
*uint_ptr = snmp_stats.ingetresponses;
break;
case 19: /* snmpInTraps */
*uint_ptr = snmp_stats.intraps;
break;
case 20: /* snmpOutTooBigs */
*uint_ptr = snmp_stats.outtoobigs;
break;
case 21: /* snmpOutNoSuchNames */
*uint_ptr = snmp_stats.outnosuchnames;
break;
case 22: /* snmpOutBadValues */
*uint_ptr = snmp_stats.outbadvalues;
break;
case 24: /* snmpOutGenErrs */
*uint_ptr = snmp_stats.outgenerrs;
break;
case 25: /* snmpOutGetRequests */
*uint_ptr = snmp_stats.outgetrequests;
break;
case 26: /* snmpOutGetNexts */
*uint_ptr = snmp_stats.outgetnexts;
break;
case 27: /* snmpOutSetRequests */
*uint_ptr = snmp_stats.outsetrequests;
break;
case 28: /* snmpOutGetResponses */
*uint_ptr = snmp_stats.outgetresponses;
break;
case 29: /* snmpOutTraps */
*uint_ptr = snmp_stats.outtraps;
break;
case 30: /* snmpEnableAuthenTraps */
if (snmp_get_auth_traps_enabled() == SNMP_AUTH_TRAPS_DISABLED) {
*uint_ptr = MIB2_AUTH_TRAPS_DISABLED;
} else {
*uint_ptr = MIB2_AUTH_TRAPS_ENABLED;
}
break;
case 31: /* snmpSilentDrops */
*uint_ptr = 0; /* not supported */
break;
case 32: /* snmpProxyDrops */
*uint_ptr = 0; /* not supported */
break;
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_value(): unknown id: %"S32_F"\n", node->oid));
return 0;
}
return sizeof(*uint_ptr);
}
static snmp_err_t
snmp_set_test(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
{
snmp_err_t ret = SNMP_ERR_WRONGVALUE;
LWIP_UNUSED_ARG(len);
if (node->oid == 30) {
/* snmpEnableAuthenTraps */
s32_t *sint_ptr = (s32_t*)value;
/* we should have writable non-volatile mem here */
if ((*sint_ptr == MIB2_AUTH_TRAPS_DISABLED) || (*sint_ptr == MIB2_AUTH_TRAPS_ENABLED)) {
ret = SNMP_ERR_NOERROR;
}
}
return ret;
}
static snmp_err_t
snmp_set_value(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
{
LWIP_UNUSED_ARG(len);
if (node->oid == 30) {
/* snmpEnableAuthenTraps */
s32_t *sint_ptr = (s32_t*)value;
if (*sint_ptr == MIB2_AUTH_TRAPS_DISABLED) {
snmp_set_auth_traps_enabled(SNMP_AUTH_TRAPS_DISABLED);
} else {
snmp_set_auth_traps_enabled(SNMP_AUTH_TRAPS_ENABLED);
}
}
return SNMP_ERR_NOERROR;
}
/* 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 */
{ 3, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadVersions */
{ 4, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadCommunityNames */
{ 5, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadCommunityUses */
{ 6, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInASNParseErrs */
{ 8, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTooBigs */
{ 9, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInNoSuchNames */
{10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadValues */
{11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInReadOnlys */
{12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGenErrs */
{13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTotalReqVars */
{14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTotalSetVars */
{15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGetRequests */
{16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGetNexts */
{17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInSetRequests */
{18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGetResponses */
{19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTraps */
{20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutTooBigs */
{21, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutNoSuchNames */
{22, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutBadValues */
{24, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGenErrs */
{25, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGetRequests */
{26, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGetNexts */
{27, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutSetRequests */
{28, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGetResponses */
{29, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutTraps */
{30, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE}, /* snmpEnableAuthenTraps */
{31, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpSilentDrops */
{32, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY} /* snmpProxyDrops */
};
const struct snmp_scalar_array_node snmp_mib2_snmp_root = SNMP_SCALAR_CREATE_ARRAY_NODE(11, snmp_nodes, snmp_get_value, snmp_set_test, snmp_set_value);
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */

View File

@@ -0,0 +1,377 @@
/**
* @file
* Management Information Base II (RFC1213) SYSTEM objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_table.h"
#include "lwip/apps/snmp_scalar.h"
#include "lwip/sys.h"
#include <string.h>
#if LWIP_SNMP && SNMP_LWIP_MIB2
#if SNMP_USE_NETCONN
#define SYNC_NODE_NAME(node_name) node_name ## _synced
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
#else
#define SYNC_NODE_NAME(node_name) node_name
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
#endif
/* --- system .1.3.6.1.2.1.1 ----------------------------------------------------- */
/** mib-2.system.sysDescr */
static const u8_t sysdescr_default[] = SNMP_LWIP_MIB2_SYSDESC;
static const u8_t* sysdescr = sysdescr_default;
static const u16_t* sysdescr_len = NULL; /* use strlen for determining len */
/** mib-2.system.sysContact */
static const u8_t syscontact_default[] = SNMP_LWIP_MIB2_SYSCONTACT;
static const u8_t* syscontact = syscontact_default;
static const u16_t* syscontact_len = NULL; /* use strlen for determining len */
static u8_t* syscontact_wr = NULL; /* if writable, points to the same buffer as syscontact (required for correct constness) */
static u16_t* syscontact_wr_len = NULL; /* if writable, points to the same buffer as syscontact_len (required for correct constness) */
static u16_t syscontact_bufsize = 0; /* 0=not writable */
/** mib-2.system.sysName */
static const u8_t sysname_default[] = SNMP_LWIP_MIB2_SYSNAME;
static const u8_t* sysname = sysname_default;
static const u16_t* sysname_len = NULL; /* use strlen for determining len */
static u8_t* sysname_wr = NULL; /* if writable, points to the same buffer as sysname (required for correct constness) */
static u16_t* sysname_wr_len = NULL; /* if writable, points to the same buffer as sysname_len (required for correct constness) */
static u16_t sysname_bufsize = 0; /* 0=not writable */
/** mib-2.system.sysLocation */
static const u8_t syslocation_default[] = SNMP_LWIP_MIB2_SYSLOCATION;
static const u8_t* syslocation = syslocation_default;
static const u16_t* syslocation_len = NULL; /* use strlen for determining len */
static u8_t* syslocation_wr = NULL; /* if writable, points to the same buffer as syslocation (required for correct constness) */
static u16_t* syslocation_wr_len = NULL; /* if writable, points to the same buffer as syslocation_len (required for correct constness) */
static u16_t syslocation_bufsize = 0; /* 0=not writable */
/**
* @ingroup snmp_mib2
* Initializes sysDescr pointers.
*
* @param str if non-NULL then copy str pointer
* @param len points to string length, excluding zero terminator
*/
void
snmp_mib2_set_sysdescr(const u8_t *str, const u16_t *len)
{
if (str != NULL) {
sysdescr = str;
sysdescr_len = len;
}
}
/**
* @ingroup snmp_mib2
* Initializes sysContact pointers
*
* @param ocstr if non-NULL then copy str pointer
* @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)
* if ocstrlen is NULL buffer needs space for terminating 0 byte.
* otherwise complete buffer is used for string.
* if bufsize is set to 0, the value is regarded as read-only.
*/
void
snmp_mib2_set_syscontact(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize)
{
if (ocstr != NULL) {
syscontact = ocstr;
syscontact_wr = ocstr;
syscontact_len = ocstrlen;
syscontact_wr_len = ocstrlen;
syscontact_bufsize = bufsize;
}
}
/**
* @ingroup snmp_mib2
* see \ref snmp_mib2_set_syscontact but set pointer to readonly memory
*/
void
snmp_mib2_set_syscontact_readonly(const u8_t *ocstr, const u16_t *ocstrlen)
{
if (ocstr != NULL) {
syscontact = ocstr;
syscontact_len = ocstrlen;
syscontact_wr = NULL;
syscontact_wr_len = NULL;
syscontact_bufsize = 0;
}
}
/**
* @ingroup snmp_mib2
* Initializes sysName pointers
*
* @param ocstr if non-NULL then copy str pointer
* @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)
* if ocstrlen is NULL buffer needs space for terminating 0 byte.
* otherwise complete buffer is used for string.
* if bufsize is set to 0, the value is regarded as read-only.
*/
void
snmp_mib2_set_sysname(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize)
{
if (ocstr != NULL) {
sysname = ocstr;
sysname_wr = ocstr;
sysname_len = ocstrlen;
sysname_wr_len = ocstrlen;
sysname_bufsize = bufsize;
}
}
/**
* @ingroup snmp_mib2
* see \ref snmp_mib2_set_sysname but set pointer to readonly memory
*/
void
snmp_mib2_set_sysname_readonly(const u8_t *ocstr, const u16_t *ocstrlen)
{
if (ocstr != NULL) {
sysname = ocstr;
sysname_len = ocstrlen;
sysname_wr = NULL;
sysname_wr_len = NULL;
sysname_bufsize = 0;
}
}
/**
* @ingroup snmp_mib2
* Initializes sysLocation pointers
*
* @param ocstr if non-NULL then copy str pointer
* @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)
* if ocstrlen is NULL buffer needs space for terminating 0 byte.
* otherwise complete buffer is used for string.
* if bufsize is set to 0, the value is regarded as read-only.
*/
void
snmp_mib2_set_syslocation(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize)
{
if (ocstr != NULL) {
syslocation = ocstr;
syslocation_wr = ocstr;
syslocation_len = ocstrlen;
syslocation_wr_len = ocstrlen;
syslocation_bufsize = bufsize;
}
}
/**
* @ingroup snmp_mib2
* see \ref snmp_mib2_set_syslocation but set pointer to readonly memory
*/
void
snmp_mib2_set_syslocation_readonly(const u8_t *ocstr, const u16_t *ocstrlen)
{
if (ocstr != NULL) {
syslocation = ocstr;
syslocation_len = ocstrlen;
syslocation_wr = NULL;
syslocation_wr_len = NULL;
syslocation_bufsize = 0;
}
}
static s16_t
system_get_value(const struct snmp_scalar_array_node_def *node, void *value)
{
const u8_t* var = NULL;
const s16_t* var_len;
u16_t result;
switch (node->oid) {
case 1: /* sysDescr */
var = sysdescr;
var_len = (const s16_t*)sysdescr_len;
break;
case 2: /* sysObjectID */
{
const struct snmp_obj_id* dev_enterprise_oid = snmp_get_device_enterprise_oid();
MEMCPY(value, dev_enterprise_oid->id, dev_enterprise_oid->len * sizeof(u32_t));
return dev_enterprise_oid->len * sizeof(u32_t);
}
case 3: /* sysUpTime */
MIB2_COPY_SYSUPTIME_TO((u32_t*)value);
return sizeof(u32_t);
case 4: /* sysContact */
var = syscontact;
var_len = (const s16_t*)syscontact_len;
break;
case 5: /* sysName */
var = sysname;
var_len = (const s16_t*)sysname_len;
break;
case 6: /* sysLocation */
var = syslocation;
var_len = (const s16_t*)syslocation_len;
break;
case 7: /* sysServices */
*(s32_t*)value = SNMP_SYSSERVICES;
return sizeof(s32_t);
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_value(): unknown id: %"S32_F"\n", node->oid));
return 0;
}
/* handle string values (OID 1,4,5 and 6) */
LWIP_ASSERT("", (value != NULL));
if (var_len == NULL) {
result = (s16_t)strlen((const char*)var);
} else {
result = *var_len;
}
MEMCPY(value, var, result);
return result;
}
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;
const u16_t* var_bufsize = NULL;
const u16_t* var_wr_len;
LWIP_UNUSED_ARG(value);
switch (node->oid) {
case 4: /* sysContact */
var_bufsize = &syscontact_bufsize;
var_wr_len = syscontact_wr_len;
break;
case 5: /* sysName */
var_bufsize = &sysname_bufsize;
var_wr_len = sysname_wr_len;
break;
case 6: /* sysLocation */
var_bufsize = &syslocation_bufsize;
var_wr_len = syslocation_wr_len;
break;
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_set_test(): unknown id: %"S32_F"\n", node->oid));
return ret;
}
/* check if value is writable at all */
if (*var_bufsize > 0) {
if (var_wr_len == NULL) {
/* we have to take the terminating 0 into account */
if (len < *var_bufsize) {
ret = SNMP_ERR_NOERROR;
}
} else {
if (len <= *var_bufsize) {
ret = SNMP_ERR_NOERROR;
}
}
} else {
ret = SNMP_ERR_NOTWRITABLE;
}
return ret;
}
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;
u16_t* var_wr_len;
switch (node->oid) {
case 4: /* sysContact */
var_wr = syscontact_wr;
var_wr_len = syscontact_wr_len;
break;
case 5: /* sysName */
var_wr = sysname_wr;
var_wr_len = sysname_wr_len;
break;
case 6: /* sysLocation */
var_wr = syslocation_wr;
var_wr_len = syslocation_wr_len;
break;
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_set_value(): unknown id: %"S32_F"\n", node->oid));
return SNMP_ERR_GENERROR;
}
/* no need to check size of target buffer, this was already done in set_test method */
LWIP_ASSERT("", var_wr != NULL);
MEMCPY(var_wr, value, len);
if (var_wr_len == NULL) {
/* add terminating 0 */
var_wr[len] = 0;
} else {
*var_wr_len = len;
}
return SNMP_ERR_NOERROR;
}
static const struct snmp_scalar_array_node_def system_nodes[] = {
{1, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* sysDescr */
{2, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_NODE_INSTANCE_READ_ONLY}, /* sysObjectID */
{3, SNMP_ASN1_TYPE_TIMETICKS, SNMP_NODE_INSTANCE_READ_ONLY}, /* sysUpTime */
{4, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_WRITE}, /* sysContact */
{5, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_WRITE}, /* sysName */
{6, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_WRITE}, /* sysLocation */
{7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY} /* sysServices */
};
const struct snmp_scalar_array_node snmp_mib2_system_node = SNMP_SCALAR_CREATE_ARRAY_NODE(1, system_nodes, system_get_value, system_set_test, system_set_value);
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */

View File

@@ -0,0 +1,594 @@
/**
* @file
* Management Information Base II (RFC1213) TCP objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_table.h"
#include "lwip/apps/snmp_scalar.h"
#include "lwip/tcp.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/stats.h"
#include <string.h>
#if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_TCP
#if SNMP_USE_NETCONN
#define SYNC_NODE_NAME(node_name) node_name ## _synced
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
#else
#define SYNC_NODE_NAME(node_name) node_name
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
#endif
/* --- tcp .1.3.6.1.2.1.6 ----------------------------------------------------- */
static s16_t
tcp_get_value(struct snmp_node_instance* instance, void* value)
{
u32_t *uint_ptr = (u32_t*)value;
s32_t *sint_ptr = (s32_t*)value;
switch (instance->node->oid) {
case 1: /* tcpRtoAlgorithm, vanj(4) */
*sint_ptr = 4;
return sizeof(*sint_ptr);
case 2: /* tcpRtoMin */
/* @todo not the actual value, a guess,
needs to be calculated */
*sint_ptr = 1000;
return sizeof(*sint_ptr);
case 3: /* tcpRtoMax */
/* @todo not the actual value, a guess,
needs to be calculated */
*sint_ptr = 60000;
return sizeof(*sint_ptr);
case 4: /* tcpMaxConn */
*sint_ptr = MEMP_NUM_TCP_PCB;
return sizeof(*sint_ptr);
case 5: /* tcpActiveOpens */
*uint_ptr = STATS_GET(mib2.tcpactiveopens);
return sizeof(*uint_ptr);
case 6: /* tcpPassiveOpens */
*uint_ptr = STATS_GET(mib2.tcppassiveopens);
return sizeof(*uint_ptr);
case 7: /* tcpAttemptFails */
*uint_ptr = STATS_GET(mib2.tcpattemptfails);
return sizeof(*uint_ptr);
case 8: /* tcpEstabResets */
*uint_ptr = STATS_GET(mib2.tcpestabresets);
return sizeof(*uint_ptr);
case 9: /* tcpCurrEstab */
{
u16_t tcpcurrestab = 0;
struct tcp_pcb *pcb = tcp_active_pcbs;
while (pcb != NULL) {
if ((pcb->state == ESTABLISHED) ||
(pcb->state == CLOSE_WAIT)) {
tcpcurrestab++;
}
pcb = pcb->next;
}
*uint_ptr = tcpcurrestab;
}
return sizeof(*uint_ptr);
case 10: /* tcpInSegs */
*uint_ptr = STATS_GET(mib2.tcpinsegs);
return sizeof(*uint_ptr);
case 11: /* tcpOutSegs */
*uint_ptr = STATS_GET(mib2.tcpoutsegs);
return sizeof(*uint_ptr);
case 12: /* tcpRetransSegs */
*uint_ptr = STATS_GET(mib2.tcpretranssegs);
return sizeof(*uint_ptr);
case 14: /* tcpInErrs */
*uint_ptr = STATS_GET(mib2.tcpinerrs);
return sizeof(*uint_ptr);
case 15: /* tcpOutRsts */
*uint_ptr = STATS_GET(mib2.tcpoutrsts);
return sizeof(*uint_ptr);
case 17: /* tcpHCInSegs */
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
return 2*sizeof(u32_t);
case 18: /* tcpHCOutSegs */
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
return 2*sizeof(u32_t);
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_value(): unknown id: %"S32_F"\n", instance->node->oid));
break;
}
return 0;
}
/* --- tcpConnTable --- */
#if LWIP_IPV4
/* list of allowed value ranges for incoming OID */
static const struct snmp_oid_range tcp_ConnTable_oid_ranges[] = {
{ 0, 0xff }, /* IP A */
{ 0, 0xff }, /* IP B */
{ 0, 0xff }, /* IP C */
{ 0, 0xff }, /* IP D */
{ 0, 0xffff }, /* Port */
{ 0, 0xff }, /* IP A */
{ 0, 0xff }, /* IP B */
{ 0, 0xff }, /* IP C */
{ 0, 0xff }, /* IP D */
{ 0, 0xffff } /* Port */
};
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);
/* value */
switch (*column) {
case 1: /* tcpConnState */
value->u32 = pcb->state + 1;
break;
case 2: /* tcpConnLocalAddress */
value->u32 = ip_2_ip4(&pcb->local_ip)->addr;
break;
case 3: /* tcpConnLocalPort */
value->u32 = pcb->local_port;
break;
case 4: /* tcpConnRemAddress */
if (pcb->state == LISTEN) {
value->u32 = IP4_ADDR_ANY4->addr;
} else {
value->u32 = ip_2_ip4(&pcb->remote_ip)->addr;
}
break;
case 5: /* tcpConnRemPort */
if (pcb->state == LISTEN) {
value->u32 = 0;
} else {
value->u32 = pcb->remote_port;
}
break;
default:
LWIP_ASSERT("invalid id", 0);
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
static snmp_err_t
tcp_ConnTable_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)
{
u8_t i;
ip4_addr_t local_ip;
ip4_addr_t remote_ip;
u16_t local_port;
u16_t remote_port;
struct tcp_pcb *pcb;
/* check if incoming OID length and if values are in plausible range */
if (!snmp_oid_in_range(row_oid, row_oid_len, tcp_ConnTable_oid_ranges, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges))) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* get IPs and ports from incoming OID */
snmp_oid_to_ip4(&row_oid[0], &local_ip); /* we know it succeeds because of oid_in_range check above */
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];
while (pcb != NULL) {
/* do local IP and local port match? */
if (IP_IS_V4_VAL(pcb->local_ip) &&
ip4_addr_cmp(&local_ip, ip_2_ip4(&pcb->local_ip)) && (local_port == pcb->local_port)) {
/* 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_ANY4) && (remote_port == 0)) {
/* fill in object properties */
return tcp_ConnTable_get_cell_value_core(pcb, column, value, value_len);
}
} else {
if (IP_IS_V4_VAL(pcb->remote_ip) &&
ip4_addr_cmp(&remote_ip, ip_2_ip4(&pcb->remote_ip)) && (remote_port == pcb->remote_port)) {
/* fill in object properties */
return tcp_ConnTable_get_cell_value_core(pcb, column, value, value_len);
}
}
}
pcb = pcb->next;
}
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
tcp_ConnTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
u8_t i;
struct tcp_pcb *pcb;
struct snmp_next_oid_state state;
u32_t result_temp[LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)];
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges));
/* iterate over all possible OIDs to find the next one */
for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) {
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_ANY4, &test_oid[5]);
test_oid[9] = 0;
} else {
if (IP_IS_V6_VAL(pcb->remote_ip)) { /* should never happen */
continue;
}
snmp_ip4_to_oid(ip_2_ip4(&pcb->remote_ip), &test_oid[5]);
test_oid[9] = pcb->remote_port;
}
/* 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;
}
}
/* 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);
/* fill in object properties */
return tcp_ConnTable_get_cell_value_core((struct tcp_pcb*)state.reference, column, value, value_len);
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
#endif /* LWIP_IPV4 */
/* --- tcpConnectionTable --- */
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 */
switch (*column) {
case 7: /* tcpConnectionState */
value->u32 = pcb->state + 1;
break;
case 8: /* tcpConnectionProcess */
value->u32 = 0; /* not supported */
break;
default:
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
static snmp_err_t
tcp_ConnectionTable_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;
u16_t local_port, remote_port;
struct tcp_pcb *pcb;
u8_t idx = 0;
u8_t i;
struct tcp_pcb ** const tcp_pcb_nonlisten_lists[] = {&tcp_bound_pcbs, &tcp_active_pcbs, &tcp_tw_pcbs};
LWIP_UNUSED_ARG(value_len);
/* tcpConnectionLocalAddressType + tcpConnectionLocalAddress + tcpConnectionLocalPort */
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port);
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) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* 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) &&
ip_addr_cmp(&remote_ip, &pcb->remote_ip) &&
(remote_port == pcb->remote_port)) {
/* fill in object properties */
return tcp_ConnectionTable_get_cell_value_core(column, pcb, value);
}
pcb = pcb->next;
}
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
tcp_ConnectionTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
struct tcp_pcb *pcb;
struct snmp_next_oid_state state;
/* 1x tcpConnectionLocalAddressType + 1x OID len + 16x tcpConnectionLocalAddress + 1x tcpConnectionLocalPort
* 1x tcpConnectionRemAddressType + 1x OID len + 16x tcpConnectionRemAddress + 1x tcpConnectionRemPort */
u32_t result_temp[38];
u8_t i;
struct tcp_pcb ** const tcp_pcb_nonlisten_lists[] = {&tcp_bound_pcbs, &tcp_active_pcbs, &tcp_tw_pcbs};
LWIP_UNUSED_ARG(value_len);
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp));
/* iterate over all possible OIDs to find the next one */
for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_nonlisten_lists); i++) {
pcb = *tcp_pcb_nonlisten_lists[i];
while (pcb != NULL) {
u8_t idx = 0;
u32_t test_oid[LWIP_ARRAYSIZE(result_temp)];
/* tcpConnectionLocalAddressType + tcpConnectionLocalAddress + tcpConnectionLocalPort */
idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]);
/* tcpConnectionRemAddressType + tcpConnectionRemAddress + tcpConnectionRemPort */
idx += snmp_ip_port_to_oid(&pcb->remote_ip, pcb->remote_port, &test_oid[idx]);
/* 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);
/* fill in object properties */
return tcp_ConnectionTable_get_cell_value_core(column, (struct tcp_pcb*)state.reference, value);
} else {
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
}
/* --- tcpListenerTable --- */
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 */
switch (*column) {
case 4: /* tcpListenerProcess */
value->u32 = 0; /* not supported */
break;
default:
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
static snmp_err_t
tcp_ListenerTable_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;
u16_t local_port;
struct tcp_pcb_listen *pcb;
u8_t idx = 0;
LWIP_UNUSED_ARG(value_len);
/* tcpListenerLocalAddressType + tcpListenerLocalAddress + tcpListenerLocalPort */
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port);
if (idx == 0) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* find tcp_pcb with requested ip and port*/
pcb = tcp_listen_pcbs.listen_pcbs;
while (pcb != NULL) {
if (ip_addr_cmp(&local_ip, &pcb->local_ip) &&
(local_port == pcb->local_port)) {
/* fill in object properties */
return tcp_ListenerTable_get_cell_value_core(column, value);
}
pcb = pcb->next;
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
tcp_ListenerTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
struct tcp_pcb_listen *pcb;
struct snmp_next_oid_state state;
/* 1x tcpListenerLocalAddressType + 1x OID len + 16x tcpListenerLocalAddress + 1x tcpListenerLocalPort */
u32_t result_temp[19];
LWIP_UNUSED_ARG(value_len);
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp));
/* iterate over all possible OIDs to find the next one */
pcb = tcp_listen_pcbs.listen_pcbs;
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;
}
/* 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);
/* fill in object properties */
return tcp_ListenerTable_get_cell_value_core(column, value);
} else {
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
}
static const struct snmp_scalar_node tcp_RtoAlgorithm = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_INTEGER, tcp_get_value);
static const struct snmp_scalar_node tcp_RtoMin = SNMP_SCALAR_CREATE_NODE_READONLY(2, SNMP_ASN1_TYPE_INTEGER, tcp_get_value);
static const struct snmp_scalar_node tcp_RtoMax = SNMP_SCALAR_CREATE_NODE_READONLY(3, SNMP_ASN1_TYPE_INTEGER, tcp_get_value);
static const struct snmp_scalar_node tcp_MaxConn = SNMP_SCALAR_CREATE_NODE_READONLY(4, SNMP_ASN1_TYPE_INTEGER, tcp_get_value);
static const struct snmp_scalar_node tcp_ActiveOpens = SNMP_SCALAR_CREATE_NODE_READONLY(5, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_PassiveOpens = SNMP_SCALAR_CREATE_NODE_READONLY(6, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_AttemptFails = SNMP_SCALAR_CREATE_NODE_READONLY(7, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_EstabResets = SNMP_SCALAR_CREATE_NODE_READONLY(8, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_CurrEstab = SNMP_SCALAR_CREATE_NODE_READONLY(9, SNMP_ASN1_TYPE_GAUGE, tcp_get_value);
static const struct snmp_scalar_node tcp_InSegs = SNMP_SCALAR_CREATE_NODE_READONLY(10, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_OutSegs = SNMP_SCALAR_CREATE_NODE_READONLY(11, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_RetransSegs = SNMP_SCALAR_CREATE_NODE_READONLY(12, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_InErrs = SNMP_SCALAR_CREATE_NODE_READONLY(14, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_OutRsts = SNMP_SCALAR_CREATE_NODE_READONLY(15, SNMP_ASN1_TYPE_COUNTER, tcp_get_value);
static const struct snmp_scalar_node tcp_HCInSegs = SNMP_SCALAR_CREATE_NODE_READONLY(17, SNMP_ASN1_TYPE_COUNTER64, tcp_get_value);
static const struct snmp_scalar_node tcp_HCOutSegs = SNMP_SCALAR_CREATE_NODE_READONLY(18, SNMP_ASN1_TYPE_COUNTER64, tcp_get_value);
#if LWIP_IPV4
static const struct snmp_table_simple_col_def tcp_ConnTable_columns[] = {
{ 1, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnState */
{ 2, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnLocalAddress */
{ 3, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnLocalPort */
{ 4, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnRemAddress */
{ 5, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpConnRemPort */
};
static const struct snmp_table_simple_node tcp_ConnTable = SNMP_TABLE_CREATE_SIMPLE(13, tcp_ConnTable_columns, tcp_ConnTable_get_cell_value, tcp_ConnTable_get_next_cell_instance_and_value);
#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 */
{ 7, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnectionState */
{ 8, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpConnectionProcess */
};
static const struct snmp_table_simple_node tcp_ConnectionTable = SNMP_TABLE_CREATE_SIMPLE(19, tcp_ConnectionTable_columns, tcp_ConnectionTable_get_cell_value, tcp_ConnectionTable_get_next_cell_instance_and_value);
static const struct snmp_table_simple_col_def tcp_ListenerTable_columns[] = {
/* 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 */
CREATE_LWIP_SYNC_NODE( 1, tcp_RtoAlgorithm)
CREATE_LWIP_SYNC_NODE( 2, tcp_RtoMin)
CREATE_LWIP_SYNC_NODE( 3, tcp_RtoMax)
CREATE_LWIP_SYNC_NODE( 4, tcp_MaxConn)
CREATE_LWIP_SYNC_NODE( 5, tcp_ActiveOpens)
CREATE_LWIP_SYNC_NODE( 6, tcp_PassiveOpens)
CREATE_LWIP_SYNC_NODE( 7, tcp_AttemptFails)
CREATE_LWIP_SYNC_NODE( 8, tcp_EstabResets)
CREATE_LWIP_SYNC_NODE( 9, tcp_CurrEstab)
CREATE_LWIP_SYNC_NODE(10, tcp_InSegs)
CREATE_LWIP_SYNC_NODE(11, tcp_OutSegs)
CREATE_LWIP_SYNC_NODE(12, tcp_RetransSegs)
#if LWIP_IPV4
CREATE_LWIP_SYNC_NODE(13, tcp_ConnTable)
#endif /* LWIP_IPV4 */
CREATE_LWIP_SYNC_NODE(14, tcp_InErrs)
CREATE_LWIP_SYNC_NODE(15, tcp_OutRsts)
CREATE_LWIP_SYNC_NODE(17, tcp_HCInSegs)
CREATE_LWIP_SYNC_NODE(18, tcp_HCOutSegs)
CREATE_LWIP_SYNC_NODE(19, tcp_ConnectionTable)
CREATE_LWIP_SYNC_NODE(20, tcp_ListenerTable)
static const struct snmp_node* const tcp_nodes[] = {
&SYNC_NODE_NAME(tcp_RtoAlgorithm).node.node,
&SYNC_NODE_NAME(tcp_RtoMin).node.node,
&SYNC_NODE_NAME(tcp_RtoMax).node.node,
&SYNC_NODE_NAME(tcp_MaxConn).node.node,
&SYNC_NODE_NAME(tcp_ActiveOpens).node.node,
&SYNC_NODE_NAME(tcp_PassiveOpens).node.node,
&SYNC_NODE_NAME(tcp_AttemptFails).node.node,
&SYNC_NODE_NAME(tcp_EstabResets).node.node,
&SYNC_NODE_NAME(tcp_CurrEstab).node.node,
&SYNC_NODE_NAME(tcp_InSegs).node.node,
&SYNC_NODE_NAME(tcp_OutSegs).node.node,
&SYNC_NODE_NAME(tcp_RetransSegs).node.node,
#if LWIP_IPV4
&SYNC_NODE_NAME(tcp_ConnTable).node.node,
#endif /* LWIP_IPV4 */
&SYNC_NODE_NAME(tcp_InErrs).node.node,
&SYNC_NODE_NAME(tcp_OutRsts).node.node,
&SYNC_NODE_NAME(tcp_HCInSegs).node.node,
&SYNC_NODE_NAME(tcp_HCOutSegs).node.node,
&SYNC_NODE_NAME(tcp_ConnectionTable).node.node,
&SYNC_NODE_NAME(tcp_ListenerTable).node.node
};
const struct snmp_tree_node snmp_mib2_tcp_root = SNMP_CREATE_TREE_NODE(6, tcp_nodes);
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_TCP */

View File

@@ -0,0 +1,357 @@
/**
* @file
* Management Information Base II (RFC1213) UDP objects and functions.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* 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: Dirk Ziegelmeier <dziegel@gmx.de>
* Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_table.h"
#include "lwip/apps/snmp_scalar.h"
#include "lwip/udp.h"
#include "lwip/stats.h"
#include <string.h>
#if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_UDP
#if SNMP_USE_NETCONN
#define SYNC_NODE_NAME(node_name) node_name ## _synced
#define CREATE_LWIP_SYNC_NODE(oid, node_name) \
static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks);
#else
#define SYNC_NODE_NAME(node_name) node_name
#define CREATE_LWIP_SYNC_NODE(oid, node_name)
#endif
/* --- udp .1.3.6.1.2.1.7 ----------------------------------------------------- */
static s16_t
udp_get_value(struct snmp_node_instance* instance, void* value)
{
u32_t *uint_ptr = (u32_t*)value;
switch (instance->node->oid) {
case 1: /* udpInDatagrams */
*uint_ptr = STATS_GET(mib2.udpindatagrams);
return sizeof(*uint_ptr);
case 2: /* udpNoPorts */
*uint_ptr = STATS_GET(mib2.udpnoports);
return sizeof(*uint_ptr);
case 3: /* udpInErrors */
*uint_ptr = STATS_GET(mib2.udpinerrors);
return sizeof(*uint_ptr);
case 4: /* udpOutDatagrams */
*uint_ptr = STATS_GET(mib2.udpoutdatagrams);
return sizeof(*uint_ptr);
case 8: /* udpHCInDatagrams */
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
return 2*sizeof(u32_t);
case 9: /* udpHCOutDatagrams */
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
return 2*sizeof(u32_t);
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_value(): unknown id: %"S32_F"\n", instance->node->oid));
break;
}
return 0;
}
/* --- udpEndpointTable --- */
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 */
switch (*column) {
case 8: /* udpEndpointProcess */
value->u32 = 0; /* not supported */
break;
default:
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
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;
u16_t local_port, remote_port;
struct udp_pcb *pcb;
u8_t idx = 0;
LWIP_UNUSED_ARG(value_len);
/* udpEndpointLocalAddressType + udpEndpointLocalAddress + udpEndpointLocalPort */
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port);
if (idx == 0) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* udpEndpointRemoteAddressType + udpEndpointRemoteAddress + udpEndpointRemotePort */
idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &remote_ip, &remote_port);
if (idx == 0) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* udpEndpointInstance */
if (row_oid_len < (idx+1)) {
return SNMP_ERR_NOSUCHINSTANCE;
}
if (row_oid[idx] != 0) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* find udp_pcb with requested ip and port*/
pcb = udp_pcbs;
while (pcb != NULL) {
if (ip_addr_cmp(&local_ip, &pcb->local_ip) &&
(local_port == pcb->local_port) &&
ip_addr_cmp(&remote_ip, &pcb->remote_ip) &&
(remote_port == pcb->remote_port)) {
/* fill in object properties */
return udp_endpointTable_get_cell_value_core(column, value);
}
pcb = pcb->next;
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
udp_endpointTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
struct udp_pcb *pcb;
struct snmp_next_oid_state state;
/* 1x udpEndpointLocalAddressType + 1x OID len + 16x udpEndpointLocalAddress + 1x udpEndpointLocalPort +
* 1x udpEndpointRemoteAddressType + 1x OID len + 16x udpEndpointRemoteAddress + 1x udpEndpointRemotePort +
* 1x udpEndpointInstance = 39
*/
u32_t result_temp[39];
LWIP_UNUSED_ARG(value_len);
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp));
/* iterate over all possible OIDs to find the next one */
pcb = udp_pcbs;
while (pcb != NULL) {
u32_t test_oid[LWIP_ARRAYSIZE(result_temp)];
u8_t idx = 0;
/* udpEndpointLocalAddressType + udpEndpointLocalAddress + udpEndpointLocalPort */
idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]);
/* udpEndpointRemoteAddressType + udpEndpointRemoteAddress + udpEndpointRemotePort */
idx += snmp_ip_port_to_oid(&pcb->remote_ip, pcb->remote_port, &test_oid[idx]);
test_oid[idx] = 0; /* udpEndpointInstance */
idx++;
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, idx, NULL);
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);
/* fill in object properties */
return udp_endpointTable_get_cell_value_core(column, value);
} else {
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
}
/* --- udpTable --- */
#if LWIP_IPV4
/* list of allowed value ranges for incoming OID */
static const struct snmp_oid_range udp_Table_oid_ranges[] = {
{ 0, 0xff }, /* IP A */
{ 0, 0xff }, /* IP B */
{ 0, 0xff }, /* IP C */
{ 0, 0xff }, /* IP D */
{ 1, 0xffff } /* Port */
};
static snmp_err_t
udp_Table_get_cell_value_core(struct udp_pcb *pcb, const u32_t* column, union snmp_variant_value* value, u32_t* value_len)
{
LWIP_UNUSED_ARG(value_len);
switch (*column) {
case 1: /* udpLocalAddress */
/* set reference to PCB local IP and return a generic node that copies IP4 addresses */
value->u32 = ip_2_ip4(&pcb->local_ip)->addr;
break;
case 2: /* udpLocalPort */
/* set reference to PCB local port and return a generic node that copies u16_t values */
value->u32 = pcb->local_port;
break;
default:
return SNMP_ERR_NOSUCHINSTANCE;
}
return SNMP_ERR_NOERROR;
}
static snmp_err_t
udp_Table_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)
{
ip4_addr_t ip;
u16_t port;
struct udp_pcb *pcb;
/* check if incoming OID length and if values are in plausible range */
if (!snmp_oid_in_range(row_oid, row_oid_len, udp_Table_oid_ranges, LWIP_ARRAYSIZE(udp_Table_oid_ranges))) {
return SNMP_ERR_NOSUCHINSTANCE;
}
/* get IP and port from incoming OID */
snmp_oid_to_ip4(&row_oid[0], &ip); /* we know it succeeds because of oid_in_range check above */
port = (u16_t)row_oid[4];
/* find udp_pcb with requested ip and port*/
pcb = udp_pcbs;
while (pcb != NULL) {
if (IP_IS_V4_VAL(pcb->local_ip)) {
if (ip4_addr_cmp(&ip, ip_2_ip4(&pcb->local_ip)) && (port == pcb->local_port)) {
/* fill in object properties */
return udp_Table_get_cell_value_core(pcb, column, value, value_len);
}
}
pcb = pcb->next;
}
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
udp_Table_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
struct udp_pcb *pcb;
struct snmp_next_oid_state state;
u32_t result_temp[LWIP_ARRAYSIZE(udp_Table_oid_ranges)];
/* init struct to search next oid */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(udp_Table_oid_ranges));
/* iterate over all possible OIDs to find the next one */
pcb = udp_pcbs;
while (pcb != NULL) {
u32_t test_oid[LWIP_ARRAYSIZE(udp_Table_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;
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(udp_Table_oid_ranges), 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);
/* fill in object properties */
return udp_Table_get_cell_value_core((struct udp_pcb*)state.reference, column, value, value_len);
} else {
/* not found */
return SNMP_ERR_NOSUCHINSTANCE;
}
}
#endif /* LWIP_IPV4 */
static const struct snmp_scalar_node udp_inDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_COUNTER, udp_get_value);
static const struct snmp_scalar_node udp_noPorts = SNMP_SCALAR_CREATE_NODE_READONLY(2, SNMP_ASN1_TYPE_COUNTER, udp_get_value);
static const struct snmp_scalar_node udp_inErrors = SNMP_SCALAR_CREATE_NODE_READONLY(3, SNMP_ASN1_TYPE_COUNTER, udp_get_value);
static const struct snmp_scalar_node udp_outDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(4, SNMP_ASN1_TYPE_COUNTER, udp_get_value);
static const struct snmp_scalar_node udp_HCInDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(8, SNMP_ASN1_TYPE_COUNTER64, udp_get_value);
static const struct snmp_scalar_node udp_HCOutDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(9, SNMP_ASN1_TYPE_COUNTER64, udp_get_value);
#if LWIP_IPV4
static const struct snmp_table_simple_col_def udp_Table_columns[] = {
{ 1, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* udpLocalAddress */
{ 2, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* udpLocalPort */
};
static const struct snmp_table_simple_node udp_Table = SNMP_TABLE_CREATE_SIMPLE(5, udp_Table_columns, udp_Table_get_cell_value, udp_Table_get_next_cell_instance_and_value);
#endif /* LWIP_IPV4 */
static const struct snmp_table_simple_col_def udp_endpointTable_columns[] = {
/* all items except udpEndpointProcess are declared as not-accessible */
{ 8, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* udpEndpointProcess */
};
static const struct snmp_table_simple_node udp_endpointTable = SNMP_TABLE_CREATE_SIMPLE(7, udp_endpointTable_columns, udp_endpointTable_get_cell_value, udp_endpointTable_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 */
CREATE_LWIP_SYNC_NODE(1, udp_inDatagrams)
CREATE_LWIP_SYNC_NODE(2, udp_noPorts)
CREATE_LWIP_SYNC_NODE(3, udp_inErrors)
CREATE_LWIP_SYNC_NODE(4, udp_outDatagrams)
#if LWIP_IPV4
CREATE_LWIP_SYNC_NODE(5, udp_Table)
#endif /* LWIP_IPV4 */
CREATE_LWIP_SYNC_NODE(7, udp_endpointTable)
CREATE_LWIP_SYNC_NODE(8, udp_HCInDatagrams)
CREATE_LWIP_SYNC_NODE(9, udp_HCOutDatagrams)
static const struct snmp_node* const udp_nodes[] = {
&SYNC_NODE_NAME(udp_inDatagrams).node.node,
&SYNC_NODE_NAME(udp_noPorts).node.node,
&SYNC_NODE_NAME(udp_inErrors).node.node,
&SYNC_NODE_NAME(udp_outDatagrams).node.node,
#if LWIP_IPV4
&SYNC_NODE_NAME(udp_Table).node.node,
#endif /* LWIP_IPV4 */
&SYNC_NODE_NAME(udp_endpointTable).node.node,
&SYNC_NODE_NAME(udp_HCInDatagrams).node.node,
&SYNC_NODE_NAME(udp_HCOutDatagrams).node.node
};
const struct snmp_tree_node snmp_mib2_udp_root = SNMP_CREATE_TREE_NODE(7, udp_nodes);
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_UDP */

1668
ext/lwip/src/apps/snmp/snmp_msg.c Executable file

File diff suppressed because it is too large Load Diff

194
ext/lwip/src/apps/snmp/snmp_msg.h Executable file
View File

@@ -0,0 +1,194 @@
/**
* @file
* SNMP Agent message handling structures (internal API, do not use in client code).
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* Copyright (c) 2016 Elias Oenal.
* 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: Christiaan Simons <christiaan.simons@axon.tv>
* Martin Hentschel <info@cl-soft.de>
* Elias Oenal <lwip@eliasoenal.com>
*/
#ifndef LWIP_HDR_APPS_SNMP_MSG_H
#define LWIP_HDR_APPS_SNMP_MSG_H
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "snmp_pbuf_stream.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#if LWIP_SNMP_V3
#include "snmpv3_priv.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* The listen port of the SNMP agent. Clients have to make their requests to
this port. Most standard clients won't work if you change this! */
#ifndef SNMP_IN_PORT
#define SNMP_IN_PORT 161
#endif
/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't
work if you change this! */
#ifndef SNMP_TRAP_PORT
#define SNMP_TRAP_PORT 162
#endif
/* version defines used in PDU */
#define SNMP_VERSION_1 0
#define SNMP_VERSION_2c 1
#define SNMP_VERSION_3 3
struct snmp_varbind_enumerator
{
struct snmp_pbuf_stream pbuf_stream;
u16_t varbind_count;
};
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);
struct snmp_request
{
/* Communication handle */
void *handle;
/* source IP address */
const ip_addr_t *source_ip;
/* source UDP port */
u16_t source_port;
/* incoming snmp version */
u8_t version;
/* community name (zero terminated) */
u8_t community[SNMP_MAX_COMMUNITY_STR_LEN + 1];
/* community string length (exclusive zero term) */
u16_t community_strlen;
/* request type */
u8_t request_type;
/* request ID */
s32_t request_id;
/* error status */
s32_t error_status;
/* error index */
s32_t error_index;
/* non-repeaters (getBulkRequest (SNMPv2c)) */
s32_t non_repeaters;
/* max-repetitions (getBulkRequest (SNMPv2c)) */
s32_t max_repetitions;
#if LWIP_SNMP_V3
s32_t msg_id;
s32_t msg_max_size;
u8_t msg_flags;
s32_t msg_security_model;
u8_t msg_authoritative_engine_id[SNMP_V3_MAX_ENGINE_ID_LENGTH];
u8_t msg_authoritative_engine_id_len;
s32_t msg_authoritative_engine_boots;
s32_t msg_authoritative_engine_time;
u8_t msg_user_name[SNMP_V3_MAX_USER_LENGTH];
u8_t msg_user_name_len;
u8_t msg_authentication_parameters[SNMP_V3_MAX_AUTH_PARAM_LENGTH];
u8_t msg_privacy_parameters[SNMP_V3_MAX_PRIV_PARAM_LENGTH];
u8_t context_engine_id[SNMP_V3_MAX_ENGINE_ID_LENGTH];
u8_t context_engine_id_len;
u8_t context_name[SNMP_V3_MAX_ENGINE_ID_LENGTH];
u8_t context_name_len;
#endif
struct pbuf *inbound_pbuf;
struct snmp_varbind_enumerator inbound_varbind_enumerator;
u16_t inbound_varbind_offset;
u16_t inbound_varbind_len;
u16_t inbound_padding_len;
struct pbuf *outbound_pbuf;
struct snmp_pbuf_stream outbound_pbuf_stream;
u16_t outbound_pdu_offset;
u16_t outbound_error_status_offset;
u16_t outbound_error_index_offset;
u16_t outbound_varbind_offset;
#if LWIP_SNMP_V3
u16_t outbound_msg_global_data_offset;
u16_t outbound_msg_global_data_end;
u16_t outbound_msg_security_parameters_str_offset;
u16_t outbound_msg_security_parameters_seq_offset;
u16_t outbound_msg_security_parameters_end;
u16_t outbound_msg_authentication_parameters_offset;
u16_t outbound_scoped_pdu_seq_offset;
u16_t outbound_scoped_pdu_string_offset;
#endif
u8_t value_buffer[SNMP_MAX_VALUE_SIZE];
};
/** A helper struct keeping length information about varbinds */
struct snmp_varbind_len
{
u8_t vb_len_len;
u16_t vb_value_len;
u8_t oid_len_len;
u16_t oid_value_len;
u8_t value_len_len;
u16_t value_value_len;
};
/** Agent community string */
extern const char *snmp_community;
/** Agent community string for write access */
extern const char *snmp_community_write;
/** handle for sending traps */
extern void* snmp_traps_handle;
void snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port);
err_t snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port);
u8_t snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result);
err_t snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len);
err_t snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind* varbind);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_SNMP */
#endif /* LWIP_HDR_APPS_SNMP_MSG_H */

View File

@@ -0,0 +1,121 @@
/**
* @file
* SNMP netconn frontend.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP && SNMP_USE_NETCONN
#include <string.h>
#include "lwip/api.h"
#include "lwip/ip.h"
#include "lwip/udp.h"
#include "snmp_msg.h"
#include "lwip/sys.h"
/** SNMP netconn API worker thread */
static void
snmp_netconn_thread(void *arg)
{
struct netconn *conn;
struct netbuf *buf;
err_t err;
LWIP_UNUSED_ARG(arg);
/* Bind to SNMP port with default IP address */
#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, IP4_ADDR_ANY, SNMP_IN_PORT);
#endif /* LWIP_IPV6 */
LWIP_ERROR("snmp_netconn: invalid conn", (conn != NULL), return;);
snmp_traps_handle = conn;
do {
err = netconn_recv(conn, &buf);
if (err == ERR_OK) {
snmp_receive(conn, buf->p, &buf->addr, buf->port);
}
if (buf != NULL) {
netbuf_delete(buf);
}
} while(1);
}
err_t
snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port)
{
err_t result;
struct netbuf buf;
memset(&buf, 0, sizeof(buf));
buf.p = p;
result = netconn_sendto((struct netconn*)handle, &buf, dst, port);
return result;
}
u8_t
snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result)
{
struct netconn* conn = (struct netconn*)handle;
struct netif *dst_if;
const ip_addr_t* dst_ip;
LWIP_UNUSED_ARG(conn); /* unused in case of IPV4 only configuration */
ip_route_get_local_ip(&conn->pcb.udp->local_ip, dst, dst_if, dst_ip);
if ((dst_if != NULL) && (dst_ip != NULL)) {
ip_addr_copy(*result, *dst_ip);
return 1;
} else {
return 0;
}
}
/**
* Starts SNMP Agent.
*/
void
snmp_init(void)
{
sys_thread_new("snmp_netconn", snmp_netconn_thread, NULL, SNMP_STACK_SIZE, SNMP_THREAD_PRIO);
}
#endif /* LWIP_SNMP && SNMP_USE_NETCONN */

View File

@@ -0,0 +1,156 @@
/**
* @file
* SNMP pbuf stream wrapper implementation (internal API, do not use in client code).
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "snmp_pbuf_stream.h"
#include "lwip/def.h"
#include <string.h>
err_t
snmp_pbuf_stream_init(struct snmp_pbuf_stream* pbuf_stream, struct pbuf* p, u16_t offset, u16_t length)
{
pbuf_stream->offset = offset;
pbuf_stream->length = length;
pbuf_stream->pbuf = p;
return ERR_OK;
}
err_t
snmp_pbuf_stream_read(struct snmp_pbuf_stream* pbuf_stream, u8_t* data)
{
if (pbuf_stream->length == 0) {
return ERR_BUF;
}
if (pbuf_copy_partial(pbuf_stream->pbuf, data, 1, pbuf_stream->offset) == 0) {
return ERR_BUF;
}
pbuf_stream->offset++;
pbuf_stream->length--;
return ERR_OK;
}
err_t
snmp_pbuf_stream_write(struct snmp_pbuf_stream* pbuf_stream, u8_t data)
{
return snmp_pbuf_stream_writebuf(pbuf_stream, &data, 1);
}
err_t
snmp_pbuf_stream_writebuf(struct snmp_pbuf_stream* pbuf_stream, const void* buf, u16_t buf_len)
{
if (pbuf_stream->length < buf_len) {
return ERR_BUF;
}
if (pbuf_take_at(pbuf_stream->pbuf, buf, buf_len, pbuf_stream->offset) != ERR_OK) {
return ERR_BUF;
}
pbuf_stream->offset += buf_len;
pbuf_stream->length -= buf_len;
return ERR_OK;
}
err_t
snmp_pbuf_stream_writeto(struct snmp_pbuf_stream* pbuf_stream, struct snmp_pbuf_stream* target_pbuf_stream, u16_t len)
{
if ((pbuf_stream == NULL) || (target_pbuf_stream == NULL)) {
return ERR_ARG;
}
if ((len > pbuf_stream->length) || (len > target_pbuf_stream->length)) {
return ERR_ARG;
}
if (len == 0) {
len = LWIP_MIN(pbuf_stream->length, target_pbuf_stream->length);
}
while (len > 0) {
u16_t chunk_len;
err_t err;
u16_t target_offset;
struct pbuf* pbuf = pbuf_skip(pbuf_stream->pbuf, pbuf_stream->offset, &target_offset);
if ((pbuf == NULL) || (pbuf->len == 0)) {
return ERR_BUF;
}
chunk_len = LWIP_MIN(len, pbuf->len);
err = snmp_pbuf_stream_writebuf(target_pbuf_stream, &((u8_t*)pbuf->payload)[target_offset], chunk_len);
if (err != ERR_OK) {
return err;
}
pbuf_stream->offset += chunk_len;
pbuf_stream->length -= chunk_len;
len -= chunk_len;
}
return ERR_OK;
}
err_t
snmp_pbuf_stream_seek(struct snmp_pbuf_stream* pbuf_stream, s32_t offset)
{
if ((offset < 0) || (offset > pbuf_stream->length)) {
/* we cannot seek backwards or forward behind stream end */
return ERR_ARG;
}
pbuf_stream->offset += (u16_t)offset;
pbuf_stream->length -= (u16_t)offset;
return ERR_OK;
}
err_t
snmp_pbuf_stream_seek_abs(struct snmp_pbuf_stream* pbuf_stream, u32_t offset)
{
s32_t rel_offset = offset - pbuf_stream->offset;
return snmp_pbuf_stream_seek(pbuf_stream, rel_offset);
}
#endif /* LWIP_SNMP */

View File

@@ -0,0 +1,73 @@
/**
* @file
* SNMP pbuf stream wrapper (internal API, do not use in client code).
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
#ifndef LWIP_HDR_APPS_SNMP_PBUF_STREAM_H
#define LWIP_HDR_APPS_SNMP_PBUF_STREAM_H
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP
#include "lwip/err.h"
#include "lwip/pbuf.h"
#ifdef __cplusplus
extern "C" {
#endif
struct snmp_pbuf_stream
{
struct pbuf* pbuf;
u16_t offset;
u16_t length;
};
err_t snmp_pbuf_stream_init(struct snmp_pbuf_stream* pbuf_stream, struct pbuf* p, u16_t offset, u16_t length);
err_t snmp_pbuf_stream_read(struct snmp_pbuf_stream* pbuf_stream, u8_t* data);
err_t snmp_pbuf_stream_write(struct snmp_pbuf_stream* pbuf_stream, u8_t data);
err_t snmp_pbuf_stream_writebuf(struct snmp_pbuf_stream* pbuf_stream, const void* buf, u16_t buf_len);
err_t snmp_pbuf_stream_writeto(struct snmp_pbuf_stream* pbuf_stream, struct snmp_pbuf_stream* target_pbuf_stream, u16_t len);
err_t snmp_pbuf_stream_seek(struct snmp_pbuf_stream* pbuf_stream, s32_t offset);
err_t snmp_pbuf_stream_seek_abs(struct snmp_pbuf_stream* pbuf_stream, u32_t offset);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_SNMP */
#endif /* LWIP_HDR_APPS_SNMP_PBUF_STREAM_H */

100
ext/lwip/src/apps/snmp/snmp_raw.c Executable file
View File

@@ -0,0 +1,100 @@
/**
* @file
* SNMP RAW API frontend.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
*/
#include "lwip/apps/snmp_opts.h"
#include "lwip/ip_addr.h"
#if LWIP_SNMP && SNMP_USE_RAW
#include "lwip/udp.h"
#include "lwip/ip.h"
#include "snmp_msg.h"
/* lwIP UDP receive callback function */
static void
snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
LWIP_UNUSED_ARG(arg);
snmp_receive(pcb, p, addr, port);
pbuf_free(p);
}
err_t
snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port)
{
return udp_sendto((struct udp_pcb*)handle, p, dst, port);
}
u8_t
snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result)
{
struct udp_pcb* udp_pcb = (struct udp_pcb*)handle;
struct netif *dst_if;
const ip_addr_t* dst_ip;
LWIP_UNUSED_ARG(udp_pcb); /* unused in case of IPV4 only configuration */
ip_route_get_local_ip(&udp_pcb->local_ip, dst, dst_if, dst_ip);
if ((dst_if != NULL) && (dst_ip != NULL)) {
ip_addr_copy(*result, *dst_ip);
return 1;
} else {
return 0;
}
}
/**
* @ingroup snmp_core
* Starts SNMP Agent.
* Allocates UDP pcb and binds it to IP_ANY_TYPE port 161.
*/
void
snmp_init(void)
{
err_t err;
struct udp_pcb *snmp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
LWIP_ERROR("snmp_raw: no PCB", (snmp_pcb != NULL), return;);
snmp_traps_handle = snmp_pcb;
udp_recv(snmp_pcb, snmp_recv, (void *)SNMP_IN_PORT);
err = udp_bind(snmp_pcb, IP_ANY_TYPE, SNMP_IN_PORT);
LWIP_ERROR("snmp_raw: Unable to bind PCB", (err == ERR_OK), return;);
}
#endif /* LWIP_SNMP && SNMP_USE_RAW */

View File

@@ -0,0 +1,220 @@
/**
* @file
* SNMP scalar node support implementation.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_scalar.h"
#include "lwip/apps/snmp_core.h"
static s16_t snmp_scalar_array_get_value(struct snmp_node_instance* instance, void* value);
static snmp_err_t snmp_scalar_array_set_test(struct snmp_node_instance* instance, u16_t value_len, void* value);
static snmp_err_t snmp_scalar_array_set_value(struct snmp_node_instance* instance, u16_t value_len, void* value);
snmp_err_t
snmp_scalar_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
const struct snmp_scalar_node* scalar_node = (const struct snmp_scalar_node*)(const void*)instance->node;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
/* scalar only has one dedicated instance: .0 */
if ((instance->instance_oid.len != 1) || (instance->instance_oid.id[0] != 0)) {
return SNMP_ERR_NOSUCHINSTANCE;
}
instance->access = scalar_node->access;
instance->asn1_type = scalar_node->asn1_type;
instance->get_value = scalar_node->get_value;
instance->set_test = scalar_node->set_test;
instance->set_value = scalar_node->set_value;
return SNMP_ERR_NOERROR;
}
snmp_err_t
snmp_scalar_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
/* because our only instance is .0 we can only return a next instance if no instance oid is passed */
if (instance->instance_oid.len == 0) {
instance->instance_oid.len = 1;
instance->instance_oid.id[0] = 0;
return snmp_scalar_get_instance(root_oid, root_oid_len, instance);
}
return SNMP_ERR_NOSUCHINSTANCE;
}
snmp_err_t
snmp_scalar_array_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
if ((instance->instance_oid.len == 2) && (instance->instance_oid.id[1] == 0)) {
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
const struct snmp_scalar_array_node_def* array_node_def = array_node->array_nodes;
u32_t i = 0;
while (i < array_node->array_node_count) {
if (array_node_def->oid == instance->instance_oid.id[0]) {
break;
}
array_node_def++;
i++;
}
if (i < array_node->array_node_count) {
instance->access = array_node_def->access;
instance->asn1_type = array_node_def->asn1_type;
instance->get_value = snmp_scalar_array_get_value;
instance->set_test = snmp_scalar_array_set_test;
instance->set_value = snmp_scalar_array_set_value;
instance->reference.const_ptr = array_node_def;
return SNMP_ERR_NOERROR;
}
}
return SNMP_ERR_NOSUCHINSTANCE;
}
snmp_err_t
snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
const struct snmp_scalar_array_node_def* array_node_def = array_node->array_nodes;
const struct snmp_scalar_array_node_def* result = NULL;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
if ((instance->instance_oid.len == 0) && (array_node->array_node_count > 0)) {
/* return node with lowest OID */
u16_t i = 0;
result = array_node_def;
array_node_def++;
for (i = 1; i < array_node->array_node_count; i++) {
if (array_node_def->oid < result->oid) {
result = array_node_def;
}
array_node_def++;
}
} else if (instance->instance_oid.len >= 1) {
if (instance->instance_oid.len == 1) {
/* if we have the requested OID we return its instance, otherwise we search for the next available */
u16_t i = 0;
while (i < array_node->array_node_count) {
if (array_node_def->oid == instance->instance_oid.id[0]) {
result = array_node_def;
break;
}
array_node_def++;
i++;
}
}
if (result == NULL) {
u32_t oid_dist = 0xFFFFFFFFUL;
u16_t i = 0;
array_node_def = array_node->array_nodes; /* may be already at the end when if case before was executed without result -> reinitialize to start */
while (i < array_node->array_node_count) {
if ((array_node_def->oid > instance->instance_oid.id[0]) &&
((u32_t)(array_node_def->oid - instance->instance_oid.id[0]) < oid_dist)) {
result = array_node_def;
oid_dist = array_node_def->oid - instance->instance_oid.id[0];
}
array_node_def++;
i++;
}
}
}
if (result == NULL) {
/* nothing to return */
return SNMP_ERR_NOSUCHINSTANCE;
}
instance->instance_oid.len = 2;
instance->instance_oid.id[0] = result->oid;
instance->instance_oid.id[1] = 0;
instance->access = result->access;
instance->asn1_type = result->asn1_type;
instance->get_value = snmp_scalar_array_get_value;
instance->set_test = snmp_scalar_array_set_test;
instance->set_value = snmp_scalar_array_set_value;
instance->reference.const_ptr = result;
return SNMP_ERR_NOERROR;
}
static s16_t
snmp_scalar_array_get_value(struct snmp_node_instance* instance, void* value)
{
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr;
return array_node->get_value(array_node_def, value);
}
static snmp_err_t
snmp_scalar_array_set_test(struct snmp_node_instance* instance, u16_t value_len, void* value)
{
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr;
return array_node->set_test(array_node_def, value_len, value);
}
static snmp_err_t
snmp_scalar_array_set_value(struct snmp_node_instance* instance, u16_t value_len, void* value)
{
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr;
return array_node->set_value(array_node_def, value_len, value);
}
#endif /* LWIP_SNMP */

View File

@@ -0,0 +1,343 @@
/**
* @file
* SNMP table support implementation.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_table.h"
#include <string.h>
snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE;
const struct snmp_table_node* table_node = (const struct snmp_table_node*)(const void*)instance->node;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
/* check min. length (fixed row entry definition, column, row instance oid with at least one entry */
/* fixed row entry always has oid 1 */
if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1)) {
/* search column */
const struct snmp_table_col_def* col_def = table_node->columns;
u16_t i = table_node->column_count;
while (i > 0) {
if (col_def->index == instance->instance_oid.id[1]) {
break;
}
col_def++;
i--;
}
if (i > 0) {
/* everything may be overwritten by get_cell_instance_method() in order to implement special handling for single columns/cells */
instance->asn1_type = col_def->asn1_type;
instance->access = col_def->access;
instance->get_value = table_node->get_value;
instance->set_test = table_node->set_test;
instance->set_value = table_node->set_value;
ret = table_node->get_cell_instance(
&(instance->instance_oid.id[1]),
&(instance->instance_oid.id[2]),
instance->instance_oid.len-2,
instance);
}
}
return ret;
}
snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
const struct snmp_table_node* table_node = (const struct snmp_table_node*)(const void*)instance->node;
const struct snmp_table_col_def* col_def;
struct snmp_obj_id row_oid;
u32_t column = 0;
snmp_err_t result;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
/* check that first part of id is 0 or 1, referencing fixed row entry */
if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1)) {
return SNMP_ERR_NOSUCHINSTANCE;
}
if (instance->instance_oid.len > 1) {
column = instance->instance_oid.id[1];
}
if (instance->instance_oid.len > 2) {
snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2);
} else {
row_oid.len = 0;
}
instance->get_value = table_node->get_value;
instance->set_test = table_node->set_test;
instance->set_value = table_node->set_value;
/* resolve column and value */
do {
u16_t i;
const struct snmp_table_col_def* next_col_def = NULL;
col_def = table_node->columns;
for (i = 0; i < table_node->column_count; i++) {
if (col_def->index == column) {
next_col_def = col_def;
break;
} else if ((col_def->index > column) && ((next_col_def == NULL) || (col_def->index < next_col_def->index))) {
next_col_def = col_def;
}
col_def++;
}
if (next_col_def == NULL) {
/* no further column found */
return SNMP_ERR_NOSUCHINSTANCE;
}
instance->asn1_type = next_col_def->asn1_type;
instance->access = next_col_def->access;
result = table_node->get_next_cell_instance(
&next_col_def->index,
&row_oid,
instance);
if (result == SNMP_ERR_NOERROR) {
col_def = next_col_def;
break;
}
row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */
column = next_col_def->index + 1;
} while (1);
/* build resulting oid */
instance->instance_oid.len = 2;
instance->instance_oid.id[0] = 1;
instance->instance_oid.id[1] = col_def->index;
snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len);
return SNMP_ERR_NOERROR;
}
snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE;
const struct snmp_table_simple_node* table_node = (const struct snmp_table_simple_node*)(const void*)instance->node;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
/* check min. length (fixed row entry definition, column, row instance oid with at least one entry */
/* fixed row entry always has oid 1 */
if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1)) {
ret = table_node->get_cell_value(
&(instance->instance_oid.id[1]),
&(instance->instance_oid.id[2]),
instance->instance_oid.len-2,
&instance->reference,
&instance->reference_len);
if (ret == SNMP_ERR_NOERROR) {
/* search column */
const struct snmp_table_simple_col_def* col_def = table_node->columns;
u32_t i = table_node->column_count;
while (i > 0) {
if (col_def->index == instance->instance_oid.id[1]) {
break;
}
col_def++;
i--;
}
if (i > 0) {
instance->asn1_type = col_def->asn1_type;
instance->access = SNMP_NODE_INSTANCE_READ_ONLY;
instance->set_test = NULL;
instance->set_value = NULL;
switch (col_def->data_type) {
case SNMP_VARIANT_VALUE_TYPE_U32:
instance->get_value = snmp_table_extract_value_from_u32ref;
break;
case SNMP_VARIANT_VALUE_TYPE_S32:
instance->get_value = snmp_table_extract_value_from_s32ref;
break;
case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */
case SNMP_VARIANT_VALUE_TYPE_CONST_PTR:
instance->get_value = snmp_table_extract_value_from_refconstptr;
break;
default:
LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type));
return SNMP_ERR_GENERROR;
}
ret = SNMP_ERR_NOERROR;
} else {
ret = SNMP_ERR_NOSUCHINSTANCE;
}
}
}
return ret;
}
snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
const struct snmp_table_simple_node* table_node = (const struct snmp_table_simple_node*)(const void*)instance->node;
const struct snmp_table_simple_col_def* col_def;
struct snmp_obj_id row_oid;
u32_t column = 0;
snmp_err_t result;
LWIP_UNUSED_ARG(root_oid);
LWIP_UNUSED_ARG(root_oid_len);
/* check that first part of id is 0 or 1, referencing fixed row entry */
if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1)) {
return SNMP_ERR_NOSUCHINSTANCE;
}
if (instance->instance_oid.len > 1) {
column = instance->instance_oid.id[1];
}
if (instance->instance_oid.len > 2) {
snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2);
} else {
row_oid.len = 0;
}
/* resolve column and value */
do {
u32_t i;
const struct snmp_table_simple_col_def* next_col_def = NULL;
col_def = table_node->columns;
for (i = 0; i < table_node->column_count; i++) {
if (col_def->index == column) {
next_col_def = col_def;
break;
} else if ((col_def->index > column) && ((next_col_def == NULL) ||
(col_def->index < next_col_def->index))) {
next_col_def = col_def;
}
col_def++;
}
if (next_col_def == NULL) {
/* no further column found */
return SNMP_ERR_NOSUCHINSTANCE;
}
result = table_node->get_next_cell_instance_and_value(
&next_col_def->index,
&row_oid,
&instance->reference,
&instance->reference_len);
if (result == SNMP_ERR_NOERROR) {
col_def = next_col_def;
break;
}
row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */
column = next_col_def->index + 1;
}
while (1);
instance->asn1_type = col_def->asn1_type;
instance->access = SNMP_NODE_INSTANCE_READ_ONLY;
instance->set_test = NULL;
instance->set_value = NULL;
switch (col_def->data_type) {
case SNMP_VARIANT_VALUE_TYPE_U32:
instance->get_value = snmp_table_extract_value_from_u32ref;
break;
case SNMP_VARIANT_VALUE_TYPE_S32:
instance->get_value = snmp_table_extract_value_from_s32ref;
break;
case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */
case SNMP_VARIANT_VALUE_TYPE_CONST_PTR:
instance->get_value = snmp_table_extract_value_from_refconstptr;
break;
default:
LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type));
return SNMP_ERR_GENERROR;
}
/* build resulting oid */
instance->instance_oid.len = 2;
instance->instance_oid.id[0] = 1;
instance->instance_oid.id[1] = col_def->index;
snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len);
return SNMP_ERR_NOERROR;
}
s16_t
snmp_table_extract_value_from_s32ref(struct snmp_node_instance* instance, void* value)
{
s32_t *dst = (s32_t*)value;
*dst = instance->reference.s32;
return sizeof(*dst);
}
s16_t
snmp_table_extract_value_from_u32ref(struct snmp_node_instance* instance, void* value)
{
u32_t *dst = (u32_t*)value;
*dst = instance->reference.u32;
return sizeof(*dst);
}
s16_t
snmp_table_extract_value_from_refconstptr(struct snmp_node_instance* instance, void* value)
{
MEMCPY(value, instance->reference.const_ptr, instance->reference_len);
return (u16_t)instance->reference_len;
}
#endif /* LWIP_SNMP */

View File

@@ -0,0 +1,219 @@
/**
* @file
* SNMP thread synchronization implementation.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Dirk Ziegelmeier <dziegel@gmx.de>
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP && (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */
#include "lwip/apps/snmp_threadsync.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/sys.h"
#include <string.h>
static void
call_synced_function(struct threadsync_data *call_data, snmp_threadsync_called_fn fn)
{
sys_mutex_lock(&call_data->threadsync_node->instance->sem_usage_mutex);
call_data->threadsync_node->instance->sync_fn(fn, call_data);
sys_sem_wait(&call_data->threadsync_node->instance->sem);
sys_mutex_unlock(&call_data->threadsync_node->instance->sem_usage_mutex);
}
static void
threadsync_get_value_synced(void *ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
call_data->retval.s16 = call_data->proxy_instance.get_value(&call_data->proxy_instance, call_data->arg1.value);
sys_sem_signal(&call_data->threadsync_node->instance->sem);
}
static s16_t
threadsync_get_value(struct snmp_node_instance* instance, void* value)
{
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
call_data->arg1.value = value;
call_synced_function(call_data, threadsync_get_value_synced);
return call_data->retval.s16;
}
static void
threadsync_set_test_synced(void *ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
call_data->retval.err = call_data->proxy_instance.set_test(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value);
sys_sem_signal(&call_data->threadsync_node->instance->sem);
}
static snmp_err_t
threadsync_set_test(struct snmp_node_instance* instance, u16_t len, void *value)
{
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
call_data->arg1.value = value;
call_data->arg2.len = len;
call_synced_function(call_data, threadsync_set_test_synced);
return call_data->retval.err;
}
static void
threadsync_set_value_synced(void *ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
call_data->retval.err = call_data->proxy_instance.set_value(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value);
sys_sem_signal(&call_data->threadsync_node->instance->sem);
}
static snmp_err_t
threadsync_set_value(struct snmp_node_instance* instance, u16_t len, void *value)
{
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
call_data->arg1.value = value;
call_data->arg2.len = len;
call_synced_function(call_data, threadsync_set_value_synced);
return call_data->retval.err;
}
static void
threadsync_release_instance_synced(void* ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
call_data->proxy_instance.release_instance(&call_data->proxy_instance);
sys_sem_signal(&call_data->threadsync_node->instance->sem);
}
static void
threadsync_release_instance(struct snmp_node_instance *instance)
{
struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr;
if (call_data->proxy_instance.release_instance != NULL) {
call_synced_function(call_data, threadsync_release_instance_synced);
}
}
static void
get_instance_synced(void* ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
const struct snmp_leaf_node *leaf = (const struct snmp_leaf_node*)(const void*)call_data->proxy_instance.node;
call_data->retval.err = leaf->get_instance(call_data->arg1.root_oid, call_data->arg2.root_oid_len, &call_data->proxy_instance);
sys_sem_signal(&call_data->threadsync_node->instance->sem);
}
static void
get_next_instance_synced(void* ctx)
{
struct threadsync_data *call_data = (struct threadsync_data*)ctx;
const struct snmp_leaf_node *leaf = (const struct snmp_leaf_node*)(const void*)call_data->proxy_instance.node;
call_data->retval.err = leaf->get_next_instance(call_data->arg1.root_oid, call_data->arg2.root_oid_len, &call_data->proxy_instance);
sys_sem_signal(&call_data->threadsync_node->instance->sem);
}
static snmp_err_t
do_sync(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance, snmp_threadsync_called_fn fn)
{
const struct snmp_threadsync_node *threadsync_node = (const struct snmp_threadsync_node*)(const void*)instance->node;
struct threadsync_data *call_data = &threadsync_node->instance->data;
if (threadsync_node->node.node.oid != threadsync_node->target->node.oid) {
LWIP_DEBUGF(SNMP_DEBUG, ("Sync node OID does not match target node OID"));
return SNMP_ERR_NOSUCHINSTANCE;
}
memset(&call_data->proxy_instance, 0, sizeof(call_data->proxy_instance));
instance->reference.ptr = call_data;
snmp_oid_assign(&call_data->proxy_instance.instance_oid, instance->instance_oid.id, instance->instance_oid.len);
call_data->proxy_instance.node = &threadsync_node->target->node;
call_data->threadsync_node = threadsync_node;
call_data->arg1.root_oid = root_oid;
call_data->arg2.root_oid_len = root_oid_len;
call_synced_function(call_data, fn);
if (call_data->retval.err == SNMP_ERR_NOERROR) {
instance->access = call_data->proxy_instance.access;
instance->asn1_type = call_data->proxy_instance.asn1_type;
instance->release_instance = threadsync_release_instance;
instance->get_value = (call_data->proxy_instance.get_value != NULL)? threadsync_get_value : NULL;
instance->set_value = (call_data->proxy_instance.set_value != NULL)? threadsync_set_value : NULL;
instance->set_test = (call_data->proxy_instance.set_test != NULL)? threadsync_set_test : NULL;
snmp_oid_assign(&instance->instance_oid, call_data->proxy_instance.instance_oid.id, call_data->proxy_instance.instance_oid.len);
}
return call_data->retval.err;
}
snmp_err_t
snmp_threadsync_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
return do_sync(root_oid, root_oid_len, instance, get_instance_synced);
}
snmp_err_t
snmp_threadsync_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
return do_sync(root_oid, root_oid_len, instance, get_next_instance_synced);
}
/** Initializes thread synchronization instance */
void snmp_threadsync_init(struct snmp_threadsync_instance *instance, snmp_threadsync_synchronizer_fn sync_fn)
{
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;
}
#endif /* LWIP_SNMP */

View File

@@ -0,0 +1,445 @@
/**
* @file
* SNMPv1 traps implementation.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel
* Christiaan Simons <christiaan.simons@axon.tv>
*
*/
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include <string.h>
#include "lwip/snmp.h"
#include "lwip/sys.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "snmp_msg.h"
#include "snmp_asn1.h"
#include "snmp_core_priv.h"
struct snmp_msg_trap
{
/* source enterprise ID (sysObjectID) */
const struct snmp_obj_id *enterprise;
/* source IP address, raw network order format */
ip_addr_t sip;
/* generic trap code */
u32_t gen_trap;
/* specific trap code */
u32_t spc_trap;
/* timestamp */
u32_t ts;
/* snmp_version */
u32_t snmp_version;
/* output trap lengths used in ASN encoding */
/* encoding pdu length */
u16_t pdulen;
/* encoding community length */
u16_t comlen;
/* encoding sequence length */
u16_t seqlen;
/* encoding varbinds sequence length */
u16_t vbseqlen;
};
static u16_t snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds);
static u16_t snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len);
static void snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream);
static void snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds);
/** Agent community string for sending traps */
extern const char *snmp_community_trap;
void* snmp_traps_handle;
struct snmp_trap_dst
{
/* destination IP address in network order */
ip_addr_t dip;
/* set to 0 when disabled, >0 when enabled */
u8_t enable;
};
static struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS];
static u8_t snmp_auth_traps_enabled = 0;
/**
* @ingroup snmp_traps
* Sets enable switch for this trap destination.
* @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
* @param enable switch if 0 destination is disabled >0 enabled.
*/
void
snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)
{
if (dst_idx < SNMP_TRAP_DESTINATIONS) {
trap_dst[dst_idx].enable = enable;
}
}
/**
* @ingroup snmp_traps
* Sets IPv4 address for this trap destination.
* @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
* @param dst IPv4 address in host order.
*/
void
snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst)
{
if (dst_idx < SNMP_TRAP_DESTINATIONS) {
ip_addr_set(&trap_dst[dst_idx].dip, dst);
}
}
/**
* @ingroup snmp_traps
* Enable/disable authentication traps
*/
void
snmp_set_auth_traps_enabled(u8_t enable)
{
snmp_auth_traps_enabled = enable;
}
/**
* @ingroup snmp_traps
* Get authentication traps enabled state
*/
u8_t
snmp_get_auth_traps_enabled(void)
{
return snmp_auth_traps_enabled;
}
/**
* @ingroup snmp_traps
* Sends a generic or enterprise specific trap message.
*
* @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
* is per RFC1215.
* Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps
* and .iso.org.dod.internet.private.enterprises.yourenterprise
* (sysObjectID) for specific traps.
*/
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;
struct pbuf *p;
u16_t i, tot_len;
err_t err = ERR_OK;
trap_msg.snmp_version = 0;
for (i = 0, td = &trap_dst[0]; i < SNMP_TRAP_DESTINATIONS; i++, td++) {
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 (eoid == NULL) {
trap_msg.enterprise = snmp_get_device_enterprise_oid();
} else {
trap_msg.enterprise = eoid;
}
trap_msg.gen_trap = generic_trap;
if (generic_trap == SNMP_GENTRAP_ENTERPRISE_SPECIFIC) {
trap_msg.spc_trap = specific_trap;
} else {
trap_msg.spc_trap = 0;
}
MIB2_COPY_SYSUPTIME_TO(&trap_msg.ts);
/* pass 0, calculate length fields */
tot_len = snmp_trap_varbind_sum(&trap_msg, varbinds);
tot_len = snmp_trap_header_sum(&trap_msg, tot_len);
/* allocate pbuf(s) */
p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_RAM);
if (p != NULL) {
struct snmp_pbuf_stream pbuf_stream;
snmp_pbuf_stream_init(&pbuf_stream, p, 0, tot_len);
/* pass 1, encode packet ino the pbuf(s) */
snmp_trap_header_enc(&trap_msg, &pbuf_stream);
snmp_trap_varbind_enc(&trap_msg, &pbuf_stream, varbinds);
snmp_stats.outtraps++;
snmp_stats.outpkts++;
/** send to the TRAP destination */
snmp_sendto(snmp_traps_handle, p, &td->dip, SNMP_TRAP_PORT);
pbuf_free(p);
} else {
err = ERR_MEM;
}
} else {
/* routing error */
err = ERR_RTE;
}
}
}
return err;
}
/**
* @ingroup snmp_traps
* Send generic SNMP trap
*/
err_t
snmp_send_trap_generic(s32_t generic_trap)
{
static const struct snmp_obj_id oid = { 7, { 1, 3, 6, 1, 2, 1, 11 } };
return snmp_send_trap(&oid, generic_trap, 0, NULL);
}
/**
* @ingroup snmp_traps
* Send specific SNMP trap with variable bindings
*/
err_t
snmp_send_trap_specific(s32_t specific_trap, struct snmp_varbind *varbinds)
{
return snmp_send_trap(NULL, SNMP_GENTRAP_ENTERPRISE_SPECIFIC, specific_trap, varbinds);
}
/**
* @ingroup snmp_traps
* Send coldstart trap
*/
void
snmp_coldstart_trap(void)
{
snmp_send_trap_generic(SNMP_GENTRAP_COLDSTART);
}
/**
* @ingroup snmp_traps
* Send authentication failure trap (used internally by agent)
*/
void
snmp_authfail_trap(void)
{
if (snmp_auth_traps_enabled != 0) {
snmp_send_trap_generic(SNMP_GENTRAP_AUTH_FAILURE);
}
}
static u16_t
snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds)
{
struct snmp_varbind *varbind;
u16_t tot_len;
u8_t tot_len_len;
tot_len = 0;
varbind = varbinds;
while (varbind != NULL) {
struct snmp_varbind_len len;
if (snmp_varbind_length(varbind, &len) == ERR_OK) {
tot_len += 1 + len.vb_len_len + len.vb_value_len;
}
varbind = varbind->next;
}
trap->vbseqlen = tot_len;
snmp_asn1_enc_length_cnt(trap->vbseqlen, &tot_len_len);
tot_len += 1 + tot_len_len;
return tot_len;
}
/**
* 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
* @return the required length for encoding the trap header
*/
static u16_t
snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len)
{
u16_t tot_len;
u16_t len;
u8_t lenlen;
tot_len = vb_len;
snmp_asn1_enc_u32t_cnt(trap->ts, &len);
snmp_asn1_enc_length_cnt(len, &lenlen);
tot_len += 1 + len + lenlen;
snmp_asn1_enc_s32t_cnt(trap->spc_trap, &len);
snmp_asn1_enc_length_cnt(len, &lenlen);
tot_len += 1 + len + lenlen;
snmp_asn1_enc_s32t_cnt(trap->gen_trap, &len);
snmp_asn1_enc_length_cnt(len, &lenlen);
tot_len += 1 + len + lenlen;
if (IP_IS_V6_VAL(trap->sip)) {
#if LWIP_IPV6
len = sizeof(ip_2_ip6(&trap->sip)->addr);
#endif
} else {
#if LWIP_IPV4
len = sizeof(ip_2_ip4(&trap->sip)->addr);
#endif
}
snmp_asn1_enc_length_cnt(len, &lenlen);
tot_len += 1 + len + lenlen;
snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &len);
snmp_asn1_enc_length_cnt(len, &lenlen);
tot_len += 1 + len + lenlen;
trap->pdulen = tot_len;
snmp_asn1_enc_length_cnt(trap->pdulen, &lenlen);
tot_len += 1 + lenlen;
trap->comlen = (u16_t)LWIP_MIN(strlen(snmp_community_trap), 0xFFFF);
snmp_asn1_enc_length_cnt(trap->comlen, &lenlen);
tot_len += 1 + lenlen + trap->comlen;
snmp_asn1_enc_s32t_cnt(trap->snmp_version, &len);
snmp_asn1_enc_length_cnt(len, &lenlen);
tot_len += 1 + len + lenlen;
trap->seqlen = tot_len;
snmp_asn1_enc_length_cnt(trap->seqlen, &lenlen);
tot_len += 1 + lenlen;
return tot_len;
}
static void
snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds)
{
struct snmp_asn1_tlv tlv;
struct snmp_varbind *varbind;
varbind = varbinds;
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->vbseqlen);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
while (varbind != NULL) {
snmp_append_outbound_varbind(pbuf_stream, varbind);
varbind = varbind->next;
}
}
/**
* Encodes trap header from head to tail.
*/
static void
snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream)
{
struct snmp_asn1_tlv tlv;
/* 'Message' sequence */
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->seqlen);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
/* version */
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
snmp_asn1_enc_s32t_cnt(trap->snmp_version, &tlv.value_len);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->snmp_version);
/* community */
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, trap->comlen);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)snmp_community_trap, trap->comlen);
/* 'PDU' sequence */
SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_TRAP), 0, trap->pdulen);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
/* object ID */
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, 0, 0);
snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &tlv.value_len);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_oid(pbuf_stream, trap->enterprise->id, trap->enterprise->len);
/* IP addr */
if (IP_IS_V6_VAL(trap->sip)) {
#if LWIP_IPV6
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip6(&trap->sip)->addr));
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip6(&trap->sip)->addr, sizeof(ip_2_ip6(&trap->sip)->addr));
#endif
} else {
#if LWIP_IPV4
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip4(&trap->sip)->addr));
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip4(&trap->sip)->addr, sizeof(ip_2_ip4(&trap->sip)->addr));
#endif
}
/* trap length */
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
snmp_asn1_enc_s32t_cnt(trap->gen_trap, &tlv.value_len);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->gen_trap);
/* specific trap */
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
snmp_asn1_enc_s32t_cnt(trap->spc_trap, &tlv.value_len);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->spc_trap);
/* timestamp */
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_TIMETICKS, 0, 0);
snmp_asn1_enc_s32t_cnt(trap->ts, &tlv.value_len);
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->ts);
}
#endif /* LWIP_SNMP */

136
ext/lwip/src/apps/snmp/snmpv3.c Executable file
View File

@@ -0,0 +1,136 @@
/**
* @file
* Additional SNMPv3 functionality RFC3414 and RFC3826.
*/
/*
* Copyright (c) 2016 Elias Oenal.
* 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: Elias Oenal <lwip@eliasoenal.com>
*/
#include "snmpv3_priv.h"
#include "lwip/apps/snmpv3.h"
#include "lwip/sys.h"
#include <string.h>
#if LWIP_SNMP && LWIP_SNMP_V3
#ifdef LWIP_SNMPV3_INCLUDE_ENGINE
#include LWIP_SNMPV3_INCLUDE_ENGINE
#endif
#define SNMP_MAX_TIME_BOOT 2147483647UL
/** Call this if engine has been changed. Has to reset boots, see below */
void
snmpv3_engine_id_changed(void)
{
snmpv3_set_engine_boots(0);
}
/** According to RFC3414 2.2.2.
*
* The number of times that the SNMP engine has
* (re-)initialized itself since snmpEngineID
* was last configured.
*/
u32_t
snmpv3_get_engine_boots_internal(void)
{
if (snmpv3_get_engine_boots() == 0 ||
snmpv3_get_engine_boots() < SNMP_MAX_TIME_BOOT) {
return snmpv3_get_engine_boots();
}
snmpv3_set_engine_boots(SNMP_MAX_TIME_BOOT);
return snmpv3_get_engine_boots();
}
/** RFC3414 2.2.2.
*
* Once the timer reaches 2147483647 it gets reset to zero and the
* engine boot ups get incremented.
*/
u32_t
snmpv3_get_engine_time_internal(void)
{
if (snmpv3_get_engine_time() >= SNMP_MAX_TIME_BOOT) {
snmpv3_reset_engine_time();
if (snmpv3_get_engine_boots() < SNMP_MAX_TIME_BOOT - 1) {
snmpv3_set_engine_boots(snmpv3_get_engine_boots() + 1);
} else {
snmpv3_set_engine_boots(SNMP_MAX_TIME_BOOT);
}
}
return snmpv3_get_engine_time();
}
#if LWIP_SNMP_V3_CRYPTO
/* This function ignores the byte order suggestion in RFC3414
* since it simply doesn't influence the effectiveness of an IV.
*
* Implementing RFC3826 priv param algorithm if LWIP_RAND is available.
*
* @todo: This is a potential thread safety issue.
*/
err_t
snmpv3_build_priv_param(u8_t* priv_param)
{
#ifdef LWIP_RAND /* Based on RFC3826 */
static u8_t init;
static u32_t priv1, priv2;
/* Lazy initialisation */
if (init == 0) {
init = 1;
priv1 = LWIP_RAND();
priv2 = LWIP_RAND();
}
SMEMCPY(&priv_param[0], &priv1, sizeof(priv1));
SMEMCPY(&priv_param[4], &priv2, sizeof(priv2));
/* Emulate 64bit increment */
priv1++;
if (!priv1) { /* Overflow */
priv2++;
}
#else /* Based on RFC3414 */
static u32_t ctr;
u32_t boots = LWIP_SNMPV3_GET_ENGINE_BOOTS();
SMEMCPY(&priv_param[0], &boots, 4);
SMEMCPY(&priv_param[4], &ctr, 4);
ctr++;
#endif
return ERR_OK;
}
#endif /* LWIP_SNMP_V3_CRYPTO */
#endif

View File

@@ -0,0 +1,145 @@
/**
* @file
* Dummy SNMPv3 functions.
*/
/*
* Copyright (c) 2016 Elias Oenal.
* 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: Elias Oenal <lwip@eliasoenal.com>
* Dirk Ziegelmeier <dirk@ziegelmeier.net>
*/
#include "lwip/apps/snmpv3.h"
#include "snmpv3_priv.h"
#include <string.h>
#include "lwip/err.h"
#if LWIP_SNMP && LWIP_SNMP_V3
/**
* @param username is a pointer to a string.
* @param auth_algo is a pointer to u8_t. The implementation has to set this if user was found.
* @param auth_key is a pointer to a pointer to a string. Implementation has to set this if user was found.
* @param priv_algo is a pointer to u8_t. The implementation has to set this if user was found.
* @param priv_key is a pointer to a pointer to a string. Implementation has to set this if user was found.
*/
err_t
snmpv3_get_user(const char* username, u8_t *auth_algo, u8_t *auth_key, u8_t *priv_algo, u8_t *priv_key)
{
const char* engine_id;
u8_t engine_id_len;
if(strlen(username) == 0) {
return ERR_OK;
}
if(memcmp(username, "lwip", 4) != 0) {
return ERR_VAL;
}
snmpv3_get_engine_id(&engine_id, &engine_id_len);
if(auth_key != NULL) {
snmpv3_password_to_key_sha((const u8_t*)"maplesyrup", 10,
(const u8_t*)engine_id, engine_id_len,
auth_key);
*auth_algo = SNMP_V3_AUTH_ALGO_SHA;
}
if(priv_key != NULL) {
snmpv3_password_to_key_sha((const u8_t*)"maplesyrup", 10,
(const u8_t*)engine_id, engine_id_len,
priv_key);
*priv_algo = SNMP_V3_PRIV_ALGO_DES;
}
return ERR_OK;
}
/**
* Get engine ID from persistence
* @param id
* @param len
*/
void
snmpv3_get_engine_id(const char **id, u8_t *len)
{
*id = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02";
*len = 12;
}
/**
* Store engine ID in persistence
* @param id
* @param len
*/
err_t
snmpv3_set_engine_id(const char *id, u8_t len)
{
LWIP_UNUSED_ARG(id);
LWIP_UNUSED_ARG(len);
return ERR_OK;
}
/**
* Get engine boots from persistence. Must be increased on each boot.
* @return
*/
u32_t
snmpv3_get_engine_boots(void)
{
return 0;
}
/**
* Store engine boots in persistence
* @param boots
*/
void
snmpv3_set_engine_boots(u32_t boots)
{
LWIP_UNUSED_ARG(boots);
}
/**
* RFC3414 2.2.2.
* Once the timer reaches 2147483647 it gets reset to zero and the
* engine boot ups get incremented.
*/
u32_t
snmpv3_get_engine_time(void)
{
return 0;
}
/**
* Reset current engine time to 0
*/
void
snmpv3_reset_engine_time(void)
{
}
#endif /* LWIP_SNMP && LWIP_SNMP_V3 */

View File

@@ -0,0 +1,331 @@
/**
* @file
* SNMPv3 crypto/auth functions implemented for ARM mbedtls.
*/
/*
* Copyright (c) 2016 Elias Oenal and Dirk Ziegelmeier.
* 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: Elias Oenal <lwip@eliasoenal.com>
* Dirk Ziegelmeier <dirk@ziegelmeier.net>
*/
#include "lwip/apps/snmpv3.h"
#include "snmpv3_priv.h"
#include "lwip/arch.h"
#include "snmp_msg.h"
#include "lwip/sys.h"
#include <string.h>
#if LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS
#include "mbedtls/md.h"
#include "mbedtls/cipher.h"
#include "mbedtls/md5.h"
#include "mbedtls/sha1.h"
err_t
snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length,
const u8_t* key, u8_t algo, u8_t* hmac_out)
{
u32_t i;
u8_t key_len;
const mbedtls_md_info_t *md_info;
mbedtls_md_context_t ctx;
struct snmp_pbuf_stream read_stream;
snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length);
if (algo == SNMP_V3_AUTH_ALGO_MD5) {
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5);
key_len = SNMP_V3_MD5_LEN;
} else if (algo == SNMP_V3_AUTH_ALGO_SHA) {
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
key_len = SNMP_V3_SHA_LEN;
} else {
return ERR_ARG;
}
mbedtls_md_init(&ctx);
if(mbedtls_md_setup(&ctx, md_info, 1) != 0) {
return ERR_ARG;
}
if (mbedtls_md_hmac_starts(&ctx, key, key_len) != 0) {
goto free_md;
}
for (i = 0; i < length; i++) {
u8_t byte;
if (snmp_pbuf_stream_read(&read_stream, &byte)) {
goto free_md;
}
if (mbedtls_md_hmac_update(&ctx, &byte, 1) != 0) {
goto free_md;
}
}
if (mbedtls_md_hmac_finish(&ctx, hmac_out) != 0) {
goto free_md;
}
mbedtls_md_free(&ctx);
return ERR_OK;
free_md:
mbedtls_md_free(&ctx);
return ERR_ARG;
}
#if LWIP_SNMP_V3_CRYPTO
err_t
snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length,
const u8_t* key, const u8_t* priv_param, const u32_t engine_boots,
const u32_t engine_time, u8_t algo, u8_t mode)
{
size_t i;
mbedtls_cipher_context_t ctx;
const mbedtls_cipher_info_t *cipher_info;
struct snmp_pbuf_stream read_stream;
struct snmp_pbuf_stream write_stream;
snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length);
snmp_pbuf_stream_init(&write_stream, stream->pbuf, stream->offset, stream->length);
mbedtls_cipher_init(&ctx);
if (algo == SNMP_V3_PRIV_ALGO_DES) {
u8_t iv_local[8];
u8_t out_bytes[8];
size_t out_len;
/* RFC 3414 mandates padding for DES */
if ((length & 0x07) != 0) {
return ERR_ARG;
}
cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_DES_CBC);
if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) {
return ERR_ARG;
}
if(mbedtls_cipher_set_padding_mode(&ctx, MBEDTLS_PADDING_NONE) != 0) {
return ERR_ARG;
}
if(mbedtls_cipher_setkey(&ctx, key, 8*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) {
goto error;
}
/* Prepare IV */
for (i = 0; i < LWIP_ARRAYSIZE(iv_local); i++) {
iv_local[i] = priv_param[i] ^ key[i + 8];
}
if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) {
goto error;
}
for (i = 0; i < length; i += 8) {
size_t j;
u8_t in_bytes[8];
out_len = LWIP_ARRAYSIZE(out_bytes) ;
for (j = 0; j < LWIP_ARRAYSIZE(in_bytes); j++) {
snmp_pbuf_stream_read(&read_stream, &in_bytes[j]);
}
if(mbedtls_cipher_update(&ctx, in_bytes, LWIP_ARRAYSIZE(in_bytes), out_bytes, &out_len) != 0) {
goto error;
}
snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len);
}
out_len = LWIP_ARRAYSIZE(out_bytes);
if(mbedtls_cipher_finish(&ctx, out_bytes, &out_len) != 0) {
goto error;
}
snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len);
} else if (algo == SNMP_V3_PRIV_ALGO_AES) {
u8_t iv_local[16];
cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CFB128);
if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) {
return ERR_ARG;
}
if(mbedtls_cipher_setkey(&ctx, key, 16*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) {
goto error;
}
/*
* IV is the big endian concatenation of boots,
* uptime and priv param - see RFC3826.
*/
iv_local[0 + 0] = (engine_boots >> 24) & 0xFF;
iv_local[0 + 1] = (engine_boots >> 16) & 0xFF;
iv_local[0 + 2] = (engine_boots >> 8) & 0xFF;
iv_local[0 + 3] = (engine_boots >> 0) & 0xFF;
iv_local[4 + 0] = (engine_time >> 24) & 0xFF;
iv_local[4 + 1] = (engine_time >> 16) & 0xFF;
iv_local[4 + 2] = (engine_time >> 8) & 0xFF;
iv_local[4 + 3] = (engine_time >> 0) & 0xFF;
SMEMCPY(iv_local + 8, priv_param, 8);
if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) {
goto error;
}
for (i = 0; i < length; i++) {
u8_t in_byte;
u8_t out_byte;
size_t out_len = sizeof(out_byte);
snmp_pbuf_stream_read(&read_stream, &in_byte);
if(mbedtls_cipher_update(&ctx, &in_byte, sizeof(in_byte), &out_byte, &out_len) != 0) {
goto error;
}
snmp_pbuf_stream_write(&write_stream, out_byte);
}
} else {
return ERR_ARG;
}
mbedtls_cipher_free(&ctx);
return ERR_OK;
error:
mbedtls_cipher_free(&ctx);
return ERR_OK;
}
#endif /* LWIP_SNMP_V3_CRYPTO */
/* A.2.1. Password to Key Sample Code for MD5 */
void
snmpv3_password_to_key_md5(
const u8_t *password, /* IN */
u8_t passwordlen, /* IN */
const u8_t *engineID, /* IN - pointer to snmpEngineID */
u8_t engineLength,/* IN - length of snmpEngineID */
u8_t *key) /* OUT - pointer to caller 16-octet buffer */
{
mbedtls_md5_context MD;
u8_t *cp, password_buf[64];
u32_t password_index = 0;
u8_t i;
u32_t count = 0;
mbedtls_md5_init(&MD); /* initialize MD5 */
mbedtls_md5_starts(&MD);
/**********************************************/
/* Use while loop until we've done 1 Megabyte */
/**********************************************/
while (count < 1048576) {
cp = password_buf;
for (i = 0; i < 64; i++) {
/*************************************************/
/* Take the next octet of the password, wrapping */
/* to the beginning of the password as necessary.*/
/*************************************************/
*cp++ = password[password_index++ % passwordlen];
}
mbedtls_md5_update(&MD, password_buf, 64);
count += 64;
}
mbedtls_md5_finish(&MD, key); /* tell MD5 we're done */
/*****************************************************/
/* Now localize the key with the engineID and pass */
/* through MD5 to produce final key */
/* May want to ensure that engineLength <= 32, */
/* otherwise need to use a buffer larger than 64 */
/*****************************************************/
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);
mbedtls_md5_finish(&MD, key);
mbedtls_md5_free(&MD);
return;
}
/* A.2.2. Password to Key Sample Code for SHA */
void
snmpv3_password_to_key_sha(
const u8_t *password, /* IN */
u8_t passwordlen, /* IN */
const u8_t *engineID, /* IN - pointer to snmpEngineID */
u8_t engineLength,/* IN - length of snmpEngineID */
u8_t *key) /* OUT - pointer to caller 20-octet buffer */
{
mbedtls_sha1_context SH;
u8_t *cp, password_buf[72];
u32_t password_index = 0;
u8_t i;
u32_t count = 0;
mbedtls_sha1_init(&SH); /* initialize SHA */
mbedtls_sha1_starts(&SH);
/**********************************************/
/* Use while loop until we've done 1 Megabyte */
/**********************************************/
while (count < 1048576) {
cp = password_buf;
for (i = 0; i < 64; i++) {
/*************************************************/
/* Take the next octet of the password, wrapping */
/* to the beginning of the password as necessary.*/
/*************************************************/
*cp++ = password[password_index++ % passwordlen];
}
mbedtls_sha1_update(&SH, password_buf, 64);
count += 64;
}
mbedtls_sha1_finish(&SH, key); /* tell SHA we're done */
/*****************************************************/
/* Now localize the key with the engineID and pass */
/* through SHA to produce final key */
/* May want to ensure that engineLength <= 32, */
/* otherwise need to use a buffer larger than 72 */
/*****************************************************/
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);
mbedtls_sha1_finish(&SH, key);
mbedtls_sha1_free(&SH);
return;
}
#endif /* LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS */

View File

@@ -0,0 +1,66 @@
/**
* @file
* Additional SNMPv3 functionality RFC3414 and RFC3826 (internal API, do not use in client code).
*/
/*
* Copyright (c) 2016 Elias Oenal.
* 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: Elias Oenal <lwip@eliasoenal.com>
*/
#ifndef LWIP_HDR_APPS_SNMP_V3_PRIV_H
#define LWIP_HDR_APPS_SNMP_V3_PRIV_H
#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP && LWIP_SNMP_V3
#include "snmp_pbuf_stream.h"
/* According to RFC 3411 */
#define SNMP_V3_MAX_ENGINE_ID_LENGTH 32
#define SNMP_V3_MAX_USER_LENGTH 32
#define SNMP_V3_MAX_AUTH_PARAM_LENGTH 12
#define SNMP_V3_MAX_PRIV_PARAM_LENGTH 8
#define SNMP_V3_AUTH_FLAG 0x01
#define SNMP_V3_PRIV_FLAG 0x02
#define SNMP_V3_MD5_LEN 16
#define SNMP_V3_SHA_LEN 20
u32_t snmpv3_get_engine_boots_internal(void);
u32_t snmpv3_get_engine_time_internal(void);
err_t snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key, u8_t algo, u8_t* hmac_out);
err_t snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key,
const u8_t* priv_param, const u32_t engine_boots, const u32_t engine_time, u8_t algo, u8_t mode);
err_t snmpv3_build_priv_param(u8_t* priv_param);
#endif
#endif /* LWIP_HDR_APPS_SNMP_V3_PRIV_H */

727
ext/lwip/src/apps/sntp/sntp.c Executable file
View File

@@ -0,0 +1,727 @@
/**
* @file
* SNTP client module
*/
/*
* Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt
* 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: Frédéric Bernon, Simon Goldschmidt
*/
/**
* @defgroup sntp SNTP
* @ingroup apps
*
* This is simple "SNTP" client for the lwIP raw API.
* It is a minimal implementation of SNTPv4 as specified in RFC 4330.
*
* For a list of some public NTP servers, see this link :
* http://support.ntp.org/bin/view/Servers/NTPPoolServers
*
* @todo:
* - set/change servers at runtime
* - complete SNTP_CHECK_RESPONSE checks 3 and 4
*/
#include "lwip/apps/sntp.h"
#include "lwip/opt.h"
#include "lwip/timeouts.h"
#include "lwip/udp.h"
#include "lwip/dns.h"
#include "lwip/ip_addr.h"
#include "lwip/pbuf.h"
#include "lwip/dhcp.h"
#include <string.h>
#include <time.h>
#if LWIP_UDP
/* Handle support for more than one server via SNTP_MAX_SERVERS */
#if SNTP_MAX_SERVERS > 1
#define SNTP_SUPPORT_MULTIPLE_SERVERS 1
#else /* NTP_MAX_SERVERS > 1 */
#define SNTP_SUPPORT_MULTIPLE_SERVERS 0
#endif /* NTP_MAX_SERVERS > 1 */
#if (SNTP_UPDATE_DELAY < 15000) && !defined(SNTP_SUPPRESS_DELAY_CHECK)
#error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!"
#endif
/* Configure behaviour depending on microsecond or second precision */
#ifdef SNTP_SET_SYSTEM_TIME_US
#define SNTP_CALC_TIME_US 1
#define SNTP_RECEIVE_TIME_SIZE 2
#else
#define SNTP_SET_SYSTEM_TIME_US(sec, us)
#define SNTP_CALC_TIME_US 0
#define SNTP_RECEIVE_TIME_SIZE 1
#endif
/* the various debug levels for this file */
#define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE)
#define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE)
#define SNTP_DEBUG_WARN (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING)
#define SNTP_DEBUG_WARN_STATE (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE)
#define SNTP_DEBUG_SERIOUS (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS)
#define SNTP_ERR_KOD 1
/* SNTP protocol defines */
#define SNTP_MSG_LEN 48
#define SNTP_OFFSET_LI_VN_MODE 0
#define SNTP_LI_MASK 0xC0
#define SNTP_LI_NO_WARNING 0x00
#define SNTP_LI_LAST_MINUTE_61_SEC 0x01
#define SNTP_LI_LAST_MINUTE_59_SEC 0x02
#define SNTP_LI_ALARM_CONDITION 0x03 /* (clock not synchronized) */
#define SNTP_VERSION_MASK 0x38
#define SNTP_VERSION (4/* NTP Version 4*/<<3)
#define SNTP_MODE_MASK 0x07
#define SNTP_MODE_CLIENT 0x03
#define SNTP_MODE_SERVER 0x04
#define SNTP_MODE_BROADCAST 0x05
#define SNTP_OFFSET_STRATUM 1
#define SNTP_STRATUM_KOD 0x00
#define SNTP_OFFSET_ORIGINATE_TIME 24
#define SNTP_OFFSET_RECEIVE_TIME 32
#define SNTP_OFFSET_TRANSMIT_TIME 40
/* number of seconds between 1900 and 1970 (MSB=1)*/
#define DIFF_SEC_1900_1970 (2208988800UL)
/* number of seconds between 1970 and Feb 7, 2036 (6:28:16 UTC) (MSB=0) */
#define DIFF_SEC_1970_2036 (2085978496UL)
/**
* SNTP packet format (without optional fields)
* Timestamps are coded as 64 bits:
* - 32 bits seconds since Jan 01, 1970, 00:00
* - 32 bits seconds fraction (0-padded)
* For future use, if the MSB in the seconds part is set, seconds are based
* on Feb 07, 2036, 06:28:16.
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct sntp_msg {
PACK_STRUCT_FLD_8(u8_t li_vn_mode);
PACK_STRUCT_FLD_8(u8_t stratum);
PACK_STRUCT_FLD_8(u8_t poll);
PACK_STRUCT_FLD_8(u8_t precision);
PACK_STRUCT_FIELD(u32_t root_delay);
PACK_STRUCT_FIELD(u32_t root_dispersion);
PACK_STRUCT_FIELD(u32_t reference_identifier);
PACK_STRUCT_FIELD(u32_t reference_timestamp[2]);
PACK_STRUCT_FIELD(u32_t originate_timestamp[2]);
PACK_STRUCT_FIELD(u32_t receive_timestamp[2]);
PACK_STRUCT_FIELD(u32_t transmit_timestamp[2]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/* function prototypes */
static void sntp_request(void *arg);
/** The operating mode */
static u8_t sntp_opmode;
/** The UDP pcb used by the SNTP client */
static struct udp_pcb* sntp_pcb;
/** Names/Addresses of servers */
struct sntp_server {
#if SNTP_SERVER_DNS
char* name;
#endif /* SNTP_SERVER_DNS */
ip_addr_t addr;
};
static struct sntp_server sntp_servers[SNTP_MAX_SERVERS];
#if SNTP_GET_SERVERS_FROM_DHCP
static u8_t sntp_set_servers_from_dhcp;
#endif /* SNTP_GET_SERVERS_FROM_DHCP */
#if SNTP_SUPPORT_MULTIPLE_SERVERS
/** The currently used server (initialized to 0) */
static u8_t sntp_current_server;
#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
#define sntp_current_server 0
#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
#if SNTP_RETRY_TIMEOUT_EXP
#define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT
/** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */
static u32_t sntp_retry_timeout;
#else /* SNTP_RETRY_TIMEOUT_EXP */
#define SNTP_RESET_RETRY_TIMEOUT()
#define sntp_retry_timeout SNTP_RETRY_TIMEOUT
#endif /* SNTP_RETRY_TIMEOUT_EXP */
#if SNTP_CHECK_RESPONSE >= 1
/** Saves the last server address to compare with response */
static ip_addr_t sntp_last_server_address;
#endif /* SNTP_CHECK_RESPONSE >= 1 */
#if SNTP_CHECK_RESPONSE >= 2
/** Saves the last timestamp sent (which is sent back by the server)
* to compare against in response */
static u32_t sntp_last_timestamp_sent[2];
#endif /* SNTP_CHECK_RESPONSE >= 2 */
/**
* SNTP processing of received timestamp
*/
static void
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 = 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 = 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));
#else /* SNTP_CALC_TIME_US */
/* change system time and/or the update the RTC clock */
SNTP_SET_SYSTEM_TIME(t);
/* display local time from GMT time */
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s", ctime(&tim)));
#endif /* SNTP_CALC_TIME_US */
LWIP_UNUSED_ARG(tim);
}
/**
* Initialize request struct to be sent to server.
*/
static void
sntp_initialize_request(struct sntp_msg *req)
{
memset(req, 0, SNTP_MSG_LEN);
req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
#if SNTP_CHECK_RESPONSE >= 2
{
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] = 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] = lwip_htonl(sntp_time_us);
req->transmit_timestamp[1] = sntp_last_timestamp_sent[1];
}
#endif /* SNTP_CHECK_RESPONSE >= 2 */
}
/**
* Retry: send a new request (and increase retry timeout).
*
* @param arg is unused (only necessary to conform to sys_timeout)
*/
static void
sntp_retry(void* arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n",
sntp_retry_timeout));
/* set up a timer to send a retry and increase the retry delay */
sys_timeout(sntp_retry_timeout, sntp_request, NULL);
#if SNTP_RETRY_TIMEOUT_EXP
{
u32_t new_retry_timeout;
/* increase the timeout for next retry */
new_retry_timeout = sntp_retry_timeout << 1;
/* limit to maximum timeout and prevent overflow */
if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) &&
(new_retry_timeout > sntp_retry_timeout)) {
sntp_retry_timeout = new_retry_timeout;
}
}
#endif /* SNTP_RETRY_TIMEOUT_EXP */
}
#if SNTP_SUPPORT_MULTIPLE_SERVERS
/**
* If Kiss-of-Death is received (or another packet parsing error),
* try the next server or retry the current server and increase the retry
* timeout if only one server is available.
* (implicitly, SNTP_MAX_SERVERS > 1)
*
* @param arg is unused (only necessary to conform to sys_timeout)
*/
static void
sntp_try_next_server(void* arg)
{
u8_t old_server, i;
LWIP_UNUSED_ARG(arg);
old_server = sntp_current_server;
for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) {
sntp_current_server++;
if (sntp_current_server >= SNTP_MAX_SERVERS) {
sntp_current_server = 0;
}
if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr)
#if SNTP_SERVER_DNS
|| (sntp_servers[sntp_current_server].name != NULL)
#endif
) {
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n",
(u16_t)sntp_current_server));
/* new server: reset retry timeout */
SNTP_RESET_RETRY_TIMEOUT();
/* instantly send a request to the next server */
sntp_request(NULL);
return;
}
}
/* no other valid server found */
sntp_current_server = old_server;
sntp_retry(NULL);
}
#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
/* Always retry on error if only one server is supported */
#define sntp_try_next_server sntp_retry
#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
/** UDP recv callback for the sntp pcb */
static void
sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
u8_t mode;
u8_t stratum;
u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE];
err_t err;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(pcb);
/* packet received: stop retry timeout */
sys_untimeout(sntp_try_next_server, NULL);
sys_untimeout(sntp_request, NULL);
err = ERR_ARG;
#if SNTP_CHECK_RESPONSE >= 1
/* check server address and port */
if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) &&
(port == SNTP_PORT))
#else /* SNTP_CHECK_RESPONSE >= 1 */
LWIP_UNUSED_ARG(addr);
LWIP_UNUSED_ARG(port);
#endif /* SNTP_CHECK_RESPONSE >= 1 */
{
/* process the response */
if (p->tot_len == SNTP_MSG_LEN) {
pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE);
mode &= SNTP_MODE_MASK;
/* if this is a SNTP response... */
if (((sntp_opmode == SNTP_OPMODE_POLL) && (mode == SNTP_MODE_SERVER)) ||
((sntp_opmode == SNTP_OPMODE_LISTENONLY) && (mode == SNTP_MODE_BROADCAST))) {
pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM);
if (stratum == SNTP_STRATUM_KOD) {
/* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
err = SNTP_ERR_KOD;
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n"));
} else {
#if SNTP_CHECK_RESPONSE >= 2
/* check originate_timetamp against sntp_last_timestamp_sent */
u32_t originate_timestamp[2];
pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME);
if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) ||
(originate_timestamp[1] != sntp_last_timestamp_sent[1]))
{
LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid originate timestamp in response\n"));
} else
#endif /* SNTP_CHECK_RESPONSE >= 2 */
/* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */
{
/* correct answer */
err = ERR_OK;
pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_TRANSMIT_TIME);
}
}
} else {
LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode));
/* wait for correct response */
err = ERR_TIMEOUT;
}
} else {
LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len));
}
}
#if SNTP_CHECK_RESPONSE >= 1
else {
/* packet from wrong remote address or port, wait for correct response */
err = ERR_TIMEOUT;
}
#endif /* SNTP_CHECK_RESPONSE >= 1 */
pbuf_free(p);
if (err == ERR_OK) {
sntp_process(receive_timestamp);
/* Set up timeout for next request (only if poll response was received)*/
if (sntp_opmode == SNTP_OPMODE_POLL) {
/* Correct response, reset retry timeout */
SNTP_RESET_RETRY_TIMEOUT();
sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL);
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n",
(u32_t)SNTP_UPDATE_DELAY));
}
} else if (err != ERR_TIMEOUT) {
/* Errors are only processed in case of an explicit poll response */
if (sntp_opmode == SNTP_OPMODE_POLL) {
if (err == SNTP_ERR_KOD) {
/* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
sntp_try_next_server(NULL);
} else {
/* another error, try the same server again */
sntp_retry(NULL);
}
}
}
}
/** Actually send an sntp request to a server.
*
* @param server_addr resolved IP address of the SNTP server
*/
static void
sntp_send_request(const ip_addr_t *server_addr)
{
struct pbuf* p;
p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);
if (p != NULL) {
struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload;
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n"));
/* initialize request message */
sntp_initialize_request(sntpmsg);
/* send request */
udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT);
/* free the pbuf after sending it */
pbuf_free(p);
/* set up receive timeout: try next server or retry on timeout */
sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL);
#if SNTP_CHECK_RESPONSE >= 1
/* save server address to verify it in sntp_recv */
ip_addr_set(&sntp_last_server_address, server_addr);
#endif /* SNTP_CHECK_RESPONSE >= 1 */
} else {
LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n",
(u32_t)SNTP_RETRY_TIMEOUT));
/* out of memory: set up a timer to send a retry */
sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL);
}
}
#if SNTP_SERVER_DNS
/**
* DNS found callback when using DNS names as server address.
*/
static void
sntp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
{
LWIP_UNUSED_ARG(hostname);
LWIP_UNUSED_ARG(arg);
if (ipaddr != NULL) {
/* Address resolved, send request */
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n"));
sntp_send_request(ipaddr);
} else {
/* DNS resolving failed -> try another server */
LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n"));
sntp_try_next_server(NULL);
}
}
#endif /* SNTP_SERVER_DNS */
/**
* Send out an sntp request.
*
* @param arg is unused (only necessary to conform to sys_timeout)
*/
static void
sntp_request(void *arg)
{
ip_addr_t sntp_server_address;
err_t err;
LWIP_UNUSED_ARG(arg);
/* initialize SNTP server address */
#if SNTP_SERVER_DNS
if (sntp_servers[sntp_current_server].name) {
/* always resolve the name and rely on dns-internal caching & timeout */
ip_addr_set_zero(&sntp_servers[sntp_current_server].addr);
err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address,
sntp_dns_found, NULL);
if (err == ERR_INPROGRESS) {
/* DNS request sent, wait for sntp_dns_found being called */
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n"));
return;
} else if (err == ERR_OK) {
sntp_servers[sntp_current_server].addr = sntp_server_address;
}
} else
#endif /* SNTP_SERVER_DNS */
{
sntp_server_address = sntp_servers[sntp_current_server].addr;
err = (ip_addr_isany_val(sntp_server_address)) ? ERR_ARG : ERR_OK;
}
if (err == ERR_OK) {
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %s\n",
ipaddr_ntoa(&sntp_server_address)));
sntp_send_request(&sntp_server_address);
} else {
/* address conversion failed, try another server */
LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n"));
sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL);
}
}
/**
* @ingroup sntp
* Initialize this module.
* Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC).
*/
void
sntp_init(void)
{
#ifdef SNTP_SERVER_ADDRESS
#if SNTP_SERVER_DNS
sntp_setservername(0, SNTP_SERVER_ADDRESS);
#else
#error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0
#endif
#endif /* SNTP_SERVER_ADDRESS */
if (sntp_pcb == NULL) {
sntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL);
if (sntp_pcb != NULL) {
udp_recv(sntp_pcb, sntp_recv, NULL);
if (sntp_opmode == SNTP_OPMODE_POLL) {
SNTP_RESET_RETRY_TIMEOUT();
#if SNTP_STARTUP_DELAY
sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL);
#else
sntp_request(NULL);
#endif
} else if (sntp_opmode == SNTP_OPMODE_LISTENONLY) {
ip_set_option(sntp_pcb, SOF_BROADCAST);
udp_bind(sntp_pcb, IP_ANY_TYPE, SNTP_PORT);
}
}
}
}
/**
* @ingroup sntp
* Stop this module.
*/
void
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;
}
}
/**
* @ingroup sntp
* Get enabled state.
*/
u8_t sntp_enabled(void)
{
return (sntp_pcb != NULL)? 1 : 0;
}
/**
* @ingroup sntp
* Sets the operating mode.
* @param operating_mode one of the available operating modes
*/
void
sntp_setoperatingmode(u8_t operating_mode)
{
LWIP_ASSERT("Invalid operating mode", operating_mode <= SNTP_OPMODE_LISTENONLY);
LWIP_ASSERT("Operating mode must not be set while SNTP client is running", sntp_pcb == NULL);
sntp_opmode = operating_mode;
}
/**
* @ingroup sntp
* Gets the operating mode.
*/
u8_t
sntp_getoperatingmode(void)
{
return sntp_opmode;
}
#if SNTP_GET_SERVERS_FROM_DHCP
/**
* Config SNTP server handling by IP address, name, or DHCP; clear table
* @param set_servers_from_dhcp enable or disable getting server addresses from dhcp
*/
void
sntp_servermode_dhcp(int set_servers_from_dhcp)
{
u8_t new_mode = set_servers_from_dhcp ? 1 : 0;
if (sntp_set_servers_from_dhcp != new_mode) {
sntp_set_servers_from_dhcp = new_mode;
}
}
#endif /* SNTP_GET_SERVERS_FROM_DHCP */
/**
* @ingroup sntp
* Initialize one of the NTP servers by IP address
*
* @param idx the index of the NTP server to set must be < SNTP_MAX_SERVERS
* @param server IP address of the NTP server to set
*/
void
sntp_setserver(u8_t idx, const ip_addr_t *server)
{
if (idx < SNTP_MAX_SERVERS) {
if (server != NULL) {
sntp_servers[idx].addr = (*server);
} else {
ip_addr_set_zero(&sntp_servers[idx].addr);
}
#if SNTP_SERVER_DNS
sntp_servers[idx].name = NULL;
#endif
}
}
#if LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP
/**
* Initialize one of the NTP servers by IP address, required by DHCP
*
* @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
* @param dnsserver IP address of the NTP server to set
*/
void
dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server)
{
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n",
(sntp_set_servers_from_dhcp ? "Got" : "Rejected"),
ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num));
if (sntp_set_servers_from_dhcp && num) {
u8_t i;
for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) {
ip_addr_t addr;
ip_addr_copy_from_ip4(addr, server[i]);
sntp_setserver(i, &addr);
}
for (i = num; i < SNTP_MAX_SERVERS; i++) {
sntp_setserver(i, NULL);
}
}
}
#endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */
/**
* @ingroup sntp
* Obtain one of the currently configured by IP address (or DHCP) NTP servers
*
* @param idx the index of the NTP server
* @return IP address of the indexed NTP server or "ip_addr_any" if the NTP
* server has not been configured by address (or at all).
*/
const ip_addr_t*
sntp_getserver(u8_t idx)
{
if (idx < SNTP_MAX_SERVERS) {
return &sntp_servers[idx].addr;
}
return IP_ADDR_ANY;
}
#if SNTP_SERVER_DNS
/**
* Initialize one of the NTP servers by name
*
* @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
* @param dnsserver DNS name of the NTP server to set, to be resolved at contact time
*/
void
sntp_setservername(u8_t idx, char *server)
{
if (idx < SNTP_MAX_SERVERS) {
sntp_servers[idx].name = server;
}
}
/**
* Obtain one of the currently configured by name NTP servers.
*
* @param numdns the index of the NTP server
* @return IP address of the indexed NTP server or NULL if the NTP
* server has not been configured by name (or at all)
*/
char *
sntp_getservername(u8_t idx)
{
if (idx < SNTP_MAX_SERVERS) {
return sntp_servers[idx].name;
}
return NULL;
}
#endif /* SNTP_SERVER_DNS */
#endif /* LWIP_UDP */

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 */

190
ext/lwip/src/core/def.c Normal file → Executable file
View File

@@ -2,6 +2,28 @@
* @file * @file
* Common functions used throughout the stack. * 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/opt.h"
#include "lwip/def.h" #include "lwip/def.h"
/** #include <string.h>
* These are reference implementations of the byte swapping functions.
* Again with the aim of being simple, correct and fully portable.
* Byte swapping is the second thing you would want to optimize. You will
* need to port it to your architecture and in your cc.h:
*
* #define LWIP_PLATFORM_BYTESWAP 1
* #define LWIP_PLATFORM_HTONS(x) <your_htons>
* #define LWIP_PLATFORM_HTONL(x) <your_htonl>
*
* Note ntohs() and ntohl() are merely references to the htonx counterparts.
*/
#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) #if BYTE_ORDER == LITTLE_ENDIAN
#if !defined(lwip_htons)
/** /**
* Convert an u16_t from host- to network byte order. * Convert an u16_t from host- to network byte order.
* *
@@ -63,21 +75,11 @@
u16_t u16_t
lwip_htons(u16_t n) lwip_htons(u16_t n)
{ {
return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); return (u16_t)PP_HTONS(n);
}
/**
* 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);
} }
#endif /* lwip_htons */
#if !defined(lwip_htonl)
/** /**
* Convert an u32_t from host- to network byte order. * Convert an u32_t from host- to network byte order.
* *
@@ -87,22 +89,134 @@ lwip_ntohs(u16_t n)
u32_t u32_t
lwip_htonl(u32_t n) lwip_htonl(u32_t n)
{ {
return ((n & 0xff) << 24) | return (u32_t)PP_HTONL(n);
((n & 0xff00) << 8) |
((n & 0xff0000UL) >> 8) |
((n & 0xff000000UL) >> 24);
} }
#endif /* lwip_htonl */
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
#ifndef lwip_strnstr
/** /**
* Convert an u32_t from network- to host byte order. * @ingroup sys_nonstandard
* * lwIP default implementation for strnstr() non-standard function.
* @param n u32_t in network byte order * This can be \#defined to strnstr() depending on your platform port.
* @return n in host byte order
*/ */
u32_t char*
lwip_ntohl(u32_t n) 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

425
ext/lwip/src/core/dns.c Normal file → Executable file
View File

@@ -1,6 +1,37 @@
/** /**
* @file * @file
* DNS - host name to IP address resolver. * 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. * 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 1035 - Domain names - implementation and specification
* RFC 2181 - Clarifications to the DNS Specification * RFC 2181 - Clarifications to the DNS Specification
@@ -73,6 +76,7 @@
/** @todo: define good default values (rfc compliance) */ /** @todo: define good default values (rfc compliance) */
/** @todo: improve answer parsing, more checkings... */ /** @todo: improve answer parsing, more checkings... */
/** @todo: check RFC1035 - 7.3. Processing responses */ /** @todo: check RFC1035 - 7.3. Processing responses */
/** @todo: one-shot mDNS: dual-stack fallback to another IP version */
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
* Includes * Includes
@@ -82,10 +86,12 @@
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
#include "lwip/def.h"
#include "lwip/udp.h" #include "lwip/udp.h"
#include "lwip/mem.h" #include "lwip/mem.h"
#include "lwip/memp.h" #include "lwip/memp.h"
#include "lwip/dns.h" #include "lwip/dns.h"
#include "lwip/prot/dns.h"
#include <string.h> #include <string.h>
@@ -104,11 +110,6 @@ static u16_t dns_txid;
#define DNS_PORT_ALLOWED(port) ((port) >= 1024) #define DNS_PORT_ALLOWED(port) ((port) >= 1024)
#endif #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". */ /** DNS maximum number of retries when asking for a name, before "timeout". */
#ifndef DNS_MAX_RETRIES #ifndef DNS_MAX_RETRIES
#define DNS_MAX_RETRIES 4 #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 #error DNS_MAX_TTL must be a positive 32-bit value
#endif #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 /* The number of parallel requests (i.e. calls to dns_gethostbyname
* that cannot be answered from the DNS table. * that cannot be answered from the DNS table.
* This is set to the table size by default. * 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) #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
#ifndef DNS_MAX_REQUESTS #ifndef DNS_MAX_REQUESTS
#define DNS_MAX_REQUESTS DNS_TABLE_SIZE #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 #endif
#else #else
/* In this configuration, both arrays have to have the same size and are used /* 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) #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
#ifndef DNS_MAX_SOURCE_PORTS #ifndef DNS_MAX_SOURCE_PORTS
#define DNS_MAX_SOURCE_PORTS DNS_MAX_REQUESTS #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 #endif
#else #else
#ifdef DNS_MAX_SOURCE_PORTS #ifdef DNS_MAX_SOURCE_PORTS
@@ -165,70 +181,11 @@ static u16_t dns_txid;
#define LWIP_DNS_SET_ADDRTYPE(x, y) #define LWIP_DNS_SET_ADDRTYPE(x, y)
#endif /* LWIP_IPV4 && LWIP_IPV6 */ #endif /* LWIP_IPV4 && LWIP_IPV6 */
/** DNS field TYPE used for "Resource Records" */ #if LWIP_DNS_SUPPORT_MDNS_QUERIES
#define DNS_RRTYPE_A 1 /* a host address */ #define LWIP_DNS_ISMDNS_ARG(x) , x
#define DNS_RRTYPE_NS 2 /* an authoritative name server */ #else
#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */ #define LWIP_DNS_ISMDNS_ARG(x)
#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"
#endif #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. /** DNS query message structure.
No packing needed: only used locally on the stack. */ 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 */ /* maximum allowed size for the struct due to non-packed */
#define SIZEOF_DNS_ANSWER_ASSERT 12 #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 */ /** DNS table entry */
struct dns_table_entry { struct dns_table_entry {
u32_t ttl; u32_t ttl;
@@ -271,6 +236,9 @@ struct dns_table_entry {
#if LWIP_IPV4 && LWIP_IPV6 #if LWIP_IPV4 && LWIP_IPV6
u8_t reqaddrtype; u8_t reqaddrtype;
#endif /* LWIP_IPV4 && LWIP_IPV6 */ #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 /** DNS request table entry: used when dns_gehostbyname cannot answer the
@@ -312,6 +280,7 @@ DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
static void dns_init_local(void); static void dns_init_local(void);
static err_t dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype));
#endif /* DNS_LOCAL_HOSTLIST */ #endif /* DNS_LOCAL_HOSTLIST */
@@ -334,39 +303,12 @@ static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS]; static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS];
static ip_addr_t dns_servers[DNS_MAX_SERVERS]; static ip_addr_t dns_servers[DNS_MAX_SERVERS];
#ifndef LWIP_DNS_STRICMP #if LWIP_IPV4
#define LWIP_DNS_STRICMP(str1, str2) dns_stricmp(str1, str2) const ip_addr_t dns_mquery_v4group = DNS_MQUERY_IPV4_GROUP_INIT;
/** #endif /* LWIP_IPV4 */
* A small but sufficient implementation for case insensitive strcmp. #if LWIP_IPV6
* This can be defined to e.g. stricmp for windows or strcasecmp for linux. */ const ip_addr_t dns_mquery_v6group = DNS_MQUERY_IPV6_GROUP_INIT;
static int #endif /* LWIP_IPV6 */
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 */
/** /**
* Initialize the resolver: set up the UDP pcb and configure the default server * Initialize the resolver: set up the UDP pcb and configure the default server
@@ -489,6 +431,38 @@ dns_init_local(void)
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */ #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
} }
/**
* @ingroup dns
* Iterate the local host-list for a hostname.
*
* @param iterator_fn a function that is called for every entry in the local host-list
* @param iterator_arg 3rd argument passed to iterator_fn
* @return the number of entries in the local host-list
*/
size_t
dns_local_iterate(dns_found_callback iterator_fn, void *iterator_arg)
{
size_t i;
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
struct local_hostlist_entry *entry = local_hostlist_dynamic;
i = 0;
while (entry != NULL) {
if (iterator_fn != NULL) {
iterator_fn(entry->name, &entry->addr, iterator_arg);
}
i++;
entry = entry->next;
}
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) {
if (iterator_fn != NULL) {
iterator_fn(local_hostlist_static[i].name, &local_hostlist_static[i].addr, iterator_arg);
}
}
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
return i;
}
/** /**
* @ingroup dns * @ingroup dns
* Scans the local host-list for a hostname. * Scans the local host-list for a hostname.
@@ -496,15 +470,27 @@ dns_init_local(void)
* @param hostname Hostname to look for in the local host-list * @param hostname Hostname to look for in the local host-list
* @param addr the first IP address for the hostname in the local host-list or * @param addr the first IP address for the hostname in the local host-list or
* IPADDR_NONE if not found. * IPADDR_NONE if not found.
* @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 (ATTENTION: no fallback here!)
* - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 (ATTENTION: no fallback here!)
* - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only
* - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only
* @return ERR_OK if found, ERR_ARG if not found * @return ERR_OK if found, ERR_ARG if not found
*/ */
err_t
dns_local_lookup(const char *hostname, ip_addr_t *addr, u8_t dns_addrtype)
{
LWIP_UNUSED_ARG(dns_addrtype);
return dns_lookup_local(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype));
}
/* Internal implementation for dns_local_lookup and dns_lookup */
static err_t static err_t
dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype))
{ {
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
struct local_hostlist_entry *entry = local_hostlist_dynamic; struct local_hostlist_entry *entry = local_hostlist_dynamic;
while (entry != NULL) { 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)) { LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, entry->addr)) {
if (addr) { if (addr) {
ip_addr_copy(*addr, entry->addr); ip_addr_copy(*addr, entry->addr);
@@ -516,7 +502,7 @@ dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
size_t i; size_t i;
for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); 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)) { LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, local_hostlist_static[i].addr)) {
if (addr) { if (addr) {
ip_addr_copy(*addr, local_hostlist_static[i].addr); ip_addr_copy(*addr, local_hostlist_static[i].addr);
@@ -546,7 +532,7 @@ dns_local_removehost(const char *hostname, const ip_addr_t *addr)
struct local_hostlist_entry *entry = local_hostlist_dynamic; struct local_hostlist_entry *entry = local_hostlist_dynamic;
struct local_hostlist_entry *last_entry = NULL; struct local_hostlist_entry *last_entry = NULL;
while (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))) { ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
struct local_hostlist_entry *free_entry; struct local_hostlist_entry *free_entry;
if (last_entry != NULL) { if (last_entry != NULL) {
@@ -635,7 +621,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. */ /* Walk through name list, return entry if found. If not, return NULL. */
for (i = 0; i < DNS_TABLE_SIZE; ++i) { for (i = 0; i < DNS_TABLE_SIZE; ++i) {
if ((dns_table[i].state == DNS_STATE_DONE) && 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_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, dns_table[i].ipaddr)) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr)); ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
@@ -664,11 +650,14 @@ dns_lookup(const char *name, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addr
static u16_t static u16_t
dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset) dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset)
{ {
unsigned char n; int n;
u16_t response_offset = start_offset; u16_t response_offset = start_offset;
do { 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 */ /** @see RFC 1035 - 4.1.4. Message compression */
if ((n & 0xc0) == 0xc0) { if ((n & 0xc0) == 0xc0) {
/* Compressed name: cannot be equal since we don't send them */ /* Compressed name: cannot be equal since we don't send them */
@@ -676,7 +665,11 @@ dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset)
} else { } else {
/* Not compressed name */ /* Not compressed name */
while (n > 0) { 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; return 0xFFFF;
} }
++response_offset; ++response_offset;
@@ -685,7 +678,11 @@ dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset)
} }
++query; ++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; return response_offset + 1;
} }
@@ -698,26 +695,34 @@ dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset)
* @return index to end of the name * @return index to end of the name
*/ */
static u16_t 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 { 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 */ /** @see RFC 1035 - 4.1.4. Message compression */
if ((n & 0xc0) == 0xc0) { if ((n & 0xc0) == 0xc0) {
/* Compressed name */ /* Compressed name: since we only want to skip it (not check it), stop here */
break; break;
} else { } else {
/* Not compressed name */ /* Not compressed name */
while (n > 0) { if (offset + n >= p->tot_len) {
++query_idx; return 0xFFFF;
--n;
} }
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 +747,11 @@ dns_send(u8_t idx)
LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n", LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
(u16_t)(entry->server_idx), entry->name)); (u16_t)(entry->server_idx), entry->name));
LWIP_ASSERT("dns server out of array", entry->server_idx < DNS_MAX_SERVERS); 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 */ /* DNS server not valid anymore, e.g. PPP netif has been shut down */
/* call specified callback function if provided */ /* call specified callback function if provided */
dns_call_found(idx, NULL); dns_call_found(idx, NULL);
@@ -755,9 +764,11 @@ dns_send(u8_t idx)
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 + p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 +
SIZEOF_DNS_QUERY), PBUF_RAM); SIZEOF_DNS_QUERY), PBUF_RAM);
if (p != NULL) { if (p != NULL) {
const ip_addr_t* dst;
u16_t dst_port;
/* fill dns header */ /* fill dns header */
memset(&hdr, 0, SIZEOF_DNS_HDR); memset(&hdr, 0, SIZEOF_DNS_HDR);
hdr.id = htons(entry->txid); hdr.id = lwip_htons(entry->txid);
hdr.flags1 = DNS_FLAG1_RD; hdr.flags1 = DNS_FLAG1_RD;
hdr.numquestions = PP_HTONS(1); hdr.numquestions = PP_HTONS(1);
pbuf_take(p, &hdr, SIZEOF_DNS_HDR); pbuf_take(p, &hdr, SIZEOF_DNS_HDR);
@@ -797,7 +808,30 @@ dns_send(u8_t idx)
/* send dns packet */ /* send dns packet */
LWIP_DEBUGF(DNS_DEBUG, ("sending DNS request ID %d for name \"%s\" to server %d\r\n", LWIP_DEBUGF(DNS_DEBUG, ("sending DNS request ID %d for name \"%s\" to server %d\r\n",
entry->txid, entry->name, entry->server_idx)); 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 */ /* free pbuf */
pbuf_free(p); pbuf_free(p);
@@ -982,12 +1016,9 @@ dns_check_entry(u8_t i)
LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE); LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
switch (entry->state) { switch (entry->state) {
case DNS_STATE_NEW:
case DNS_STATE_NEW: {
u16_t txid;
/* initialize new entry */ /* initialize new entry */
txid = dns_create_txid(); entry->txid = dns_create_txid();
entry->txid = txid;
entry->state = DNS_STATE_ASKING; entry->state = DNS_STATE_ASKING;
entry->server_idx = 0; entry->server_idx = 0;
entry->tmr = 1; entry->tmr = 1;
@@ -1000,12 +1031,14 @@ dns_check_entry(u8_t i)
("dns_send returned error: %s\n", lwip_strerr(err))); ("dns_send returned error: %s\n", lwip_strerr(err)));
} }
break; break;
}
case DNS_STATE_ASKING: case DNS_STATE_ASKING:
if (--entry->tmr == 0) { if (--entry->tmr == 0) {
if (++entry->retries == DNS_MAX_RETRIES) { 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 */ /* change of server */
entry->server_idx++; entry->server_idx++;
entry->tmr = 1; entry->tmr = 1;
@@ -1095,8 +1128,6 @@ dns_correct_response(u8_t idx, u32_t ttl)
} }
/** /**
* Receive input function for DNS response packets arriving for the dns UDP pcb. * Receive input function for DNS response packets arriving for the dns UDP pcb.
*
* @params see udp.h
*/ */
static void static void
dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
@@ -1123,7 +1154,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 */ /* copy dns payload inside static buffer for processing */
if (pbuf_copy_partial(p, &hdr, SIZEOF_DNS_HDR, 0) == SIZEOF_DNS_HDR) { if (pbuf_copy_partial(p, &hdr, SIZEOF_DNS_HDR, 0) == SIZEOF_DNS_HDR) {
/* Match the ID in the DNS header with the name table. */ /* 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++) { for (i = 0; i < DNS_TABLE_SIZE; i++) {
const struct dns_table_entry *entry = &dns_table[i]; const struct dns_table_entry *entry = &dns_table[i];
if ((entry->state == DNS_STATE_ASKING) && if ((entry->state == DNS_STATE_ASKING) &&
@@ -1131,8 +1162,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 /* We only care about the question(s) and the answers. The authrr
and the extrarr are simply discarded. */ and the extrarr are simply discarded. */
nquestions = htons(hdr.numquestions); nquestions = lwip_htons(hdr.numquestions);
nanswers = htons(hdr.numanswers); nanswers = lwip_htons(hdr.numanswers);
/* Check for correct response. */ /* Check for correct response. */
if ((hdr.flags1 & DNS_FLAG1_RESPONSE) == 0) { if ((hdr.flags1 & DNS_FLAG1_RESPONSE) == 0) {
@@ -1144,11 +1175,16 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
goto memerr; /* ignore this packet */ 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 /* Check whether response comes from the same network address to which the
question was sent. (RFC 5452) */ question was sent. (RFC 5452) */
if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) { if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) {
goto memerr; /* ignore this packet */ goto memerr; /* ignore this packet */
} }
}
/* Check if the name in the "question" part match with the name in the entry and /* Check if the name in the "question" part match with the name in the entry and
skip it if equal. */ skip it if equal. */
@@ -1159,7 +1195,9 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
} }
/* check if "question" part matches the request */ /* 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)) || 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_AAAA))) ||
(!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_A)))) { (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_A)))) {
@@ -1175,11 +1213,17 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
} else { } else {
while ((nanswers > 0) && (res_idx < p->tot_len)) { while ((nanswers > 0) && (res_idx < p->tot_len)) {
/* skip answer resource record's host name */ /* 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. */ /* 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; res_idx += SIZEOF_DNS_ANSWER;
if (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) { if (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) {
#if LWIP_IPV4 #if LWIP_IPV4
if ((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.len == PP_HTONS(sizeof(ip4_addr_t)))) { if ((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.len == PP_HTONS(sizeof(ip4_addr_t)))) {
@@ -1189,11 +1233,13 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
{ {
ip4_addr_t ip4addr; ip4_addr_t ip4addr;
/* read the IP address after answer resource record's header */ /* 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); ip_addr_copy_from_ip4(dns_table[i].ipaddr, ip4addr);
pbuf_free(p); pbuf_free(p);
/* handle correct response */ /* handle correct response */
dns_correct_response(i, ntohl(ans.ttl)); dns_correct_response(i, lwip_ntohl(ans.ttl));
return; return;
} }
} }
@@ -1206,18 +1252,23 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
{ {
ip6_addr_t ip6addr; ip6_addr_t ip6addr;
/* read the IP address after answer resource record's header */ /* 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); ip_addr_copy_from_ip6(dns_table[i].ipaddr, ip6addr);
pbuf_free(p); pbuf_free(p);
/* handle correct response */ /* handle correct response */
dns_correct_response(i, ntohl(ans.ttl)); dns_correct_response(i, lwip_ntohl(ans.ttl));
return; return;
} }
} }
#endif /* LWIP_IPV6 */ #endif /* LWIP_IPV6 */
} }
/* skip this answer */ /* 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; --nanswers;
} }
#if LWIP_IPV4 && LWIP_IPV6 #if LWIP_IPV4 && LWIP_IPV6
@@ -1260,11 +1311,11 @@ memerr:
* @param hostnamelen length of the hostname * @param hostnamelen length of the hostname
* @param found a callback function to be called on success, failure or timeout * @param found a callback function to be called on success, failure or timeout
* @param callback_arg argument to pass to the callback function * @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 static err_t
dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, 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 i;
u8_t lseq, lseqi; u8_t lseq, lseqi;
@@ -1277,7 +1328,7 @@ dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found,
/* check for duplicate entries */ /* check for duplicate entries */
for (i = 0; i < DNS_TABLE_SIZE; i++) { for (i = 0; i < DNS_TABLE_SIZE; i++) {
if ((dns_table[i].state == DNS_STATE_ASKING) && 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 LWIP_IPV4 && LWIP_IPV6
if (dns_table[i].reqaddrtype != dns_addrtype) { if (dns_table[i].reqaddrtype != dns_addrtype) {
/* requested address types don't match /* requested address types don't match
@@ -1313,8 +1364,9 @@ dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found,
} }
/* check if this is the oldest completed entry */ /* check if this is the oldest completed entry */
if (entry->state == DNS_STATE_DONE) { if (entry->state == DNS_STATE_DONE) {
if ((u8_t)(dns_seqno - entry->seqno) > lseq) { u8_t age = dns_seqno - entry->seqno;
lseq = dns_seqno - entry->seqno; if (age > lseq) {
lseq = age;
lseqi = i; lseqi = i;
} }
} }
@@ -1379,6 +1431,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))); LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS pcb %"U16_F"\n", name, (u16_t)(entry->pcb_idx)));
#endif #endif
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
entry->is_mdns = is_mdns;
#endif
dns_seqno++; dns_seqno++;
/* force to send query without waiting timer */ /* force to send query without waiting timer */
@@ -1424,7 +1480,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 * @param found a callback function to be called on success, failure or timeout (only if
* ERR_INPROGRESS is returned!) * ERR_INPROGRESS is returned!)
* @param callback_arg argument to pass to the callback function * @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_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_IPV4: try to resolve IPv4 only
* - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only * - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only
@@ -1434,6 +1490,9 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call
void *callback_arg, u8_t dns_addrtype) void *callback_arg, u8_t dns_addrtype)
{ {
size_t hostnamelen; 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 /* not initialized or no valid server yet, or invalid addr pointer
* or invalid hostname or invalid hostname length */ * or invalid hostname or invalid hostname length */
if ((addr == NULL) || if ((addr == NULL) ||
@@ -1490,13 +1549,25 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call
LWIP_UNUSED_ARG(dns_addrtype); LWIP_UNUSED_ARG(dns_addrtype);
#endif /* LWIP_IPV4 && LWIP_IPV6 */ #endif /* LWIP_IPV4 && LWIP_IPV6 */
#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 */ /* prevent calling found callback if no server is set, return error instead */
if (ip_addr_isany_val(dns_servers[0])) { if (ip_addr_isany_val(dns_servers[0])) {
return ERR_VAL; return ERR_VAL;
} }
}
/* queue query with specified callback */ /* 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 */ #endif /* LWIP_DNS */

37
ext/lwip/src/core/inet_chksum.c Normal file → Executable file
View File

@@ -1,7 +1,16 @@
/** /**
* @file * @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/def.h"
#include "lwip/ip_addr.h" #include "lwip/ip_addr.h"
#include <stddef.h>
#include <string.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 #ifndef LWIP_CHKSUM
# define LWIP_CHKSUM lwip_standard_chksum # define LWIP_CHKSUM lwip_standard_chksum
# ifndef LWIP_CHKSUM_ALGORITHM # ifndef LWIP_CHKSUM_ALGORITHM
@@ -110,10 +107,10 @@ lwip_standard_chksum(const void *dataptr, int len)
if ((acc & 0xffff0000UL) != 0) { if ((acc & 0xffff0000UL) != 0) {
acc = (acc >> 16) + (acc & 0x0000ffffUL); acc = (acc >> 16) + (acc & 0x0000ffffUL);
} }
/* This maybe a little confusing: reorder sum using htons() /* This maybe a little confusing: reorder sum using lwip_htons()
instead of ntohs() since it has a little less call overhead. instead of lwip_ntohs() since it has a little less call overhead.
The caller must invert bits for Internet sum ! */ The caller must invert bits for Internet sum ! */
return htons((u16_t)acc); return lwip_htons((u16_t)acc);
} }
#endif #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 = SWAP_BYTES_IN_WORD(acc);
} }
acc += (u32_t)htons((u16_t)proto); acc += (u32_t)lwip_htons((u16_t)proto);
acc += (u32_t)htons(proto_len); acc += (u32_t)lwip_htons(proto_len);
/* Fold 32-bit sum to 16 bits /* Fold 32-bit sum to 16 bits
calling this twice is probably faster than if statements... */ 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 = SWAP_BYTES_IN_WORD(acc);
} }
acc += (u32_t)htons((u16_t)proto); acc += (u32_t)lwip_htons((u16_t)proto);
acc += (u32_t)htons(proto_len); acc += (u32_t)lwip_htons(proto_len);
/* Fold 32-bit sum to 16 bits /* Fold 32-bit sum to 16 bits
calling this twice is probably faster than if statements... */ calling this twice is probably faster than if statements... */

65
ext/lwip/src/core/init.c Normal file → Executable file
View File

@@ -35,27 +35,6 @@
* Author: Adam Dunkels <adam@sics.se> * 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/opt.h"
#include "lwip/init.h" #include "lwip/init.h"
@@ -70,7 +49,6 @@
#include "lwip/raw.h" #include "lwip/raw.h"
#include "lwip/udp.h" #include "lwip/udp.h"
#include "lwip/priv/tcp_priv.h" #include "lwip/priv/tcp_priv.h"
#include "lwip/autoip.h"
#include "lwip/igmp.h" #include "lwip/igmp.h"
#include "lwip/dns.h" #include "lwip/dns.h"
#include "lwip/timeouts.h" #include "lwip/timeouts.h"
@@ -83,6 +61,25 @@
#include "netif/ppp/ppp_opts.h" #include "netif/ppp/ppp_opts.h"
#include "netif/ppp/ppp_impl.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. /* Compile-time sanity checks for configuration errors.
* These can be done independently of LWIP_DEBUG, without penalty. * These can be done independently of LWIP_DEBUG, without penalty.
*/ */
@@ -144,7 +141,7 @@
#if (LWIP_TCP && (TCP_WND > 0xffffffff)) #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" #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 #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!" #error "The maximum valid window scale value is 14!"
#endif #endif
#if (LWIP_TCP && (TCP_WND > (0xFFFFU << TCP_RCV_SCALE))) #if (LWIP_TCP && (TCP_WND > (0xFFFFU << TCP_RCV_SCALE)))
@@ -221,18 +218,12 @@
#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT) #if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT)
#error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT" #error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT"
#endif #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"
#endif
#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING #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" #error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too"
#endif #endif
#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE #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" #error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets"
#endif #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 LWIP_NETCONN && LWIP_TCP
#if NETCONN_COPY != TCP_WRITE_FLAG_COPY #if NETCONN_COPY != TCP_WRITE_FLAG_COPY
#error "NETCONN_COPY != TCP_WRITE_FLAG_COPY" #error "NETCONN_COPY != TCP_WRITE_FLAG_COPY"
@@ -325,10 +316,10 @@
#if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN #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." #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 #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." #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 #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." #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 #endif
#if TCP_WND < TCP_MSS #if TCP_WND < TCP_MSS
@@ -345,6 +336,15 @@
void void
lwip_init(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 */ /* Modules initialization */
stats_init(); stats_init();
#if !NO_SYS #if !NO_SYS
@@ -369,9 +369,6 @@ lwip_init(void)
#if LWIP_TCP #if LWIP_TCP
tcp_init(); tcp_init();
#endif /* LWIP_TCP */ #endif /* LWIP_TCP */
#if LWIP_AUTOIP
autoip_init();
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP #if LWIP_IGMP
igmp_init(); igmp_init();
#endif /* LWIP_IGMP */ #endif /* LWIP_IGMP */

36
ext/lwip/src/core/ip.c Normal file → Executable file
View File

@@ -1,7 +1,24 @@
/** /**
* @file ip.c * @file
* Common IPv4 and IPv6 code * 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" #include "lwip/opt.h"
#if LWIP_IPV4 || LWIP_IPV6 #if LWIP_IPV4 || LWIP_IPV6

227
ext/lwip/src/core/ipv4/autoip.c Normal file → Executable file
View File

@@ -2,6 +2,28 @@
* @file * @file
* AutoIP Automatic LinkLocal IP Configuration * 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. * OF SUCH DAMAGE.
* *
* Author: Dominik Spies <kontakt@dspies.de> * 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" #include "lwip/opt.h"
@@ -79,35 +66,10 @@
#include "lwip/netif.h" #include "lwip/netif.h"
#include "lwip/autoip.h" #include "lwip/autoip.h"
#include "lwip/etharp.h" #include "lwip/etharp.h"
#include "lwip/prot/autoip.h"
#include <stdlib.h>
#include <string.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. /** Pseudo random macro based on netif informations.
* You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */ * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */
#ifndef LWIP_AUTOIP_RAND #ifndef LWIP_AUTOIP_RAND
@@ -115,7 +77,7 @@
((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \ ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \
((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \ ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \
((u32_t)((netif->hwaddr[4]) & 0xff))) + \ ((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 */ #endif /* LWIP_AUTOIP_RAND */
/** /**
@@ -124,7 +86,7 @@
*/ */
#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR #ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \ #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))) ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))
#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */ #endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */
@@ -132,7 +94,6 @@
static err_t autoip_arp_announce(struct netif *netif); static err_t autoip_arp_announce(struct netif *netif);
static void autoip_start_probing(struct netif *netif); static void autoip_start_probing(struct netif *netif);
/** /**
* @ingroup autoip * @ingroup autoip
* Set a statically allocated struct autoip to work with. * 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("netif != NULL", netif != NULL);
LWIP_ASSERT("autoip != NULL", autoip != 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 */ /* clear data structure */
memset(autoip, 0, sizeof(struct autoip)); memset(autoip, 0, sizeof(struct autoip));
/* autoip->state = AUTOIP_STATE_OFF; */ /* 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) /** 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 static void
autoip_restart(struct netif *netif) autoip_restart(struct netif *netif)
{ {
netif->autoip->tried_llipaddr++; struct autoip* autoip = netif_autoip_data(netif);
autoip->tried_llipaddr++;
autoip_start(netif); autoip_start(netif);
} }
@@ -171,6 +134,8 @@ autoip_restart(struct netif *netif)
static void static void
autoip_handle_arp_conflict(struct netif *netif) 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 /* RFC3927, 2.5 "Conflict Detection and Defense" allows two options where
a) means retreat on the first conflict and a) means retreat on the first conflict and
b) allows to keep an already configured address when having only one 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 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. */ 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 */ /* retreat, there was a conflicting ARP in the last DEFEND_INTERVAL seconds */
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n")); ("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, LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n")); ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
autoip_arp_announce(netif); 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 static void
autoip_create_addr(struct netif *netif, ip4_addr_t *ipaddr) 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 /* 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 * compliant to RFC 3927 Section 2.1
* We have 254 * 256 possibilities */ * We have 254 * 256 possibilities */
u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif)); u32_t addr = lwip_ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
addr += netif->autoip->tried_llipaddr; addr += autoip->tried_llipaddr;
addr = AUTOIP_NET | (addr & 0xffff); addr = AUTOIP_NET | (addr & 0xffff);
/* Now, 169.254.0.0 <= addr <= 169.254.255.255 */ /* 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) && LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
(addr <= AUTOIP_RANGE_END)); (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, 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", ("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))); 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 static err_t
autoip_arp_probe(struct netif *netif) autoip_arp_probe(struct netif *netif)
{ {
struct autoip* autoip = netif_autoip_data(netif);
/* this works because netif->ip_addr is ANY */ /* 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 static err_t
autoip_bind(struct netif *netif) autoip_bind(struct netif *netif)
{ {
struct autoip *autoip = netif->autoip; struct autoip* autoip = netif_autoip_data(netif);
ip4_addr_t sn_mask, gw_addr; ip4_addr_t sn_mask, gw_addr;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
@@ -285,7 +253,7 @@ autoip_bind(struct netif *netif)
err_t err_t
autoip_start(struct netif *netif) autoip_start(struct netif *netif)
{ {
struct autoip *autoip = netif->autoip; struct autoip* autoip = netif_autoip_data(netif);
err_t result = ERR_OK; err_t result = ERR_OK;
LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;); 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 /* Set IP-Address, Netmask and Gateway to 0 to make sure that
* ARP Packets are formed correctly * 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, LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], ("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)); memset(autoip, 0, sizeof(struct autoip));
/* store this AutoIP client in the netif */ /* 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")); LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));
} else { } else {
autoip->state = AUTOIP_STATE_OFF; autoip->state = AUTOIP_STATE_OFF;
@@ -329,14 +297,14 @@ autoip_start(struct netif *netif)
static void static void
autoip_start_probing(struct netif *netif) autoip_start_probing(struct netif *netif)
{ {
struct autoip *autoip = netif->autoip; struct autoip* autoip = netif_autoip_data(netif);
autoip->state = AUTOIP_STATE_PROBING; autoip->state = AUTOIP_STATE_PROBING;
autoip->sent_num = 0; autoip->sent_num = 0;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, 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", ("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_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
/* time to wait to first probe, this is randomly /* time to wait to first probe, this is randomly
* chosen out of 0 to PROBE_WAIT seconds. * chosen out of 0 to PROBE_WAIT seconds.
@@ -363,7 +331,9 @@ autoip_start_probing(struct netif *netif)
void void
autoip_network_changed(struct netif *netif) 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); autoip_start_probing(netif);
} }
} }
@@ -377,10 +347,12 @@ autoip_network_changed(struct netif *netif)
err_t err_t
autoip_stop(struct netif *netif) autoip_stop(struct netif *netif)
{ {
if (netif->autoip) { struct autoip* autoip = netif_autoip_data(netif);
netif->autoip->state = AUTOIP_STATE_OFF;
if (autoip != NULL) {
autoip->state = AUTOIP_STATE_OFF;
if (ip4_addr_islinklocal(netif_ip4_addr(netif))) { 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; return ERR_OK;
@@ -395,45 +367,46 @@ autoip_tmr(void)
struct netif *netif = netif_list; struct netif *netif = netif_list;
/* loop through netif's */ /* loop through netif's */
while (netif != NULL) { while (netif != NULL) {
struct autoip* autoip = netif_autoip_data(netif);
/* only act on AutoIP configured interfaces */ /* only act on AutoIP configured interfaces */
if (netif->autoip != NULL) { if (autoip != NULL) {
if (netif->autoip->lastconflict > 0) { if (autoip->lastconflict > 0) {
netif->autoip->lastconflict--; autoip->lastconflict--;
} }
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n", ("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) { if (autoip->ttw > 0) {
netif->autoip->ttw--; autoip->ttw--;
} }
switch(netif->autoip->state) { switch(autoip->state) {
case AUTOIP_STATE_PROBING: case AUTOIP_STATE_PROBING:
if (netif->autoip->ttw == 0) { if (autoip->ttw == 0) {
if (netif->autoip->sent_num >= PROBE_NUM) { if (autoip->sent_num >= PROBE_NUM) {
/* Switch to ANNOUNCING: now we can bind to an IP address and use it */ /* 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(netif);
/* autoip_bind() calls netif_set_addr(): this triggers a gratuitous ARP /* autoip_bind() calls netif_set_addr(): this triggers a gratuitous ARP
which counts as an announcement */ which counts as an announcement */
netif->autoip->sent_num = 1; autoip->sent_num = 1;
netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, 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", ("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_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
} else { } else {
autoip_arp_probe(netif); autoip_arp_probe(netif);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() PROBING Sent Probe\n")); LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() PROBING Sent Probe\n"));
netif->autoip->sent_num++; autoip->sent_num++;
if (netif->autoip->sent_num == PROBE_NUM) { if (autoip->sent_num == PROBE_NUM) {
/* calculate time to wait to for announce */ /* 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 { } else {
/* calculate time to wait to next probe */ /* 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_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +
PROBE_MIN * AUTOIP_TICKS_PER_SECOND); PROBE_MIN * AUTOIP_TICKS_PER_SECOND);
} }
@@ -442,20 +415,20 @@ autoip_tmr(void)
break; break;
case AUTOIP_STATE_ANNOUNCING: case AUTOIP_STATE_ANNOUNCING:
if (netif->autoip->ttw == 0) { if (autoip->ttw == 0) {
autoip_arp_announce(netif); autoip_arp_announce(netif);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() ANNOUNCING Sent Announce\n")); LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() ANNOUNCING Sent Announce\n"));
netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND; autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
netif->autoip->sent_num++; autoip->sent_num++;
if (netif->autoip->sent_num >= ANNOUNCE_NUM) { if (autoip->sent_num >= ANNOUNCE_NUM) {
netif->autoip->state = AUTOIP_STATE_BOUND; autoip->state = AUTOIP_STATE_BOUND;
netif->autoip->sent_num = 0; autoip->sent_num = 0;
netif->autoip->ttw = 0; autoip->ttw = 0;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, 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", ("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_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
} }
} }
break; 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 netif network interface to use for autoip processing
* @param hdr Incoming ARP packet * @param hdr Incoming ARP packet
@@ -479,8 +452,10 @@ autoip_tmr(void)
void void
autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) 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")); 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 ip.src == llipaddr && hw.src != netif->hwaddr
* *
* when probing ip.dst == 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(&sipaddr, &hdr->sipaddr);
IPADDR2_COPY(&dipaddr, &hdr->dipaddr); IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
if (netif->autoip->state == AUTOIP_STATE_PROBING) { if (autoip->state == AUTOIP_STATE_PROBING) {
/* RFC 3927 Section 2.2.1: /* RFC 3927 Section 2.2.1:
* from beginning to after ANNOUNCE_WAIT * from beginning to after ANNOUNCE_WAIT
* seconds we have a conflict if * seconds we have a conflict if
* ip.src == llipaddr OR * ip.src == llipaddr OR
* ip.dst == llipaddr && hw.src != own hwaddr * ip.dst == llipaddr && hw.src != own hwaddr
*/ */
if ((ip4_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) || if ((ip4_addr_cmp(&sipaddr, &autoip->llipaddr)) ||
(ip4_addr_cmp(&dipaddr, &netif->autoip->llipaddr) && (ip4_addr_isany_val(sipaddr) &&
ip4_addr_cmp(&dipaddr, &autoip->llipaddr) &&
!eth_addr_cmp(&netifaddr, &hdr->shwaddr))) { !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
("autoip_arp_reply(): Probe Conflict detected\n")); ("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 * in any state we have a conflict if
* ip.src == llipaddr && hw.src != own hwaddr * 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)) { !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
("autoip_arp_reply(): Conflicting ARP-Packet detected\n")); ("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
@@ -534,13 +510,18 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
u8_t u8_t
autoip_supplied_address(const struct netif *netif) autoip_supplied_address(const struct netif *netif)
{ {
if ((netif != NULL) && (netif->autoip != NULL)) { if ((netif != NULL) && (netif_autoip_data(netif) != NULL)) {
if ((netif->autoip->state == AUTOIP_STATE_BOUND) || struct autoip* autoip = netif_autoip_data(netif);
(netif->autoip->state == AUTOIP_STATE_ANNOUNCING)) { return (autoip->state == AUTOIP_STATE_BOUND) || (autoip->state == AUTOIP_STATE_ANNOUNCING);
return 1;
}
} }
return 0; 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 */ #endif /* LWIP_IPV4 && LWIP_AUTOIP */

284
ext/lwip/src/core/ipv4/dhcp.c Normal file → Executable file
View File

@@ -2,6 +2,26 @@
* @file * @file
* Dynamic Host Configuration Protocol client * 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> * 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" #include "lwip/opt.h"
@@ -86,6 +74,7 @@
#include "lwip/autoip.h" #include "lwip/autoip.h"
#include "lwip/dns.h" #include "lwip/dns.h"
#include "lwip/etharp.h" #include "lwip/etharp.h"
#include "lwip/prot/dhcp.h"
#include <string.h> #include <string.h>
@@ -114,26 +103,40 @@
#define REBOOT_TRIES 2 #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 /** Option handling: options are parsed in dhcp_parse_reply
* and saved in an array where other functions can load them from. * and saved in an array where other functions can load them from.
* This might be moved into the struct dhcp (not necessarily since * This might be moved into the struct dhcp (not necessarily since
* lwIP is single-threaded and the array is only used while in recv * lwIP is single-threaded and the array is only used while in recv
* callback). */ * callback). */
#define DHCP_OPTION_IDX_OVERLOAD 0 enum dhcp_option_idx {
#define DHCP_OPTION_IDX_MSG_TYPE 1 DHCP_OPTION_IDX_OVERLOAD = 0,
#define DHCP_OPTION_IDX_SERVER_ID 2 DHCP_OPTION_IDX_MSG_TYPE,
#define DHCP_OPTION_IDX_LEASE_TIME 3 DHCP_OPTION_IDX_SERVER_ID,
#define DHCP_OPTION_IDX_T1 4 DHCP_OPTION_IDX_LEASE_TIME,
#define DHCP_OPTION_IDX_T2 5 DHCP_OPTION_IDX_T1,
#define DHCP_OPTION_IDX_SUBNET_MASK 6 DHCP_OPTION_IDX_T2,
#define DHCP_OPTION_IDX_ROUTER 7 DHCP_OPTION_IDX_SUBNET_MASK,
#define DHCP_OPTION_IDX_DNS_SERVER 8 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 #if LWIP_DHCP_GET_NTP_SRV
#define DHCP_OPTION_IDX_NTP_SERVER (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS) DHCP_OPTION_IDX_NTP_SERVER,
#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_NTP_SERVER + LWIP_DHCP_MAX_NTP_SERVERS) DHCP_OPTION_IDX_NTP_SERVER_LAST = DHCP_OPTION_IDX_NTP_SERVER + LWIP_DHCP_MAX_NTP_SERVERS - 1,
#else /* LWIP_DHCP_GET_NTP_SRV */
#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS)
#endif /* LWIP_DHCP_GET_NTP_SRV */ #endif /* LWIP_DHCP_GET_NTP_SRV */
DHCP_OPTION_IDX_MAX
};
/** Holds the decoded option values, only valid while in dhcp_recv. /** Holds the decoded option values, only valid while in dhcp_recv.
@todo: move this into struct dhcp? */ @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[] = { static u8_t dhcp_discover_request_options[] = {
DHCP_OPTION_SUBNET_MASK, DHCP_OPTION_SUBNET_MASK,
DHCP_OPTION_ROUTER, DHCP_OPTION_ROUTER,
DHCP_OPTION_BROADCAST, DHCP_OPTION_BROADCAST
DHCP_OPTION_DNS_SERVER #if LWIP_DHCP_PROVIDE_DNS_SERVERS
, DHCP_OPTION_DNS_SERVER
#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
#if LWIP_DHCP_GET_NTP_SRV #if LWIP_DHCP_GET_NTP_SRV
, DHCP_OPTION_NTP , DHCP_OPTION_NTP
#endif /* LWIP_DHCP_GET_NTP_SRV */ #endif /* LWIP_DHCP_GET_NTP_SRV */
@@ -221,8 +226,8 @@ dhcp_inc_pcb_refcount(void)
ip_set_option(dhcp_pcb, SOF_BROADCAST); 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 */ /* 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_bind(dhcp_pcb, IP4_ADDR_ANY, DHCP_CLIENT_PORT);
udp_connect(dhcp_pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); udp_connect(dhcp_pcb, IP4_ADDR_ANY, DHCP_SERVER_PORT);
udp_recv(dhcp_pcb, dhcp_recv, NULL); udp_recv(dhcp_pcb, dhcp_recv, NULL);
} }
@@ -259,14 +264,15 @@ dhcp_dec_pcb_refcount(void)
static void static void
dhcp_handle_nak(struct netif *netif) 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", 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)); (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
/* Change to a defined state - set this before assigning the address /* Change to a defined state - set this before assigning the address
to ensure the callback can use dhcp_supplied_address() */ to ensure the callback can use dhcp_supplied_address() */
dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF); dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF);
/* remove IP address from interface (must no longer be used, as per RFC2131) */ /* 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 */ /* We can immediately restart discovery */
dhcp_discover(netif); dhcp_discover(netif);
} }
@@ -284,7 +290,7 @@ dhcp_handle_nak(struct netif *netif)
static void static void
dhcp_check(struct netif *netif) dhcp_check(struct netif *netif)
{ {
struct dhcp *dhcp = netif->dhcp; struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result; err_t result;
u16_t msecs; u16_t msecs;
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0], 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 static void
dhcp_handle_offer(struct netif *netif) 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", 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)); (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
/* obtain the server address */ /* obtain the server address */
if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) { 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", 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)))); ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr))));
/* remember offered address */ /* remember offered address */
@@ -344,7 +351,7 @@ dhcp_handle_offer(struct netif *netif)
static err_t static err_t
dhcp_select(struct netif *netif) dhcp_select(struct netif *netif)
{ {
struct dhcp *dhcp = netif->dhcp; struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result; err_t result;
u16_t msecs; u16_t msecs;
u8_t i; u8_t i;
@@ -360,10 +367,10 @@ dhcp_select(struct netif *netif)
/* MUST request the offered IP address */ /* MUST request the offered IP address */
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); 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(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)); 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++) { 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); pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
/* send broadcast to any DHCP server */ /* 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); dhcp_delete_msg(dhcp);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n")); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n"));
} else { } else {
@@ -396,6 +403,7 @@ dhcp_select(struct netif *netif)
/** /**
* The DHCP timer that checks for lease renewal/rebind timeouts. * The DHCP timer that checks for lease renewal/rebind timeouts.
* Must be called once a minute (see @ref DHCP_COARSE_TIMER_SECS).
*/ */
void void
dhcp_coarse_tmr(void) dhcp_coarse_tmr(void)
@@ -405,7 +413,7 @@ dhcp_coarse_tmr(void)
/* iterate through all network interfaces */ /* iterate through all network interfaces */
while (netif != NULL) { while (netif != NULL) {
/* only act on DHCP configured interfaces */ /* 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)) { if ((dhcp != NULL) && (dhcp->state != DHCP_STATE_OFF)) {
/* compare lease time to expire timeout */ /* compare lease time to expire timeout */
if (dhcp->t0_timeout && (++dhcp->lease_used == dhcp->t0_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. * A DHCP server is expected to respond within a short period of time.
* This timer checks whether an outstanding DHCP request is timed out. * This timer checks whether an outstanding DHCP request is timed out.
@@ -442,14 +451,15 @@ dhcp_fine_tmr(void)
struct netif *netif = netif_list; struct netif *netif = netif_list;
/* loop through netif's */ /* loop through netif's */
while (netif != NULL) { while (netif != NULL) {
struct dhcp *dhcp = netif_dhcp_data(netif);
/* only act on DHCP configured interfaces */ /* only act on DHCP configured interfaces */
if (netif->dhcp != NULL) { if (dhcp != NULL) {
/* timer is active (non zero), and is about to trigger now */ /* timer is active (non zero), and is about to trigger now */
if (netif->dhcp->request_timeout > 1) { if (dhcp->request_timeout > 1) {
netif->dhcp->request_timeout--; dhcp->request_timeout--;
} }
else if (netif->dhcp->request_timeout == 1) { else if (dhcp->request_timeout == 1) {
netif->dhcp->request_timeout--; dhcp->request_timeout--;
/* { netif->dhcp->request_timeout == 0 } */ /* { netif->dhcp->request_timeout == 0 } */
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n")); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));
/* this client's request timeout triggered */ /* this client's request timeout triggered */
@@ -472,7 +482,8 @@ dhcp_fine_tmr(void)
static void static void
dhcp_timeout(struct netif *netif) 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")); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n"));
/* back-off period has passed, or server selection timed out */ /* back-off period has passed, or server selection timed out */
if ((dhcp->state == DHCP_STATE_BACKING_OFF) || (dhcp->state == DHCP_STATE_SELECTING)) { if ((dhcp->state == DHCP_STATE_BACKING_OFF) || (dhcp->state == DHCP_STATE_SELECTING)) {
@@ -518,7 +529,8 @@ dhcp_timeout(struct netif *netif)
static void static void
dhcp_t1_timeout(struct netif *netif) 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")); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n"));
if ((dhcp->state == DHCP_STATE_REQUESTING) || (dhcp->state == DHCP_STATE_BOUND) || if ((dhcp->state == DHCP_STATE_REQUESTING) || (dhcp->state == DHCP_STATE_BOUND) ||
(dhcp->state == DHCP_STATE_RENEWING)) { (dhcp->state == DHCP_STATE_RENEWING)) {
@@ -530,9 +542,9 @@ dhcp_t1_timeout(struct netif *netif)
DHCP_STATE_RENEWING, not DHCP_STATE_BOUND */ DHCP_STATE_RENEWING, not DHCP_STATE_BOUND */
dhcp_renew(netif); dhcp_renew(netif);
/* Calculate next timeout */ /* 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 static void
dhcp_t2_timeout(struct netif *netif) 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")); 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) || if ((dhcp->state == DHCP_STATE_REQUESTING) || (dhcp->state == DHCP_STATE_BOUND) ||
(dhcp->state == DHCP_STATE_RENEWING) || (dhcp->state == DHCP_STATE_REBINDING)) { (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_STATE_REBINDING, not DHCP_STATE_BOUND */
dhcp_rebind(netif); dhcp_rebind(netif);
/* Calculate next timeout */ /* 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 static void
dhcp_handle_ack(struct netif *netif) dhcp_handle_ack(struct netif *netif)
{ {
struct dhcp *dhcp = netif->dhcp; struct dhcp *dhcp = netif_dhcp_data(netif);
#if LWIP_DNS || LWIP_DHCP_GET_NTP_SRV
#if LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV
u8_t n; 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 #if LWIP_DHCP_GET_NTP_SRV
ip4_addr_t ntp_server_addrs[LWIP_DHCP_MAX_NTP_SERVERS]; ip4_addr_t ntp_server_addrs[LWIP_DHCP_MAX_NTP_SERVERS];
#endif #endif
@@ -615,13 +629,13 @@ dhcp_handle_ack(struct netif *netif)
#if LWIP_DHCP_BOOTP_FILE #if LWIP_DHCP_BOOTP_FILE
/* copy boot server address, /* copy boot server address,
boot file name copied in dhcp_parse_reply if not overloaded */ 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 */ #endif /* LWIP_DHCP_BOOTP_FILE */
/* subnet mask given? */ /* subnet mask given? */
if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) { if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) {
/* remember given 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; dhcp->subnet_mask_given = 1;
} else { } else {
dhcp->subnet_mask_given = 0; dhcp->subnet_mask_given = 0;
@@ -629,25 +643,25 @@ dhcp_handle_ack(struct netif *netif)
/* gateway router */ /* gateway router */
if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_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 #if LWIP_DHCP_GET_NTP_SRV
/* NTP servers */ /* NTP servers */
for (n = 0; (n < LWIP_DHCP_MAX_NTP_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n); n++) { 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); dhcp_set_ntp_servers(n, ntp_server_addrs);
#endif /* LWIP_DHCP_GET_NTP_SRV */ #endif /* LWIP_DHCP_GET_NTP_SRV */
#if LWIP_DNS #if LWIP_DHCP_PROVIDE_DNS_SERVERS
/* 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_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); 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("netif != NULL", netif != NULL);
LWIP_ASSERT("dhcp != NULL", dhcp != 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 */ /* clear data structure */
memset(dhcp, 0, sizeof(struct dhcp)); memset(dhcp, 0, sizeof(struct dhcp));
/* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */ /* 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); LWIP_ASSERT("netif != NULL", netif != NULL);
if (netif->dhcp != NULL) { if (netif_dhcp_data(netif) != NULL) {
mem_free(netif->dhcp); mem_free(netif_dhcp_data(netif));
netif->dhcp = NULL; 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 != NULL", (netif != NULL), return ERR_ARG;);
LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), 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)); 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 */ /* check MTU of the netif */
@@ -730,7 +744,7 @@ dhcp_start(struct netif *netif)
} }
/* store this dhcp client in the netif */ /* 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")); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp"));
/* already has DHCP client attached */ /* already has DHCP client attached */
} else { } else {
@@ -829,7 +843,8 @@ dhcp_inform(struct netif *netif)
void void
dhcp_network_changed(struct netif *netif) dhcp_network_changed(struct netif *netif)
{ {
struct dhcp *dhcp = netif->dhcp; struct dhcp *dhcp = netif_dhcp_data(netif);
if (!dhcp) if (!dhcp)
return; return;
switch (dhcp->state) { switch (dhcp->state) {
@@ -862,7 +877,8 @@ dhcp_network_changed(struct netif *netif)
#if DHCP_DOES_ARP_CHECK #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 netif the network interface on which the reply was received
* @param addr The IP address we received a reply from * @param addr The IP address we received a reply from
@@ -870,15 +886,18 @@ dhcp_network_changed(struct netif *netif)
void void
dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr) dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr)
{ {
struct dhcp *dhcp;
LWIP_ERROR("netif != NULL", (netif != NULL), return;); LWIP_ERROR("netif != NULL", (netif != NULL), return;);
dhcp = netif_dhcp_data(netif);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n")); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n"));
/* is a DHCP client doing an ARP check? */ /* 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", 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))); ip4_addr_get_u32(addr)));
/* did a host respond with the address we /* did a host respond with the address we
were offered by the DHCP server? */ 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 */ /* we will not accept the offered address */
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, 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")); ("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 static err_t
dhcp_decline(struct netif *netif) dhcp_decline(struct netif *netif)
{ {
struct dhcp *dhcp = netif->dhcp; struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result = ERR_OK; err_t result = ERR_OK;
u16_t msecs; u16_t msecs;
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n")); 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); result = dhcp_create_msg(netif, dhcp, DHCP_DECLINE);
if (result == ERR_OK) { if (result == ERR_OK) {
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); 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); dhcp_option_trailer(dhcp);
/* resize pbuf to reflect true size of options */ /* resize pbuf to reflect true size of options */
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
/* per section 4.4.4, broadcast DECLINE messages */ /* 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); dhcp_delete_msg(dhcp);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n")); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
} else { } else {
@@ -941,7 +960,7 @@ dhcp_decline(struct netif *netif)
static err_t static err_t
dhcp_discover(struct netif *netif) dhcp_discover(struct netif *netif)
{ {
struct dhcp *dhcp = netif->dhcp; struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result = ERR_OK; err_t result = ERR_OK;
u16_t msecs; u16_t msecs;
u8_t i; 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); 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")); 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")); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
dhcp_delete_msg(dhcp); dhcp_delete_msg(dhcp);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n")); 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; struct dhcp *dhcp;
ip4_addr_t sn_mask, gw_addr; ip4_addr_t sn_mask, gw_addr;
LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;); 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_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)); 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 err_t
dhcp_renew(struct netif *netif) dhcp_renew(struct netif *netif)
{ {
struct dhcp *dhcp = netif->dhcp; struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result; err_t result;
u16_t msecs; u16_t msecs;
u8_t i; u8_t i;
@@ -1159,7 +1178,7 @@ dhcp_renew(struct netif *netif)
static err_t static err_t
dhcp_rebind(struct netif *netif) dhcp_rebind(struct netif *netif)
{ {
struct dhcp *dhcp = netif->dhcp; struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result; err_t result;
u16_t msecs; u16_t msecs;
u8_t i; u8_t i;
@@ -1209,7 +1228,7 @@ dhcp_rebind(struct netif *netif)
static err_t static err_t
dhcp_reboot(struct netif *netif) dhcp_reboot(struct netif *netif)
{ {
struct dhcp *dhcp = netif->dhcp; struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result; err_t result;
u16_t msecs; u16_t msecs;
u8_t i; u8_t i;
@@ -1220,10 +1239,10 @@ dhcp_reboot(struct netif *netif)
result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);
if (result == ERR_OK) { if (result == ERR_OK) {
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
dhcp_option_short(dhcp, 576); dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN_MIN_REQUIRED);
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); 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)); 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++) { for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) {
@@ -1253,14 +1272,14 @@ dhcp_reboot(struct netif *netif)
/** /**
* @ingroup dhcp4 * @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 * @param netif network interface which must release its lease
*/ */
err_t err_t
dhcp_release(struct netif *netif) dhcp_release(struct netif *netif)
{ {
struct dhcp *dhcp = netif->dhcp; struct dhcp *dhcp = netif_dhcp_data(netif);
err_t result; err_t result;
ip_addr_t server_ip_addr; ip_addr_t server_ip_addr;
u8_t is_dhcp_supplied_address; u8_t is_dhcp_supplied_address;
@@ -1295,7 +1314,7 @@ dhcp_release(struct netif *netif)
result = dhcp_create_msg(netif, dhcp, DHCP_RELEASE); result = dhcp_create_msg(netif, dhcp, DHCP_RELEASE);
if (result == ERR_OK) { if (result == ERR_OK) {
dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); 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); 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")); 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) */ /* 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; return result;
} }
@@ -1325,7 +1344,7 @@ dhcp_stop(struct netif *netif)
{ {
struct dhcp *dhcp; struct dhcp *dhcp;
LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;); 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")); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_stop()\n"));
/* netif is DHCP configured? */ /* netif is DHCP configured? */
@@ -1410,14 +1429,15 @@ dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif)
if (netif->hostname != NULL) { if (netif->hostname != NULL) {
size_t namelen = strlen(netif->hostname); size_t namelen = strlen(netif->hostname);
if (namelen > 0) { if (namelen > 0) {
u8_t len; size_t len;
const char *p = netif->hostname; const char *p = netif->hostname;
/* Shrink len to available bytes (need 2 bytes for OPTION_HOSTNAME /* Shrink len to available bytes (need 2 bytes for OPTION_HOSTNAME
and 1 byte for trailer) */ and 1 byte for trailer) */
size_t available = DHCP_OPTIONS_LEN - dhcp->options_out_len - 3; size_t available = DHCP_OPTIONS_LEN - dhcp->options_out_len - 3;
LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available); LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available);
len = LWIP_MIN(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--) { while (len--) {
dhcp_option_byte(dhcp, *p++); dhcp_option_byte(dhcp, *p++);
} }
@@ -1487,7 +1507,7 @@ again:
int decode_idx = -1; int decode_idx = -1;
u16_t val_offset = offset + 2; u16_t val_offset = offset + 2;
/* len byte might be in the next pbuf */ /* len byte might be in the next pbuf */
if (offset + 1 < q->len) { if ((offset + 1) < q->len) {
len = options[offset + 1]; len = options[offset + 1];
} else { } else {
len = (q->next != NULL ? ((u8_t*)q->next->payload)[0] : 0); 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;); LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_ROUTER; decode_idx = DHCP_OPTION_IDX_ROUTER;
break; break;
#if LWIP_DHCP_PROVIDE_DNS_SERVERS
case(DHCP_OPTION_DNS_SERVER): case(DHCP_OPTION_DNS_SERVER):
/* special case: there might be more than one 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 */ /* limit number of DNS servers */
decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS); decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS);
LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_DNS_SERVER; decode_idx = DHCP_OPTION_IDX_DNS_SERVER;
break; break;
#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
case(DHCP_OPTION_LEASE_TIME): case(DHCP_OPTION_LEASE_TIME):
LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_LEASE_TIME; decode_idx = DHCP_OPTION_IDX_LEASE_TIME;
@@ -1526,7 +1548,7 @@ again:
#if LWIP_DHCP_GET_NTP_SRV #if LWIP_DHCP_GET_NTP_SRV
case(DHCP_OPTION_NTP): case(DHCP_OPTION_NTP):
/* special case: there might be more than one 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 NTP servers */ /* limit number of NTP servers */
decode_len = LWIP_MIN(len, 4 * LWIP_DHCP_MAX_NTP_SERVERS); decode_len = LWIP_MIN(len, 4 * LWIP_DHCP_MAX_NTP_SERVERS);
LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
@@ -1535,6 +1557,8 @@ again:
#endif /* LWIP_DHCP_GET_NTP_SRV*/ #endif /* LWIP_DHCP_GET_NTP_SRV*/
case(DHCP_OPTION_OVERLOAD): case(DHCP_OPTION_OVERLOAD):
LWIP_ERROR("len == 1", len == 1, return ERR_VAL;); LWIP_ERROR("len == 1", len == 1, return ERR_VAL;);
/* decode overload only in options, not in file/sname: invalid packet */
LWIP_ERROR("overload in file/sname", options_idx == DHCP_OPTIONS_OFS, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_OVERLOAD; decode_idx = DHCP_OPTION_IDX_OVERLOAD;
break; break;
case(DHCP_OPTION_MESSAGE_TYPE): case(DHCP_OPTION_MESSAGE_TYPE):
@@ -1566,18 +1590,20 @@ decode_next:
LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX); LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX);
if (!dhcp_option_given(dhcp, decode_idx)) { if (!dhcp_option_given(dhcp, decode_idx)) {
copy_len = LWIP_MIN(decode_len, 4); 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) { if (decode_len > 4) {
/* decode more than one u32_t */ /* 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_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; decode_len -= 4;
val_offset += 4; val_offset += 4;
decode_idx++; decode_idx++;
goto decode_next; goto decode_next;
} else if (decode_len == 4) { } else if (decode_len == 4) {
value = ntohl(value); value = lwip_ntohl(value);
} else { } else {
LWIP_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL;); LWIP_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL;);
value = ((u8_t*)&value)[0]; value = ((u8_t*)&value)[0];
@@ -1622,7 +1648,9 @@ decode_next:
if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) && if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) &&
(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK)) (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK))
/* copy bootp file name, don't care for sname (server hostname) */ /* 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 */ /* make sure the string is really NULL-terminated */
dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0; dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0;
} }
@@ -1650,7 +1678,7 @@ static void
dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) 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 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; struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;
u8_t msg_type; u8_t msg_type;
u8_t i; u8_t i;
@@ -1694,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 */ /* 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, 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; goto free_pbuf_and_return;
} }
/* option fields could be unfold? */ /* option fields could be unfold? */
@@ -1825,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->htype = DHCP_HTYPE_ETH;
dhcp->msg_out->hlen = netif->hwaddr_len; dhcp->msg_out->hlen = netif->hwaddr_len;
dhcp->msg_out->hops = 0; 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; dhcp->msg_out->secs = 0;
/* we don't need the broadcast flag since we can receive unicast traffic /* we don't need the broadcast flag since we can receive unicast traffic
before being fully configured! */ before being fully configured! */
@@ -1912,11 +1940,9 @@ dhcp_option_trailer(struct dhcp *dhcp)
u8_t u8_t
dhcp_supplied_address(const struct netif *netif) dhcp_supplied_address(const struct netif *netif)
{ {
if ((netif != NULL) && (netif->dhcp != NULL)) { if ((netif != NULL) && (netif_dhcp_data(netif) != NULL)) {
if ((netif->dhcp->state == DHCP_STATE_BOUND) || struct dhcp* dhcp = netif_dhcp_data(netif);
(netif->dhcp->state == DHCP_STATE_RENEWING)) { return (dhcp->state == DHCP_STATE_BOUND) || (dhcp->state == DHCP_STATE_RENEWING);
return 1;
}
} }
return 0; return 0;
} }

299
ext/lwip/src/core/ipv4/etharp.c Normal file → Executable file
View File

@@ -52,9 +52,14 @@
#include "lwip/snmp.h" #include "lwip/snmp.h"
#include "lwip/dhcp.h" #include "lwip/dhcp.h"
#include "lwip/autoip.h" #include "lwip/autoip.h"
#include "netif/ethernet.h"
#include <string.h> #include <string.h>
#ifdef LWIP_HOOK_FILENAME
#include LWIP_HOOK_FILENAME
#endif
#if LWIP_IPV4 && LWIP_ARP /* don't build if not configured for use in lwipopts.h */ #if LWIP_IPV4 && LWIP_ARP /* don't build if not configured for use in lwipopts.h */
/** Re-request a used ARP entry 1 minute before it would expire to prevent /** Re-request a used ARP entry 1 minute before it would expire to prevent
@@ -71,8 +76,7 @@
*/ */
#define ARP_MAXPENDING 5 #define ARP_MAXPENDING 5
#define HWTYPE_ETHERNET 1 /** ARP states */
enum etharp_state { enum etharp_state {
ETHARP_STATE_EMPTY = 0, ETHARP_STATE_EMPTY = 0,
ETHARP_STATE_PENDING, ETHARP_STATE_PENDING,
@@ -128,7 +132,11 @@ static u8_t etharp_cached_entry;
static err_t etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr* hw_dst_addr); static err_t etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr* hw_dst_addr);
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,
const struct eth_addr *hwdst_addr, const ip4_addr_t *ipdst_addr,
const u16_t opcode);
#if ARP_QUEUEING #if ARP_QUEUEING
/** /**
@@ -240,7 +248,7 @@ etharp_tmr(void)
* old entries. Heuristic choose the least important entry for recycling. * 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 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) * @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 * @return The ARP entry index that matched or is created, ERR_MEM if no
@@ -394,47 +402,6 @@ etharp_find_entry(const ip4_addr_t *ipaddr, u8_t flags, struct netif* netif)
return (err_t)i; 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. * Update (or insert) a IP/MAC address pair in the ARP cache.
* *
@@ -444,7 +411,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 netif netif related to this entry (used for NETIF_ADDRHINT)
* @param ipaddr IP address of the inserted ARP entry. * @param ipaddr IP address of the inserted ARP entry.
* @param ethaddr Ethernet address of the inserted ARP entry. * @param ethaddr Ethernet address of the inserted ARP entry.
* @param flags @see definition of ETHARP_FLAG_* * @param flags See @ref etharp_state
* *
* @return * @return
* - ERR_OK Successfully updated ARP cache. * - ERR_OK Successfully updated ARP cache.
@@ -518,7 +485,7 @@ etharp_update_arp_entry(struct netif *netif, const ip4_addr_t *ipaddr, struct et
arp_table[i].q = NULL; arp_table[i].q = NULL;
#endif /* ARP_QUEUEING */ #endif /* ARP_QUEUEING */
/* send the queued IP packet */ /* 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 */ /* free the queued IP packet */
pbuf_free(p); pbuf_free(p);
} }
@@ -532,7 +499,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 ipaddr IP address for the new static entry
* @param ethaddr ethernet 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 err_t
etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr) etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr)
@@ -658,56 +625,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 * 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. * send out queued IP packets. Updates cache with snooped address pairs.
@@ -715,47 +632,22 @@ etharp_ip_input(struct netif *netif, struct pbuf *p)
* Should be called for incoming ARP packets. The pbuf in the argument * Should be called for incoming ARP packets. The pbuf in the argument
* is freed by this function. * 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. * @param p The ARP packet that arrived on netif. Is freed by this function.
* * @param netif The lwIP network interface on which the ARP packet pbuf arrived.
* @return NULL
* *
* @see pbuf_free() * @see pbuf_free()
*/ */
void 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 etharp_hdr *hdr;
struct eth_hdr *ethhdr;
/* these are aligned properly, whereas the ARP header fields might not be */ /* these are aligned properly, whereas the ARP header fields might not be */
ip4_addr_t sipaddr, dipaddr; ip4_addr_t sipaddr, dipaddr;
u8_t for_us; u8_t for_us;
#if LWIP_AUTOIP
const u8_t * ethdst_hwaddr;
#endif /* LWIP_AUTOIP */
LWIP_ERROR("netif != NULL", (netif != NULL), return;); LWIP_ERROR("netif != NULL", (netif != NULL), return;);
/* drop short ARP packets: we have to check for p->len instead of p->tot_len here hdr = (struct etharp_hdr *)p->payload;
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 */
/* RFC 826 "Packet Reception": */ /* RFC 826 "Packet Reception": */
if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) || if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) ||
@@ -763,7 +655,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
(hdr->protolen != sizeof(ip4_addr_t)) || (hdr->protolen != sizeof(ip4_addr_t)) ||
(hdr->proto != PP_HTONS(ETHTYPE_IP))) { (hdr->proto != PP_HTONS(ETHTYPE_IP))) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, 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)); hdr->hwtype, (u16_t)hdr->hwlen, hdr->proto, (u16_t)hdr->protolen));
ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.proterr);
ETHARP_STATS_INC(etharp.drop); ETHARP_STATS_INC(etharp.drop);
@@ -808,55 +700,28 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
* reply. In any case, we time-stamp any existing ARP entry, * reply. In any case, we time-stamp any existing ARP entry,
* and possibly send out an IP packet that was queued on it. */ * 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? */ /* ARP request for our address? */
if (for_us) { if (for_us) {
/* send ARP response */
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n")); etharp_raw(netif,
/* Re-use pbuf to send ARP reply. (struct eth_addr *)netif->hwaddr, &hdr->shwaddr,
Since we are re-using an existing pbuf, we can't call etharp_raw since (struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif),
that would allocate a new pbuf. */ &hdr->shwaddr, &sipaddr,
hdr->opcode = htons(ARP_REPLY); 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 */
/* return ARP reply */
netif->linkoutput(netif, p);
/* we are not configured? */ /* we are not configured? */
} else if (ip4_addr_isany_val(*netif_ip4_addr(netif))) { } else if (ip4_addr_isany_val(*netif_ip4_addr(netif))) {
/* { for_us == 0 and netif->ip_addr.addr == 0 } */ /* { 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 */ /* request was not directed to us */
} else { } else {
/* { for_us == 0 and netif->ip_addr.addr != 0 } */ /* { 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; break;
case PP_HTONS(ARP_REPLY): case PP_HTONS(ARP_REPLY):
/* ARP reply. We already updated the ARP cache earlier. */ /* 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) #if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
/* DHCP wants to know about ARP replies from any host with an /* 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 * IP address also offered to us by the DHCP server. We do not
@@ -866,7 +731,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
#endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */ #endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */
break; break;
default: 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); ETHARP_STATS_INC(etharp.err);
break; break;
} }
@@ -899,8 +764,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), return ethernet_output(netif, q, (struct eth_addr*)(netif->hwaddr), &arp_table[arp_idx].ethaddr, ETHTYPE_IP);
&arp_table[arp_idx].ethaddr);
} }
/** /**
@@ -919,7 +783,7 @@ etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx)
* *
* @return * @return
* - ERR_RTE No route to destination (no gateway to external networks), * - 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 err_t
etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr) etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
@@ -932,19 +796,6 @@ etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
LWIP_ASSERT("q != NULL", q != NULL); LWIP_ASSERT("q != NULL", q != NULL);
LWIP_ASSERT("ipaddr != NULL", ipaddr != 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 /* Determine on destination hardware address. Broadcasts and multicasts
* are special, other IP addresses are looked up in the ARP table. */ * are special, other IP addresses are looked up in the ARP table. */
@@ -971,11 +822,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)) && if (!ip4_addr_netcmp(ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif)) &&
!ip4_addr_islinklocal(ipaddr)) { !ip4_addr_islinklocal(ipaddr)) {
#if LWIP_AUTOIP #if LWIP_AUTOIP
struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload + struct ip_hdr *iphdr = LWIP_ALIGNMENT_CAST(struct ip_hdr*, 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));
/* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with /* 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 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 on the same physical link. The host MUST NOT send the packet to any
@@ -1009,6 +856,9 @@ etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
if (etharp_cached_entry < ARP_TABLE_SIZE) { if (etharp_cached_entry < ARP_TABLE_SIZE) {
#endif /* LWIP_NETIF_HWADDRHINT */ #endif /* LWIP_NETIF_HWADDRHINT */
if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) && 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))) { (ip4_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) {
/* the per-pcb-cached entry is stable and the right one! */ /* the per-pcb-cached entry is stable and the right one! */
ETHARP_STATS_INC(etharp.cachehit); ETHARP_STATS_INC(etharp.cachehit);
@@ -1023,6 +873,9 @@ etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
throughput and etharp_find_entry() is kind of slow */ throughput and etharp_find_entry() is kind of slow */
for (i = 0; i < ARP_TABLE_SIZE; i++) { for (i = 0; i < ARP_TABLE_SIZE; i++) {
if ((arp_table[i].state >= ETHARP_STATE_STABLE) && 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))) { (ip4_addr_cmp(dst_addr, &arp_table[i].ipaddr))) {
/* found an existing, stable entry */ /* found an existing, stable entry */
ETHARP_SET_HINT(netif, i); ETHARP_SET_HINT(netif, i);
@@ -1037,7 +890,7 @@ etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
/* continuation for multicast/broadcast destinations */ /* continuation for multicast/broadcast destinations */
/* obtain source Ethernet address of the given interface */ /* obtain source Ethernet address of the given interface */
/* send packet directly on the link */ /* 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 +990,7 @@ etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q)
/* we have a valid IP->Ethernet address mapping */ /* we have a valid IP->Ethernet address mapping */
ETHARP_SET_HINT(netif, i); ETHARP_SET_HINT(netif, i);
/* send the packet */ /* 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 */ /* pending entry? (either just created or already pending */
} else if (arp_table[i].state == ETHARP_STATE_PENDING) { } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
/* entry is still pending, queue the given packet 'q' */ /* entry is still pending, queue the given packet 'q' */
@@ -1157,7 +1010,7 @@ etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q)
} }
if (copy_needed) { if (copy_needed) {
/* copy the whole packet into new pbufs */ /* 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 (p != NULL) {
if (pbuf_copy(p, q) != ERR_OK) { if (pbuf_copy(p, q) != ERR_OK) {
pbuf_free(p); pbuf_free(p);
@@ -1245,10 +1098,7 @@ etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q)
* ERR_MEM if the ARP packet couldn't be allocated * ERR_MEM if the ARP packet couldn't be allocated
* any other err_t on failure * any other err_t on failure
*/ */
#if !LWIP_AUTOIP static err_t
static
#endif /* LWIP_AUTOIP */
err_t
etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
const struct eth_addr *ethdst_addr, const struct eth_addr *ethdst_addr,
const struct eth_addr *hwsrc_addr, const ip4_addr_t *ipsrc_addr, const struct eth_addr *hwsrc_addr, const ip4_addr_t *ipsrc_addr,
@@ -1257,19 +1107,12 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
{ {
struct pbuf *p; struct pbuf *p;
err_t result = ERR_OK; 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; struct etharp_hdr *hdr;
#if LWIP_AUTOIP
const u8_t * ethdst_hwaddr;
#endif /* LWIP_AUTOIP */
LWIP_ASSERT("netif != NULL", netif != NULL); LWIP_ASSERT("netif != NULL", netif != NULL);
/* allocate a pbuf for the outgoing ARP request packet */ /* 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? */ /* could allocate a pbuf for an ARP request? */
if (p == NULL) { if (p == NULL) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
@@ -1278,26 +1121,15 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
return ERR_MEM; return ERR_MEM;
} }
LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr", 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; hdr = (struct etharp_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) */
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n")); 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!", LWIP_ASSERT("netif->hwaddr_len must be the same as ETH_HWADDR_LEN for etharp!",
(netif->hwaddr_len == ETH_HWADDR_LEN)); (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 */ /* Write the ARP MAC-Addresses */
ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr); ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr);
ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr); ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr);
@@ -1312,30 +1144,19 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
hdr->hwlen = ETH_HWADDR_LEN; hdr->hwlen = ETH_HWADDR_LEN;
hdr->protolen = sizeof(ip4_addr_t); 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 */ /* 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); ETHARP_STATS_INC(etharp.xmit);
/* free ARP query packet */ /* free ARP query packet */
pbuf_free(p); pbuf_free(p);

16
ext/lwip/src/core/ipv4/icmp.c Normal file → Executable file
View File

@@ -51,6 +51,10 @@
#include <string.h> #include <string.h>
#ifdef LWIP_HOOK_FILENAME
#include LWIP_HOOK_FILENAME
#endif
/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be /** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be
* used to modify and send a response packet (and to 1 if this is not the case, * used to modify and send a response packet (and to 1 if this is not the case,
* e.g. when link header is stripped of when receiving) */ * e.g. when link header is stripped of when receiving) */
@@ -81,7 +85,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
#endif /* LWIP_DEBUG */ #endif /* LWIP_DEBUG */
struct icmp_echo_hdr *iecho; struct icmp_echo_hdr *iecho;
const struct ip_hdr *iphdr_in; const struct ip_hdr *iphdr_in;
s16_t hlen; u16_t hlen;
const ip4_addr_t* src; const ip4_addr_t* src;
ICMP_STATS_INC(icmp.recv); ICMP_STATS_INC(icmp.recv);
@@ -148,7 +152,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
} }
#endif #endif
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN #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 /* p is not big enough to contain link headers
* allocate a new one and copy p into it * allocate a new one and copy p into it
*/ */
@@ -167,7 +171,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
/* copy the ip header */ /* copy the ip header */
MEMCPY(r->payload, iphdr_in, hlen); MEMCPY(r->payload, iphdr_in, hlen);
/* switch r->payload back to icmp header (cannot fail) */ /* 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); LWIP_ASSERT("icmp_input: moving r->payload to icmp header failed\n", 0);
pbuf_free(r); pbuf_free(r);
goto icmperr; goto icmperr;
@@ -194,7 +198,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
/* We generate an answer by switching the dest and src ip addresses, /* We generate an answer by switching the dest and src ip addresses,
* setting the icmp type to ECHO_RESPONSE and updating the checksum. */ * setting the icmp type to ECHO_RESPONSE and updating the checksum. */
iecho = (struct icmp_echo_hdr *)p->payload; 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")); LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Can't move over header in packet"));
} else { } else {
err_t ret; err_t ret;
@@ -236,7 +240,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
MIB2_STATS_INC(mib2.icmpoutechoreps); MIB2_STATS_INC(mib2.icmpoutechoreps);
/* send an ICMP packet */ /* 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); ICMP_TTL, 0, IP_PROTO_ICMP, inp);
if (ret != ERR_OK) { if (ret != ERR_OK) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %s\n", lwip_strerr(ret))); LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %s\n", lwip_strerr(ret)));
@@ -247,7 +251,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
if (type == ICMP_DUR) { if (type == ICMP_DUR) {
MIB2_STATS_INC(mib2.icmpindestunreachs); MIB2_STATS_INC(mib2.icmpindestunreachs);
} else if (type == ICMP_TE) { } else if (type == ICMP_TE) {
MIB2_STATS_INC(mib2.icmpindestunreachs); MIB2_STATS_INC(mib2.icmpintimeexcds);
} else if (type == ICMP_PP) { } else if (type == ICMP_PP) {
MIB2_STATS_INC(mib2.icmpinparmprobs); MIB2_STATS_INC(mib2.icmpinparmprobs);
} else if (type == ICMP_SQ) { } else if (type == ICMP_SQ) {

213
ext/lwip/src/core/ipv4/igmp.c Normal file → Executable file
View File

@@ -2,6 +2,9 @@
* @file * @file
* IGMP - Internet Group Management Protocol * IGMP - Internet Group Management Protocol
* *
* @defgroup igmp IGMP
* @ingroup ip4
* To be called from TCPIP thread
*/ */
/* /*
@@ -38,12 +41,6 @@
* source code. * source code.
*/ */
/**
* @defgroup igmp IGMP
* @ingroup ip4
* To be called from TCPIP thread
*/
/*------------------------------------------------------------- /*-------------------------------------------------------------
Note 1) Note 1)
Although the rfc requires V1 AND V2 capability Although the rfc requires V1 AND V2 capability
@@ -95,63 +92,21 @@ Steve Reynolds
#include "lwip/inet_chksum.h" #include "lwip/inet_chksum.h"
#include "lwip/netif.h" #include "lwip/netif.h"
#include "lwip/stats.h" #include "lwip/stats.h"
#include "lwip/prot/igmp.h"
#include "string.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 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 err_t igmp_remove_group(struct netif* netif, struct igmp_group *group);
static void igmp_timeout( 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_start_timer(struct igmp_group *group, u8_t max_time);
static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp); 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 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 allsystems;
static ip4_addr_t allrouters; static ip4_addr_t allrouters;
/** /**
* Initialize the IGMP module * Initialize the IGMP module
*/ */
@@ -187,7 +142,7 @@ igmp_start(struct netif *netif)
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD ")); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
ip4_addr_debug_print_val(IGMP_DEBUG, allsystems); ip4_addr_debug_print_val(IGMP_DEBUG, allsystems);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif)); 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; return ERR_OK;
@@ -204,36 +159,24 @@ igmp_start(struct netif *netif)
err_t err_t
igmp_stop(struct netif *netif) igmp_stop(struct netif *netif)
{ {
struct igmp_group *group = igmp_group_list; struct igmp_group *group = netif_igmp_data(netif);
struct igmp_group *prev = NULL;
struct igmp_group *next; 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) { while (group != NULL) {
next = group->next; struct igmp_group *next = group->next; /* avoid use-after-free below */
/* 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 */ /* disable the group at the MAC level */
if (netif->igmp_mac_filter != NULL) { if (netif->igmp_mac_filter != NULL) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL ")); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
ip4_addr_debug_print(IGMP_DEBUG, &group->group_address); ip4_addr_debug_print(IGMP_DEBUG, &group->group_address);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif)); LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif));
netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER); netif->igmp_mac_filter(netif, &(group->group_address), NETIF_DEL_MAC_FILTER);
} }
/* free group */ /* free group */
memp_free(MEMP_IGMP_GROUP, group); memp_free(MEMP_IGMP_GROUP, group);
} else {
/* change the "previous" */
prev = group;
}
/* move to "next" */ /* move to "next" */
group = next; group = next;
} }
@@ -248,14 +191,17 @@ igmp_stop(struct netif *netif)
void void
igmp_report_groups(struct netif *netif) 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)); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", (void*)netif));
while (group != NULL) { /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */
if ((group->netif == netif) && (!(ip4_addr_cmp(&(group->group_address), &allsystems)))) { if(group != NULL) {
igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR); group = group->next;
} }
while (group != NULL) {
igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
group = group->next; group = group->next;
} }
} }
@@ -271,10 +217,10 @@ igmp_report_groups(struct netif *netif)
struct igmp_group * struct igmp_group *
igmp_lookfor_group(struct netif *ifp, const ip4_addr_t *addr) 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) { while (group != NULL) {
if ((group->netif == ifp) && (ip4_addr_cmp(&(group->group_address), addr))) { if (ip4_addr_cmp(&(group->group_address), addr)) {
return group; return group;
} }
group = group->next; group = group->next;
@@ -294,10 +240,11 @@ igmp_lookfor_group(struct netif *ifp, const ip4_addr_t *addr)
* @return a struct igmp_group*, * @return a struct igmp_group*,
* NULL on memory error. * NULL on memory error.
*/ */
struct igmp_group * static struct igmp_group *
igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr) igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr)
{ {
struct igmp_group *group; struct igmp_group *group;
struct igmp_group *list_head = netif_igmp_data(ifp);
/* Search if the group already exists */ /* Search if the group already exists */
group = igmp_lookfor_group(ifp, addr); group = igmp_lookfor_group(ifp, addr);
@@ -309,15 +256,26 @@ igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr)
/* Group doesn't exist yet, create a new one */ /* Group doesn't exist yet, create a new one */
group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP); group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
if (group != NULL) { if (group != NULL) {
group->netif = ifp;
ip4_addr_set(&(group->group_address), addr); ip4_addr_set(&(group->group_address), addr);
group->timer = 0; /* Not running */ group->timer = 0; /* Not running */
group->group_state = IGMP_GROUP_NON_MEMBER; group->group_state = IGMP_GROUP_NON_MEMBER;
group->last_reporter_flag = 0; group->last_reporter_flag = 0;
group->use = 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 "))); 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 * @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 * @return ERR_OK if group was removed from the list, an err_t otherwise
*/ */
static err_t 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; err_t err = ERR_OK;
struct igmp_group *tmp_group;
/* Is it the first group? */ /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */
if (igmp_group_list == group) { for (tmp_group = netif_igmp_data(netif); tmp_group != NULL; tmp_group = tmp_group->next) {
igmp_group_list = group->next; if (tmp_group->next == group) {
} else { tmp_group->next = group->next;
/* 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; break;
} }
} }
/* Group not found in the global igmp_group_list */ /* Group not found in the global igmp_group_list */
if (tmpGroup == NULL) { if (tmp_group == NULL) {
err = ERR_ARG; err = ERR_ARG;
} }
}
/* free group */
memp_free(MEMP_IGMP_GROUP, group);
return err; 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); IGMP_STATS_INC(igmp.rx_general);
} }
groupref = igmp_group_list; groupref = netif_igmp_data(inp);
while (groupref) {
/* Do not send messages on the all systems group address! */ /* Do not send messages on the all systems group address! */
if ((groupref->netif == inp) && (!(ip4_addr_cmp(&(groupref->group_address), &allsystems)))) { /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */
igmp_delaying_member(groupref, igmp->igmp_maxresp); if(groupref != NULL) {
groupref = groupref->next;
} }
while (groupref) {
igmp_delaying_member(groupref, igmp->igmp_maxresp);
groupref = groupref->next; groupref = groupref->next;
} }
} else { } else {
@@ -473,7 +428,7 @@ igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest)
break; break;
default: default:
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n", 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); IGMP_STATS_INC(igmp.proterr);
break; 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 ")); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: igmp_mac_filter(ADD "));
ip4_addr_debug_print(IGMP_DEBUG, groupaddr); ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif)); 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_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); 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 there is no other use of the group */
if (group->use <= 1) { 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 we are the last reporter for this group */
if (group->last_reporter_flag) { if (group->last_reporter_flag) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: sending leaving group\n")); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: sending leaving group\n"));
IGMP_STATS_INC(igmp.tx_leave); 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 */ /* 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 ")); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: igmp_mac_filter(DEL "));
ip4_addr_debug_print(IGMP_DEBUG, groupaddr); ip4_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif)); 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: ")); /* Free group struct */
ip4_addr_debug_print(IGMP_DEBUG, groupaddr); memp_free(MEMP_IGMP_GROUP, group);
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
/* Free the group */
igmp_remove_group(group);
} else { } else {
/* Decrement group use */ /* Decrement group use */
group->use--; group->use--;
@@ -684,17 +638,22 @@ igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr)
void void
igmp_tmr(void) igmp_tmr(void)
{ {
struct igmp_group *group = igmp_group_list; struct netif *netif = netif_list;
while (netif != NULL) {
struct igmp_group *group = netif_igmp_data(netif);
while (group != NULL) { while (group != NULL) {
if (group->timer > 0) { if (group->timer > 0) {
group->timer--; group->timer--;
if (group->timer == 0) { if (group->timer == 0) {
igmp_timeout(group); 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 * @param group an igmp_group for which a timeout is reached
*/ */
static void 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 /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group
(unless it is the allsystems group) */ (unless it is the allsystems group) */
@@ -712,10 +671,12 @@ igmp_timeout(struct igmp_group *group)
(!(ip4_addr_cmp(&(group->group_address), &allsystems)))) { (!(ip4_addr_cmp(&(group->group_address), &allsystems)))) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address ")); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
ip4_addr_debug_print(IGMP_DEBUG, &(group->group_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_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. * 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 * @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 protocol header; if dest == LWIP_IP_HDRINCL, p already includes an
header and p->payload points to that IP header) 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 * @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) * 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 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 * @param netif the netif on which to send this packet
* @return ERR_OK if the packet was sent OK * @return ERR_OK if the packet was sent OK
* ERR_BUF if p doesn't have enough space for IP/LINK headers * 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 * @param type the type of igmp packet to send
*/ */
static void 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 pbuf* p = NULL;
struct igmp_msg* igmp = 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; ip4_addr_t* dest = NULL;
/* IP header + "router alert" option + IGMP header */ /* 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; igmp = (struct igmp_msg *)p->payload;
LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg", LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
(p->len >= sizeof(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) { if (type == IGMP_V2_MEMB_REPORT) {
dest = &(group->group_address); dest = &(group->group_address);
@@ -828,7 +787,7 @@ igmp_send(struct igmp_group *group, u8_t type)
igmp->igmp_checksum = 0; igmp->igmp_checksum = 0;
igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN); igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
igmp_ip_output_if(p, &src, dest, group->netif); igmp_ip_output_if(p, &src, dest, netif);
} }
pbuf_free(p); pbuf_free(p);

87
ext/lwip/src/core/ipv4/ip4.c Normal file → Executable file
View File

@@ -53,12 +53,16 @@
#include "lwip/raw.h" #include "lwip/raw.h"
#include "lwip/udp.h" #include "lwip/udp.h"
#include "lwip/priv/tcp_priv.h" #include "lwip/priv/tcp_priv.h"
#include "lwip/dhcp.h"
#include "lwip/autoip.h" #include "lwip/autoip.h"
#include "lwip/stats.h" #include "lwip/stats.h"
#include "lwip/prot/dhcp.h"
#include <string.h> #include <string.h>
#ifdef LWIP_HOOK_FILENAME
#include LWIP_HOOK_FILENAME
#endif
/** Set this to 0 in the rare case of wanting to call an extra function to /** Set this to 0 in the rare case of wanting to call an extra function to
* generate the IP checksum (in contrast to calculating it on-the-fly). */ * generate the IP checksum (in contrast to calculating it on-the-fly). */
#ifndef LWIP_INLINE_IP_CHKSUM #ifndef LWIP_INLINE_IP_CHKSUM
@@ -106,7 +110,9 @@ static u16_t ip_id;
/** The default netif used for multicast */ /** The default netif used for multicast */
static struct netif* ip4_default_multicast_netif; static struct netif* ip4_default_multicast_netif;
/** Set a default netif for IPv4 multicast. */ /**
* @ingroup ip4
* Set a default netif for IPv4 multicast. */
void void
ip4_set_default_multicast_netif(struct netif* default_multicast_netif) ip4_set_default_multicast_netif(struct netif* default_multicast_netif)
{ {
@@ -175,7 +181,7 @@ ip4_route(const ip4_addr_t *dest)
/* loopif is disabled, looopback traffic is passed through any netif */ /* loopif is disabled, looopback traffic is passed through any netif */
if (ip4_addr_isloopback(dest)) { if (ip4_addr_isloopback(dest)) {
/* don't check for link on loopback traffic */ /* 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; return netif_default;
} }
/* default netif is not up, just use any netif for loopback traffic */ /* default netif is not up, just use any netif for loopback traffic */
@@ -220,13 +226,12 @@ ip4_route(const ip4_addr_t *dest)
* that may not be forwarded, or whether datagrams to that destination * that may not be forwarded, or whether datagrams to that destination
* may be forwarded. * may be forwarded.
* @param p the packet to forward * @param p the packet to forward
* @param dest the destination IP address
* @return 1: can forward 0: discard * @return 1: can forward 0: discard
*/ */
static int static int
ip4_canforward(struct pbuf *p) 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) { if (p->flags & PBUF_FLAG_LLBCAST) {
/* don't route link-layer broadcasts */ /* don't route link-layer broadcasts */
@@ -265,6 +270,7 @@ ip4_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
struct netif *netif; struct netif *netif;
PERF_START; PERF_START;
LWIP_UNUSED_ARG(inp);
if (!ip4_canforward(p)) { if (!ip4_canforward(p)) {
goto return_noroute; goto return_noroute;
@@ -402,7 +408,7 @@ ip4_input(struct pbuf *p, struct netif *inp)
/* calculate IP header length in bytes */ /* calculate IP header length in bytes */
iphdr_hlen *= 4; iphdr_hlen *= 4;
/* obtain ip length in bytes */ /* 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. */ /* Trim pbuf. This is especially required for packets < 60 bytes. */
if (iphdr_len < p->tot_len) { if (iphdr_len < p->tot_len) {
@@ -507,8 +513,7 @@ ip4_input(struct pbuf *p, struct netif *inp)
#if LWIP_AUTOIP #if LWIP_AUTOIP
/* connections to link-local addresses must persist after changing /* connections to link-local addresses must persist after changing
the netif's address (RFC3927 ch. 1.9) */ the netif's address (RFC3927 ch. 1.9) */
if ((netif->autoip != NULL) && if (autoip_accept_packet(netif, ip4_current_dest_addr())) {
ip4_addr_cmp(ip4_current_dest_addr(), &(netif->autoip->llipaddr))) {
LWIP_DEBUGF(IP_DEBUG, ("ip4_input: LLA packet accepted on interface %c%c\n", LWIP_DEBUGF(IP_DEBUG, ("ip4_input: LLA packet accepted on interface %c%c\n",
netif->name[0], netif->name[1])); netif->name[0], netif->name[1]));
/* break out of for loop */ /* break out of for loop */
@@ -517,6 +522,15 @@ ip4_input(struct pbuf *p, struct netif *inp)
#endif /* LWIP_AUTOIP */ #endif /* LWIP_AUTOIP */
} }
if (first) { 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; first = 0;
netif = netif_list; netif = netif_list;
} else { } else {
@@ -543,7 +557,7 @@ ip4_input(struct pbuf *p, struct netif *inp)
if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen); 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", 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)) { if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: DHCP packet accepted.\n")); LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: DHCP packet accepted.\n"));
netif = inp; netif = inp;
@@ -588,6 +602,7 @@ ip4_input(struct pbuf *p, struct netif *inp)
} else } else
#endif /* IP_FORWARD */ #endif /* IP_FORWARD */
{ {
IP_STATS_INC(ip.drop);
MIB2_STATS_INC(mib2.ipinaddrerrors); MIB2_STATS_INC(mib2.ipinaddrerrors);
MIB2_STATS_INC(mib2.ipindiscards); MIB2_STATS_INC(mib2.ipindiscards);
} }
@@ -598,7 +613,7 @@ ip4_input(struct pbuf *p, struct netif *inp)
if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) { if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) {
#if IP_REASSEMBLY /* packet fragment reassembly code present? */ #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", 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*/ /* reassemble the packet*/
p = ip4_reass(p); p = ip4_reass(p);
/* packet not fully reassembled yet? */ /* packet not fully reassembled yet? */
@@ -609,7 +624,7 @@ ip4_input(struct pbuf *p, struct netif *inp)
#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ #else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
pbuf_free(p); 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", 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.opterr);
IP_STATS_INC(ip.drop); IP_STATS_INC(ip.drop);
/* unsupported protocol feature */ /* unsupported protocol feature */
@@ -716,13 +731,13 @@ ip4_input(struct pbuf *p, struct netif *inp)
* the IP header and calculates the IP header checksum. If the source * the IP header and calculates the IP header checksum. If the source
* IP address is NULL, the IP address of the outgoing network * IP address is NULL, the IP address of the outgoing network
* interface is filled in as source address. * 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. * 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 * @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 protocol header; if dest == LWIP_IP_HDRINCL, p already includes an
header and p->payload points to that IP header) 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 * @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) * 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 dest the destination IP address to send the packet to
* @param ttl the TTL value to be set in the IP header * @param ttl the TTL value to be set in the IP header
@@ -758,7 +773,7 @@ ip4_output_if_opt(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
{ {
#endif /* IP_OPTIONS_SEND */ #endif /* IP_OPTIONS_SEND */
const ip4_addr_t *src_used = src; const ip4_addr_t *src_used = src;
if (dest != IP_HDRINCL) { if (dest != LWIP_IP_HDRINCL) {
if (ip4_addr_isany(src)) { if (ip4_addr_isany(src)) {
src_used = netif_ip4_addr(netif); src_used = netif_ip4_addr(netif);
} }
@@ -806,7 +821,7 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d
MIB2_STATS_INC(mib2.ipoutrequests); MIB2_STATS_INC(mib2.ipoutrequests);
/* Should the IP header be generated or is it already included in p? */ /* 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; u16_t ip_hlen = IP_HLEN;
#if IP_OPTIONS_SEND #if IP_OPTIONS_SEND
u16_t optlen_aligned = 0; u16_t optlen_aligned = 0;
@@ -852,7 +867,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_TTL_SET(iphdr, ttl);
IPH_PROTO_SET(iphdr, proto); IPH_PROTO_SET(iphdr, proto);
#if CHECKSUM_GEN_IP_INLINE #if CHECKSUM_GEN_IP_INLINE
chk_sum += LWIP_MAKE_U16(proto, ttl); chk_sum += PP_NTOHS(proto | (ttl << 8));
#endif /* CHECKSUM_GEN_IP_INLINE */ #endif /* CHECKSUM_GEN_IP_INLINE */
/* dest cannot be NULL here */ /* dest cannot be NULL here */
@@ -865,21 +880,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_VHL_SET(iphdr, 4, ip_hlen / 4);
IPH_TOS_SET(iphdr, tos); IPH_TOS_SET(iphdr, tos);
#if CHECKSUM_GEN_IP_INLINE #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 */ #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 #if CHECKSUM_GEN_IP_INLINE
chk_sum += iphdr->_len; chk_sum += iphdr->_len;
#endif /* CHECKSUM_GEN_IP_INLINE */ #endif /* CHECKSUM_GEN_IP_INLINE */
IPH_OFFSET_SET(iphdr, 0); 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 #if CHECKSUM_GEN_IP_INLINE
chk_sum += iphdr->_id; chk_sum += iphdr->_id;
#endif /* CHECKSUM_GEN_IP_INLINE */ #endif /* CHECKSUM_GEN_IP_INLINE */
++ip_id; ++ip_id;
if (src == NULL) { if (src == NULL) {
ip4_addr_copy(iphdr->src, *IP4_ADDR_ANY); ip4_addr_copy(iphdr->src, *IP4_ADDR_ANY4);
} else { } else {
/* src cannot be NULL here */ /* src cannot be NULL here */
ip4_addr_copy(iphdr->src, *src); ip4_addr_copy(iphdr->src, *src);
@@ -951,9 +966,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. * 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 * @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 protocol header; if dest == LWIP_IP_HDRINCL, p already includes an
header and p->payload points to that IP header) 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 * @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) * 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 dest the destination IP address to send the packet to
* @param ttl the TTL value to be set in the IP header * @param ttl the TTL value to be set in the IP header
@@ -986,9 +1001,9 @@ ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
* before calling ip_output_if. * before calling ip_output_if.
* *
* @param p the packet to send (p->payload points to the data, e.g. next * @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 protocol header; if dest == LWIP_IP_HDRINCL, p already includes an
header and p->payload points to that IP header) 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 * @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) * 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 dest the destination IP address to send the packet to
* @param ttl the TTL value to be set in the IP header * @param ttl the TTL value to be set in the IP header
@@ -1031,7 +1046,6 @@ ip4_output_hinted(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
void void
ip4_debug_print(struct pbuf *p) ip4_debug_print(struct pbuf *p)
{ {
#if defined(LWIP_DEBUG)
struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
@@ -1040,19 +1054,19 @@ ip4_debug_print(struct pbuf *p)
(u16_t)IPH_V(iphdr), (u16_t)IPH_V(iphdr),
(u16_t)IPH_HL(iphdr), (u16_t)IPH_HL(iphdr),
(u16_t)IPH_TOS(iphdr), (u16_t)IPH_TOS(iphdr),
ntohs(IPH_LEN(iphdr)))); lwip_ntohs(IPH_LEN(iphdr))));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); 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", LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n",
ntohs(IPH_ID(iphdr)), lwip_ntohs(IPH_ID(iphdr)),
(u16_t)(ntohs(IPH_OFFSET(iphdr)) >> 15 & 1), (u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) >> 15 & 1),
(u16_t)(ntohs(IPH_OFFSET(iphdr)) >> 14 & 1), (u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) >> 14 & 1),
(u16_t)(ntohs(IPH_OFFSET(iphdr)) >> 13 & 1), (u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) >> 13 & 1),
(u16_t)(ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK))); (u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\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_TTL(iphdr),
(u16_t)IPH_PROTO(iphdr), (u16_t)IPH_PROTO(iphdr),
ntohs(IPH_CHKSUM(iphdr)))); lwip_ntohs(IPH_CHKSUM(iphdr))));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n", LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n",
ip4_addr1_16(&iphdr->src), ip4_addr1_16(&iphdr->src),
@@ -1066,7 +1080,6 @@ ip4_debug_print(struct pbuf *p)
ip4_addr3_16(&iphdr->dest), ip4_addr3_16(&iphdr->dest),
ip4_addr4_16(&iphdr->dest))); ip4_addr4_16(&iphdr->dest)));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
#endif
} }
#endif /* IP_DEBUG */ #endif /* IP_DEBUG */

10
ext/lwip/src/core/ipv4/ip4_addr.c Normal file → Executable file
View File

@@ -43,7 +43,7 @@
#include "lwip/ip_addr.h" #include "lwip/ip_addr.h"
#include "lwip/netif.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_any = IPADDR4_INIT(IPADDR_ANY);
const ip_addr_t ip_addr_broadcast = IPADDR4_INIT(IPADDR_BROADCAST); 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 (;;) { for (;;) {
if (isdigit(c)) { if (isdigit(c)) {
val = (val * base) + (int)(c - '0'); val = (val * base) + (u32_t)(c - '0');
c = *++cp; c = *++cp;
} else if (base == 16 && isxdigit(c)) { } 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; c = *++cp;
} else { } else {
break; break;
@@ -260,7 +260,7 @@ ip4addr_aton(const char *cp, ip4_addr_t *addr)
break; break;
} }
if (addr) { if (addr) {
ip4_addr_set_u32(addr, htonl(val)); ip4_addr_set_u32(addr, lwip_htonl(val));
} }
return 1; return 1;
} }
@@ -310,7 +310,7 @@ ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen)
do { do {
rem = *ap % (u8_t)10; rem = *ap % (u8_t)10;
*ap /= (u8_t)10; *ap /= (u8_t)10;
inv[i++] = '0' + rem; inv[i++] = (char)('0' + rem);
} while (*ap); } while (*ap);
while (i--) { while (i--) {
if (len++ >= buflen) { if (len++ >= buflen) {

154
ext/lwip/src/core/ipv4/ip4_frag.c Normal file → Executable file
View File

@@ -160,7 +160,7 @@ static int
ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
{ {
u16_t pbufs_freed = 0; u16_t pbufs_freed = 0;
u8_t clen; u16_t clen;
struct pbuf *p; struct pbuf *p;
struct ip_reass_helper *iprh; 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. * will grow over time as new pbufs are rx.
* Also checks that the datagram passes basic continuity checks (if the last * Also checks that the datagram passes basic continuity checks (if the last
* fragment was received at least once). * 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 * @param new_p points to the pbuf for the current fragment
* @return 0 if invalid, >0 otherwise * @return 0 if invalid, >0 otherwise
*/ */
@@ -346,8 +346,8 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct
/* Extract length and fragment offset from current fragment */ /* Extract length and fragment offset from current fragment */
fraghdr = (struct ip_hdr*)new_p->payload; fraghdr = (struct ip_hdr*)new_p->payload;
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; len = lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; offset = (lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
/* overwrite the fragment's ip header from the pbuf with our helper struct, /* overwrite the fragment's ip header from the pbuf with our helper struct,
* and setup the embedded helper structure. */ * and setup the embedded helper structure. */
@@ -487,8 +487,7 @@ ip4_reass(struct pbuf *p)
struct ip_hdr *fraghdr; struct ip_hdr *fraghdr;
struct ip_reassdata *ipr; struct ip_reassdata *ipr;
struct ip_reass_helper *iprh; struct ip_reass_helper *iprh;
u16_t offset, len; u16_t offset, len, clen;
u8_t clen;
IPFRAG_STATS_INC(ip_frag.recv); IPFRAG_STATS_INC(ip_frag.recv);
MIB2_STATS_INC(mib2.ipreasmreqds); MIB2_STATS_INC(mib2.ipreasmreqds);
@@ -501,8 +500,8 @@ ip4_reass(struct pbuf *p)
goto nullreturn; goto nullreturn;
} }
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; offset = (lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; len = lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
/* Check if we are allowed to enqueue more datagrams. */ /* Check if we are allowed to enqueue more datagrams. */
clen = pbuf_clen(p); clen = pbuf_clen(p);
@@ -530,7 +529,7 @@ ip4_reass(struct pbuf *p)
fragment into the buffer. */ fragment into the buffer. */
if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) { if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip4_reass: matching previous fragment ID=%"X16_F"\n", 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); IPFRAG_STATS_INC(ip_frag.cachehit);
break; break;
} }
@@ -544,8 +543,8 @@ ip4_reass(struct pbuf *p)
goto nullreturn; goto nullreturn;
} }
} else { } else {
if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) && if (((lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
((ntohs(IPH_OFFSET(&ipr->iphdr)) & 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 /* 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 * -> copy fraghdr into ipr->iphdr since we want to have the header
* of the first fragment (for ICMP time exceeded and later, for copying * 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 */ /* copy the original ip header back to the first pbuf */
fraghdr = (struct ip_hdr*)(ipr->p->payload); fraghdr = (struct ip_hdr*)(ipr->p->payload);
SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN); 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_OFFSET_SET(fraghdr, 0);
IPH_CHKSUM_SET(fraghdr, 0); IPH_CHKSUM_SET(fraghdr, 0);
/* @todo: do we need to set/calculate the correct checksum? */ /* @todo: do we need to set/calculate the correct checksum? */
@@ -639,10 +638,6 @@ nullreturn:
#endif /* IP_REASSEMBLY */ #endif /* IP_REASSEMBLY */
#if IP_FRAG #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 #if !LWIP_NETIF_TX_SINGLE_PBUF
/** Allocate a new struct pbuf_custom_ref */ /** Allocate a new struct pbuf_custom_ref */
static 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); ip_frag_free_pbuf_custom_ref(pcr);
} }
#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ #endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
#endif /* IP_FRAG_USES_STATIC_BUF */
/** /**
* Fragment an IP datagram if too large for the netif. * Fragment an IP datagram if too large for the netif.
* *
* Chop the datagram in MTU sized chunks and send them in order * Chop the datagram in MTU sized chunks and send them in order
* by using a fixed size static memory buffer (PBUF_REF) or * by pointing PBUF_REFs into p.
* point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).
* *
* @param p ip packet to send * @param p ip packet to send
* @param netif the netif on which 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) ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
{ {
struct pbuf *rambuf; struct pbuf *rambuf;
#if IP_FRAG_USES_STATIC_BUF
struct pbuf *header;
#else
#if !LWIP_NETIF_TX_SINGLE_PBUF #if !LWIP_NETIF_TX_SINGLE_PBUF
struct pbuf *newpbuf; 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 newpbuflen = 0;
u16_t left_to_copy; u16_t left_to_copy;
#endif #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; original_iphdr = (struct ip_hdr *)p->payload;
iphdr = original_iphdr; 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 */ /* Save original offset */
tmp = ntohs(IPH_OFFSET(iphdr)); tmp = lwip_ntohs(IPH_OFFSET(iphdr));
ofo = tmp & IP_OFFMASK; 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; left = p->tot_len - IP_HLEN;
nfb = (mtu - IP_HLEN) / 8;
while (left) { 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 */ /* 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 #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) { if (rambuf == NULL) {
goto memerr; goto memerr;
} }
LWIP_ASSERT("this needs a pbuf in one piece!", LWIP_ASSERT("this needs a pbuf in one piece!",
(rambuf->len == rambuf->tot_len) && (rambuf->next == NULL)); (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 */ /* make room for the IP header */
if (pbuf_header(rambuf, IP_HLEN)) { if (pbuf_header(rambuf, IP_HLEN)) {
pbuf_free(rambuf); 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); SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
iphdr = (struct ip_hdr *)rambuf->payload; iphdr = (struct ip_hdr *)rambuf->payload;
/* Can just adjust p directly for needed offset. */ left_to_copy = fragsize;
p->payload = (u8_t *)p->payload + poff;
p->len -= poff;
left_to_copy = cop;
while (left_to_copy) { while (left_to_copy) {
struct pbuf_custom_ref *pcr; 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? */ /* Is this pbuf already empty? */
if (!newpbuflen) { if (!newpbuflen) {
poff = 0;
p = p->next; p = p->next;
continue; continue;
} }
@@ -809,7 +762,8 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
goto memerr; goto memerr;
} }
/* Mirror this pbuf, although we might not need all of it. */ /* 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) { if (newpbuf == NULL) {
ip_frag_free_pbuf_custom_ref(pcr); ip_frag_free_pbuf_custom_ref(pcr);
pbuf_free(rambuf); pbuf_free(rambuf);
@@ -825,16 +779,23 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
pbuf_cat(rambuf, newpbuf); pbuf_cat(rambuf, newpbuf);
left_to_copy -= newpbuflen; left_to_copy -= newpbuflen;
if (left_to_copy) { if (left_to_copy) {
poff = 0;
p = p->next; p = p->next;
} }
} }
poff = newpbuflen; poff += newpbuflen;
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
#endif /* IP_FRAG_USES_STATIC_BUF */
/* Correct header */ /* Correct header */
IPH_OFFSET_SET(iphdr, htons(tmp)); last = (left <= netif->mtu - IP_HLEN);
IPH_LEN_SET(iphdr, htons(cop + 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); IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP #if CHECKSUM_GEN_IP
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_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 */ #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 /* No need for separate header pbuf - we allowed room for it in rambuf
* when allocated. * when allocated.
*/ */
@@ -879,13 +817,9 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
*/ */
pbuf_free(rambuf); pbuf_free(rambuf);
#endif /* IP_FRAG_USES_STATIC_BUF */ left -= fragsize;
left -= cop;
ofo += nfb; ofo += nfb;
} }
#if IP_FRAG_USES_STATIC_BUF
pbuf_free(rambuf);
#endif /* IP_FRAG_USES_STATIC_BUF */
MIB2_STATS_INC(mib2.ipfragoks); MIB2_STATS_INC(mib2.ipfragoks);
return ERR_OK; return ERR_OK;
memerr: memerr:

View File

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

0
ext/lwip/src/core/ipv6/dhcp6.c Normal file → Executable file
View File

85
ext/lwip/src/core/ipv6/ethip6.c Normal file → Executable file
View File

@@ -41,7 +41,7 @@
#include "lwip/opt.h" #include "lwip/opt.h"
#if LWIP_IPV6 && LWIP_ETHERNET
#include "lwip/ethip6.h" #include "lwip/ethip6.h"
#include "lwip/nd6.h" #include "lwip/nd6.h"
@@ -51,42 +51,20 @@
#include "lwip/inet_chksum.h" #include "lwip/inet_chksum.h"
#include "lwip/netif.h" #include "lwip/netif.h"
#include "lwip/icmp6.h" #include "lwip/icmp6.h"
#include "lwip/prot/ethernet.h"
#include "netif/ethernet.h" #include "netif/ethernet.h"
#include <string.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. * Resolve and fill-in Ethernet address header for outgoing IPv6 packet.
* *
* For IPv6 multicast, corresponding Ethernet addresses * For IPv6 multicast, corresponding Ethernet addresses
* are selected and the packet is transmitted on the link. * 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 * @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. * @param ip6addr The IP address of the packet destination.
* *
* @return * @return
* - ERR_RTE No route to destination (no gateway to external networks), * - ERR_OK or the return value of @ref nd6_get_next_hop_addr_or_queue.
* or the return type of either etharp_query() or etharp_send_ip().
*/ */
err_t err_t
ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr)
{ {
struct eth_addr dest; struct eth_addr dest;
s8_t i; const u8_t *hwaddr;
err_t result;
/* 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;
}
/* multicast destination IP address? */ /* multicast destination IP address? */
if (ip6_addr_ismulticast(ip6addr)) { if (ip6_addr_ismulticast(ip6addr)) {
@@ -123,35 +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]; dest.addr[5] = ((const u8_t *)(&(ip6addr->addr[3])))[3];
/* Send out. */ /* 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 */ /* We have a unicast destination IP address */
/* @todo anycast? */ /* @todo anycast? */
/* Get next hop record. */
i = nd6_get_next_hop_entry(ip6addr, netif); /* Ask ND6 what to do with the packet. */
if (i < 0) { result = nd6_get_next_hop_addr_or_queue(netif, q, ip6addr, &hwaddr);
/* failed to get a next hop neighbor record. */ if (result != ERR_OK) {
return ERR_MEM; return result;
} }
/* Now that we have a destination record, send or queue the packet. */ /* If no hardware address is returned, nd6 has queued the packet for later. */
if (neighbor_cache[i].state == ND6_STALE) { if (hwaddr == NULL) {
/* Switch to delay state. */ return ERR_OK;
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);
}
/* 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 */

1
ext/lwip/src/core/ipv6/icmp6.c Normal file → Executable file
View File

@@ -44,6 +44,7 @@
#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ #if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/icmp6.h" #include "lwip/icmp6.h"
#include "lwip/prot/icmp6.h"
#include "lwip/ip6.h" #include "lwip/ip6.h"
#include "lwip/ip6_addr.h" #include "lwip/ip6_addr.h"
#include "lwip/inet_chksum.h" #include "lwip/inet_chksum.h"

0
ext/lwip/src/core/ipv6/inet6.c Normal file → Executable file
View File

78
ext/lwip/src/core/ipv6/ip6.c Normal file → Executable file
View File

@@ -46,6 +46,7 @@
#include "lwip/def.h" #include "lwip/def.h"
#include "lwip/mem.h" #include "lwip/mem.h"
#include "lwip/netif.h" #include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/ip6.h" #include "lwip/ip6.h"
#include "lwip/ip6_addr.h" #include "lwip/ip6_addr.h"
#include "lwip/ip6_frag.h" #include "lwip/ip6_frag.h"
@@ -59,6 +60,10 @@
#include "lwip/debug.h" #include "lwip/debug.h"
#include "lwip/stats.h" #include "lwip/stats.h"
#ifdef LWIP_HOOK_FILENAME
#include LWIP_HOOK_FILENAME
#endif
/** /**
* Finds the appropriate network interface for a given IPv6 address. It tries to select * Finds the appropriate network interface for a given IPv6 address. It tries to select
* a netif following a sequence of heuristics: * a netif following a sequence of heuristics:
@@ -93,7 +98,8 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
if (ip6_addr_islinklocal(dest)) { if (ip6_addr_islinklocal(dest)) {
if (ip6_addr_isany(src)) { if (ip6_addr_isany(src)) {
/* Use default netif, if Up. */ /* 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 NULL;
} }
return netif_default; return netif_default;
@@ -113,7 +119,8 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
} }
/* netif not found, use default netif, if up */ /* 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 NULL;
} }
return netif_default; return netif_default;
@@ -141,15 +148,9 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
} }
/* Get the netif for a suitable router. */ /* Get the netif for a suitable router. */
i = nd6_select_router(dest, NULL); netif = nd6_find_route(dest);
if (i >= 0) { if ((netif != NULL) && netif_is_up(netif) && netif_is_link_up(netif)) {
if (default_router_list[i].neighbor_entry != NULL) { return netif;
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;
}
}
}
} }
/* try with the netif that matches the source address. */ /* try with the netif that matches the source address. */
@@ -171,7 +172,7 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
/* loopif is disabled, loopback traffic is passed through any netif */ /* loopif is disabled, loopback traffic is passed through any netif */
if (ip6_addr_isloopback(dest)) { if (ip6_addr_isloopback(dest)) {
/* don't check for link on loopback traffic */ /* 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; return netif_default;
} }
/* default netif is not up, just use any netif for loopback traffic */ /* default netif is not up, just use any netif for loopback traffic */
@@ -192,6 +193,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 * Select the best IPv6 source address for a given destination
* IPv6 address. Loosely follows RFC 3484. "Strong host" behavior * IPv6 address. Loosely follows RFC 3484. "Strong host" behavior
* is assumed. * is assumed.
@@ -288,8 +290,9 @@ ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp)
{ {
struct netif *netif; struct netif *netif;
/* do not forward link-local addresses */ /* do not forward link-local or loopback addresses */
if (ip6_addr_islinklocal(ip6_current_dest_addr())) { 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")); LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n"));
IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.rterr);
IP6_STATS_INC(ip6.drop); IP6_STATS_INC(ip6.drop);
@@ -444,9 +447,11 @@ ip6_input(struct pbuf *p, struct netif *inp)
ip_addr_copy_from_ip6(ip_data.current_iphdr_dest, ip6hdr->dest); ip_addr_copy_from_ip6(ip_data.current_iphdr_dest, ip6hdr->dest);
ip_addr_copy_from_ip6(ip_data.current_iphdr_src, ip6hdr->src); ip_addr_copy_from_ip6(ip_data.current_iphdr_src, ip6hdr->src);
/* Don't accept virtual IPv6 mapped IPv4 addresses */ /* Don't accept virtual IPv4 mapped IPv6 addresses.
if (ip6_addr_isipv6mappedipv4(ip_2_ip6(&ip_data.current_iphdr_dest)) || * Don't accept multicast source addresses. */
ip6_addr_isipv6mappedipv4(ip_2_ip6(&ip_data.current_iphdr_src)) ) { if (ip6_addr_isipv4mappedipv6(ip_2_ip6(&ip_data.current_iphdr_dest)) ||
ip6_addr_isipv4mappedipv6(ip_2_ip6(&ip_data.current_iphdr_src)) ||
ip6_addr_ismulticast(ip_2_ip6(&ip_data.current_iphdr_src))) {
IP6_STATS_INC(ip6.err); IP6_STATS_INC(ip6.err);
IP6_STATS_INC(ip6.drop); IP6_STATS_INC(ip6.drop);
return ERR_OK; return ERR_OK;
@@ -507,12 +512,21 @@ ip6_input(struct pbuf *p, struct netif *inp)
} }
} }
} }
if (ip6_addr_islinklocal(ip6_current_dest_addr())) { if (first) {
/* Do not match link-local addresses to other netifs. */ 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; netif = NULL;
break; break;
} }
if (first) {
first = 0; first = 0;
netif = netif_list; netif = netif_list;
} else { } else {
@@ -707,7 +721,7 @@ netif_found:
options_done: options_done:
/* p points to IPv6 header again. */ /* 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 */ /* send to upper layers */
LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n")); LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n"));
@@ -781,11 +795,11 @@ ip6_input_cleanup:
* used as source (usually during network startup). If the source IPv6 address it * 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 * 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 * 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 * LWIP_IP_HDRINCL, p is assumed to already include an IPv6 header and
* to it instead of the data. * p->payload points to it instead of the data.
* *
* @param p the packet to send (p->payload points to the data, e.g. next * @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) 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 * @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. * IP address of the netif is selected and used as source address.
@@ -805,10 +819,10 @@ ip6_output_if(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
u8_t nexth, struct netif *netif) u8_t nexth, struct netif *netif)
{ {
const ip6_addr_t *src_used = src; const ip6_addr_t *src_used = src;
if (dest != IP_HDRINCL) { if (dest != LWIP_IP_HDRINCL) {
if (src != NULL && ip6_addr_isany(src)) { if (src != NULL && ip6_addr_isany(src)) {
src = ip_2_ip6(ip6_select_source_address(netif, dest)); src_used = ip_2_ip6(ip6_select_source_address(netif, dest));
if ((src == NULL) || ip6_addr_isany(src)) { if ((src_used == NULL) || ip6_addr_isany(src_used)) {
/* No appropriate source address was found for this packet. */ /* No appropriate source address was found for this packet. */
LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: No suitable source address for packet.\n")); LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: No suitable source address for packet.\n"));
IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.rterr);
@@ -834,7 +848,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); LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);
/* Should the IPv6 header be generated or is it already included in 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 */ /* generate IPv6 header */
if (pbuf_header(p, IP6_HLEN)) { 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")); LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: not enough room for IPv6 header in pbuf\n"));
@@ -907,7 +921,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. * 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 * @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) 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 * @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. * IP address of the netif is selected and used as source address.
@@ -930,7 +944,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); LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);
if (dest != IP_HDRINCL) { if (dest != LWIP_IP_HDRINCL) {
netif = ip6_route(src, dest); netif = ip6_route(src, dest);
} else { } else {
/* IP header included in p, read addresses. */ /* IP header included in p, read addresses. */
@@ -963,7 +977,7 @@ ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
* before calling ip6_output_if. * before calling ip6_output_if.
* *
* @param p the packet to send (p->payload points to the data, e.g. next * @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) 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 * @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. * IP address of the netif is selected and used as source address.
@@ -989,7 +1003,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); LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);
if (dest != IP_HDRINCL) { if (dest != LWIP_IP_HDRINCL) {
netif = ip6_route(src, dest); netif = ip6_route(src, dest);
} else { } else {
/* IP header included in p, read addresses. */ /* IP header included in p, read addresses. */

10
ext/lwip/src/core/ipv6/ip6_addr.c Normal file → Executable file
View File

@@ -132,8 +132,8 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr)
} else if (isxdigit(*s)) { } else if (isxdigit(*s)) {
/* add current digit */ /* add current digit */
current_block_value = (current_block_value << 4) + current_block_value = (current_block_value << 4) +
(isdigit(*s) ? *s - '0' : (isdigit(*s) ? (u32_t)(*s - '0') :
10 + (islower(*s) ? *s - 'a' : *s - 'A')); (u32_t)(10 + (islower(*s) ? *s - 'a' : *s - 'A')));
} else { } else {
/* unexpected digit, space? CRLF? */ /* unexpected digit, space? CRLF? */
break; break;
@@ -152,7 +152,7 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr)
/* convert to network byte order. */ /* convert to network byte order. */
if (addr) { if (addr) {
for (addr_index = 0; addr_index < 4; addr_index++) { 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++) { for (current_block_index = 0; current_block_index < 8; current_block_index++) {
/* get the current 16-bit block */ /* 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) { if ((current_block_index & 0x1) == 0) {
current_block_value = current_block_value >> 16; 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) { if (empty_block_flag == 0) {
/* generate empty block "::", but only if more than one contiguous zero block, /* generate empty block "::", but only if more than one contiguous zero block,
* according to current formatting suggestions RFC 5952. */ * 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) { if ((current_block_index & 0x1) == 0x01) {
next_block_value = next_block_value >> 16; next_block_value = next_block_value >> 16;
} }

61
ext/lwip/src/core/ipv6/ip6_frag.c Normal file → Executable file
View File

@@ -147,7 +147,7 @@ ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr)
{ {
struct ip6_reassdata *prev; struct ip6_reassdata *prev;
u16_t pbufs_freed = 0; u16_t pbufs_freed = 0;
u8_t clen; u16_t clen;
struct pbuf *p; struct pbuf *p;
struct ip6_reass_helper *iprh; struct ip6_reass_helper *iprh;
@@ -262,7 +262,8 @@ ip6_reass(struct pbuf *p)
struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; 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; u16_t offset, len;
u8_t clen, valid = 1; u16_t clen;
u8_t valid = 1;
struct pbuf *q; struct pbuf *q;
IP6_FRAG_STATS_INC(ip6_frag.recv); IP6_FRAG_STATS_INC(ip6_frag.recv);
@@ -278,12 +279,12 @@ ip6_reass(struct pbuf *p)
clen = pbuf_clen(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. /* Calculate fragment length from IPv6 payload length.
* Adjust for headers before Fragment Header. * Adjust for headers before Fragment Header.
* And finally adjust by Fragment Header length. */ * 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 -= (u16_t)(((u8_t*)p->payload - (const u8_t*)ip6_current_header()) - IP6_HLEN);
len -= IP6_FRAG_HLEN; len -= IP6_FRAG_HLEN;
@@ -377,8 +378,9 @@ ip6_reass(struct pbuf *p)
if (IPV6_FRAG_REQROOM > 0) { if (IPV6_FRAG_REQROOM > 0) {
/* Make room for struct ip6_reass_helper (only required if sizeof(void*) > 4). /* Make room for struct ip6_reass_helper (only required if sizeof(void*) > 4).
This cannot fail since we already checked when receiving this fragment. */ This cannot fail since we already checked when receiving this fragment. */
err_t hdrerr = pbuf_header_force(p, IPV6_FRAG_REQROOM); u8_t hdrerr = pbuf_header_force(p, IPV6_FRAG_REQROOM);
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == ERR_OK); LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0);
} }
#else /* IPV6_FRAG_COPYHEADER */ #else /* IPV6_FRAG_COPYHEADER */
LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1", 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_COPYHEADER
if (IPV6_FRAG_REQROOM > 0) { if (IPV6_FRAG_REQROOM > 0) {
/* hide the extra bytes borrowed from ip6_hdr for struct ip6_reass_helper */ /* 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)); u8_t hdrerr = pbuf_header(next_pbuf, -(s16_t)(IPV6_FRAG_REQROOM));
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == ERR_OK); LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0);
} }
#endif #endif
pbuf_cat(ipr->p, next_pbuf); pbuf_cat(ipr->p, next_pbuf);
@@ -544,8 +547,9 @@ ip6_reass(struct pbuf *p)
#if IPV6_FRAG_COPYHEADER #if IPV6_FRAG_COPYHEADER
if (IPV6_FRAG_REQROOM > 0) { if (IPV6_FRAG_REQROOM > 0) {
/* get back room for struct ip6_reass_helper (only required if sizeof(void*) > 4) */ /* 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)); u8_t hdrerr = pbuf_header(ipr->p, -(s16_t)(IPV6_FRAG_REQROOM));
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == ERR_OK); 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); iphdr_ptr = (struct ip6_hdr*)((u8_t*)ipr->p->payload - IP6_HLEN);
MEMCPY(iphdr_ptr, &ipr->iphdr, IP6_HLEN); MEMCPY(iphdr_ptr, &ipr->iphdr, IP6_HLEN);
@@ -559,7 +563,7 @@ ip6_reass(struct pbuf *p)
- IP6_HLEN); - IP6_HLEN);
/* Set payload length in ip header. */ /* 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. */ /* Get the first pbuf. */
p = ipr->p; p = ipr->p;
@@ -609,6 +613,7 @@ nullreturn:
#if LWIP_IPV6 && LWIP_IPV6_FRAG #if LWIP_IPV6 && LWIP_IPV6_FRAG
#if !LWIP_NETIF_TX_SINGLE_PBUF
/** Allocate a new struct pbuf_custom_ref */ /** Allocate a new struct pbuf_custom_ref */
static struct pbuf_custom_ref* static struct pbuf_custom_ref*
ip6_frag_alloc_pbuf_custom_ref(void) 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); 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. * Fragment an IPv6 datagram if too large for the netif or path MTU.
@@ -657,7 +663,11 @@ ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest)
struct ip6_hdr *ip6hdr; struct ip6_hdr *ip6hdr;
struct ip6_frag_hdr *frag_hdr; struct ip6_frag_hdr *frag_hdr;
struct pbuf *rambuf; struct pbuf *rambuf;
#if !LWIP_NETIF_TX_SINGLE_PBUF
struct pbuf *newpbuf; struct pbuf *newpbuf;
u16_t newpbuflen = 0;
u16_t left_to_copy;
#endif
static u32_t identification; static u32_t identification;
u16_t nfb; u16_t nfb;
u16_t left, cop; 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 fragment_offset = 0;
u16_t last; u16_t last;
u16_t poff = IP6_HLEN; u16_t poff = IP6_HLEN;
u16_t newpbuflen = 0;
u16_t left_to_copy;
identification++; identification++;
@@ -685,6 +693,26 @@ ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest)
/* Fill this fragment */ /* Fill this fragment */
cop = last ? left : nfb; 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. /* 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 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, * 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; return ERR_MEM;
} }
LWIP_ASSERT("this needs a pbuf in one piece!", 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); SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN);
ip6hdr = (struct ip6_hdr *)rambuf->payload; ip6hdr = (struct ip6_hdr *)rambuf->payload;
frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN); 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; poff = newpbuflen;
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
/* Set headers */ /* Set headers */
frag_hdr->_nexth = original_ip6hdr->_nexth; frag_hdr->_nexth = original_ip6hdr->_nexth;
frag_hdr->reserved = 0; frag_hdr->reserved = 0;
frag_hdr->_fragment_offset = htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG)); frag_hdr->_fragment_offset = lwip_htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG));
frag_hdr->_identification = htonl(identification); frag_hdr->_identification = lwip_htonl(identification);
IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT); IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT);
IP6H_PLEN_SET(ip6hdr, cop + IP6_FRAG_HLEN); IP6H_PLEN_SET(ip6hdr, cop + IP6_FRAG_HLEN);

122
ext/lwip/src/core/ipv6/mld6.c Normal file → Executable file
View File

@@ -1,5 +1,12 @@
/** /**
* @file * @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> * <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 */ /* Based on igmp.c implementation of igmp v2 protocol */
#include "lwip/opt.h" #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 */ #if LWIP_IPV6 && LWIP_IPV6_MLD /* don't build if not configured for use in lwipopts.h */
#include "lwip/mld6.h" #include "lwip/mld6.h"
#include "lwip/prot/mld6.h"
#include "lwip/icmp6.h" #include "lwip/icmp6.h"
#include "lwip/ip6.h" #include "lwip/ip6.h"
#include "lwip/ip6_addr.h" #include "lwip/ip6_addr.h"
@@ -75,16 +75,11 @@
#define MLD6_GROUP_DELAYING_MEMBER 1 #define MLD6_GROUP_DELAYING_MEMBER 1
#define MLD6_GROUP_IDLE_MEMBER 2 #define MLD6_GROUP_IDLE_MEMBER 2
/* The list of joined groups. */
static struct mld_group* mld_group_list;
/* Forward declarations. */ /* Forward declarations. */
static struct mld_group *mld6_new_group(struct netif *ifp, const ip6_addr_t *addr); 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 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_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 err_t
mld6_stop(struct netif *netif) mld6_stop(struct netif *netif)
{ {
struct mld_group *group = mld_group_list; struct mld_group *group = netif_mld6_data(netif);
struct mld_group *prev = NULL;
struct mld_group *next; 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) { while (group != NULL) {
next = group->next; struct mld_group *next = group->next; /* avoid use-after-free below */
/* 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 */ /* disable the group at the MAC level */
if (netif->mld_mac_filter != NULL) { if (netif->mld_mac_filter != NULL) {
netif->mld_mac_filter(netif, &(group->group_address), MLD6_DEL_MAC_FILTER); netif->mld_mac_filter(netif, &(group->group_address), NETIF_DEL_MAC_FILTER);
} }
/* free group */ /* free group */
memp_free(MEMP_MLD6_GROUP, group); memp_free(MEMP_MLD6_GROUP, group);
} else {
/* change the "previous" */
prev = group;
}
/* move to "next" */ /* move to "next" */
group = next; group = next;
} }
@@ -136,12 +119,10 @@ mld6_stop(struct netif *netif)
void void
mld6_report_groups(struct netif *netif) mld6_report_groups(struct netif *netif)
{ {
struct mld_group *group = mld_group_list; struct mld_group *group = netif_mld6_data(netif);
while (group != NULL) { 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; group = group->next;
} }
} }
@@ -157,10 +138,10 @@ mld6_report_groups(struct netif *netif)
struct mld_group * struct mld_group *
mld6_lookfor_group(struct netif *ifp, const ip6_addr_t *addr) 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) { while (group != NULL) {
if ((group->netif == ifp) && (ip6_addr_cmp(&(group->group_address), addr))) { if (ip6_addr_cmp(&(group->group_address), addr)) {
return group; return group;
} }
group = group->next; 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); group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP);
if (group != NULL) { if (group != NULL) {
group->netif = ifp;
ip6_addr_set(&(group->group_address), addr); ip6_addr_set(&(group->group_address), addr);
group->timer = 0; /* Not running */ group->timer = 0; /* Not running */
group->group_state = MLD6_GROUP_IDLE_MEMBER; group->group_state = MLD6_GROUP_IDLE_MEMBER;
group->last_reporter_flag = 0; group->last_reporter_flag = 0;
group->use = 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; 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 * @param group the group to remove
* @return ERR_OK if group was removed from the list, an err_t otherwise * @return ERR_OK if group was removed from the list, an err_t otherwise
*/ */
static err_t 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; err_t err = ERR_OK;
/* Is it the first group? */ /* Is it the first group? */
if (mld_group_list == group) { if (netif_mld6_data(netif) == group) {
mld_group_list = group->next; netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, group->next);
} else { } else {
/* look for group further down the list */ /* look for group further down the list */
struct mld_group *tmpGroup; 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) { if (tmpGroup->next == group) {
tmpGroup->next = group->next; tmpGroup->next = group->next;
break; break;
@@ -227,8 +207,6 @@ mld6_free_group(struct mld_group *group)
err = ERR_ARG; err = ERR_ARG;
} }
} }
/* free group */
memp_free(MEMP_MLD6_GROUP, group);
return err; return err;
} }
@@ -266,10 +244,9 @@ mld6_input(struct pbuf *p, struct netif *inp)
ip6_addr_isany(&(mld_hdr->multicast_address))) { ip6_addr_isany(&(mld_hdr->multicast_address))) {
MLD6_STATS_INC(mld6.rx_general); MLD6_STATS_INC(mld6.rx_general);
/* Report all groups, except all nodes group, and if-local groups. */ /* Report all groups, except all nodes group, and if-local groups. */
group = mld_group_list; group = netif_mld6_data(inp);
while (group != NULL) { while (group != NULL) {
if ((group->netif == inp) && if ((!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) &&
(!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) &&
(!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) { (!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) {
mld6_delayed_report(group, mld_hdr->max_resp_delay); 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. */ /* Activate this address on the MAC layer. */
if (netif->mld_mac_filter != NULL) { 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. */ /* Report our membership. */
MLD6_STATS_INC(mld6.tx_report); 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); 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) { if (group != NULL) {
/* Leave if there is no other use of the group */ /* Leave if there is no other use of the group */
if (group->use <= 1) { 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 we are the last reporter for this group */
if (group->last_reporter_flag) { if (group->last_reporter_flag) {
MLD6_STATS_INC(mld6.tx_leave); 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 */ /* Disable the group at the MAC level */
if (netif->mld_mac_filter != NULL) { 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 */ /* free group struct */
mld6_free_group(group); memp_free(MEMP_MLD6_GROUP, group);
} else { } else {
/* Decrement group use */ /* Decrement group use */
group->use--; group->use--;
@@ -476,7 +456,10 @@ mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr)
void void
mld6_tmr(void) mld6_tmr(void)
{ {
struct mld_group *group = mld_group_list; struct netif *netif = netif_list;
while (netif != NULL) {
struct mld_group *group = netif_mld6_data(netif);
while (group != NULL) { while (group != NULL) {
if (group->timer > 0) { if (group->timer > 0) {
@@ -485,13 +468,15 @@ mld6_tmr(void)
/* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */ /* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */
if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) {
MLD6_STATS_INC(mld6.tx_report); MLD6_STATS_INC(mld6.tx_report);
mld6_send(group, ICMP6_TYPE_MLR); mld6_send(netif, group, ICMP6_TYPE_MLR);
group->group_state = MLD6_GROUP_IDLE_MEMBER; group->group_state = MLD6_GROUP_IDLE_MEMBER;
} }
} }
} }
group = group->next; group = group->next;
} }
netif = netif->next;
}
} }
/** /**
@@ -537,7 +522,7 @@ mld6_delayed_report(struct mld_group *group, u16_t maxresp)
* @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done) * @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done)
*/ */
static void 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 mld_header *mld_hdr;
struct pbuf *p; struct pbuf *p;
@@ -558,13 +543,13 @@ mld6_send(struct mld_group *group, u8_t type)
} }
/* Select our source address. */ /* 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. /* 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. */ * We must join the multicast group, but we don't have a valid address yet. */
src_addr = IP6_ADDR_ANY6; src_addr = IP6_ADDR_ANY6;
} else { } else {
/* Use link-local address as source address. */ /* 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. */ /* 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)); ip6_addr_set(&(mld_hdr->multicast_address), &(group->group_address));
#if CHECKSUM_GEN_ICMP6 #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, mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len,
src_addr, &(group->group_address)); src_addr, &(group->group_address));
} }
@@ -588,10 +573,15 @@ mld6_send(struct mld_group *group, u8_t type)
/* Add hop-by-hop headers options: router alert with MLD value. */ /* Add hop-by-hop headers options: router alert with MLD value. */
ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD); ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD);
if (type == ICMP6_TYPE_MLR) {
/* Remember we were the last to report */
group->last_reporter_flag = 1;
}
/* Send the packet out. */ /* Send the packet out. */
MLD6_STATS_INC(mld6.xmit); MLD6_STATS_INC(mld6.xmit);
ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address), 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); pbuf_free(p);
} }

420
ext/lwip/src/core/ipv6/nd6.c Normal file → Executable file
View File

@@ -46,6 +46,9 @@
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ #if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/nd6.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/pbuf.h"
#include "lwip/mem.h" #include "lwip/mem.h"
#include "lwip/memp.h" #include "lwip/memp.h"
@@ -57,9 +60,17 @@
#include "lwip/mld6.h" #include "lwip/mld6.h"
#include "lwip/ip.h" #include "lwip/ip.h"
#include "lwip/stats.h" #include "lwip/stats.h"
#include "lwip/dns.h"
#include <string.h> #include <string.h>
#ifdef LWIP_HOOK_FILENAME
#include LWIP_HOOK_FILENAME
#endif
#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. */ /* Router tables. */
struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS]; struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS];
@@ -88,15 +99,19 @@ 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_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_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_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_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_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_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_MULTICAST_DEST 0x01
#define ND6_SEND_FLAG_ALLNODES_DEST 0x02 #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_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_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 #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 */ #endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
@@ -143,10 +158,41 @@ nd6_input(struct pbuf *p, struct netif *inp)
/* Unsolicited NA?*/ /* Unsolicited NA?*/
if (ip6_addr_ismulticast(ip6_current_dest_addr())) { if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
ip6_addr_t target_address;
/* This is an unsolicited NA. /* This is an unsolicited NA.
* link-layer changed? * link-layer changed?
* part of DAD mechanism? */ * 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. */ /* Check that link-layer address option also fits in packet. */
if (p->len < (sizeof(struct na_header) + 2)) { if (p->len < (sizeof(struct na_header) + 2)) {
/* @todo debug message */ /* @todo debug message */
@@ -166,58 +212,25 @@ nd6_input(struct pbuf *p, struct netif *inp)
return; 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. */ /* 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 (i >= 0) {
if (na_hdr->flags & ND6_FLAG_OVERRIDE) { if (na_hdr->flags & ND6_FLAG_OVERRIDE) {
MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
} }
} }
} else { } else {
ip6_addr_t target_address;
/* This is a solicited NA. /* This is a solicited NA.
* neighbor address resolution response? * neighbor address resolution response?
* neighbor unreachability detection response? */ * neighbor unreachability detection response? */
/* Override ip6_current_dest_addr() so that we have an aligned copy. */ /* Create an aligned copy. */
ip6_addr_set(ip6_current_dest_addr(), &(na_hdr->target_address)); ip6_addr_set(&target_address, &(na_hdr->target_address));
/* Find the cache entry corresponding to this na. */ /* 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) { if (i < 0) {
/* We no longer care about this target address. drop it. */ /* We no longer care about this target address. drop it. */
pbuf_free(p); pbuf_free(p);
@@ -225,8 +238,6 @@ nd6_input(struct pbuf *p, struct netif *inp)
} }
/* Update cache entry. */ /* Update cache entry. */
neighbor_cache[i].netif = inp;
neighbor_cache[i].counter.reachable_time = reachable_time;
if ((na_hdr->flags & ND6_FLAG_OVERRIDE) || if ((na_hdr->flags & ND6_FLAG_OVERRIDE) ||
(neighbor_cache[i].state == ND6_INCOMPLETE)) { (neighbor_cache[i].state == ND6_INCOMPLETE)) {
/* Check that link-layer address option also fits in packet. */ /* Check that link-layer address option also fits in packet. */
@@ -250,7 +261,10 @@ nd6_input(struct pbuf *p, struct netif *inp)
MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); 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].state = ND6_REACHABLE;
neighbor_cache[i].counter.reachable_time = reachable_time;
/* Send queued packets, if any. */ /* Send queued packets, if any. */
if (neighbor_cache[i].q != NULL) { if (neighbor_cache[i].q != NULL) {
@@ -320,6 +334,8 @@ nd6_input(struct pbuf *p, struct netif *inp)
} }
} }
} else { } else {
ip6_addr_t target_address;
/* Sender is trying to resolve our address. */ /* Sender is trying to resolve our address. */
/* Verify that they included their own link-layer address. */ /* Verify that they included their own link-layer address. */
if (lladdr_opt == NULL) { if (lladdr_opt == NULL) {
@@ -339,7 +355,7 @@ nd6_input(struct pbuf *p, struct netif *inp)
/* Delay probe in case we get confirmation of reachability from upper layer (TCP). */ /* Delay probe in case we get confirmation of reachability from upper layer (TCP). */
neighbor_cache[i].state = ND6_DELAY; 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 { } else {
/* Add their IPv6 address and link-layer address to neighbor cache. /* Add their IPv6 address and link-layer address to neighbor cache.
@@ -360,14 +376,14 @@ nd6_input(struct pbuf *p, struct netif *inp)
/* Receiving a message does not prove reachability: only in one direction. /* Receiving a message does not prove reachability: only in one direction.
* Delay probe in case we get confirmation of reachability from upper layer (TCP). */ * Delay probe in case we get confirmation of reachability from upper layer (TCP). */
neighbor_cache[i].state = ND6_DELAY; 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. */ /* Create an aligned copy. */
ip6_addr_set(ip6_current_dest_addr(), &(ns_hdr->target_address)); ip6_addr_set(&target_address, &(ns_hdr->target_address));
/* Send back a NA for us. Allocate the reply pbuf. */ /* 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 */ break; /* ICMP6_TYPE_NS */
@@ -377,6 +393,10 @@ nd6_input(struct pbuf *p, struct netif *inp)
struct ra_header *ra_hdr; struct ra_header *ra_hdr;
u8_t *buffer; /* Used to copy options. */ u8_t *buffer; /* Used to copy options. */
u16_t offset; 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. */ /* Check that RA header fits in packet. */
if (p->len < sizeof(struct ra_header)) { if (p->len < sizeof(struct ra_header)) {
@@ -413,15 +433,15 @@ nd6_input(struct pbuf *p, struct netif *inp)
} }
/* Re-set invalidation timer. */ /* 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. */ /* Re-set default timer values. */
#if LWIP_ND6_ALLOW_RA_UPDATES #if LWIP_ND6_ALLOW_RA_UPDATES
if (ra_hdr->retrans_timer > 0) { 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) { 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 */ #endif /* LWIP_ND6_ALLOW_RA_UPDATES */
@@ -441,7 +461,12 @@ nd6_input(struct pbuf *p, struct netif *inp)
buffer = &((u8_t*)p->payload)[offset]; buffer = &((u8_t*)p->payload)[offset];
} else { } else {
buffer = nd6_ra_buffer; 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) { if (buffer[1] == 0) {
/* zero-length extension. drop packet */ /* zero-length extension. drop packet */
@@ -467,9 +492,9 @@ nd6_input(struct pbuf *p, struct netif *inp)
{ {
struct mtu_option *mtu_opt; struct mtu_option *mtu_opt;
mtu_opt = (struct mtu_option *)buffer; 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 #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 */ #endif /* LWIP_ND6_ALLOW_RA_UPDATES */
} }
break; break;
@@ -479,21 +504,24 @@ nd6_input(struct pbuf *p, struct netif *inp)
struct prefix_option *prefix_opt; struct prefix_option *prefix_opt;
prefix_opt = (struct prefix_option *)buffer; 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. */ /* Add to on-link prefix list. */
s8_t prefix; s8_t prefix;
ip6_addr_t prefix_addr;
/* Get a memory-aligned copy of the prefix. */ /* 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. */ /* 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) { if (prefix < 0) {
/* Create a new cache entry. */ /* 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) { 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 LWIP_IPV6_AUTOCONFIG
if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) { if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) {
@@ -513,6 +541,37 @@ nd6_input(struct pbuf *p, struct netif *inp)
route_opt = (struct route_option *)buffer;*/ route_opt = (struct route_option *)buffer;*/
break; 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: default:
/* Unrecognized option, abort. */ /* Unrecognized option, abort. */
ND6_STATS_INC(nd6.proterr); ND6_STATS_INC(nd6.proterr);
@@ -528,6 +587,7 @@ nd6_input(struct pbuf *p, struct netif *inp)
{ {
struct redirect_header *redir_hdr; struct redirect_header *redir_hdr;
struct lladdr_option *lladdr_opt; struct lladdr_option *lladdr_opt;
ip6_addr_t tmp;
/* Check that Redir header fits in packet. */ /* Check that Redir header fits in packet. */
if (p->len < sizeof(struct redirect_header)) { if (p->len < sizeof(struct redirect_header)) {
@@ -550,10 +610,10 @@ nd6_input(struct pbuf *p, struct netif *inp)
} }
/* Copy original destination address to current source address, to have an aligned copy. */ /* 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 */ /* 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) { if (i < 0) {
/* Destination not in cache, drop packet. */ /* Destination not in cache, drop packet. */
pbuf_free(p); pbuf_free(p);
@@ -567,20 +627,20 @@ nd6_input(struct pbuf *p, struct netif *inp)
if (lladdr_opt != NULL) { if (lladdr_opt != NULL) {
if (lladdr_opt->type == ND6_OPTION_TYPE_TARGET_LLADDR) { if (lladdr_opt->type == ND6_OPTION_TYPE_TARGET_LLADDR) {
/* Copy target address to current source address, to have an aligned copy. */ /* 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) { if (i < 0) {
i = nd6_new_neighbor_cache_entry(); i = nd6_new_neighbor_cache_entry();
if (i >= 0) { if (i >= 0) {
neighbor_cache[i].netif = inp; neighbor_cache[i].netif = inp;
MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); 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. /* Receiving a message does not prove reachability: only in one direction.
* Delay probe in case we get confirmation of reachability from upper layer (TCP). */ * Delay probe in case we get confirmation of reachability from upper layer (TCP). */
neighbor_cache[i].state = ND6_DELAY; 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) { if (i >= 0) {
@@ -589,7 +649,7 @@ nd6_input(struct pbuf *p, struct netif *inp)
/* Receiving a message does not prove reachability: only in one direction. /* Receiving a message does not prove reachability: only in one direction.
* Delay probe in case we get confirmation of reachability from upper layer (TCP). */ * Delay probe in case we get confirmation of reachability from upper layer (TCP). */
neighbor_cache[i].state = ND6_DELAY; 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;
} }
} }
} }
@@ -601,6 +661,7 @@ nd6_input(struct pbuf *p, struct netif *inp)
struct icmp6_hdr *icmp6hdr; /* Packet too big message */ 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; u32_t pmtu;
ip6_addr_t tmp;
/* Check that ICMPv6 header + IPv6 header fit in payload */ /* Check that ICMPv6 header + IPv6 header fit in payload */
if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) { if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) {
@@ -615,10 +676,10 @@ nd6_input(struct pbuf *p, struct netif *inp)
ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr)); 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. */ /* 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. */ /* 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) { if (i < 0) {
/* Destination not in cache, drop packet. */ /* Destination not in cache, drop packet. */
pbuf_free(p); pbuf_free(p);
@@ -626,7 +687,7 @@ nd6_input(struct pbuf *p, struct netif *inp)
} }
/* Change the Path MTU. */ /* Change the Path MTU. */
pmtu = htonl(icmp6hdr->data); pmtu = lwip_htonl(icmp6hdr->data);
destination_cache[i].pmtu = (u16_t)LWIP_MIN(pmtu, 0xFFFF); destination_cache[i].pmtu = (u16_t)LWIP_MIN(pmtu, 0xFFFF);
break; /* ICMP6_TYPE_PTB */ break; /* ICMP6_TYPE_PTB */
@@ -668,7 +729,7 @@ nd6_tmr(void)
} else { } else {
/* Send a NS for this entry. */ /* Send a NS for this entry. */
neighbor_cache[i].counter.probes_sent++; 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; break;
case ND6_REACHABLE: case ND6_REACHABLE:
@@ -685,15 +746,15 @@ nd6_tmr(void)
} }
break; break;
case ND6_STALE: case ND6_STALE:
neighbor_cache[i].counter.stale_time += ND6_TMR_INTERVAL; neighbor_cache[i].counter.stale_time++;
break; break;
case ND6_DELAY: 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. */ /* Change to PROBE state. */
neighbor_cache[i].state = ND6_PROBE; neighbor_cache[i].state = ND6_PROBE;
neighbor_cache[i].counter.probes_sent = 0; neighbor_cache[i].counter.probes_sent = 0;
} else { } else {
neighbor_cache[i].counter.delay_time -= ND6_TMR_INTERVAL; neighbor_cache[i].counter.delay_time--;
} }
break; break;
case ND6_PROBE: case ND6_PROBE:
@@ -704,7 +765,7 @@ nd6_tmr(void)
} else { } else {
/* Send a NS for this entry. */ /* Send a NS for this entry. */
neighbor_cache[i].counter.probes_sent++; 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; break;
case ND6_NO_ENTRY: case ND6_NO_ENTRY:
@@ -745,8 +806,7 @@ nd6_tmr(void)
#if LWIP_IPV6_AUTOCONFIG #if LWIP_IPV6_AUTOCONFIG
/* If any addresses were configured with this prefix, remove them */ /* If any addresses were configured with this prefix, remove them */
if (prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED) if (prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED) {
{
s8_t j; s8_t j;
for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) { for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) {
@@ -778,7 +838,7 @@ nd6_tmr(void)
for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) { for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) {
if (netif_ip6_addr_state(prefix_list[i].netif, j) == IP6_ADDR_INVALID) { if (netif_ip6_addr_state(prefix_list[i].netif, j) == IP6_ADDR_INVALID) {
/* Generate an address using this prefix and interface ID from link-local address. */ /* Generate an address using this prefix and interface ID from link-local address. */
IP_ADDR6(&prefix_list[i].netif->ip6_addr[j], netif_ip6_addr_set_parts(prefix_list[i].netif, j,
prefix_list[i].prefix.addr[0], prefix_list[i].prefix.addr[1], prefix_list[i].prefix.addr[0], prefix_list[i].prefix.addr[1],
netif_ip6_addr(prefix_list[i].netif, 0)->addr[2], netif_ip6_addr(prefix_list[i].netif, 0)->addr[3]); netif_ip6_addr(prefix_list[i].netif, 0)->addr[2], netif_ip6_addr(prefix_list[i].netif, 0)->addr[3]);
@@ -802,22 +862,17 @@ nd6_tmr(void)
/* Process our own addresses, if DAD configured. */ /* Process our own addresses, if DAD configured. */
for (netif = netif_list; netif != NULL; netif = netif->next) { for (netif = netif_list; netif != NULL; netif = netif->next) {
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) {
if (ip6_addr_istentative(netif->ip6_addr_state[i])) { u8_t addr_state = netif_ip6_addr_state(netif, i);
if ((netif->ip6_addr_state[i] & 0x07) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) { if (ip6_addr_istentative(addr_state)) {
if ((addr_state & IP6_ADDR_TENTATIVE_COUNT_MASK) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) {
/* No NA received in response. Mark address as valid. */ /* No NA received in response. Mark address as valid. */
netif->ip6_addr_state[i] = IP6_ADDR_PREFERRED; netif_ip6_addr_set_state(netif, i, IP6_ADDR_PREFERRED);
/* @todo implement preferred and valid lifetimes. */ /* @todo implement preferred and valid lifetimes. */
} else if (netif->flags & NETIF_FLAG_UP) { } else if (netif->flags & NETIF_FLAG_UP) {
#if LWIP_IPV6_MLD
if ((netif->ip6_addr_state[i] & 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. */ /* Send a NS for this address. */
nd6_send_ns(netif, netif_ip6_addr(netif, i), ND6_SEND_FLAG_MULTICAST_DEST); nd6_send_ns(netif, netif_ip6_addr(netif, i), ND6_SEND_FLAG_MULTICAST_DEST);
netif->ip6_addr_state[i]++; /* tentative: set next state by increasing by one */
netif_ip6_addr_set_state(netif, i, addr_state + 1);
/* @todo send max 1 NS per tmr call? enable return*/ /* @todo send max 1 NS per tmr call? enable return*/
/*return;*/ /*return;*/
} }
@@ -839,6 +894,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 * Send a neighbor solicitation message
* *
@@ -926,7 +992,7 @@ nd6_send_na(struct netif * netif, const ip6_addr_t * target_addr, u8_t flags)
u16_t lladdr_opt_len; u16_t lladdr_opt_len;
/* Use link-local address as source address. */ /* Use link-local address as source address. */
/* src_addr = &(netif->ip6_addr[0]); */ /* src_addr = netif_ip6_addr(netif, 0); */
/* Use target address as source address. */ /* Use target address as source address. */
src_addr = target_addr; src_addr = target_addr;
@@ -1260,6 +1326,22 @@ nd6_new_destination_cache_entry(void)
return j; 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. * Determine whether an address matches an on-link prefix.
* *
@@ -1295,7 +1377,7 @@ nd6_is_prefix_in_netif(const ip6_addr_t * ip6addr, struct netif * netif)
* @return the default router entry index, or -1 if no suitable * @return the default router entry index, or -1 if no suitable
* router is found * router is found
*/ */
s8_t static s8_t
nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif) nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif)
{ {
s8_t i; s8_t i;
@@ -1347,6 +1429,30 @@ nd6_select_router(const ip6_addr_t * ip6addr, struct netif * netif)
return -1; 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. * Find an entry for a default router.
* *
@@ -1383,6 +1489,7 @@ 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 router_index;
s8_t free_router_index;
s8_t neighbor_index; s8_t neighbor_index;
/* Do we have a neighbor entry for this router? */ /* Do we have a neighbor entry for this router? */
@@ -1398,18 +1505,29 @@ nd6_new_router(const ip6_addr_t * router_addr, struct netif * netif)
neighbor_cache[neighbor_index].netif = netif; neighbor_cache[neighbor_index].netif = netif;
neighbor_cache[neighbor_index].q = NULL; neighbor_cache[neighbor_index].q = NULL;
neighbor_cache[neighbor_index].state = ND6_INCOMPLETE; 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. */ /* Mark neighbor as router. */
neighbor_cache[neighbor_index].isrouter = 1; neighbor_cache[neighbor_index].isrouter = 1;
/* Look for empty entry. */ /* Look for empty entry. */
for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) { free_router_index = LWIP_ND6_NUM_ROUTERS;
if (default_router_list[router_index].neighbor_entry == NULL) { for (router_index = LWIP_ND6_NUM_ROUTERS - 1; router_index >= 0; router_index--) {
default_router_list[router_index].neighbor_entry = &(neighbor_cache[neighbor_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; return router_index;
} }
if (default_router_list[router_index].neighbor_entry == NULL) {
/* 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. */ /* Could not create a router entry. */
@@ -1487,9 +1605,12 @@ nd6_new_onlink_prefix(ip6_addr_t * prefix, struct netif * netif)
* suitable next hop was found, ERR_MEM if no cache entry * suitable next hop was found, ERR_MEM if no cache entry
* could be created * could be created
*/ */
s8_t static s8_t
nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif) 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; s8_t i;
#if LWIP_NETIF_HWADDRHINT #if LWIP_NETIF_HWADDRHINT
@@ -1533,6 +1654,12 @@ nd6_get_next_hop_entry(const ip6_addr_t * ip6addr, struct netif * netif)
/* Destination in local link. */ /* Destination in local link. */
destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; 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); 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 { } else {
/* We need to select a router. */ /* We need to select a router. */
i = nd6_select_router(ip6addr, netif); i = nd6_select_router(ip6addr, netif);
@@ -1582,7 +1709,8 @@ nd6_get_next_hop_entry(const ip6_addr_t * ip6addr, struct netif * netif)
neighbor_cache[i].isrouter = 0; neighbor_cache[i].isrouter = 0;
neighbor_cache[i].netif = netif; neighbor_cache[i].netif = netif;
neighbor_cache[i].state = ND6_INCOMPLETE; 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);
} }
} }
@@ -1599,7 +1727,7 @@ nd6_get_next_hop_entry(const ip6_addr_t * ip6addr, struct netif * netif)
* @param q packet to be queued * @param q packet to be queued
* @return ERR_OK if succeeded, ERR_MEM if out of memory * @return ERR_OK if succeeded, ERR_MEM if out of memory
*/ */
err_t static err_t
nd6_queue_packet(s8_t neighbor_index, struct pbuf *q) nd6_queue_packet(s8_t neighbor_index, struct pbuf *q)
{ {
err_t result = ERR_MEM; err_t result = ERR_MEM;
@@ -1735,6 +1863,7 @@ static void
nd6_send_q(s8_t i) nd6_send_q(s8_t i)
{ {
struct ip6_hdr *ip6hdr; struct ip6_hdr *ip6hdr;
ip6_addr_t dest;
#if LWIP_ND6_QUEUEING #if LWIP_ND6_QUEUEING
struct nd6_q_entry *q; struct nd6_q_entry *q;
#endif /* LWIP_ND6_QUEUEING */ #endif /* LWIP_ND6_QUEUEING */
@@ -1751,10 +1880,10 @@ nd6_send_q(s8_t i)
neighbor_cache[i].q = q->next; neighbor_cache[i].q = q->next;
/* Get ipv6 header. */ /* Get ipv6 header. */
ip6hdr = (struct ip6_hdr *)(q->p->payload); ip6hdr = (struct ip6_hdr *)(q->p->payload);
/* Override ip6_current_dest_addr() so that we have an aligned copy. */ /* Create an aligned copy. */
ip6_addr_set(ip6_current_dest_addr(), &(ip6hdr->dest)); ip6_addr_set(&dest, &(ip6hdr->dest));
/* send the queued IPv6 packet */ /* 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 */ /* free the queued IP packet */
pbuf_free(q->p); pbuf_free(q->p);
/* now queue entry can be freed */ /* now queue entry can be freed */
@@ -1764,10 +1893,10 @@ nd6_send_q(s8_t i)
if (neighbor_cache[i].q != NULL) { if (neighbor_cache[i].q != NULL) {
/* Get ipv6 header. */ /* Get ipv6 header. */
ip6hdr = (struct ip6_hdr *)(neighbor_cache[i].q->payload); ip6hdr = (struct ip6_hdr *)(neighbor_cache[i].q->payload);
/* Override ip6_current_dest_addr() so that we have an aligned copy. */ /* Create an aligned copy. */
ip6_addr_set(ip6_current_dest_addr(), &(ip6hdr->dest)); ip6_addr_set(&dest, &(ip6hdr->dest));
/* send the queued IPv6 packet */ /* 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 */ /* free the queued IP packet */
pbuf_free(neighbor_cache[i].q); pbuf_free(neighbor_cache[i].q);
neighbor_cache[i].q = NULL; neighbor_cache[i].q = NULL;
@@ -1775,6 +1904,61 @@ nd6_send_q(s8_t i)
#endif /* LWIP_ND6_QUEUEING */ #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. * Get the Path MTU for a destination.
@@ -1881,4 +2065,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 */ #endif /* LWIP_IPV6 */

40
ext/lwip/src/core/mem.c Normal file → Executable file
View File

@@ -9,7 +9,7 @@
* *
* To let mem_malloc() use pools (prevents fragmentation and is much faster than * 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 * 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): * of pools like this (more pools can be added between _START and _END):
* *
* Define three pools with sizes 256, 512, and 1512 bytes * Define three pools with sizes 256, 512, and 1512 bytes
@@ -54,15 +54,20 @@
*/ */
#include "lwip/opt.h" #include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h" #include "lwip/mem.h"
#include "lwip/def.h"
#include "lwip/sys.h" #include "lwip/sys.h"
#include "lwip/stats.h" #include "lwip/stats.h"
#include "lwip/err.h" #include "lwip/err.h"
#include <string.h> #include <string.h>
#if MEM_LIBC_MALLOC
#include <stdlib.h> /* for malloc()/free() */
#endif
#if MEM_LIBC_MALLOC || MEM_USE_POOLS #if MEM_LIBC_MALLOC || MEM_USE_POOLS
/** mem_init is not used when using pools instead of a heap or using /** mem_init is not used when using pools instead of a heap or using
* C library malloc(). * C library malloc().
*/ */
@@ -161,17 +166,26 @@ void *
mem_malloc(mem_size_t size) mem_malloc(mem_size_t size)
{ {
void *ret; void *ret;
struct memp_malloc_helper *element; struct memp_malloc_helper *element = NULL;
memp_t poolnr; memp_t poolnr;
mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); 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)) { 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 /* 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? */ plus a struct memp_malloc_helper that saves the pool this element came from? */
if (required_size <= memp_pools[poolnr]->size) { 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; break;
} }
} }
@@ -180,20 +194,6 @@ again:
MEM_STATS_INC(err); MEM_STATS_INC(err);
return NULL; 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 */ /* save the pool number this element came from */
element->poolnr = poolnr; element->poolnr = poolnr;

95
ext/lwip/src/core/memp.c Normal file → Executable file
View File

@@ -4,6 +4,11 @@
* *
* lwIP has dedicated pools for many structures (netconn, protocol control blocks, * lwIP has dedicated pools for many structures (netconn, protocol control blocks,
* packet buffers, ...). All these pools are managed here. * 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/opt.h"
#include "lwip/memp.h" #include "lwip/memp.h"
@@ -72,11 +71,10 @@
#include "netif/ppp/ppp_opts.h" #include "netif/ppp/ppp_opts.h"
#include "lwip/netdb.h" #include "lwip/netdb.h"
#include "lwip/dns.h" #include "lwip/dns.h"
#include "lwip/nd6.h" #include "lwip/priv/nd6_priv.h"
#include "lwip/ip6_frag.h" #include "lwip/ip6_frag.h"
#include "lwip/mld6.h" #include "lwip/mld6.h"
#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc) #define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc)
#include "lwip/priv/memp_std.h" #include "lwip/priv/memp_std.h"
@@ -85,6 +83,10 @@ const struct memp_desc* const memp_pools[MEMP_MAX] = {
#include "lwip/priv/memp_std.h" #include "lwip/priv/memp_std.h"
}; };
#ifdef LWIP_HOOK_FILENAME
#include LWIP_HOOK_FILENAME
#endif
#if MEMP_MEM_MALLOC && MEMP_OVERFLOW_CHECK >= 2 #if MEMP_MEM_MALLOC && MEMP_OVERFLOW_CHECK >= 2
#undef MEMP_OVERFLOW_CHECK #undef MEMP_OVERFLOW_CHECK
/* MEMP_OVERFLOW_CHECK >= 2 does not work with MEMP_MEM_MALLOC, use 1 instead */ /* MEMP_OVERFLOW_CHECK >= 2 does not work with MEMP_MEM_MALLOC, use 1 instead */
@@ -120,14 +122,14 @@ memp_sanity(const struct memp_desc *desc)
* (e.g. the restricted area after it has been altered) * (e.g. the restricted area after it has been altered)
* *
* @param p the memp element to check * @param p the memp element to check
* @param memp_type the pool p comes from * @param desc the pool p comes from
*/ */
static void static void
memp_overflow_check_element_overflow(struct memp *p, const struct memp_desc *desc) memp_overflow_check_element_overflow(struct memp *p, const struct memp_desc *desc)
{ {
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
u16_t k; u16_t k;
u8_t *m; u8_t *m;
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE + desc->size; m = (u8_t*)p + MEMP_SIZE + desc->size;
for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) { for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
if (m[k] != 0xcd) { if (m[k] != 0xcd) {
@@ -136,7 +138,10 @@ memp_overflow_check_element_overflow(struct memp *p, const struct memp_desc *des
LWIP_ASSERT(errstr, 0); 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 +149,14 @@ memp_overflow_check_element_overflow(struct memp *p, const struct memp_desc *des
* (e.g. the restricted area before it has been altered) * (e.g. the restricted area before it has been altered)
* *
* @param p the memp element to check * @param p the memp element to check
* @param memp_type the pool p comes from * @param desc the pool p comes from
*/ */
static void static void
memp_overflow_check_element_underflow(struct memp *p, const struct memp_desc *desc) memp_overflow_check_element_underflow(struct memp *p, const struct memp_desc *desc)
{ {
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
u16_t k; u16_t k;
u8_t *m; u8_t *m;
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) { for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {
if (m[k] != 0xcd) { if (m[k] != 0xcd) {
@@ -160,7 +165,10 @@ memp_overflow_check_element_underflow(struct memp *p, const struct memp_desc *de
LWIP_ASSERT(errstr, 0); 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 +177,7 @@ memp_overflow_check_element_underflow(struct memp *p, const struct memp_desc *de
static void static void
memp_overflow_init_element(struct memp *p, const struct memp_desc *desc) 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; u8_t *m;
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 #if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
@@ -178,6 +187,10 @@ memp_overflow_init_element(struct memp *p, const struct memp_desc *desc)
m = (u8_t*)p + MEMP_SIZE + desc->size; m = (u8_t*)p + MEMP_SIZE + desc->size;
memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED); memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
#endif #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 #if MEMP_OVERFLOW_CHECK >= 2
@@ -195,34 +208,16 @@ memp_overflow_check_all(void)
SYS_ARCH_PROTECT(old_level); SYS_ARCH_PROTECT(old_level);
for (i = 0; i < MEMP_MAX; ++i) { 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) { for (j = 0; j < memp_pools[i]->num; ++j) {
memp_overflow_check_element_overflow(p, memp_pools[i]); memp_overflow_check_element_overflow(p, memp_pools[i]);
memp_overflow_check_element_underflow(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); SYS_ARCH_UNPROTECT(old_level);
} }
#endif /* MEMP_OVERFLOW_CHECK >= 2 */ #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 *)(size_t)(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 */ #endif /* MEMP_OVERFLOW_CHECK */
/** /**
@@ -246,6 +241,9 @@ memp_init_pool(const struct memp_desc *desc)
for (i = 0; i < desc->num; ++i) { for (i = 0; i < desc->num; ++i) {
memp->next = *desc->tab; memp->next = *desc->tab;
*desc->tab = memp; *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 */ /* cast through void* to get rid of alignment warnings */
memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size
#if MEMP_OVERFLOW_CHECK #if MEMP_OVERFLOW_CHECK
@@ -253,21 +251,14 @@ memp_init_pool(const struct memp_desc *desc)
#endif #endif
); );
} }
#if MEMP_OVERFLOW_CHECK
memp_overflow_init(desc);
#endif /* MEMP_OVERFLOW_CHECK */
#endif /* !MEMP_MEM_MALLOC */
#if MEMP_STATS #if MEMP_STATS
#if !MEMP_MEM_MALLOC
desc->stats->avail = desc->num; desc->stats->avail = desc->num;
#endif /* MEMP_STATS */
#endif /* !MEMP_MEM_MALLOC */ #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; desc->stats->name = desc->desc;
#endif /* defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY */ #endif /* MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY) */
#endif /* MEMP_STATS */
} }
/** /**
@@ -313,15 +304,15 @@ do_memp_malloc_pool_fn(const struct memp_desc *desc, const char* file, const int
SYS_ARCH_PROTECT(old_level); SYS_ARCH_PROTECT(old_level);
memp = *desc->tab; 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 */ #endif /* MEMP_MEM_MALLOC */
if (memp != NULL) { if (memp != NULL) {
#if !MEMP_MEM_MALLOC #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; *desc->tab = memp->next;
#if MEMP_OVERFLOW_CHECK #if MEMP_OVERFLOW_CHECK
memp->next = NULL; memp->next = NULL;
@@ -483,12 +474,16 @@ memp_free(memp_t type, void *mem)
LWIP_ERROR("memp_free: type < MEMP_MAX", (type < MEMP_MAX), return;); LWIP_ERROR("memp_free: type < MEMP_MAX", (type < MEMP_MAX), return;);
if (mem == NULL) {
return;
}
#if MEMP_OVERFLOW_CHECK >= 2 #if MEMP_OVERFLOW_CHECK >= 2
memp_overflow_check_all(); memp_overflow_check_all();
#endif /* MEMP_OVERFLOW_CHECK >= 2 */ #endif /* MEMP_OVERFLOW_CHECK >= 2 */
#ifdef LWIP_HOOK_MEMP_AVAILABLE #ifdef LWIP_HOOK_MEMP_AVAILABLE
old_first = memp_pools[type].tab; old_first = *memp_pools[type]->tab;
#endif #endif
do_memp_free_pool(memp_pools[type], mem); do_memp_free_pool(memp_pools[type], mem);

305
ext/lwip/src/core/netif.c Normal file → Executable file
View File

@@ -1,6 +1,20 @@
/** /**
* @file * @file
* lwIP network interface abstraction * 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> * Author: Adam Dunkels <adam@sics.se>
*/ */
/**
* @defgroup netif Network interface (NETIF)
* @ingroup callbackstyle_api
*/
#include "lwip/opt.h" #include "lwip/opt.h"
#include <string.h>
#include "lwip/def.h" #include "lwip/def.h"
#include "lwip/ip_addr.h" #include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h" #include "lwip/ip6_addr.h"
#include "lwip/netif.h" #include "lwip/netif.h"
#include "lwip/priv/tcp_priv.h" #include "lwip/priv/tcp_priv.h"
#include "lwip/udp.h" #include "lwip/udp.h"
#include "lwip/raw.h"
#include "lwip/snmp.h" #include "lwip/snmp.h"
#include "lwip/igmp.h" #include "lwip/igmp.h"
#include "lwip/etharp.h" #include "lwip/etharp.h"
#include "lwip/stats.h" #include "lwip/stats.h"
#include "lwip/sys.h" #include "lwip/sys.h"
#include "lwip/ip.h"
#if ENABLE_LOOPBACK #if ENABLE_LOOPBACK
#include "lwip/sys.h"
#if LWIP_NETIF_LOOPBACK_MULTITHREADING #if LWIP_NETIF_LOOPBACK_MULTITHREADING
#include "lwip/tcpip.h" #include "lwip/tcpip.h"
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
#endif /* ENABLE_LOOPBACK */ #endif /* ENABLE_LOOPBACK */
#include "netif/ethernet.h"
#if LWIP_AUTOIP #if LWIP_AUTOIP
#include "lwip/autoip.h" #include "lwip/autoip.h"
#endif /* LWIP_AUTOIP */ #endif /* LWIP_AUTOIP */
@@ -92,6 +106,10 @@ struct netif *netif_default;
static u8_t netif_num; 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_IPV4 0x01
#define NETIF_REPORT_TYPE_IPV6 0x02 #define NETIF_REPORT_TYPE_IPV6 0x02
static void netif_issue_reports(struct netif* netif, u8_t report_type); static void netif_issue_reports(struct netif* netif, u8_t report_type);
@@ -162,7 +180,7 @@ netif_init(void)
#endif /* NO_SYS */ #endif /* NO_SYS */
#if LWIP_IPV6 #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; loop_netif.ip6_addr_state[0] = IP6_ADDR_VALID;
#endif /* LWIP_IPV6 */ #endif /* LWIP_IPV6 */
@@ -210,7 +228,12 @@ netif_input(struct pbuf *p, struct netif *inp)
* These functions use netif flags NETIF_FLAG_ETHARP and NETIF_FLAG_ETHERNET * These functions use netif flags NETIF_FLAG_ETHARP and NETIF_FLAG_ETHERNET
* to decide whether to forward to ethernet_input() or ip_input(). * to decide whether to forward to ethernet_input() or ip_input().
* In other words, the functions only work when the netif * 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. * @return netif, or NULL if failed.
*/ */
@@ -222,7 +245,7 @@ netif_add(struct netif *netif,
void *state, netif_init_fn init, netif_input_fn input) void *state, netif_init_fn init, netif_input_fn input)
{ {
#if LWIP_IPV6 #if LWIP_IPV6
u32_t i; s8_t i;
#endif #endif
LWIP_ASSERT("No init function given", init != NULL); LWIP_ASSERT("No init function given", init != NULL);
@@ -236,20 +259,15 @@ netif_add(struct netif *netif,
#if LWIP_IPV6 #if LWIP_IPV6
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
ip_addr_set_zero_ip6(&netif->ip6_addr[i]); ip_addr_set_zero_ip6(&netif->ip6_addr[i]);
netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID); netif->ip6_addr_state[i] = IP6_ADDR_INVALID;
} }
netif->output_ip6 = netif_null_output_ip6; netif->output_ip6 = netif_null_output_ip6;
#endif /* LWIP_IPV6 */ #endif /* LWIP_IPV6 */
NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL); NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL);
netif->flags = 0; netif->flags = 0;
#if LWIP_DHCP #ifdef netif_get_client_data
/* netif not under DHCP control by default */ memset(netif->client_data, 0, sizeof(netif->client_data));
netif->dhcp = NULL; #endif /* LWIP_NUM_NETIF_CLIENT_DATA */
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
/* netif not under AutoIP control by default */
netif->autoip = NULL;
#endif /* LWIP_AUTOIP */
#if LWIP_IPV6_AUTOCONFIG #if LWIP_IPV6_AUTOCONFIG
/* IPv6 address autoconfiguration not enabled by default */ /* IPv6 address autoconfiguration not enabled by default */
netif->ip6_autoconfig_enabled = 0; netif->ip6_autoconfig_enabled = 0;
@@ -257,10 +275,6 @@ netif_add(struct netif *netif,
#if LWIP_IPV6_SEND_ROUTER_SOLICIT #if LWIP_IPV6_SEND_ROUTER_SOLICIT
netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT; netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT;
#endif /* LWIP_IPV6_SEND_ROUTER_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 #if LWIP_NETIF_STATUS_CALLBACK
netif->status_callback = NULL; netif->status_callback = NULL;
#endif /* LWIP_NETIF_STATUS_CALLBACK */ #endif /* LWIP_NETIF_STATUS_CALLBACK */
@@ -325,7 +339,7 @@ netif_add(struct netif *netif,
#if LWIP_IPV4 #if LWIP_IPV4
/** /**
* @ingroup netif * @ingroup netif_ip4
* Change IP address configuration for a network interface (including netmask * Change IP address configuration for a network interface (including netmask
* and default gateway). * and default gateway).
* *
@@ -362,6 +376,10 @@ netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *
void void
netif_remove(struct netif *netif) netif_remove(struct netif *netif)
{ {
#if LWIP_IPV6
int i;
#endif
if (netif == NULL) { if (netif == NULL) {
return; return;
} }
@@ -369,9 +387,14 @@ netif_remove(struct netif *netif)
#if LWIP_IPV4 #if LWIP_IPV4
if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) { if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) {
#if LWIP_TCP #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 */ #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 #if LWIP_IGMP
@@ -382,10 +405,25 @@ netif_remove(struct netif *netif)
#endif /* LWIP_IGMP */ #endif /* LWIP_IGMP */
#endif /* LWIP_IPV4*/ #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 */ /* stop MLD processing */
mld6_stop(netif); mld6_stop(netif);
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ #endif /* LWIP_IPV6_MLD */
#endif /* LWIP_IPV6 */
if (netif_is_up(netif)) { if (netif_is_up(netif)) {
/* set netif down before removing (call callback function) */ /* set netif down before removing (call callback function) */
netif_set_down(netif); netif_set_down(netif);
@@ -440,7 +478,7 @@ netif_find(const char *name)
return NULL; return NULL;
} }
num = name[2] - '0'; num = (u8_t)(name[2] - '0');
for (netif = netif_list; netif != NULL; netif = netif->next) { for (netif = netif_list; netif != NULL; netif = netif->next) {
if (num == netif->num && if (num == netif->num &&
@@ -456,7 +494,7 @@ netif_find(const char *name)
#if LWIP_IPV4 #if LWIP_IPV4
/** /**
* @ingroup netif * @ingroup netif_ip4
* Change the IP address of a network interface * Change the IP address of a network interface
* *
* @param netif the network interface to change * @param netif the network interface to change
@@ -468,16 +506,22 @@ netif_find(const char *name)
void void
netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr) 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? */ /* 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")); LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
#if LWIP_TCP #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 */ #endif /* LWIP_TCP */
#if LWIP_UDP #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 */ #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_ip4(netif);
mib2_remove_route_ip4(0, 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 * Change the default gateway for a network interface
* *
* @param netif the network interface to change * @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 * Change the netmask of a network interface
* *
* @param netif the network interface to change * @param netif the network interface to change
@@ -694,15 +738,11 @@ netif_set_link_up(struct netif *netif)
netif->flags |= NETIF_FLAG_LINK_UP; netif->flags |= NETIF_FLAG_LINK_UP;
#if LWIP_DHCP #if LWIP_DHCP
if (netif->dhcp) {
dhcp_network_changed(netif); dhcp_network_changed(netif);
}
#endif /* LWIP_DHCP */ #endif /* LWIP_DHCP */
#if LWIP_AUTOIP #if LWIP_AUTOIP
if (netif->autoip) {
autoip_network_changed(netif); autoip_network_changed(netif);
}
#endif /* LWIP_AUTOIP */ #endif /* LWIP_AUTOIP */
if (netif->flags & NETIF_FLAG_UP) { if (netif->flags & NETIF_FLAG_UP) {
@@ -761,7 +801,7 @@ netif_loop_output(struct netif *netif, struct pbuf *p)
err_t err; err_t err;
struct pbuf *last; struct pbuf *last;
#if LWIP_LOOPBACK_MAX_PBUFS #if LWIP_LOOPBACK_MAX_PBUFS
u8_t clen = 0; u16_t clen = 0;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */ #endif /* LWIP_LOOPBACK_MAX_PBUFS */
/* If we have a loopif, SNMP counters are adjusted for it, /* If we have a loopif, SNMP counters are adjusted for it,
* if not they are adjusted for 'netif'. */ * 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 void
netif_poll(struct netif *netif) netif_poll(struct netif *netif)
{ {
struct pbuf *in;
/* If we have a loopif, SNMP counters are adjusted for it, /* If we have a loopif, SNMP counters are adjusted for it,
* if not they are adjusted for 'netif'. */ * if not they are adjusted for 'netif'. */
#if MIB2_STATS #if MIB2_STATS
@@ -876,15 +915,15 @@ netif_poll(struct netif *netif)
#endif /* MIB2_STATS */ #endif /* MIB2_STATS */
SYS_ARCH_DECL_PROTECT(lev); SYS_ARCH_DECL_PROTECT(lev);
do {
/* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
SYS_ARCH_PROTECT(lev); SYS_ARCH_PROTECT(lev);
in = netif->loop_first; while (netif->loop_first != NULL) {
if (in != NULL) { struct pbuf *in, *in_end;
struct pbuf *in_end = in;
#if LWIP_LOOPBACK_MAX_PBUFS #if LWIP_LOOPBACK_MAX_PBUFS
u8_t clen = 1; u8_t clen = 1;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */ #endif /* LWIP_LOOPBACK_MAX_PBUFS */
in = in_end = netif->loop_first;
while (in_end->len != in_end->tot_len) { while (in_end->len != in_end->tot_len) {
LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
in_end = in_end->next; in_end = in_end->next;
@@ -910,10 +949,8 @@ netif_poll(struct netif *netif)
} }
/* De-queue the pbuf from its successors on the 'loop_' list. */ /* De-queue the pbuf from its successors on the 'loop_' list. */
in_end->next = NULL; in_end->next = NULL;
}
SYS_ARCH_UNPROTECT(lev); SYS_ARCH_UNPROTECT(lev);
if (in != NULL) {
LINK_STATS_INC(link.recv); LINK_STATS_INC(link.recv);
MIB2_STATS_NETIF_ADD(stats_if, ifinoctets, in->tot_len); MIB2_STATS_NETIF_ADD(stats_if, ifinoctets, in->tot_len);
MIB2_STATS_NETIF_INC(stats_if, ifinucastpkts); MIB2_STATS_NETIF_INC(stats_if, ifinucastpkts);
@@ -921,11 +958,9 @@ netif_poll(struct netif *netif)
if (ip_input(in, netif) != ERR_OK) { if (ip_input(in, netif) != ERR_OK) {
pbuf_free(in); pbuf_free(in);
} }
/* Don't reference the packet any more! */ SYS_ARCH_PROTECT(lev);
in = NULL;
} }
/* go on while there is a packet on the list */ SYS_ARCH_UNPROTECT(lev);
} while (netif->loop_first != NULL);
} }
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING #if !LWIP_NETIF_LOOPBACK_MULTITHREADING
@@ -946,7 +981,160 @@ netif_poll_all(void)
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ #endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
#endif /* ENABLE_LOOPBACK */ #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 #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, 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)
{
const ip6_addr_t *old_addr;
LWIP_ASSERT("netif != NULL", netif != NULL);
LWIP_ASSERT("invalid index", addr_idx < LWIP_IPV6_NUM_ADDRESSES);
old_addr = netif_ip6_addr(netif, addr_idx);
/* address is actually being changed? */
if ((old_addr->addr[0] != i0) || (old_addr->addr[1] != 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"));
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);
IP_SET_TYPE_VAL(netif->ip6_addr[addr_idx], IPADDR_TYPE_V6);
if (netif_ip6_addr_state(netif, addr_idx) & IP6_ADDR_VALID) {
netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV6);
NETIF_STATUS_CALLBACK(netif);
}
}
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IPv6 address %d of interface %c%c set to %s/0x%"X8_F"\n",
addr_idx, netif->name[0], netif->name[1], ip6addr_ntoa(netif_ip6_addr(netif, addr_idx)),
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)
{
u8_t old_state;
LWIP_ASSERT("netif != NULL", netif != NULL);
LWIP_ASSERT("invalid index", addr_idx < LWIP_IPV6_NUM_ADDRESSES);
old_state = netif_ip6_addr_state(netif, addr_idx);
/* state is actually being changed? */
if (old_state != state) {
u8_t old_valid = old_state & IP6_ADDR_VALID;
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 */
#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;
if (!old_valid && new_valid) {
/* address added by setting valid */
/* @todo: add mib2 ip6 entries? */
netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV6);
}
if ((old_state & IP6_ADDR_PREFERRED) != (state & IP6_ADDR_PREFERRED)) {
/* address state has changed (valid flag changed or switched between
preferred and deprecated) -> call the callback function */
NETIF_STATUS_CALLBACK(netif);
}
}
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IPv6 address %d of interface %c%c set to %s/0x%"X8_F"\n",
addr_idx, netif->name[0], netif->name[1], ip6addr_ntoa(netif_ip6_addr(netif, addr_idx)),
netif_ip6_addr_state(netif, addr_idx)));
}
/** /**
* Checks if a specific address is assigned to the netif and returns its * Checks if a specific address is assigned to the netif and returns its
* index. * index.
@@ -970,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) * Create a link-local IPv6 address on a netif (stored in slot 0)
* *
* @param netif the netif to create the address on * @param netif the netif to create the address on
@@ -980,7 +1168,6 @@ netif_get_ip6_addr_match(struct netif *netif, const ip6_addr_t *ip6addr)
void void
netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit) netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit)
{ {
LWIP_DEBUGF(1, ("netif_create_ip6_linklocal_address\n"));
u8_t i, addr_index; u8_t i, addr_index;
/* Link-local prefix. */ /* Link-local prefix. */
@@ -990,11 +1177,11 @@ netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit)
/* Generate interface ID. */ /* Generate interface ID. */
if (from_mac_48bit) { if (from_mac_48bit) {
/* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */ /* 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[1]) << 16) |
((u32_t)(netif->hwaddr[2]) << 8) | ((u32_t)(netif->hwaddr[2]) << 8) |
(0xff)); (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[3]) << 16) |
((u32_t)(netif->hwaddr[4]) << 8) | ((u32_t)(netif->hwaddr[4]) << 8) |
(netif->hwaddr[5])); (netif->hwaddr[5]));
@@ -1015,15 +1202,15 @@ netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit)
/* Set address state. */ /* Set address state. */
#if LWIP_IPV6_DUP_DETECT_ATTEMPTS #if LWIP_IPV6_DUP_DETECT_ATTEMPTS
/* Will perform duplicate address detection (DAD). */ /* 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 #else
/* Consider address valid. */ /* 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 */ #endif /* LWIP_IPV6_AUTOCONFIG */
} }
/** /**
* @ingroup netif * @ingroup netif_ip6
* This function allows for the easy addition of a new IPv6 address to an interface. * 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 * It takes care of finding an empty slot and then sets the address tentative
* (to make sure that all the subsequent processing happens). * (to make sure that all the subsequent processing happens).
@@ -1048,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) */ /* Find a free slot -- musn't be the first one (reserved for link local) */
for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { 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); ip_addr_copy_from_ip6(netif->ip6_addr[i], *ip6addr);
netif_ip6_addr_set_state(netif, i, IP6_ADDR_TENTATIVE); netif_ip6_addr_set_state(netif, i, IP6_ADDR_TENTATIVE);
if (chosen_idx != NULL) { if (chosen_idx != NULL) {

169
ext/lwip/src/core/pbuf.c Normal file → Executable file
View File

@@ -32,6 +32,49 @@
* *
* Therefore, looping through a pbuf of a single packet, has an * Therefore, looping through a pbuf of a single packet, has an
* loop end condition (tot_len == p->len), NOT (next == NULL). * 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
*/ */
/* /*
@@ -235,6 +278,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
return NULL; return NULL;
} }
switch (type) { switch (type) {
case PBUF_POOL: case PBUF_POOL:
/* allocate head of pbuf chain into p */ /* allocate head of pbuf chain into p */
@@ -271,18 +315,14 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
rem_len = length - p->len; rem_len = length - p->len;
/* any remaining pbufs to be allocated? */ /* any remaining pbufs to be allocated? */
while (rem_len > 0) { while (rem_len > 0) {
q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
if (q == NULL) { if (q == NULL) {
PBUF_POOL_IS_EMPTY(); PBUF_POOL_IS_EMPTY();
/* free chain so far allocated */ /* free chain so far allocated */
pbuf_free(p); pbuf_free(p);
/* bail out unsuccessfully */ /* bail out unsuccessfully */
return NULL; return NULL;
} }
q->type = type; q->type = type;
q->flags = 0; q->flags = 0;
q->next = NULL; q->next = NULL;
@@ -310,9 +350,18 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
break; break;
case PBUF_RAM: case PBUF_RAM:
{
mem_size_t alloc_len = LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length);
/* bug #50040: Check for integer overflow when calculating alloc_len */
if (alloc_len < LWIP_MEM_ALIGN_SIZE(length)) {
return NULL;
}
/* If pbuf is to be allocated in RAM, allocate memory for it. */ /* If pbuf is to be allocated in RAM, allocate memory for it. */
p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length)); p = (struct pbuf*)mem_malloc(alloc_len);
}
if (p == NULL) { if (p == NULL) {
return NULL; return NULL;
} }
@@ -330,16 +379,13 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
/* pbuf references existing (externally allocated) RAM payload? */ /* pbuf references existing (externally allocated) RAM payload? */
case PBUF_REF: case PBUF_REF:
/* only allocate memory for the pbuf structure */ /* only allocate memory for the pbuf structure */
p = (struct pbuf *)memp_malloc(MEMP_PBUF); p = (struct pbuf *)memp_malloc(MEMP_PBUF);
if (p == NULL) { if (p == NULL) {
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
(type == PBUF_ROM) ? "ROM" : "REF")); (type == PBUF_ROM) ? "ROM" : "REF"));
return NULL; return NULL;
} }
/* caller must set this field properly, afterwards */ /* caller must set this field properly, afterwards */
p->payload = NULL; p->payload = NULL;
p->len = p->tot_len = length; p->len = p->tot_len = length;
@@ -355,7 +401,6 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
/* set flags */ /* set flags */
p->flags = 0; p->flags = 0;
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
return p; return p;
} }
@@ -533,11 +578,11 @@ pbuf_header_impl(struct pbuf *p, s16_t header_size_increment, u8_t force)
} }
if (header_size_increment < 0) { 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 */ /* 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;); LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);
} else { } else {
increment_magnitude = header_size_increment; increment_magnitude = (u16_t)header_size_increment;
#if 0 #if 0
/* Can't assert these as some callers speculatively call /* Can't assert these as some callers speculatively call
pbuf_header() to see if it's OK. Will return 1 below instead. */ pbuf_header() to see if it's OK. Will return 1 below instead. */
@@ -751,10 +796,10 @@ pbuf_free(struct pbuf *p)
* @param p first pbuf of chain * @param p first pbuf of chain
* @return the number of pbufs in a chain * @return the number of pbufs in a chain
*/ */
u8_t u16_t
pbuf_clen(struct pbuf *p) pbuf_clen(const struct pbuf *p)
{ {
u8_t len; u16_t len;
len = 0; len = 0;
while (p != NULL) { while (p != NULL) {
@@ -774,12 +819,10 @@ pbuf_clen(struct pbuf *p)
void void
pbuf_ref(struct pbuf *p) pbuf_ref(struct pbuf *p)
{ {
SYS_ARCH_DECL_PROTECT(old_level);
/* pbuf given? */ /* pbuf given? */
if (p != NULL) { if (p != NULL) {
SYS_ARCH_PROTECT(old_level); SYS_ARCH_INC(p->ref, 1);
++(p->ref); LWIP_ASSERT("pbuf ref overflow", p->ref > 0);
SYS_ARCH_UNPROTECT(old_level);
} }
} }
@@ -902,12 +945,12 @@ pbuf_dechain(struct pbuf *p)
* enough to hold p_from * enough to hold p_from
*/ */
err_t 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; u16_t offset_to=0, offset_from=0, len;
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n", 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? */ /* is the target big enough to hold the source? */
LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) && LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&
@@ -969,9 +1012,9 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
* @return the number of bytes copied, or 0 on failure * @return the number of bytes copied, or 0 on failure
*/ */
u16_t 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 left;
u16_t buf_copy_len; u16_t buf_copy_len;
u16_t copied_total = 0; u16_t copied_total = 0;
@@ -993,8 +1036,9 @@ pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
} else { } else {
/* copy from this buffer. maybe only partially. */ /* copy from this buffer. maybe only partially. */
buf_copy_len = p->len - offset; buf_copy_len = p->len - offset;
if (buf_copy_len > len) if (buf_copy_len > len) {
buf_copy_len = len; buf_copy_len = len;
}
/* copy the necessary parts of the buffer */ /* copy the necessary parts of the buffer */
MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len); MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
copied_total += buf_copy_len; copied_total += buf_copy_len;
@@ -1056,6 +1100,24 @@ void pbuf_split_64k(struct pbuf *p, struct pbuf **rest)
} }
#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ #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 * @ingroup pbuf
* Skip a number of bytes at the start of a pbuf * Skip a number of bytes at the start of a pbuf
@@ -1068,18 +1130,8 @@ void pbuf_split_64k(struct pbuf *p, struct pbuf **rest)
struct pbuf* struct pbuf*
pbuf_skip(struct pbuf* in, u16_t in_offset, u16_t* out_offset) pbuf_skip(struct pbuf* in, u16_t in_offset, u16_t* out_offset)
{ {
u16_t offset_left = in_offset; const struct pbuf* out = pbuf_skip_const(in, in_offset, out_offset);
struct pbuf* q = in; return LWIP_CONST_CAST(struct pbuf*, out);
/* 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;
} }
/** /**
@@ -1187,6 +1239,7 @@ pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
return p; return p;
} }
err = pbuf_copy(q, p); err = pbuf_copy(q, p);
LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
pbuf_free(p); pbuf_free(p);
return q; return q;
@@ -1243,16 +1296,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 * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len
*/ */
u8_t 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; 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 */ /* return requested data if pbuf is OK */
if ((q != NULL) && (q->len > q_idx)) { if ((q != NULL) && (q->len > q_idx)) {
return ((u8_t*)q->payload)[q_idx]; return ((u8_t*)q->payload)[q_idx];
} }
return 0; return -1;
} }
/** /**
@@ -1288,20 +1359,26 @@ pbuf_put_at(struct pbuf* p, u16_t offset, u8_t data)
* (0xffff if p is too short, diffoffset+1 otherwise) * (0xffff if p is too short, diffoffset+1 otherwise)
*/ */
u16_t 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; u16_t start = offset;
struct pbuf* q = p; const struct pbuf* q = p;
u16_t i;
/* get the correct pbuf */ /* 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)) { while ((q != NULL) && (q->len <= start)) {
start -= q->len; start -= q->len;
q = q->next; q = q->next;
} }
/* return requested data if pbuf is OK */ /* return requested data if pbuf is OK */
if ((q != NULL) && (q->len > start)) {
u16_t i;
for (i = 0; i < n; i++) { 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 a = pbuf_get_at(q, start + i);
u8_t b = ((const u8_t*)s2)[i]; u8_t b = ((const u8_t*)s2)[i];
if (a != b) { if (a != b) {
@@ -1310,8 +1387,6 @@ pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)
} }
return 0; return 0;
} }
return 0xffff;
}
/** /**
* @ingroup pbuf * @ingroup pbuf
@@ -1326,7 +1401,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 * @return 0xFFFF if substr was not found in p or the index where it was found
*/ */
u16_t 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 i;
u16_t max = p->tot_len - mem_len; u16_t max = p->tot_len - mem_len;
@@ -1353,7 +1428,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 * @return 0xFFFF if substr was not found in p or the index where it was found
*/ */
u16_t u16_t
pbuf_strstr(struct pbuf* p, const char* substr) pbuf_strstr(const struct pbuf* p, const char* substr)
{ {
size_t substr_len; size_t substr_len;
if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) { if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) {

75
ext/lwip/src/core/raw.c Normal file → Executable file
View File

@@ -4,6 +4,13 @@
* different types of protocols besides (or overriding) those * different types of protocols besides (or overriding) those
* already available in lwIP.\n * already available in lwIP.\n
* See also @ref raw_raw * 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" #include "lwip/opt.h"
#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ #if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
@@ -204,7 +196,7 @@ raw_input(struct pbuf *p, struct netif *inp)
* Bind a RAW PCB. * Bind a RAW PCB.
* *
* @param pcb RAW PCB to be bound with a local address ipaddr. * @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. * bind to all local interfaces.
* *
* @return lwIP error code. * @return lwIP error code.
@@ -217,7 +209,7 @@ raw_input(struct pbuf *p, struct netif *inp)
err_t err_t
raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr) 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)) {
return ERR_VAL; return ERR_VAL;
} }
ip_addr_set_ipaddr(&pcb->local_ip, ipaddr); 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 err_t
raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr) 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)) {
return ERR_VAL; return ERR_VAL;
} }
ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr); 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. * 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 * - not free the packet, and return zero. The packet will be matched
* against further PCBs and/or forwarded to another protocol layers. * 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 void
raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) 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; const ip_addr_t *src_ip;
struct pbuf *q; /* q will be sent down the stack */ struct pbuf *q; /* q will be sent down the stack */
s16_t header_size; s16_t header_size;
const ip_addr_t *dst_ip = ipaddr;
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) { if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
return ERR_VAL; 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) { if (netif == NULL) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to ")); 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() */ /* free any temporary header pbuf allocated by pbuf_header() */
if (q != p) { if (q != p) {
pbuf_free(q); 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)) { if (ip_addr_isany(&pcb->local_ip)) {
/* use outgoing network interface IP address as source address */ /* 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 LWIP_IPV6
if (src_ip == NULL) { if (src_ip == NULL) {
if (q != p) { 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 LWIP_IPV6
/* If requested, based on the IPV6_CHECKSUM socket option per RFC3542, /* If requested, based on the IPV6_CHECKSUM socket option per RFC3542,
compute the checksum and update the checksum in the payload. */ compute the checksum and update the checksum in the payload. */
if (IP_IS_V6(dst_ip) && pcb->chksum_reqd) { 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(dst_ip)); 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)); 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)); SMEMCPY(((u8_t *)p->payload) + pcb->chksum_offset, &chksum, sizeof(u16_t));
} }
#endif #endif
NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); 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); NETIF_SET_HWADDRHINT(netif, NULL);
/* did we chain a header earlier? */ /* 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 * @return The RAW PCB which was created. NULL if the PCB data structure
* could not be allocated. * 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 * @param proto the protocol number (next header) of the IPv6 packet payload
* (e.g. IP6_NEXTH_ICMP6) * (e.g. IP6_NEXTH_ICMP6)
* *
@@ -501,4 +497,25 @@ raw_new_ip_type(u8_t type, u8_t proto)
return pcb; 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 */ #endif /* LWIP_RAW */

4
ext/lwip/src/core/stats.c Normal file → Executable file
View File

@@ -96,7 +96,7 @@ stats_display_igmp(struct stats_igmp *igmp, const char *name)
LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report)); LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report));
LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join)); LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join));
LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave)); LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave));
LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n\t", igmp->tx_report)); LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n", igmp->tx_report));
} }
#endif /* IGMP_STATS || MLD6_STATS */ #endif /* IGMP_STATS || MLD6_STATS */
@@ -135,7 +135,7 @@ stats_display_sys(struct stats_sys *sys)
LWIP_PLATFORM_DIAG(("mutex.err: %"U32_F"\n\t", (u32_t)sys->mutex.err)); LWIP_PLATFORM_DIAG(("mutex.err: %"U32_F"\n\t", (u32_t)sys->mutex.err));
LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used)); LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used));
LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max)); LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max));
LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err)); LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n", (u32_t)sys->mbox.err));
} }
#endif /* SYS_STATS */ #endif /* SYS_STATS */

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