Merge branch 'master' into STABLE-2_0_0

# Conflicts:
#	src/include/lwip/init.h
This commit is contained in:
Dirk Ziegelmeier 2017-01-05 15:01:08 +01:00
commit 1a2a9a4e96
109 changed files with 4182 additions and 955 deletions

5
.gitignore vendored
View File

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

View File

@ -6,6 +6,74 @@ HISTORY
++ 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-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:
2016-07-27: Simon Goldschmidt
* opt.h, timeouts.h/.c: added LWIP_TIMERS_CUSTOM to override the default
implementation of timeouts

View File

@ -8,7 +8,12 @@ with newer versions.
* [Enter new changes just after this line - do not remove this line]
* TODO
++ 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)

View File

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

View File

@ -32,19 +32,19 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.
PROJECT_NAME = "lwIP 2.0.0"
PROJECT_NAME = "lwIP"
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = "lwIP 2.0.0"
PROJECT_NUMBER = "2.0.1"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = Lightweight IP stack
PROJECT_BRIEF = "Lightweight IP stack"
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55

View File

@ -103,7 +103,8 @@
* *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
* 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

162
doc/mqtt_client.txt Normal 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)

View File

@ -29,7 +29,7 @@ in a mailbox is just a pointer, nothing more.
Semaphores are represented by the type "sys_sem_t" which is typedef'd
in the sys_arch.h file. Mailboxes are equivalently represented by the
type "sys_mbox_t". Mutexes are represented ny the type "sys_mutex_t".
type "sys_mbox_t". Mutexes are represented by the type "sys_mutex_t".
lwIP does not place any restrictions on how these types are represented
internally.

View File

@ -167,6 +167,9 @@ NETBIOSNSFILES=$(LWIPDIR)/apps/netbiosns/netbiosns.c
# TFTPFILES: TFTP server files
TFTPFILES=$(LWIPDIR)/apps/tftp/tftp_server.c
# MQTTFILES: MQTT client files
MQTTFILES=$(LWIPDIR)/apps/mqtt/mqtt.c
# LWIPAPPFILES: All LWIP APPs
LWIPAPPFILES=$(SNMPFILES) \
$(HTTPDFILES) \
@ -174,4 +177,5 @@ LWIPAPPFILES=$(SNMPFILES) \
$(SNTPFILES) \
$(MDNSFILES) \
$(NETBIOSNSFILES) \
$(TFTPFILES)
$(TFTPFILES) \
$(MQTTFILES)

View File

@ -254,10 +254,22 @@ netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port)
LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
#if LWIP_IPV4
/* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
if (addr == NULL) {
addr = IP4_ADDR_ANY;
}
#endif /* LWIP_IPV4 */
#if LWIP_IPV4 && LWIP_IPV6
/* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY,
* and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind
*/
if ((netconn_get_ipv6only(conn) == 0) &&
ip_addr_cmp(addr, IP6_ADDR_ANY)) {
addr = IP_ANY_TYPE;
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
API_MSG_VAR_ALLOC(msg);
API_MSG_VAR_REF(msg).conn = conn;
@ -286,10 +298,12 @@ netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port)
LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
#if LWIP_IPV4
/* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
if (addr == NULL) {
addr = IP4_ADDR_ANY;
}
#endif /* LWIP_IPV4 */
API_MSG_VAR_ALLOC(msg);
API_MSG_VAR_REF(msg).conn = conn;
@ -376,7 +390,6 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn)
#if LWIP_TCP
void *accept_ptr;
struct netconn *newconn;
err_t err;
#if TCP_LISTEN_BACKLOG
API_MSG_VAR_DECLARE(msg);
#endif /* TCP_LISTEN_BACKLOG */
@ -385,11 +398,10 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn)
*new_conn = NULL;
LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
err = conn->last_err;
if (ERR_IS_FATAL(err)) {
if (ERR_IS_FATAL(conn->last_err)) {
/* don't recv on fatal errors: this might block the application task
waiting on acceptmbox forever! */
return err;
return conn->last_err;
}
if (!sys_mbox_valid(&conn->acceptmbox)) {
return ERR_CLSD;
@ -465,7 +477,6 @@ netconn_recv_data(struct netconn *conn, void **new_buf)
{
void *buf = NULL;
u16_t len;
err_t err;
#if LWIP_TCP
API_MSG_VAR_DECLARE(msg);
#if LWIP_MPU_COMPATIBLE
@ -489,13 +500,12 @@ netconn_recv_data(struct netconn *conn, void **new_buf)
#endif /* LWIP_TCP */
LWIP_ERROR("netconn_recv: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
err = conn->last_err;
if (ERR_IS_FATAL(err)) {
if (ERR_IS_FATAL(conn->last_err)) {
/* don't recv on fatal errors: this might block the application task
waiting on recvmbox forever! */
/* @todo: this does not allow us to fetch data that has been put into recvmbox
before the fatal error occurred - is that a problem? */
return err;
return conn->last_err;
}
#if LWIP_TCP
#if (LWIP_UDP || LWIP_RAW)
@ -697,6 +707,7 @@ netconn_send(struct netconn *conn, struct netbuf *buf)
LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
API_MSG_VAR_ALLOC(msg);
API_MSG_VAR_REF(msg).conn = conn;
API_MSG_VAR_REF(msg).msg.b = buf;
@ -734,6 +745,11 @@ netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
return ERR_OK;
}
dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
#if LWIP_SO_SNDTIMEO
if (conn->send_timeout != 0) {
dontblock = 1;
}
#endif /* LWIP_SO_SNDTIMEO */
if (dontblock && !bytes_written) {
/* This implies netconn_write() cannot be used for non-blocking send, since
it has no way to return the number of bytes written. */
@ -761,11 +777,7 @@ netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
non-blocking version here. */
err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg));
if ((err == ERR_OK) && (bytes_written != NULL)) {
if (dontblock
#if LWIP_SO_SNDTIMEO
|| (conn->send_timeout != 0)
#endif /* LWIP_SO_SNDTIMEO */
) {
if (dontblock) {
/* nonblocking write: maybe the data has been sent partly */
*bytes_written = API_MSG_VAR_REF(msg).msg.w.len;
} else {
@ -869,6 +881,7 @@ netconn_join_leave_group(struct netconn *conn,
API_MSG_VAR_ALLOC(msg);
#if LWIP_IPV4
/* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
if (multiaddr == NULL) {
multiaddr = IP4_ADDR_ANY;
@ -876,6 +889,7 @@ netconn_join_leave_group(struct netconn *conn,
if (netif_addr == NULL) {
netif_addr = IP4_ADDR_ANY;
}
#endif /* LWIP_IPV4 */
API_MSG_VAR_REF(msg).conn = conn;
API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
@ -914,6 +928,7 @@ netconn_gethostbyname(const char *name, ip_addr_t *addr)
sys_sem_t sem;
#endif /* LWIP_MPU_COMPATIBLE */
err_t err;
err_t cberr;
LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
@ -946,13 +961,13 @@ netconn_gethostbyname(const char *name, ip_addr_t *addr)
}
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
err = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg));
if (err != ERR_OK) {
cberr = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg));
if (cberr != ERR_OK) {
#if !LWIP_NETCONN_SEM_PER_THREAD
sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
#endif /* !LWIP_NETCONN_SEM_PER_THREAD */
API_VAR_FREE(MEMP_DNS_API_MSG, msg);
return err;
return cberr;
}
sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem));
#if !LWIP_NETCONN_SEM_PER_THREAD

View File

@ -43,6 +43,7 @@
#include "lwip/priv/api_msg.h"
#include "lwip/ip.h"
#include "lwip/ip_addr.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/raw.h"
@ -544,13 +545,22 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
static void
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);
#if LWIP_IPV6 && LWIP_IPV4
/* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */
if(NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) {
iptype = IPADDR_TYPE_ANY;
}
#endif
/* Allocate a PCB for this connection */
switch(NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
case NETCONN_RAW:
msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto);
if (msg->conn->pcb.raw != NULL) {
raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
}
@ -558,7 +568,7 @@ pcb_new(struct api_msg *msg)
#endif /* LWIP_RAW */
#if LWIP_UDP
case NETCONN_UDP:
msg->conn->pcb.udp = udp_new();
msg->conn->pcb.udp = udp_new_ip_type(iptype);
if (msg->conn->pcb.udp != NULL) {
#if LWIP_UDPLITE
if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
@ -574,7 +584,7 @@ pcb_new(struct api_msg *msg)
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
msg->conn->pcb.tcp = tcp_new();
msg->conn->pcb.tcp = tcp_new_ip_type(iptype);
if (msg->conn->pcb.tcp != NULL) {
setup_tcp(msg->conn);
}
@ -588,15 +598,6 @@ pcb_new(struct api_msg *msg)
if (msg->conn->pcb.ip == NULL) {
msg->err = ERR_MEM;
}
#if LWIP_IPV4 && LWIP_IPV6
else {
if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
/* Convert IPv4 PCB manually to an IPv6 PCB */
IP_SET_TYPE_VAL(msg->conn->pcb.ip->local_ip, IPADDR_TYPE_V6);
IP_SET_TYPE_VAL(msg->conn->pcb.ip->remote_ip, IPADDR_TYPE_V6);
}
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
}
/**
@ -1113,37 +1114,20 @@ lwip_netconn_do_bind(void *m)
} else {
msg->err = ERR_VAL;
if (msg->conn->pcb.tcp != NULL) {
const ip_addr_t *ipaddr = API_EXPR_REF(msg->msg.bc.ipaddr);
#if LWIP_IPV4 && LWIP_IPV6
/* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY,
* and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to bind
*/
if (ip_addr_cmp(ipaddr, IP6_ADDR_ANY) &&
(netconn_get_ipv6only(msg->conn) == 0)) {
/* change PCB type to IPADDR_TYPE_ANY */
IP_SET_TYPE_VAL(msg->conn->pcb.ip->local_ip, IPADDR_TYPE_ANY);
IP_SET_TYPE_VAL(msg->conn->pcb.ip->remote_ip, IPADDR_TYPE_ANY);
/* bind to IPADDR_TYPE_ANY */
ipaddr = IP_ANY_TYPE;
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
case NETCONN_RAW:
msg->err = raw_bind(msg->conn->pcb.raw, ipaddr);
msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
break;
#endif /* LWIP_RAW */
#if LWIP_UDP
case NETCONN_UDP:
msg->err = udp_bind(msg->conn->pcb.udp, ipaddr, msg->msg.bc.port);
msg->err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
msg->err = tcp_bind(msg->conn->pcb.tcp, ipaddr, msg->msg.bc.port);
msg->err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
break;
#endif /* LWIP_TCP */
default:
@ -1323,6 +1307,13 @@ lwip_netconn_do_listen(void *m)
/* connection is not closed, cannot listen */
msg->err = ERR_VAL;
} else {
err_t err;
u8_t backlog;
#if TCP_LISTEN_BACKLOG
backlog = msg->msg.lb.backlog;
#else /* TCP_LISTEN_BACKLOG */
backlog = TCP_DEFAULT_LISTEN_BACKLOG;
#endif /* TCP_LISTEN_BACKLOG */
#if LWIP_IPV4 && LWIP_IPV6
/* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
* and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
@ -1335,15 +1326,11 @@ lwip_netconn_do_listen(void *m)
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
#if TCP_LISTEN_BACKLOG
lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
#else /* TCP_LISTEN_BACKLOG */
lpcb = tcp_listen(msg->conn->pcb.tcp);
#endif /* TCP_LISTEN_BACKLOG */
lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
if (lpcb == NULL) {
/* in this case, the old pcb is still allocated */
msg->err = ERR_MEM;
msg->err = err;
} else {
/* delete the recvmbox and allocate the acceptmbox */
if (sys_mbox_valid(&msg->conn->recvmbox)) {
@ -1400,7 +1387,7 @@ lwip_netconn_do_send(void *m)
switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
case NETCONN_RAW:
if (ip_addr_isany(&msg->msg.b->addr)) {
if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
} else {
msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
@ -1588,10 +1575,11 @@ err_mem:
write_finished = 1;
conn->current_msg->msg.w.len = 0;
}
} else if ((err == ERR_MEM) && !dontblock) {
/* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
we do NOT return to the application thread, since ERR_MEM is
only a temporary error! */
} else if (err == ERR_MEM) {
/* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called.
For blocking sockets, we do NOT return to the application
thread, since ERR_MEM is only a temporary error! Non-blocking
will remain non-writable until sent_tcp/poll_tcp is called */
/* tcp_write returned ERR_MEM, try tcp_output anyway */
err_t out_err = tcp_output(conn->pcb.tcp);
@ -1602,6 +1590,11 @@ err_mem:
err = out_err;
write_finished = 1;
conn->current_msg->msg.w.len = 0;
} else if (dontblock) {
/* non-blocking write is done on ERR_MEM */
err = ERR_WOULDBLOCK;
write_finished = 1;
conn->current_msg->msg.w.len = 0;
}
} else {
/* On errors != ERR_MEM, we don't try writing any more but return
@ -1710,6 +1703,7 @@ lwip_netconn_do_getaddr(void *m)
ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
msg->conn->pcb.ip->remote_ip);
}
msg->err = ERR_OK;
switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW

View File

@ -64,6 +64,15 @@ static const int err_to_errno_table[] = {
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
@ -104,14 +113,3 @@ lwip_strerr(err_t err)
}
#endif /* LWIP_DEBUG */
#if !NO_SYS
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 */

View File

@ -46,8 +46,8 @@
#include "lwip/api.h"
#include "lwip/dns.h"
#include <string.h>
#include <stdlib.h>
#include <string.h> /* memset */
#include <stdlib.h> /* atoi */
/** helper struct for gethostbyname_r to access the char* buffer */
struct gethostbyname_r_helper {
@ -382,7 +382,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
#if LWIP_IPV4
struct sockaddr_in *sa4 = (struct sockaddr_in*)sa;
/* set up sockaddr */
inet_addr_from_ipaddr(&sa4->sin_addr, ip_2_ip4(&addr));
inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr));
sa4->sin_family = AF_INET;
sa4->sin_len = sizeof(struct sockaddr_in);
sa4->sin_port = lwip_htons((u16_t)port_nr);

View File

@ -82,10 +82,10 @@
(sin)->sin_len = sizeof(struct sockaddr_in); \
(sin)->sin_family = AF_INET; \
(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)
#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) = lwip_ntohs((sin)->sin_port); }while(0)
#endif /* LWIP_IPV4 */
@ -482,7 +482,7 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
sock_set_errno(sock, EWOULDBLOCK);
set_errno(EWOULDBLOCK);
return -1;
}
@ -584,6 +584,14 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port));
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Unmap IPv6 mapped IPv4 addresses */
if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&local_addr))) {
unmap_ipv6_mapped_ipv4(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr));
IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4);
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
err = netconn_bind(sock->conn, &local_addr, local_port);
if (err != ERR_OK) {
@ -668,6 +676,14 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port));
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Unmap IPv6 mapped IPv4 addresses */
if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&remote_addr))) {
unmap_ipv6_mapped_ipv4(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr));
IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4);
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
err = netconn_connect(sock->conn, &remote_addr, remote_port);
}
@ -755,7 +771,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
return off;
}
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
sock_set_errno(sock, EWOULDBLOCK);
set_errno(EWOULDBLOCK);
return -1;
}
@ -847,6 +863,15 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
port = netbuf_fromport((struct netbuf *)buf);
fromaddr = netbuf_fromaddr((struct netbuf *)buf);
}
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Map IPv4 addresses to IPv6 mapped IPv4 */
if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) && IP_IS_V4(fromaddr)) {
ip4_2_ipv6_mapped_ipv4(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr));
IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6);
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port);
ip_addr_debug_print(SOCKETS_DEBUG, fromaddr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
@ -1066,6 +1091,14 @@ lwip_sendmsg(int s, const struct msghdr *msg, int flags)
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
if (err == ERR_OK) {
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Unmap IPv6 mapped IPv4 addresses */
if (IP_IS_V6_VAL(chain_buf->addr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&chain_buf->addr))) {
unmap_ipv6_mapped_ipv4(ip_2_ip4(&chain_buf->addr), ip_2_ip6(&chain_buf->addr));
IP_SET_TYPE_VAL(chain_buf->addr, IPADDR_TYPE_V4);
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
/* send the data */
err = netconn_send(sock->conn, chain_buf);
}
@ -1107,12 +1140,6 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
#endif /* LWIP_TCP */
}
if ((to != NULL) && !SOCK_ADDR_TYPE_MATCH(to, sock)) {
/* sockaddr does not match socket type (IPv4/IPv6) */
sock_set_errno(sock, err_to_errno(ERR_VAL));
return -1;
}
/* @todo: split into multiple sendto's? */
LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
short_size = (u16_t)size;
@ -1162,6 +1189,14 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
err = netbuf_ref(&buf, data, short_size);
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
if (err == ERR_OK) {
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Unmap IPv6 mapped IPv4 addresses */
if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&buf.addr))) {
unmap_ipv6_mapped_ipv4(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr));
IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4);
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
/* send the data */
err = netconn_send(sock->conn, &buf);
}
@ -1179,9 +1214,7 @@ lwip_socket(int domain, int type, int protocol)
struct netconn *conn;
int i;
#if !LWIP_IPV6
LWIP_UNUSED_ARG(domain); /* @todo: check this */
#endif /* LWIP_IPV6 */
/* create a netconn */
switch (type) {
@ -1244,7 +1277,7 @@ lwip_writev(int s, const struct iovec *iov, int iovcnt)
msg.msg_namelen = 0;
/* Hack: we have to cast via number to cast from 'const' pointer to non-const.
Blame the opengroup standard for this inconsistency. */
msg.msg_iov = (struct iovec *)(size_t)iov;
msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov);
msg.msg_iovlen = iovcnt;
msg.msg_control = NULL;
msg.msg_controllen = 0;
@ -1710,12 +1743,21 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
}
/* get the IP address and port */
/* @todo: this does not work for IPv6, yet */
err = netconn_getaddr(sock->conn, &naddr, &port, local);
if (err != ERR_OK) {
sock_set_errno(sock, err_to_errno(err));
return -1;
}
#if LWIP_IPV4 && LWIP_IPV6
/* Dual-stack: Map IPv4 addresses to IPv6 mapped IPv4 */
if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) &&
IP_IS_V4_VAL(naddr)) {
ip4_2_ipv6_mapped_ipv4(ip_2_ip6(&naddr), ip_2_ip4(&naddr));
IP_SET_TYPE_VAL(naddr, IPADDR_TYPE_V6);
}
#endif /* LWIP_IPV4 && LWIP_IPV6 */
IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
@ -2001,7 +2043,7 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
return ENOPROTOOPT;
}
inet_addr_from_ipaddr((struct in_addr*)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp));
inet_addr_from_ip4addr((struct in_addr*)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp));
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
s, *(u32_t *)optval));
break;
@ -2029,6 +2071,9 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt
case IPPROTO_TCP:
/* Special case: all IPPROTO_TCP option take an int */
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP);
if (sock->conn->pcb.tcp->state == LISTEN) {
return EINVAL;
}
switch (optname) {
case TCP_NODELAY:
*(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
@ -2073,10 +2118,6 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt
switch (optname) {
case IPV6_V6ONLY:
LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
/* @todo: this does not work for datagram sockets, yet */
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
return ENOPROTOOPT;
}
*(int*)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n",
s, *(int *)optval));
@ -2365,7 +2406,7 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
{
ip4_addr_t if_addr;
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP);
inet_addr_to_ipaddr(&if_addr, (const struct in_addr*)optval);
inet_addr_to_ip4addr(&if_addr, (const struct in_addr*)optval);
udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr);
}
break;
@ -2389,8 +2430,8 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
ip4_addr_t if_addr;
ip4_addr_t multi_addr;
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP);
inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
inet_addr_to_ip4addr(&if_addr, &imr->imr_interface);
inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr);
if (optname == IP_ADD_MEMBERSHIP) {
if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) {
/* cannot track membership (out of memory) */
@ -2422,6 +2463,9 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
case IPPROTO_TCP:
/* Special case: all IPPROTO_TCP option take an int */
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
if (sock->conn->pcb.tcp->state == LISTEN) {
return EINVAL;
}
switch (optname) {
case TCP_NODELAY:
if (*(const int*)optval) {
@ -2469,7 +2513,6 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
case IPPROTO_IPV6:
switch (optname) {
case IPV6_V6ONLY:
/* @todo: this does not work for datagram sockets, yet */
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
if (*(const int*)optval) {
netconn_set_ipv6only(sock->conn, 1);
@ -2770,7 +2813,7 @@ lwip_socket_drop_registered_memberships(int s)
ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
netconn_join_leave_group(sockets[s].conn, &multi_addr, &if_addr, NETCONN_LEAVE);
netconn_join_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE);
}
}
}

View File

@ -98,8 +98,8 @@
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include <string.h>
#include <stdlib.h>
#include <string.h> /* memset */
#include <stdlib.h> /* atoi */
#include <stdio.h>
#if LWIP_TCP
@ -2563,6 +2563,7 @@ httpd_init(void)
tcp_setprio(pcb, HTTPD_TCP_PRIO);
/* set SOF_REUSEADDR here to explicitly bind httpd to multiple interfaces */
err = tcp_bind(pcb, IP_ANY_TYPE, HTTPD_SERVER_PORT);
LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("httpd_init: tcp_bind failed", err == ERR_OK);
pcb = tcp_listen(pcb);
LWIP_ASSERT("httpd_init: tcp_listen failed", pcb != NULL);

View File

@ -294,7 +294,7 @@ lwiperf_tcp_client_send_more(lwiperf_state_tcp_t* conn)
} else {
/* transmit data */
/* @todo: every x bytes, transmit the settings again */
txptr = (void*)(size_t)&lwiperf_txbuf_const[conn->bytes_transferred % 10];
txptr = LWIP_CONST_CAST(void*, &lwiperf_txbuf_const[conn->bytes_transferred % 10]);
txlen_max = TCP_MSS;
if (conn->bytes_transferred == 48) { /* @todo: fix this for intermediate settings, too */
txlen_max = TCP_MSS - 24;
@ -494,10 +494,8 @@ lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
return ERR_VAL;
}
}
packet_idx += i;
#else
packet_idx += q->len;
#endif
packet_idx += q->len;
}
LWIP_ASSERT("count mismatch", packet_idx == p->tot_len);
conn->bytes_transferred += packet_idx;
@ -579,7 +577,7 @@ lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
void*
lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void* report_arg)
{
return lwiperf_start_tcp_server(IP4_ADDR_ANY, LWIPERF_TCP_PORT_DEFAULT,
return lwiperf_start_tcp_server(IP_ADDR_ANY, LWIPERF_TCP_PORT_DEFAULT,
report_fn, report_arg);
}

View File

@ -52,10 +52,7 @@
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Erik Ekman <erik.ekman@verisure.com>
*
* Please coordinate changes and requests with Erik Ekman
* <erik.ekman@verisure.com>
* Author: Erik Ekman <erik@kryo.se>
*
*/
@ -68,7 +65,6 @@
#include "lwip/prot/dns.h"
#include <string.h>
#include <stdlib.h>
#if LWIP_MDNS_RESPONDER
@ -85,13 +81,13 @@
#if LWIP_IPV4
#include "lwip/igmp.h"
/* IPv4 multicast group 224.0.0.251 */
static const ip_addr_t v4group = IPADDR4_INIT(PP_HTONL(0xE00000FBUL));
static const ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT;
#endif
#if LWIP_IPV6
#include "lwip/mld6.h"
/* IPv6 multicast group FF02::FB */
static const ip_addr_t v6group = IPADDR6_INIT(PP_HTONL(0xFF020000UL), PP_HTONL(0x00000000UL), PP_HTONL(0x00000000UL), PP_HTONL(0x000000FBUL));
static const ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT;
#endif
#define MDNS_PORT 5353
@ -573,7 +569,7 @@ mdns_build_dnssd_domain(struct mdns_domain *domain)
LWIP_ERROR("mdns_build_dnssd_domain: Failed to add label", (res == ERR_OK), return res);
res = mdns_domain_add_label(domain, "_dns-sd", (u8_t)(sizeof("_dns-sd")-1));
LWIP_ERROR("mdns_build_dnssd_domain: Failed to add label", (res == ERR_OK), return res);
res = mdns_domain_add_label(domain, dnssd_protos[DNSSD_PROTO_UDP], (u8_t)(sizeof(dnssd_protos[DNSSD_PROTO_UDP])-1));
res = mdns_domain_add_label(domain, dnssd_protos[DNSSD_PROTO_UDP], (u8_t)strlen(dnssd_protos[DNSSD_PROTO_UDP]));
LWIP_ERROR("mdns_build_dnssd_domain: Failed to add label", (res == ERR_OK), return res);
return mdns_add_dotlocal(domain);
}
@ -598,7 +594,7 @@ mdns_build_service_domain(struct mdns_domain *domain, struct mdns_service *servi
}
res = mdns_domain_add_label(domain, service->service, (u8_t)strlen(service->service));
LWIP_ERROR("mdns_build_service_domain: Failed to add label", (res == ERR_OK), return res);
res = mdns_domain_add_label(domain, dnssd_protos[service->proto], (u8_t)(sizeof(dnssd_protos[DNSSD_PROTO_UDP])-1));
res = mdns_domain_add_label(domain, dnssd_protos[service->proto], (u8_t)strlen(dnssd_protos[service->proto]));
LWIP_ERROR("mdns_build_service_domain: Failed to add label", (res == ERR_OK), return res);
return mdns_add_dotlocal(domain);
}
@ -1824,6 +1820,7 @@ mdns_resp_init(void)
mdns_pcb->ttl = MDNS_TTL;
#endif
res = udp_bind(mdns_pcb, IP_ANY_TYPE, MDNS_PORT);
LWIP_UNUSED_ARG(res); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("Failed to bind pcb", res == ERR_OK);
udp_recv(mdns_pcb, mdns_recv, NULL);
@ -2022,7 +2019,7 @@ mdns_resp_add_service(struct netif *netif, const char *name, const char *service
err_t
mdns_resp_add_service_txtitem(struct mdns_service *service, const char *txt, u8_t txt_len)
{
LWIP_ASSERT("mdns_resp_add_service: service != NULL", service);
LWIP_ASSERT("mdns_resp_add_service_txtitem: service != NULL", service);
/* Use a mdns_domain struct to store txt chunks since it is the same encoding */
return mdns_domain_add_label(&service->txtdata, txt, txt_len);

1335
src/apps/mqtt/mqtt.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -581,7 +581,7 @@ ip_NetToMediaTable_get_next_cell_instance_and_value(const u32_t* column, struct
snmp_ip4_to_oid(ip, &test_oid[1]);
/* check generated OID: is it a candidate for the next one? */
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges), (void*)(size_t)i);
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges), LWIP_PTR_NUMERIC_CAST(void*, i));
}
}
@ -589,7 +589,7 @@ ip_NetToMediaTable_get_next_cell_instance_and_value(const u32_t* column, struct
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
/* fill in object properties */
return ip_NetToMediaTable_get_cell_value_core((u8_t)(size_t)state.reference, column, value, value_len);
return ip_NetToMediaTable_get_cell_value_core(LWIP_PTR_NUMERIC_CAST(u8_t, state.reference), column, value, value_len);
}
/* not found */

View File

@ -36,6 +36,7 @@
#if LWIP_SNMP && SNMP_USE_NETCONN
#include <string.h>
#include "lwip/api.h"
#include "lwip/ip.h"
#include "lwip/udp.h"

View File

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

View File

@ -573,6 +573,7 @@ sntp_stop(void)
{
if (sntp_pcb != NULL) {
sys_untimeout(sntp_request, NULL);
sys_untimeout(sntp_try_next_server, NULL);
udp_remove(sntp_pcb);
sntp_pcb = NULL;
}
@ -688,7 +689,7 @@ sntp_getserver(u8_t idx)
if (idx < SNTP_MAX_SERVERS) {
return &sntp_servers[idx].addr;
}
return IP4_ADDR_ANY;
return IP_ADDR_ANY;
}
#if SNTP_SERVER_DNS

View File

@ -20,6 +20,10 @@
* @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.
*/
/*
@ -101,13 +105,13 @@ char*
lwip_strnstr(const char* buffer, const char* token, size_t n)
{
const char* p;
int tokenlen = (int)strlen(token);
size_t tokenlen = strlen(token);
if (tokenlen == 0) {
return (char *)(size_t)buffer;
return LWIP_CONST_CAST(char *, buffer);
}
for (p = buffer; *p && (p + tokenlen <= buffer + n); p++) {
if ((*p == *token) && (strncmp(p, token, tokenlen) == 0)) {
return (char *)(size_t)p;
return LWIP_CONST_CAST(char *, p);
}
}
return NULL;

View File

@ -24,6 +24,11 @@
* 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.
@ -71,6 +76,7 @@
/** @todo: define good default values (rfc compliance) */
/** @todo: improve answer parsing, more checkings... */
/** @todo: check RFC1035 - 7.3. Processing responses */
/** @todo: one-shot mDNS: dual-stack fallback to another IP version */
/*-----------------------------------------------------------------------------
* Includes
@ -116,6 +122,13 @@ static u16_t dns_txid;
#error DNS_MAX_TTL must be a positive 32-bit value
#endif
#if DNS_TABLE_SIZE > 255
#error DNS_TABLE_SIZE must fit into an u8_t
#endif
#if DNS_MAX_SERVERS > 255
#error DNS_MAX_SERVERS must fit into an u8_t
#endif
/* The number of parallel requests (i.e. calls to dns_gethostbyname
* that cannot be answered from the DNS table.
* This is set to the table size by default.
@ -123,6 +136,10 @@ static u16_t dns_txid;
#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
#ifndef DNS_MAX_REQUESTS
#define DNS_MAX_REQUESTS DNS_TABLE_SIZE
#else
#if DNS_MAX_REQUESTS > 255
#error DNS_MAX_REQUESTS must fit into an u8_t
#endif
#endif
#else
/* In this configuration, both arrays have to have the same size and are used
@ -134,6 +151,10 @@ static u16_t dns_txid;
#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
#ifndef DNS_MAX_SOURCE_PORTS
#define DNS_MAX_SOURCE_PORTS DNS_MAX_REQUESTS
#else
#if DNS_MAX_SOURCE_PORTS > 255
#error DNS_MAX_SOURCE_PORTS must fit into an u8_t
#endif
#endif
#else
#ifdef DNS_MAX_SOURCE_PORTS
@ -160,6 +181,12 @@ static u16_t dns_txid;
#define LWIP_DNS_SET_ADDRTYPE(x, y)
#endif /* LWIP_IPV4 && LWIP_IPV6 */
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
#define LWIP_DNS_ISMDNS_ARG(x) , x
#else
#define LWIP_DNS_ISMDNS_ARG(x)
#endif
/** DNS query message structure.
No packing needed: only used locally on the stack. */
struct dns_query {
@ -209,6 +236,9 @@ struct dns_table_entry {
#if LWIP_IPV4 && LWIP_IPV6
u8_t reqaddrtype;
#endif /* LWIP_IPV4 && LWIP_IPV6 */
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
u8_t is_mdns;
#endif
};
/** DNS request table entry: used when dns_gehostbyname cannot answer the
@ -272,6 +302,13 @@ static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS];
static ip_addr_t dns_servers[DNS_MAX_SERVERS];
#if LWIP_IPV4
const ip_addr_t dns_mquery_v4group = DNS_MQUERY_IPV4_GROUP_INIT;
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
const ip_addr_t dns_mquery_v6group = DNS_MQUERY_IPV6_GROUP_INIT;
#endif /* LWIP_IPV6 */
/**
* Initialize the resolver: set up the UDP pcb and configure the default server
* (if DNS_SERVER_ADDRESS is set).
@ -329,7 +366,7 @@ dns_setserver(u8_t numdns, const ip_addr_t *dnsserver)
if (dnsserver != NULL) {
dns_servers[numdns] = (*dnsserver);
} else {
dns_servers[numdns] = *IP4_ADDR_ANY;
dns_servers[numdns] = *IP_ADDR_ANY;
}
}
}
@ -348,7 +385,7 @@ dns_getserver(u8_t numdns)
if (numdns < DNS_MAX_SERVERS) {
return &dns_servers[numdns];
} else {
return IP4_ADDR_ANY;
return IP_ADDR_ANY;
}
}
@ -665,7 +702,11 @@ dns_send(u8_t idx)
LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
(u16_t)(entry->server_idx), entry->name));
LWIP_ASSERT("dns server out of array", entry->server_idx < DNS_MAX_SERVERS);
if (ip_addr_isany_val(dns_servers[entry->server_idx])) {
if (ip_addr_isany_val(dns_servers[entry->server_idx])
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
&& !entry->is_mdns
#endif
) {
/* DNS server not valid anymore, e.g. PPP netif has been shut down */
/* call specified callback function if provided */
dns_call_found(idx, NULL);
@ -678,6 +719,8 @@ dns_send(u8_t idx)
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 +
SIZEOF_DNS_QUERY), PBUF_RAM);
if (p != NULL) {
const ip_addr_t* dst;
u16_t dst_port;
/* fill dns header */
memset(&hdr, 0, SIZEOF_DNS_HDR);
hdr.id = lwip_htons(entry->txid);
@ -720,7 +763,30 @@ dns_send(u8_t idx)
/* send dns packet */
LWIP_DEBUGF(DNS_DEBUG, ("sending DNS request ID %d for name \"%s\" to server %d\r\n",
entry->txid, entry->name, entry->server_idx));
err = udp_sendto(dns_pcbs[pcb_idx], p, &dns_servers[entry->server_idx], DNS_SERVER_PORT);
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
if (entry->is_mdns) {
dst_port = DNS_MQUERY_PORT;
#if LWIP_IPV6
if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype))
{
dst = &dns_mquery_v6group;
}
#endif
#if LWIP_IPV4 && LWIP_IPV6
else
#endif
#if LWIP_IPV4
{
dst = &dns_mquery_v4group;
}
#endif
} else
#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
{
dst_port = DNS_SERVER_PORT;
dst = &dns_servers[entry->server_idx];
}
err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port);
/* free pbuf */
pbuf_free(p);
@ -923,7 +989,11 @@ dns_check_entry(u8_t i)
case DNS_STATE_ASKING:
if (--entry->tmr == 0) {
if (++entry->retries == DNS_MAX_RETRIES) {
if ((entry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[entry->server_idx + 1])) {
if ((entry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[entry->server_idx + 1])
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
&& !entry->is_mdns
#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
) {
/* change of server */
entry->server_idx++;
entry->tmr = 1;
@ -1060,11 +1130,16 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
goto memerr; /* ignore this packet */
}
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
if (!entry->is_mdns)
#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
{
/* Check whether response comes from the same network address to which the
question was sent. (RFC 5452) */
if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) {
goto memerr; /* ignore this packet */
}
}
/* Check if the name in the "question" part match with the name in the entry and
skip it if equal. */
@ -1195,7 +1270,7 @@ memerr:
*/
static err_t
dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found,
void *callback_arg LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype))
void *callback_arg LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype) LWIP_DNS_ISMDNS_ARG(u8_t is_mdns))
{
u8_t i;
u8_t lseq, lseqi;
@ -1244,8 +1319,9 @@ dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found,
}
/* check if this is the oldest completed entry */
if (entry->state == DNS_STATE_DONE) {
if ((u8_t)(dns_seqno - entry->seqno) > lseq) {
lseq = dns_seqno - entry->seqno;
u8_t age = dns_seqno - entry->seqno;
if (age > lseq) {
lseq = age;
lseqi = i;
}
}
@ -1310,6 +1386,10 @@ dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found,
LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS pcb %"U16_F"\n", name, (u16_t)(entry->pcb_idx)));
#endif
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
entry->is_mdns = is_mdns;
#endif
dns_seqno++;
/* force to send query without waiting timer */
@ -1365,6 +1445,9 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call
void *callback_arg, u8_t dns_addrtype)
{
size_t hostnamelen;
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
u8_t is_mdns;
#endif
/* not initialized or no valid server yet, or invalid addr pointer
* or invalid hostname or invalid hostname length */
if ((addr == NULL) ||
@ -1421,13 +1504,25 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call
LWIP_UNUSED_ARG(dns_addrtype);
#endif /* LWIP_IPV4 && LWIP_IPV6 */
#if LWIP_DNS_SUPPORT_MDNS_QUERIES
if (strstr(hostname, ".local") == &hostname[hostnamelen] - 6) {
is_mdns = 1;
} else {
is_mdns = 0;
}
if (!is_mdns)
#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
{
/* prevent calling found callback if no server is set, return error instead */
if (ip_addr_isany_val(dns_servers[0])) {
return ERR_VAL;
}
}
/* queue query with specified callback */
return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype));
return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)
LWIP_DNS_ISMDNS_ARG(is_mdns));
}
#endif /* LWIP_DNS */

View File

@ -51,7 +51,6 @@
#include "lwip/def.h"
#include "lwip/ip_addr.h"
#include <stddef.h>
#include <string.h>
#ifndef LWIP_CHKSUM

View File

@ -141,7 +141,7 @@ PACK_STRUCT_END
#if (LWIP_TCP && (TCP_WND > 0xffffffff))
#error "If you want to use TCP, TCP_WND must fit in an u32_t, so, you have to reduce it in your lwipopts.h"
#endif
#if (LWIP_TCP && LWIP_WND_SCALE && (TCP_RCV_SCALE > 14))
#if (LWIP_TCP && (TCP_RCV_SCALE > 14))
#error "The maximum valid window scale value is 14!"
#endif
#if (LWIP_TCP && (TCP_WND > (0xFFFFU << TCP_RCV_SCALE)))
@ -339,6 +339,11 @@ PACK_STRUCT_END
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

View File

@ -68,7 +68,6 @@
#include "lwip/etharp.h"
#include "lwip/prot/autoip.h"
#include <stdlib.h>
#include <string.h>
/** Pseudo random macro based on netif informations.
@ -95,8 +94,6 @@
static err_t autoip_arp_announce(struct netif *netif);
static void autoip_start_probing(struct netif *netif);
#define netif_autoip_data(netif) ((struct autoip*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP))
/**
* @ingroup autoip
* Set a statically allocated struct autoip to work with.
@ -482,7 +479,8 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
* ip.dst == llipaddr && hw.src != own hwaddr
*/
if ((ip4_addr_cmp(&sipaddr, &autoip->llipaddr)) ||
(ip4_addr_cmp(&dipaddr, &autoip->llipaddr) &&
(ip4_addr_isany_val(sipaddr) &&
ip4_addr_cmp(&dipaddr, &autoip->llipaddr) &&
!eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
("autoip_arp_reply(): Probe Conflict detected\n"));

View File

@ -103,26 +103,40 @@
#define REBOOT_TRIES 2
#if LWIP_DNS && LWIP_DHCP_MAX_DNS_SERVERS
#if DNS_MAX_SERVERS > LWIP_DHCP_MAX_DNS_SERVERS
#define LWIP_DHCP_PROVIDE_DNS_SERVERS LWIP_DHCP_MAX_DNS_SERVERS
#else
#define LWIP_DHCP_PROVIDE_DNS_SERVERS DNS_MAX_SERVERS
#endif
#else
#define LWIP_DHCP_PROVIDE_DNS_SERVERS 0
#endif
/** Option handling: options are parsed in dhcp_parse_reply
* and saved in an array where other functions can load them from.
* This might be moved into the struct dhcp (not necessarily since
* lwIP is single-threaded and the array is only used while in recv
* callback). */
#define DHCP_OPTION_IDX_OVERLOAD 0
#define DHCP_OPTION_IDX_MSG_TYPE 1
#define DHCP_OPTION_IDX_SERVER_ID 2
#define DHCP_OPTION_IDX_LEASE_TIME 3
#define DHCP_OPTION_IDX_T1 4
#define DHCP_OPTION_IDX_T2 5
#define DHCP_OPTION_IDX_SUBNET_MASK 6
#define DHCP_OPTION_IDX_ROUTER 7
#define DHCP_OPTION_IDX_DNS_SERVER 8
enum dhcp_option_idx {
DHCP_OPTION_IDX_OVERLOAD = 0,
DHCP_OPTION_IDX_MSG_TYPE,
DHCP_OPTION_IDX_SERVER_ID,
DHCP_OPTION_IDX_LEASE_TIME,
DHCP_OPTION_IDX_T1,
DHCP_OPTION_IDX_T2,
DHCP_OPTION_IDX_SUBNET_MASK,
DHCP_OPTION_IDX_ROUTER,
#if LWIP_DHCP_PROVIDE_DNS_SERVERS
DHCP_OPTION_IDX_DNS_SERVER,
DHCP_OPTION_IDX_DNS_SERVER_LAST = DHCP_OPTION_IDX_DNS_SERVER + LWIP_DHCP_PROVIDE_DNS_SERVERS - 1,
#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
#if LWIP_DHCP_GET_NTP_SRV
#define DHCP_OPTION_IDX_NTP_SERVER (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS)
#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_NTP_SERVER + LWIP_DHCP_MAX_NTP_SERVERS)
#else /* LWIP_DHCP_GET_NTP_SRV */
#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS)
DHCP_OPTION_IDX_NTP_SERVER,
DHCP_OPTION_IDX_NTP_SERVER_LAST = DHCP_OPTION_IDX_NTP_SERVER + LWIP_DHCP_MAX_NTP_SERVERS - 1,
#endif /* LWIP_DHCP_GET_NTP_SRV */
DHCP_OPTION_IDX_MAX
};
/** Holds the decoded option values, only valid while in dhcp_recv.
@todo: move this into struct dhcp? */
@ -135,8 +149,10 @@ u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX];
static u8_t dhcp_discover_request_options[] = {
DHCP_OPTION_SUBNET_MASK,
DHCP_OPTION_ROUTER,
DHCP_OPTION_BROADCAST,
DHCP_OPTION_DNS_SERVER
DHCP_OPTION_BROADCAST
#if LWIP_DHCP_PROVIDE_DNS_SERVERS
, DHCP_OPTION_DNS_SERVER
#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
#if LWIP_DHCP_GET_NTP_SRV
, DHCP_OPTION_NTP
#endif /* LWIP_DHCP_GET_NTP_SRV */
@ -193,8 +209,6 @@ static void dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif);
/* always add the DHCP options trailer to end and pad */
static void dhcp_option_trailer(struct dhcp *dhcp);
#define netif_dhcp_data(netif) ((struct dhcp*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP))
/** Ensure DHCP PCB is allocated and bound */
static err_t
dhcp_inc_pcb_refcount(void)
@ -572,9 +586,9 @@ dhcp_handle_ack(struct netif *netif)
{
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;
#endif /* LWIP_DNS || LWIP_DHCP_GET_NTP_SRV */
#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV */
#if LWIP_DHCP_GET_NTP_SRV
ip4_addr_t ntp_server_addrs[LWIP_DHCP_MAX_NTP_SERVERS];
#endif
@ -640,14 +654,14 @@ dhcp_handle_ack(struct netif *netif)
dhcp_set_ntp_servers(n, ntp_server_addrs);
#endif /* LWIP_DHCP_GET_NTP_SRV */
#if LWIP_DNS
#if LWIP_DHCP_PROVIDE_DNS_SERVERS
/* DNS servers */
for (n = 0; (n < DNS_MAX_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) {
for (n = 0; (n < LWIP_DHCP_PROVIDE_DNS_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) {
ip_addr_t dns_addr;
ip_addr_set_ip4_u32(&dns_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n)));
dns_setserver(n, &dns_addr);
}
#endif /* LWIP_DNS */
#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
}
/**
@ -1517,6 +1531,7 @@ again:
LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_ROUTER;
break;
#if LWIP_DHCP_PROVIDE_DNS_SERVERS
case(DHCP_OPTION_DNS_SERVER):
/* special case: there might be more than one server */
LWIP_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;);
@ -1525,6 +1540,7 @@ again:
LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_DNS_SERVER;
break;
#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
case(DHCP_OPTION_LEASE_TIME):
LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_LEASE_TIME;
@ -1541,6 +1557,8 @@ again:
#endif /* LWIP_DHCP_GET_NTP_SRV*/
case(DHCP_OPTION_OVERLOAD):
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;
break;
case(DHCP_OPTION_MESSAGE_TYPE):

View File

@ -840,7 +840,7 @@ etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
if (!ip4_addr_netcmp(ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif)) &&
!ip4_addr_islinklocal(ipaddr)) {
#if LWIP_AUTOIP
struct ip_hdr *iphdr = (struct ip_hdr*)(size_t)q->payload;
struct ip_hdr *iphdr = LWIP_ALIGNMENT_CAST(struct ip_hdr*, q->payload);
/* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with
a link-local source address must always be "directly to its destination
on the same physical link. The host MUST NOT send the packet to any

View File

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

View File

@ -244,6 +244,7 @@ struct igmp_group *
igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr)
{
struct igmp_group *group;
struct igmp_group *list_head = netif_igmp_data(ifp);
/* Search if the group already exists */
group = igmp_lookfor_group(ifp, addr);
@ -260,9 +261,21 @@ igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr)
group->group_state = IGMP_GROUP_NON_MEMBER;
group->last_reporter_flag = 0;
group->use = 0;
group->next = netif_igmp_data(ifp);
/* 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 ")));
@ -282,24 +295,19 @@ static err_t
igmp_remove_group(struct netif* netif, struct igmp_group *group)
{
err_t err = ERR_OK;
struct igmp_group *tmp_group;
/* Is it the first group? */
if (netif_igmp_data(netif) == group) {
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, group->next);
} else {
/* look for group further down the list */
struct igmp_group *tmpGroup;
for (tmpGroup = netif_igmp_data(netif); tmpGroup != NULL; tmpGroup = tmpGroup->next) {
if (tmpGroup->next == group) {
tmpGroup->next = group->next;
/* Skip the first group in the list, it is always the allsystems group added in igmp_start() */
for (tmp_group = netif_igmp_data(netif); tmp_group != NULL; tmp_group = tmp_group->next) {
if (tmp_group->next == group) {
tmp_group->next = group->next;
break;
}
}
/* Group not found in the global igmp_group_list */
if (tmpGroup == NULL) {
if (tmp_group == NULL) {
err = ERR_ARG;
}
}
return err;
}

View File

@ -177,7 +177,7 @@ ip4_route(const ip4_addr_t *dest)
/* loopif is disabled, looopback traffic is passed through any netif */
if (ip4_addr_isloopback(dest)) {
/* don't check for link on loopback traffic */
if (netif_is_up(netif_default)) {
if (netif_default != NULL && netif_is_up(netif_default)) {
return netif_default;
}
/* default netif is not up, just use any netif for loopback traffic */
@ -518,6 +518,15 @@ ip4_input(struct pbuf *p, struct netif *inp)
#endif /* LWIP_AUTOIP */
}
if (first) {
#if !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF
/* Packets sent to the loopback address must not be accepted on an
* interface that does not have the loopback address assigned to it,
* unless a non-loopback interface is used for loopback traffic. */
if (ip4_addr_isloopback(ip4_current_dest_addr())) {
netif = NULL;
break;
}
#endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */
first = 0;
netif = netif_list;
} else {
@ -589,6 +598,7 @@ ip4_input(struct pbuf *p, struct netif *inp)
} else
#endif /* IP_FORWARD */
{
IP_STATS_INC(ip.drop);
MIB2_STATS_INC(mib2.ipinaddrerrors);
MIB2_STATS_INC(mib2.ipindiscards);
}
@ -853,7 +863,7 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d
IPH_TTL_SET(iphdr, ttl);
IPH_PROTO_SET(iphdr, proto);
#if CHECKSUM_GEN_IP_INLINE
chk_sum += LWIP_MAKE_U16(proto, ttl);
chk_sum += PP_NTOHS(proto | (ttl << 8));
#endif /* CHECKSUM_GEN_IP_INLINE */
/* dest cannot be NULL here */
@ -866,7 +876,7 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d
IPH_VHL_SET(iphdr, 4, ip_hlen / 4);
IPH_TOS_SET(iphdr, tos);
#if CHECKSUM_GEN_IP_INLINE
chk_sum += LWIP_MAKE_U16(tos, iphdr->_v_hl);
chk_sum += PP_NTOHS(tos | (iphdr->_v_hl << 8));
#endif /* CHECKSUM_GEN_IP_INLINE */
IPH_LEN_SET(iphdr, lwip_htons(p->tot_len));
#if CHECKSUM_GEN_IP_INLINE

View File

@ -183,10 +183,10 @@ ip4addr_aton(const char *cp, ip4_addr_t *addr)
}
for (;;) {
if (isdigit(c)) {
val = (val * base) + (int)(c - '0');
val = (val * base) + (u32_t)(c - '0');
c = *++cp;
} else if (base == 16 && isxdigit(c)) {
val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));
val = (val << 4) | (u32_t)(c + 10 - (islower(c) ? 'a' : 'A'));
c = *++cp;
} else {
break;
@ -310,7 +310,7 @@ ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen)
do {
rem = *ap % (u8_t)10;
*ap /= (u8_t)10;
inv[i++] = '0' + rem;
inv[i++] = (char)('0' + rem);
} while (*ap);
while (i--) {
if (len++ >= buflen) {

View File

@ -687,6 +687,8 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
struct pbuf *rambuf;
#if !LWIP_NETIF_TX_SINGLE_PBUF
struct pbuf *newpbuf;
u16_t newpbuflen = 0;
u16_t left_to_copy;
#endif
struct ip_hdr *original_iphdr;
struct ip_hdr *iphdr;
@ -696,10 +698,6 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
int last;
u16_t poff = IP_HLEN;
u16_t tmp;
#if !LWIP_NETIF_TX_SINGLE_PBUF
u16_t newpbuflen = 0;
u16_t left_to_copy;
#endif
original_iphdr = (struct ip_hdr *)p->payload;
iphdr = original_iphdr;

View File

@ -62,7 +62,9 @@
* For IPv6 multicast, corresponding Ethernet addresses
* are selected and the packet is transmitted on the link.
*
* For unicast addresses, ...
* For unicast addresses, ask the ND6 module what to do. It will either let us
* send the the packet right away, or queue the packet for later itself, unless
* an error occurs.
*
* @todo anycast addresses
*
@ -71,14 +73,14 @@
* @param ip6addr The IP address of the packet destination.
*
* @return
* - ERR_RTE No route to destination (no gateway to external networks),
* or the return type of either nd6_queue_packet() or ethernet_output().
* - ERR_OK or the return value of @ref nd6_get_next_hop_addr_or_queue.
*/
err_t
ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr)
{
struct eth_addr dest;
s8_t i;
const u8_t *hwaddr;
err_t result;
/* multicast destination IP address? */
if (ip6_addr_ismulticast(ip6addr)) {
@ -91,36 +93,26 @@ ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr)
dest.addr[5] = ((const u8_t *)(&(ip6addr->addr[3])))[3];
/* Send out. */
return ethernet_output(netif, q, (struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6);
return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6);
}
/* We have a unicast destination IP address */
/* @todo anycast? */
/* Get next hop record. */
i = nd6_get_next_hop_entry(ip6addr, netif);
if (i < 0) {
/* failed to get a next hop neighbor record. */
return ERR_MEM;
/* Ask ND6 what to do with the packet. */
result = nd6_get_next_hop_addr_or_queue(netif, q, ip6addr, &hwaddr);
if (result != ERR_OK) {
return result;
}
/* Now that we have a destination record, send or queue the packet. */
if (neighbor_cache[i].state == ND6_STALE) {
/* Switch to delay state. */
neighbor_cache[i].state = ND6_DELAY;
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / 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)) {
/* Send out. */
SMEMCPY(dest.addr, neighbor_cache[i].lladdr, 6);
return ethernet_output(netif, q, (struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6);
/* If no hardware address is returned, nd6 has queued the packet for later. */
if (hwaddr == NULL) {
return ERR_OK;
}
/* We should queue packet on this interface. */
return nd6_queue_packet(i, q);
/* Send out the packet using the returned hardware address. */
SMEMCPY(dest.addr, hwaddr, 6);
return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6);
}
#endif /* LWIP_IPV6 && LWIP_ETHERNET */

View File

@ -94,7 +94,8 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
if (ip6_addr_islinklocal(dest)) {
if (ip6_addr_isany(src)) {
/* Use default netif, if Up. */
if (!netif_is_up(netif_default) || !netif_is_link_up(netif_default)) {
if (netif_default == NULL || !netif_is_up(netif_default) ||
!netif_is_link_up(netif_default)) {
return NULL;
}
return netif_default;
@ -114,7 +115,8 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
}
/* netif not found, use default netif, if up */
if (!netif_is_up(netif_default) || !netif_is_link_up(netif_default)) {
if (netif_default == NULL || !netif_is_up(netif_default) ||
!netif_is_link_up(netif_default)) {
return NULL;
}
return netif_default;
@ -142,15 +144,9 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
}
/* Get the netif for a suitable router. */
i = nd6_select_router(dest, NULL);
if (i >= 0) {
if (default_router_list[i].neighbor_entry != NULL) {
if (default_router_list[i].neighbor_entry->netif != NULL) {
if (netif_is_up(default_router_list[i].neighbor_entry->netif) && netif_is_link_up(default_router_list[i].neighbor_entry->netif)) {
return default_router_list[i].neighbor_entry->netif;
}
}
}
netif = nd6_find_route(dest);
if ((netif != NULL) && netif_is_up(netif) && netif_is_link_up(netif)) {
return netif;
}
/* try with the netif that matches the source address. */
@ -172,7 +168,7 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
/* loopif is disabled, loopback traffic is passed through any netif */
if (ip6_addr_isloopback(dest)) {
/* don't check for link on loopback traffic */
if (netif_is_up(netif_default)) {
if (netif_default != NULL && netif_is_up(netif_default)) {
return netif_default;
}
/* default netif is not up, just use any netif for loopback traffic */
@ -290,8 +286,9 @@ ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp)
{
struct netif *netif;
/* do not forward link-local addresses */
if (ip6_addr_islinklocal(ip6_current_dest_addr())) {
/* do not forward link-local or loopback addresses */
if (ip6_addr_islinklocal(ip6_current_dest_addr()) ||
ip6_addr_isloopback(ip6_current_dest_addr())) {
LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n"));
IP6_STATS_INC(ip6.rterr);
IP6_STATS_INC(ip6.drop);
@ -509,12 +506,21 @@ ip6_input(struct pbuf *p, struct netif *inp)
}
}
}
if (ip6_addr_islinklocal(ip6_current_dest_addr())) {
/* Do not match link-local addresses to other netifs. */
if (first) {
if (ip6_addr_islinklocal(ip6_current_dest_addr())
#if !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF
|| ip6_addr_isloopback(ip6_current_dest_addr())
#endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */
) {
/* Do not match link-local addresses to other netifs. The loopback
* address is to be considered link-local and packets to it should be
* dropped on other interfaces, as per RFC 4291 Sec. 2.5.3. This
* requirement cannot be implemented in the case that loopback
* traffic is sent across a non-loopback interface, however.
*/
netif = NULL;
break;
}
if (first) {
first = 0;
netif = netif_list;
} else {
@ -709,7 +715,7 @@ netif_found:
options_done:
/* p points to IPv6 header again. */
pbuf_header_force(p, ip_data.current_ip_header_tot_len);
pbuf_header_force(p, (s16_t)ip_data.current_ip_header_tot_len);
/* send to upper layers */
LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n"));

View File

@ -132,8 +132,8 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr)
} else if (isxdigit(*s)) {
/* add current digit */
current_block_value = (current_block_value << 4) +
(isdigit(*s) ? *s - '0' :
10 + (islower(*s) ? *s - 'a' : *s - 'A'));
(isdigit(*s) ? (u32_t)(*s - '0') :
(u32_t)(10 + (islower(*s) ? *s - 'a' : *s - 'A')));
} else {
/* unexpected digit, space? CRLF? */
break;

View File

@ -379,6 +379,7 @@ ip6_reass(struct pbuf *p)
/* Make room for struct ip6_reass_helper (only required if sizeof(void*) > 4).
This cannot fail since we already checked when receiving this fragment. */
u8_t hdrerr = pbuf_header_force(p, IPV6_FRAG_REQROOM);
LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0);
}
#else /* IPV6_FRAG_COPYHEADER */
@ -530,6 +531,7 @@ ip6_reass(struct pbuf *p)
if (IPV6_FRAG_REQROOM > 0) {
/* hide the extra bytes borrowed from ip6_hdr for struct ip6_reass_helper */
u8_t hdrerr = pbuf_header(next_pbuf, -(s16_t)(IPV6_FRAG_REQROOM));
LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0);
}
#endif
@ -546,6 +548,7 @@ ip6_reass(struct pbuf *p)
if (IPV6_FRAG_REQROOM > 0) {
/* get back room for struct ip6_reass_helper (only required if sizeof(void*) > 4) */
u8_t hdrerr = pbuf_header(ipr->p, -(s16_t)(IPV6_FRAG_REQROOM));
LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0);
}
iphdr_ptr = (struct ip6_hdr*)((u8_t*)ipr->p->payload - IP6_HLEN);
@ -610,6 +613,7 @@ nullreturn:
#if LWIP_IPV6 && LWIP_IPV6_FRAG
#if !LWIP_NETIF_TX_SINGLE_PBUF
/** Allocate a new struct pbuf_custom_ref */
static struct pbuf_custom_ref*
ip6_frag_alloc_pbuf_custom_ref(void)
@ -638,6 +642,7 @@ ip6_frag_free_pbuf_custom(struct pbuf *p)
}
ip6_frag_free_pbuf_custom_ref(pcr);
}
#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
/**
* Fragment an IPv6 datagram if too large for the netif or path MTU.
@ -658,7 +663,11 @@ ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest)
struct ip6_hdr *ip6hdr;
struct ip6_frag_hdr *frag_hdr;
struct pbuf *rambuf;
#if !LWIP_NETIF_TX_SINGLE_PBUF
struct pbuf *newpbuf;
u16_t newpbuflen = 0;
u16_t left_to_copy;
#endif
static u32_t identification;
u16_t nfb;
u16_t left, cop;
@ -666,8 +675,6 @@ ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest)
u16_t fragment_offset = 0;
u16_t last;
u16_t poff = IP6_HLEN;
u16_t newpbuflen = 0;
u16_t left_to_copy;
identification++;
@ -686,6 +693,26 @@ ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest)
/* Fill this fragment */
cop = last ? left : nfb;
#if LWIP_NETIF_TX_SINGLE_PBUF
rambuf = pbuf_alloc(PBUF_IP, cop + IP6_FRAG_HLEN, PBUF_RAM);
if (rambuf == NULL) {
IP6_FRAG_STATS_INC(ip6_frag.memerr);
return ERR_MEM;
}
LWIP_ASSERT("this needs a pbuf in one piece!",
(rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
poff += pbuf_copy_partial(p, (u8_t*)rambuf->payload + IP6_FRAG_HLEN, cop, poff);
/* make room for the IP header */
if (pbuf_header(rambuf, IP6_HLEN)) {
pbuf_free(rambuf);
IP6_FRAG_STATS_INC(ip6_frag.memerr);
return ERR_MEM;
}
/* fill in the IP header */
SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN);
ip6hdr = (struct ip6_hdr *)rambuf->payload;
frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN);
#else
/* When not using a static buffer, create a chain of pbufs.
* The first will be a PBUF_RAM holding the link, IPv6, and Fragment header.
* The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
@ -744,6 +771,7 @@ ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest)
}
}
poff = newpbuflen;
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
/* Set headers */
frag_hdr->_nexth = original_ip6hdr->_nexth;

View File

@ -46,6 +46,7 @@
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/nd6.h"
#include "lwip/priv/nd6_priv.h"
#include "lwip/prot/nd6.h"
#include "lwip/prot/icmp6.h"
#include "lwip/pbuf.h"
@ -59,6 +60,7 @@
#include "lwip/mld6.h"
#include "lwip/ip.h"
#include "lwip/stats.h"
#include "lwip/dns.h"
#include <string.h>
@ -93,10 +95,13 @@ 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_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_select_router(const ip6_addr_t *ip6addr, struct netif *netif);
static s8_t nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif);
static s8_t nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif);
static s8_t nd6_get_onlink_prefix(ip6_addr_t *prefix, struct netif *netif);
static s8_t nd6_new_onlink_prefix(ip6_addr_t *prefix, struct netif *netif);
static s8_t nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif);
static err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf *q);
#define ND6_SEND_FLAG_MULTICAST_DEST 0x01
#define ND6_SEND_FLAG_ALLNODES_DEST 0x02
@ -155,25 +160,6 @@ nd6_input(struct pbuf *p, struct netif *inp)
* link-layer changed?
* part of DAD mechanism? */
/* Check that link-layer address option also fits in packet. */
if (p->len < (sizeof(struct na_header) + 2)) {
/* @todo debug message */
pbuf_free(p);
ND6_STATS_INC(nd6.lenerr);
ND6_STATS_INC(nd6.drop);
return;
}
lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header));
if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) {
/* @todo debug message */
pbuf_free(p);
ND6_STATS_INC(nd6.lenerr);
ND6_STATS_INC(nd6.drop);
return;
}
/* Create an aligned copy. */
ip6_addr_set(&target_address, &(na_hdr->target_address));
@ -185,12 +171,6 @@ nd6_input(struct pbuf *p, struct netif *inp)
/* 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(inp, &multicast_address);
#endif /* LWIP_IPV6_MLD */
#if LWIP_IPV6_AUTOCONFIG
/* Check to see if this address was autoconfigured. */
if (!ip6_addr_islinklocal(&target_address)) {
@ -209,6 +189,25 @@ nd6_input(struct pbuf *p, struct netif *inp)
}
#endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */
/* Check that link-layer address option also fits in packet. */
if (p->len < (sizeof(struct na_header) + 2)) {
/* @todo debug message */
pbuf_free(p);
ND6_STATS_INC(nd6.lenerr);
ND6_STATS_INC(nd6.drop);
return;
}
lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header));
if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) {
/* @todo debug message */
pbuf_free(p);
ND6_STATS_INC(nd6.lenerr);
ND6_STATS_INC(nd6.drop);
return;
}
/* This is an unsolicited NA, most likely there was a LLADDR change. */
i = nd6_find_neighbor_cache_entry(&target_address);
if (i >= 0) {
@ -390,6 +389,10 @@ nd6_input(struct pbuf *p, struct netif *inp)
struct ra_header *ra_hdr;
u8_t *buffer; /* Used to copy options. */
u16_t offset;
#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS
/* There can by multiple RDNSS options per RA */
u8_t rdnss_server_idx = 0;
#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */
/* Check that RA header fits in packet. */
if (p->len < sizeof(struct ra_header)) {
@ -534,6 +537,37 @@ nd6_input(struct pbuf *p, struct netif *inp)
route_opt = (struct route_option *)buffer;*/
break;
#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS
case ND6_OPTION_TYPE_RDNSS:
{
u8_t num, n;
struct rdnss_option * rdnss_opt;
rdnss_opt = (struct rdnss_option *)buffer;
num = (rdnss_opt->length - 1) / 2;
for (n = 0; (rdnss_server_idx < DNS_MAX_SERVERS) && (n < num); n++) {
ip_addr_t rdnss_address;
/* Get a memory-aligned copy of the prefix. */
ip_addr_copy_from_ip6(rdnss_address, rdnss_opt->rdnss_address[n]);
if (htonl(rdnss_opt->lifetime) > 0) {
/* TODO implement Lifetime > 0 */
dns_setserver(rdnss_server_idx++, &rdnss_address);
} else {
/* TODO implement DNS removal in dns.c */
u8_t s;
for (s = 0; s < DNS_MAX_SERVERS; s++) {
const ip_addr_t *addr = dns_getserver(s);
if(ip_addr_cmp(addr, &rdnss_address)) {
dns_setserver(s, NULL);
}
}
}
}
break;
}
#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */
default:
/* Unrecognized option, abort. */
ND6_STATS_INC(nd6.proterr);
@ -549,6 +583,7 @@ nd6_input(struct pbuf *p, struct netif *inp)
{
struct redirect_header *redir_hdr;
struct lladdr_option *lladdr_opt;
ip6_addr_t tmp;
/* Check that Redir header fits in packet. */
if (p->len < sizeof(struct redirect_header)) {
@ -571,10 +606,10 @@ nd6_input(struct pbuf *p, struct netif *inp)
}
/* Copy original destination address to current source address, to have an aligned copy. */
ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->destination_address));
ip6_addr_set(&tmp, &(redir_hdr->destination_address));
/* Find dest address in cache */
i = nd6_find_destination_cache_entry(ip6_current_src_addr());
i = nd6_find_destination_cache_entry(&tmp);
if (i < 0) {
/* Destination not in cache, drop packet. */
pbuf_free(p);
@ -588,15 +623,15 @@ nd6_input(struct pbuf *p, struct netif *inp)
if (lladdr_opt != NULL) {
if (lladdr_opt->type == ND6_OPTION_TYPE_TARGET_LLADDR) {
/* Copy target address to current source address, to have an aligned copy. */
ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->target_address));
ip6_addr_set(&tmp, &(redir_hdr->target_address));
i = nd6_find_neighbor_cache_entry(ip6_current_src_addr());
i = nd6_find_neighbor_cache_entry(&tmp);
if (i < 0) {
i = nd6_new_neighbor_cache_entry();
if (i >= 0) {
neighbor_cache[i].netif = inp;
MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr());
ip6_addr_set(&(neighbor_cache[i].next_hop_address), &tmp);
/* Receiving a message does not prove reachability: only in one direction.
* Delay probe in case we get confirmation of reachability from upper layer (TCP). */
@ -622,6 +657,7 @@ nd6_input(struct pbuf *p, struct netif *inp)
struct icmp6_hdr *icmp6hdr; /* Packet too big message */
struct ip6_hdr *ip6hdr; /* IPv6 header of the packet which caused the error */
u32_t pmtu;
ip6_addr_t tmp;
/* Check that ICMPv6 header + IPv6 header fit in payload */
if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) {
@ -636,10 +672,10 @@ nd6_input(struct pbuf *p, struct netif *inp)
ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr));
/* Copy original destination address to current source address, to have an aligned copy. */
ip6_addr_set(ip6_current_src_addr(), &(ip6hdr->dest));
ip6_addr_set(&tmp, &(ip6hdr->dest));
/* Look for entry in destination cache. */
i = nd6_find_destination_cache_entry(ip6_current_src_addr());
i = nd6_find_destination_cache_entry(&tmp);
if (i < 0) {
/* Destination not in cache, drop packet. */
pbuf_free(p);
@ -829,13 +865,6 @@ nd6_tmr(void)
netif_ip6_addr_set_state(netif, i, IP6_ADDR_PREFERRED);
/* @todo implement preferred and valid lifetimes. */
} else if (netif->flags & NETIF_FLAG_UP) {
#if LWIP_IPV6_MLD
if ((addr_state & IP6_ADDR_TENTATIVE_COUNT_MASK) == 0) {
/* Join solicited node multicast group. */
ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, i)->addr[3]);
mld6_joingroup_netif(netif, &multicast_address);
}
#endif /* LWIP_IPV6_MLD */
/* Send a NS for this address. */
nd6_send_ns(netif, netif_ip6_addr(netif, i), ND6_SEND_FLAG_MULTICAST_DEST);
/* tentative: set next state by increasing by one */
@ -1293,6 +1322,22 @@ nd6_new_destination_cache_entry(void)
return j;
}
/**
* Clear the destination cache.
*
* This operation may be necessary for consistency in the light of changing
* local addresses and/or use of the gateway hook.
*/
void
nd6_clear_destination_cache(void)
{
int i;
for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) {
ip6_addr_set_any(&destination_cache[i].destination_addr);
}
}
/**
* Determine whether an address matches an on-link prefix.
*
@ -1328,7 +1373,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
* router is found
*/
s8_t
static s8_t
nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif)
{
s8_t i;
@ -1380,6 +1425,30 @@ nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif)
return -1;
}
/**
* Find a router-announced route to the given destination.
*
* The caller is responsible for checking whether the returned netif, if any,
* is in a suitable state (up, link up) to be used for packet transmission.
*
* @param ip6addr the destination IPv6 address
* @return the netif to use for the destination, or NULL if none found
*/
struct netif *
nd6_find_route(const ip6_addr_t *ip6addr)
{
s8_t i;
i = nd6_select_router(ip6addr, NULL);
if (i >= 0) {
if (default_router_list[i].neighbor_entry != NULL) {
return default_router_list[i].neighbor_entry->netif; /* may be NULL */
}
}
return NULL;
}
/**
* Find an entry for a default router.
*
@ -1416,6 +1485,7 @@ static s8_t
nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif)
{
s8_t router_index;
s8_t free_router_index;
s8_t neighbor_index;
/* Do we have a neighbor entry for this router? */
@ -1439,11 +1509,21 @@ nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif)
neighbor_cache[neighbor_index].isrouter = 1;
/* Look for empty entry. */
for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) {
if (default_router_list[router_index].neighbor_entry == NULL) {
default_router_list[router_index].neighbor_entry = &(neighbor_cache[neighbor_index]);
free_router_index = LWIP_ND6_NUM_ROUTERS;
for (router_index = LWIP_ND6_NUM_ROUTERS - 1; router_index >= 0; router_index--) {
/* check if router already exists (this is a special case for 2 netifs on the same subnet
- e.g. wifi and cable) */
if(default_router_list[router_index].neighbor_entry == &(neighbor_cache[neighbor_index])){
return router_index;
}
if (default_router_list[router_index].neighbor_entry == NULL) {
/* 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. */
@ -1521,9 +1601,12 @@ nd6_new_onlink_prefix(ip6_addr_t *prefix, struct netif *netif)
* suitable next hop was found, ERR_MEM if no cache entry
* could be created
*/
s8_t
static s8_t
nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif)
{
#ifdef LWIP_HOOK_ND6_GET_GW
const ip6_addr_t *next_hop_addr;
#endif /* LWIP_HOOK_ND6_GET_GW */
s8_t i;
#if LWIP_NETIF_HWADDRHINT
@ -1567,6 +1650,12 @@ nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif)
/* Destination in local link. */
destination_cache[nd6_cached_destination_index].pmtu = netif->mtu;
ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, destination_cache[nd6_cached_destination_index].destination_addr);
#ifdef LWIP_HOOK_ND6_GET_GW
} else if ((next_hop_addr = LWIP_HOOK_ND6_GET_GW(netif, ip6addr)) != NULL) {
/* Next hop for destination provided by hook function. */
destination_cache[nd6_cached_destination_index].pmtu = netif->mtu;
ip6_addr_set(&destination_cache[nd6_cached_destination_index].next_hop_addr, next_hop_addr);
#endif /* LWIP_HOOK_ND6_GET_GW */
} else {
/* We need to select a router. */
i = nd6_select_router(ip6addr, netif);
@ -1634,7 +1723,7 @@ nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif)
* @param q packet to be queued
* @return ERR_OK if succeeded, ERR_MEM if out of memory
*/
err_t
static err_t
nd6_queue_packet(s8_t neighbor_index, struct pbuf *q)
{
err_t result = ERR_MEM;
@ -1811,6 +1900,61 @@ nd6_send_q(s8_t i)
#endif /* LWIP_ND6_QUEUEING */
}
/**
* A packet is to be transmitted to a specific IPv6 destination on a specific
* interface. Check if we can find the hardware address of the next hop to use
* for the packet. If so, give the hardware address to the caller, which should
* use it to send the packet right away. Otherwise, enqueue the packet for
* later transmission while looking up the hardware address, if possible.
*
* As such, this function returns one of three different possible results:
*
* - ERR_OK with a non-NULL 'hwaddrp': the caller should send the packet now.
* - ERR_OK with a NULL 'hwaddrp': the packet has been enqueued for later.
* - not ERR_OK: something went wrong; forward the error upward in the stack.
*
* @param netif The lwIP network interface on which the IP packet will be sent.
* @param q The pbuf(s) containing the IP packet to be sent.
* @param ip6addr The destination IPv6 address of the packet.
* @param hwaddrp On success, filled with a pointer to a HW address or NULL (meaning
* the packet has been queued).
* @return
* - ERR_OK on success, ERR_RTE if no route was found for the packet,
* or ERR_MEM if low memory conditions prohibit sending the packet at all.
*/
err_t
nd6_get_next_hop_addr_or_queue(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr, const u8_t **hwaddrp)
{
s8_t i;
/* Get next hop record. */
i = nd6_get_next_hop_entry(ip6addr, netif);
if (i < 0) {
/* failed to get a next hop neighbor record. */
return i;
}
/* Now that we have a destination record, send or queue the packet. */
if (neighbor_cache[i].state == ND6_STALE) {
/* Switch to delay state. */
neighbor_cache[i].state = ND6_DELAY;
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL;
}
/* @todo should we send or queue if PROBE? send for now, to let unicast NS pass. */
if ((neighbor_cache[i].state == ND6_REACHABLE) ||
(neighbor_cache[i].state == ND6_DELAY) ||
(neighbor_cache[i].state == ND6_PROBE)) {
/* Tell the caller to send out the packet now. */
*hwaddrp = neighbor_cache[i].lladdr;
return ERR_OK;
}
/* We should queue packet on this interface. */
*hwaddrp = NULL;
return nd6_queue_packet(i, q);
}
/**
* Get the Path MTU for a destination.
@ -1917,4 +2061,38 @@ nd6_cleanup_netif(struct netif *netif)
}
}
#if LWIP_IPV6_MLD
/**
* The state of a local IPv6 address entry is about to change. If needed, join
* or leave the solicited-node multicast group for the address.
*
* @param netif The netif that owns the address.
* @param addr_idx The index of the address.
* @param new_state The new (IP6_ADDR_) state for the address.
*/
void
nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state)
{
u8_t old_state, old_member, new_member;
old_state = netif_ip6_addr_state(netif, addr_idx);
/* Determine whether we were, and should be, a member of the solicited-node
* multicast group for this address. For tentative addresses, the group is
* not joined until the address enters the TENTATIVE_1 (or VALID) state. */
old_member = (old_state != IP6_ADDR_INVALID && old_state != IP6_ADDR_TENTATIVE);
new_member = (new_state != IP6_ADDR_INVALID && new_state != IP6_ADDR_TENTATIVE);
if (old_member != new_member) {
ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, addr_idx)->addr[3]);
if (new_member) {
mld6_joingroup_netif(netif, &multicast_address);
} else {
mld6_leavegroup_netif(netif, &multicast_address);
}
}
}
#endif /* LWIP_IPV6_MLD */
#endif /* LWIP_IPV6 */

View File

@ -61,9 +61,13 @@
#include "lwip/err.h"
#include <string.h>
#include <stdlib.h>
#if MEM_LIBC_MALLOC
#include <stdlib.h> /* for malloc()/free() */
#endif
#if MEM_LIBC_MALLOC || MEM_USE_POOLS
/** mem_init is not used when using pools instead of a heap or using
* C library malloc().
*/
@ -162,7 +166,7 @@ void *
mem_malloc(mem_size_t size)
{
void *ret;
struct memp_malloc_helper *element;
struct memp_malloc_helper *element = NULL;
memp_t poolnr;
mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));

View File

@ -71,7 +71,7 @@
#include "netif/ppp/ppp_opts.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "lwip/nd6.h"
#include "lwip/priv/nd6_priv.h"
#include "lwip/ip6_frag.h"
#include "lwip/mld6.h"
@ -209,7 +209,7 @@ memp_overflow_check_all(void)
for (j = 0; j < memp_pools[i]->num; ++j) {
memp_overflow_check_element_overflow(p, memp_pools[i]);
memp_overflow_check_element_underflow(p, memp_pools[i]);
p = (struct memp*)(size_t)((u8_t*)p + MEMP_SIZE + memp_pools[i]->size + MEMP_SANITY_REGION_AFTER_ALIGNED);
p = LWIP_ALIGNMENT_CAST(struct memp*, ((u8_t*)p + MEMP_SIZE + memp_pools[i]->size + MEMP_SANITY_REGION_AFTER_ALIGNED));
}
}
SYS_ARCH_UNPROTECT(old_level);
@ -301,15 +301,15 @@ do_memp_malloc_pool_fn(const struct memp_desc *desc, const char* file, const int
SYS_ARCH_PROTECT(old_level);
memp = *desc->tab;
#if MEMP_OVERFLOW_CHECK == 1
memp_overflow_check_element_overflow(memp, desc);
memp_overflow_check_element_underflow(memp, desc);
#endif /* MEMP_OVERFLOW_CHECK */
#endif /* MEMP_MEM_MALLOC */
if (memp != NULL) {
#if !MEMP_MEM_MALLOC
#if MEMP_OVERFLOW_CHECK == 1
memp_overflow_check_element_overflow(memp, desc);
memp_overflow_check_element_underflow(memp, desc);
#endif /* MEMP_OVERFLOW_CHECK */
*desc->tab = memp->next;
#if MEMP_OVERFLOW_CHECK
memp->next = NULL;

View File

@ -180,7 +180,7 @@ netif_init(void)
#endif /* NO_SYS */
#if LWIP_IPV6
IP_ADDR6(loop_netif.ip6_addr, 0, 0, 0, PP_HTONL(0x00000001UL));
IP_ADDR6_HOST(loop_netif.ip6_addr, 0, 0, 0, 0x00000001UL);
loop_netif.ip6_addr_state[0] = IP6_ADDR_VALID;
#endif /* LWIP_IPV6 */
@ -478,7 +478,7 @@ netif_find(const char *name)
return NULL;
}
num = name[2] - '0';
num = (u8_t)(name[2] - '0');
for (netif = netif_list; netif != NULL; netif = netif->next) {
if (num == netif->num &&
@ -904,7 +904,6 @@ netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t* ad
void
netif_poll(struct netif *netif)
{
struct pbuf *in;
/* If we have a loopif, SNMP counters are adjusted for it,
* if not they are adjusted for 'netif'. */
#if MIB2_STATS
@ -916,15 +915,15 @@ netif_poll(struct netif *netif)
#endif /* MIB2_STATS */
SYS_ARCH_DECL_PROTECT(lev);
do {
/* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
SYS_ARCH_PROTECT(lev);
in = netif->loop_first;
if (in != NULL) {
struct pbuf *in_end = in;
while (netif->loop_first != NULL) {
struct pbuf *in, *in_end;
#if LWIP_LOOPBACK_MAX_PBUFS
u8_t clen = 1;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
in = in_end = netif->loop_first;
while (in_end->len != in_end->tot_len) {
LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
in_end = in_end->next;
@ -950,10 +949,8 @@ netif_poll(struct netif *netif)
}
/* De-queue the pbuf from its successors on the 'loop_' list. */
in_end->next = NULL;
}
SYS_ARCH_UNPROTECT(lev);
if (in != NULL) {
LINK_STATS_INC(link.recv);
MIB2_STATS_NETIF_ADD(stats_if, ifinoctets, in->tot_len);
MIB2_STATS_NETIF_INC(stats_if, ifinucastpkts);
@ -961,11 +958,9 @@ netif_poll(struct netif *netif)
if (ip_input(in, netif) != ERR_OK) {
pbuf_free(in);
}
/* Don't reference the packet any more! */
in = NULL;
SYS_ARCH_PROTECT(lev);
}
/* go on while there is a packet on the list */
} while (netif->loop_first != NULL);
SYS_ARCH_UNPROTECT(lev);
}
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
@ -1101,6 +1096,13 @@ netif_ip6_addr_set_state(struct netif* netif, s8_t addr_idx, u8_t state)
u8_t new_valid = state & IP6_ADDR_VALID;
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set_state: netif address state being changed\n"));
#if LWIP_IPV6_MLD
/* Reevaluate solicited-node multicast group membership. */
if (netif->flags & NETIF_FLAG_MLD6) {
nd6_adjust_mld_membership(netif, addr_idx, state);
}
#endif /* LWIP_IPV6_MLD */
if (old_valid && !new_valid) {
/* address about to be removed by setting invalid */
#if LWIP_TCP
@ -1200,10 +1202,10 @@ netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit)
/* Set address state. */
#if LWIP_IPV6_DUP_DETECT_ATTEMPTS
/* Will perform duplicate address detection (DAD). */
netif->ip6_addr_state[0] = IP6_ADDR_TENTATIVE;
netif_ip6_addr_set_state(netif, 0, IP6_ADDR_TENTATIVE);
#else
/* Consider address valid. */
netif->ip6_addr_state[0] = IP6_ADDR_PREFERRED;
netif_ip6_addr_set_state(netif, 0, IP6_ADDR_PREFERRED);
#endif /* LWIP_IPV6_AUTOCONFIG */
}
@ -1233,7 +1235,7 @@ netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chos
/* Find a free slot -- musn't be the first one (reserved for link local) */
for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (!ip6_addr_isvalid(netif->ip6_addr_state[i])) {
if (ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) {
ip_addr_copy_from_ip6(netif->ip6_addr[i], *ip6addr);
netif_ip6_addr_set_state(netif, i, IP6_ADDR_TENTATIVE);
if (chosen_idx != NULL) {

View File

@ -568,11 +568,11 @@ pbuf_header_impl(struct pbuf *p, s16_t header_size_increment, u8_t force)
}
if (header_size_increment < 0) {
increment_magnitude = -header_size_increment;
increment_magnitude = (u16_t)-header_size_increment;
/* Check that we aren't going to move off the end of the pbuf */
LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);
} else {
increment_magnitude = header_size_increment;
increment_magnitude = (u16_t)header_size_increment;
#if 0
/* Can't assert these as some callers speculatively call
pbuf_header() to see if it's OK. Will return 1 below instead. */
@ -1119,7 +1119,8 @@ pbuf_skip_const(const struct pbuf* in, u16_t in_offset, u16_t* out_offset)
struct pbuf*
pbuf_skip(struct pbuf* in, u16_t in_offset, u16_t* out_offset)
{
return (struct pbuf*)(size_t)pbuf_skip_const(in, in_offset, out_offset);
const struct pbuf* out = pbuf_skip_const(in, in_offset, out_offset);
return LWIP_CONST_CAST(struct pbuf*, out);
}
/**
@ -1227,6 +1228,7 @@ pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
return p;
}
err = pbuf_copy(q, p);
LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */
LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
pbuf_free(p);
return q;

View File

@ -209,7 +209,7 @@ raw_input(struct pbuf *p, struct netif *inp)
err_t
raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
{
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
return ERR_VAL;
}
ip_addr_set_ipaddr(&pcb->local_ip, ipaddr);
@ -233,7 +233,7 @@ raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
err_t
raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
{
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
return ERR_VAL;
}
ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr);
@ -320,7 +320,13 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr)
}
}
if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
/* Don't call ip_route() with IP_ANY_TYPE */
netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(ipaddr)), ipaddr);
} else {
netif = ip_route(&pcb->local_ip, ipaddr);
}
if (netif == NULL) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to "));
ip_addr_debug_print(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ipaddr);

View File

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

View File

@ -551,7 +551,7 @@ tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port)
#endif /* LWIP_IPV4 */
/* still need to check for ipaddr == NULL in IPv6 only case */
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
return ERR_VAL;
}
@ -636,19 +636,44 @@ tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)
*
* @note The original tcp_pcb is freed. This function therefore has to be
* called like this:
* tpcb = tcp_listen(tpcb);
* tpcb = tcp_listen_with_backlog(tpcb, backlog);
*/
struct tcp_pcb *
tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
{
struct tcp_pcb_listen *lpcb;
return tcp_listen_with_backlog_and_err(pcb, backlog, NULL);
}
/**
* @ingroup tcp_raw
* Set the state of the connection to be LISTEN, which means that it
* is able to accept incoming connections. The protocol control block
* is reallocated in order to consume less memory. Setting the
* connection to LISTEN is an irreversible process.
*
* @param pcb the original tcp_pcb
* @param backlog the incoming connections queue limit
* @param err when NULL is returned, this contains the error reason
* @return tcp_pcb used for listening, consumes less memory.
*
* @note The original tcp_pcb is freed. This function therefore has to be
* called like this:
* tpcb = tcp_listen_with_backlog_and_err(tpcb, backlog, &err);
*/
struct tcp_pcb *
tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err)
{
struct tcp_pcb_listen *lpcb = NULL;
err_t res;
LWIP_UNUSED_ARG(backlog);
LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL);
LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, res = ERR_CLSD; goto done);
/* already listening? */
if (pcb->state == LISTEN) {
return pcb;
lpcb = (struct tcp_pcb_listen*)pcb;
res = ERR_ALREADY;
goto done;
}
#if SO_REUSE
if (ip_get_option(pcb, SOF_REUSEADDR)) {
@ -659,14 +684,17 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
if ((lpcb->local_port == pcb->local_port) &&
ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) {
/* this address/port is already used */
return NULL;
lpcb = NULL;
res = ERR_USE;
goto done;
}
}
}
#endif /* SO_REUSE */
lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN);
if (lpcb == NULL) {
return NULL;
res = ERR_MEM;
goto done;
}
lpcb->callback_arg = pcb->callback_arg;
lpcb->local_port = pcb->local_port;
@ -691,6 +719,11 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
tcp_backlog_set(lpcb, backlog);
#endif /* TCP_LISTEN_BACKLOG */
TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb);
res = ERR_OK;
done:
if (err != NULL) {
*err = res;
}
return (struct tcp_pcb *)lpcb;
}
@ -826,7 +859,7 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port,
u32_t iss;
u16_t old_local_port;
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
return ERR_VAL;
}
@ -880,10 +913,11 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port,
#endif /* SO_REUSE */
}
iss = tcp_next_iss();
iss = tcp_next_iss(pcb);
pcb->rcv_nxt = 0;
pcb->snd_nxt = iss;
pcb->lastack = iss - 1;
pcb->snd_wl2 = iss - 1;
pcb->snd_lbb = iss - 1;
/* Start with a window that does not need scaling. When window scaling is
enabled and used, the window is enlarged when both sides agree on scaling. */
@ -1491,7 +1525,6 @@ struct tcp_pcb *
tcp_alloc(u8_t prio)
{
struct tcp_pcb *pcb;
u32_t iss;
pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);
if (pcb == NULL) {
@ -1554,11 +1587,6 @@ tcp_alloc(u8_t prio)
pcb->sv = 3000 / TCP_SLOW_INTERVAL;
pcb->rtime = -1;
pcb->cwnd = 1;
iss = tcp_next_iss();
pcb->snd_wl2 = iss;
pcb->snd_nxt = iss;
pcb->lastack = iss;
pcb->snd_lbb = iss;
pcb->tmr = tcp_ticks;
pcb->last_timer = tcp_timer_ctr;
@ -1826,12 +1854,18 @@ tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
* @return u32_t pseudo random sequence number
*/
u32_t
tcp_next_iss(void)
tcp_next_iss(struct tcp_pcb *pcb)
{
#ifdef LWIP_HOOK_TCP_ISN
return LWIP_HOOK_TCP_ISN(&pcb->local_ip, pcb->local_port, &pcb->remote_ip, pcb->remote_port);
#else /* LWIP_HOOK_TCP_ISN */
static u32_t iss = 6510;
LWIP_UNUSED_ARG(pcb);
iss += tcp_ticks; /* XXX */
return iss;
#endif /* LWIP_HOOK_TCP_ISN */
}
#if TCP_CALCULATE_EFF_SEND_MSS

View File

@ -358,6 +358,11 @@ tcp_input(struct pbuf *p, struct netif *inp)
((pcb->refused_data != NULL) && (tcplen > 0))) {
/* pcb has been aborted or refused data is still refused and the new
segment contains data */
if (pcb->rcv_ann_wnd == 0) {
/* this is a zero-window probe, we respond to it with current RCV.NXT
and drop the data segment */
tcp_send_empty_ack(pcb);
}
TCP_STATS_INC(tcp.drop);
MIB2_STATS_INC(mib2.tcpinerrs);
goto aborted;
@ -542,6 +547,7 @@ static void
tcp_listen_input(struct tcp_pcb_listen *pcb)
{
struct tcp_pcb *npcb;
u32_t iss;
err_t rc;
if (flags & TCP_RST) {
@ -589,6 +595,11 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
npcb->state = SYN_RCVD;
npcb->rcv_nxt = seqno + 1;
npcb->rcv_ann_right_edge = npcb->rcv_nxt;
iss = tcp_next_iss(npcb);
npcb->snd_wl2 = iss;
npcb->snd_nxt = iss;
npcb->lastack = iss;
npcb->snd_lbb = iss;
npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
npcb->callback_arg = pcb->callback_arg;
#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG
@ -602,7 +613,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
/* Parse any options in the SYN. */
tcp_parseopt(npcb);
npcb->snd_wnd = SND_WND_SCALE(npcb, tcphdr->wnd);
npcb->snd_wnd = tcphdr->wnd;
npcb->snd_wnd_max = npcb->snd_wnd;
npcb->ssthresh = LWIP_TCP_INITIAL_SSTHRESH(npcb);
@ -751,7 +762,7 @@ tcp_process(struct tcp_pcb *pcb)
pcb->rcv_nxt = seqno + 1;
pcb->rcv_ann_right_edge = pcb->rcv_nxt;
pcb->lastack = ackno;
pcb->snd_wnd = SND_WND_SCALE(pcb, tcphdr->wnd);
pcb->snd_wnd = tcphdr->wnd;
pcb->snd_wnd_max = pcb->snd_wnd;
pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
pcb->state = ESTABLISHED;

View File

@ -377,6 +377,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
u16_t oversize = 0;
u16_t oversize_used = 0;
#endif /* TCP_OVERSIZE */
u16_t extendlen = 0;
#if TCP_CHECKSUM_ON_COPY
u16_t concat_chksum = 0;
u8_t concat_chksum_swapped = 0;
@ -480,6 +481,10 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
/*
* Phase 2: Chain a new pbuf to the end of pcb->unsent.
*
* As an exception when NOT copying the data, if the given data buffer
* directly follows the last unsent data buffer in memory, extend the last
* ROM pbuf reference to the buffer, thus saving a ROM pbuf allocation.
*
* We don't extend segments containing SYN/FIN flags or options
* (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at
* the end.
@ -506,25 +511,34 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
#if TCP_CHECKSUM_ON_COPY
concat_chksummed += seglen;
#endif /* TCP_CHECKSUM_ON_COPY */
queuelen += pbuf_clen(concat_p);
} else {
/* Data is not copied */
/* If the last unsent pbuf is of type PBUF_ROM, try to extend it. */
struct pbuf *p;
for (p = last_unsent->p; p->next != NULL; p = p->next);
if (p->type == PBUF_ROM && (const u8_t *)p->payload + p->len == (const u8_t *)arg) {
LWIP_ASSERT("tcp_write: ROM pbufs cannot be oversized", pos == 0);
extendlen = seglen;
} else {
if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("tcp_write: could not allocate memory for zero-copy pbuf\n"));
goto memerr;
}
/* reference the non-volatile payload data */
((struct pbuf_rom*)concat_p)->payload = (const u8_t*)arg + pos;
queuelen += pbuf_clen(concat_p);
}
#if TCP_CHECKSUM_ON_COPY
/* calculate the checksum of nocopy-data */
tcp_seg_add_chksum(~inet_chksum((const u8_t*)arg + pos, seglen), seglen,
&concat_chksum, &concat_chksum_swapped);
concat_chksummed += seglen;
#endif /* TCP_CHECKSUM_ON_COPY */
/* reference the non-volatile payload data */
((struct pbuf_rom*)concat_p)->payload = (const u8_t*)arg + pos;
}
pos += seglen;
queuelen += pbuf_clen(concat_p);
}
} else {
#if TCP_OVERSIZE
@ -669,15 +683,30 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
#endif /* TCP_OVERSIZE */
/*
* Phase 2: concat_p can be concatenated onto last_unsent->p
* Phase 2: concat_p can be concatenated onto last_unsent->p, unless we
* determined that the last ROM pbuf can be extended to include the new data.
*/
if (concat_p != NULL) {
LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty",
(last_unsent != NULL));
pbuf_cat(last_unsent->p, concat_p);
last_unsent->len += concat_p->tot_len;
} else if (extendlen > 0) {
struct pbuf *p;
LWIP_ASSERT("tcp_write: extension of reference requires reference",
last_unsent != NULL && last_unsent->p != NULL);
for (p = last_unsent->p; p->next != NULL; p = p->next) {
p->tot_len += extendlen;
}
p->tot_len += extendlen;
p->len += extendlen;
last_unsent->len += extendlen;
}
#if TCP_CHECKSUM_ON_COPY
if (concat_chksummed) {
LWIP_ASSERT("tcp_write: concat checksum needs concatenated data",
concat_p != NULL || extendlen > 0);
/*if concat checksumm swapped - swap it back */
if (concat_chksum_swapped) {
concat_chksum = SWAP_BYTES_IN_WORD(concat_chksum);
@ -687,7 +716,6 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED;
}
#endif /* TCP_CHECKSUM_ON_COPY */
}
/*
* Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that
@ -1033,6 +1061,24 @@ tcp_output(struct tcp_pcb *pcb)
lwip_ntohl(seg->tcphdr->seqno), pcb->lastack));
}
#endif /* TCP_CWND_DEBUG */
/* Check if we need to start the persistent timer when the next unsent segment
* does not fit within the remaining send window and RTO timer is not running (we
* have no in-flight data). A traditional approach would fill the remaining window
* with part of the unsent segment (which will engage zero-window probing upon
* reception of the zero window update from the receiver). This ensures the
* subsequent window update is reliably received. With the goal of being lightweight,
* we avoid splitting the unsent segment and treat the window as already zero.
*/
if (seg != NULL &&
lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd &&
wnd > 0 && wnd == pcb->snd_wnd && pcb->unacked == NULL) {
/* Start the persist timer */
if (pcb->persist_backoff == 0) {
pcb->persist_cnt = 0;
pcb->persist_backoff = 1;
}
goto output_done;
}
/* data available and window allows it to be sent? */
while (seg != NULL &&
lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
@ -1112,6 +1158,7 @@ tcp_output(struct tcp_pcb *pcb)
}
seg = pcb->unsent;
}
output_done:
#if TCP_OVERSIZE
if (pcb->unsent == NULL) {
/* last unsent has been removed, reset unsent_oversize */

View File

@ -179,7 +179,7 @@ void sys_timeouts_init(void)
for (i = 1; i < LWIP_ARRAYSIZE(lwip_cyclic_timers); i++) {
/* we have to cast via size_t to get rid of const warning
(this is OK as cyclic_timer() casts back to const* */
sys_timeout(lwip_cyclic_timers[i].interval_ms, cyclic_timer, (void*)(size_t)&lwip_cyclic_timers[i]);
sys_timeout(lwip_cyclic_timers[i].interval_ms, cyclic_timer, LWIP_CONST_CAST(void*, &lwip_cyclic_timers[i]));
}
/* Initialise timestamp for sys_check_timeouts */

View File

@ -116,24 +116,6 @@ again:
}
}
return udp_port;
#if 0
struct udp_pcb *ipcb = udp_pcbs;
while ((ipcb != NULL) && (udp_port != UDP_LOCAL_PORT_RANGE_END)) {
if (ipcb->local_port == udp_port) {
/* port is already used by another udp_pcb */
udp_port++;
/* restart scanning all udp pcbs */
ipcb = udp_pcbs;
} else {
/* go on with next udp pcb */
ipcb = ipcb->next;
}
}
if (ipcb != NULL) {
return 0;
}
return udp_port;
#endif
}
/** Common code to see if the current input packet matches the pcb
@ -178,15 +160,8 @@ udp_input_local_match(struct udp_pcb *pcb, struct netif *inp, u8_t broadcast)
}
} else
#endif /* LWIP_IPV4 */
/* Handle IPv4 and IPv6: all, multicast or exact match */
if (ip_addr_isany(&pcb->local_ip) ||
#if LWIP_IPV6_MLD
(ip_current_is_v6() && ip6_addr_ismulticast(ip6_current_dest_addr())) ||
#endif /* LWIP_IPV6_MLD */
#if LWIP_IGMP
(!ip_current_is_v6() && ip4_addr_ismulticast(ip4_current_dest_addr())) ||
#endif /* LWIP_IGMP */
ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) {
/* Handle IPv4 and IPv6: all or exact match */
if (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) {
return 1;
}
}
@ -429,7 +404,7 @@ udp_input(struct pbuf *p, struct netif *inp)
destination address was broadcast/multicast. */
if (!broadcast && !ip_addr_ismulticast(ip_current_dest_addr())) {
/* move payload pointer back to ip header */
pbuf_header_force(p, ip_current_header_tot_len() + UDP_HLEN);
pbuf_header_force(p, (s16_t)(ip_current_header_tot_len() + UDP_HLEN));
icmp_port_unreach(ip_current_is_v6(), p);
}
#endif /* LWIP_ICMP || LWIP_ICMP6 */
@ -571,7 +546,12 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip,
#endif /* LWIP_IPV6 || (LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS) */
/* find the outgoing network interface for this packet */
if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
/* Don't call ip_route() with IP_ANY_TYPE */
netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(dst_ip_route)), dst_ip_route);
} else {
netif = ip_route(&pcb->local_ip, dst_ip_route);
}
/* no outgoing network interface could be found? */
if (netif == NULL) {
@ -662,7 +642,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_i
* this could be an old address if netif->ip_addr has changed */
if (!ip4_addr_cmp(ip_2_ip4(&(pcb->local_ip)), netif_ip4_addr(netif))) {
/* local_ip doesn't match, drop the packet */
return ERR_VAL;
return ERR_RTE;
}
/* use UDP PCB local IP address as source address */
src_ip = &pcb->local_ip;
@ -912,7 +892,7 @@ udp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port)
#endif /* LWIP_IPV4 */
/* still need to check for ipaddr == NULL in IPv6 only case */
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
return ERR_VAL;
}

View File

@ -43,8 +43,7 @@
/* Note: Netconn API is always available when sockets are enabled -
* sockets are implemented on top of them */
#include <stddef.h> /* for size_t */
#include "lwip/arch.h"
#include "lwip/netbuf.h"
#include "lwip/sys.h"
#include "lwip/ip_addr.h"
@ -90,6 +89,7 @@ extern "C" {
#define NETCONNTYPE_ISUDPLITE(t) (((t)&0xF3) == NETCONN_UDPLITE)
#define NETCONNTYPE_ISUDPNOCHKSUM(t) (((t)&0xF3) == NETCONN_UDPNOCHKSUM)
#else /* LWIP_IPV6 */
#define NETCONNTYPE_ISIPV6(t) (0)
#define NETCONNTYPE_ISUDPLITE(t) ((t) == NETCONN_UDPLITE)
#define NETCONNTYPE_ISUDPNOCHKSUM(t) ((t) == NETCONN_UDPNOCHKSUM)
#endif /* LWIP_IPV6 */

View File

@ -31,7 +31,7 @@
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Erik Ekman <erik.ekman@verisure.com>
* Author: Erik Ekman <erik@kryo.se>
*
*/
#ifndef LWIP_HDR_MDNS_H

View File

@ -31,7 +31,7 @@
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Erik Ekman <erik.ekman@verisure.com>
* Author: Erik Ekman <erik@kryo.se>
*
*/

View File

@ -31,7 +31,7 @@
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Erik Ekman <erik.ekman@verisure.com>
* Author: Erik Ekman <erik@kryo.se>
*
*/
#ifndef LWIP_HDR_MDNS_PRIV_H

View File

@ -0,0 +1,243 @@
/**
* @file
* MQTT client
*/
/*
* Copyright (c) 2016 Erik Andersson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Erik Andersson
*
*/
#ifndef LWIP_HDR_APPS_MQTT_CLIENT_H
#define LWIP_HDR_APPS_MQTT_CLIENT_H
#include "lwip/apps/mqtt_opts.h"
#include "lwip/err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct mqtt_client_t mqtt_client_t;
/** @ingroup mqtt
* Default MQTT port */
#define MQTT_PORT 1883
/*---------------------------------------------------------------------------------------------- */
/* Connection with server */
/**
* @ingroup mqtt
* Client information and connection parameters */
struct mqtt_connect_client_info_t {
/** Client identifier, must be set by caller */
const char *client_id;
/** User name and password, set to NULL if not used */
const char* client_user;
const char* client_pass;
/** keep alive time in seconds, 0 to disable keep alive functionality*/
u16_t keep_alive;
/** will topic, set to NULL if will is not to be used,
will_msg, will_qos and will retain are then ignored */
const char* will_topic;
const char* will_msg;
u8_t will_qos;
u8_t will_retain;
};
/**
* @ingroup mqtt
* Connection status codes */
typedef enum
{
MQTT_CONNECT_ACCEPTED = 0,
MQTT_CONNECT_REFUSED_PROTOCOL_VERSION = 1,
MQTT_CONNECT_REFUSED_IDENTIFIER = 2,
MQTT_CONNECT_REFUSED_SERVER = 3,
MQTT_CONNECT_REFUSED_USERNAME_PASS = 4,
MQTT_CONNECT_REFUSED_NOT_AUTHORIZED_ = 5,
MQTT_CONNECT_DISCONNECTED = 256,
MQTT_CONNECT_TIMEOUT = 257
} mqtt_connection_status_t;
/**
* @ingroup mqtt
* Function prototype for mqtt connection status callback. Called when
* client has connected to the server after initiating a mqtt connection attempt by
* calling mqtt_connect() or when connection is closed by server or an error
*
* @param client MQTT client itself
* @param arg Additional argument to pass to the callback function
* @param status Connect result code or disconnection notification @see mqtt_connection_status_t
*
*/
typedef void (*mqtt_connection_cb_t)(mqtt_client_t *client, void *arg, mqtt_connection_status_t status);
/**
* @ingroup mqtt
* Data callback flags */
enum {
/** Flag set when last fragment of data arrives in data callback */
MQTT_DATA_FLAG_LAST = 1
};
/**
* @ingroup mqtt
* Function prototype for MQTT incoming publish data callback function. Called when data
* arrives to a subscribed topic @see mqtt_subscribe
*
* @param arg Additional argument to pass to the callback function
* @param data User data, pointed object, data may not be referenced after callback return,
NULL is passed when all publish data are delivered
* @param len Length of publish data fragment
* @param flags MQTT_DATA_FLAG_LAST set when this call contains the last part of data from publish message
*
*/
typedef void (*mqtt_incoming_data_cb_t)(void *arg, const u8_t *data, u16_t len, u8_t flags);
/**
* @ingroup mqtt
* Function prototype for MQTT incoming publish function. Called when an incoming publish
* arrives to a subscribed topic @see mqtt_subscribe
*
* @param arg Additional argument to pass to the callback function
* @param topic Zero terminated Topic text string, topic may not be referenced after callback return
* @param tot_len Total length of publish data, if set to 0 (no publish payload) data callback will not be invoked
*/
typedef void (*mqtt_incoming_publish_cb_t)(void *arg, const char *topic, u32_t tot_len);
/**
* @ingroup mqtt
* Function prototype for mqtt request callback. Called when a subscribe, unsubscribe
* or publish request has completed
* @param arg Pointer to user data supplied when invoking request
* @param err ERR_OK on success
* ERR_TIMEOUT if no response was received within timeout,
* ERR_ABRT if (un)subscribe was denied
*/
typedef void (*mqtt_request_cb_t)(void *arg, err_t err);
/**
* Pending request item, binds application callback to pending server requests
*/
struct mqtt_request_t
{
/** Next item in list, NULL means this is the last in chain,
next pointing at itself means request is unallocated */
struct mqtt_request_t *next;
/** Callback to upper layer */
mqtt_request_cb_t cb;
void *arg;
/** MQTT packet identifier */
u16_t pkt_id;
/** Expire time relative to element before this */
u16_t timeout_diff;
};
/** Ring buffer */
struct mqtt_ringbuf_t {
u16_t put;
u16_t get;
u8_t buf[MQTT_OUTPUT_RINGBUF_SIZE];
};
/** MQTT client */
struct mqtt_client_t
{
/** Timers and timeouts */
u16_t cyclic_tick;
u16_t keep_alive;
u16_t server_watchdog;
/** Packet identifier generator*/
u16_t pkt_id_seq;
/** Packet identifier of pending incoming publish */
u16_t inpub_pkt_id;
/** Connection state */
u8_t conn_state;
struct tcp_pcb *conn;
/** Connection callback */
void *connect_arg;
mqtt_connection_cb_t connect_cb;
/** Pending requests to server */
struct mqtt_request_t *pend_req_queue;
struct mqtt_request_t req_list[MQTT_REQ_MAX_IN_FLIGHT];
void *inpub_arg;
/** Incoming data callback */
mqtt_incoming_data_cb_t data_cb;
mqtt_incoming_publish_cb_t pub_cb;
/** Input */
u32_t msg_idx;
u8_t rx_buffer[MQTT_VAR_HEADER_BUFFER_LEN];
/** Output ring-buffer */
struct mqtt_ringbuf_t output;
};
/** Connect to server */
err_t mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ipaddr, u16_t port, mqtt_connection_cb_t cb, void *arg,
const struct mqtt_connect_client_info_t *client_info);
/** Disconnect from server */
void mqtt_disconnect(mqtt_client_t *client);
/** Create new client */
mqtt_client_t *mqtt_client_new(void);
/** Check connection status */
u8_t mqtt_client_is_connected(mqtt_client_t *client);
/** Set callback to call for incoming publish */
void mqtt_set_inpub_callback(mqtt_client_t *client, mqtt_incoming_publish_cb_t,
mqtt_incoming_data_cb_t data_cb, void *arg);
/** Common function for subscribe and unsubscribe */
err_t mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_request_cb_t cb, void *arg, u8_t sub);
/** @ingroup mqtt
*Subscribe to topic */
#define mqtt_subscribe(client, topic, qos, cb, arg) mqtt_sub_unsub(client, topic, qos, cb, arg, 1)
/** @ingroup mqtt
* Unsubscribe to topic */
#define mqtt_unsubscribe(client, topic, cb, arg) mqtt_sub_unsub(client, topic, 0, cb, arg, 0)
/** Publish data to topic */
err_t mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_t payload_length, u8_t qos, u8_t retain,
mqtt_request_cb_t cb, void *arg);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_HDR_APPS_MQTT_CLIENT_H */

View File

@ -0,0 +1,103 @@
/**
* @file
* MQTT client options
*/
/*
* Copyright (c) 2016 Erik Andersson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Erik Andersson
*
*/
#ifndef LWIP_HDR_APPS_MQTT_OPTS_H
#define LWIP_HDR_APPS_MQTT_OPTS_H
#include "lwip/opt.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup mqtt_opts Options
* @ingroup mqtt
* @{
*/
/**
* Output ring-buffer size, must be able to fit largest outgoing publish message topic+payloads
*/
#ifndef MQTT_OUTPUT_RINGBUF_SIZE
#define MQTT_OUTPUT_RINGBUF_SIZE 256
#endif
/**
* Number of bytes in receive buffer, must be at least the size of the longest incoming topic + 8
* If one wants to avoid fragmented incoming publish, set length to max incoming topic length + max payload length + 8
*/
#ifndef MQTT_VAR_HEADER_BUFFER_LEN
#define MQTT_VAR_HEADER_BUFFER_LEN 128
#endif
/**
* Maximum number of pending subscribe, unsubscribe and publish requests to server .
*/
#ifndef MQTT_REQ_MAX_IN_FLIGHT
#define MQTT_REQ_MAX_IN_FLIGHT 4
#endif
/**
* Seconds between each cyclic timer call.
*/
#ifndef MQTT_CYCLIC_TIMER_INTERVAL
#define MQTT_CYCLIC_TIMER_INTERVAL 5
#endif
/**
* Publish, subscribe and unsubscribe request timeout in seconds.
*/
#ifndef MQTT_REQ_TIMEOUT
#define MQTT_REQ_TIMEOUT 30
#endif
/**
* Seconds for MQTT connect response timeout after sending connect request
*/
#ifndef MQTT_CONNECT_TIMOUT
#define MQTT_CONNECT_TIMOUT 100
#endif
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* LWIP_HDR_APPS_MQTT_OPTS_H */

View File

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

View File

@ -88,6 +88,8 @@ u8_t autoip_supplied_address(const struct netif *netif);
/* for lwIP internal use by ip4.c */
u8_t autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr);
#define netif_autoip_data(netif) ((struct autoip*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP))
#ifdef __cplusplus
}
#endif

View File

@ -40,24 +40,45 @@
#include "lwip/arch.h"
#include "lwip/opt.h"
/** lower two bits indicate debug level
* - 0 all
* - 1 warning
* - 2 serious
* - 3 severe
/**
* @defgroup debugging_levels LWIP_DBG_MIN_LEVEL and LWIP_DBG_TYPES_ON values
* @ingroup lwip_opts_debugmsg
* @{
*/
#define LWIP_DBG_LEVEL_ALL 0x00
#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL /* compatibility define only */
#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */
#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */
#define LWIP_DBG_LEVEL_SEVERE 0x03
#define LWIP_DBG_MASK_LEVEL 0x03
/** @name Debug level (LWIP_DBG_MIN_LEVEL)
* @{
*/
/** Debug level: ALL messages*/
#define LWIP_DBG_LEVEL_ALL 0x00
/** Debug level: Warnings. bad checksums, dropped packets, ... */
#define LWIP_DBG_LEVEL_WARNING 0x01
/** Debug level: Serious. memory allocation failures, ... */
#define LWIP_DBG_LEVEL_SERIOUS 0x02
/** Debug level: Severe */
#define LWIP_DBG_LEVEL_SEVERE 0x03
/**
* @}
*/
#define LWIP_DBG_MASK_LEVEL 0x03
/* compatibility define only */
#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL
/** @name Enable/disable debug messages completely (LWIP_DBG_TYPES_ON)
* @{
*/
/** flag for LWIP_DEBUGF to enable that debug message */
#define LWIP_DBG_ON 0x80U
/** flag for LWIP_DEBUGF to disable that debug message */
#define LWIP_DBG_OFF 0x00U
/**
* @}
*/
/** @name Debug message types (LWIP_DBG_TYPES_ON)
* @{
*/
/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */
#define LWIP_DBG_TRACE 0x40U
/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */
@ -66,11 +87,31 @@
#define LWIP_DBG_FRESH 0x10U
/** flag for LWIP_DEBUGF to halt after printing this debug message */
#define LWIP_DBG_HALT 0x08U
/**
* @}
*/
/**
* LWIP_NOASSERT: Disable LWIP_ASSERT checks.
* -- To disable assertions define LWIP_NOASSERT in arch/cc.h.
* @}
*/
/**
* @defgroup lwip_assertions Assertion handling
* @ingroup lwip_opts_debug
* @{
*/
/**
* LWIP_NOASSERT: Disable LWIP_ASSERT checks:
* To disable assertions define LWIP_NOASSERT in arch/cc.h.
*/
#ifdef __DOXYGEN__
#define LWIP_NOASSERT
#undef LWIP_NOASSERT
#endif
/**
* @}
*/
#ifndef LWIP_NOASSERT
#define LWIP_ASSERT(message, assertion) do { if (!(assertion)) { \
LWIP_PLATFORM_ASSERT(message); }} while(0)
@ -81,7 +122,6 @@
#define LWIP_ASSERT(message, assertion)
#endif /* LWIP_NOASSERT */
/** if "expression" isn't true, then print "message" and execute "handler" expression */
#ifndef LWIP_ERROR
#ifndef LWIP_NOASSERT
#define LWIP_PLATFORM_ERROR(message) LWIP_PLATFORM_ASSERT(message)
@ -91,17 +131,23 @@
#define LWIP_PLATFORM_ERROR(message)
#endif
/* if "expression" isn't true, then print "message" and execute "handler" expression */
#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
LWIP_PLATFORM_ERROR(message); handler;}} while(0)
#endif /* LWIP_ERROR */
/** Enable debug message printing, but only if debug message type is enabled
* AND is of correct type AND is at least LWIP_DBG_LEVEL.
*/
#ifdef __DOXYGEN__
#define LWIP_DEBUG
#undef LWIP_DEBUG
#endif
#ifdef LWIP_DEBUG
#ifndef LWIP_PLATFORM_DIAG
#error "If you want to use LWIP_DEBUG, LWIP_PLATFORM_DIAG(message) needs to be defined in your arch/cc.h"
#endif
/** print debug message only if debug message type is enabled...
* AND is of correct type AND is at least LWIP_DBG_LEVEL
*/
#define LWIP_DEBUGF(debug, message) do { \
if ( \
((debug) & LWIP_DBG_ON) && \
@ -119,4 +165,3 @@
#endif /* LWIP_DEBUG */
#endif /* LWIP_HDR_DEBUG_H */

View File

@ -57,6 +57,12 @@ extern "C" {
/* Get the number of entries in an array ('x' must NOT be a pointer!) */
#define LWIP_ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0]))
/** Create u32_t value from bytes */
#define LWIP_MAKEU32(a,b,c,d) (((u32_t)((a) & 0xff) << 24) | \
((u32_t)((b) & 0xff) << 16) | \
((u32_t)((c) & 0xff) << 8) | \
(u32_t)((d) & 0xff))
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
@ -65,13 +71,6 @@ extern "C" {
#endif
#endif
/* Endianess-optimized shifting of two u8_t to create one u16_t */
#if BYTE_ORDER == LITTLE_ENDIAN
#define LWIP_MAKE_U16(a, b) ((a << 8) | b)
#else
#define LWIP_MAKE_U16(a, b) ((b << 8) | a)
#endif
#if BYTE_ORDER == BIG_ENDIAN
#define lwip_htons(x) (x)
#define lwip_ntohs(x) (x)
@ -103,11 +102,11 @@ u32_t lwip_htonl(u32_t x);
/* These macros should be calculated by the preprocessor and are used
with compile-time constants only (so that there is no little-endian
overhead at runtime). */
#define PP_HTONS(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
#define PP_HTONS(x) ((((x) & 0x00ffUL) << 8) | (((x) & 0xff00UL) >> 8))
#define PP_NTOHS(x) PP_HTONS(x)
#define PP_HTONL(x) ((((x) & 0xff) << 24) | \
(((x) & 0xff00) << 8) | \
(((x) & 0xff0000UL) >> 8) | \
#define PP_HTONL(x) ((((x) & 0x000000ffUL) << 24) | \
(((x) & 0x0000ff00UL) << 8) | \
(((x) & 0x00ff0000UL) >> 8) | \
(((x) & 0xff000000UL) >> 24))
#define PP_NTOHL(x) PP_HTONL(x)

View File

@ -132,6 +132,8 @@ void dhcp_fine_tmr(void);
extern void dhcp_set_ntp_servers(u8_t num_ntp_servers, const ip4_addr_t* ntp_server_addrs);
#endif /* LWIP_DHCP_GET_NTP_SRV */
#define netif_dhcp_data(netif) ((struct dhcp*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP))
#ifdef __cplusplus
}
#endif

View File

@ -61,7 +61,7 @@ extern "C" {
#ifndef LWIP_DNS_ADDRTYPE_DEFAULT
#define LWIP_DNS_ADDRTYPE_DEFAULT LWIP_DNS_ADDRTYPE_IPV4_IPV6
#endif
#elif defined(LWIP_IPV4)
#elif LWIP_IPV4
#define LWIP_DNS_ADDRTYPE_DEFAULT LWIP_DNS_ADDRTYPE_IPV4
#else
#define LWIP_DNS_ADDRTYPE_DEFAULT LWIP_DNS_ADDRTYPE_IPV6
@ -84,6 +84,13 @@ struct local_hostlist_entry {
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
#endif /* DNS_LOCAL_HOSTLIST */
#if LWIP_IPV4
extern const ip_addr_t dns_mquery_v4group;
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
extern const ip_addr_t dns_mquery_v6group;
#endif /* LWIP_IPV6 */
/** Callback which is invoked when a hostname is found.
* A function of this type must be implemented by the application using the DNS resolver.
* @param name pointer to the name that was looked up.

View File

@ -45,99 +45,12 @@
#include "lwip/pbuf.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
#include "lwip/prot/icmp6.h"
#ifdef __cplusplus
extern "C" {
#endif
/** ICMP type */
enum icmp6_type {
/** Destination unreachable */
ICMP6_TYPE_DUR = 1,
/** Packet too big */
ICMP6_TYPE_PTB = 2,
/** Time exceeded */
ICMP6_TYPE_TE = 3,
/** Parameter problem */
ICMP6_TYPE_PP = 4,
/** Private experimentation */
ICMP6_TYPE_PE1 = 100,
/** Private experimentation */
ICMP6_TYPE_PE2 = 101,
/** Reserved for expansion of error messages */
ICMP6_TYPE_RSV_ERR = 127,
/** Echo request */
ICMP6_TYPE_EREQ = 128,
/** Echo reply */
ICMP6_TYPE_EREP = 129,
/** Multicast listener query */
ICMP6_TYPE_MLQ = 130,
/** Multicast listener report */
ICMP6_TYPE_MLR = 131,
/** Multicast listener done */
ICMP6_TYPE_MLD = 132,
/** Router solicitation */
ICMP6_TYPE_RS = 133,
/** Router advertisement */
ICMP6_TYPE_RA = 134,
/** Neighbor solicitation */
ICMP6_TYPE_NS = 135,
/** Neighbor advertisement */
ICMP6_TYPE_NA = 136,
/** Redirect */
ICMP6_TYPE_RD = 137,
/** Multicast router advertisement */
ICMP6_TYPE_MRA = 151,
/** Multicast router solicitation */
ICMP6_TYPE_MRS = 152,
/** Multicast router termination */
ICMP6_TYPE_MRT = 153,
/** Private experimentation */
ICMP6_TYPE_PE3 = 200,
/** Private experimentation */
ICMP6_TYPE_PE4 = 201,
/** Reserved for expansion of informational messages */
ICMP6_TYPE_RSV_INF = 255
};
/** ICMP destination unreachable codes */
enum icmp6_dur_code {
/** No route to destination */
ICMP6_DUR_NO_ROUTE = 0,
/** Communication with destination administratively prohibited */
ICMP6_DUR_PROHIBITED = 1,
/** Beyond scope of source address */
ICMP6_DUR_SCOPE = 2,
/** Address unreachable */
ICMP6_DUR_ADDRESS = 3,
/** Port unreachable */
ICMP6_DUR_PORT = 4,
/** Source address failed ingress/egress policy */
ICMP6_DUR_POLICY = 5,
/** Reject route to destination */
ICMP6_DUR_REJECT_ROUTE = 6
};
/** ICMP time exceeded codes */
enum icmp6_te_code {
/** Hop limit exceeded in transit */
ICMP6_TE_HL = 0,
/** Fragment reassembly time exceeded */
ICMP6_TE_FRAG = 1
};
/** ICMP parameter code */
enum icmp6_pp_code {
/** Erroneous header field encountered */
ICMP6_PP_FIELD = 0,
/** Unrecognized next header type encountered */
ICMP6_PP_HEADER = 1,
/** Unrecognized IPv6 option encountered */
ICMP6_PP_OPTION = 2
};
#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
void icmp6_input(struct pbuf *p, struct netif *inp);

View File

@ -132,10 +132,10 @@ extern const struct in6_addr in6addr_any;
#if LWIP_IPV4
#define inet_addr_from_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr))
#define inet_addr_to_ipaddr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr))
#define inet_addr_from_ip4addr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr))
#define inet_addr_to_ip4addr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr))
/* ATTENTION: the next define only works because both s_addr and ip4_addr_t are an u32_t effectively! */
#define inet_addr_to_ipaddr_p(target_ip4addr_p, source_inaddr) ((target_ip4addr_p) = (ip4_addr_t*)&((source_inaddr)->s_addr))
#define inet_addr_to_ip4addr_p(target_ip4addr_p, source_inaddr) ((target_ip4addr_p) = (ip4_addr_t*)&((source_inaddr)->s_addr))
/* directly map this to the lwip internal functions */
#define inet_addr(cp) ipaddr_addr(cp)

View File

@ -54,11 +54,11 @@ extern "C" {
/** x.X.x: Minor version of the stack */
#define LWIP_VERSION_MINOR 0
/** x.x.X: Revision of the stack */
#define LWIP_VERSION_REVISION 0
#define LWIP_VERSION_REVISION 1
/** For release candidates, this is set to 1..254
* For official releases, this is set to 255 (LWIP_RC_RELEASE)
* For development versions (Git), this is set to 0 (LWIP_RC_DEVELOPMENT) */
#define LWIP_VERSION_RC LWIP_RC_RELEASE
#define LWIP_VERSION_RC LWIP_RC_DEVELOPMENT
/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */
#define LWIP_RC_RELEASE 255

View File

@ -52,24 +52,9 @@ struct ip4_addr {
u32_t addr;
};
/** This is the packed version of ip4_addr_t,
used in network headers that are itself packed */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip4_addr_packed {
PACK_STRUCT_FIELD(u32_t addr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** ip4_addr_t uses a struct for convenience only, so that the same defines can
* operate both on ip4_addr_t as well as on ip4_addr_p_t. */
typedef struct ip4_addr ip4_addr_t;
typedef struct ip4_addr_packed ip4_addr_p_t;
/**
* struct ipaddr2 is used in the definition of the ARP packet format in
@ -131,23 +116,8 @@ struct netif;
#define IP_LOOPBACKNET 127 /* official! */
#if BYTE_ORDER == BIG_ENDIAN
/** Set an IP address given by the four byte-parts */
#define IP4_ADDR(ipaddr, a,b,c,d) \
(ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \
((u32_t)((b) & 0xff) << 16) | \
((u32_t)((c) & 0xff) << 8) | \
(u32_t)((d) & 0xff)
#else
/** Set an IP address given by the four byte-parts.
Little-endian version that prevents the use of lwip_htonl. */
#define IP4_ADDR(ipaddr, a,b,c,d) \
(ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \
((u32_t)((c) & 0xff) << 16) | \
((u32_t)((b) & 0xff) << 8) | \
(u32_t)((a) & 0xff)
#endif
#define IP4_ADDR(ipaddr, a,b,c,d) (ipaddr)->addr = PP_HTONL(LWIP_MAKEU32(a,b,c,d))
/** MEMCPY-like copying of IP addresses where addresses are known to be
* 16-bit-aligned if the port is correctly configured (so a port could define

View File

@ -43,6 +43,7 @@
#define LWIP_HDR_IP6_ADDR_H
#include "lwip/opt.h"
#include "def.h"
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
@ -58,41 +59,12 @@ struct ip6_addr {
u32_t addr[4];
};
/** This is the packed version of ip6_addr_t,
used in network headers that are itself packed */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip6_addr_packed {
PACK_STRUCT_FIELD(u32_t addr[4]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** IPv6 address */
typedef struct ip6_addr ip6_addr_t;
typedef struct ip6_addr_packed ip6_addr_p_t;
#if BYTE_ORDER == BIG_ENDIAN
/** Set an IPv6 partial address given by byte-parts. */
/** Set an IPv6 partial address given by byte-parts */
#define IP6_ADDR_PART(ip6addr, index, a,b,c,d) \
(ip6addr)->addr[index] = ((u32_t)((a) & 0xff) << 24) | \
((u32_t)((b) & 0xff) << 16) | \
((u32_t)((c) & 0xff) << 8) | \
(u32_t)((d) & 0xff)
#else
/** Set an IPv6 partial address given by byte-parts.
Little-endian version, stored in network order (no lwip_htonl). */
#define IP6_ADDR_PART(ip6addr, index, a,b,c,d) \
(ip6addr)->addr[index] = ((u32_t)((d) & 0xff) << 24) | \
((u32_t)((c) & 0xff) << 16) | \
((u32_t)((b) & 0xff) << 8) | \
(u32_t)((a) & 0xff)
#endif
(ip6addr)->addr[index] = PP_HTONL(LWIP_MAKEU32(a,b,c,d))
/** Set a full IPv6 address by passing the 4 u32_t indices in network byte order
(use PP_HTONL() for constants) */

View File

@ -66,7 +66,7 @@ enum lwip_ip_addr_type {
* A union struct for both IP version's addresses.
* ATTENTION: watch out for its size when adding IPv6 address scope!
*/
typedef struct _ip_addr {
typedef struct ip_addr {
union {
ip6_addr_t ip6;
ip4_addr_t ip4;
@ -79,8 +79,12 @@ extern const ip_addr_t ip_addr_any_type;
/** @ingroup ip4addr */
#define IPADDR4_INIT(u32val) { { { { u32val, 0ul, 0ul, 0ul } } }, IPADDR_TYPE_V4 }
/** @ingroup ip4addr */
#define IPADDR4_INIT_BYTES(a,b,c,d) IPADDR4_INIT(PP_HTONL(LWIP_MAKEU32(a,b,c,d)))
/** @ingroup ip6addr */
#define IPADDR6_INIT(a, b, c, d) { { { { a, b, c, d } } }, IPADDR_TYPE_V6 }
/** @ingroup ip6addr */
#define IPADDR6_INIT_HOST(a, b, c, d) { { { { PP_HTONL(a), PP_HTONL(b), PP_HTONL(c), PP_HTONL(d) } } }, IPADDR_TYPE_V6 }
/** @ingroup ipaddr */
#define IP_IS_ANY_TYPE_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_ANY)
@ -118,6 +122,8 @@ extern const ip_addr_t ip_addr_any_type;
/** @ingroup ip6addr */
#define IP_ADDR6(ipaddr,i0,i1,i2,i3) do { IP6_ADDR(ip_2_ip6(ipaddr),i0,i1,i2,i3); \
IP_SET_TYPE_VAL(*(ipaddr), IPADDR_TYPE_V6); } while(0)
/** @ingroup ip6addr */
#define IP_ADDR6_HOST(ipaddr,i0,i1,i2,i3) IP_ADDR6(ipaddr,PP_HTONL(i0),PP_HTONL(i1),PP_HTONL(i2),PP_HTONL(i3))
/** @ingroup ipaddr */
#define ip_addr_copy(dest, src) do{ IP_SET_TYPE_VAL(dest, IP_GET_TYPE(&src)); if(IP_IS_V6_VAL(src)){ \
@ -215,6 +221,19 @@ int ipaddr_aton(const char *cp, ip_addr_t *addr);
/** @ingroup ipaddr */
#define IPADDR_STRLEN_MAX IP6ADDR_STRLEN_MAX
/** @ingroup ipaddr */
#define ip4_2_ipv6_mapped_ipv4(ip6addr, ip4addr) do { \
(ip6addr)->addr[3] = (ip4addr)->addr; \
(ip6addr)->addr[2] = PP_HTONL(0x0000FFFFUL); \
(ip6addr)->addr[1] = 0; \
(ip6addr)->addr[0] = 0; } while(0);
/** @ingroup ipaddr */
#define unmap_ipv6_mapped_ipv4(ip4addr, ip6addr) \
(ip4addr)->addr = (ip6addr)->addr[3];
#define IP46_ADDR_ANY(type) (((type) == IPADDR_TYPE_V6)? IP6_ADDR_ANY : IP4_ADDR_ANY)
#else /* LWIP_IPV4 && LWIP_IPV6 */
#define IP_ADDR_PCB_VERSION_MATCH(addr, pcb) 1
@ -224,6 +243,7 @@ int ipaddr_aton(const char *cp, ip_addr_t *addr);
typedef ip4_addr_t ip_addr_t;
#define IPADDR4_INIT(u32val) { u32val }
#define IPADDR4_INIT_BYTES(a,b,c,d) IPADDR4_INIT(PP_HTONL(LWIP_MAKEU32(a,b,c,d)))
#define IP_IS_V4_VAL(ipaddr) 1
#define IP_IS_V6_VAL(ipaddr) 0
#define IP_IS_V4(ipaddr) 1
@ -263,10 +283,13 @@ typedef ip4_addr_t ip_addr_t;
#define IPADDR_STRLEN_MAX IP4ADDR_STRLEN_MAX
#define IP46_ADDR_ANY(type) (IP4_ADDR_ANY)
#else /* LWIP_IPV4 */
typedef ip6_addr_t ip_addr_t;
#define IPADDR6_INIT(a, b, c, d) { { a, b, c, d } }
#define IPADDR6_INIT_HOST(a, b, c, d) { { PP_HTONL(a), PP_HTONL(b), PP_HTONL(c), PP_HTONL(d) } }
#define IP_IS_V4_VAL(ipaddr) 0
#define IP_IS_V6_VAL(ipaddr) 1
#define IP_IS_V4(ipaddr) 0
@ -277,6 +300,7 @@ typedef ip6_addr_t ip_addr_t;
#define IP_GET_TYPE(ipaddr) IPADDR_TYPE_V6
#define ip_2_ip6(ipaddr) (ipaddr)
#define IP_ADDR6(ipaddr,i0,i1,i2,i3) IP6_ADDR(ipaddr,i0,i1,i2,i3)
#define IP_ADDR6_HOST(ipaddr,i0,i1,i2,i3) IP_ADDR6(ipaddr,PP_HTONL(i0),PP_HTONL(i1),PP_HTONL(i2),PP_HTONL(i3))
#define ip_addr_copy(dest, src) ip6_addr_copy(dest, src)
#define ip_addr_copy_from_ip6(dest, src) ip6_addr_copy(dest, src)
@ -304,6 +328,8 @@ typedef ip6_addr_t ip_addr_t;
#define IPADDR_STRLEN_MAX IP6ADDR_STRLEN_MAX
#define IP46_ADDR_ANY(type) (IP6_ADDR_ANY)
#endif /* LWIP_IPV4 */
#endif /* LWIP_IPV4 && LWIP_IPV6 */
@ -314,7 +340,13 @@ extern const ip_addr_t ip_addr_broadcast;
/**
* @ingroup ip4addr
* Provided for compatibility. Use IP4_ADDR_ANY for better readability.
* Can be used as a fixed/const ip_addr_t
* for the IP wildcard.
* Defined to @ref IP4_ADDR_ANY when IPv4 is enabled.
* Defined to @ref IP6_ADDR_ANY in IPv6 only systems.
* Use this if you can handle IPv4 _AND_ IPv6 addresses.
* Use @ref IP4_ADDR_ANY or @ref IP6_ADDR_ANY when the IP
* type matters.
*/
#define IP_ADDR_ANY IP4_ADDR_ANY
/**
@ -355,7 +387,7 @@ extern const ip_addr_t ip6_addr_any;
#define IP6_ADDR_ANY6 (ip_2_ip6(&ip6_addr_any))
#if !LWIP_IPV4
/** Just a little upgrade-helper for IPv6-only configurations: */
/** IPv6-only configurations */
#define IP_ADDR_ANY IP6_ADDR_ANY
#endif /* !LWIP_IPV4 */

View File

@ -45,7 +45,8 @@ extern "C" {
#if MEM_LIBC_MALLOC
#include <stddef.h> /* for size_t */
#include "lwip/arch.h"
typedef size_t mem_size_t;
#define MEM_SIZE_F SZT_F

View File

@ -48,107 +48,32 @@
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/pbuf.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
#include "lwip/err.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Struct for tables. */
struct nd6_neighbor_cache_entry {
ip6_addr_t next_hop_address;
struct netif *netif;
u8_t lladdr[NETIF_MAX_HWADDR_LEN];
/*u32_t pmtu;*/
#if LWIP_ND6_QUEUEING
/** Pointer to queue of pending outgoing packets on this entry. */
struct nd6_q_entry *q;
#else /* LWIP_ND6_QUEUEING */
/** Pointer to a single pending outgoing packet on this entry. */
struct pbuf *q;
#endif /* LWIP_ND6_QUEUEING */
u8_t state;
u8_t isrouter;
union {
u32_t reachable_time; /* in ms since value may originate from network packet */
u32_t delay_time; /* ticks (ND6_TMR_INTERVAL) */
u32_t probes_sent;
u32_t stale_time; /* ticks (ND6_TMR_INTERVAL) */
} counter;
};
struct nd6_destination_cache_entry {
ip6_addr_t destination_addr;
ip6_addr_t next_hop_addr;
u16_t pmtu;
u32_t age;
};
struct nd6_prefix_list_entry {
ip6_addr_t prefix;
struct netif *netif;
u32_t invalidation_timer; /* in ms since value may originate from network packet */
#if LWIP_IPV6_AUTOCONFIG
u8_t flags;
#define ND6_PREFIX_AUTOCONFIG_AUTONOMOUS 0x01
#define ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED 0x02
#define ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE 0x04
#endif /* LWIP_IPV6_AUTOCONFIG */
};
struct nd6_router_list_entry {
struct nd6_neighbor_cache_entry *neighbor_entry;
u32_t invalidation_timer; /* in ms since value may originate from network packet */
u8_t flags;
};
enum nd6_neighbor_cache_entry_state {
ND6_NO_ENTRY = 0,
ND6_INCOMPLETE,
ND6_REACHABLE,
ND6_STALE,
ND6_DELAY,
ND6_PROBE
};
#if LWIP_ND6_QUEUEING
/** struct for queueing outgoing packets for unknown address
* defined here to be accessed by memp.h
*/
struct nd6_q_entry {
struct nd6_q_entry *next;
struct pbuf *p;
};
#endif /* LWIP_ND6_QUEUEING */
/** 1 second period */
#define ND6_TMR_INTERVAL 1000
/* Router tables. */
/* @todo make these static? and entries accessible through API? */
extern struct nd6_neighbor_cache_entry neighbor_cache[];
extern struct nd6_destination_cache_entry destination_cache[];
extern struct nd6_prefix_list_entry prefix_list[];
extern struct nd6_router_list_entry default_router_list[];
/* Default values, can be updated by a RA message. */
extern u32_t reachable_time;
extern u32_t retrans_timer;
struct pbuf;
struct netif;
void nd6_tmr(void);
void nd6_input(struct pbuf *p, struct netif *inp);
s8_t nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif);
s8_t nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif);
void nd6_clear_destination_cache(void);
struct netif *nd6_find_route(const ip6_addr_t *ip6addr);
err_t nd6_get_next_hop_addr_or_queue(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr, const u8_t **hwaddrp);
u16_t nd6_get_destination_mtu(const ip6_addr_t *ip6addr, struct netif *netif);
err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf *p);
#if LWIP_ND6_TCP_REACHABILITY_HINTS
void nd6_reachability_hint(const ip6_addr_t *ip6addr);
#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */
void nd6_cleanup_netif(struct netif *netif);
#if LWIP_IPV6_MLD
void nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state);
#endif /* LWIP_IPV6_MLD */
#ifdef __cplusplus
}

View File

@ -38,8 +38,7 @@
#if LWIP_DNS && LWIP_SOCKET
#include <stddef.h> /* for size_t */
#include "lwip/arch.h"
#include "lwip/inet.h"
#include "lwip/sockets.h"

View File

@ -100,6 +100,10 @@ err_t netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,
#define netifapi_netif_set_down(n) netifapi_netif_common(n, netif_set_down, NULL)
/** @ingroup netifapi_netif */
#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL)
/** @ingroup netifapi_netif */
#define netifapi_netif_set_link_up(n) netifapi_netif_common(n, netif_set_link_up, NULL)
/** @ingroup netifapi_netif */
#define netifapi_netif_set_link_down(n) netifapi_netif_common(n, netif_set_link_down, NULL)
/**
* @defgroup netifapi_dhcp4 DHCPv4

View File

@ -882,6 +882,15 @@
#if !defined LWIP_DHCP_MAX_NTP_SERVERS || defined __DOXYGEN__
#define LWIP_DHCP_MAX_NTP_SERVERS 1
#endif
/**
* LWIP_DHCP_MAX_DNS_SERVERS > 0: Request DNS servers with discover/select.
* DHCP servers received in the response are passed to DNS via @ref dns_setserver()
* (up to the maximum limit defined here).
*/
#if !defined LWIP_DHCP_MAX_DNS_SERVERS || defined __DOXYGEN__
#define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS
#endif
/**
* @}
*/
@ -1057,6 +1066,12 @@
#if !defined DNS_LOCAL_HOSTLIST_IS_DYNAMIC || defined __DOXYGEN__
#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
/** Set this to 1 to enable querying ".local" names via mDNS
* using a One-Shot Multicast DNS Query */
#if !defined LWIP_DNS_SUPPORT_MDNS_QUERIES || defined __DOXYGEN__
#define LWIP_DNS_SUPPORT_MDNS_QUERIES 0
#endif
/**
* @}
*/
@ -1128,7 +1143,10 @@
/**
* TCP_WND: The size of a TCP window. This must be at least
* (2 * TCP_MSS) for things to work well
* (2 * TCP_MSS) for things to work well.
* ATTENTION: when using TCP_RCV_SCALE, TCP_WND is the total size
* with scaling applied. Maximum window value in the TCP header
* will be TCP_WND >> TCP_RCV_SCALE
*/
#if !defined TCP_WND || defined __DOXYGEN__
#define TCP_WND (4 * TCP_MSS)
@ -1345,7 +1363,7 @@
* for an additional encapsulation header before ethernet headers (e.g. 802.11)
*/
#if !defined PBUF_LINK_ENCAPSULATION_HLEN || defined __DOXYGEN__
#define PBUF_LINK_ENCAPSULATION_HLEN 0
#define PBUF_LINK_ENCAPSULATION_HLEN 0u
#endif
/**
@ -2161,7 +2179,7 @@
/**
* LWIP_IPV6_REASS==1: reassemble incoming IPv6 packets that fragmented
*/
#if !defined LWIP_IPV6_REASS || defined __DOXYGEN__ || defined __DOXYGEN__
#if !defined LWIP_IPV6_REASS || defined __DOXYGEN__
#define LWIP_IPV6_REASS (LWIP_IPV6)
#endif
@ -2227,13 +2245,18 @@
*/
/**
* LWIP_IPV6_MLD==1: Enable multicast listener discovery protocol.
* If LWIP_IPV6 is enabled but this setting is disabled, the MAC layer must
* indiscriminately pass all inbound IPv6 multicast traffic to lwIP.
*/
#if !defined LWIP_IPV6_MLD || defined __DOXYGEN__
#define LWIP_IPV6_MLD (LWIP_IPV6)
#endif
/**
* MEMP_NUM_MLD6_GROUP: Max number of IPv6 multicast that can be joined.
* MEMP_NUM_MLD6_GROUP: Max number of IPv6 multicast groups that can be joined.
* There must be enough groups so that each netif can join the solicited-node
* multicast group for each of its local addresses, plus one for MDNS if
* applicable, plus any number of groups to be joined on UDP sockets.
*/
#if !defined MEMP_NUM_MLD6_GROUP || defined __DOXYGEN__
#define MEMP_NUM_MLD6_GROUP 4
@ -2339,7 +2362,7 @@
* LWIP_ND6_DELAY_FIRST_PROBE_TIME: Delay before first unicast neighbor solicitation
* message is sent, during neighbor reachability detection.
*/
#if !defined LWIP_ND6_DELAY_FIRST_PROBE_TIME || defined __DOXYGEN__s
#if !defined LWIP_ND6_DELAY_FIRST_PROBE_TIME || defined __DOXYGEN__
#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000
#endif
@ -2356,9 +2379,18 @@
* with reachability hints for connected destinations. This helps avoid sending
* unicast neighbor solicitation messages.
*/
#if !defined LWIP_ND6_TCP_REACHABILITY_HINTS || defined __DOXYGEN__ || defined __DOXYGEN__
#if !defined LWIP_ND6_TCP_REACHABILITY_HINTS || defined __DOXYGEN__
#define LWIP_ND6_TCP_REACHABILITY_HINTS 1
#endif
/**
* LWIP_ND6_RDNSS_MAX_DNS_SERVERS > 0: Use IPv6 Router Advertisement Recursive
* DNS Server Option (as per RFC 6106) to copy a defined maximum number of DNS
* servers to the DNS module.
*/
#if !defined LWIP_ND6_RDNSS_MAX_DNS_SERVERS || defined __DOXYGEN__
#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS 0
#endif
/**
* @}
*/
@ -2383,6 +2415,29 @@
* @{
*/
/**
* LWIP_HOOK_TCP_ISN:
* Hook for generation of the Initial Sequence Number (ISN) for a new TCP
* connection. The default lwIP ISN generation algorithm is very basic and may
* allow for TCP spoofing attacks. This hook provides the means to implement
* the standardized ISN generation algorithm from RFC 6528 (see contrib/adons/tcp_isn),
* or any other desired algorithm as a replacement.
* Called from tcp_connect() and tcp_listen_input() when an ISN is needed for
* a new TCP connection, if TCP support (@ref LWIP_TCP) is enabled.\n
* Signature: u32_t my_hook_tcp_isn(const ip_addr_t* local_ip, u16_t local_port, const ip_addr_t* remote_ip, u16_t remote_port);
* - it may be necessary to use "struct ip_addr" (ip4_addr, ip6_addr) instead of "ip_addr_t" in function declarations\n
* Arguments:
* - local_ip: pointer to the local IP address of the connection
* - local_port: local port number of the connection (host-byte order)
* - remote_ip: pointer to the remote IP address of the connection
* - remote_port: remote port number of the connection (host-byte order)\n
* Return value:
* - the 32-bit Initial Sequence Number to use for the new TCP connection.
*/
#ifdef __DOXYGEN__
#define LWIP_HOOK_TCP_ISN(local_ip, local_port, remote_ip, remote_port)
#endif
/**
* LWIP_HOOK_IP4_INPUT(pbuf, input_netif):
* - called from ip_input() (IPv4)
@ -2424,7 +2479,7 @@
* - dest: the destination IPv4 address
* Returns the IPv4 address of the gateway to handle the specified destination
* IPv4 address. If NULL is returned, the netif's default gateway is used.
* The returned address MUST be reachable on the specified netif!
* The returned address MUST be directly reachable on the specified netif!
* This function is meant to implement advanced IPv4 routing together with
* LWIP_HOOK_IP4_ROUTE(). The actual routing/gateway table implementation is
* not part of lwIP but can e.g. be hidden in the netif's state argument.
@ -2460,6 +2515,22 @@
#define LWIP_HOOK_IP6_ROUTE(src, dest)
#endif
/**
* LWIP_HOOK_ND6_GET_GW(netif, dest):
* - called from nd6_get_next_hop_entry() (IPv6)
* - netif: the netif used for sending
* - dest: the destination IPv6 address
* Returns the IPv6 address of the next hop to handle the specified destination
* IPv6 address. If NULL is returned, a NDP-discovered router is used instead.
* The returned address MUST be directly reachable on the specified netif!
* This function is meant to implement advanced IPv6 routing together with
* LWIP_HOOK_IP6_ROUTE(). The actual routing/gateway table implementation is
* not part of lwIP but can e.g. be hidden in the netif's state argument.
*/
#ifdef __DOXYGEN__
#define LWIP_HOOK_ND6_GET_GW(netif, dest)
#endif
/**
* LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr):
* - called from ethernet_input() if VLAN support is enabled
@ -2523,7 +2594,7 @@
---------------------------------------
*/
/**
* @defgroup lwip_opts_debugmsg Debugging
* @defgroup lwip_opts_debugmsg Debug messages
* @ingroup lwip_opts_debug
* @{
*/
@ -2531,14 +2602,16 @@
* LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is
* compared against this value. If it is smaller, then debugging
* messages are written.
* @see debugging_levels
*/
#if !defined LWIP_DBG_MIN_LEVEL || defined __DOXYGEN__ || defined __DOXYGEN__
#if !defined LWIP_DBG_MIN_LEVEL || defined __DOXYGEN__
#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL
#endif
/**
* LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable
* debug messages of certain types.
* @see debugging_levels
*/
#if !defined LWIP_DBG_TYPES_ON || defined __DOXYGEN__
#define LWIP_DBG_TYPES_ON LWIP_DBG_ON

View File

@ -43,8 +43,7 @@
/* Note: Netconn API is always available when sockets are enabled -
* sockets are implemented on top of them */
#include <stddef.h> /* for size_t */
#include "lwip/arch.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#include "lwip/sys.h"

View File

@ -0,0 +1,144 @@
/**
* @file
*
* Neighbor discovery and stateless address autoconfiguration for IPv6.
* Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862
* (Address autoconfiguration).
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef LWIP_HDR_ND6_PRIV_H
#define LWIP_HDR_ND6_PRIV_H
#include "lwip/opt.h"
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/pbuf.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
#if LWIP_ND6_QUEUEING
/** struct for queueing outgoing packets for unknown address
* defined here to be accessed by memp.h
*/
struct nd6_q_entry {
struct nd6_q_entry *next;
struct pbuf *p;
};
#endif /* LWIP_ND6_QUEUEING */
/** Struct for tables. */
struct nd6_neighbor_cache_entry {
ip6_addr_t next_hop_address;
struct netif *netif;
u8_t lladdr[NETIF_MAX_HWADDR_LEN];
/*u32_t pmtu;*/
#if LWIP_ND6_QUEUEING
/** Pointer to queue of pending outgoing packets on this entry. */
struct nd6_q_entry *q;
#else /* LWIP_ND6_QUEUEING */
/** Pointer to a single pending outgoing packet on this entry. */
struct pbuf *q;
#endif /* LWIP_ND6_QUEUEING */
u8_t state;
u8_t isrouter;
union {
u32_t reachable_time; /* in ms since value may originate from network packet */
u32_t delay_time; /* ticks (ND6_TMR_INTERVAL) */
u32_t probes_sent;
u32_t stale_time; /* ticks (ND6_TMR_INTERVAL) */
} counter;
};
struct nd6_destination_cache_entry {
ip6_addr_t destination_addr;
ip6_addr_t next_hop_addr;
u16_t pmtu;
u32_t age;
};
struct nd6_prefix_list_entry {
ip6_addr_t prefix;
struct netif *netif;
u32_t invalidation_timer; /* in ms since value may originate from network packet */
#if LWIP_IPV6_AUTOCONFIG
u8_t flags;
#define ND6_PREFIX_AUTOCONFIG_AUTONOMOUS 0x01
#define ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED 0x02
#define ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE 0x04
#endif /* LWIP_IPV6_AUTOCONFIG */
};
struct nd6_router_list_entry {
struct nd6_neighbor_cache_entry *neighbor_entry;
u32_t invalidation_timer; /* in ms since value may originate from network packet */
u8_t flags;
};
enum nd6_neighbor_cache_entry_state {
ND6_NO_ENTRY = 0,
ND6_INCOMPLETE,
ND6_REACHABLE,
ND6_STALE,
ND6_DELAY,
ND6_PROBE
};
/* Router tables. */
/* @todo make these static? and entries accessible through API? */
extern struct nd6_neighbor_cache_entry neighbor_cache[];
extern struct nd6_destination_cache_entry destination_cache[];
extern struct nd6_prefix_list_entry prefix_list[];
extern struct nd6_router_list_entry default_router_list[];
/* Default values, can be updated by a RA message. */
extern u32_t reachable_time;
extern u32_t retrans_timer;
#ifdef __cplusplus
}
#endif
#endif /* LWIP_IPV6 */
#endif /* LWIP_HDR_ND6_PRIV_H */

View File

@ -34,8 +34,8 @@
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_HDR_TCP_IMPL_H
#define LWIP_HDR_TCP_IMPL_H
#ifndef LWIP_HDR_TCP_PRIV_H
#define LWIP_HDR_TCP_PRIV_H
#include "lwip/opt.h"
@ -452,7 +452,7 @@ void tcp_rst(u32_t seqno, u32_t ackno,
const ip_addr_t *local_ip, const ip_addr_t *remote_ip,
u16_t local_port, u16_t remote_port);
u32_t tcp_next_iss(void);
u32_t tcp_next_iss(struct tcp_pcb *pcb);
err_t tcp_keepalive(struct tcp_pcb *pcb);
err_t tcp_zero_window_probe(struct tcp_pcb *pcb);
@ -501,4 +501,4 @@ void tcp_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_a
#endif /* LWIP_TCP */
#endif /* LWIP_HDR_TCP_H */
#endif /* LWIP_HDR_TCP_PRIV_H */

View File

@ -115,6 +115,24 @@ PACK_STRUCT_END
#endif
#define SIZEOF_DNS_HDR 12
/* Multicast DNS definitions */
/** UDP port for multicast DNS queries */
#ifndef DNS_MQUERY_PORT
#define DNS_MQUERY_PORT 5353
#endif
/* IPv4 group for multicast DNS queries: 224.0.0.251 */
#ifndef DNS_MQUERY_IPV4_GROUP_INIT
#define DNS_MQUERY_IPV4_GROUP_INIT IPADDR4_INIT_BYTES(224,0,0,251)
#endif
/* IPv6 group for multicast DNS queries: FF02::FB */
#ifndef DNS_MQUERY_IPV6_GROUP_INIT
#define DNS_MQUERY_IPV6_GROUP_INIT IPADDR6_INIT_HOST(0xFF020000,0,0,0xFB)
#endif
#ifdef __cplusplus
}
#endif

View File

@ -43,6 +43,93 @@
extern "C" {
#endif
/** ICMP type */
enum icmp6_type {
/** Destination unreachable */
ICMP6_TYPE_DUR = 1,
/** Packet too big */
ICMP6_TYPE_PTB = 2,
/** Time exceeded */
ICMP6_TYPE_TE = 3,
/** Parameter problem */
ICMP6_TYPE_PP = 4,
/** Private experimentation */
ICMP6_TYPE_PE1 = 100,
/** Private experimentation */
ICMP6_TYPE_PE2 = 101,
/** Reserved for expansion of error messages */
ICMP6_TYPE_RSV_ERR = 127,
/** Echo request */
ICMP6_TYPE_EREQ = 128,
/** Echo reply */
ICMP6_TYPE_EREP = 129,
/** Multicast listener query */
ICMP6_TYPE_MLQ = 130,
/** Multicast listener report */
ICMP6_TYPE_MLR = 131,
/** Multicast listener done */
ICMP6_TYPE_MLD = 132,
/** Router solicitation */
ICMP6_TYPE_RS = 133,
/** Router advertisement */
ICMP6_TYPE_RA = 134,
/** Neighbor solicitation */
ICMP6_TYPE_NS = 135,
/** Neighbor advertisement */
ICMP6_TYPE_NA = 136,
/** Redirect */
ICMP6_TYPE_RD = 137,
/** Multicast router advertisement */
ICMP6_TYPE_MRA = 151,
/** Multicast router solicitation */
ICMP6_TYPE_MRS = 152,
/** Multicast router termination */
ICMP6_TYPE_MRT = 153,
/** Private experimentation */
ICMP6_TYPE_PE3 = 200,
/** Private experimentation */
ICMP6_TYPE_PE4 = 201,
/** Reserved for expansion of informational messages */
ICMP6_TYPE_RSV_INF = 255
};
/** ICMP destination unreachable codes */
enum icmp6_dur_code {
/** No route to destination */
ICMP6_DUR_NO_ROUTE = 0,
/** Communication with destination administratively prohibited */
ICMP6_DUR_PROHIBITED = 1,
/** Beyond scope of source address */
ICMP6_DUR_SCOPE = 2,
/** Address unreachable */
ICMP6_DUR_ADDRESS = 3,
/** Port unreachable */
ICMP6_DUR_PORT = 4,
/** Source address failed ingress/egress policy */
ICMP6_DUR_POLICY = 5,
/** Reject route to destination */
ICMP6_DUR_REJECT_ROUTE = 6
};
/** ICMP time exceeded codes */
enum icmp6_te_code {
/** Hop limit exceeded in transit */
ICMP6_TE_HL = 0,
/** Fragment reassembly time exceeded */
ICMP6_TE_FRAG = 1
};
/** ICMP parameter code */
enum icmp6_pp_code {
/** Erroneous header field encountered */
ICMP6_PP_FIELD = 0,
/** Unrecognized next header type encountered */
ICMP6_PP_HEADER = 1,
/** Unrecognized IPv6 option encountered */
ICMP6_PP_OPTION = 2
};
/** This is the standard ICMP6 header. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"

View File

@ -44,6 +44,22 @@
extern "C" {
#endif
/** This is the packed version of ip4_addr_t,
used in network headers that are itself packed */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip4_addr_packed {
PACK_STRUCT_FIELD(u32_t addr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
typedef struct ip4_addr_packed ip4_addr_p_t;
/* Size of the IPv4 header. Same as 'sizeof(struct ip_hdr)'. */
#define IP_HLEN 20

View File

@ -44,6 +44,21 @@
extern "C" {
#endif
/** This is the packed version of ip6_addr_t,
used in network headers that are itself packed */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip6_addr_packed {
PACK_STRUCT_FIELD(u32_t addr[4]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
typedef struct ip6_addr_packed ip6_addr_p_t;
#define IP6_HLEN 40
#define IP6_NEXTH_HOPBYHOP 0

View File

@ -38,7 +38,7 @@
#define LWIP_HDR_PROT_MLD6_H
#include "lwip/arch.h"
#include "lwip/ip6_addr.h"
#include "lwip/prot/ip6.h"
#ifdef __cplusplus
extern "C" {

View File

@ -39,6 +39,7 @@
#include "lwip/arch.h"
#include "lwip/ip6_addr.h"
#include "lwip/prot/ip6.h"
#ifdef __cplusplus
extern "C" {
@ -246,6 +247,29 @@ PACK_STRUCT_END
# include "arch/epstruct.h"
#endif
/** Recursive DNS Server Option. */
#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS
#define LWIP_RDNSS_OPTION_MAX_SERVERS LWIP_ND6_RDNSS_MAX_DNS_SERVERS
#else
#define LWIP_RDNSS_OPTION_MAX_SERVERS 1
#endif
#define ND6_OPTION_TYPE_RDNSS (25)
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct rdnss_option {
PACK_STRUCT_FLD_8(u8_t type);
PACK_STRUCT_FLD_8(u8_t length);
PACK_STRUCT_FIELD(u16_t reserved);
PACK_STRUCT_FIELD(u32_t lifetime);
PACK_STRUCT_FLD_S(ip6_addr_p_t rdnss_address[LWIP_RDNSS_OPTION_MAX_SERVERS]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#ifdef __cplusplus
}
#endif

View File

@ -85,7 +85,7 @@ PACK_STRUCT_END
#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = lwip_htons(((len) << 12) | TCPH_FLAGS(phdr))
#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS(~TCP_FLAGS)) | lwip_htons(flags))
#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = lwip_htons(((len) << 12) | (flags))
#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = (u16_t)(lwip_htons((u16_t)((len) << 12) | (flags)))
#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | lwip_htons(flags))
#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags & ~lwip_htons(flags))

View File

@ -43,8 +43,6 @@
#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
#include <stddef.h> /* for size_t */
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#include "lwip/inet.h"

View File

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

View File

@ -387,6 +387,7 @@ err_t tcp_bind (struct tcp_pcb *pcb, const ip_addr_t *ipaddr,
err_t tcp_connect (struct tcp_pcb *pcb, const ip_addr_t *ipaddr,
u16_t port, tcp_connected_fn connected);
struct tcp_pcb * tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err);
struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog);
/** @ingroup tcp_raw */
#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG)

View File

@ -616,7 +616,8 @@ lowpan4_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
err_t
lowpan6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr)
{
s8_t i;
err_t result;
const u8_t *hwaddr;
struct ieee_802154_addr src, dest;
#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS
ip6_addr_t ip6_src;
@ -663,37 +664,25 @@ lowpan6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr)
}
#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */
/* Get next hop record. */
i = nd6_get_next_hop_entry(ip6addr, netif);
if (i < 0) {
/* Ask ND6 what to do with the packet. */
result = nd6_get_next_hop_addr_or_queue(netif, q, ip6addr, &hwaddr);
if (result != ERR_OK) {
MIB2_STATS_NETIF_INC(netif, ifoutdiscards);
/* failed to get a next hop neighbor record. */
return ERR_MEM;
return result;
}
/* Now that we have a destination record, send or queue the packet. */
if (neighbor_cache[i].state == ND6_STALE) {
/* Switch to delay state. */
neighbor_cache[i].state = ND6_DELAY;
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME;
/* If no hardware address is returned, nd6 has queued the packet for later. */
if (hwaddr == NULL) {
return ERR_OK;
}
/* @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. */
/* Send out the packet using the returned hardware address. */
dest.addr_len = netif->hwaddr_len;
SMEMCPY(dest.addr, neighbor_cache[i].lladdr, netif->hwaddr_len);
SMEMCPY(dest.addr, hwaddr, netif->hwaddr_len);
MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
return lowpan6_frag(netif, q, &src, &dest);
}
/* We should queue packet on this interface. */
return nd6_queue_packet(i, q);
}
static struct pbuf *
lowpan6_decompress(struct pbuf * p, struct ieee_802154_addr * src, struct ieee_802154_addr * dest)
{

View File

@ -1145,12 +1145,12 @@ int cdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2) {
nsa = dns_getserver(0);
ip_addr_set_ip4_u32(&nsb, ns1);
if (ip_addr_cmp(nsa, &nsb)) {
dns_setserver(0, IP4_ADDR_ANY);
dns_setserver(0, IP_ADDR_ANY);
}
nsa = dns_getserver(1);
ip_addr_set_ip4_u32(&nsb, ns2);
if (ip_addr_cmp(nsa, &nsb)) {
dns_setserver(1, IP4_ADDR_ANY);
dns_setserver(1, IP_ADDR_ANY);
}
return 1;
}

View File

@ -222,6 +222,7 @@ pppapi_do_pppol2tp_create(struct tcpip_api_call_data *m)
msg->msg.msg.l2tpcreate.secret_len,
#else /* PPPOL2TP_AUTH_SUPPORT */
NULL,
0,
#endif /* PPPOL2TP_AUTH_SUPPORT */
msg->msg.msg.l2tpcreate.link_status_cb, msg->msg.msg.l2tpcreate.ctx_cb);
return ERR_OK;
@ -239,6 +240,10 @@ pppapi_pppol2tp_create(struct netif *pppif, struct netif *netif, ip_addr_t *ipad
ppp_pcb* result;
PPPAPI_VAR_DECLARE(msg);
PPPAPI_VAR_ALLOC_RETURN_NULL(msg);
#if !PPPOL2TP_AUTH_SUPPORT
LWIP_UNUSED_ARG(secret);
LWIP_UNUSED_ARG(secret_len);
#endif /* !PPPOL2TP_AUTH_SUPPORT */
PPPAPI_VAR_REF(msg).msg.ppp = NULL;
PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.pppif = pppif;

View File

@ -113,6 +113,10 @@ ppp_pcb *pppol2tp_create(struct netif *pppif,
ppp_pcb *ppp;
pppol2tp_pcb *l2tp;
struct udp_pcb *udp;
#if !PPPOL2TP_AUTH_SUPPORT
LWIP_UNUSED_ARG(secret);
LWIP_UNUSED_ARG(secret_len);
#endif /* !PPPOL2TP_AUTH_SUPPORT */
if (ipaddr == NULL) {
goto ipaddr_check_failed;
@ -303,7 +307,7 @@ static err_t pppol2tp_connect(ppp_pcb *ppp, void *ctx) {
udp_bind(l2tp->udp, IP6_ADDR_ANY, 0);
} else
#endif /* LWIP_IPV6 */
udp_bind(l2tp->udp, IP4_ADDR_ANY, 0);
udp_bind(l2tp->udp, IP_ADDR_ANY, 0);
#if PPPOL2TP_AUTH_SUPPORT
/* Generate random vector */

View File

@ -35,8 +35,8 @@
#if PPP_SUPPORT && PPPOS_SUPPORT /* don't build if not configured for use in lwipopts.h */
#include <string.h>
#include <stddef.h>
#include "lwip/arch.h"
#include "lwip/err.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
@ -471,18 +471,20 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l)
u8_t escaped;
PPPOS_DECL_PROTECT(lev);
PPPOS_PROTECT(lev);
if (!pppos->open) {
PPPOS_UNPROTECT(lev);
return;
}
PPPOS_UNPROTECT(lev);
PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l));
while (l-- > 0) {
cur_char = *s++;
PPPOS_PROTECT(lev);
/* ppp_input can disconnect the interface, we need to abort to prevent a memory
* leak if there are remaining bytes because pppos_connect and pppos_listen
* functions expect input buffer to be free. Furthermore there are no real
* reason to continue reading bytes if we are disconnected.
*/
if (!pppos->open) {
PPPOS_UNPROTECT(lev);
return;
}
escaped = ESCAPE_P(pppos->in_accm, cur_char);
PPPOS_UNPROTECT(lev);
/* Handle special characters. */

View File

@ -247,11 +247,13 @@ int ppp_vslprintf(char *buf, int buflen, const char *fmt, va_list args) {
val = va_arg(args, unsigned int);
base = 16;
break;
#if 0 /* unused (and wrong on LLP64 systems) */
case 'p':
val = (unsigned long) va_arg(args, void *);
base = 16;
neg = 2;
break;
#endif /* unused (and wrong on LLP64 systems) */
case 's':
str = va_arg(args, char *);
break;

53
test/fuzz/Makefile Normal file
View File

@ -0,0 +1,53 @@
#
# Copyright (c) 2001, 2002 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>
#
all compile: lwip_fuzz
.PHONY: all clean
CC=afl-gcc
LDFLAGS=-lm
CFLAGS=-O0
CONTRIBDIR=../../../lwip-contrib
include $(CONTRIBDIR)/ports/unix/Common.mk
clean:
rm -f *.o $(LWIPLIBCOMMON) lwip_fuzz *.s .depend* *.core core
depend dep: .depend
include .depend
.depend: fuzz.c $(LWIPFILES) $(APPFILES)
$(CCDEP) $(CFLAGS) -MM $^ > .depend || rm -f .depend
lwip_fuzz: .depend $(LWIPLIBCOMMON) fuzz.o
$(CC) $(CFLAGS) -o lwip_fuzz fuzz.o $(LWIPLIBCOMMON) $(LDFLAGS)

34
test/fuzz/README Normal file
View File

@ -0,0 +1,34 @@
Fuzzing the lwIP stack (afl-fuzz requires linux/unix or similar)
This directory contains a small app that reads Ethernet frames from stdin and
processes them. It is used together with the 'american fuzzy lop' tool (found
at http://lcamtuf.coredump.cx/afl/) and the sample inputs to test how
unexpected inputs are handled. The afl tool will read the known inputs, and
try to modify them to exercise as many code paths as possible, by instrumenting
the code and keeping track of which code is executed.
Just running make will produce the test program.
Then run afl with:
afl-fuzz -i inputs/<INPUT> -o output ./lwip_fuzz
and it should start working. It will probably complain about CPU scheduler,
set AFL_SKIP_CPUFREQ=1 to ignore it.
If it complains about invalid "/proc/sys/kernel/core_pattern" setting, try
executing "sudo bash -c 'echo core > /proc/sys/kernel/core_pattern'".
The input is split into different subdirectories since they test different
parts of the code, and since you want to run one instance of afl-fuzz on each
core.
When afl finds a crash or a hang, the input that caused it will be placed in
the output directory. If you have hexdump and text2pcap tools installed,
running output_to_pcap.sh <outputdir> will create pcap files for each input
file to simplify viewing in wireshark.
The lwipopts.h file needs to have checksum checking off, otherwise almost every
packet will be discarded because of that. The other options can be tuned to
expose different parts of the code.

0
test/fuzz/config.h Normal file
View File

136
test/fuzz/fuzz.c Normal file
View File

@ -0,0 +1,136 @@
/*
* 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: Erik Ekman <erik@kryo.se>
*
*/
#include "lwip/init.h"
#include "lwip/netif.h"
#include "netif/etharp.h"
#if LWIP_IPV6
#include "lwip/ethip6.h"
#include "lwip/nd6.h"
#endif
#include <string.h>
#include <stdio.h>
/* no-op send function */
static err_t lwip_tx_func(struct netif *netif, struct pbuf *p)
{
LWIP_UNUSED_ARG(netif);
LWIP_UNUSED_ARG(p);
return ERR_OK;
}
static err_t testif_init(struct netif *netif)
{
netif->name[0] = 'f';
netif->name[1] = 'z';
netif->output = etharp_output;
netif->linkoutput = lwip_tx_func;
netif->mtu = 1500;
netif->hwaddr_len = 6;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
netif->hwaddr[0] = 0x00;
netif->hwaddr[1] = 0x23;
netif->hwaddr[2] = 0xC1;
netif->hwaddr[3] = 0xDE;
netif->hwaddr[4] = 0xD0;
netif->hwaddr[5] = 0x0D;
#if LWIP_IPV6
netif->output_ip6 = ethip6_output;
netif->ip6_autoconfig_enabled = 1;
netif_create_ip6_linklocal_address(netif, 1);
netif->flags |= NETIF_FLAG_MLD6;
#endif
return ERR_OK;
}
static void input_pkt(struct netif *netif, const u8_t *data, size_t len)
{
struct pbuf *p, *q;
err_t err;
LWIP_ASSERT("pkt too big", len <= 0xFFFF);
p = pbuf_alloc(PBUF_RAW, (u16_t)len, PBUF_POOL);
LWIP_ASSERT("alloc failed", p);
for(q = p; q != NULL; q = q->next) {
MEMCPY(q->payload, data, q->len);
data += q->len;
}
err = netif->input(p, netif);
if (err != ERR_OK) {
pbuf_free(p);
}
}
int main(int argc, char** argv)
{
struct netif net_test;
ip4_addr_t addr;
ip4_addr_t netmask;
ip4_addr_t gw;
u8_t pktbuf[2000];
size_t len;
lwip_init();
IP4_ADDR(&addr, 172, 30, 115, 84);
IP4_ADDR(&netmask, 255, 255, 255, 0);
IP4_ADDR(&gw, 172, 30, 115, 1);
netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input);
netif_set_up(&net_test);
#if LWIP_IPV6
nd6_tmr(); /* tick nd to join multicast groups */
#endif
if(argc > 1) {
FILE* f;
const char* filename;
printf("reading input from file... ");
fflush(stdout);
filename = argv[1];
LWIP_ASSERT("invalid filename", filename != NULL);
f = fopen(filename, "rb");
LWIP_ASSERT("open failed", f != NULL);
len = fread(pktbuf, 1, sizeof(pktbuf), f);
fclose(f);
printf("testing file: \"%s\"...\r\n", filename);
} else {
len = fread(pktbuf, 1, sizeof(pktbuf), stdin);
}
input_pkt(&net_test, pktbuf, len);
return 0;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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