From b9dc41517874a4df38b14dc258eec3c8d4e02826 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 10 Nov 2016 09:59:05 +0100 Subject: [PATCH 001/184] master: Set version to 2.0.1 --- src/include/lwip/init.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/lwip/init.h b/src/include/lwip/init.h index b655b43e..c87d2cce 100644 --- a/src/include/lwip/init.h +++ b/src/include/lwip/init.h @@ -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 0 +#define LWIP_VERSION_RC LWIP_RC_DEVELOPMENT /** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */ #define LWIP_RC_RELEASE 255 From b90682dc8b0b498385b891bce8a84e359e17ba04 Mon Sep 17 00:00:00 2001 From: Erik Ekman Date: Thu, 10 Nov 2016 11:19:27 +0100 Subject: [PATCH 002/184] Update email address I am leaving Verisure at the end of the month. --- src/apps/mdns/mdns.c | 5 +---- src/include/lwip/apps/mdns.h | 2 +- src/include/lwip/apps/mdns_opts.h | 2 +- src/include/lwip/apps/mdns_priv.h | 2 +- test/unit/mdns/test_mdns.c | 5 +---- 5 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/apps/mdns/mdns.c b/src/apps/mdns/mdns.c index e0c528c3..3c5cf2d1 100644 --- a/src/apps/mdns/mdns.c +++ b/src/apps/mdns/mdns.c @@ -52,10 +52,7 @@ * * This file is part of the lwIP TCP/IP stack. * - * Author: Erik Ekman - * - * Please coordinate changes and requests with Erik Ekman - * + * Author: Erik Ekman * */ diff --git a/src/include/lwip/apps/mdns.h b/src/include/lwip/apps/mdns.h index f57b182f..d0368161 100644 --- a/src/include/lwip/apps/mdns.h +++ b/src/include/lwip/apps/mdns.h @@ -31,7 +31,7 @@ * * This file is part of the lwIP TCP/IP stack. * - * Author: Erik Ekman + * Author: Erik Ekman * */ #ifndef LWIP_HDR_MDNS_H diff --git a/src/include/lwip/apps/mdns_opts.h b/src/include/lwip/apps/mdns_opts.h index a298c5aa..bf186bcc 100644 --- a/src/include/lwip/apps/mdns_opts.h +++ b/src/include/lwip/apps/mdns_opts.h @@ -31,7 +31,7 @@ * * This file is part of the lwIP TCP/IP stack. * - * Author: Erik Ekman + * Author: Erik Ekman * */ diff --git a/src/include/lwip/apps/mdns_priv.h b/src/include/lwip/apps/mdns_priv.h index 9ae2cef9..8ee6db86 100644 --- a/src/include/lwip/apps/mdns_priv.h +++ b/src/include/lwip/apps/mdns_priv.h @@ -31,7 +31,7 @@ * * This file is part of the lwIP TCP/IP stack. * - * Author: Erik Ekman + * Author: Erik Ekman * */ #ifndef LWIP_HDR_MDNS_PRIV_H diff --git a/test/unit/mdns/test_mdns.c b/test/unit/mdns/test_mdns.c index 9cff0fd7..223520c1 100644 --- a/test/unit/mdns/test_mdns.c +++ b/test/unit/mdns/test_mdns.c @@ -26,10 +26,7 @@ * * This file is part of the lwIP TCP/IP stack. * - * Author: Erik Ekman - * - * Please coordinate changes and requests with Erik Ekman - * + * Author: Erik Ekman * */ From fdcd8f6faf6b14cdada7f215c5d4fa6f0d84410c Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Fri, 11 Nov 2016 11:11:50 +0100 Subject: [PATCH 003/184] Fix bug #49578: lwip_socket_drop_registered_memberships API may not work with LWIP_SOCKET_OFFSET --- src/api/sockets.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index 9968a9ae..960ac7e5 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -2770,7 +2770,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); } } } From f965034366f774e5ae5e1b9a2b7e292f04605867 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Fri, 11 Nov 2016 11:12:54 +0100 Subject: [PATCH 004/184] Fix inconsistent return value in udp_sendto_if() - ERR_RTE should always be returned when there is no available route --- src/core/udp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/udp.c b/src/core/udp.c index f9aee732..e0ab1863 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -662,7 +662,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; From 6dc3a2108ad040ba225c0c46e5c4e0f41455e6d2 Mon Sep 17 00:00:00 2001 From: Joel Cunningham Date: Fri, 11 Nov 2016 15:59:03 -0600 Subject: [PATCH 005/184] WND_SCALE: duplicate define check & doc cleanup This commit cleans up a duplicate #if check for LWIP_WND_SCALE in init.c which was already under #if LWIP_WND_SCALE This commit also improves documentation for TCP_WND in the window scaling case to communicate TCP_WND is always the calculated (scaled) window value, not the value reported in the TCP header Our developers were confused by having to set both the window and scaling factor and only after studying the usage of TCP_WND throughout the code, was it determined to be the calculated (scaled) window --- src/core/init.c | 2 +- src/include/lwip/opt.h | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/core/init.c b/src/core/init.c index 0eb1e44c..570d54aa 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -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))) diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 0db03b50..61305016 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -1128,7 +1128,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) From 81a32e9b06cc6685866061b88645135c44d651d4 Mon Sep 17 00:00:00 2001 From: Roberto Barbieri Carrera Date: Wed, 16 Nov 2016 12:24:57 +0100 Subject: [PATCH 006/184] Fixed bug #49610: Sometimes, autoIP fails to reuse the same address Signed-off-by: goldsimon --- src/core/ipv4/autoip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/ipv4/autoip.c b/src/core/ipv4/autoip.c index 86a4aed3..9aa32833 100644 --- a/src/core/ipv4/autoip.c +++ b/src/core/ipv4/autoip.c @@ -482,7 +482,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")); From f79eabd24b0b266d0263b331afdc4df1fc545e22 Mon Sep 17 00:00:00 2001 From: Joel Cunningham Date: Mon, 14 Nov 2016 15:31:57 -0600 Subject: [PATCH 007/184] bug #49533: start persist timer when unsent seg can't fit in window This commit returns LwIP to previous behavior where if the next unsent segment can't be sent due to the current send window, we start the persist timer. This is done to engage window probing in the case that the subsequent window update from the receiver is dropped, thus preventing connection deadlock This commit refines the previous logic to only target the following case: 1) Next unsent segment doesn't fit within the send window (not congestion) and there is some room in the window 2) Unacked queue is empty (otherwise data is inflight and the RTO timer will take care of any dropped window updates) See commit d8f090a7595a79050c435545d00efc1261b9691c (which removed this behavior) to reference the old logic. The old logic falsely started the persit timer when the RTO timer was already running. --- src/core/tcp_out.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 3c2bc81a..28d17441 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -1033,6 +1033,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 +1130,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 */ From b99b7577fca92e9ad9697b56eb647c0498e3f7ce Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 16 Nov 2016 20:15:51 +0100 Subject: [PATCH 008/184] memp.c: Only check for overflow/underflow if an element could be allocated In other words: Don't dereference NULL pointers --- src/core/memp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/memp.c b/src/core/memp.c index 2e3db28e..2ecb1814 100644 --- a/src/core/memp.c +++ b/src/core/memp.c @@ -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; From ee7a2f346c24e750b555bf2924d2ddc76b24a187 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 16 Nov 2016 20:30:13 +0100 Subject: [PATCH 009/184] inet.h: Consistently name some inet <-> ipaddr conversion macros They operate on ip4_addr_t, not on ip_addr_t This should be clearly visible in their names --- src/api/netdb.c | 2 +- src/api/sockets.c | 12 ++++++------ src/include/lwip/inet.h | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/api/netdb.c b/src/api/netdb.c index ef0c79b1..9361913c 100644 --- a/src/api/netdb.c +++ b/src/api/netdb.c @@ -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)); + inet4_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); diff --git a/src/api/sockets.c b/src/api/sockets.c index 960ac7e5..ba8d18b0 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -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); \ + inet4_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)); \ + inet4_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \ (port) = lwip_ntohs((sin)->sin_port); }while(0) #endif /* LWIP_IPV4 */ @@ -2001,7 +2001,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)); + inet4_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; @@ -2365,7 +2365,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); + inet4_addr_to_ip4addr(&if_addr, (const struct in_addr*)optval); udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr); } break; @@ -2389,8 +2389,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); + inet4_addr_to_ip4addr(&if_addr, &imr->imr_interface); + inet4_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) */ diff --git a/src/include/lwip/inet.h b/src/include/lwip/inet.h index 17edef33..636f1575 100644 --- a/src/include/lwip/inet.h +++ b/src/include/lwip/inet.h @@ -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 inet4_addr_from_ip4addr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) +#define inet4_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 inet4_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) From ad17f345e7431ba69baae947c543bf2277256c92 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 16 Nov 2016 21:01:15 +0100 Subject: [PATCH 010/184] mdns: Use strlen to determine string length of strings contained in a struct - padding seems to be applied to these strings, and sizeof() returns the _padded_ size??? Found by compiling with CLANG with address sanitizer enabled --- src/apps/mdns/mdns.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/apps/mdns/mdns.c b/src/apps/mdns/mdns.c index 3c5cf2d1..92f7a2cc 100644 --- a/src/apps/mdns/mdns.c +++ b/src/apps/mdns/mdns.c @@ -570,7 +570,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); } @@ -595,7 +595,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); } From c1eb6d8aa4e034cf66cac47e9928f5b492ec6ac6 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Mon, 31 Oct 2016 19:24:27 +0100 Subject: [PATCH 011/184] Minor: Add macros to map/unmap IPv6 mapped IPv4 addresses --- src/include/lwip/ip_addr.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/include/lwip/ip_addr.h b/src/include/lwip/ip_addr.h index c1df7464..8ec640e7 100644 --- a/src/include/lwip/ip_addr.h +++ b/src/include/lwip/ip_addr.h @@ -215,6 +215,16 @@ int ipaddr_aton(const char *cp, ip_addr_t *addr); /** @ingroup ipaddr */ #define IPADDR_STRLEN_MAX IP6ADDR_STRLEN_MAX +#define ip4_2_ipv6_mapped_ipv4(ip6addr, ip4addr) do { \ + (ip6addr)->addr[0] = 0; \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = PP_HTONL(0x0000FFFFUL); \ + (ip6addr)->addr[3] = (ip4addr)->addr; } while(0); + +#define unmap_ipv6_mapped_ipv4(target, source) do { \ + (target)->u_addr.ip4.addr = (source)->u_addr.ip6.addr[3]; \ + (target)->type = IPADDR_TYPE_V4; } while(0); + #else /* LWIP_IPV4 && LWIP_IPV6 */ #define IP_ADDR_PCB_VERSION_MATCH(addr, pcb) 1 From 2f37dc0606c39e34b96b60290886f137f17c168a Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Mon, 31 Oct 2016 19:28:11 +0100 Subject: [PATCH 012/184] api_msg.c: Partly add support for IPv6 mapped IPv4 addresses - lwip_netconn_do_getaddr(): Convert IPv4 addresses to IPv6 mapped IPv4 addresses - lwip_netconn_do_send(): Support IPv6 mapped IPv4 addresses - Not done: connect(), bind() --- src/api/api_msg.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 86546c29..76131aed 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -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" @@ -1397,10 +1398,18 @@ lwip_netconn_do_send(void *m) } else { msg->err = ERR_CONN; if (msg->conn->pcb.tcp != NULL) { + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ + if(NETCONNTYPE_ISIPV6(netconn_type(msg->conn)) && IP_IS_V4_VAL(msg->msg.b->addr)) { + unmap_ipv6_mapped_ipv4(&msg->msg.b->addr, &msg->msg.b->addr); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + 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); @@ -1710,6 +1719,18 @@ lwip_netconn_do_getaddr(void *m) ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), msg->conn->pcb.ip->remote_ip); } + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Map IPv4 addresses to IPv6 */ + if(NETCONNTYPE_ISIPV6(netconn_type(msg->conn)) && IP_IS_V4_VAL(API_EXPR_DEREF(msg->msg.ad.ipaddr))) { + ip4_addr_t ip4; + + ip4_addr_copy(ip4, *ip_2_ip4(&API_EXPR_DEREF(msg->msg.ad.ipaddr))); + ip4_2_ipv6_mapped_ipv4(ip_2_ip6(&API_EXPR_DEREF(msg->msg.ad.ipaddr)), &ip4); + IP_SET_TYPE_VAL(API_EXPR_DEREF(msg->msg.ad.ipaddr), IPADDR_TYPE_V6); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + msg->err = ERR_OK; switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW From 1dd97e7d533aa9af818a926d64c23ee7650fd299 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Mon, 31 Oct 2016 19:29:26 +0100 Subject: [PATCH 013/184] sockets.c, lwip_sendto(): Remove check whether IP address matches socket type. Is checked in lower layers anyway. --- src/api/sockets.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index ba8d18b0..9726f0c8 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -1107,12 +1107,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; From b70ddf7b5428a6f1ace7aea8c74fc327d6cb0a97 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 2 Nov 2016 11:58:33 +0100 Subject: [PATCH 014/184] Cleanup unmap_ipv6_mapped_ipv4() macro --- src/api/api_msg.c | 12 +++++------- src/include/lwip/ip_addr.h | 13 +++++++------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 76131aed..2b76f077 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -1401,8 +1401,9 @@ lwip_netconn_do_send(void *m) #if LWIP_IPV4 && LWIP_IPV6 /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ - if(NETCONNTYPE_ISIPV6(netconn_type(msg->conn)) && IP_IS_V4_VAL(msg->msg.b->addr)) { - unmap_ipv6_mapped_ipv4(&msg->msg.b->addr, &msg->msg.b->addr); + if (NETCONNTYPE_ISIPV6(netconn_type(msg->conn)) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&msg->msg.b->addr))) { + unmap_ipv6_mapped_ipv4(ip_2_ip4(&msg->msg.b->addr), ip_2_ip6(&msg->msg.b->addr)); + IP_SET_TYPE(&msg->msg.b->addr, IPADDR_TYPE_V4); } #endif /* LWIP_IPV4 && LWIP_IPV6 */ @@ -1722,11 +1723,8 @@ lwip_netconn_do_getaddr(void *m) #if LWIP_IPV4 && LWIP_IPV6 /* Dual-stack: Map IPv4 addresses to IPv6 */ - if(NETCONNTYPE_ISIPV6(netconn_type(msg->conn)) && IP_IS_V4_VAL(API_EXPR_DEREF(msg->msg.ad.ipaddr))) { - ip4_addr_t ip4; - - ip4_addr_copy(ip4, *ip_2_ip4(&API_EXPR_DEREF(msg->msg.ad.ipaddr))); - ip4_2_ipv6_mapped_ipv4(ip_2_ip6(&API_EXPR_DEREF(msg->msg.ad.ipaddr)), &ip4); + if (NETCONNTYPE_ISIPV6(netconn_type(msg->conn)) && IP_IS_V4_VAL(API_EXPR_DEREF(msg->msg.ad.ipaddr))) { + ip4_2_ipv6_mapped_ipv4(ip_2_ip6(&API_EXPR_DEREF(msg->msg.ad.ipaddr)), ip_2_ip4(&API_EXPR_DEREF(msg->msg.ad.ipaddr))); IP_SET_TYPE_VAL(API_EXPR_DEREF(msg->msg.ad.ipaddr), IPADDR_TYPE_V6); } #endif /* LWIP_IPV4 && LWIP_IPV6 */ diff --git a/src/include/lwip/ip_addr.h b/src/include/lwip/ip_addr.h index 8ec640e7..7e850377 100644 --- a/src/include/lwip/ip_addr.h +++ b/src/include/lwip/ip_addr.h @@ -215,15 +215,16 @@ 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[0] = 0; \ - (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[3] = (ip4addr)->addr; \ (ip6addr)->addr[2] = PP_HTONL(0x0000FFFFUL); \ - (ip6addr)->addr[3] = (ip4addr)->addr; } while(0); + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[0] = 0; } while(0); -#define unmap_ipv6_mapped_ipv4(target, source) do { \ - (target)->u_addr.ip4.addr = (source)->u_addr.ip6.addr[3]; \ - (target)->type = IPADDR_TYPE_V4; } while(0); +/** @ingroup ipaddr */ +#define unmap_ipv6_mapped_ipv4(target, source) \ + (target)->addr = (source)->addr[3]; #else /* LWIP_IPV4 && LWIP_IPV6 */ From 010f3550b6d25557f3ab1c62d42bf0ffdc8d7322 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 2 Nov 2016 12:00:13 +0100 Subject: [PATCH 015/184] Cleanup macro parameter names --- src/include/lwip/ip_addr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/lwip/ip_addr.h b/src/include/lwip/ip_addr.h index 7e850377..26ab916e 100644 --- a/src/include/lwip/ip_addr.h +++ b/src/include/lwip/ip_addr.h @@ -223,8 +223,8 @@ int ipaddr_aton(const char *cp, ip_addr_t *addr); (ip6addr)->addr[0] = 0; } while(0); /** @ingroup ipaddr */ -#define unmap_ipv6_mapped_ipv4(target, source) \ - (target)->addr = (source)->addr[3]; +#define unmap_ipv6_mapped_ipv4(ip4addr, ip6addr) \ + (ip4addr)->addr = (ip6addr)->addr[3]; #else /* LWIP_IPV4 && LWIP_IPV6 */ From 1712b06a64637e4e6ab56d65749ee74edee3fa78 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 16 Nov 2016 22:58:38 +0100 Subject: [PATCH 016/184] Work on dual-stack netconn IPv6 netconns are created as IPADDR_TYPE_ANY raw/udp/tcp PCBs internally bind, connect and sendto now accept IPv6 mapped IPv4 addresses or IPv4 addresses as argument getaddr and receive functions now return IPv6 mapped IPv4 addresses instead of IPv4 addresses This behavior is close to BSD socket API --- src/api/api_lib.c | 71 ++++++++++++++++++++++++++++++++++++++++-- src/api/api_msg.c | 62 +++++++----------------------------- src/include/lwip/api.h | 1 + 3 files changed, 81 insertions(+), 53 deletions(-) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index b4fc403d..9be38b71 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -231,6 +231,14 @@ netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) err = netconn_apimsg(lwip_netconn_do_getaddr, &msg); #endif /* LWIP_MPU_COMPATIBLE */ API_MSG_VAR_FREE(msg); + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Map IPv4 addresses to IPv6 mapped IPv4 */ + if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4(addr)) { + ip4_2_ipv6_mapped_ipv4(ip_2_ip6(addr), ip_2_ip4(addr)); + IP_SET_TYPE(addr, IPADDR_TYPE_V6); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ return err; } @@ -250,6 +258,7 @@ err_t netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) { API_MSG_VAR_DECLARE(msg); + ip_addr_t ipaddr; err_t err; LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); @@ -258,10 +267,28 @@ netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) if (addr == NULL) { addr = IP4_ADDR_ANY; } + + ip_addr_copy(ipaddr, *addr); + + #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(&ipaddr, IP6_ADDR_ANY)) { + ip_addr_copy(ipaddr, *IP_ANY_TYPE); + } + + /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ + if (IP_IS_V6_VAL(ipaddr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&ipaddr))) { + unmap_ipv6_mapped_ipv4(ip_2_ip4(&ipaddr), ip_2_ip6(&ipaddr)); + IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ API_MSG_VAR_ALLOC(msg); API_MSG_VAR_REF(msg).conn = conn; - API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); + API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(&ipaddr); API_MSG_VAR_REF(msg).msg.bc.port = port; err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg)); API_MSG_VAR_FREE(msg); @@ -282,6 +309,7 @@ err_t netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port) { API_MSG_VAR_DECLARE(msg); + ip_addr_t ipaddr; err_t err; LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); @@ -291,9 +319,27 @@ netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port) addr = IP4_ADDR_ANY; } + ip_addr_copy(ipaddr, *addr); + + #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(&ipaddr, IP6_ADDR_ANY)) { + ip_addr_copy(ipaddr, *IP_ANY_TYPE); + } + + /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ + if (IP_IS_V6_VAL(ipaddr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&ipaddr))) { + unmap_ipv6_mapped_ipv4(ip_2_ip4(&ipaddr), ip_2_ip6(&ipaddr)); + IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + API_MSG_VAR_ALLOC(msg); API_MSG_VAR_REF(msg).conn = conn; - API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); + API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(&ipaddr); API_MSG_VAR_REF(msg).msg.bc.port = port; err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg)); API_MSG_VAR_FREE(msg); @@ -561,8 +607,18 @@ netconn_recv_data(struct netconn *conn, void **new_buf) #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ #if (LWIP_UDP || LWIP_RAW) { + struct netbuf* nbuf = (struct netbuf*)buf; + LWIP_ASSERT("buf != NULL", buf != NULL); - len = netbuf_len((struct netbuf *)buf); + len = netbuf_len(nbuf); + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Map IPv4 addresses to IPv6 mapped IPv4 */ + if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4_VAL(nbuf->addr)) { + ip4_2_ipv6_mapped_ipv4(ip_2_ip6(&nbuf->addr), ip_2_ip4(&nbuf->addr)); + IP_SET_TYPE_VAL(nbuf->addr, IPADDR_TYPE_V6); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ } #endif /* (LWIP_UDP || LWIP_RAW) */ @@ -697,6 +753,15 @@ 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)); + +#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 */ + API_MSG_VAR_ALLOC(msg); API_MSG_VAR_REF(msg).conn = conn; API_MSG_VAR_REF(msg).msg.b = buf; diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 2b76f077..e19a6a0c 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -545,13 +545,18 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) static void pcb_new(struct api_msg *msg) { - LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); + enum lwip_ip_addr_type iptype; + LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); + + /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */ + iptype = NETCONNTYPE_ISIPV6(netconn_type(msg->conn))? IPADDR_TYPE_ANY : IPADDR_TYPE_V4; + /* Allocate a PCB for this connection */ switch(NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: - msg->conn->pcb.raw = raw_new(msg->msg.n.proto); + msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto); if (msg->conn->pcb.raw != NULL) { raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); } @@ -559,7 +564,7 @@ pcb_new(struct api_msg *msg) #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: - msg->conn->pcb.udp = udp_new(); + msg->conn->pcb.udp = udp_new_ip_type(iptype); if (msg->conn->pcb.udp != NULL) { #if LWIP_UDPLITE if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) { @@ -575,7 +580,7 @@ pcb_new(struct api_msg *msg) #endif /* LWIP_UDP */ #if LWIP_TCP case NETCONN_TCP: - msg->conn->pcb.tcp = tcp_new(); + msg->conn->pcb.tcp = tcp_new_ip_type(iptype); if (msg->conn->pcb.tcp != NULL) { setup_tcp(msg->conn); } @@ -589,15 +594,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 */ } /** @@ -1114,37 +1110,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: @@ -1398,15 +1377,6 @@ lwip_netconn_do_send(void *m) } else { msg->err = ERR_CONN; if (msg->conn->pcb.tcp != NULL) { - -#if LWIP_IPV4 && LWIP_IPV6 - /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ - if (NETCONNTYPE_ISIPV6(netconn_type(msg->conn)) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&msg->msg.b->addr))) { - unmap_ipv6_mapped_ipv4(ip_2_ip4(&msg->msg.b->addr), ip_2_ip6(&msg->msg.b->addr)); - IP_SET_TYPE(&msg->msg.b->addr, IPADDR_TYPE_V4); - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: @@ -1720,14 +1690,6 @@ lwip_netconn_do_getaddr(void *m) ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), msg->conn->pcb.ip->remote_ip); } - -#if LWIP_IPV4 && LWIP_IPV6 - /* Dual-stack: Map IPv4 addresses to IPv6 */ - if (NETCONNTYPE_ISIPV6(netconn_type(msg->conn)) && IP_IS_V4_VAL(API_EXPR_DEREF(msg->msg.ad.ipaddr))) { - ip4_2_ipv6_mapped_ipv4(ip_2_ip6(&API_EXPR_DEREF(msg->msg.ad.ipaddr)), ip_2_ip4(&API_EXPR_DEREF(msg->msg.ad.ipaddr))); - IP_SET_TYPE_VAL(API_EXPR_DEREF(msg->msg.ad.ipaddr), IPADDR_TYPE_V6); - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ msg->err = ERR_OK; switch (NETCONNTYPE_GROUP(msg->conn->type)) { diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index e8620dd8..d1394533 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -90,6 +90,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 */ From d026a3954ad0f49d1a70a0d5060b4ef79381c106 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 16 Nov 2016 23:30:19 +0100 Subject: [PATCH 017/184] Dual-stack fixes in raw/udp/tcp bind() may change IP type when previous type is IPADDR_TYPE_ANY connect() IP type must exactly match bind IP type Use correct IPADDRx_ANY type when calling ip_route() --- src/core/raw.c | 10 ++++++++-- src/core/tcp.c | 2 +- src/core/udp.c | 11 ++++++++--- src/include/lwip/ip_addr.h | 6 ++++++ 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/core/raw.c b/src/core/raw.c index f692c9c2..e4ea13c1 100644 --- a/src/core/raw.c +++ b/src/core/raw.c @@ -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); @@ -320,7 +320,13 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) } } - netif = ip_route(&pcb->local_ip, 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); diff --git a/src/core/tcp.c b/src/core/tcp.c index 1d700980..eac05fbe 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -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; } diff --git a/src/core/udp.c b/src/core/udp.c index e0ab1863..8c3a3ce5 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -571,7 +571,12 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, #endif /* LWIP_IPV6 || (LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS) */ /* find the outgoing network interface for this packet */ - netif = ip_route(&pcb->local_ip, dst_ip_route); + if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { + /* Don't call ip_route() with IP_ANY_TYPE */ + netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(dst_ip_route)), dst_ip_route); + } else { + netif = ip_route(&pcb->local_ip, dst_ip_route); + } /* no outgoing network interface could be found? */ if (netif == NULL) { @@ -912,7 +917,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; } @@ -1002,7 +1007,7 @@ udp_connect(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) { struct udp_pcb *ipcb; - if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) { + if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) { return ERR_VAL; } diff --git a/src/include/lwip/ip_addr.h b/src/include/lwip/ip_addr.h index 26ab916e..127d4144 100644 --- a/src/include/lwip/ip_addr.h +++ b/src/include/lwip/ip_addr.h @@ -226,6 +226,8 @@ int ipaddr_aton(const char *cp, ip_addr_t *addr); #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 @@ -274,6 +276,8 @@ 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; @@ -315,6 +319,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 */ From 80a24c03993e33ec3e92ded873279cd9931eb1f5 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 16 Nov 2016 23:39:43 +0100 Subject: [PATCH 018/184] raw, udp, tcp connect() does NOT need to match exact IP type - when PCB is bound to IPADDR_ANY_TYPE, it is OK to connect to IPv4 or IPv6 This should finally implement task #14187: Dual Stack sendto with socket APIs --- src/core/raw.c | 2 +- src/core/tcp.c | 2 +- src/core/udp.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/raw.c b/src/core/raw.c index e4ea13c1..93c65473 100644 --- a/src/core/raw.c +++ b/src/core/raw.c @@ -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); diff --git a/src/core/tcp.c b/src/core/tcp.c index eac05fbe..8712d76c 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -826,7 +826,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; } diff --git a/src/core/udp.c b/src/core/udp.c index 8c3a3ce5..491fb074 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -1007,7 +1007,7 @@ udp_connect(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) { struct udp_pcb *ipcb; - 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; } From e8e853f2cbd1e6cf64329b92c07de7dbb58a9e1b Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 16 Nov 2016 23:49:44 +0100 Subject: [PATCH 019/184] Move ICMP6 protocol constants to include/lwip/prot/icmp6 --- src/include/lwip/icmp6.h | 89 +---------------------------------- src/include/lwip/prot/icmp6.h | 87 ++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 88 deletions(-) diff --git a/src/include/lwip/icmp6.h b/src/include/lwip/icmp6.h index e66557d4..a29dc8c1 100644 --- a/src/include/lwip/icmp6.h +++ b/src/include/lwip/icmp6.h @@ -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); diff --git a/src/include/lwip/prot/icmp6.h b/src/include/lwip/prot/icmp6.h index a0a713ba..34611204 100644 --- a/src/include/lwip/prot/icmp6.h +++ b/src/include/lwip/prot/icmp6.h @@ -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" From 792224ead0fd3198b50fc6ff39f61b8d7608bb83 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 17 Nov 2016 08:48:55 +0100 Subject: [PATCH 020/184] Try to fix compile error with clang (found by Erik's Travis-CI) --- src/api/api_msg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/api/api_msg.c b/src/api/api_msg.c index e19a6a0c..3971bd63 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -545,12 +545,14 @@ 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; + enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4; LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */ - iptype = NETCONNTYPE_ISIPV6(netconn_type(msg->conn))? IPADDR_TYPE_ANY : IPADDR_TYPE_V4; + if(NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) { + iptype = IPADDR_TYPE_ANY; + } /* Allocate a PCB for this connection */ switch(NETCONNTYPE_GROUP(msg->conn->type)) { From 180ba72a068355eaaf253b5615f08e11b0772e2f Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 17 Nov 2016 08:51:07 +0100 Subject: [PATCH 021/184] Dual-stack: Use IPv6 mapped IPv4 addresses in receive() and getaddr() only in socket API, not in netconn API. It is better to present correct IP types in netconn API. Netconn API now accepts IPv6 mapped IPv4 addresses as well as IPv6 and IPv4 in send(), bind() and connect(), but does NOT map IPv4 to IPv6 mapped IPv4 in getaddr() and receive() functions. --- src/api/api_lib.c | 20 +------------------- src/api/sockets.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index 9be38b71..c3419370 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -231,14 +231,6 @@ netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) err = netconn_apimsg(lwip_netconn_do_getaddr, &msg); #endif /* LWIP_MPU_COMPATIBLE */ API_MSG_VAR_FREE(msg); - -#if LWIP_IPV4 && LWIP_IPV6 - /* Dual-stack: Map IPv4 addresses to IPv6 mapped IPv4 */ - if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4(addr)) { - ip4_2_ipv6_mapped_ipv4(ip_2_ip6(addr), ip_2_ip4(addr)); - IP_SET_TYPE(addr, IPADDR_TYPE_V6); - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ return err; } @@ -607,18 +599,8 @@ netconn_recv_data(struct netconn *conn, void **new_buf) #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ #if (LWIP_UDP || LWIP_RAW) { - struct netbuf* nbuf = (struct netbuf*)buf; - LWIP_ASSERT("buf != NULL", buf != NULL); - len = netbuf_len(nbuf); - -#if LWIP_IPV4 && LWIP_IPV6 - /* Dual-stack: Map IPv4 addresses to IPv6 mapped IPv4 */ - if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4_VAL(nbuf->addr)) { - ip4_2_ipv6_mapped_ipv4(ip_2_ip6(&nbuf->addr), ip_2_ip4(&nbuf->addr)); - IP_SET_TYPE_VAL(nbuf->addr, IPADDR_TYPE_V6); - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ + len = netbuf_len((struct netbuf*)buf); } #endif /* (LWIP_UDP || LWIP_RAW) */ diff --git a/src/api/sockets.c b/src/api/sockets.c index 9726f0c8..22f3acd6 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -847,6 +847,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)); @@ -1710,6 +1719,15 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) 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)); From 44e430ebc2a0f5ed2879b89204d950fd5e9d42aa Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 17 Nov 2016 09:12:38 +0100 Subject: [PATCH 022/184] Fix compile with MSVC 2010 and remove handling for IP6_ADDR_ANY in netconn_connect() - IP6_ADDR_ANY does not make sense in connect() --- src/api/api_lib.c | 82 ++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index c3419370..4ffb0a21 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -250,7 +250,6 @@ err_t netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) { API_MSG_VAR_DECLARE(msg); - ip_addr_t ipaddr; err_t err; LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); @@ -260,30 +259,33 @@ netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) addr = IP4_ADDR_ANY; } - ip_addr_copy(ipaddr, *addr); + { +#if LWIP_IPV4 && LWIP_IPV6 + ip_addr_t 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 0, use IP_ANY_TYPE to bind - */ - if ((netconn_get_ipv6only(conn) == 0) && - ip_addr_cmp(&ipaddr, IP6_ADDR_ANY)) { - ip_addr_copy(ipaddr, *IP_ANY_TYPE); - } + /* "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; + } - /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ - if (IP_IS_V6_VAL(ipaddr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&ipaddr))) { - unmap_ipv6_mapped_ipv4(ip_2_ip4(&ipaddr), ip_2_ip6(&ipaddr)); - IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); - } + /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ + if (IP_IS_V6(addr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(addr))) { + unmap_ipv6_mapped_ipv4(ip_2_ip4(&ipaddr), ip_2_ip6(addr)); + IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); + addr = &ipaddr; + } #endif /* LWIP_IPV4 && LWIP_IPV6 */ - API_MSG_VAR_ALLOC(msg); - API_MSG_VAR_REF(msg).conn = conn; - API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(&ipaddr); - API_MSG_VAR_REF(msg).msg.bc.port = port; - err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg)); - API_MSG_VAR_FREE(msg); + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); + API_MSG_VAR_REF(msg).msg.bc.port = port; + err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + } return err; } @@ -301,7 +303,6 @@ err_t netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port) { API_MSG_VAR_DECLARE(msg); - ip_addr_t ipaddr; err_t err; LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); @@ -311,30 +312,25 @@ netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port) addr = IP4_ADDR_ANY; } - ip_addr_copy(ipaddr, *addr); + { +#if LWIP_IPV4 && LWIP_IPV6 + ip_addr_t 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 0, use IP_ANY_TYPE to bind - */ - if ((netconn_get_ipv6only(conn) == 0) && - ip_addr_cmp(&ipaddr, IP6_ADDR_ANY)) { - ip_addr_copy(ipaddr, *IP_ANY_TYPE); - } - - /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ - if (IP_IS_V6_VAL(ipaddr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(&ipaddr))) { - unmap_ipv6_mapped_ipv4(ip_2_ip4(&ipaddr), ip_2_ip6(&ipaddr)); - IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); - } + /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ + if (IP_IS_V6(addr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(addr))) { + unmap_ipv6_mapped_ipv4(ip_2_ip4(&ipaddr), ip_2_ip6(addr)); + IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); + addr = &ipaddr; + } #endif /* LWIP_IPV4 && LWIP_IPV6 */ - API_MSG_VAR_ALLOC(msg); - API_MSG_VAR_REF(msg).conn = conn; - API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(&ipaddr); - API_MSG_VAR_REF(msg).msg.bc.port = port; - err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg)); - API_MSG_VAR_FREE(msg); + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); + API_MSG_VAR_REF(msg).msg.bc.port = port; + err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + } return err; } From 4b7e0f50b7e6a94e22ec7cb8369222f286ae92ec Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 17 Nov 2016 09:14:29 +0100 Subject: [PATCH 023/184] Fix indent in api_lib.c --- src/api/api_lib.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index 4ffb0a21..ae366ad4 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -273,9 +273,9 @@ netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ if (IP_IS_V6(addr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(addr))) { - unmap_ipv6_mapped_ipv4(ip_2_ip4(&ipaddr), ip_2_ip6(addr)); - IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); - addr = &ipaddr; + unmap_ipv6_mapped_ipv4(ip_2_ip4(&ipaddr), ip_2_ip6(addr)); + IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); + addr = &ipaddr; } #endif /* LWIP_IPV4 && LWIP_IPV6 */ @@ -318,9 +318,9 @@ netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port) /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ if (IP_IS_V6(addr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(addr))) { - unmap_ipv6_mapped_ipv4(ip_2_ip4(&ipaddr), ip_2_ip6(addr)); - IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); - addr = &ipaddr; + unmap_ipv6_mapped_ipv4(ip_2_ip4(&ipaddr), ip_2_ip6(addr)); + IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); + addr = &ipaddr; } #endif /* LWIP_IPV4 && LWIP_IPV6 */ From 5d5eeca0080804b10aca360e7569ed262c81237a Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 17 Nov 2016 09:23:57 +0100 Subject: [PATCH 024/184] Once more: Try fix compile with clang --- src/api/api_msg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 3971bd63..e0b062bb 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -549,10 +549,12 @@ pcb_new(struct api_msg *msg) 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)) { From 9366c0eaabde4ef2744ab93d40e96def453925dc Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 17 Nov 2016 12:41:00 +0100 Subject: [PATCH 025/184] I decided to keep the "complexity" of handling IPv6 mapped IPv4 addresses out of netconn API. Only socket API understands this address type now. --- src/api/api_lib.c | 70 +++++++++++++---------------------------------- src/api/sockets.c | 35 +++++++++++++++++++++++- 2 files changed, 53 insertions(+), 52 deletions(-) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index ae366ad4..31be589c 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -259,33 +259,22 @@ netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) addr = IP4_ADDR_ANY; } - { #if LWIP_IPV4 && LWIP_IPV6 - ip_addr_t ipaddr; - - /* "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; - } - - /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ - if (IP_IS_V6(addr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(addr))) { - unmap_ipv6_mapped_ipv4(ip_2_ip4(&ipaddr), ip_2_ip6(addr)); - IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); - addr = &ipaddr; - } + /* "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; - API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); - API_MSG_VAR_REF(msg).msg.bc.port = port; - err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg)); - API_MSG_VAR_FREE(msg); - } + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); + API_MSG_VAR_REF(msg).msg.bc.port = port; + err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); return err; } @@ -312,25 +301,12 @@ netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port) addr = IP4_ADDR_ANY; } - { -#if LWIP_IPV4 && LWIP_IPV6 - ip_addr_t ipaddr; - - /* Dual-stack: Unmap IPv6 mapped IPv4 addresses */ - if (IP_IS_V6(addr) && ip6_addr_isipv6mappedipv4(ip_2_ip6(addr))) { - unmap_ipv6_mapped_ipv4(ip_2_ip4(&ipaddr), ip_2_ip6(addr)); - IP_SET_TYPE_VAL(ipaddr, IPADDR_TYPE_V4); - addr = &ipaddr; - } -#endif /* LWIP_IPV4 && LWIP_IPV6 */ - - API_MSG_VAR_ALLOC(msg); - API_MSG_VAR_REF(msg).conn = conn; - API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); - API_MSG_VAR_REF(msg).msg.bc.port = port; - err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg)); - API_MSG_VAR_FREE(msg); - } + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); + API_MSG_VAR_REF(msg).msg.bc.port = port; + err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); return err; } @@ -731,14 +707,6 @@ 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)); - -#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 */ API_MSG_VAR_ALLOC(msg); API_MSG_VAR_REF(msg).conn = conn; diff --git a/src/api/sockets.c b/src/api/sockets.c index 22f3acd6..2db0949d 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -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); } @@ -1075,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); } @@ -1165,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); } @@ -1722,7 +1754,8 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) #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)) { + 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); } From 31b0237c501652e6e18f0705e473004f5e20823a Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Fri, 18 Nov 2016 08:13:15 +0100 Subject: [PATCH 026/184] Apply patch #9165: Allowing udp src port to be 0 in cases when we don't care about outgoing port --- src/core/udp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/core/udp.c b/src/core/udp.c index 491fb074..ebb04edc 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -283,8 +283,12 @@ udp_input(struct pbuf *p, struct netif *inp) uncon_pcb = pcb; } - /* compare PCB remote addr+port to UDP source addr+port */ - if ((pcb->remote_port == src) && + /* Compare PCB remote addr+port to UDP source addr+port. + * Allow pcb->remote_port 0 for matching any port + * from a specified pcb->remote_ip. + * See patch #9165 + */ + if (((pcb->remote_port == src) || (pcb->remote_port == 0)) && (ip_addr_isany_val(pcb->remote_ip) || ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()))) { /* the first fully matching PCB */ From 0034abfa45abc9d6a3b4382627a02a2c88d2d385 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Fri, 18 Nov 2016 22:25:48 +0000 Subject: [PATCH 027/184] Always check whether netif_default is NULL In general, netif_default may be NULL, and various places in the code already check for this case before attempting to dereference the netif_default pointer. Some places do not perform this check though, and may cause null pointer dereferences if netif_default is not set. This patch adds NULL checks to those places as well. --- src/core/ipv4/ip4.c | 2 +- src/core/ipv6/ip6.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index c7836774..ceaeb7c6 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -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 */ diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c index 8cc9c010..d645c55f 100644 --- a/src/core/ipv6/ip6.c +++ b/src/core/ipv6/ip6.c @@ -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; @@ -172,7 +174,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 */ From 4076b12ee93e13fc60c59cf92068588489a96608 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Tue, 22 Nov 2016 14:35:45 +0100 Subject: [PATCH 028/184] Revert "Apply patch #9165: Allowing udp src port to be 0 in cases when we don't care about outgoing port" This reverts commit 31b0237c501652e6e18f0705e473004f5e20823a. --- src/core/udp.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/core/udp.c b/src/core/udp.c index ebb04edc..491fb074 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -283,12 +283,8 @@ udp_input(struct pbuf *p, struct netif *inp) uncon_pcb = pcb; } - /* Compare PCB remote addr+port to UDP source addr+port. - * Allow pcb->remote_port 0 for matching any port - * from a specified pcb->remote_ip. - * See patch #9165 - */ - if (((pcb->remote_port == src) || (pcb->remote_port == 0)) && + /* compare PCB remote addr+port to UDP source addr+port */ + if ((pcb->remote_port == src) && (ip_addr_isany_val(pcb->remote_ip) || ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()))) { /* the first fully matching PCB */ From 68ec20fffc2e98dd9b9fdc0d606fe5e718a16754 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Tue, 22 Nov 2016 18:36:51 +0000 Subject: [PATCH 029/184] ipv4/ipv6: restrict loopback-destined traffic Generally speaking, packets with a loopback destination address - 127.0.0.1 for IPv4 and ::1 for IPv6 - should not be accepted on non-loopback interfaces. For IPv4, this is implied by RFC 1122 Sec. 3.2.1.3. For IPv6, it is mandated by RFC 4291 Sec. 2.5.3. Failure to perform this filtering may have security implications, as applications that bind sockets to loopback addresses may not expect that nodes on the local external network be able to produce traffic that will arrive at such sockets. With this patch, lwIP drops packets that are sent to a loopback address but do not originate from the interface that has the loopback address assigned to it. This approach works regardless of whether it is lwIP or the system using it that implements a loopback netif. The only exception that must be made is for configurations that enable netif packet loopback but disable the lwIP loopback netif: in that case, loopback packets are routed across non-loopback netifs and would thus be lost by the new filter as well. For IPv6, loopback-destined packets are also no longer forwarded; the IPv4 forwarding code already had a check for that. As a small performance improvement, the IPv6 link-local/loopback address check is now performed only once per packet rather than repeatedly for every candidate netif. --- src/core/ipv4/ip4.c | 9 +++++++++ src/core/ipv6/ip6.c | 24 +++++++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index ceaeb7c6..7dfca76a 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -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 { diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c index d645c55f..0cb03182 100644 --- a/src/core/ipv6/ip6.c +++ b/src/core/ipv6/ip6.c @@ -292,8 +292,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); @@ -511,12 +512,21 @@ ip6_input(struct pbuf *p, struct netif *inp) } } } - if (ip6_addr_islinklocal(ip6_current_dest_addr())) { - /* Do not match link-local addresses to other netifs. */ - netif = NULL; - break; - } if (first) { + if (ip6_addr_islinklocal(ip6_current_dest_addr()) +#if !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF + || ip6_addr_isloopback(ip6_current_dest_addr()) +#endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */ + ) { + /* Do not match link-local addresses to other netifs. The loopback + * address is to be considered link-local and packets to it should be + * dropped on other interfaces, as per RFC 4291 Sec. 2.5.3. This + * requirement cannot be implemented in the case that loopback + * traffic is sent across a non-loopback interface, however. + */ + netif = NULL; + break; + } first = 0; netif = netif_list; } else { From 03a9aac15709b3a1ba8a713e1191c48e5d44e65a Mon Sep 17 00:00:00 2001 From: sg Date: Tue, 22 Nov 2016 21:34:12 +0100 Subject: [PATCH 030/184] dns_enqueue(): minor readability improvement: add local variable "age" to store result of subtraction --- src/core/dns.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/dns.c b/src/core/dns.c index 2aa1dd99..65355be7 100644 --- a/src/core/dns.c +++ b/src/core/dns.c @@ -1244,8 +1244,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; } } From 8c3c96baf7b744163d0fe9bc211036fefc3805a5 Mon Sep 17 00:00:00 2001 From: Sylvain Rochet Date: Tue, 22 Nov 2016 22:13:24 +0100 Subject: [PATCH 031/184] PPP, L2TP: fix PPPOL2TP_AUTH_SUPPORT == 0 support Fix compiler warnings on unused parameters and a function signature mismatch in PPPAPI. --- src/netif/ppp/pppapi.c | 5 +++++ src/netif/ppp/pppol2tp.c | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/netif/ppp/pppapi.c b/src/netif/ppp/pppapi.c index e2bedc75..947f7ba8 100644 --- a/src/netif/ppp/pppapi.c +++ b/src/netif/ppp/pppapi.c @@ -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; diff --git a/src/netif/ppp/pppol2tp.c b/src/netif/ppp/pppol2tp.c index c215cff6..f6e0f3a1 100644 --- a/src/netif/ppp/pppol2tp.c +++ b/src/netif/ppp/pppol2tp.c @@ -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; From 09547832ba683f07364d9526e080479286494c36 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 23 Nov 2016 12:46:35 +0100 Subject: [PATCH 032/184] Fix bug #49662: UDP layer should filter incoming multicast datagrams against the bound IP address Change lwIP UDP API to match socket behavior. 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. --- src/core/udp.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/core/udp.c b/src/core/udp.c index 491fb074..5786e4f9 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -178,15 +178,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; } } From 0f87cb92b82b183d81175b2f5b58904157c92acb Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 23 Nov 2016 13:10:16 +0100 Subject: [PATCH 033/184] Add note about UDP multicast behavior fix to UPGRADING document --- UPGRADING | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/UPGRADING b/UPGRADING index c42c67d1..d9b9d4ab 100644 --- a/UPGRADING +++ b/UPGRADING @@ -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) From 5030fa81a020280c467126568027608fa08e5136 Mon Sep 17 00:00:00 2001 From: Joel Cunningham Date: Wed, 23 Nov 2016 09:45:38 -0600 Subject: [PATCH 034/184] bug #49684, api_msg: treat non-blocking ERR_MEM as ERR_WOULDBLOCK This corrects a case in lwip_netconn_do_writemore() where if a non-blocking socket receives ERR_MEM in a call to tcp_write(), it would return ERR_MEM, which would result in ENOMEM coming out of the socket layer This case can be gracefully handled by returning ERR_WOULDBLOCK since the socket is already marked as no longer writable and sent_tcp/poll_tcp will mark the socket as writable again based on available buffer space This is very similiar to how ERR_MEM is resolved for blocking sockets --- src/api/api_msg.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/api/api_msg.c b/src/api/api_msg.c index e0b062bb..10092285 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -1572,10 +1572,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); @@ -1586,6 +1587,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 From eb1de78ce1b08863f9e5f5e680a47a0e9bb15a35 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Thu, 24 Nov 2016 11:12:22 +0100 Subject: [PATCH 035/184] prepare CHANGELOG for post-2.0.0 --- CHANGELOG | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 8f030fde..b1f592a9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,13 @@ HISTORY ++ New features: + ++ Bugfixes: + + +(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 From 4c8620e03b1b5a0681c4fa3f706d57ee3aeada65 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Thu, 24 Nov 2016 11:21:00 +0100 Subject: [PATCH 036/184] Added important post-2.0.0 changes to CHANGELOG to keep track of changes for future 2.0.1 release --- CHANGELOG | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index b1f592a9..482ab89b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,8 +6,28 @@ HISTORY ++ New features: + 2016-11-16: Dirk Ziegelmeier + * sockets.c: added support for IPv6 mapped IPv4 addresses + ++ Bugfixes: + 2016-11-23: Dirk Ziegelmeier + * udp.c: fixed bug #49662: ulticast 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 + + 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) From 8ba7363d11088fe37ceeaae5652d745ea3795342 Mon Sep 17 00:00:00 2001 From: Ambroz Bizjak Date: Thu, 24 Nov 2016 11:27:34 +0100 Subject: [PATCH 037/184] Optimize passing contiguous nocopy buffers to tcp_write While TCP_OVERSIZE works only when tcp_write() is used with TCP_WRITE_FLAG_COPY, this new code achieves similar benefits for the use case that the caller manages their own send buffers and passes successive chunks of those to tcp_write() without TCP_WRITE_FLAG_COPY. In particular, if a buffer is passed to tcp_write() that is adjacent in memory to the previously passed buffer, it will be combined into the previous ROM pbuf reference whenever possible, thus extending that ROM pbuf rather than allocating a new ROM pbuf. For the aforementioned use case, the advantages of this code are twofold: 1) fewer ROM pbufs need to be allocated to send the same data, and, 2) the MAC layer gets outgoing TCP packets with shorter pbuf chains. Original patch by Ambroz Bizjak Edited by David van Moolenbroek Signed-off-by: goldsimon --- CHANGELOG | 3 +++ src/core/tcp_out.c | 64 +++++++++++++++++++++++++++++++++------------- 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 482ab89b..347ef150 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,9 @@ HISTORY ++ New features: + 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 diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 28d17441..8ccdffb9 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -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,12 +511,24 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) #if TCP_CHECKSUM_ON_COPY concat_chksummed += seglen; #endif /* TCP_CHECKSUM_ON_COPY */ + queuelen += pbuf_clen(concat_p); } else { /* Data is not copied */ - if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("tcp_write: could not allocate memory for zero-copy pbuf\n")); - goto memerr; + /* If the last unsent pbuf is of type PBUF_ROM, try to extend it. */ + struct pbuf *p; + for (p = last_unsent->p; p->next != NULL; p = p->next); + if (p->type == PBUF_ROM && (const u8_t *)p->payload + p->len == (const u8_t *)arg) { + LWIP_ASSERT("tcp_write: ROM pbufs cannot be oversized", pos == 0); + extendlen = seglen; + } else { + if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("tcp_write: could not allocate memory for zero-copy pbuf\n")); + goto memerr; + } + /* reference the non-volatile payload data */ + ((struct pbuf_rom*)concat_p)->payload = (const u8_t*)arg + pos; + queuelen += pbuf_clen(concat_p); } #if TCP_CHECKSUM_ON_COPY /* calculate the checksum of nocopy-data */ @@ -519,12 +536,9 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) &concat_chksum, &concat_chksum_swapped); concat_chksummed += seglen; #endif /* TCP_CHECKSUM_ON_COPY */ - /* reference the non-volatile payload data */ - ((struct pbuf_rom*)concat_p)->payload = (const u8_t*)arg + pos; } pos += seglen; - queuelen += pbuf_clen(concat_p); } } else { #if TCP_OVERSIZE @@ -669,26 +683,40 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) #endif /* TCP_OVERSIZE */ /* - * Phase 2: concat_p can be concatenated onto last_unsent->p + * Phase 2: concat_p can be concatenated onto last_unsent->p, unless we + * determined that the last ROM pbuf can be extended to include the new data. */ if (concat_p != NULL) { LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty", (last_unsent != NULL)); pbuf_cat(last_unsent->p, concat_p); last_unsent->len += concat_p->tot_len; -#if TCP_CHECKSUM_ON_COPY - if (concat_chksummed) { - /*if concat checksumm swapped - swap it back */ - if (concat_chksum_swapped) { - concat_chksum = SWAP_BYTES_IN_WORD(concat_chksum); - } - tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum, - &last_unsent->chksum_swapped); - last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED; + } else if (extendlen > 0) { + struct pbuf *p; + LWIP_ASSERT("tcp_write: extension of reference requires reference", + last_unsent != NULL && last_unsent->p != NULL); + for (p = last_unsent->p; p->next != NULL; p = p->next) { + p->tot_len += extendlen; } -#endif /* TCP_CHECKSUM_ON_COPY */ + p->tot_len += extendlen; + p->len += extendlen; + last_unsent->len += extendlen; } +#if TCP_CHECKSUM_ON_COPY + if (concat_chksummed) { + LWIP_ASSERT("tcp_write: concat checksum needs concatenated data", + concat_p != NULL || extendlen > 0); + /*if concat checksumm swapped - swap it back */ + if (concat_chksum_swapped) { + concat_chksum = SWAP_BYTES_IN_WORD(concat_chksum); + } + tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum, + &last_unsent->chksum_swapped); + last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED; + } +#endif /* TCP_CHECKSUM_ON_COPY */ + /* * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that * is harmless From f419231dc33f75bccd72a9f2fd018615fd05573b Mon Sep 17 00:00:00 2001 From: goldsimon Date: Thu, 24 Nov 2016 11:31:46 +0100 Subject: [PATCH 038/184] fixed typo in CHANGELOG --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 347ef150..b5a06e71 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,7 +15,7 @@ HISTORY ++ Bugfixes: 2016-11-23: Dirk Ziegelmeier - * udp.c: fixed bug #49662: ulticast traffic is now only received on a UDP PCB + * 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 From 2ed755764ef933095b644e4f0d713e4675778653 Mon Sep 17 00:00:00 2001 From: Richard Sailer Date: Wed, 23 Nov 2016 22:46:22 +0100 Subject: [PATCH 039/184] doxygen/generate.sh: Add shebang line This file had the x bit set. But executing it produced an error, since it was missing the "#!/bin/sh" line. This patch adds the "#!/bin/sh" line and makes generate.sh directly executable. --- doc/doxygen/generate.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/doxygen/generate.sh b/doc/doxygen/generate.sh index 99afb124..89344b0e 100755 --- a/doc/doxygen/generate.sh +++ b/doc/doxygen/generate.sh @@ -1 +1,3 @@ +#!/bin/sh + doxygen lwip.Doxyfile From 0e07ed4b13fb8a3f23158b11dc298b4c9486bbfb Mon Sep 17 00:00:00 2001 From: goldsimon Date: Fri, 25 Nov 2016 10:03:43 +0100 Subject: [PATCH 040/184] fixed bug #49676 (Possible endless loop when parsing dhcp options) & added unit test for that --- CHANGELOG | 3 + src/core/ipv4/dhcp.c | 2 + test/unit/dhcp/test_dhcp.c | 111 ++++++++++++++++++++++++++++++++++++- 3 files changed, 114 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b5a06e71..2859a03c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,9 @@ HISTORY ++ Bugfixes: + 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 diff --git a/src/core/ipv4/dhcp.c b/src/core/ipv4/dhcp.c index de5fc73b..abff34dd 100644 --- a/src/core/ipv4/dhcp.c +++ b/src/core/ipv4/dhcp.c @@ -1541,6 +1541,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): diff --git a/test/unit/dhcp/test_dhcp.c b/test/unit/dhcp/test_dhcp.c index 68f28819..3ff42cc4 100644 --- a/test/unit/dhcp/test_dhcp.c +++ b/test/unit/dhcp/test_dhcp.c @@ -120,7 +120,8 @@ static enum tcase { TEST_LWIP_DHCP, TEST_LWIP_DHCP_NAK, TEST_LWIP_DHCP_RELAY, - TEST_LWIP_DHCP_NAK_NO_ENDMARKER + TEST_LWIP_DHCP_NAK_NO_ENDMARKER, + TEST_LWIP_DHCP_INVALID_OVERLOAD } tcase; static int debug = 0; @@ -904,6 +905,111 @@ START_TEST(test_dhcp_nak_no_endmarker) } END_TEST +START_TEST(test_dhcp_invalid_overload) +{ + u8_t dhcp_offer_invalid_overload[] = { + 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, /* To unit */ + 0x00, 0x0F, 0xEE, 0x30, 0xAB, 0x22, /* From Remote host */ + 0x08, 0x00, /* Protocol: IP */ + 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x36, 0xcc, 0xc3, 0xaa, 0xbd, 0xab, 0xc3, 0xaa, 0xbd, 0xc8, /* IP header */ + 0x00, 0x43, 0x00, 0x44, 0x01, 0x34, 0x00, 0x00, /* UDP header */ + + 0x02, /* Type == Boot reply */ + 0x01, 0x06, /* Hw Ethernet, 6 bytes addrlen */ + 0x00, /* 0 hops */ + 0xAA, 0xAA, 0xAA, 0xAA, /* Transaction id, will be overwritten */ + 0x00, 0x00, /* 0 seconds elapsed */ + 0x00, 0x00, /* Flags (unicast) */ + 0x00, 0x00, 0x00, 0x00, /* Client ip */ + 0xc3, 0xaa, 0xbd, 0xc8, /* Your IP */ + 0xc3, 0xaa, 0xbd, 0xab, /* DHCP server ip */ + 0x00, 0x00, 0x00, 0x00, /* relay agent */ + 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MAC addr + padding */ + + /* Empty server name */ + 0x34, 0x01, 0x02, 0xff, /* Overload: SNAME + END */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Empty boot file name */ + 0x34, 0x01, 0x01, 0xff, /* Overload FILE + END */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x63, 0x82, 0x53, 0x63, /* Magic cookie */ + 0x35, 0x01, 0x02, /* Message type: Offer */ + 0x36, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* Server identifier (IP) */ + 0x33, 0x04, 0x00, 0x00, 0x00, 0x78, /* Lease time 2 minutes */ + 0x03, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* Router IP */ + 0x01, 0x04, 0xff, 0xff, 0xff, 0x00, /* Subnet mask */ + 0x34, 0x01, 0x03, /* Overload: FILE + SNAME */ + 0xff, /* End option */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Padding */ + }; + ip4_addr_t addr; + ip4_addr_t netmask; + ip4_addr_t gw; + u32_t xid; + LWIP_UNUSED_ARG(_i); + + tcase = TEST_LWIP_DHCP_INVALID_OVERLOAD; + setdebug(0); + + IP4_ADDR(&addr, 0, 0, 0, 0); + IP4_ADDR(&netmask, 0, 0, 0, 0); + IP4_ADDR(&gw, 0, 0, 0, 0); + + netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); + netif_set_up(&net_test); + + dhcp_start(&net_test); + + fail_unless(txpacket == 1); /* DHCP discover sent */ + xid = htonl(netif_dhcp_data(&net_test)->xid); + memcpy(&dhcp_offer_invalid_overload[46], &xid, 4); /* insert correct transaction id */ + dhcp_offer_invalid_overload[311] = 3; + send_pkt(&net_test, dhcp_offer_invalid_overload, sizeof(dhcp_offer_invalid_overload)); + /* IP addresses should be zero */ + fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); + fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); + fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); + fail_unless(txpacket == 1); /* Nothing more sent */ + + dhcp_offer_invalid_overload[311] = 2; + send_pkt(&net_test, dhcp_offer_invalid_overload, sizeof(dhcp_offer_invalid_overload)); + /* IP addresses should be zero */ + fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); + fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); + fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); + fail_unless(txpacket == 1); /* Nothing more sent */ + + dhcp_offer_invalid_overload[311] = 1; + send_pkt(&net_test, dhcp_offer_invalid_overload, sizeof(dhcp_offer_invalid_overload)); + /* IP addresses should be zero */ + fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); + fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); + fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); + fail_unless(txpacket == 1); /* Nothing more sent */ + + dhcp_offer_invalid_overload[311] = 0; + send_pkt(&net_test, dhcp_offer_invalid_overload, sizeof(dhcp_offer)); + + fail_unless(netif_dhcp_data(&net_test)->state == DHCP_STATE_REQUESTING); + + fail_unless(txpacket == 2); /* No more sent */ + xid = htonl(netif_dhcp_data(&net_test)->xid); /* xid updated */ + + netif_remove(&net_test); +} +END_TEST /** Create the suite including all tests for this module */ Suite * @@ -913,7 +1019,8 @@ dhcp_suite(void) TESTFUNC(test_dhcp), TESTFUNC(test_dhcp_nak), TESTFUNC(test_dhcp_relayed), - TESTFUNC(test_dhcp_nak_no_endmarker) + TESTFUNC(test_dhcp_nak_no_endmarker), + TESTFUNC(test_dhcp_invalid_overload) }; return create_suite("DHCP", tests, sizeof(tests)/sizeof(testfunc), dhcp_setup, dhcp_teardown); } From 1d4cbe768df73d86bbd16dbe648e9aee54f95116 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 25 Nov 2016 19:47:34 +0800 Subject: [PATCH 041/184] netif: Add proper lock protect for accessing netif->loop_first All the reset part of the code accessing netif->loop_first has lock protection, the only missing part is "while (netif->loop_first != NULL)". Fix it by adding lock protect around the while loop. Also convert the code to use while{} loop instead of do .. while{} loop, then we can avoid NULL test for in pointer in each loop and reduce a level of indent. Signed-off-by: Axel Lin --- src/core/netif.c | 83 +++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/src/core/netif.c b/src/core/netif.c index fc9e50b0..44e567d5 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -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,56 +915,52 @@ netif_poll(struct netif *netif) #endif /* MIB2_STATS */ SYS_ARCH_DECL_PROTECT(lev); - do { - /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ - SYS_ARCH_PROTECT(lev); - in = netif->loop_first; - if (in != NULL) { - struct pbuf *in_end = in; + /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ + SYS_ARCH_PROTECT(lev); + while (netif->loop_first != NULL) { + struct pbuf *in, *in_end; #if LWIP_LOOPBACK_MAX_PBUFS - u8_t clen = 1; -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ - while (in_end->len != in_end->tot_len) { - LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); - in_end = in_end->next; -#if LWIP_LOOPBACK_MAX_PBUFS - clen++; -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ - } -#if LWIP_LOOPBACK_MAX_PBUFS - /* adjust the number of pbufs on queue */ - LWIP_ASSERT("netif->loop_cnt_current underflow", - ((netif->loop_cnt_current - clen) < netif->loop_cnt_current)); - netif->loop_cnt_current -= clen; + u8_t clen = 1; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ - /* 'in_end' now points to the last pbuf from 'in' */ - if (in_end == netif->loop_last) { - /* this was the last pbuf in the list */ - netif->loop_first = netif->loop_last = NULL; - } else { - /* pop the pbuf off the list */ - netif->loop_first = in_end->next; - LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL); - } - /* De-queue the pbuf from its successors on the 'loop_' list. */ - in_end->next = NULL; + in = in_end = netif->loop_first; + while (in_end->len != in_end->tot_len) { + LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); + in_end = in_end->next; +#if LWIP_LOOPBACK_MAX_PBUFS + clen++; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ } +#if LWIP_LOOPBACK_MAX_PBUFS + /* adjust the number of pbufs on queue */ + LWIP_ASSERT("netif->loop_cnt_current underflow", + ((netif->loop_cnt_current - clen) < netif->loop_cnt_current)); + netif->loop_cnt_current -= clen; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + + /* 'in_end' now points to the last pbuf from 'in' */ + if (in_end == netif->loop_last) { + /* this was the last pbuf in the list */ + netif->loop_first = netif->loop_last = NULL; + } else { + /* pop the pbuf off the list */ + netif->loop_first = in_end->next; + LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL); + } + /* De-queue the pbuf from its successors on the 'loop_' list. */ + in_end->next = NULL; SYS_ARCH_UNPROTECT(lev); - if (in != NULL) { - LINK_STATS_INC(link.recv); - MIB2_STATS_NETIF_ADD(stats_if, ifinoctets, in->tot_len); - MIB2_STATS_NETIF_INC(stats_if, ifinucastpkts); - /* loopback packets are always IP packets! */ - if (ip_input(in, netif) != ERR_OK) { - pbuf_free(in); - } - /* Don't reference the packet any more! */ - in = NULL; + LINK_STATS_INC(link.recv); + MIB2_STATS_NETIF_ADD(stats_if, ifinoctets, in->tot_len); + MIB2_STATS_NETIF_INC(stats_if, ifinucastpkts); + /* loopback packets are always IP packets! */ + if (ip_input(in, netif) != ERR_OK) { + pbuf_free(in); } - /* go on while there is a packet on the list */ - } while (netif->loop_first != NULL); + SYS_ARCH_PROTECT(lev); + } + SYS_ARCH_UNPROTECT(lev); } #if !LWIP_NETIF_LOOPBACK_MULTITHREADING From aea872431ccc940510bbe76796577093b1fff445 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Fri, 25 Nov 2016 22:13:12 +0100 Subject: [PATCH 042/184] Fix naming of some inet_addr_* macros in inet.h From inet4_addr_* to inet_addr_* - inet_addr is a "known word", don't change it --- src/api/netdb.c | 2 +- src/api/sockets.c | 12 ++++++------ src/include/lwip/inet.h | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/api/netdb.c b/src/api/netdb.c index 9361913c..55f2f760 100644 --- a/src/api/netdb.c +++ b/src/api/netdb.c @@ -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 */ - inet4_addr_from_ip4addr(&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); diff --git a/src/api/sockets.c b/src/api/sockets.c index 2db0949d..4d2dd656 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -82,10 +82,10 @@ (sin)->sin_len = sizeof(struct sockaddr_in); \ (sin)->sin_family = AF_INET; \ (sin)->sin_port = lwip_htons((port)); \ - inet4_addr_from_ip4addr(&(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 { \ - inet4_addr_to_ip4addr(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 */ @@ -2046,7 +2046,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; } - inet4_addr_from_ip4addr((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; @@ -2410,7 +2410,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); - inet4_addr_to_ip4addr(&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; @@ -2434,8 +2434,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); - inet4_addr_to_ip4addr(&if_addr, &imr->imr_interface); - inet4_addr_to_ip4addr(&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) */ diff --git a/src/include/lwip/inet.h b/src/include/lwip/inet.h index 636f1575..4a34f026 100644 --- a/src/include/lwip/inet.h +++ b/src/include/lwip/inet.h @@ -132,10 +132,10 @@ extern const struct in6_addr in6addr_any; #if LWIP_IPV4 -#define inet4_addr_from_ip4addr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) -#define inet4_addr_to_ip4addr(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 inet4_addr_to_ip4addr_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) From cac3dc8a4610f829e6155513e9325c3bf305b312 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 28 Nov 2016 17:18:01 +0800 Subject: [PATCH 043/184] netif: Trivial indent fix Signed-off-by: Axel Lin --- src/core/netif.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/netif.c b/src/core/netif.c index 44e567d5..38db54c0 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -415,7 +415,7 @@ netif_remove(struct netif *netif) udp_netif_ip_addr_changed(netif_ip_addr6(netif, i), NULL); #endif /* LWIP_UDP */ #if LWIP_RAW - raw_netif_ip_addr_changed(netif_ip_addr6(netif, i), NULL); + raw_netif_ip_addr_changed(netif_ip_addr6(netif, i), NULL); #endif /* LWIP_RAW */ } } @@ -1053,7 +1053,7 @@ netif_ip6_addr_set_parts(struct netif *netif, s8_t addr_idx, u32_t i0, u32_t i1, udp_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), &new_ipaddr); #endif /* LWIP_UDP */ #if LWIP_RAW - raw_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), &new_ipaddr); + raw_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), &new_ipaddr); #endif /* LWIP_RAW */ } /* @todo: remove/readd mib2 ip6 entries? */ @@ -1105,7 +1105,7 @@ netif_ip6_addr_set_state(struct netif* netif, s8_t addr_idx, u8_t state) udp_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), NULL); #endif /* LWIP_UDP */ #if LWIP_RAW - raw_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), NULL); + raw_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), NULL); #endif /* LWIP_RAW */ /* @todo: remove mib2 ip6 entries? */ } From 6f1304e03e5833048f607de1c7c5d921890c25ea Mon Sep 17 00:00:00 2001 From: goldsimon Date: Mon, 28 Nov 2016 10:26:42 +0100 Subject: [PATCH 044/184] patch by Ambroz Bizjak: fixed bug #49717 (window size in received SYN and SYN-ACK assumed scaled) --- CHANGELOG | 4 ++++ src/core/tcp_in.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2859a03c..b8400536 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,10 @@ HISTORY ++ Bugfixes: + 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) diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 93268b34..7f42f577 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -602,7 +602,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 +751,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; From ca9342c54942d04c477f5a9dc98b63b25fa44fd8 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Mon, 28 Nov 2016 12:51:45 +0100 Subject: [PATCH 045/184] fixed bug #49725 (send-timeout: netwonn_write() can return ERR_OK without all bytes being written) --- CHANGELOG | 4 ++++ src/api/api_lib.c | 11 ++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b8400536..4598effe 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,10 @@ HISTORY ++ Bugfixes: + 2016-11-28: Simon Goldschmidt + * api_lib.c: fixed bug #49725 (send-timeout: netwonn_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) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index 31be589c..704a3e00 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -745,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. */ @@ -772,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 { From 2a882b63878c0e608637b8b2f85a7bfe8c9aa141 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Mon, 28 Nov 2016 12:54:17 +0100 Subject: [PATCH 046/184] minor: fixed indent --- src/api/api_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index 704a3e00..73225268 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -747,7 +747,7 @@ netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); #if LWIP_SO_SNDTIMEO if (conn->send_timeout != 0) { - dontblock = 1; + dontblock = 1; } #endif /* LWIP_SO_SNDTIMEO */ if (dontblock && !bytes_written) { From b934c3f4711fca0171e6a7d62c1f47b3d2ffd839 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Mon, 28 Nov 2016 15:50:59 +0100 Subject: [PATCH 047/184] fixed bug #49726: setsockopt() set TCP_NODELAY TCP_KEEPALIVE ... with a listen state TCP will crash --- src/api/sockets.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/api/sockets.c b/src/api/sockets.c index 4d2dd656..e493ba6b 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -2074,6 +2074,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); @@ -2467,6 +2470,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) { From 47fd67a35c1fac5e3bf085f4a276c9fec0743de7 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Mon, 28 Nov 2016 15:56:59 +0100 Subject: [PATCH 048/184] Remove TODO comments and one check from sockets.c indicating IPV6_V6ONLY socket option handling does not work --- src/api/sockets.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index e493ba6b..9cffd519 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -1745,7 +1745,6 @@ 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)); @@ -2121,10 +2120,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)); @@ -2520,7 +2515,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); From 182d7c138a5b845c74b7d364ee07af6105d8e786 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 30 Nov 2016 07:43:59 +0100 Subject: [PATCH 049/184] Add #include to a central place (arch.h) instead of #including it in several other files throughout lwip since size_t is needed in many places See http://lwip.100.n7.nabble.com/Issue-in-arch-h-for-lwIP-2-0-0-td27948.html --- src/core/inet_chksum.c | 1 - src/include/lwip/api.h | 3 +-- src/include/lwip/arch.h | 2 ++ src/include/lwip/mem.h | 3 ++- src/include/lwip/netdb.h | 3 +-- src/include/lwip/priv/api_msg.h | 3 +-- src/include/lwip/sockets.h | 2 -- 7 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/core/inet_chksum.c b/src/core/inet_chksum.c index 80289528..917f3e4f 100644 --- a/src/core/inet_chksum.c +++ b/src/core/inet_chksum.c @@ -51,7 +51,6 @@ #include "lwip/def.h" #include "lwip/ip_addr.h" -#include #include #ifndef LWIP_CHKSUM diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index d1394533..516bd163 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -43,8 +43,7 @@ /* Note: Netconn API is always available when sockets are enabled - * sockets are implemented on top of them */ -#include /* for size_t */ - +#include "lwip/arch.h" #include "lwip/netbuf.h" #include "lwip/sys.h" #include "lwip/ip_addr.h" diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index 473e4a4a..27923948 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -47,6 +47,8 @@ #include "arch/cc.h" +#include /* for size_t */ + /** 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 diff --git a/src/include/lwip/mem.h b/src/include/lwip/mem.h index e4f6a64d..ff208d25 100644 --- a/src/include/lwip/mem.h +++ b/src/include/lwip/mem.h @@ -45,7 +45,8 @@ extern "C" { #if MEM_LIBC_MALLOC -#include /* for size_t */ +#include "lwip/arch.h" + typedef size_t mem_size_t; #define MEM_SIZE_F SZT_F diff --git a/src/include/lwip/netdb.h b/src/include/lwip/netdb.h index 21688c65..d3d15dfa 100644 --- a/src/include/lwip/netdb.h +++ b/src/include/lwip/netdb.h @@ -38,8 +38,7 @@ #if LWIP_DNS && LWIP_SOCKET -#include /* for size_t */ - +#include "lwip/arch.h" #include "lwip/inet.h" #include "lwip/sockets.h" diff --git a/src/include/lwip/priv/api_msg.h b/src/include/lwip/priv/api_msg.h index ad383456..f12b8b7d 100644 --- a/src/include/lwip/priv/api_msg.h +++ b/src/include/lwip/priv/api_msg.h @@ -43,8 +43,7 @@ /* Note: Netconn API is always available when sockets are enabled - * sockets are implemented on top of them */ -#include /* for size_t */ - +#include "lwip/arch.h" #include "lwip/ip_addr.h" #include "lwip/err.h" #include "lwip/sys.h" diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index 9d76776f..2522056d 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -43,8 +43,6 @@ #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ -#include /* for size_t */ - #include "lwip/ip_addr.h" #include "lwip/err.h" #include "lwip/inet.h" From 12e35c4c12e8d50b973966ed7d598efe392e85f6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 30 Nov 2016 16:11:15 +0800 Subject: [PATCH 050/184] mdns: Fix assertion message in mdns_resp_add_service_txtitem() So we know which function emits the assertion. Signed-off-by: Axel Lin --- src/apps/mdns/mdns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/mdns/mdns.c b/src/apps/mdns/mdns.c index 92f7a2cc..c1401855 100644 --- a/src/apps/mdns/mdns.c +++ b/src/apps/mdns/mdns.c @@ -2019,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); From 7f48289fcd7c74acc48b41bc4f44061b0b164e9f Mon Sep 17 00:00:00 2001 From: Joel Cunningham Date: Tue, 29 Nov 2016 15:22:55 -0600 Subject: [PATCH 051/184] Increment ip.drop when dropping due to NULL netif This commit increments the ip.drop statistic when an IP packet is dropped due to no matching netif found and forwarding is disabled This adds parity to the other places where mib2.ipinaddrerrors and mib2.ipindiscards are incremented which also increment ip.drop --- src/core/ipv4/ip4.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index 7dfca76a..b72afab1 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -598,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); } From f28e63b2a33c7f9146decd5e0d46037a487f1c1a Mon Sep 17 00:00:00 2001 From: Joel Cunningham Date: Tue, 29 Nov 2016 16:12:26 -0600 Subject: [PATCH 052/184] Add netifapi macros for set link up/down This commit extends the netifapi macros to support netif_set_link_up and netif_set_link_down --- src/include/lwip/netifapi.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/include/lwip/netifapi.h b/src/include/lwip/netifapi.h index 20f8bcaa..8bd2b4f7 100644 --- a/src/include/lwip/netifapi.h +++ b/src/include/lwip/netifapi.h @@ -93,13 +93,17 @@ err_t netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc, netifapi_errt_fn errtfunc); /** @ingroup netifapi_netif */ -#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL) +#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL) /** @ingroup netifapi_netif */ -#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL) +#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL) /** @ingroup netifapi_netif */ -#define netifapi_netif_set_down(n) netifapi_netif_common(n, netif_set_down, NULL) +#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) +#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 From 7d0aeaf539e4c8b5af84831c68322b8cb7ad03b4 Mon Sep 17 00:00:00 2001 From: Joel Cunningham Date: Wed, 30 Nov 2016 10:26:49 -0600 Subject: [PATCH 053/184] Doc: correct minor mis-spelling in sys_arch.txt This corrects a minor mis-spelling where "by" was mis-spelled as "ny" --- doc/sys_arch.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sys_arch.txt b/doc/sys_arch.txt index 333946da..4dc727b6 100644 --- a/doc/sys_arch.txt +++ b/doc/sys_arch.txt @@ -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. From 4bbed75cc478a142e0f6a28d2176c6d91fcea863 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 1 Dec 2016 08:55:01 +0100 Subject: [PATCH 054/184] Minor code layout cleanup in err.c and errno.h --- src/api/err.c | 20 ++--- src/include/lwip/errno.h | 184 +++++++++++++++++++-------------------- 2 files changed, 101 insertions(+), 103 deletions(-) diff --git a/src/api/err.c b/src/api/err.c index 1593e70a..35e9c025 100644 --- a/src/api/err.c +++ b/src/api/err.c @@ -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 */ diff --git a/src/include/lwip/errno.h b/src/include/lwip/errno.h index 25bc1f89..641cffb0 100644 --- a/src/include/lwip/errno.h +++ b/src/include/lwip/errno.h @@ -45,100 +45,100 @@ extern "C" { #ifdef LWIP_PROVIDE_ERRNO -#define EPERM 1 /* Operation not permitted */ -#define ENOENT 2 /* No such file or directory */ -#define ESRCH 3 /* No such process */ -#define EINTR 4 /* Interrupted system call */ -#define EIO 5 /* I/O error */ -#define ENXIO 6 /* No such device or address */ -#define E2BIG 7 /* Arg list too long */ -#define ENOEXEC 8 /* Exec format error */ -#define EBADF 9 /* Bad file number */ -#define ECHILD 10 /* No child processes */ -#define EAGAIN 11 /* Try again */ -#define ENOMEM 12 /* Out of memory */ -#define EACCES 13 /* Permission denied */ -#define EFAULT 14 /* Bad address */ -#define ENOTBLK 15 /* Block device required */ -#define EBUSY 16 /* Device or resource busy */ -#define EEXIST 17 /* File exists */ -#define EXDEV 18 /* Cross-device link */ -#define ENODEV 19 /* No such device */ -#define ENOTDIR 20 /* Not a directory */ -#define EISDIR 21 /* Is a directory */ -#define EINVAL 22 /* Invalid argument */ -#define ENFILE 23 /* File table overflow */ -#define EMFILE 24 /* Too many open files */ -#define ENOTTY 25 /* Not a typewriter */ -#define ETXTBSY 26 /* Text file busy */ -#define EFBIG 27 /* File too large */ -#define ENOSPC 28 /* No space left on device */ -#define ESPIPE 29 /* Illegal seek */ -#define EROFS 30 /* Read-only file system */ -#define EMLINK 31 /* Too many links */ -#define EPIPE 32 /* Broken pipe */ -#define EDOM 33 /* Math argument out of domain of func */ -#define ERANGE 34 /* Math result not representable */ -#define EDEADLK 35 /* Resource deadlock would occur */ -#define ENAMETOOLONG 36 /* File name too long */ -#define ENOLCK 37 /* No record locks available */ -#define ENOSYS 38 /* Function not implemented */ -#define ENOTEMPTY 39 /* Directory not empty */ -#define ELOOP 40 /* Too many symbolic links encountered */ -#define EWOULDBLOCK EAGAIN /* Operation would block */ -#define ENOMSG 42 /* No message of desired type */ -#define EIDRM 43 /* Identifier removed */ -#define ECHRNG 44 /* Channel number out of range */ -#define EL2NSYNC 45 /* Level 2 not synchronized */ -#define EL3HLT 46 /* Level 3 halted */ -#define EL3RST 47 /* Level 3 reset */ -#define ELNRNG 48 /* Link number out of range */ -#define EUNATCH 49 /* Protocol driver not attached */ -#define ENOCSI 50 /* No CSI structure available */ -#define EL2HLT 51 /* Level 2 halted */ -#define EBADE 52 /* Invalid exchange */ -#define EBADR 53 /* Invalid request descriptor */ -#define EXFULL 54 /* Exchange full */ -#define ENOANO 55 /* No anode */ -#define EBADRQC 56 /* Invalid request code */ -#define EBADSLT 57 /* Invalid slot */ +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ -#define EDEADLOCK EDEADLK +#define EDEADLOCK EDEADLK -#define EBFONT 59 /* Bad font file format */ -#define ENOSTR 60 /* Device not a stream */ -#define ENODATA 61 /* No data available */ -#define ETIME 62 /* Timer expired */ -#define ENOSR 63 /* Out of streams resources */ -#define ENONET 64 /* Machine is not on the network */ -#define ENOPKG 65 /* Package not installed */ -#define EREMOTE 66 /* Object is remote */ -#define ENOLINK 67 /* Link has been severed */ -#define EADV 68 /* Advertise error */ -#define ESRMNT 69 /* Srmount error */ -#define ECOMM 70 /* Communication error on send */ -#define EPROTO 71 /* Protocol error */ -#define EMULTIHOP 72 /* Multihop attempted */ -#define EDOTDOT 73 /* RFS specific error */ -#define EBADMSG 74 /* Not a data message */ -#define EOVERFLOW 75 /* Value too large for defined data type */ -#define ENOTUNIQ 76 /* Name not unique on network */ -#define EBADFD 77 /* File descriptor in bad state */ -#define EREMCHG 78 /* Remote address changed */ -#define ELIBACC 79 /* Can not access a needed shared library */ -#define ELIBBAD 80 /* Accessing a corrupted shared library */ -#define ELIBSCN 81 /* .lib section in a.out corrupted */ -#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ -#define ELIBEXEC 83 /* Cannot exec a shared library directly */ -#define EILSEQ 84 /* Illegal byte sequence */ -#define ERESTART 85 /* Interrupted system call should be restarted */ -#define ESTRPIPE 86 /* Streams pipe error */ -#define EUSERS 87 /* Too many users */ -#define ENOTSOCK 88 /* Socket operation on non-socket */ -#define EDESTADDRREQ 89 /* Destination address required */ -#define EMSGSIZE 90 /* Message too long */ -#define EPROTOTYPE 91 /* Protocol wrong type for socket */ -#define ENOPROTOOPT 92 /* Protocol not available */ +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ #define EPROTONOSUPPORT 93 /* Protocol not supported */ #define ESOCKTNOSUPPORT 94 /* Socket type not supported */ #define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ From bcaf2f08aab5f86d384ffe96a09755ac1b8bd210 Mon Sep 17 00:00:00 2001 From: Sylvain Rochet Date: Wed, 30 Nov 2016 21:56:27 +0100 Subject: [PATCH 055/184] PPP, PPPoS: fix memory leak when disconnecting if there are remaining input bytes Art says: pppos_input() can call ppp_input() which can call pppos_disconnect() to disconnect the interface. However, it will continue to read in characters and allocate a pbuf from the PBUF_POOL and keep it in pppos->in_head and in_tail. When a re-connect happens and pppos_connect() is called, this pppos->in_head and in_tail are zeroed, hence a memory leak. (This happens with PPP_INPROC_IRQ_SAFE not defined.) A fix would be inside pppos_input() to break out of the loop inputting characters after calling ppp_input() if pppos->open == 0. Note that the loop is not even entered if pppos->open == 0. ppp_input(ppp, inp); if(pppos->open == 0) //get out if they disconnected break; Fix it in a similar way which doesn't add new code by moving the existing pppos->open check inside the byte loop. --- src/netif/ppp/pppos.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/netif/ppp/pppos.c b/src/netif/ppp/pppos.c index 5220ed30..eaeb2d12 100644 --- a/src/netif/ppp/pppos.c +++ b/src/netif/ppp/pppos.c @@ -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. */ From 92183bb3549a14b8a53e5eb86e05d22cd2272672 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 4 Dec 2016 20:00:43 +0800 Subject: [PATCH 056/184] icmp: Increment mib2.icmpintimeexcds counter if got ICMP_TE Increment mib2.icmpintimeexcds rather than mib2.icmpindestunreachs if got ICMP_TE. Signed-off-by: Axel Lin --- src/core/ipv4/icmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ipv4/icmp.c b/src/core/ipv4/icmp.c index e60e4481..6f5311d0 100644 --- a/src/core/ipv4/icmp.c +++ b/src/core/ipv4/icmp.c @@ -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) { From a6bc4227291c633f0efe889614560dc844ecfbae Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Mon, 5 Dec 2016 21:53:43 +0100 Subject: [PATCH 057/184] Move declaration of struct ip4_addr_packed and ip4_addr_p_t to prot/ip4.h The types are used in structs declared in ip4.h. --- src/include/lwip/ip4_addr.h | 15 --------------- src/include/lwip/prot/ip4.h | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/include/lwip/ip4_addr.h b/src/include/lwip/ip4_addr.h index 166acfab..0181d87f 100644 --- a/src/include/lwip/ip4_addr.h +++ b/src/include/lwip/ip4_addr.h @@ -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 diff --git a/src/include/lwip/prot/ip4.h b/src/include/lwip/prot/ip4.h index c3c34038..bd442c68 100644 --- a/src/include/lwip/prot/ip4.h +++ b/src/include/lwip/prot/ip4.h @@ -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 From 16877216000a926471c765f5c3912a29087c0536 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Mon, 5 Dec 2016 22:01:58 +0100 Subject: [PATCH 058/184] Fix compile when IPv4 is disabled --- src/api/api_lib.c | 6 ++++++ src/apps/lwiperf/lwiperf.c | 2 +- src/apps/snmp/snmp_netconn.c | 2 +- src/apps/sntp/sntp.c | 2 +- src/core/dns.c | 4 ++-- src/netif/ppp/ppp.c | 4 ++-- src/netif/ppp/pppol2tp.c | 2 +- 7 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index 73225268..1e356aa0 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -254,10 +254,12 @@ 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, @@ -296,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; @@ -881,6 +885,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; @@ -888,6 +893,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); diff --git a/src/apps/lwiperf/lwiperf.c b/src/apps/lwiperf/lwiperf.c index 1996cd1a..3bdd01c7 100644 --- a/src/apps/lwiperf/lwiperf.c +++ b/src/apps/lwiperf/lwiperf.c @@ -579,7 +579,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); } diff --git a/src/apps/snmp/snmp_netconn.c b/src/apps/snmp/snmp_netconn.c index 070b41c3..27c004df 100644 --- a/src/apps/snmp/snmp_netconn.c +++ b/src/apps/snmp/snmp_netconn.c @@ -52,7 +52,7 @@ snmp_netconn_thread(void *arg) LWIP_UNUSED_ARG(arg); /* Bind to SNMP port with default IP address */ - #if LWIP_IPV6 +#if LWIP_IPV6 conn = netconn_new(NETCONN_UDP_IPV6); netconn_bind(conn, IP6_ADDR_ANY, SNMP_IN_PORT); #else /* LWIP_IPV6 */ diff --git a/src/apps/sntp/sntp.c b/src/apps/sntp/sntp.c index fb952111..ac69650a 100644 --- a/src/apps/sntp/sntp.c +++ b/src/apps/sntp/sntp.c @@ -688,7 +688,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 diff --git a/src/core/dns.c b/src/core/dns.c index 65355be7..05870db0 100644 --- a/src/core/dns.c +++ b/src/core/dns.c @@ -329,7 +329,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 +348,7 @@ dns_getserver(u8_t numdns) if (numdns < DNS_MAX_SERVERS) { return &dns_servers[numdns]; } else { - return IP4_ADDR_ANY; + return IP_ADDR_ANY; } } diff --git a/src/netif/ppp/ppp.c b/src/netif/ppp/ppp.c index 0e37eeb2..d9b50777 100644 --- a/src/netif/ppp/ppp.c +++ b/src/netif/ppp/ppp.c @@ -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; } diff --git a/src/netif/ppp/pppol2tp.c b/src/netif/ppp/pppol2tp.c index f6e0f3a1..90cf1082 100644 --- a/src/netif/ppp/pppol2tp.c +++ b/src/netif/ppp/pppol2tp.c @@ -307,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 */ From cc25c2634bcb0010ab910b955f2200395ea470a5 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Tue, 6 Dec 2016 09:36:36 +0100 Subject: [PATCH 059/184] Cleanup: move struct ip6_addr_packed and ip6_addr_p_t type to prot/ip6.h - these types are used in prot/ip6.h and prot/mld6.h --- src/include/lwip/ip6_addr.h | 15 --------------- src/include/lwip/prot/ip6.h | 15 +++++++++++++++ src/include/lwip/prot/mld6.h | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/include/lwip/ip6_addr.h b/src/include/lwip/ip6_addr.h index 14d0f7cf..1171df9e 100644 --- a/src/include/lwip/ip6_addr.h +++ b/src/include/lwip/ip6_addr.h @@ -58,23 +58,8 @@ 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 diff --git a/src/include/lwip/prot/ip6.h b/src/include/lwip/prot/ip6.h index 4e3ca37d..6e1e2632 100644 --- a/src/include/lwip/prot/ip6.h +++ b/src/include/lwip/prot/ip6.h @@ -43,6 +43,21 @@ #ifdef __cplusplus 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 diff --git a/src/include/lwip/prot/mld6.h b/src/include/lwip/prot/mld6.h index 2664829b..be3a006a 100644 --- a/src/include/lwip/prot/mld6.h +++ b/src/include/lwip/prot/mld6.h @@ -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" { From 795acf020e5c3b082219ed5b73036dcb48ca55d6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 6 Dec 2016 09:01:43 +0800 Subject: [PATCH 060/184] lwiperf: Simplify #if LWIPERF_CHECK_RX_DATA guard The variable i is equal to q->len after exit the for loop. Check the received data should not change the logic of update packet_idx. So let's simplify the code a bit. Signed-off-by: Axel Lin --- src/apps/lwiperf/lwiperf.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/apps/lwiperf/lwiperf.c b/src/apps/lwiperf/lwiperf.c index 3bdd01c7..079dd6b1 100644 --- a/src/apps/lwiperf/lwiperf.c +++ b/src/apps/lwiperf/lwiperf.c @@ -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; From cb29a49a640dd88c59bbeace1fed17f5a76e531e Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Tue, 6 Dec 2016 11:39:03 +0100 Subject: [PATCH 061/184] Update CHANGELOG --- CHANGELOG | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4598effe..59e5be95 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,8 +14,11 @@ HISTORY ++ Bugfixes: + 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: netwonn_write() can return + * api_lib.c: fixed bug #49725 (send-timeout: netconn_write() can return ERR_OK without all bytes being written) 2016-11-28: Ambroz Bizjak @@ -30,7 +33,7 @@ HISTORY (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 + * *: 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 From e00a131160b44bbd63ef29f230c6adc26c74d2ac Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Tue, 6 Dec 2016 20:29:12 +0100 Subject: [PATCH 062/184] Fix bug #49778: sntp_stop does not cancel all timers Patch by Ari Suutari --- src/apps/sntp/sntp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/apps/sntp/sntp.c b/src/apps/sntp/sntp.c index ac69650a..71b2abed 100644 --- a/src/apps/sntp/sntp.c +++ b/src/apps/sntp/sntp.c @@ -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; } From c87855423c2da353f945bbbac05d94668cb9cdb3 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 7 Dec 2016 09:09:45 +0100 Subject: [PATCH 063/184] DNS: added compile-time check for some defines to fit into an u8_t (bug #49658) --- src/core/dns.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/core/dns.c b/src/core/dns.c index 05870db0..997a548e 100644 --- a/src/core/dns.c +++ b/src/core/dns.c @@ -116,6 +116,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 +130,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 +145,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 From b31b0c814882bddfb83819655e32bdf68d6873f3 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 7 Dec 2016 12:44:57 +0100 Subject: [PATCH 064/184] remove bogus LWIP_MAKE_U16() define and use PP_NTOHS() in ip4.c instead --- src/core/ipv4/ip4.c | 4 ++-- src/include/lwip/def.h | 7 ------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index b72afab1..2e2ce4bd 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -863,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 */ @@ -876,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 diff --git a/src/include/lwip/def.h b/src/include/lwip/def.h index bb07009c..befc4fb7 100644 --- a/src/include/lwip/def.h +++ b/src/include/lwip/def.h @@ -65,13 +65,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) From ff3656f4f5cc00355f0ce7777dbdd916cd8ffb2e Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 7 Dec 2016 13:06:07 +0100 Subject: [PATCH 065/184] Added improved macros for ip address initialization: IPADDR4_INIT_BYTES(), IPADDR6_INIT_HOST() and IP4_ADDR_MAKEU32() --- src/include/lwip/ip4_addr.h | 25 +++++++++++++------------ src/include/lwip/ip_addr.h | 6 ++++++ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/include/lwip/ip4_addr.h b/src/include/lwip/ip4_addr.h index 0181d87f..a53257fe 100644 --- a/src/include/lwip/ip4_addr.h +++ b/src/include/lwip/ip4_addr.h @@ -118,22 +118,23 @@ struct netif; #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) +/** Convert IP address given by the four byte-parts to an u32_t. */ +#define IP4_ADDR_MAKEU32(a,b,c,d) (((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. +/** Convert IP address given by the four byte-parts to an u32_t. 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) +#define IP4_ADDR_MAKEU32(a,b,c,d) (((u32_t)((d) & 0xff) << 24) | \ + ((u32_t)((c) & 0xff) << 16) | \ + ((u32_t)((b) & 0xff) << 8) | \ + (u32_t)((a) & 0xff)) #endif +/** Set an IP address given by the four byte-parts */ +#define IP4_ADDR(ipaddr, a,b,c,d) (ipaddr)->addr = IP4_ADDR_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 * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */ diff --git a/src/include/lwip/ip_addr.h b/src/include/lwip/ip_addr.h index 127d4144..855c9788 100644 --- a/src/include/lwip/ip_addr.h +++ b/src/include/lwip/ip_addr.h @@ -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(IP4_ADDR_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) @@ -237,6 +241,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(IP4_ADDR_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 @@ -282,6 +287,7 @@ typedef ip4_addr_t ip_addr_t; 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 From 0ca82df062afc9d49ad27b665db1ab6ef0b15079 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 7 Dec 2016 20:18:58 +0100 Subject: [PATCH 066/184] Cleanup byte order handling a bit. - Create LWIP_MAKEU32(a,b,c,d) to create an U32 value from bytes - Use PP_HTONL() in some macros to emphasize network byte order conversion --- src/include/lwip/def.h | 6 ++++++ src/include/lwip/ip4_addr.h | 18 +----------------- src/include/lwip/ip6_addr.h | 19 +++---------------- src/include/lwip/ip_addr.h | 4 ++-- 4 files changed, 12 insertions(+), 35 deletions(-) diff --git a/src/include/lwip/def.h b/src/include/lwip/def.h index befc4fb7..f3cfccae 100644 --- a/src/include/lwip/def.h +++ b/src/include/lwip/def.h @@ -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 diff --git a/src/include/lwip/ip4_addr.h b/src/include/lwip/ip4_addr.h index a53257fe..51b46b8d 100644 --- a/src/include/lwip/ip4_addr.h +++ b/src/include/lwip/ip4_addr.h @@ -116,24 +116,8 @@ struct netif; #define IP_LOOPBACKNET 127 /* official! */ - -#if BYTE_ORDER == BIG_ENDIAN -/** Convert IP address given by the four byte-parts to an u32_t. */ -#define IP4_ADDR_MAKEU32(a,b,c,d) (((u32_t)((a) & 0xff) << 24) | \ - ((u32_t)((b) & 0xff) << 16) | \ - ((u32_t)((c) & 0xff) << 8) | \ - (u32_t)((d) & 0xff)) -#else -/** Convert IP address given by the four byte-parts to an u32_t. - Little-endian version that prevents the use of lwip_htonl. */ -#define IP4_ADDR_MAKEU32(a,b,c,d) (((u32_t)((d) & 0xff) << 24) | \ - ((u32_t)((c) & 0xff) << 16) | \ - ((u32_t)((b) & 0xff) << 8) | \ - (u32_t)((a) & 0xff)) -#endif - /** Set an IP address given by the four byte-parts */ -#define IP4_ADDR(ipaddr, a,b,c,d) (ipaddr)->addr = IP4_ADDR_MAKEU32(a,b,c,d) +#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 diff --git a/src/include/lwip/ip6_addr.h b/src/include/lwip/ip6_addr.h index 1171df9e..d04472c3 100644 --- a/src/include/lwip/ip6_addr.h +++ b/src/include/lwip/ip6_addr.h @@ -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 */ @@ -61,23 +62,9 @@ struct ip6_addr { /** IPv6 address */ typedef struct ip6_addr ip6_addr_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) */ diff --git a/src/include/lwip/ip_addr.h b/src/include/lwip/ip_addr.h index 855c9788..419cc424 100644 --- a/src/include/lwip/ip_addr.h +++ b/src/include/lwip/ip_addr.h @@ -80,7 +80,7 @@ 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(IP4_ADDR_MAKEU32(a,b,c,d)) +#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 */ @@ -241,7 +241,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(IP4_ADDR_MAKEU32(a,b,c,d)) +#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 From 5bb83301ddd722c3045f6e7f19b70f34cf04d70a Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 7 Dec 2016 22:19:16 +0100 Subject: [PATCH 067/184] Add macro to init an IPv6 address with U32 in host byte order --- src/include/lwip/ip_addr.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/include/lwip/ip_addr.h b/src/include/lwip/ip_addr.h index 419cc424..b0db3106 100644 --- a/src/include/lwip/ip_addr.h +++ b/src/include/lwip/ip_addr.h @@ -122,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)){ \ @@ -298,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) From aae0fc490884bbb3dacefabdbe198d471b7a7ddd Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 7 Dec 2016 22:19:37 +0100 Subject: [PATCH 068/184] Use new IPv6 init macro in netif.c --- src/core/netif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/netif.c b/src/core/netif.c index 38db54c0..69982b41 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -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 */ From 1dd563a0ae7df6fc88c19820ce7543bb09167d34 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 7 Dec 2016 22:27:57 +0100 Subject: [PATCH 069/184] arch.h: Implement possibility to provide own header for size_t, default is stddef.h --- src/include/lwip/arch.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index 27923948..7776922b 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -47,7 +47,20 @@ #include "arch/cc.h" +/** 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. 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). + */ +#ifndef LWIP_NO_STDDEF_H +#define LWIP_NO_STDDEF_H 0 +#endif + +#if !LWIP_NO_STDDEF_H #include /* 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 From f446194c8a091c080b1c846999f8dd1468ac6c4d Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 7 Dec 2016 22:29:24 +0100 Subject: [PATCH 070/184] pppos.c: Use arch.h to get size_t instead of including stddef.h --- src/netif/ppp/pppos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/netif/ppp/pppos.c b/src/netif/ppp/pppos.c index eaeb2d12..54164298 100644 --- a/src/netif/ppp/pppos.c +++ b/src/netif/ppp/pppos.c @@ -35,8 +35,8 @@ #if PPP_SUPPORT && PPPOS_SUPPORT /* don't build if not configured for use in lwipopts.h */ #include -#include +#include "lwip/arch.h" #include "lwip/err.h" #include "lwip/pbuf.h" #include "lwip/sys.h" From 9c3bbcf4e6ece834730889b8ba2a9b47ed8f45a8 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Thu, 8 Dec 2016 10:24:56 +0100 Subject: [PATCH 071/184] removed old disabled code --- src/core/udp.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/core/udp.c b/src/core/udp.c index 5786e4f9..52830c4f 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -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 From 89cb7b7aa18f17cbe3b10851cacf11b37abbfd2d Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 8 Dec 2016 11:04:35 +0100 Subject: [PATCH 072/184] Try to remove #include from many files. Does not seem necessary any more and might cause problems when porting lwIP. --- src/api/netdb.c | 1 - src/apps/httpd/httpd.c | 1 - src/apps/mdns/mdns.c | 1 - src/core/ipv4/autoip.c | 1 - src/core/mem.c | 6 +++++- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/api/netdb.c b/src/api/netdb.c index 55f2f760..ac1d8c79 100644 --- a/src/api/netdb.c +++ b/src/api/netdb.c @@ -47,7 +47,6 @@ #include "lwip/dns.h" #include -#include /** helper struct for gethostbyname_r to access the char* buffer */ struct gethostbyname_r_helper { diff --git a/src/apps/httpd/httpd.c b/src/apps/httpd/httpd.c index 103f9acb..2c836c8d 100644 --- a/src/apps/httpd/httpd.c +++ b/src/apps/httpd/httpd.c @@ -99,7 +99,6 @@ #include "lwip/tcp.h" #include -#include #include #if LWIP_TCP diff --git a/src/apps/mdns/mdns.c b/src/apps/mdns/mdns.c index c1401855..e90c5443 100644 --- a/src/apps/mdns/mdns.c +++ b/src/apps/mdns/mdns.c @@ -65,7 +65,6 @@ #include "lwip/prot/dns.h" #include -#include #if LWIP_MDNS_RESPONDER diff --git a/src/core/ipv4/autoip.c b/src/core/ipv4/autoip.c index 9aa32833..c5426ea2 100644 --- a/src/core/ipv4/autoip.c +++ b/src/core/ipv4/autoip.c @@ -68,7 +68,6 @@ #include "lwip/etharp.h" #include "lwip/prot/autoip.h" -#include #include /** Pseudo random macro based on netif informations. diff --git a/src/core/mem.c b/src/core/mem.c index 40f4cb9e..9908c027 100644 --- a/src/core/mem.c +++ b/src/core/mem.c @@ -61,9 +61,13 @@ #include "lwip/err.h" #include -#include + +#if MEM_LIBC_MALLOC +#include /* 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(). */ From a420d2530f3315126b79b9443384589f67dd3b3b Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 8 Dec 2016 11:13:51 +0100 Subject: [PATCH 073/184] arch.h: Add hint for struct packing #defines on GCC/clang --- src/include/lwip/arch.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index 7776922b..90fefaaf 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -166,18 +166,22 @@ typedef uintptr_t mem_ptr_t; extern "C" { #endif +/* GCC/clang: Nothing to do */ #ifndef PACK_STRUCT_BEGIN #define PACK_STRUCT_BEGIN #endif /* PACK_STRUCT_BEGIN */ +/* GCC/clang: Nothing to do */ #ifndef PACK_STRUCT_END #define PACK_STRUCT_END #endif /* PACK_STRUCT_END */ +/* GCC/clang: #define PACK_STRUCT_STRUCT __attribute__((packed)) */ #ifndef PACK_STRUCT_STRUCT #define PACK_STRUCT_STRUCT #endif /* PACK_STRUCT_STRUCT */ +/* GCC/clang: Nothing to do */ #ifndef PACK_STRUCT_FIELD #define PACK_STRUCT_FIELD(x) x #endif /* PACK_STRUCT_FIELD */ @@ -199,7 +203,6 @@ extern "C" { #define LWIP_UNUSED_ARG(x) (void)x #endif /* LWIP_UNUSED_ARG */ - #ifdef __cplusplus } #endif From 8a9ab9968cf64691bf42126d74a891c51f63211e Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 8 Dec 2016 12:45:21 +0100 Subject: [PATCH 074/184] Improve documentation: add compiler abstraction macros to doxygen docs --- src/include/lwip/arch.h | 49 ++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index 90fefaaf..be091762 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -47,6 +47,12 @@ #include "arch/cc.h" +/** + * @defgroup compiler_abstraction Compiler/platform abstraction + * @ingroup sys_layer + * @{ + */ + /** 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. This cannot be \#defined in * lwipopts.h since this is not an option of lwIP itself, but an option @@ -166,43 +172,70 @@ typedef uintptr_t mem_ptr_t; extern "C" { #endif -/* GCC/clang: Nothing to do */ +/** Packed structs support. + * Placed BEFORE declaration of a packed struct. \n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder. \n + * Porting to GCC/clang: Nothing to do. + */ #ifndef PACK_STRUCT_BEGIN #define PACK_STRUCT_BEGIN #endif /* PACK_STRUCT_BEGIN */ -/* GCC/clang: Nothing to do */ +/** Packed structs support. + * Placed AFTER declaration of a packed struct. \n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder. \n + * Porting to GCC/clang: Nothing to do. + */ #ifndef PACK_STRUCT_END #define PACK_STRUCT_END #endif /* PACK_STRUCT_END */ -/* GCC/clang: #define PACK_STRUCT_STRUCT __attribute__((packed)) */ +/** 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 + * Porting to GCC/clang: \#define PACK_STRUCT_STRUCT __attribute__((packed)) + */ #ifndef PACK_STRUCT_STRUCT #define PACK_STRUCT_STRUCT #endif /* PACK_STRUCT_STRUCT */ -/* GCC/clang: Nothing to do */ +/** Packed structs support. + * Wraps u32_t and u16_t members. \n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder. \n + * Porting to GCC/clang: Nothing to do. + */ #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 + * Porting to GCC/clang: Nothing to do. + */ #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 + * Porting to GCC/clang: Nothing to do. + */ #ifndef PACK_STRUCT_FLD_S #define PACK_STRUCT_FLD_S(x) PACK_STRUCT_FIELD(x) #endif /* PACK_STRUCT_FLD_S */ +/** Eliminates compiler warning about unused arguments. */ #ifndef LWIP_UNUSED_ARG #define LWIP_UNUSED_ARG(x) (void)x #endif /* LWIP_UNUSED_ARG */ +/** + * @} + */ + #ifdef __cplusplus } #endif From bb6df52ed554b230a08554bf35be4fa36d95ed38 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 8 Dec 2016 12:47:30 +0100 Subject: [PATCH 075/184] Fix doxygen parsing in my last commit --- src/include/lwip/arch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index be091762..66adb777 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -193,7 +193,7 @@ extern "C" { /** 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 - * Porting to GCC/clang: \#define PACK_STRUCT_STRUCT __attribute__((packed)) + * Porting to GCC/clang: \#define PACK_STRUCT_STRUCT \_\_attribute\_\_((packed)) */ #ifndef PACK_STRUCT_STRUCT #define PACK_STRUCT_STRUCT From b359b8c3e0a6e8cade624db022539f8344c28f7f Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 8 Dec 2016 13:35:34 +0100 Subject: [PATCH 076/184] Minor documentation improvement --- src/include/lwip/arch.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index 66adb777..a9c99988 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -50,6 +50,8 @@ /** * @defgroup compiler_abstraction Compiler/platform abstraction * @ingroup sys_layer + * All defines related to this section must not be places in lwipopts.h, + * but in arch/cc.h! * @{ */ @@ -137,7 +139,7 @@ typedef uintptr_t mem_ptr_t; * 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))) + * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[size] \_\_attribute\_\_((aligned(4))) * or more portable: * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u32_t variable_name[(size + sizeof(u32_t) - 1) / sizeof(u32_t)] */ From 55fd567a84293afb4e1556179b855a5c3563c8a8 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 8 Dec 2016 13:37:01 +0100 Subject: [PATCH 077/184] Adapt doxygen docs version number --- doc/doxygen/lwip.Doxyfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/doxygen/lwip.Doxyfile b/doc/doxygen/lwip.Doxyfile index 125d3239..caa54c4f 100644 --- a/doc/doxygen/lwip.Doxyfile +++ b/doc/doxygen/lwip.Doxyfile @@ -32,13 +32,13 @@ 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 From 33bdf9fa76c5531649a796b31781df60a9d5988b Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 8 Dec 2016 13:38:17 +0100 Subject: [PATCH 078/184] Doxygen: Fix project description text --- doc/doxygen/lwip.Doxyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/doxygen/lwip.Doxyfile b/doc/doxygen/lwip.Doxyfile index caa54c4f..177d4c4e 100644 --- a/doc/doxygen/lwip.Doxyfile +++ b/doc/doxygen/lwip.Doxyfile @@ -44,7 +44,7 @@ PROJECT_NUMBER = "2.0.1" # 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 From a2ad9d36ca0811bcc22ce8355d8ea54deea7c3ef Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 8 Dec 2016 15:25:38 +0100 Subject: [PATCH 079/184] Improve documentation: Refer to compiler/platform abstraction in NO_SYS mode description --- doc/doxygen/main_page.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/doxygen/main_page.h b/doc/doxygen/main_page.h index 31cc0df6..4f43d60a 100644 --- a/doc/doxygen/main_page.h +++ b/doc/doxygen/main_page.h @@ -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 From 85817e76112f7c97492ea1b8140fb1331052d20f Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 8 Dec 2016 16:56:19 +0100 Subject: [PATCH 080/184] Minor documentation update about IP_ADDR_ANY --- src/include/lwip/ip_addr.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/include/lwip/ip_addr.h b/src/include/lwip/ip_addr.h index b0db3106..bce65edd 100644 --- a/src/include/lwip/ip_addr.h +++ b/src/include/lwip/ip_addr.h @@ -340,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 /** @@ -381,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 */ From 5774fdfe75bb308fca36ac25f47254df0e41ceb7 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Fri, 9 Dec 2016 09:20:46 +0100 Subject: [PATCH 081/184] dns: added one-shot multicast DNS queries --- CHANGELOG | 3 ++ src/core/dns.c | 103 +++++++++++++++++++++++++++++++----- src/include/lwip/dns.h | 7 +++ src/include/lwip/opt.h | 6 +++ src/include/lwip/prot/dns.h | 18 +++++++ 5 files changed, 125 insertions(+), 12 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 59e5be95..21376eff 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,9 @@ HISTORY ++ New features: + 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) diff --git a/src/core/dns.c b/src/core/dns.c index 997a548e..056672b7 100644 --- a/src/core/dns.c +++ b/src/core/dns.c @@ -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 @@ -175,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 { @@ -224,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 @@ -287,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). @@ -680,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); @@ -693,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); @@ -735,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); @@ -938,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; @@ -1075,10 +1130,15 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, goto memerr; /* ignore this packet */ } - /* Check whether response comes from the same network address to which the - question was sent. (RFC 5452) */ - if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) { - goto memerr; /* ignore this packet */ +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + if (!entry->is_mdns) +#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ + { + /* Check whether response comes from the same network address to which the + question was sent. (RFC 5452) */ + if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) { + goto memerr; /* ignore this packet */ + } } /* Check if the name in the "question" part match with the name in the entry and @@ -1210,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; @@ -1326,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 */ @@ -1381,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) || @@ -1437,13 +1504,25 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call LWIP_UNUSED_ARG(dns_addrtype); #endif /* LWIP_IPV4 && LWIP_IPV6 */ - /* prevent calling found callback if no server is set, return error instead */ - if (ip_addr_isany_val(dns_servers[0])) { - return ERR_VAL; +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + if (strstr(hostname, ".local") == &hostname[hostnamelen] - 6) { + is_mdns = 1; + } else { + is_mdns = 0; + } + + if (!is_mdns) +#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ + { + /* prevent calling found callback if no server is set, return error instead */ + if (ip_addr_isany_val(dns_servers[0])) { + return ERR_VAL; + } } /* queue query with specified callback */ - return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)); + return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype) + LWIP_DNS_ISMDNS_ARG(is_mdns)); } #endif /* LWIP_DNS */ diff --git a/src/include/lwip/dns.h b/src/include/lwip/dns.h index 00d5a78c..3753a53a 100644 --- a/src/include/lwip/dns.h +++ b/src/include/lwip/dns.h @@ -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. diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 61305016..304609be 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -1057,6 +1057,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 /** * @} */ diff --git a/src/include/lwip/prot/dns.h b/src/include/lwip/prot/dns.h index 0a99ab0c..94782d6e 100644 --- a/src/include/lwip/prot/dns.h +++ b/src/include/lwip/prot/dns.h @@ -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 From 0e883bbbc550a4f10b13f2261fefb06cf1d79274 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Fri, 9 Dec 2016 12:49:49 +0100 Subject: [PATCH 082/184] mdns.c: use constants from dns.h/.c --- src/apps/mdns/mdns.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/apps/mdns/mdns.c b/src/apps/mdns/mdns.c index e90c5443..06e15a1c 100644 --- a/src/apps/mdns/mdns.c +++ b/src/apps/mdns/mdns.c @@ -63,6 +63,9 @@ #include "lwip/ip_addr.h" #include "lwip/mem.h" #include "lwip/prot/dns.h" +#include "lwip/dns.h" +#include "lwip/mld6.h" +#include "lwip/igmp.h" #include @@ -78,19 +81,8 @@ #error "If you want to use MDNS, you have to define LWIP_UDP=1 in your lwipopts.h" #endif -#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)); -#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)); -#endif - -#define MDNS_PORT 5353 +#define MDNS_PORT DNS_MQUERY_PORT #define MDNS_TTL 255 /* Stored offsets to beginning of domain names @@ -1420,11 +1412,11 @@ mdns_send_outpacket(struct mdns_outpacket *outpkt) if (IP_IS_V6_VAL(outpkt->dest_addr)) { #if LWIP_IPV6 - mcast_destaddr = &v6group; + mcast_destaddr = &dns_mquery_v6group; #endif } else { #if LWIP_IPV4 - mcast_destaddr = &v4group; + mcast_destaddr = &dns_mquery_v4group; #endif } /* Send created packet */ @@ -1780,14 +1772,14 @@ mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, #if LWIP_IPV6 if (IP_IS_V6(ip_current_dest_addr())) { - if (!ip_addr_cmp(ip_current_dest_addr(), &v6group)) { + if (!ip_addr_cmp(ip_current_dest_addr(), &dns_mquery_v6group)) { packet.recv_unicast = 1; } } #endif #if LWIP_IPV4 if (!IP_IS_V6(ip_current_dest_addr())) { - if (!ip_addr_cmp(ip_current_dest_addr(), &v4group)) { + if (!ip_addr_cmp(ip_current_dest_addr(), &dns_mquery_v4group)) { packet.recv_unicast = 1; } } @@ -1883,13 +1875,13 @@ mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl) /* Join multicast groups */ #if LWIP_IPV4 - res = igmp_joingroup_netif(netif, ip_2_ip4(&v4group)); + res = igmp_joingroup_netif(netif, ip_2_ip4(&dns_mquery_v4group)); if (res != ERR_OK) { goto cleanup; } #endif #if LWIP_IPV6 - res = mld6_joingroup_netif(netif, ip_2_ip6(&v6group)); + res = mld6_joingroup_netif(netif, ip_2_ip6(&dns_mquery_v6group)); if (res != ERR_OK) { goto cleanup; } @@ -1930,10 +1922,10 @@ mdns_resp_remove_netif(struct netif *netif) /* Leave multicast groups */ #if LWIP_IPV4 - igmp_leavegroup_netif(netif, ip_2_ip4(&v4group)); + igmp_leavegroup_netif(netif, ip_2_ip4(&dns_mquery_v4group)); #endif #if LWIP_IPV6 - mld6_leavegroup_netif(netif, ip_2_ip6(&v6group)); + mld6_leavegroup_netif(netif, ip_2_ip6(&dns_mquery_v6group)); #endif mem_free(mdns); From f308694dd4a0422653ba22904029a2f32629fa35 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Fri, 9 Dec 2016 13:08:00 +0100 Subject: [PATCH 083/184] Revert "mdns.c: use constants from dns.h/.c" This reverts commit 0e883bbbc550a4f10b13f2261fefb06cf1d79274. --- src/apps/mdns/mdns.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/apps/mdns/mdns.c b/src/apps/mdns/mdns.c index 06e15a1c..e90c5443 100644 --- a/src/apps/mdns/mdns.c +++ b/src/apps/mdns/mdns.c @@ -63,9 +63,6 @@ #include "lwip/ip_addr.h" #include "lwip/mem.h" #include "lwip/prot/dns.h" -#include "lwip/dns.h" -#include "lwip/mld6.h" -#include "lwip/igmp.h" #include @@ -81,8 +78,19 @@ #error "If you want to use MDNS, you have to define LWIP_UDP=1 in your lwipopts.h" #endif +#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)); +#endif -#define MDNS_PORT DNS_MQUERY_PORT +#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)); +#endif + +#define MDNS_PORT 5353 #define MDNS_TTL 255 /* Stored offsets to beginning of domain names @@ -1412,11 +1420,11 @@ mdns_send_outpacket(struct mdns_outpacket *outpkt) if (IP_IS_V6_VAL(outpkt->dest_addr)) { #if LWIP_IPV6 - mcast_destaddr = &dns_mquery_v6group; + mcast_destaddr = &v6group; #endif } else { #if LWIP_IPV4 - mcast_destaddr = &dns_mquery_v4group; + mcast_destaddr = &v4group; #endif } /* Send created packet */ @@ -1772,14 +1780,14 @@ mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, #if LWIP_IPV6 if (IP_IS_V6(ip_current_dest_addr())) { - if (!ip_addr_cmp(ip_current_dest_addr(), &dns_mquery_v6group)) { + if (!ip_addr_cmp(ip_current_dest_addr(), &v6group)) { packet.recv_unicast = 1; } } #endif #if LWIP_IPV4 if (!IP_IS_V6(ip_current_dest_addr())) { - if (!ip_addr_cmp(ip_current_dest_addr(), &dns_mquery_v4group)) { + if (!ip_addr_cmp(ip_current_dest_addr(), &v4group)) { packet.recv_unicast = 1; } } @@ -1875,13 +1883,13 @@ mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl) /* Join multicast groups */ #if LWIP_IPV4 - res = igmp_joingroup_netif(netif, ip_2_ip4(&dns_mquery_v4group)); + res = igmp_joingroup_netif(netif, ip_2_ip4(&v4group)); if (res != ERR_OK) { goto cleanup; } #endif #if LWIP_IPV6 - res = mld6_joingroup_netif(netif, ip_2_ip6(&dns_mquery_v6group)); + res = mld6_joingroup_netif(netif, ip_2_ip6(&v6group)); if (res != ERR_OK) { goto cleanup; } @@ -1922,10 +1930,10 @@ mdns_resp_remove_netif(struct netif *netif) /* Leave multicast groups */ #if LWIP_IPV4 - igmp_leavegroup_netif(netif, ip_2_ip4(&dns_mquery_v4group)); + igmp_leavegroup_netif(netif, ip_2_ip4(&v4group)); #endif #if LWIP_IPV6 - mld6_leavegroup_netif(netif, ip_2_ip6(&dns_mquery_v6group)); + mld6_leavegroup_netif(netif, ip_2_ip6(&v6group)); #endif mem_free(mdns); From ac4d99424971b46be34d362907ecf9ddf20a024c Mon Sep 17 00:00:00 2001 From: goldsimon Date: Fri, 9 Dec 2016 13:10:12 +0100 Subject: [PATCH 084/184] mdns.c: use group initializer constants from prot/dns.h --- src/apps/mdns/mdns.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/apps/mdns/mdns.c b/src/apps/mdns/mdns.c index e90c5443..631e2ceb 100644 --- a/src/apps/mdns/mdns.c +++ b/src/apps/mdns/mdns.c @@ -81,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 From a83c4e089706b3374e796f3f97892051ab2a38b3 Mon Sep 17 00:00:00 2001 From: Sylvain Rochet Date: Fri, 9 Dec 2016 14:11:21 +0100 Subject: [PATCH 085/184] PPP: fix build warning on wrong cast from void* to unsigned long ppp/utils.c: In function 'ppp_vslprintf': ppp/utils.c:251:12: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] val = (unsigned long) va_arg(args, void *); ^ This is because a void* type is casted into an unsigned long type, which obviously isn't correct on LLP64 systems such as Windows. Actually, we are not using %p, thus we remove %p support completely instead of trying to fix the issue in unused code. --- src/netif/ppp/utils.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/netif/ppp/utils.c b/src/netif/ppp/utils.c index a5ae86f0..008c6337 100644 --- a/src/netif/ppp/utils.c +++ b/src/netif/ppp/utils.c @@ -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; From 8347d3b62392dbb2a90e9ce06cee31030be3d98a Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Fri, 9 Dec 2016 19:56:29 +0100 Subject: [PATCH 086/184] Try to fix compile warning with GCC under Linux ("large integer implicitly truncated to unsigned type") --- src/include/lwip/def.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/lwip/def.h b/src/include/lwip/def.h index f3cfccae..aaa64c77 100644 --- a/src/include/lwip/def.h +++ b/src/include/lwip/def.h @@ -102,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) From 26e02e84a62d270c8baafb77599254c84eabd6d5 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Fri, 9 Dec 2016 21:26:21 +0100 Subject: [PATCH 087/184] Fix bug #48963: ip6_frag does not support LWIP_NETIF_TX_SINGLE_PBUF Implemented. --- src/core/ipv6/ip6_frag.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/core/ipv6/ip6_frag.c b/src/core/ipv6/ip6_frag.c index b374f691..cbb9868e 100644 --- a/src/core/ipv6/ip6_frag.c +++ b/src/core/ipv6/ip6_frag.c @@ -610,6 +610,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 +639,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 +660,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 +672,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 +690,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 +768,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; From 7a1b38db6ec0a305191c41ca8ba5d4b00a5c1c7b Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Fri, 9 Dec 2016 21:26:53 +0100 Subject: [PATCH 088/184] Minor: Save an #ifdef in ip4_frag.c --- src/core/ipv4/ip4_frag.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/core/ipv4/ip4_frag.c b/src/core/ipv4/ip4_frag.c index b6f90945..57fb44cb 100644 --- a/src/core/ipv4/ip4_frag.c +++ b/src/core/ipv4/ip4_frag.c @@ -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; From f2a5aa286619cdfead163900f4667d0b7ae04370 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Mon, 12 Dec 2016 10:07:00 +0100 Subject: [PATCH 089/184] Fix bug #49827: wrong cast to size_t on 16-bit x86 architecture I hope I caught all of them. TODO: Same for casts to get rid of alignment warnings, these are also casts via size_t --- src/api/sockets.c | 2 +- src/apps/lwiperf/lwiperf.c | 2 +- src/core/def.c | 4 ++-- src/core/pbuf.c | 2 +- src/core/timeouts.c | 2 +- src/include/lwip/arch.h | 5 +++++ 6 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index 9cffd519..ae2c7553 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -1279,7 +1279,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; diff --git a/src/apps/lwiperf/lwiperf.c b/src/apps/lwiperf/lwiperf.c index 079dd6b1..54bf2bca 100644 --- a/src/apps/lwiperf/lwiperf.c +++ b/src/apps/lwiperf/lwiperf.c @@ -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; diff --git a/src/core/def.c b/src/core/def.c index 99f3d62e..bdece2f9 100644 --- a/src/core/def.c +++ b/src/core/def.c @@ -103,11 +103,11 @@ lwip_strnstr(const char* buffer, const char* token, size_t n) const char* p; int tokenlen = (int)strlen(token); if (tokenlen == 0) { - return (char *)(size_t)buffer; + 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; diff --git a/src/core/pbuf.c b/src/core/pbuf.c index 887dc8aa..5a319421 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -1119,7 +1119,7 @@ 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); + return LWIP_CONST_CAST(struct pbuf*, pbuf_skip_const(in, in_offset, out_offset)); } /** diff --git a/src/core/timeouts.c b/src/core/timeouts.c index e2dc0fc7..227d71fc 100644 --- a/src/core/timeouts.c +++ b/src/core/timeouts.c @@ -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 */ diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index a9c99988..c1180147 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -133,6 +133,11 @@ typedef uintptr_t mem_ptr_t; #endif #endif +/** C++ const_cast(val) equivalent to remove constness from a value */ +#ifndef LWIP_CONST_CAST +#define LWIP_CONST_CAST(target_type, val) ((target_type)((ptrdiff_t)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 From e5f9f187adfa962aed8ccaa6a75eb01992e25dff Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Mon, 12 Dec 2016 10:17:33 +0100 Subject: [PATCH 090/184] Continue to fix incorrect casts via size_t for some platforms Now also for casts: - to remove alignment warnings - casts between pointers and ints --- src/apps/snmp/snmp_mib2_ip.c | 4 ++-- src/core/ipv4/etharp.c | 2 +- src/core/memp.c | 2 +- src/include/lwip/arch.h | 12 ++++++++++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/apps/snmp/snmp_mib2_ip.c b/src/apps/snmp/snmp_mib2_ip.c index 913d97f9..4f05180a 100644 --- a/src/apps/snmp/snmp_mib2_ip.c +++ b/src/apps/snmp/snmp_mib2_ip.c @@ -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 */ diff --git a/src/core/ipv4/etharp.c b/src/core/ipv4/etharp.c index bf4dad53..b599bcc2 100644 --- a/src/core/ipv4/etharp.c +++ b/src/core/ipv4/etharp.c @@ -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 diff --git a/src/core/memp.c b/src/core/memp.c index 2ecb1814..d3f10a94 100644 --- a/src/core/memp.c +++ b/src/core/memp.c @@ -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); diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index c1180147..940ab62a 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -138,6 +138,18 @@ typedef uintptr_t mem_ptr_t; #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 From 1c184da615e50845a64336420d7c1d1349afd8ca Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Fri, 9 Dec 2016 22:13:00 +0100 Subject: [PATCH 091/184] Update changelog for LWIP_NETIF_TX_SINGLE_PBUF --- CHANGELOG | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 21376eff..134c3c54 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,9 +3,12 @@ HISTORY (git master) * [Enter new changes just after this line - do not remove this line] - + ++ New features: + 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 From 86b01e4f292cb7106029511a2bbc4e7507affee8 Mon Sep 17 00:00:00 2001 From: Pradip De Date: Tue, 13 Dec 2016 21:53:07 +0100 Subject: [PATCH 092/184] Added LWIP_HOOK_ETHIP6_GET_GW() Signed-off-by: sg --- CHANGELOG | 3 +++ src/core/ipv6/ethip6.c | 13 +++++++++++++ src/include/lwip/opt.h | 15 ++++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 134c3c54..5755d74c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,9 @@ HISTORY ++ New features: + 2016-12-13: Pradip De + * opt.h, ethip6.c: Added LWIP_HOOK_ETHIP6_GET_GW() + 2016-12-09: Dirk Ziegelmeier * ip6_frag.c: Implemented support for LWIP_NETIF_TX_SINGLE_PBUF diff --git a/src/core/ipv6/ethip6.c b/src/core/ipv6/ethip6.c index 509fc1c5..b9bbcce4 100644 --- a/src/core/ipv6/ethip6.c +++ b/src/core/ipv6/ethip6.c @@ -96,6 +96,19 @@ ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) /* We have a unicast destination IP address */ /* @todo anycast? */ + +#ifdef LWIP_HOOK_ETHIP6_GET_GW + { + /* See if a gateway is present for the destination address in a routing table */ + const ip6_addr_t *gateway = LWIP_HOOK_ETHIP6_GET_GW(netif, ip6addr); + if (gateway != NULL) { + /* Replace the destination with the gateway. The gateway is + assumed to be on-link. */ + ip6addr = gateway; + } + } +#endif /* LWIP_HOOK_ETHIP6_GET_GW */ + /* Get next hop record. */ i = nd6_get_next_hop_entry(ip6addr, netif); if (i < 0) { diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 304609be..ceff1fd7 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -2433,7 +2433,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. @@ -2469,6 +2469,19 @@ #define LWIP_HOOK_IP6_ROUTE(src, dest) #endif +/** +* LWIP_HOOK_ETHIP6_GET_GW(netif, dest): +* - called from ethip6_output() (IPv6) +* - netif: the netif used for sending +* - dest: the destination IPv6 address +* Returns the IPv6 address of the gateway to handle the specified destination +* IPv6 address. If NULL is returned, the default nexthop is used. +* The returned address MUST be directly reachable on the specified netif! +*/ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_ETHIP6_GET_GW(netif, dest) +#endif + /** * LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr): * - called from ethernet_input() if VLAN support is enabled From 9d199a6d72b6adeec06fecebf9e8746ed3b0eb96 Mon Sep 17 00:00:00 2001 From: sg Date: Tue, 13 Dec 2016 21:54:49 +0100 Subject: [PATCH 093/184] netif_create_ip6_linklocal_address(): use macros to assign address state to ensure callbacks are triggered; netif_add_ip6_address(): only overwrite invalid addresses, not tentative addresses --- src/core/netif.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/netif.c b/src/core/netif.c index 69982b41..f7211f9a 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -1195,10 +1195,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 */ } @@ -1228,7 +1228,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) { From 002e077dbde0274810957320d23d58554ce0ff13 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Tue, 13 Dec 2016 18:23:28 +0000 Subject: [PATCH 094/184] ethip6: forward correct error code On failure, nd6_get_next_hop_entry() returns an ERR_ type negative error code. ethip6_output() erroneously assumed that that error would always be ERR_MEM, even though it may also be ERR_RTE in practice. With this patch, ethip6_output() simply forwards the returned error. --- src/core/ipv6/ethip6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ipv6/ethip6.c b/src/core/ipv6/ethip6.c index b9bbcce4..0730426c 100644 --- a/src/core/ipv6/ethip6.c +++ b/src/core/ipv6/ethip6.c @@ -113,7 +113,7 @@ ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) i = nd6_get_next_hop_entry(ip6addr, netif); if (i < 0) { /* failed to get a next hop neighbor record. */ - return ERR_MEM; + return i; } /* Now that we have a destination record, send or queue the packet. */ From afb21603dc514b6febf93a68cca7acf76e282963 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 14 Dec 2016 08:31:09 +0100 Subject: [PATCH 095/184] Add a check for correct implementation of LWIP_CONST_CAST() to lwip_init() --- src/core/init.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/init.c b/src/core/init.c index 570d54aa..ee415a97 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -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 From 74a5537e159b1b4d4857ff393764886c2cc65f09 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 14 Dec 2016 08:36:47 +0100 Subject: [PATCH 096/184] Revert "Added LWIP_HOOK_ETHIP6_GET_GW()" This reverts commit 86b01e4f292cb7106029511a2bbc4e7507affee8. --- CHANGELOG | 3 --- src/core/ipv6/ethip6.c | 13 ------------- src/include/lwip/opt.h | 15 +-------------- 3 files changed, 1 insertion(+), 30 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5755d74c..134c3c54 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,9 +6,6 @@ HISTORY ++ New features: - 2016-12-13: Pradip De - * opt.h, ethip6.c: Added LWIP_HOOK_ETHIP6_GET_GW() - 2016-12-09: Dirk Ziegelmeier * ip6_frag.c: Implemented support for LWIP_NETIF_TX_SINGLE_PBUF diff --git a/src/core/ipv6/ethip6.c b/src/core/ipv6/ethip6.c index 0730426c..35d424e3 100644 --- a/src/core/ipv6/ethip6.c +++ b/src/core/ipv6/ethip6.c @@ -96,19 +96,6 @@ ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) /* We have a unicast destination IP address */ /* @todo anycast? */ - -#ifdef LWIP_HOOK_ETHIP6_GET_GW - { - /* See if a gateway is present for the destination address in a routing table */ - const ip6_addr_t *gateway = LWIP_HOOK_ETHIP6_GET_GW(netif, ip6addr); - if (gateway != NULL) { - /* Replace the destination with the gateway. The gateway is - assumed to be on-link. */ - ip6addr = gateway; - } - } -#endif /* LWIP_HOOK_ETHIP6_GET_GW */ - /* Get next hop record. */ i = nd6_get_next_hop_entry(ip6addr, netif); if (i < 0) { diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index ceff1fd7..304609be 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -2433,7 +2433,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 directly reachable on the specified netif! + * The returned address MUST be 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. @@ -2469,19 +2469,6 @@ #define LWIP_HOOK_IP6_ROUTE(src, dest) #endif -/** -* LWIP_HOOK_ETHIP6_GET_GW(netif, dest): -* - called from ethip6_output() (IPv6) -* - netif: the netif used for sending -* - dest: the destination IPv6 address -* Returns the IPv6 address of the gateway to handle the specified destination -* IPv6 address. If NULL is returned, the default nexthop is used. -* The returned address MUST be directly reachable on the specified netif! -*/ -#ifdef __DOXYGEN__ -#define LWIP_HOOK_ETHIP6_GET_GW(netif, dest) -#endif - /** * LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr): * - called from ethernet_input() if VLAN support is enabled From 7d119fd86b89c10dca0072ba9f71e61efd18b8e6 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Tue, 13 Dec 2016 20:40:22 +0000 Subject: [PATCH 097/184] nd6: add LWIP_HOOK_ND6_GET_GW hook --- src/core/ipv6/nd6.c | 9 +++++++++ src/include/lwip/opt.h | 16 ++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 82394f6e..e5553216 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -1524,6 +1524,9 @@ nd6_new_onlink_prefix(ip6_addr_t *prefix, struct netif *netif) 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 +1570,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); diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 304609be..336b77e9 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -2469,6 +2469,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 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 From 1a53c106e160429fc9f7048c7ffcdb92f5a97914 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 14 Dec 2016 08:42:11 +0100 Subject: [PATCH 098/184] CHANGELOG: added LWIP_HOOK_ND6_GET_GW() --- CHANGELOG | 3 +++ src/include/lwip/opt.h | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 134c3c54..42e81894 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,9 @@ HISTORY ++ New features: + 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 diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 336b77e9..8e5eeefb 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -2433,7 +2433,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. @@ -2476,7 +2476,7 @@ * - 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 reachable on the specified netif! + * 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. From d4fad5929c1311068f25668ea895ee2d5bf80b7a Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 14 Dec 2016 13:11:13 +0100 Subject: [PATCH 099/184] nd6_input(): allow using NA without lladdr_opt for DAD --- src/core/ipv6/nd6.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index e5553216..72a25239 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -155,25 +155,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)); @@ -209,6 +190,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) { From cee59ba8cdae886afbcb8e514da6dbb2d7b6519e Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Wed, 14 Dec 2016 12:44:23 +0000 Subject: [PATCH 100/184] nd6: add nd6_clear_destination_cache() function The new function, while currently not used internally, allows external code to clear the ND destination cache in the case that it may have become inconsistent with the current situation, for example as the result of a change of locally assigned addresses, or a change in routing tables implemented through the LWIP_HOOK_ND6_GET_GW hook. --- src/core/ipv6/nd6.c | 16 ++++++++++++++++ src/include/lwip/nd6.h | 1 + 2 files changed, 17 insertions(+) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 72a25239..37b91dbb 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -1293,6 +1293,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) +{ + s8_t 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. * diff --git a/src/include/lwip/nd6.h b/src/include/lwip/nd6.h index e4715ad3..e6e2d9c1 100644 --- a/src/include/lwip/nd6.h +++ b/src/include/lwip/nd6.h @@ -141,6 +141,7 @@ extern u32_t retrans_timer; void nd6_tmr(void); void nd6_input(struct pbuf *p, struct netif *inp); +void nd6_clear_destination_cache(void); 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); u16_t nd6_get_destination_mtu(const ip6_addr_t *ip6addr, struct netif *netif); From 06ff89cbe49a57781ac3fdc98a4990ebfff18f8c Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Wed, 14 Dec 2016 13:59:08 +0000 Subject: [PATCH 101/184] nd6: use default_router_list internally only This patch rearranges the code division between nd6.c and ip6.c such that the latter does not need to access ND6-internal data structures (specifically, "default_router_list") directly anymore. --- src/core/ipv6/ip6.c | 12 +++--------- src/core/ipv6/nd6.c | 25 +++++++++++++++++++++++++ src/include/lwip/nd6.h | 2 +- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c index 0cb03182..2c2bd099 100644 --- a/src/core/ipv6/ip6.c +++ b/src/core/ipv6/ip6.c @@ -144,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. */ diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 37b91dbb..fb4e7339 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -93,6 +93,7 @@ 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); @@ -1396,6 +1397,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. * diff --git a/src/include/lwip/nd6.h b/src/include/lwip/nd6.h index e6e2d9c1..1d4b2f26 100644 --- a/src/include/lwip/nd6.h +++ b/src/include/lwip/nd6.h @@ -143,7 +143,7 @@ void nd6_tmr(void); void nd6_input(struct pbuf *p, struct netif *inp); void nd6_clear_destination_cache(void); 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); +struct netif *nd6_find_route(const ip6_addr_t *ip6addr); 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 From 69a7039f75ed46bd0110648940ab49dd7aa12c66 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Wed, 14 Dec 2016 16:19:24 +0000 Subject: [PATCH 102/184] nd6: centralize link-local packet send decision Previously, ethip6 and lowpan6 each had their own copy of code that used internal nd6 data structures to decide whether to send a packet on the local link right away, or queue it while nd6 performed local address resolution. This patch moves that code into nd6, thereby eliminating all remaining cases of external access to internal nd6 data structures, as well as the need to expose two specific nd6 functions. As a side effect, the patch effectively fixes two bugs in the lowpan6 code that were already fixed in the ethip6 code. --- src/core/ipv6/ethip6.c | 42 ++++++++++++----------------- src/core/ipv6/nd6.c | 60 ++++++++++++++++++++++++++++++++++++++++-- src/include/lwip/nd6.h | 3 +-- src/netif/lowpan6.c | 39 ++++++++++----------------- 4 files changed, 90 insertions(+), 54 deletions(-) diff --git a/src/core/ipv6/ethip6.c b/src/core/ipv6/ethip6.c index 35d424e3..32d0edf6 100644 --- a/src/core/ipv6/ethip6.c +++ b/src/core/ipv6/ethip6.c @@ -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 nd6_packet_send_check. */ 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)) { @@ -96,31 +98,21 @@ ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) /* 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 i; + + /* Ask ND6 what to do with the packet. */ + result = nd6_packet_send_check(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, (struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6); } #endif /* LWIP_IPV6 && LWIP_ETHERNET */ diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index fb4e7339..8bb337f1 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -98,6 +98,8 @@ 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 @@ -1562,7 +1564,7 @@ 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 @@ -1684,7 +1686,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; @@ -1861,6 +1863,60 @@ 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. + * @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_packet_send_check(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. diff --git a/src/include/lwip/nd6.h b/src/include/lwip/nd6.h index 1d4b2f26..97df6b0b 100644 --- a/src/include/lwip/nd6.h +++ b/src/include/lwip/nd6.h @@ -142,10 +142,9 @@ extern u32_t retrans_timer; void nd6_tmr(void); void nd6_input(struct pbuf *p, struct netif *inp); void nd6_clear_destination_cache(void); -s8_t nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif); struct netif *nd6_find_route(const ip6_addr_t *ip6addr); +err_t nd6_packet_send_check(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 */ diff --git a/src/netif/lowpan6.c b/src/netif/lowpan6.c index eca9a453..36c041ad 100644 --- a/src/netif/lowpan6.c +++ b/src/netif/lowpan6.c @@ -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,35 +664,23 @@ 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_packet_send_check(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; - } - /* @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. */ - dest.addr_len = netif->hwaddr_len; - SMEMCPY(dest.addr, neighbor_cache[i].lladdr, netif->hwaddr_len); - MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); - return lowpan6_frag(netif, q, &src, &dest); + /* If no hardware address is returned, nd6 has queued the packet for later. */ + if (hwaddr == NULL) { + return ERR_OK; } - /* We should queue packet on this interface. */ - return nd6_queue_packet(i, q); + /* Send out the packet using the returned hardware address. */ + dest.addr_len = netif->hwaddr_len; + SMEMCPY(dest.addr, hwaddr, netif->hwaddr_len); + MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); + return lowpan6_frag(netif, q, &src, &dest); } static struct pbuf * From 4c16ea920ccbcc08bca61a8ec07de95686719694 Mon Sep 17 00:00:00 2001 From: sg Date: Wed, 14 Dec 2016 20:52:44 +0100 Subject: [PATCH 103/184] Minor: nd6_packet_send_check() -> nd6_get_next_hop_addr_or_queue() (too long, but a little more self-explaining); cosmetics... --- src/core/ipv6/ethip6.c | 8 ++++---- src/core/ipv6/ip6.c | 2 +- src/core/ipv6/nd6.c | 7 ++++--- src/include/lwip/nd6.h | 2 +- src/netif/lowpan6.c | 2 +- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/core/ipv6/ethip6.c b/src/core/ipv6/ethip6.c index 32d0edf6..8f9a91b5 100644 --- a/src/core/ipv6/ethip6.c +++ b/src/core/ipv6/ethip6.c @@ -73,7 +73,7 @@ * @param ip6addr The IP address of the packet destination. * * @return - * - ERR_OK or the return value of nd6_packet_send_check. + * - 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) @@ -93,14 +93,14 @@ 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? */ /* Ask ND6 what to do with the packet. */ - result = nd6_packet_send_check(netif, q, ip6addr, &hwaddr); + result = nd6_get_next_hop_addr_or_queue(netif, q, ip6addr, &hwaddr); if (result != ERR_OK) { return result; } @@ -112,7 +112,7 @@ ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) /* Send out the packet using the returned hardware address. */ SMEMCPY(dest.addr, hwaddr, 6); - 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); } #endif /* LWIP_IPV6 && LWIP_ETHERNET */ diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c index 2c2bd099..f17b6c85 100644 --- a/src/core/ipv6/ip6.c +++ b/src/core/ipv6/ip6.c @@ -145,7 +145,7 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) /* Get the netif for a suitable router. */ netif = nd6_find_route(dest); - if (netif != NULL && netif_is_up(netif) && netif_is_link_up(netif)) { + if ((netif != NULL) && netif_is_up(netif) && netif_is_link_up(netif)) { return netif; } diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 8bb337f1..689e1324 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -1305,7 +1305,7 @@ nd6_new_destination_cache_entry(void) void nd6_clear_destination_cache(void) { - s8_t i; + int i; for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { ip6_addr_set_any(&destination_cache[i].destination_addr); @@ -1879,13 +1879,14 @@ nd6_send_q(s8_t i) * @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. + * @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_packet_send_check(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr, const u8_t **hwaddrp) +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; diff --git a/src/include/lwip/nd6.h b/src/include/lwip/nd6.h index 97df6b0b..69a059b1 100644 --- a/src/include/lwip/nd6.h +++ b/src/include/lwip/nd6.h @@ -143,7 +143,7 @@ void nd6_tmr(void); void nd6_input(struct pbuf *p, struct netif *inp); void nd6_clear_destination_cache(void); struct netif *nd6_find_route(const ip6_addr_t *ip6addr); -err_t nd6_packet_send_check(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr, const u8_t **hwaddrp); +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); #if LWIP_ND6_TCP_REACHABILITY_HINTS void nd6_reachability_hint(const ip6_addr_t *ip6addr); diff --git a/src/netif/lowpan6.c b/src/netif/lowpan6.c index 36c041ad..9a84cbcc 100644 --- a/src/netif/lowpan6.c +++ b/src/netif/lowpan6.c @@ -665,7 +665,7 @@ lowpan6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) #endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ /* Ask ND6 what to do with the packet. */ - result = nd6_packet_send_check(netif, q, ip6addr, &hwaddr); + result = nd6_get_next_hop_addr_or_queue(netif, q, ip6addr, &hwaddr); if (result != ERR_OK) { MIB2_STATS_NETIF_INC(netif, ifoutdiscards); return result; From 60cd25c6a15ae0c3f3e1240fe08a138e8c7958ba Mon Sep 17 00:00:00 2001 From: sg Date: Wed, 14 Dec 2016 21:04:53 +0100 Subject: [PATCH 104/184] Moved nd6 implementation details to new file nd6_priv.h (possible after David's cleanups) --- src/core/ipv6/nd6.c | 1 + src/core/memp.c | 2 +- src/include/lwip/nd6.h | 84 ++----------------------------------- src/include/lwip/prot/nd6.h | 1 + 4 files changed, 6 insertions(+), 82 deletions(-) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 689e1324..298b0ea0 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -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" diff --git a/src/core/memp.c b/src/core/memp.c index d3f10a94..31624492 100644 --- a/src/core/memp.c +++ b/src/core/memp.c @@ -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" diff --git a/src/include/lwip/nd6.h b/src/include/lwip/nd6.h index 69a059b1..817dfb9e 100644 --- a/src/include/lwip/nd6.h +++ b/src/include/lwip/nd6.h @@ -48,96 +48,18 @@ #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); diff --git a/src/include/lwip/prot/nd6.h b/src/include/lwip/prot/nd6.h index eae3d28e..7f46c535 100644 --- a/src/include/lwip/prot/nd6.h +++ b/src/include/lwip/prot/nd6.h @@ -39,6 +39,7 @@ #include "lwip/arch.h" #include "lwip/ip6_addr.h" +#include "lwip/prot/ip6.h" #ifdef __cplusplus extern "C" { From e8461f9994cb68c04fea4824e759d80cb406b531 Mon Sep 17 00:00:00 2001 From: sg Date: Wed, 14 Dec 2016 21:05:22 +0100 Subject: [PATCH 105/184] minor: corrected include guard name in tcp_priv.h --- src/include/lwip/priv/tcp_priv.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/include/lwip/priv/tcp_priv.h b/src/include/lwip/priv/tcp_priv.h index 51747e0f..f0eeb450 100644 --- a/src/include/lwip/priv/tcp_priv.h +++ b/src/include/lwip/priv/tcp_priv.h @@ -34,8 +34,8 @@ * Author: Adam Dunkels * */ -#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" @@ -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 */ From 281ef5d094d8ec22e00b784ab40a29a99498d211 Mon Sep 17 00:00:00 2001 From: sg Date: Wed, 14 Dec 2016 21:18:50 +0100 Subject: [PATCH 106/184] minor: fixed errors in some defined __DOXYGEN__ guards --- src/include/lwip/opt.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 8e5eeefb..4e8cb718 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -2170,7 +2170,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 @@ -2348,7 +2348,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 @@ -2365,9 +2365,10 @@ * 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 + /** * @} */ @@ -2557,7 +2558,7 @@ * compared against this value. If it is smaller, then debugging * messages are written. */ -#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 From bd1defc1d83fd4135b2d948aabb40dcc844218e5 Mon Sep 17 00:00:00 2001 From: sg Date: Wed, 14 Dec 2016 21:24:48 +0100 Subject: [PATCH 107/184] added forgoten new file nd6_priv.h :-( --- src/include/lwip/priv/nd6_priv.h | 144 +++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 src/include/lwip/priv/nd6_priv.h diff --git a/src/include/lwip/priv/nd6_priv.h b/src/include/lwip/priv/nd6_priv.h new file mode 100644 index 00000000..4bda0b79 --- /dev/null +++ b/src/include/lwip/priv/nd6_priv.h @@ -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 + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#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 */ From cd5dfa2bc54732f507e961339c0b0d9626c7c7fa Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Wed, 14 Dec 2016 20:18:09 +0000 Subject: [PATCH 108/184] nd6: minor 'static' consistency fix --- src/core/ipv6/nd6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 298b0ea0..4dbaa7c5 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -1348,7 +1348,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; From 53b9f2a5bd3acd9b920ee4aaff1d8c57bb5574e4 Mon Sep 17 00:00:00 2001 From: sg Date: Wed, 14 Dec 2016 21:56:39 +0100 Subject: [PATCH 109/184] dhcp: covert DHCP_OPTION_IDX_* from defines to enum (mainly to ease offset calculation) --- src/core/ipv4/dhcp.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/core/ipv4/dhcp.c b/src/core/ipv4/dhcp.c index abff34dd..eaae34dd 100644 --- a/src/core/ipv4/dhcp.c +++ b/src/core/ipv4/dhcp.c @@ -108,21 +108,23 @@ * 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, + DHCP_OPTION_IDX_DNS_SERVER, + DHCP_OPTION_IDX_DNS_SERVER_LAST = DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS - 1, #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? */ From 4e3cf61571f5d414b5ee92fea4c3163e181a3ccd Mon Sep 17 00:00:00 2001 From: sg Date: Wed, 14 Dec 2016 22:04:08 +0100 Subject: [PATCH 110/184] opt.h: added LWIP_DHCP_MAX_DNS_SERVERS to configure the maximum number of DNS servers configured from dhcp.c(v4) (if any; guarded with LWIP_DNS) --- src/core/ipv4/dhcp.c | 32 ++++++++++++++++++++++++-------- src/include/lwip/opt.h | 9 +++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/core/ipv4/dhcp.c b/src/core/ipv4/dhcp.c index eaae34dd..fadb8e72 100644 --- a/src/core/ipv4/dhcp.c +++ b/src/core/ipv4/dhcp.c @@ -103,6 +103,16 @@ #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 @@ -117,8 +127,10 @@ enum dhcp_option_idx { 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 + DNS_MAX_SERVERS - 1, + 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 DHCP_OPTION_IDX_NTP_SERVER, DHCP_OPTION_IDX_NTP_SERVER_LAST = DHCP_OPTION_IDX_NTP_SERVER + LWIP_DHCP_MAX_NTP_SERVERS - 1, @@ -137,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 */ @@ -574,9 +588,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 @@ -642,14 +656,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 */ } /** @@ -1519,6 +1533,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;); @@ -1527,6 +1542,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; diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 4e8cb718..2326b301 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -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 /** * @} */ From 6b1950ec24bc7de59aa1112b13c16a780b2a78fa Mon Sep 17 00:00:00 2001 From: sg Date: Wed, 14 Dec 2016 22:12:14 +0100 Subject: [PATCH 111/184] nd6: add support for RDNSS option (as per RFC 6106) --- CHANGELOG | 3 +++ src/core/ipv6/nd6.c | 33 +++++++++++++++++++++++++++++++++ src/include/lwip/opt.h | 8 ++++++++ src/include/lwip/prot/nd6.h | 23 +++++++++++++++++++++++ 4 files changed, 67 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 42e81894..653a8879 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,9 @@ HISTORY ++ New features: + 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() diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 4dbaa7c5..689b56e7 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -60,6 +60,7 @@ #include "lwip/mld6.h" #include "lwip/ip.h" #include "lwip/stats.h" +#include "lwip/dns.h" #include @@ -394,6 +395,10 @@ nd6_input(struct pbuf *p, struct netif *inp) struct ra_header *ra_hdr; u8_t *buffer; /* Used to copy options. */ u16_t offset; +#ifdef 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)) { @@ -538,6 +543,34 @@ 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++) { + /* Get a memory-aligned copy of the prefix. */ + ip6_addr_set(ip6_current_dest_addr(), &(rdnss_opt->rdnss_address[n])); + + if (htonl(rdnss_opt->lifetime) > 0) { + /* TODO implement Lifetime > 0 */ + dns_setserver(rdnss_server_idx++, ip_current_dest_addr()); + } 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, ip_current_dest_addr())) { + dns_setserver(s, NULL); + } + } + } + } + break; + } +#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */ default: /* Unrecognized option, abort. */ ND6_STATS_INC(nd6.proterr); diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 2326b301..d350f3ce 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -2378,6 +2378,14 @@ #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 /** * @} */ diff --git a/src/include/lwip/prot/nd6.h b/src/include/lwip/prot/nd6.h index 7f46c535..2d4903d1 100644 --- a/src/include/lwip/prot/nd6.h +++ b/src/include/lwip/prot/nd6.h @@ -247,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 From e3925cc359ed8e55dca3162d8f38afc20764ec86 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 15 Dec 2016 14:11:20 +0800 Subject: [PATCH 112/184] nd6: Fix build error if LWIP_ND6_RDNSS_MAX_DNS_SERVERS == 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix below build error when LWIP_ND6_RDNSS_MAX_DNS_SERVERS == 0 ../../../../lwip/src/core/ipv6/nd6.c: In function ‘nd6_input’: ../../../../lwip/src/core/ipv6/nd6.c:400:10: error: unused variable ‘rdnss_server_idx’ [-Werror=unused-variable] u8_t rdnss_server_idx = 0; ^~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors ../Common.mk:93: recipe for target 'nd6.o' failed make: *** [nd6.o] Error 1 Fixes: 6b1950ec24bc ("nd6: add support for RDNSS option (as per RFC 6106)") Signed-off-by: Axel Lin --- src/core/ipv6/nd6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 689b56e7..00b70f73 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -395,7 +395,7 @@ nd6_input(struct pbuf *p, struct netif *inp) struct ra_header *ra_hdr; u8_t *buffer; /* Used to copy options. */ u16_t offset; -#ifdef LWIP_ND6_RDNSS_MAX_DNS_SERVERS +#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 */ From da15132aa02ab7fda01249a16c9e2d909db7472c Mon Sep 17 00:00:00 2001 From: goldsimon Date: Thu, 15 Dec 2016 09:25:44 +0100 Subject: [PATCH 113/184] Make nd6_new_router() handle already existing routers (this is a special case for 2 netifs on the same subnet - e.g. wifi and cable) see bug #46506 --- src/core/ipv6/nd6.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 00b70f73..ec5b283c 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -1493,6 +1493,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? */ @@ -1516,12 +1517,22 @@ 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++) { + free_router_index = LWIP_ND6_NUM_ROUTERS; + for (router_index = LWIP_ND6_NUM_ROUTERS - 1; router_index >= 0; router_index--) { + /* check if router already exists (this is a special case for 2 netifs on the same subnet + - e.g. wifi and cable) */ + if(default_router_list[router_index].neighbor_entry == &(neighbor_cache[neighbor_index])){ + return router_index; + } if (default_router_list[router_index].neighbor_entry == NULL) { - default_router_list[router_index].neighbor_entry = &(neighbor_cache[neighbor_index]); - return router_index; + /* remember lowest free index to create a new entry */ + free_router_index = router_index; } } + if (free_router_index < LWIP_ND6_NUM_ROUTERS) { + default_router_list[free_router_index].neighbor_entry = &(neighbor_cache[neighbor_index]); + return free_router_index; + } /* Could not create a router entry. */ From a8b986bbb67820a59be567d280b6be762ef65e92 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Wed, 26 Oct 2016 21:24:46 +0000 Subject: [PATCH 114/184] Add hook for TCP Initial Sequence Number generation lwIP produces a TCP Initial Sequence Number (ISN) for each new TCP connection. The current algorithm is simple and predictable however. The result is that lwIP TCP connections may be the target of TCP spoofing attacks. The problem of such attacks is well known, and a recommended ISN generation algorithm is standardized in RFC 6528. This algorithm requires a high-resolution timer and cryptographic hashing function, though. The implementation (or best-effort approximation) of both of these aspects is well beyond the scope of lwIP itself. For that reason, this patch adds LWIP_HOOK_TCP_ISN, a hook that allows each platform to implement its own ISN generation using locally available means. The hook provides full flexibility, in that the hook may generate anything from a simple random number (by being set to LWIP_RAND()) to a full RFC 6528 implementation. Implementation note: Users of the hook would typically declare the function prototype of the hook function in arch/cc.h, as this is the last place where such prototypes can be supplied. However, at that point, the ip_addr_t type has not yet been defined. For that reason, this patch removes the leading underscore from "struct _ip_addr", so that a prototype of the hook function can use "struct ip_addr" instead of "ip_addr_t". Signed-off-by: sg --- src/core/tcp.c | 17 +++++++++-------- src/core/tcp_in.c | 6 ++++++ src/include/lwip/ip_addr.h | 2 +- src/include/lwip/opt.h | 23 +++++++++++++++++++++++ src/include/lwip/priv/tcp_priv.h | 2 +- 5 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/core/tcp.c b/src/core/tcp.c index 8712d76c..f72597bb 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -880,10 +880,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 +1492,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 +1554,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 +1821,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 diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 7f42f577..3d3ae33a 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -542,6 +542,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 +590,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 diff --git a/src/include/lwip/ip_addr.h b/src/include/lwip/ip_addr.h index bce65edd..def2d08c 100644 --- a/src/include/lwip/ip_addr.h +++ b/src/include/lwip/ip_addr.h @@ -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; diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index d350f3ce..98180c62 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -2410,6 +2410,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, or any other + * desired algorithm (e.g., it can be set to LWIP_RAND()), 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) diff --git a/src/include/lwip/priv/tcp_priv.h b/src/include/lwip/priv/tcp_priv.h index f0eeb450..f68a856a 100644 --- a/src/include/lwip/priv/tcp_priv.h +++ b/src/include/lwip/priv/tcp_priv.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); From 62e340067e45aeb18888062c4b010ac1df0617d7 Mon Sep 17 00:00:00 2001 From: sg Date: Thu, 15 Dec 2016 21:08:12 +0100 Subject: [PATCH 115/184] LWIP_HOOK_TCP_ISN: added CHANGELOG/fixed comment --- CHANGELOG | 4 ++++ src/include/lwip/opt.h | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 653a8879..8877eaee 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -26,6 +26,10 @@ HISTORY ++ Bugfixes: + 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) diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 98180c62..0965e09b 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -2415,8 +2415,8 @@ * 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, or any other - * desired algorithm (e.g., it can be set to LWIP_RAND()), as a replacement. + * 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); From 844c2017026e9ff981fd2a0f0425336c1a34d481 Mon Sep 17 00:00:00 2001 From: sg Date: Thu, 15 Dec 2016 21:39:46 +0100 Subject: [PATCH 116/184] added fuzz tests (moved from contrib/ports/unix/fuzz to get them to a more prominent place, even if afl-fuzz still needs *nix to run) --- test/fuzz/Makefile | 52 +++++++ test/fuzz/README | 34 +++++ test/fuzz/config.h | 0 test/fuzz/fuzz.c | 136 ++++++++++++++++++ test/fuzz/inputs/arp/arp_req.bin | Bin 0 -> 42 bytes test/fuzz/inputs/icmp/icmp_ping.bin | Bin 0 -> 98 bytes .../inputs/ipv6/neighbor_solicitation.bin | Bin 0 -> 86 bytes test/fuzz/inputs/ipv6/router_adv.bin | Bin 0 -> 118 bytes test/fuzz/inputs/tcp/tcp_syn.bin | Bin 0 -> 74 bytes test/fuzz/inputs/udp/udp_port_5000.bin | Bin 0 -> 50 bytes test/fuzz/lwipopts.h | 68 +++++++++ test/fuzz/output_to_pcap.sh | 31 ++++ 12 files changed, 321 insertions(+) create mode 100644 test/fuzz/Makefile create mode 100644 test/fuzz/README create mode 100644 test/fuzz/config.h create mode 100644 test/fuzz/fuzz.c create mode 100644 test/fuzz/inputs/arp/arp_req.bin create mode 100644 test/fuzz/inputs/icmp/icmp_ping.bin create mode 100644 test/fuzz/inputs/ipv6/neighbor_solicitation.bin create mode 100644 test/fuzz/inputs/ipv6/router_adv.bin create mode 100644 test/fuzz/inputs/tcp/tcp_syn.bin create mode 100644 test/fuzz/inputs/udp/udp_port_5000.bin create mode 100644 test/fuzz/lwipopts.h create mode 100644 test/fuzz/output_to_pcap.sh diff --git a/test/fuzz/Makefile b/test/fuzz/Makefile new file mode 100644 index 00000000..bc12ca97 --- /dev/null +++ b/test/fuzz/Makefile @@ -0,0 +1,52 @@ +# +# 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 +# + +all compile: lwip_fuzz +.PHONY: all clean + +include ../Common.mk + +CC=afl-gcc +LDFLAGS:=$(LDFLAGS) -lm +CFLAGS:=$(CFLAGS) -O0 + +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) diff --git a/test/fuzz/README b/test/fuzz/README new file mode 100644 index 00000000..28a1f9ba --- /dev/null +++ b/test/fuzz/README @@ -0,0 +1,34 @@ + +Fuzzing the lwIP stack + +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/ -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 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. + diff --git a/test/fuzz/config.h b/test/fuzz/config.h new file mode 100644 index 00000000..e69de29b diff --git a/test/fuzz/fuzz.c b/test/fuzz/fuzz.c new file mode 100644 index 00000000..a9157f13 --- /dev/null +++ b/test/fuzz/fuzz.c @@ -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 + * + */ + +#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 +#include + +/* 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; +} diff --git a/test/fuzz/inputs/arp/arp_req.bin b/test/fuzz/inputs/arp/arp_req.bin new file mode 100644 index 0000000000000000000000000000000000000000..b317334f9e2fbe8cffe7624e453ae4c782fc6de7 GIT binary patch literal 42 rcmezW9|SBI7#OrIIM^5%IT+Yj7#J;dymGZI*2opB0wsU|$O-`fG#Cph literal 0 HcmV?d00001 diff --git a/test/fuzz/inputs/icmp/icmp_ping.bin b/test/fuzz/inputs/icmp/icmp_ping.bin new file mode 100644 index 0000000000000000000000000000000000000000..87e1ea795e571f48fd3611079ab8c5a972851db8 GIT binary patch literal 98 zcmZQjK6vi}uLT1GgSG_+gDV3=h@+zeg9GEPjceqJRe?B!gW xCQcB=ARs6tEFvluA!-=t)r`_Z(wL-Y+`C=4gfZ(6Egq+ literal 0 HcmV?d00001 diff --git a/test/fuzz/inputs/ipv6/neighbor_solicitation.bin b/test/fuzz/inputs/ipv6/neighbor_solicitation.bin new file mode 100644 index 0000000000000000000000000000000000000000..d2f921c36371c68bd768f0d8e777c309cba5b908 GIT binary patch literal 86 zcmXpu{(tWRuLT1GgSJK6-2@=bpkVd?UjvB2z;OG;&z{&^`VZFo5;&6aLy_bQ3)2aa^qQJh;i1_w49hBb1rXm5m Zrwj~CEUa5tm^ip3+QQF(#2J~H*#Y7q5%>TA literal 0 HcmV?d00001 diff --git a/test/fuzz/inputs/udp/udp_port_5000.bin b/test/fuzz/inputs/udp/udp_port_5000.bin new file mode 100644 index 0000000000000000000000000000000000000000..d77e26752b9c9163d7d404502df7b121f10520b5 GIT binary patch literal 50 zcmZQjK6vi}uLT1GgSG_+gDV4rN_v $1/$$.tmp + text2pcap $1/$$.tmp ${i}.pcap + fi +done +for i in `ls $1/hangs/id*` +do + PCAPNAME=`echo $i | grep pcap` + if [ -z "$PCAPNAME" ]; then + hexdump -C $i > $1/$$.tmp + text2pcap $1/$$.tmp ${i}.pcap + fi +done +rm -f $1/$$.tmp + +echo +echo "Created pcap files:" +ls $1/*/*.pcap From c13a43e5c8180afb7fbb3288cd736a778fe74a1f Mon Sep 17 00:00:00 2001 From: sg Date: Thu, 15 Dec 2016 21:42:46 +0100 Subject: [PATCH 117/184] added note about afl-fuzz requiring linux --- test/fuzz/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fuzz/README b/test/fuzz/README index 28a1f9ba..1d1e3d8d 100644 --- a/test/fuzz/README +++ b/test/fuzz/README @@ -1,5 +1,5 @@ -Fuzzing the lwIP stack +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 From d9f461e4e4495ec7aaf1035f6d82448dd8f19a5d Mon Sep 17 00:00:00 2001 From: sg Date: Thu, 15 Dec 2016 22:32:46 +0100 Subject: [PATCH 118/184] Fixed #49848 (Non-blocking socket emit a sock error while read return EWOULDBLOCK) especially for EWOULDBLOCK (added task #14275 for the general problem) --- src/api/sockets.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index ae2c7553..d49e6416 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -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; } @@ -771,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; } From b5f51dbd0c67c5e961d3019b8dd1e1d8ff923a83 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Fri, 16 Dec 2016 08:51:06 +0100 Subject: [PATCH 119/184] ND6: Don't misuse ip6_current_dest_addr() to create an aligned copy of an IPv6 address We never know what side effect in application code this could trigger... --- src/core/ipv6/nd6.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index ec5b283c..ca7d8e91 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -548,21 +548,24 @@ nd6_input(struct pbuf *p, struct netif *inp) { 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++) { + ip6_addr_t rdnss_address; + /* Get a memory-aligned copy of the prefix. */ - ip6_addr_set(ip6_current_dest_addr(), &(rdnss_opt->rdnss_address[n])); + ip6_addr_set(&rdnss_address, &(rdnss_opt->rdnss_address[n])); if (htonl(rdnss_opt->lifetime) > 0) { /* TODO implement Lifetime > 0 */ - dns_setserver(rdnss_server_idx++, ip_current_dest_addr()); + 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, ip_current_dest_addr())) { + if(ip_addr_cmp(addr, &rdnss_address)) { dns_setserver(s, NULL); } } @@ -586,6 +589,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)) { @@ -608,10 +612,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); @@ -625,15 +629,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). */ @@ -659,6 +663,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)) { @@ -673,10 +678,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); From fcd2daf57cfec0d6572601c905d2d0d92464e777 Mon Sep 17 00:00:00 2001 From: Thomas Mueller Date: Fri, 16 Dec 2016 15:44:00 +0100 Subject: [PATCH 120/184] fixed race condition in return value of netconn_gethostbyname() (and thus also lwip_gethostbyname/_r() and lwip_getaddrinfo()) Signed-off-by: sg --- CHANGELOG | 4 ++++ src/api/api_lib.c | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8877eaee..4371f02e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -26,6 +26,10 @@ HISTORY ++ 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) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index 1e356aa0..98f232d8 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -932,6 +932,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;); @@ -964,13 +965,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 From cceea73c3f32f433f3d6b5c8212a8ca1f06cddab Mon Sep 17 00:00:00 2001 From: Joel Cunningham Date: Fri, 9 Dec 2016 18:10:24 -0600 Subject: [PATCH 121/184] bug #49631: handle zero-window probe and refused_data This commit adds support for responding to a zero-window probe when the refused_data pointer is set A zero-window probe is a data segment received when rcv_ann_wnd is 0. This corrects a standards violation where LwIP would not respond to a zero-window probe with its current ACK value (RCV.NXT) when it has refused data, thus leading to the probing TCP closing out the connection --- src/core/tcp_in.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 3d3ae33a..fbbdc729 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -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; From 11780f037bb98f68b55a2c3fbe70c28543c7a5f8 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Sat, 17 Dec 2016 10:05:49 +0100 Subject: [PATCH 122/184] Fixup Makefile of FUZZ test after moving to main lwIP rep --- .gitignore | 2 ++ test/fuzz/Makefile | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0092ea6f..2aa3170e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ /src/apps/snmp/LwipMibCompiler/SharpSnmpLib/obj/ /src/apps/snmp/LwipMibCompiler/LwipMibCompiler.userprefs /src/apps/snmp/LwipMibCompiler/*.suo +/test/fuzz/output +/test/lwip_fuzz diff --git a/test/fuzz/Makefile b/test/fuzz/Makefile index bc12ca97..834c078b 100644 --- a/test/fuzz/Makefile +++ b/test/fuzz/Makefile @@ -32,7 +32,9 @@ all compile: lwip_fuzz .PHONY: all clean -include ../Common.mk +CONTRIBDIR=../../../lwip-contrib + +include $(CONTRIBDIR)/ports/unix/Common.mk CC=afl-gcc LDFLAGS:=$(LDFLAGS) -lm From bb8088d4986d9ac5a3a52706ec441f32b09ffdf6 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Sat, 17 Dec 2016 10:09:15 +0100 Subject: [PATCH 123/184] Minor cleanup of FUZZ test Makefile --- test/fuzz/Makefile | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test/fuzz/Makefile b/test/fuzz/Makefile index 834c078b..67ffb195 100644 --- a/test/fuzz/Makefile +++ b/test/fuzz/Makefile @@ -32,13 +32,12 @@ all compile: lwip_fuzz .PHONY: all clean -CONTRIBDIR=../../../lwip-contrib - -include $(CONTRIBDIR)/ports/unix/Common.mk - CC=afl-gcc -LDFLAGS:=$(LDFLAGS) -lm -CFLAGS:=$(CFLAGS) -O0 +LDFLAGS=-lm +CFLAGS=-O0 + +CONTRIBDIR=../../../lwip-contrib +include $(CONTRIBDIR)/ports/unix/Common.mk clean: rm -f *.o $(LWIPLIBCOMMON) lwip_fuzz *.s .depend* *.core core From 102a50fa96ff797100631641bda0183669824223 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Sat, 17 Dec 2016 13:36:24 +0100 Subject: [PATCH 124/184] Fix bug #39145: IGMP membership report for 224.0.0.1 Ensure allsystems group is always first in linked list --- src/core/ipv4/igmp.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/core/ipv4/igmp.c b/src/core/ipv4/igmp.c index 5ae7d9c8..5ea2fdab 100644 --- a/src/core/ipv4/igmp.c +++ b/src/core/ipv4/igmp.c @@ -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); @@ -251,7 +252,7 @@ igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr) /* Group already exists. */ return group; } - + /* Group doesn't exist yet, create a new one */ group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP); if (group != NULL) { @@ -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); - netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, group); + /* Ensure allsystems group is always first in list */ + if (list_head == NULL) { + /* this is the first entry in linked list */ + LWIP_ASSERT("igmp_lookup_group: first group must be allsystems", + (ip4_addr_cmp(addr, &allsystems) != 0)); + group->next = NULL; + netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, group); + } else { + /* append _after_ first entry */ + LWIP_ASSERT("igmp_lookup_group: all except first group must not be allsystems", + (ip4_addr_cmp(addr, &allsystems) == 0)); + group->next = list_head->next; + list_head->next = group; + } } LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to "))); From 5c1dd6a4c65b9fb9c8628ffc911478855979d6e9 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Sat, 17 Dec 2016 15:06:33 +0100 Subject: [PATCH 125/184] Optimization in igmp_remove_group() pointed out by Axel Lin No need to handle special case "first in list" since this is always the allsystems group that shall not be removed --- src/core/ipv4/igmp.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/core/ipv4/igmp.c b/src/core/ipv4/igmp.c index 5ea2fdab..58613d3b 100644 --- a/src/core/ipv4/igmp.c +++ b/src/core/ipv4/igmp.c @@ -295,24 +295,24 @@ static err_t igmp_remove_group(struct netif* netif, struct igmp_group *group) { err_t err = ERR_OK; + struct igmp_group *tmp_group = netif_igmp_data(netif); - /* 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; - break; - } - } - /* Group not found in the global igmp_group_list */ - if (tmpGroup == NULL) { - err = ERR_ARG; + /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */ + if(tmp_group != NULL) { + tmp_group = tmp_group->next; + } + + /* look for group further down the list */ + for (; 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 (tmp_group == NULL) { + err = ERR_ARG; + } return err; } From f488c5b7bc5c0f003674f6f596d2452f6994c0cc Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 17 Dec 2016 22:41:11 +0800 Subject: [PATCH 126/184] igmp: Fix optimized code for igmp_remove_group The code in the for loop checks tmp_group->next == group, so current code actually checks from the 3rd entry in the linked groups list. Fix it. Fixes: 5c1dd6a4c65b ("Optimization in igmp_remove_group() pointed out by Axel Lin") Signed-off-by: Axel Lin --- src/core/ipv4/igmp.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/core/ipv4/igmp.c b/src/core/ipv4/igmp.c index 58613d3b..561448e0 100644 --- a/src/core/ipv4/igmp.c +++ b/src/core/ipv4/igmp.c @@ -295,15 +295,10 @@ static err_t igmp_remove_group(struct netif* netif, struct igmp_group *group) { err_t err = ERR_OK; - struct igmp_group *tmp_group = netif_igmp_data(netif); + struct igmp_group *tmp_group; /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */ - if(tmp_group != NULL) { - tmp_group = tmp_group->next; - } - - /* look for group further down the list */ - for (; tmp_group != NULL; tmp_group = tmp_group->next) { + 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; From c21763f6cb87f5d9c2cd9d03a797367e1dfd0569 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Sun, 18 Dec 2016 21:31:14 +0100 Subject: [PATCH 127/184] Minor code cleanup api_lib.c --- src/api/api_lib.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index 98f232d8..3c1d6a6c 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -390,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 */ @@ -399,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; @@ -479,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 @@ -503,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) From 7f319f5ec516b489cf47d9e71b8dc87ae3057a17 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Sun, 18 Dec 2016 21:46:49 +0100 Subject: [PATCH 128/184] Fix compile of test_tcp.c unit test after introduction of tcp_next_iss hook --- test/unit/tcp/test_tcp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unit/tcp/test_tcp.c b/test/unit/tcp/test_tcp.c index bfcfa1d9..81953466 100644 --- a/test/unit/tcp/test_tcp.c +++ b/test/unit/tcp/test_tcp.c @@ -35,8 +35,8 @@ tcp_setup(void) { /* reset iss to default (6510) */ tcp_ticks = 0; - tcp_ticks = 0 - (tcp_next_iss() - 6510); - tcp_next_iss(); + tcp_ticks = 0 - (tcp_next_iss(NULL) - 6510); + tcp_next_iss(NULL); tcp_ticks = 0; test_tcp_timer = 0; @@ -513,8 +513,8 @@ START_TEST(test_tcp_rto_rexmit_wraparound) /* create and initialize the pcb */ tcp_ticks = 0; - tcp_ticks = 0 - tcp_next_iss(); - tcp_ticks = SEQNO1 - tcp_next_iss(); + tcp_ticks = 0 - tcp_next_iss(NULL); + tcp_ticks = SEQNO1 - tcp_next_iss(NULL); pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); EXPECT(pcb->lastack == SEQNO1); From e0c0ba7e1b9bcde6f202e779a2e2d4c1437ec84d Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Mon, 19 Dec 2016 10:11:23 +0100 Subject: [PATCH 129/184] Fix compile with LWIP_NOASSERT Pointed out by Nirav Desai --- src/core/ipv6/ip6_frag.c | 3 +++ src/core/pbuf.c | 1 + 2 files changed, 4 insertions(+) diff --git a/src/core/ipv6/ip6_frag.c b/src/core/ipv6/ip6_frag.c index cbb9868e..ff07f71c 100644 --- a/src/core/ipv6/ip6_frag.c +++ b/src/core/ipv6/ip6_frag.c @@ -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); diff --git a/src/core/pbuf.c b/src/core/pbuf.c index 5a319421..52f088d2 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -1227,6 +1227,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; From c71733252c1f0421886515dac5b1f981edf352cd Mon Sep 17 00:00:00 2001 From: goldsimon Date: Mon, 19 Dec 2016 10:29:16 +0100 Subject: [PATCH 130/184] Fix compiling with LWIP_NOASSERT (and debug/error disabled, too) --- src/api/sockets.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index d49e6416..24b3b5fa 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -1214,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) { From fb07d47b82a85dadb040d57ade4c34692a358ef8 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Mon, 19 Dec 2016 10:34:49 +0100 Subject: [PATCH 131/184] more LWIP_NOASSERT fixes --- src/apps/httpd/httpd.c | 1 + src/apps/mdns/mdns.c | 1 + src/apps/snmp/snmp_threadsync.c | 1 + 3 files changed, 3 insertions(+) diff --git a/src/apps/httpd/httpd.c b/src/apps/httpd/httpd.c index 2c836c8d..bdffee32 100644 --- a/src/apps/httpd/httpd.c +++ b/src/apps/httpd/httpd.c @@ -2562,6 +2562,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); diff --git a/src/apps/mdns/mdns.c b/src/apps/mdns/mdns.c index 631e2ceb..14334fc8 100644 --- a/src/apps/mdns/mdns.c +++ b/src/apps/mdns/mdns.c @@ -1820,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); diff --git a/src/apps/snmp/snmp_threadsync.c b/src/apps/snmp/snmp_threadsync.c index 858c40e6..204f265d 100644 --- a/src/apps/snmp/snmp_threadsync.c +++ b/src/apps/snmp/snmp_threadsync.c @@ -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; } From 1e8246576638dc02eeea287c1c46511b3e43ce49 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Tue, 20 Dec 2016 09:16:21 +0100 Subject: [PATCH 132/184] task #14281: Add MQTT client Thanks to Erik Andersen Taken from https://github.com/erian747/, branch mqtt, rev 5d59470 --- src/Filelists.mk | 6 +- src/apps/mqtt/mqtt.c | 1317 ++++++++++++++++++++++++++++++++++ src/include/lwip/apps/mqtt.h | 246 +++++++ 3 files changed, 1568 insertions(+), 1 deletion(-) create mode 100644 src/apps/mqtt/mqtt.c create mode 100644 src/include/lwip/apps/mqtt.h diff --git a/src/Filelists.mk b/src/Filelists.mk index ac79422c..7d30bb8f 100644 --- a/src/Filelists.mk +++ b/src/Filelists.mk @@ -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) diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c new file mode 100644 index 00000000..e36e33a4 --- /dev/null +++ b/src/apps/mqtt/mqtt.c @@ -0,0 +1,1317 @@ +/** + * @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 + * + * + * @todo: + * - Handle large outgoing payloads for PUBLISH messages + * - Fix restriction of a single topic in each (UN)SUBSCRIBE message (protocol has support for multiple topics) + * - Add support for legacy MQTT protocol version + * + * Please coordinate changes and requests with Erik Andersson + * Erik Andersson + * + */ +#include +#include "lwip/timeouts.h" +#include "lwip/ip_addr.h" +#include "lwip/mem.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/tcp.h" +#include "mqtt.h" + +/** + * MQTT_DEBUG: Default is off. + */ +#if !defined MQTT_DEBUG || defined __DOXYGEN__ +#define MQTT_DEBUG LWIP_DBG_OFF +#endif + +#define MQTT_DEBUG_TRACE (MQTT_DEBUG | LWIP_DBG_TRACE) +#define MQTT_DEBUG_STATE (MQTT_DEBUG | LWIP_DBG_STATE) +#define MQTT_DEBUG_WARN (MQTT_DEBUG | LWIP_DBG_LEVEL_WARNING) +#define MQTT_DEBUG_WARN_STATE (MQTT_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE) +#define MQTT_DEBUG_SERIOUS (MQTT_DEBUG | LWIP_DBG_LEVEL_SERIOUS) + + +/** + * 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 + + +static void mqtt_cyclic_timer(void *arg); + +/** + * MQTT client connection states + */ +enum { + TCP_DISCONNECTED, + TCP_CONNECTING, + MQTT_CONNECTING, + MQTT_CONNECTED, +}; + +/** + * MQTT control message types + */ +enum mqtt_message_type { + MQTT_MSG_TYPE_CONNECT = 1, + MQTT_MSG_TYPE_CONNACK = 2, + MQTT_MSG_TYPE_PUBLISH = 3, + MQTT_MSG_TYPE_PUBACK = 4, + MQTT_MSG_TYPE_PUBREC = 5, + MQTT_MSG_TYPE_PUBREL = 6, + MQTT_MSG_TYPE_PUBCOMP = 7, + MQTT_MSG_TYPE_SUBSCRIBE = 8, + MQTT_MSG_TYPE_SUBACK = 9, + MQTT_MSG_TYPE_UNSUBSCRIBE = 10, + MQTT_MSG_TYPE_UNSUBACK = 11, + MQTT_MSG_TYPE_PINGREQ = 12, + MQTT_MSG_TYPE_PINGRESP = 13, + MQTT_MSG_TYPE_DISCONNECT = 14 +}; + +/** Helpers to extract control packet type and qos from first byte in fixed header */ +#define MQTT_CTL_PACKET_TYPE(fixed_hdr_byte0) ((fixed_hdr_byte0 & 0xf0) >> 4) +#define MQTT_CTL_PACKET_QOS(fixed_hdr_byte0) ((fixed_hdr_byte0 & 0x6) >> 1) + +/** + * MQTT connect flags, only used in CONNECT message + */ +enum mqtt_connect_flag { + MQTT_CONNECT_FLAG_USERNAME = 1 << 7, + MQTT_CONNECT_FLAG_PASSWORD = 1 << 6, + MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5, + MQTT_CONNECT_FLAG_WILL = 1 << 2, + MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1 +}; + + +#if (MQTT_DEBUG == LWIP_DBG_ON) && defined(LWIP_DEBUG) +static const char * const mqtt_message_type_str[15] = +{ + "UNDEFINED", + "CONNECT", + "CONNACK", + "PUBLISH", + "PUBACK", + "PUBREC", + "PUBREL", + "PUBCOMP", + "SUBSCRIBE", + "SUBACK", + "UNSUBSCRIBE", + "UNSUBACK", + "PINGREQ", + "PINGRESP", + "DISCONNECT" +}; + +/** + * Message type value to string + * @param msg_type @see mqtt_message_type + * @return Control message type text string + */ +static const char * +mqtt_msg_type_to_str(u8_t msg_type) +{ + if(msg_type > 14) { + msg_type = 0; + } + return mqtt_message_type_str[msg_type]; +} + +#endif + + +/** + * Generate MQTT packet identifier + * @param client MQTT client + * @return New packet identifier, range 1 to 65535 + */ +static u16_t +msg_generate_packet_id(mqtt_client_t *client) +{ + client->pkt_id_seq++; + if(client->pkt_id_seq == 0) { + client->pkt_id_seq++; + } + return client->pkt_id_seq; +} + +/*--------------------------------------------------------------------------------------------------------------------- */ +/* Output ring buffer */ + + +#define MQTT_RINGBUF_IDX_MASK ((MQTT_OUTPUT_RINGBUF_SIZE) - 1) + +/** Add single item to ring buffer */ +#define mqtt_ringbuf_put(rb, item) ((rb)->buf)[(rb)->put++ & MQTT_RINGBUF_IDX_MASK] = (item) + +/** Return number of bytes in ring buffer */ +#define mqtt_ringbuf_len(rb) ((u16_t)((rb)->put - (rb)->get)) + +/** Return number of bytes free in ring buffer */ +#define mqtt_ringbuf_free(rb) (MQTT_OUTPUT_RINGBUF_SIZE - mqtt_ringbuf_len(rb)) + +/** Return number of bytes possible to read without wrapping around */ +#define mqtt_ringbuf_linear_read_length(rb) LWIP_MIN(mqtt_ringbuf_len(rb), (MQTT_OUTPUT_RINGBUF_SIZE - ((rb)->get & MQTT_RINGBUF_IDX_MASK))) + +/** Return pointer to ring buffer get position */ +#define mqtt_ringbuf_get_ptr(rb) (&(rb)->buf[(rb)->get & MQTT_RINGBUF_IDX_MASK]) + +#define mqtt_ringbuf_advance_get_idx(rb, len) ((rb)->get += (len)) + + +/** + * Try send as many bytes as possible from output ring buffer + * @param rb Output ring buffer + * @param tpcb TCP connection handle + */ +static void +mqtt_output_send(struct mqtt_ringbuf_t *rb, struct tcp_pcb *tpcb) +{ + LWIP_ASSERT("mqtt_output_send: tpcb != NULL", tpcb != NULL); + err_t err; + u8_t wrap = 0; + u16_t ringbuf_lin_len = mqtt_ringbuf_linear_read_length(rb); + u16_t send_len = tcp_sndbuf(tpcb); + + if(send_len == 0 || ringbuf_lin_len == 0) { + return; + } + + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_output_send: tcp_sndbuf: %d bytes, ringbuf_linear_available: %d, get %d, put %d\n", + send_len, ringbuf_lin_len, ((rb)->get & MQTT_RINGBUF_IDX_MASK), ((rb)->put & MQTT_RINGBUF_IDX_MASK))); + + if(send_len > ringbuf_lin_len) { + /* Space in TCP output buffer is larger than available in ring buffer linear portion */ + send_len = ringbuf_lin_len; + /* Wrap around if more data in ring buffer after linear portion */ + wrap = (mqtt_ringbuf_len(rb) > ringbuf_lin_len); + } + err = tcp_write(tpcb, mqtt_ringbuf_get_ptr(rb), send_len, TCP_WRITE_FLAG_COPY | (wrap ? TCP_WRITE_FLAG_MORE : 0)); + if((err == ERR_OK) && wrap) { + mqtt_ringbuf_advance_get_idx(rb, send_len); + /* Use the lesser one of ring buffer linear length and TCP send buffer size */ + send_len = LWIP_MIN(tcp_sndbuf(tpcb), mqtt_ringbuf_linear_read_length(rb)); + err = tcp_write(tpcb, mqtt_ringbuf_get_ptr(rb), send_len, TCP_WRITE_FLAG_COPY); + } + + if(err == ERR_OK) { + mqtt_ringbuf_advance_get_idx(rb, send_len); + /* Flush */ + tcp_output(tpcb); + } else { + LWIP_DEBUGF(MQTT_DEBUG_WARN, ("mqtt_output_send: Send failed with err %d (\"%s\")\n", err, lwip_strerr(err))); + } +} + + + +/*--------------------------------------------------------------------------------------------------------------------- */ +/* Request queue */ + +/** + * Create request item + * @param r_objs Pointer to request objects + * @param pkt_id Packet identifier of request + * @param cb Packet callback to call when requests lifetime ends + * @param arg Parameter following callback + * @return Request or NULL if failed to create + */ +static struct mqtt_request_t * +mqtt_create_request(struct mqtt_request_t *r_objs, u16_t pkt_id, mqtt_request_cb_t cb, void *arg) +{ + LWIP_ASSERT("mqtt_create_request: r_objs != NULL", r_objs != NULL); + struct mqtt_request_t *r = NULL; + u8_t n; + for(n = 0; n < MQTT_REQ_MAX_IN_FLIGHT && r == NULL; n++) { + /* Item point to itself if not in use */ + if(r_objs[n].next == &r_objs[n]) { + r = &r_objs[n]; + r->next = NULL; + r->cb = cb; + r->arg = arg; + r->pkt_id = pkt_id; + } + } + return r; +} + + +/** + * Append request to pending request queue + * @param tail Pointer to request queue tail pointer + * @param r Request to append + */ +static void +mqtt_append_request(struct mqtt_request_t **tail, struct mqtt_request_t *r) +{ + LWIP_ASSERT("mqtt_append_request: tail != NULL", tail != NULL); + + struct mqtt_request_t *head = NULL; + s16_t time_before = 0; + struct mqtt_request_t *iter = *tail; + + /* Iterate trough queue to find head, and count total timeout time */ + for(iter = *tail; iter != NULL; iter = iter->next) { + time_before += iter->timeout_diff; + head = iter; + } + + LWIP_ASSERT("mqtt_append_request: time_before <= MQTT_REQ_TIMEOUT", time_before <= MQTT_REQ_TIMEOUT); + r->timeout_diff = MQTT_REQ_TIMEOUT - time_before; + if(head == NULL) { + *tail = r; + } else { + head->next = r; + } +} + + +/** + * Delete request item + * @param r Request item to delete + */ +static void +mqtt_delete_request(struct mqtt_request_t *r) +{ + if(r != NULL) { + r->next = r; + } +} + +/** + * Remove a request item with a specific packet identifier from request queue + * @param tail Pointer to request queue tail pointer + * @param pkt_id Packet identifier of request to take + * @return Request item if found, NULL if not + */ +static struct mqtt_request_t * +mqtt_take_request(struct mqtt_request_t **tail, u16_t pkt_id) +{ + LWIP_ASSERT("mqtt_take_request: tail != NULL", tail != NULL); + struct mqtt_request_t *iter = NULL, *prev = NULL; + /* Search all request for pkt_id */ + for(iter = *tail; iter != NULL; iter = iter->next) { + if(iter->pkt_id == pkt_id) { + break; + } + prev = iter; + } + + /* If request was found */ + if(iter != NULL) { + /* unchain */ + if(prev == NULL) { + *tail= iter->next; + } else { + prev->next = iter->next; + } + /* If exists, add remaining timeout time for the request to next */ + if(iter->next != NULL) { + iter->next->timeout_diff += iter->timeout_diff; + } + iter->next = NULL; + } + return iter; +} + +/** + * Handle requests timeout + * @param tail Pointer to request queue tail pointer + * @param t Time since last call in seconds + */ +static void +mqtt_request_time_elapsed(struct mqtt_request_t **tail, u8_t t) +{ + LWIP_ASSERT("mqtt_request_time_elapsed: tail != NULL", tail != NULL); + struct mqtt_request_t *r = *tail; + while(t > 0 && r != NULL) { + if(t >= r->timeout_diff) { + t -= r->timeout_diff; + /* Unchain */ + *tail = r->next; + /* Notify upper layer about timeout */ + if(r->cb != NULL) { + r->cb(r->arg, ERR_TIMEOUT); + } + mqtt_delete_request(r); + /* Tail might be be modified in callback, so re-read it in every iteration */ + r = *(struct mqtt_request_t * const volatile *)tail; + } else { + r->timeout_diff -= t; + t = 0; + } + } +} + +/** + * Free all request items + * @param tail Pointer to request queue tail pointer + */ +static void +mqtt_clear_requests(struct mqtt_request_t **tail) +{ + LWIP_ASSERT("mqtt_clear_requests: tail != NULL", tail != NULL); + struct mqtt_request_t *iter, *next; + for(iter = *tail; iter != NULL; iter = next) { + next = iter->next; + mqtt_delete_request(iter); + } + *tail = NULL; +} +/** + * Initialize all request items + * @param r_objs Pointer to request objects + */ +static void +mqtt_init_requests(struct mqtt_request_t *r_objs) +{ + LWIP_ASSERT("mqtt_init_requests: r_objs != NULL", r_objs != NULL); + u8_t n; + for(n = 0; n < MQTT_REQ_MAX_IN_FLIGHT; n++) { + /* Item pointing to itself indicates unused */ + r_objs[n].next = &r_objs[n]; + } +} + +/*--------------------------------------------------------------------------------------------------------------------- */ +/* Output message build helpers */ + + +static void +mqtt_output_append_u8(struct mqtt_ringbuf_t *rb, u8_t value) +{ + mqtt_ringbuf_put(rb, value); +} + +static +void mqtt_output_append_u16(struct mqtt_ringbuf_t *rb, u16_t value) +{ + + mqtt_ringbuf_put(rb, value >> 8); + mqtt_ringbuf_put(rb, value & 0xff); +} + +static void +mqtt_output_append_buf(struct mqtt_ringbuf_t *rb, const void *data, u16_t length) +{ + u16_t n; + for(n=0; n < length; n++) { + mqtt_ringbuf_put(rb, ((const u8_t *)data)[n]); + } +} + +static void +mqtt_output_append_string(struct mqtt_ringbuf_t *rb, const char *str, u16_t length) +{ + mqtt_ringbuf_put(rb, length >> 8); + mqtt_ringbuf_put(rb, length & 0xff); + u16_t n; + for(n=0; n < length; n++) { + mqtt_ringbuf_put(rb, str[n]); + } +} + +/** + * Append fixed header + * @param rb Output ring buffer + * @param msg_type @see mqtt_message_type + * @param dup MQTT DUP flag + * @param qos MQTT QoS field + * @param retain MQTT retain flag + * @param r_length Remaining length after fixed header + */ + +static void +mqtt_output_append_fixed_header(struct mqtt_ringbuf_t *rb, u8_t msg_type, u8_t dup, + u8_t qos, u8_t retain, u16_t r_length) +{ + + /* Start with control byte */ + mqtt_output_append_u8(rb, (((msg_type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1))); + /* Encode remaining length field */ + do { + mqtt_output_append_u8(rb, (r_length & 0x7f) | (r_length >= 128 ? 0x80 : 0)); + r_length >>= 7; + } while(r_length > 0); +} + + +/** + * Check output buffer space + * @param rb Output ring buffer + * @param r_length Remaining length after fixed header + * @return 1 if message will fit, 0 if not enough buffer space + */ +static u8_t +mqtt_output_check_space(struct mqtt_ringbuf_t *rb, u16_t r_length) +{ + LWIP_ASSERT("mqtt_output_check_space: rb != NULL", rb != NULL); + + /* Start with length of type byte + remaining length */ + u16_t total_len = 1 + r_length; + + /* Calculate number of required bytes to contain the remaining bytes field and add to total*/ + do { + total_len++; + r_length >>= 7; + } while(r_length > 0); + + return (total_len <= mqtt_ringbuf_free(rb)); +} + + +/** + * Close connection to server + * @param client MQTT client + * @param reason Reason for disconnection + */ +static void +mqtt_close(mqtt_client_t *client, mqtt_connection_status_t reason) +{ + LWIP_ASSERT("mqtt_close: client != NULL", client != NULL); + + /* Bring down TCP connection if not already done */ + if(client->conn != NULL) { + tcp_recv(client->conn, NULL); + tcp_err(client->conn, NULL); + tcp_sent(client->conn, NULL); + err_t res = tcp_close(client->conn); + if(res != ERR_OK) { + tcp_abort(client->conn); + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_close: Close err=%s\n", lwip_strerr(res))); + } + client->conn = NULL; + } + + /* Remove all pending requests */ + mqtt_clear_requests(&client->pend_req_queue); + /* Stop cyclic timer */ + sys_untimeout(mqtt_cyclic_timer, client); + + /* Notify upper layer of disconnection if changed state */ + if(client->conn_state != TCP_DISCONNECTED) { + + client->conn_state = TCP_DISCONNECTED; + if(client->connect_cb != NULL) { + client->connect_cb(client, client->connect_arg, reason); + } + } +} + + +/** + * Interval timer, called every MQTT_CYCLIC_TIMER_INTERVAL seconds in MQTT_CONNECTING and MQTT_CONNECTED states + * @param arg MQTT client + */ +static void +mqtt_cyclic_timer(void *arg) +{ + u8_t restart_timer = 1; + mqtt_client_t *client = (mqtt_client_t *)arg; + LWIP_ASSERT("mqtt_cyclic_timer: client != NULL", client != NULL); + + if(client->conn_state == MQTT_CONNECTING) { + client->cyclic_tick++; + if((client->cyclic_tick * MQTT_CYCLIC_TIMER_INTERVAL) >= MQTT_CONNECT_TIMOUT) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_cyclic_timer: CONNECT attempt to server timed out\n")); + /* Disconnect TCP */ + mqtt_close(client, MQTT_CONNECT_TIMEOUT); + restart_timer = 0; + } + } else if(client->conn_state == MQTT_CONNECTED) { + /* Handle timeout for pending requests */ + mqtt_request_time_elapsed(&client->pend_req_queue, MQTT_CYCLIC_TIMER_INTERVAL); + + /* keep_alive > 0 means keep alive functionality shall be used */ + if(client->keep_alive > 0) { + + client->server_watchdog++; + /* If reception from server has been idle for 1.5*keep_alive time, server is considered unresponsive */ + if((client->server_watchdog * MQTT_CYCLIC_TIMER_INTERVAL) > (client->keep_alive + client->keep_alive/2)) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_cyclic_timer: Server incoming keep-alive timeout\n")); + mqtt_close(client, MQTT_CONNECT_TIMEOUT); + restart_timer = 0; + } + + /* If time for a keep alive message to be sent, transmission has been idle for keep_alive time */ + if((client->cyclic_tick * MQTT_CYCLIC_TIMER_INTERVAL) >= client->keep_alive) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_cyclic_timer: Sending keep-alive message to server\n")); + if(mqtt_output_check_space(&client->output, 0) != 0) { + mqtt_output_append_fixed_header(&client->output, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0, 0); + client->cyclic_tick = 0; + } + } else { + client->cyclic_tick++; + } + } + } else { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_cyclic_timer: Timer should not be running in state %d\n", client->conn_state)); + restart_timer = 0; + } + if(restart_timer) { + sys_timeout(MQTT_CYCLIC_TIMER_INTERVAL*1000, mqtt_cyclic_timer, arg); + } +} + + +/** + * Send PUBACK, PUBREC or PUBREL response message + * @param client MQTT client + * @param msg PUBACK, PUBREC or PUBREL + * @param pkt_id Packet identifier + * @param qos QoS value + * @return ERR_OK if successful, ERR_MEM if out of memory + */ +static err_t +pub_ack_rec_rel_response(mqtt_client_t *client, u8_t msg, u16_t pkt_id, u8_t qos) +{ + err_t err = ERR_OK; + if(mqtt_output_check_space(&client->output, 2)) { + mqtt_output_append_fixed_header(&client->output, msg, 0, qos, 0, 2); + mqtt_output_append_u16(&client->output, pkt_id); + mqtt_output_send(&client->output, client->conn); + } else { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("pub_ack_rec_rel_response: OOM creating response: %s with pkt_id: %d\n", + mqtt_msg_type_to_str(msg), pkt_id)); + err = ERR_MEM; + } + return err; +} + +/** + * Subscribe response from server + * @param client MQTT client + * @param r Matching request + * @param result Result code from server + */ +static void +mqtt_incomming_suback(struct mqtt_request_t *r, u8_t result) +{ + if(r->cb != NULL) { + r->cb(r->arg, result < 3 ? ERR_OK : ERR_ABRT); + } +} + + +/** + * Complete MQTT message received or buffer full + * @param client MQTT client + * @param var_hdr_payload Pointer to beginning of variable headers and optional payload + * @param length length received part + * @param remaining_length Remaining length of complete message + */ +static mqtt_connection_status_t +mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_idx, u16_t length, u32_t remaining_length) +{ + mqtt_connection_status_t res = MQTT_CONNECT_ACCEPTED; + + u8_t *var_hdr_payload = client->rx_buffer + fixed_hdr_idx; + + /* Control packet type */ + u8_t pkt_type = MQTT_CTL_PACKET_TYPE(client->rx_buffer[0]); + u16_t pkt_id = 0; + + if(pkt_type == MQTT_MSG_TYPE_CONNACK) { + if(client->conn_state == MQTT_CONNECTING) { + /* Get result code from CONNACK */ + res = var_hdr_payload[1]; + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_message_received: Connect response code %d\n", res)); + if(res == MQTT_CONNECT_ACCEPTED) { + /* Reset cyclic_tick when changing to connected state */ + client->cyclic_tick = 0; + client->conn_state = MQTT_CONNECTED; + /* Notify upper layer */ + if(client->connect_cb != 0) { + client->connect_cb(client, client->connect_arg, res); + } + } + } else { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_message_received: Received CONNACK in connected state\n")); + } + } else if(pkt_type == MQTT_MSG_TYPE_PINGRESP) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,( "mqtt_message_received: Received PINGRESP from server\n")); + + } else if(pkt_type == MQTT_MSG_TYPE_PUBLISH) { + u16_t payload_offset = 0; + u16_t payload_length = length; + u8_t qos = MQTT_CTL_PACKET_QOS(client->rx_buffer[0]); + + if(client->msg_idx <= MQTT_VAR_HEADER_BUFFER_LEN) { + /* Should have topic and pkt id*/ + u16_t topic_len = var_hdr_payload[0]; + topic_len = (topic_len << 8) + (u16_t)(var_hdr_payload[1]); + + uint8_t *topic = var_hdr_payload + 2; + uint16_t after_topic = 2 + topic_len; + /* Check length, add one byte even for QoS 0 so that zero termination will fit */ + if((after_topic + qos ? 2 : 1) > length) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_message_received: Receive buffer can not fit topic + pkt_id\n")); + goto out_disconnect; + } + + /* id for QoS 1 and 2 */ + if(qos > 0) { + client->inpub_pkt_id = ((u16_t)var_hdr_payload[after_topic] << 8) + (u16_t)var_hdr_payload[after_topic + 1]; + after_topic += 2; + } else { + client->inpub_pkt_id = 0; + } + /* Take backup of byte after topic */ + u8_t bkp = topic[topic_len]; + /* Zero terminate string */ + topic[topic_len] = 0; + /* Payload data remaining in receive buffer */ + payload_length = length - after_topic; + payload_offset = after_topic; + + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_incomming_publish: Received message with QoS %d at topic: %s, payload length %d\n", + qos, topic, remaining_length + payload_length)); + if(client->pub_cb != NULL) { + client->pub_cb(client->inpub_arg, (const char *)topic, remaining_length + payload_length); + } + /* Restore byte after topic */ + topic[topic_len] = bkp; + } + if(payload_length > 0 || remaining_length == 0) { + client->data_cb(client->inpub_arg, var_hdr_payload + payload_offset, payload_length, remaining_length == 0 ? MQTT_DATA_FLAG_LAST : 0); + /* Reply if QoS > 0 */ + if(remaining_length == 0 && qos > 0) { + /* Send PUBACK for QoS 1 or PUBREC for QoS 2 */ + u8_t resp_msg = (qos == 1) ? MQTT_MSG_TYPE_PUBACK : MQTT_MSG_TYPE_PUBREC; + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_incomming_publish: Sending publish response: %s with pkt_id: %d\n", + mqtt_msg_type_to_str(resp_msg), client->inpub_pkt_id)); + pub_ack_rec_rel_response(client, resp_msg, client->inpub_pkt_id, 0); + } + } + } else { + /* Get packet identifier */ + pkt_id = (u16_t)var_hdr_payload[0] << 8; + pkt_id |= (u16_t)var_hdr_payload[1]; + if(pkt_id == 0) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_message_received: Got message with illegal packet identifier: 0\n")); + goto out_disconnect; + } + if(pkt_type == MQTT_MSG_TYPE_PUBREC) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_message_received: PUBREC, sending PUBREL with pkt_id: %d\n",pkt_id)); + pub_ack_rec_rel_response(client, MQTT_MSG_TYPE_PUBREL, pkt_id, 1); + + } else if(pkt_type == MQTT_MSG_TYPE_PUBREL) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_message_received: PUBREL, sending PUBCOMP response with pkt_id: %d\n",pkt_id)); + pub_ack_rec_rel_response(client, MQTT_MSG_TYPE_PUBCOMP, pkt_id, 0); + + } else if(pkt_type == MQTT_MSG_TYPE_SUBACK || pkt_type == MQTT_MSG_TYPE_UNSUBACK || + pkt_type == MQTT_MSG_TYPE_PUBCOMP || pkt_type == MQTT_MSG_TYPE_PUBACK) { + struct mqtt_request_t *r = mqtt_take_request(&client->pend_req_queue, pkt_id); + if(r != NULL) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_message_received: %s response with id %d\n", mqtt_msg_type_to_str(pkt_type), pkt_id)); + if(pkt_type == MQTT_MSG_TYPE_SUBACK) { + if(length < 3) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_message_received: To small SUBACK packet\n")); + goto out_disconnect; + } else { + mqtt_incomming_suback(r, var_hdr_payload[2]); + } + } else if(r->cb != NULL) { + r->cb(r->arg, ERR_OK); + } + mqtt_delete_request(r); + } else { + LWIP_DEBUGF(MQTT_DEBUG_WARN,( "mqtt_message_received: Received %s reply, with wrong pkt_id: %d\n", mqtt_msg_type_to_str(pkt_type), pkt_id)); + } + } else { + LWIP_DEBUGF(MQTT_DEBUG_WARN,( "mqtt_message_received: Received unknown message type: %d\n", pkt_type)); + goto out_disconnect; + } + } + return res; +out_disconnect: + return MQTT_CONNECT_DISCONNECTED; +} + + +/** + * MQTT incoming message parser + * @param client MQTT client + * @param p PBUF chain of received data + * @return Connection status + */ +static mqtt_connection_status_t +mqtt_parse_incoming(mqtt_client_t *client, struct pbuf *p) +{ + u16_t in_offset = 0; + u32_t msg_rem_len = 0; + u8_t fixed_hdr_idx = 0; + u8_t b = 0; + + while(p->tot_len > in_offset) { + if((fixed_hdr_idx < 2) || ((b & 0x80) != 0)) { + + if(fixed_hdr_idx < client->msg_idx) { + b = client->rx_buffer[fixed_hdr_idx]; + } else { + b = pbuf_get_at(p, in_offset++); + client->rx_buffer[client->msg_idx++] = b; + } + fixed_hdr_idx++; + + if(fixed_hdr_idx >= 2) { + msg_rem_len |= (u32_t)(b & 0x7f) << ((fixed_hdr_idx - 2) * 7); + if((b & 0x80) == 0) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_parse_incoming: Remaining length after fixed header: %d\n", msg_rem_len)); + if(msg_rem_len == 0) { + /* Complete message with no extra headers of payload received */ + mqtt_message_received(client, fixed_hdr_idx, 0, 0); + client->msg_idx = 0; + fixed_hdr_idx = 0; + } else { + /* Bytes remaining in message */ + msg_rem_len = (msg_rem_len + fixed_hdr_idx) - client->msg_idx; + } + } + } + } else { + u16_t cpy_len, cpy_start, buffer_space; + + cpy_start = (client->msg_idx - fixed_hdr_idx) % (MQTT_VAR_HEADER_BUFFER_LEN - fixed_hdr_idx) + fixed_hdr_idx; + + /* Allow to copy the lesser one of available length in input data or bytes remaining in message */ + cpy_len = LWIP_MIN((u16_t)(p->tot_len - in_offset), msg_rem_len); + + /* Limit to available space in buffer */ + buffer_space = MQTT_VAR_HEADER_BUFFER_LEN - cpy_start; + if(cpy_len > buffer_space) { + cpy_len = buffer_space; + } + pbuf_copy_partial(p, client->rx_buffer+cpy_start, cpy_len, in_offset); + + /* Advance get and put indexes */ + client->msg_idx += cpy_len; + in_offset += cpy_len; + msg_rem_len -= cpy_len; + + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_parse_incoming: msg_idx: %d, cpy_len: %d, remaining %d\n", client->msg_idx, cpy_len, msg_rem_len)); + if(msg_rem_len == 0 || cpy_len == buffer_space) { + /* Whole message received or buffer is full */ + mqtt_connection_status_t res = mqtt_message_received(client, fixed_hdr_idx, (cpy_start + cpy_len) - fixed_hdr_idx, msg_rem_len); + if(res != MQTT_CONNECT_ACCEPTED) { + return res; + } + if(msg_rem_len == 0) { + /* Reset parser state */ + client->msg_idx = 0; + //msg_tot_len = 0; + fixed_hdr_idx = 0; + } + } + } + } + return MQTT_CONNECT_ACCEPTED; +} + + +/** + * TCP received callback function. @see tcp_recv_fn + * @param arg MQTT client + * @param p PBUF chain of received data + * @param err Passed as return value if not ERR_OK + * @return ERR_OK or err passed into callback + */ +static err_t +mqtt_tcp_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + mqtt_client_t *client = (mqtt_client_t *)arg; + LWIP_ASSERT("mqtt_tcp_recv_cb: client != NULL", client != NULL); + LWIP_ASSERT("mqtt_tcp_recv_cb: client->conn == pcb", client->conn == pcb); + + if(p == NULL) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_tcp_recv_cb: Recv pbuf=NULL, remote has closed connection\n")); + mqtt_close(client, MQTT_CONNECT_DISCONNECTED); + } else { + if(err != ERR_OK) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_tcp_recv_cb: Recv err=%d\n", err)); + pbuf_free(p); + return err; + } + + /* Tell remote that data has been received */ + tcp_recved(pcb, p->tot_len); + mqtt_connection_status_t res = mqtt_parse_incoming(client, p); + pbuf_free(p); + + if(res != MQTT_CONNECT_ACCEPTED) { + mqtt_close(client, res); + } + /* If keep alive functionality is used */ + if(client->keep_alive != 0) { + /* Reset server alive watchdog */ + client->server_watchdog = 0; + } + + } + return ERR_OK; +} + + +/** + * TCP data sent callback function. @see tcp_sent_fn + * @param arg MQTT client + * @param tpcb TCP connection handle + * @param len Number of bytes sent + * @return ERR_OK + */ +static err_t +mqtt_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t len) +{ + LWIP_UNUSED_ARG(tpcb); + LWIP_UNUSED_ARG(len); + mqtt_client_t *client = (mqtt_client_t *)arg; + + if(client->conn_state == MQTT_CONNECTED) { + + /* Reset keep-alive send timer and server watchdog */ + client->cyclic_tick = 0; + client->server_watchdog = 0; + /* QoS 0 publish has no response from server, so call its callbacks here */ + struct mqtt_request_t *r; + while((r = mqtt_take_request(&client->pend_req_queue, 0)) != NULL) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_tcp_sent_cb: Calling QoS 0 publish complete callback\n")); + if(r->cb != NULL) { + r->cb(r->arg, ERR_OK); + } + mqtt_delete_request(r); + } + /* Try send any remaining buffers from output queue */ + mqtt_output_send(&client->output, client->conn); + } + return ERR_OK; +} + +/** + * TCP error callback function. @see tcp_err_fn + * @param arg MQTT client + * @param err Error encountered + */ +static void +mqtt_tcp_err_cb(void *arg, err_t err) +{ + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_tcp_err_cb: TCP error callback: error %d, arg: %p\n", err, arg)); + mqtt_client_t *client = (mqtt_client_t *)arg; + LWIP_ASSERT("mqtt_tcp_err_cb: client != NULL", client != NULL); + /* Set conn to null before calling close as pcb is already deallocated*/ + client->conn = 0; + mqtt_close(client, MQTT_CONNECT_DISCONNECTED); + +} +/** + * TCP poll callback function. @see tcp_poll_fn + * @param arg MQTT client + * @param tpcb TCP connection handle + * @return err ERR_OK + */ +static err_t +mqtt_tcp_poll_cb(void *arg, struct tcp_pcb *tpcb) +{ + mqtt_client_t *client = (mqtt_client_t *)arg; + if(client->conn_state == MQTT_CONNECTED) { + /* Try send any remaining buffers from output queue */ + mqtt_output_send(&client->output, tpcb); + } + return ERR_OK; +} + +/** + * TCP connect callback function. @see tcp_connected_fn + * @param arg MQTT client + * @param err Always ERR_OK, mqtt_tcp_err_cb is called in case of error + * @return ERR_OK + */ +static err_t +mqtt_tcp_connect_cb(void *arg, struct tcp_pcb *tpcb, err_t err) +{ + if(err != ERR_OK) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_tcp_connect_cb: TCP connect error %d\n", err)); + return err; + } + mqtt_client_t* client = (mqtt_client_t *)arg; + + /* Initiate receiver state */ + client->msg_idx = 0; + + /* Setup TCP callbacks */ + tcp_recv(tpcb, mqtt_tcp_recv_cb); + tcp_sent(tpcb, mqtt_tcp_sent_cb); + tcp_poll(tpcb, mqtt_tcp_poll_cb, 2); + + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_tcp_connect_cb: TCP connection established to server\n")); + /* Enter MQTT connect state */ + client->conn_state = MQTT_CONNECTING; + + /* Start cyclic timer */ + sys_timeout(MQTT_CYCLIC_TIMER_INTERVAL*1000, mqtt_cyclic_timer, client); + client->cyclic_tick = 0; + + /* Start transmission from output queue, connect message is the first one out*/ + mqtt_output_send(&client->output, client->conn); + + return ERR_OK; +} + + + +/*---------------------------------------------------------------------------------------------------- */ +/* Public API */ + + +/** + * MQTT publish function. + * @param client MQTT client + * @param topic Publish topic string + * @param payload Data to publish (NULL is allowed) + * @param payload_length: Length of payload (0 is allowed) + * @param qos Quality of service, 0 1 or 2 + * @param cb Callback to call when publish is complete or has timed out + * @param arg User supplied argument to publish callback + * @return ERR_OK if successful + * ERR_CONN if client is disconnected + * ERR_MEM if short on memory + */ +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) +{ + LWIP_ASSERT("mqtt_publish: client != NULL", client); + LWIP_ASSERT("mqtt_publish: topic != NULL", topic); + LWIP_ERROR("mqtt_publish: TCP disconnected", (client->conn_state != TCP_DISCONNECTED), return ERR_CONN); + + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_publish: Publish with payload length %d to topic \"%s\"\n", payload_length, topic)); + + struct mqtt_request_t *r; + u16_t pkt_id; + u16_t topic_len = strlen(topic); + u16_t remaining_length = 2 + topic_len + payload_length; + + if(qos > 0) { + remaining_length += 2; + /* Generate pkt_id id for QoS1 and 2 */ + pkt_id = msg_generate_packet_id(client); + } else { + /* Use reserved value pkt_id 0 for QoS 0 in request handle */ + pkt_id = 0; + } + + r = mqtt_create_request(client->req_list, pkt_id, cb, arg); + if(r == NULL) { + return ERR_MEM; + } + + if(mqtt_output_check_space(&client->output, remaining_length) == 0) { + mqtt_delete_request(r); + return ERR_MEM; + } + /* Append fixed header */ + mqtt_output_append_fixed_header(&client->output, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain, remaining_length); + + /* Append Topic */ + mqtt_output_append_string(&client->output, topic, topic_len); + + /* Append packet if for QoS 1 and 2*/ + if(qos > 0) { + mqtt_output_append_u16(&client->output, pkt_id); + } + + /* Append optional publish payload */ + if((payload != NULL) && (payload_length > 0)) { + mqtt_output_append_buf(&client->output, payload, payload_length); + } + + mqtt_append_request(&client->pend_req_queue, r); + mqtt_output_send(&client->output, client->conn); + return ERR_OK; +} + + +/** + * @brief MQTT subscribe/unsubscribe function. + * @param client MQTT client + * @param topic topic to subscribe to + * @param qos Quality of service, 0 1 or 2 (only used for subscribe) + * @param cb Callback to call when subscribe/unsubscribe reponse is received + * @param arg User supplied argument to publish callback + * @param sub 1 for subscribe, 0 for unsubscribe + * @return ERR_OK if successful, @see err_t enum for other results + */ +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) +{ + LWIP_ASSERT("mqtt_sub_unsub: client != NULL", client); + LWIP_ASSERT("mqtt_sub_unsub: topic != NULL", topic); + LWIP_ASSERT("mqtt_sub_unsub: qos < 3", qos < 3); + if(client->conn_state == TCP_DISCONNECTED) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_sub_unsub: Can not (un)subscribe in disconnected state\n")); + return ERR_CONN; + } + + u16_t topic_len = strlen(topic); + /* Topic string, pkt_id, qos for subscribe */ + u16_t remaining_length = topic_len + 2 + 2 + (sub != 0); + + u16_t pkt_id = msg_generate_packet_id(client); + struct mqtt_request_t *r = mqtt_create_request(client->req_list, pkt_id, cb, arg); + if(r == NULL) { + return ERR_MEM; + } + + if(mqtt_output_check_space(&client->output, remaining_length) == 0) { + mqtt_delete_request(r); + return ERR_MEM; + } + + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_sub_unsub: Client (un)subscribe to topic \"%s\", id: %d\n", topic, pkt_id)); + + mqtt_output_append_fixed_header(&client->output, sub ? MQTT_MSG_TYPE_SUBSCRIBE : MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0, remaining_length); + /* Packet id */ + mqtt_output_append_u16(&client->output, pkt_id); + /* Topic */ + mqtt_output_append_string(&client->output, topic, topic_len); + /* QoS */ + if(sub != 0) { + mqtt_output_append_u8(&client->output, LWIP_MIN(qos, 2)); + } + + mqtt_append_request(&client->pend_req_queue, r); + mqtt_output_send(&client->output, client->conn); + return ERR_OK; +} + + +/** + * Set callback to handle incoming publish requests from server + * @param client MQTT client + * @param pub_cb Callback invoked when publish starts, contain topic and total length of payload + * @param data_cb Callback for each fragment of payload that arrives + * @param arg User supplied argument to both callbacks + */ +void +mqtt_set_inpub_callback(mqtt_client_t *client, mqtt_incoming_publish_cb_t pub_cb, + mqtt_incoming_data_cb_t data_cb, void *arg) +{ + LWIP_ASSERT("mqtt_set_inpub_callback: client != NULL", client != NULL); + client->data_cb = data_cb; + client->pub_cb = pub_cb; + client->inpub_arg = arg; +} + +/** + * Create a new MQTT client instance + * @param client MQTT client + * @return Pointer to instance on success, NULL otherwise + */ +mqtt_client_t * +mqtt_client_new(void) +{ + mqtt_client_t *client = (mqtt_client_t *)mem_malloc(sizeof(mqtt_client_t)); + if(client != NULL) { + memset(client, 0, sizeof(mqtt_client_t)); + } + return client; +} + + +/** + * Connect to MQTT server + * @param client MQTT client + * @param host String containing server IP + * @param cb Connection state change callback + * @param arg User supplied argument to connection callback + * @param client_info Client identification and connection options + * @return ERR_OK if successful, @see err_t enum for other results + */ +err_t +mqtt_client_connect(mqtt_client_t *client, const char *host, mqtt_connection_cb_t cb, void *arg, + const struct mqtt_connect_client_info_t *client_info) +{ + + LWIP_ASSERT("mqtt_client_connect: client != NULL", client != NULL); + LWIP_ASSERT("mqtt_client_connect: host != NULL", host != NULL); + LWIP_ASSERT("mqtt_client_connect: client_info != NULL", client_info != NULL); + LWIP_ASSERT("mqtt_client_connect: client_info->client_id != NULL", client_info->client_id != NULL); + + if(client->conn_state != TCP_DISCONNECTED) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Already connected\n")); + return ERR_ISCONN; + } + err_t err; + ip_addr_t ip_addr; + u16_t port = 1883; + + if(ipaddr_aton(host, &ip_addr) == 0) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Illegal hostname: %s\n", host)); + return ERR_ARG; + } + /* Wipe clean */ + memset(client, 0, sizeof(mqtt_client_t)); + client->connect_arg = arg; + client->connect_cb = cb; + client->keep_alive = client_info->keep_alive; + mqtt_init_requests(client->req_list); + + /* Build connect message */ + /* Length is the sum of 2+"MQTT", protocol level, flags and keep alive */ + u16_t remaining_length = 2 + 4 + 1 + 1 + 2; + u8_t flags = 0, will_topic_len = 0, will_msg_len = 0; + + if(client_info->will_topic != NULL && client_info->will_msg != NULL) { + flags |= MQTT_CONNECT_FLAG_WILL; + flags |= (client_info->will_qos & 3) << 3; + if(client_info->will_retain) + flags |= MQTT_CONNECT_FLAG_WILL_RETAIN; + will_topic_len = strlen(client_info->will_topic); + will_msg_len = strlen(client_info->will_msg); + remaining_length += 2 + will_topic_len + 2 + will_msg_len; + } + + /* Don't complicate things, always connect using clean session */ + flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION; + + u16_t client_id_length = strlen(client_info->client_id); + remaining_length += 2 + client_id_length; + + if(mqtt_output_check_space(&client->output, remaining_length) == 0) { + return ERR_MEM; + } + + client->conn = tcp_new(); + if(client->conn == NULL) { + return ERR_MEM; + } + + /* Set arg pointer for callbacks */ + tcp_arg(client->conn, client); + /* Any local address, pick random local port number */ + err = tcp_bind(client->conn, IP_ADDR_ANY, 0); + if(err != ERR_OK) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Error binding to local ip/port, %d\n", err)); + goto tcp_fail; + } + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Connecting to host: %s at port:%d\n", host, port)); + + /* Connect to server */ + err = tcp_connect(client->conn, &ip_addr, port, mqtt_tcp_connect_cb); + if(err != ERR_OK) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Error connecting to remote ip/port, %d\n", err)); + goto tcp_fail; + } + /* Set error callback */ + tcp_err(client->conn, mqtt_tcp_err_cb); + client->conn_state = TCP_CONNECTING; + + /* Append fixed header */ + mqtt_output_append_fixed_header(&client->output, MQTT_MSG_TYPE_CONNECT, 0, 0, 0, remaining_length); + /* Append Protocol string */ + mqtt_output_append_string(&client->output, "MQTT", 4); + /* Append Protocol level */ + mqtt_output_append_u8(&client->output, 4); + /* Append connect flags */ + mqtt_output_append_u8(&client->output, flags); + /* Append keep-alive */ + mqtt_output_append_u16(&client->output, client_info->keep_alive); + /* Append client id */ + mqtt_output_append_string(&client->output, client_info->client_id, client_id_length); + /* Append will message if used */ + if(will_topic_len > 0) { + mqtt_output_append_string(&client->output, client_info->will_topic, will_topic_len); + mqtt_output_append_string(&client->output, client_info->will_msg, will_msg_len); + } + return ERR_OK; + +tcp_fail: + tcp_abort(client->conn); + client->conn = NULL; + return err; + +} + + +/** + * Disconnect from MQTT server + * @param client MQTT client + */ +void +mqtt_disconnect(mqtt_client_t *client) +{ + LWIP_ASSERT("mqtt_disconnect: client != NULL", client); + /* If connection in not already closed */ + if(client->conn_state != TCP_DISCONNECTED) { + /* Set conn_state before calling mqtt_close to prevent callback from being called */ + client->conn_state = TCP_DISCONNECTED; + mqtt_close(client, 0); + } +} + +/** + * Check connection with server + * @param client MQTT client + * @return 1 if connected to server, 0 otherwise + */ +u8_t +mqtt_client_is_connected(mqtt_client_t *client) +{ + LWIP_ASSERT("mqtt_client_is_connected: client != NULL", client); + return client->conn_state == MQTT_CONNECTED; +} diff --git a/src/include/lwip/apps/mqtt.h b/src/include/lwip/apps/mqtt.h new file mode 100644 index 00000000..3b27bb08 --- /dev/null +++ b/src/include/lwip/apps/mqtt.h @@ -0,0 +1,246 @@ +/** + * @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_MQTT_CLIENT_H +#define LWIP_HDR_MQTT_CLIENT_H + +#include "lwip/err.h" +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * 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 + +typedef struct mqtt_client_t mqtt_client_t; + + +/*---------------------------------------------------------------------------------------------- */ +/* Connection with server */ + +/** 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; +}; + +/** 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; + +/** 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); + + +/** Data callback flags */ +enum { + /** Flag set when last fragment of data arrives in data callback */ + MQTT_DATA_FLAG_LAST = 1, +}; + +/** Function prototype for MQTT incoming publish data callback function. Called when data + * arrives to a subscribed topic @see mqtt_subscribe + * + * @param client MQTT client itself + * @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); + + +/** Function prototype for MQTT incoming publish function. Called when an incoming publish + * arrives to a subscribed topic @see mqtt_subscribe + * + * @param client MQTT client itself + * @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 + * @return Optional numerical topic identifier to be used in data callback + */ +typedef void (*mqtt_incoming_publish_cb_t)(void *arg, const char *topic, u32_t tot_len); + + +/** 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; +}; + +/** 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 { + u16_t put; + u16_t get; + u8_t buf[MQTT_OUTPUT_RINGBUF_SIZE]; + } output; +}; + + +/** Connect to server */ +err_t mqtt_client_connect(mqtt_client_t *client, const char *host, 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); + +/** Subscribe to topic */ +#define mqtt_subscribe(client, topic, qos, cb, arg) mqtt_sub_unsub(client, topic, qos, cb, arg, 1) +/** 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_MQTT_CLIENT_H */ From 14e36866f5efffbec78a3ad7fc5aa0057b36f7dc Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Tue, 20 Dec 2016 09:41:21 +0100 Subject: [PATCH 133/184] Some cleanups in MQTT client Integrate in documentation Compile fixes, mostly: Variables must be declared before any statement in a function --- src/apps/mqtt/mqtt.c | 79 ++++++++++++++++++------------------ src/include/lwip/apps/mqtt.h | 43 ++++++++++++-------- 2 files changed, 67 insertions(+), 55 deletions(-) diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index e36e33a4..5addb2fc 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -2,6 +2,8 @@ * @file * MQTT client * + * @defgroup mqtt MQTT Client + * @ingroup apps */ /* @@ -51,7 +53,7 @@ #include "lwip/err.h" #include "lwip/pbuf.h" #include "lwip/tcp.h" -#include "mqtt.h" +#include "lwip/apps/mqtt.h" /** * MQTT_DEBUG: Default is off. @@ -139,7 +141,7 @@ enum mqtt_connect_flag { }; -#if (MQTT_DEBUG == LWIP_DBG_ON) && defined(LWIP_DEBUG) +#if defined(LWIP_DEBUG) static const char * const mqtt_message_type_str[15] = { "UNDEFINED", @@ -223,11 +225,11 @@ msg_generate_packet_id(mqtt_client_t *client) static void mqtt_output_send(struct mqtt_ringbuf_t *rb, struct tcp_pcb *tpcb) { - LWIP_ASSERT("mqtt_output_send: tpcb != NULL", tpcb != NULL); err_t err; u8_t wrap = 0; u16_t ringbuf_lin_len = mqtt_ringbuf_linear_read_length(rb); u16_t send_len = tcp_sndbuf(tpcb); + LWIP_ASSERT("mqtt_output_send: tpcb != NULL", tpcb != NULL); if(send_len == 0 || ringbuf_lin_len == 0) { return; @@ -275,9 +277,9 @@ mqtt_output_send(struct mqtt_ringbuf_t *rb, struct tcp_pcb *tpcb) static struct mqtt_request_t * mqtt_create_request(struct mqtt_request_t *r_objs, u16_t pkt_id, mqtt_request_cb_t cb, void *arg) { - LWIP_ASSERT("mqtt_create_request: r_objs != NULL", r_objs != NULL); struct mqtt_request_t *r = NULL; u8_t n; + LWIP_ASSERT("mqtt_create_request: r_objs != NULL", r_objs != NULL); for(n = 0; n < MQTT_REQ_MAX_IN_FLIGHT && r == NULL; n++) { /* Item point to itself if not in use */ if(r_objs[n].next == &r_objs[n]) { @@ -300,12 +302,12 @@ mqtt_create_request(struct mqtt_request_t *r_objs, u16_t pkt_id, mqtt_request_cb static void mqtt_append_request(struct mqtt_request_t **tail, struct mqtt_request_t *r) { - LWIP_ASSERT("mqtt_append_request: tail != NULL", tail != NULL); - struct mqtt_request_t *head = NULL; s16_t time_before = 0; struct mqtt_request_t *iter = *tail; + LWIP_ASSERT("mqtt_append_request: tail != NULL", tail != NULL); + /* Iterate trough queue to find head, and count total timeout time */ for(iter = *tail; iter != NULL; iter = iter->next) { time_before += iter->timeout_diff; @@ -343,8 +345,8 @@ mqtt_delete_request(struct mqtt_request_t *r) static struct mqtt_request_t * mqtt_take_request(struct mqtt_request_t **tail, u16_t pkt_id) { - LWIP_ASSERT("mqtt_take_request: tail != NULL", tail != NULL); struct mqtt_request_t *iter = NULL, *prev = NULL; + LWIP_ASSERT("mqtt_take_request: tail != NULL", tail != NULL); /* Search all request for pkt_id */ for(iter = *tail; iter != NULL; iter = iter->next) { if(iter->pkt_id == pkt_id) { @@ -378,8 +380,8 @@ mqtt_take_request(struct mqtt_request_t **tail, u16_t pkt_id) static void mqtt_request_time_elapsed(struct mqtt_request_t **tail, u8_t t) { - LWIP_ASSERT("mqtt_request_time_elapsed: tail != NULL", tail != NULL); struct mqtt_request_t *r = *tail; + LWIP_ASSERT("mqtt_request_time_elapsed: tail != NULL", tail != NULL); while(t > 0 && r != NULL) { if(t >= r->timeout_diff) { t -= r->timeout_diff; @@ -406,8 +408,8 @@ mqtt_request_time_elapsed(struct mqtt_request_t **tail, u8_t t) static void mqtt_clear_requests(struct mqtt_request_t **tail) { - LWIP_ASSERT("mqtt_clear_requests: tail != NULL", tail != NULL); struct mqtt_request_t *iter, *next; + LWIP_ASSERT("mqtt_clear_requests: tail != NULL", tail != NULL); for(iter = *tail; iter != NULL; iter = next) { next = iter->next; mqtt_delete_request(iter); @@ -421,8 +423,8 @@ mqtt_clear_requests(struct mqtt_request_t **tail) static void mqtt_init_requests(struct mqtt_request_t *r_objs) { - LWIP_ASSERT("mqtt_init_requests: r_objs != NULL", r_objs != NULL); u8_t n; + LWIP_ASSERT("mqtt_init_requests: r_objs != NULL", r_objs != NULL); for(n = 0; n < MQTT_REQ_MAX_IN_FLIGHT; n++) { /* Item pointing to itself indicates unused */ r_objs[n].next = &r_objs[n]; @@ -442,7 +444,6 @@ mqtt_output_append_u8(struct mqtt_ringbuf_t *rb, u8_t value) static void mqtt_output_append_u16(struct mqtt_ringbuf_t *rb, u16_t value) { - mqtt_ringbuf_put(rb, value >> 8); mqtt_ringbuf_put(rb, value & 0xff); } @@ -459,9 +460,9 @@ mqtt_output_append_buf(struct mqtt_ringbuf_t *rb, const void *data, u16_t length static void mqtt_output_append_string(struct mqtt_ringbuf_t *rb, const char *str, u16_t length) { + u16_t n; mqtt_ringbuf_put(rb, length >> 8); mqtt_ringbuf_put(rb, length & 0xff); - u16_t n; for(n=0; n < length; n++) { mqtt_ringbuf_put(rb, str[n]); } @@ -481,7 +482,6 @@ static void mqtt_output_append_fixed_header(struct mqtt_ringbuf_t *rb, u8_t msg_type, u8_t dup, u8_t qos, u8_t retain, u16_t r_length) { - /* Start with control byte */ mqtt_output_append_u8(rb, (((msg_type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1))); /* Encode remaining length field */ @@ -501,11 +501,11 @@ mqtt_output_append_fixed_header(struct mqtt_ringbuf_t *rb, u8_t msg_type, u8_t d static u8_t mqtt_output_check_space(struct mqtt_ringbuf_t *rb, u16_t r_length) { - LWIP_ASSERT("mqtt_output_check_space: rb != NULL", rb != NULL); - /* Start with length of type byte + remaining length */ u16_t total_len = 1 + r_length; + LWIP_ASSERT("mqtt_output_check_space: rb != NULL", rb != NULL); + /* Calculate number of required bytes to contain the remaining bytes field and add to total*/ do { total_len++; @@ -670,7 +670,7 @@ mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_idx, u16_t length, u if(pkt_type == MQTT_MSG_TYPE_CONNACK) { if(client->conn_state == MQTT_CONNECTING) { /* Get result code from CONNACK */ - res = var_hdr_payload[1]; + res = (mqtt_connection_status_t)var_hdr_payload[1]; LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_message_received: Connect response code %d\n", res)); if(res == MQTT_CONNECT_ACCEPTED) { /* Reset cyclic_tick when changing to connected state */ @@ -918,9 +918,10 @@ mqtt_tcp_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) static err_t mqtt_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t len) { + mqtt_client_t *client = (mqtt_client_t *)arg; + LWIP_UNUSED_ARG(tpcb); LWIP_UNUSED_ARG(len); - mqtt_client_t *client = (mqtt_client_t *)arg; if(client->conn_state == MQTT_CONNECTED) { @@ -984,11 +985,12 @@ mqtt_tcp_poll_cb(void *arg, struct tcp_pcb *tpcb) static err_t mqtt_tcp_connect_cb(void *arg, struct tcp_pcb *tpcb, err_t err) { + mqtt_client_t* client = (mqtt_client_t *)arg; + if(err != ERR_OK) { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_tcp_connect_cb: TCP connect error %d\n", err)); return err; } - mqtt_client_t* client = (mqtt_client_t *)arg; /* Initiate receiver state */ client->msg_idx = 0; @@ -1025,6 +1027,7 @@ mqtt_tcp_connect_cb(void *arg, struct tcp_pcb *tpcb, err_t err) * @param payload Data to publish (NULL is allowed) * @param payload_length: Length of payload (0 is allowed) * @param qos Quality of service, 0 1 or 2 + * @param retain MQTT retain flag * @param cb Callback to call when publish is complete or has timed out * @param arg User supplied argument to publish callback * @return ERR_OK if successful @@ -1035,17 +1038,17 @@ 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) { + struct mqtt_request_t *r; + u16_t pkt_id; + u16_t topic_len = strlen(topic); + u16_t remaining_length = 2 + topic_len + payload_length; + LWIP_ASSERT("mqtt_publish: client != NULL", client); LWIP_ASSERT("mqtt_publish: topic != NULL", topic); LWIP_ERROR("mqtt_publish: TCP disconnected", (client->conn_state != TCP_DISCONNECTED), return ERR_CONN); LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_publish: Publish with payload length %d to topic \"%s\"\n", payload_length, topic)); - struct mqtt_request_t *r; - u16_t pkt_id; - u16_t topic_len = strlen(topic); - u16_t remaining_length = 2 + topic_len + payload_length; - if(qos > 0) { remaining_length += 2; /* Generate pkt_id id for QoS1 and 2 */ @@ -1099,6 +1102,13 @@ mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_ 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) { + u16_t topic_len = strlen(topic); + /* Topic string, pkt_id, qos for subscribe */ + u16_t remaining_length = topic_len + 2 + 2 + (sub != 0); + + u16_t pkt_id = msg_generate_packet_id(client); + struct mqtt_request_t *r = mqtt_create_request(client->req_list, pkt_id, cb, arg); + LWIP_ASSERT("mqtt_sub_unsub: client != NULL", client); LWIP_ASSERT("mqtt_sub_unsub: topic != NULL", topic); LWIP_ASSERT("mqtt_sub_unsub: qos < 3", qos < 3); @@ -1107,12 +1117,6 @@ mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_request_ return ERR_CONN; } - u16_t topic_len = strlen(topic); - /* Topic string, pkt_id, qos for subscribe */ - u16_t remaining_length = topic_len + 2 + 2 + (sub != 0); - - u16_t pkt_id = msg_generate_packet_id(client); - struct mqtt_request_t *r = mqtt_create_request(client->req_list, pkt_id, cb, arg); if(r == NULL) { return ERR_MEM; } @@ -1159,7 +1163,6 @@ mqtt_set_inpub_callback(mqtt_client_t *client, mqtt_incoming_publish_cb_t pub_cb /** * Create a new MQTT client instance - * @param client MQTT client * @return Pointer to instance on success, NULL otherwise */ mqtt_client_t * @@ -1186,6 +1189,12 @@ err_t mqtt_client_connect(mqtt_client_t *client, const char *host, mqtt_connection_cb_t cb, void *arg, const struct mqtt_connect_client_info_t *client_info) { + err_t err; + ip_addr_t ip_addr; + u16_t port = 1883; + /* Length is the sum of 2+"MQTT", protocol level, flags and keep alive */ + u16_t remaining_length = 2 + 4 + 1 + 1 + 2; + u8_t flags = 0, will_topic_len = 0, will_msg_len = 0; LWIP_ASSERT("mqtt_client_connect: client != NULL", client != NULL); LWIP_ASSERT("mqtt_client_connect: host != NULL", host != NULL); @@ -1196,9 +1205,6 @@ mqtt_client_connect(mqtt_client_t *client, const char *host, mqtt_connection_cb_ LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Already connected\n")); return ERR_ISCONN; } - err_t err; - ip_addr_t ip_addr; - u16_t port = 1883; if(ipaddr_aton(host, &ip_addr) == 0) { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Illegal hostname: %s\n", host)); @@ -1212,10 +1218,6 @@ mqtt_client_connect(mqtt_client_t *client, const char *host, mqtt_connection_cb_ mqtt_init_requests(client->req_list); /* Build connect message */ - /* Length is the sum of 2+"MQTT", protocol level, flags and keep alive */ - u16_t remaining_length = 2 + 4 + 1 + 1 + 2; - u8_t flags = 0, will_topic_len = 0, will_msg_len = 0; - if(client_info->will_topic != NULL && client_info->will_msg != NULL) { flags |= MQTT_CONNECT_FLAG_WILL; flags |= (client_info->will_qos & 3) << 3; @@ -1284,7 +1286,6 @@ tcp_fail: tcp_abort(client->conn); client->conn = NULL; return err; - } @@ -1300,7 +1301,7 @@ mqtt_disconnect(mqtt_client_t *client) if(client->conn_state != TCP_DISCONNECTED) { /* Set conn_state before calling mqtt_close to prevent callback from being called */ client->conn_state = TCP_DISCONNECTED; - mqtt_close(client, 0); + mqtt_close(client, (mqtt_connection_status_t)0); } } diff --git a/src/include/lwip/apps/mqtt.h b/src/include/lwip/apps/mqtt.h index 3b27bb08..e5cd3660 100644 --- a/src/include/lwip/apps/mqtt.h +++ b/src/include/lwip/apps/mqtt.h @@ -44,6 +44,10 @@ extern "C" { #endif +/** @ingroup mqtt + * @{ + */ + /** * Output ring-buffer size, must be able to fit largest outgoing publish message topic+payloads */ @@ -173,39 +177,42 @@ struct mqtt_request_t 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; + /** 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 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; + /** 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; + 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 { - u16_t put; - u16_t get; - u8_t buf[MQTT_OUTPUT_RINGBUF_SIZE]; - } output; + /** Output ring-buffer */ + struct mqtt_ringbuf_t output; }; @@ -239,6 +246,10 @@ err_t mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_re 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 From 12bc2c04252298bd5c151c8560d78a8fdece145b Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Tue, 20 Dec 2016 10:08:50 +0100 Subject: [PATCH 134/184] MQTT cleanups: - create mqtt_opts.h file and move options in there - documentation cleanups --- src/apps/mqtt/mqtt.c | 9 +++- src/include/lwip/apps/mqtt.h | 73 +++++++++++---------------- src/include/lwip/apps/mqtt_opts.h | 82 +++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 45 deletions(-) create mode 100644 src/include/lwip/apps/mqtt_opts.h diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index 5addb2fc..74982850 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -1021,6 +1021,7 @@ mqtt_tcp_connect_cb(void *arg, struct tcp_pcb *tpcb, err_t err) /** + * @ingroup mqtt * MQTT publish function. * @param client MQTT client * @param topic Publish topic string @@ -1090,7 +1091,8 @@ mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_ /** - * @brief MQTT subscribe/unsubscribe function. + * @ingroup mqtt + * MQTT subscribe/unsubscribe function. * @param client MQTT client * @param topic topic to subscribe to * @param qos Quality of service, 0 1 or 2 (only used for subscribe) @@ -1145,6 +1147,7 @@ mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_request_ /** + * @ingroup mqtt * Set callback to handle incoming publish requests from server * @param client MQTT client * @param pub_cb Callback invoked when publish starts, contain topic and total length of payload @@ -1162,6 +1165,7 @@ mqtt_set_inpub_callback(mqtt_client_t *client, mqtt_incoming_publish_cb_t pub_cb } /** + * @ingroup mqtt * Create a new MQTT client instance * @return Pointer to instance on success, NULL otherwise */ @@ -1177,6 +1181,7 @@ mqtt_client_new(void) /** + * @ingroup mqtt * Connect to MQTT server * @param client MQTT client * @param host String containing server IP @@ -1290,6 +1295,7 @@ tcp_fail: /** + * @ingroup mqtt * Disconnect from MQTT server * @param client MQTT client */ @@ -1306,6 +1312,7 @@ mqtt_disconnect(mqtt_client_t *client) } /** + * @ingroup mqtt * Check connection with server * @param client MQTT client * @return 1 if connected to server, 0 otherwise diff --git a/src/include/lwip/apps/mqtt.h b/src/include/lwip/apps/mqtt.h index e5cd3660..f7412f62 100644 --- a/src/include/lwip/apps/mqtt.h +++ b/src/include/lwip/apps/mqtt.h @@ -34,49 +34,24 @@ * Author: Erik Andersson * */ -#ifndef LWIP_HDR_MQTT_CLIENT_H -#define LWIP_HDR_MQTT_CLIENT_H +#ifndef LWIP_HDR_APPS_MQTT_CLIENT_H +#define LWIP_HDR_APPS_MQTT_CLIENT_H +#include "lwip/apps/mqtt_opts.h" #include "lwip/err.h" -#include "lwip/opt.h" #ifdef __cplusplus extern "C" { #endif -/** @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 - typedef struct mqtt_client_t mqtt_client_t; - /*---------------------------------------------------------------------------------------------- */ /* Connection with server */ -/** Client information and connection parameters */ +/** + * @ingroup mqtt + * Client information and connection parameters */ struct mqtt_connect_client_info_t { /** Client identifier, must be set by caller */ const char *client_id; @@ -93,7 +68,9 @@ struct mqtt_connect_client_info_t { u8_t will_retain; }; -/** Connection status codes */ +/** + * @ingroup mqtt + * Connection status codes */ typedef enum { MQTT_CONNECT_ACCEPTED = 0, @@ -106,7 +83,9 @@ typedef enum MQTT_CONNECT_TIMEOUT = 257 } mqtt_connection_status_t; -/** Function prototype for mqtt connection status callback. Called when +/** + * @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 * @@ -118,13 +97,17 @@ typedef enum typedef void (*mqtt_connection_cb_t)(mqtt_client_t *client, void *arg, mqtt_connection_status_t status); -/** Data callback flags */ +/** + * @ingroup mqtt + * Data callback flags */ enum { /** Flag set when last fragment of data arrives in data callback */ MQTT_DATA_FLAG_LAST = 1, }; -/** Function prototype for MQTT incoming publish data callback function. Called when data +/** + * @ingroup mqtt + * Function prototype for MQTT incoming publish data callback function. Called when data * arrives to a subscribed topic @see mqtt_subscribe * * @param client MQTT client itself @@ -138,7 +121,9 @@ enum { typedef void (*mqtt_incoming_data_cb_t)(void *arg, const u8_t *data, u16_t len, u8_t flags); -/** Function prototype for MQTT incoming publish function. Called when an incoming publish +/** + * @ingroup mqtt + * Function prototype for MQTT incoming publish function. Called when an incoming publish * arrives to a subscribed topic @see mqtt_subscribe * * @param client MQTT client itself @@ -150,7 +135,9 @@ typedef void (*mqtt_incoming_data_cb_t)(void *arg, const u8_t *data, u16_t len, typedef void (*mqtt_incoming_publish_cb_t)(void *arg, const char *topic, u32_t tot_len); -/** Function prototype for mqtt request callback. Called when a subscribe, unsubscribe +/** + * @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 @@ -236,9 +223,11 @@ void mqtt_set_inpub_callback(mqtt_client_t *client, mqtt_incoming_publish_cb_t, /** 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); -/** Subscribe to topic */ +/** @ingroup mqtt + *Subscribe to topic */ #define mqtt_subscribe(client, topic, qos, cb, arg) mqtt_sub_unsub(client, topic, qos, cb, arg, 1) -/** Unsubscribe to topic */ +/** @ingroup mqtt + * Unsubscribe to topic */ #define mqtt_unsubscribe(client, topic, cb, arg) mqtt_sub_unsub(client, topic, 0, cb, arg, 0) @@ -246,12 +235,8 @@ err_t mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_re 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_MQTT_CLIENT_H */ +#endif /* LWIP_HDR_APPS_MQTT_CLIENT_H */ diff --git a/src/include/lwip/apps/mqtt_opts.h b/src/include/lwip/apps/mqtt_opts.h new file mode 100644 index 00000000..028ef7c2 --- /dev/null +++ b/src/include/lwip/apps/mqtt_opts.h @@ -0,0 +1,82 @@ +/** + * @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 + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_MQTT_OPTS_H */ From b6a131edfb48430379376d1e46f7e59a3d9673fb Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 20 Dec 2016 10:27:43 +0100 Subject: [PATCH 135/184] mqtt: fix C usage (declaration after statement), fix casting to smaller type --- src/apps/mqtt/mqtt.c | 89 +++++++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index 74982850..0bc3ab0a 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -384,7 +384,7 @@ mqtt_request_time_elapsed(struct mqtt_request_t **tail, u8_t t) LWIP_ASSERT("mqtt_request_time_elapsed: tail != NULL", tail != NULL); while(t > 0 && r != NULL) { if(t >= r->timeout_diff) { - t -= r->timeout_diff; + t -= (u8_t)r->timeout_diff; /* Unchain */ *tail = r->next; /* Notify upper layer about timeout */ @@ -528,10 +528,11 @@ mqtt_close(mqtt_client_t *client, mqtt_connection_status_t reason) /* Bring down TCP connection if not already done */ if(client->conn != NULL) { + err_t res; tcp_recv(client->conn, NULL); tcp_err(client->conn, NULL); tcp_sent(client->conn, NULL); - err_t res = tcp_close(client->conn); + res = tcp_close(client->conn); if(res != ERR_OK) { tcp_abort(client->conn); LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_close: Close err=%s\n", lwip_strerr(res))); @@ -694,11 +695,14 @@ mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_idx, u16_t length, u if(client->msg_idx <= MQTT_VAR_HEADER_BUFFER_LEN) { /* Should have topic and pkt id*/ + uint8_t *topic; + uint16_t after_topic; + u8_t bkp; u16_t topic_len = var_hdr_payload[0]; topic_len = (topic_len << 8) + (u16_t)(var_hdr_payload[1]); - uint8_t *topic = var_hdr_payload + 2; - uint16_t after_topic = 2 + topic_len; + topic = var_hdr_payload + 2; + after_topic = 2 + topic_len; /* Check length, add one byte even for QoS 0 so that zero termination will fit */ if((after_topic + qos ? 2 : 1) > length) { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_message_received: Receive buffer can not fit topic + pkt_id\n")); @@ -713,7 +717,7 @@ mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_idx, u16_t length, u client->inpub_pkt_id = 0; } /* Take backup of byte after topic */ - u8_t bkp = topic[topic_len]; + bkp = topic[topic_len]; /* Zero terminate string */ topic[topic_len] = 0; /* Payload data remaining in receive buffer */ @@ -831,7 +835,7 @@ mqtt_parse_incoming(mqtt_client_t *client, struct pbuf *p) cpy_start = (client->msg_idx - fixed_hdr_idx) % (MQTT_VAR_HEADER_BUFFER_LEN - fixed_hdr_idx) + fixed_hdr_idx; /* Allow to copy the lesser one of available length in input data or bytes remaining in message */ - cpy_len = LWIP_MIN((u16_t)(p->tot_len - in_offset), msg_rem_len); + cpy_len = (u16_t)LWIP_MIN((u16_t)(p->tot_len - in_offset), msg_rem_len); /* Limit to available space in buffer */ buffer_space = MQTT_VAR_HEADER_BUFFER_LEN - cpy_start; @@ -883,6 +887,7 @@ mqtt_tcp_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_tcp_recv_cb: Recv pbuf=NULL, remote has closed connection\n")); mqtt_close(client, MQTT_CONNECT_DISCONNECTED); } else { + mqtt_connection_status_t res; if(err != ERR_OK) { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_tcp_recv_cb: Recv err=%d\n", err)); pbuf_free(p); @@ -891,7 +896,7 @@ mqtt_tcp_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) /* Tell remote that data has been received */ tcp_recved(pcb, p->tot_len); - mqtt_connection_status_t res = mqtt_parse_incoming(client, p); + res = mqtt_parse_incoming(client, p); pbuf_free(p); if(res != MQTT_CONNECT_ACCEPTED) { @@ -924,12 +929,12 @@ mqtt_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t len) LWIP_UNUSED_ARG(len); if(client->conn_state == MQTT_CONNECTED) { + struct mqtt_request_t *r; /* Reset keep-alive send timer and server watchdog */ client->cyclic_tick = 0; client->server_watchdog = 0; /* QoS 0 publish has no response from server, so call its callbacks here */ - struct mqtt_request_t *r; while((r = mqtt_take_request(&client->pend_req_queue, 0)) != NULL) { LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_tcp_sent_cb: Calling QoS 0 publish complete callback\n")); if(r->cb != NULL) { @@ -951,14 +956,15 @@ mqtt_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t len) static void mqtt_tcp_err_cb(void *arg, err_t err) { - LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_tcp_err_cb: TCP error callback: error %d, arg: %p\n", err, arg)); mqtt_client_t *client = (mqtt_client_t *)arg; + LWIP_UNUSED_ARG(err); /* only used for debug output */ + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_tcp_err_cb: TCP error callback: error %d, arg: %p\n", err, arg)); LWIP_ASSERT("mqtt_tcp_err_cb: client != NULL", client != NULL); /* Set conn to null before calling close as pcb is already deallocated*/ client->conn = 0; mqtt_close(client, MQTT_CONNECT_DISCONNECTED); - } + /** * TCP poll callback function. @see tcp_poll_fn * @param arg MQTT client @@ -1021,7 +1027,6 @@ mqtt_tcp_connect_cb(void *arg, struct tcp_pcb *tpcb, err_t err) /** - * @ingroup mqtt * MQTT publish function. * @param client MQTT client * @param topic Publish topic string @@ -1041,13 +1046,22 @@ mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_ { struct mqtt_request_t *r; u16_t pkt_id; - u16_t topic_len = strlen(topic); - u16_t remaining_length = 2 + topic_len + payload_length; + size_t topic_strlen; + size_t total_len; + u16_t topic_len; + u16_t remaining_length; LWIP_ASSERT("mqtt_publish: client != NULL", client); LWIP_ASSERT("mqtt_publish: topic != NULL", topic); LWIP_ERROR("mqtt_publish: TCP disconnected", (client->conn_state != TCP_DISCONNECTED), return ERR_CONN); + topic_strlen = strlen(topic); + LWIP_ERROR("mqtt_publish: topic length overflow", (topic_strlen <= (0xFFFF - 2)), return ERR_ARG); + topic_len = (u16_t)topic_strlen; + total_len = 2 + topic_len + payload_length; + LWIP_ERROR("mqtt_publish: total length overflow", (total_len <= 0xFFFF), return ERR_ARG); + remaining_length = (u16_t)total_len; + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_publish: Publish with payload length %d to topic \"%s\"\n", payload_length, topic)); if(qos > 0) { @@ -1104,15 +1118,27 @@ mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_ 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) { - u16_t topic_len = strlen(topic); - /* Topic string, pkt_id, qos for subscribe */ - u16_t remaining_length = topic_len + 2 + 2 + (sub != 0); - - u16_t pkt_id = msg_generate_packet_id(client); - struct mqtt_request_t *r = mqtt_create_request(client->req_list, pkt_id, cb, arg); + size_t topic_strlen; + size_t total_len; + u16_t topic_len; + u16_t remaining_length; + u16_t pkt_id; + struct mqtt_request_t *r; LWIP_ASSERT("mqtt_sub_unsub: client != NULL", client); LWIP_ASSERT("mqtt_sub_unsub: topic != NULL", topic); + + topic_strlen = strlen(topic); + LWIP_ERROR("mqtt_sub_unsub: topic length overflow", (topic_strlen <= (0xFFFF - 2)), return ERR_ARG); + topic_len = (u16_t)topic_strlen; + /* Topic string, pkt_id, qos for subscribe */ + total_len = topic_len + 2 + 2 + (sub != 0); + LWIP_ERROR("mqtt_publish: total length overflow", (total_len <= 0xFFFF), return ERR_ARG); + remaining_length = (u16_t)total_len; + + pkt_id = msg_generate_packet_id(client); + r = mqtt_create_request(client->req_list, pkt_id, cb, arg); + LWIP_ASSERT("mqtt_sub_unsub: qos < 3", qos < 3); if(client->conn_state == TCP_DISCONNECTED) { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_sub_unsub: Can not (un)subscribe in disconnected state\n")); @@ -1196,6 +1222,8 @@ mqtt_client_connect(mqtt_client_t *client, const char *host, mqtt_connection_cb_ { err_t err; ip_addr_t ip_addr; + size_t len; + u16_t client_id_length; u16_t port = 1883; /* Length is the sum of 2+"MQTT", protocol level, flags and keep alive */ u16_t remaining_length = 2 + 4 + 1 + 1 + 2; @@ -1226,18 +1254,29 @@ mqtt_client_connect(mqtt_client_t *client, const char *host, mqtt_connection_cb_ if(client_info->will_topic != NULL && client_info->will_msg != NULL) { flags |= MQTT_CONNECT_FLAG_WILL; flags |= (client_info->will_qos & 3) << 3; - if(client_info->will_retain) + if(client_info->will_retain) { flags |= MQTT_CONNECT_FLAG_WILL_RETAIN; - will_topic_len = strlen(client_info->will_topic); - will_msg_len = strlen(client_info->will_msg); - remaining_length += 2 + will_topic_len + 2 + will_msg_len; + } + len = strlen(client_info->will_topic); + LWIP_ERROR("mqtt_client_connect: client_info->will_topic length overflow", len <= 0xFF, return ERR_VAL); + will_topic_len = (u8_t)len; + len = strlen(client_info->will_msg); + LWIP_ERROR("mqtt_client_connect: client_info->will_msg length overflow", len <= 0xFF, return ERR_VAL); + will_msg_len = (u8_t)len; + len = remaining_length + 2 + will_topic_len + 2 + will_msg_len; + LWIP_ERROR("mqtt_client_connect: remaining_length overflow", len <= 0xFFFF, return ERR_VAL); + remaining_length = (u16_t)len; } /* Don't complicate things, always connect using clean session */ flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION; - u16_t client_id_length = strlen(client_info->client_id); - remaining_length += 2 + client_id_length; + len = strlen(client_info->client_id); + LWIP_ERROR("mqtt_client_connect: client_info->client_id length overflow", len <= 0xFFFF, return ERR_VAL); + client_id_length = (u16_t)len; + len = remaining_length + 2 + client_id_length; + LWIP_ERROR("mqtt_client_connect: remaining_length overflow", len <= 0xFFFF, return ERR_VAL); + remaining_length = (u16_t)len; if(mqtt_output_check_space(&client->output, remaining_length) == 0) { return ERR_MEM; From 02f4610b1cc2f53f2fc1a361512e355cecb89826 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 20 Dec 2016 17:18:39 +0800 Subject: [PATCH 136/184] mqtt: Use LWIP_ARRAYSIZE to replace hardcoded value Signed-off-by: Axel Lin --- src/apps/mqtt/mqtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index 0bc3ab0a..08134116 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -169,7 +169,7 @@ static const char * const mqtt_message_type_str[15] = static const char * mqtt_msg_type_to_str(u8_t msg_type) { - if(msg_type > 14) { + if(msg_type >= LWIP_ARRAYSIZE(mqtt_message_type_str)) { msg_type = 0; } return mqtt_message_type_str[msg_type]; From dcb761637d3e4bdac56b643bdb519bd0f365a7bf Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Tue, 20 Dec 2016 10:42:56 +0100 Subject: [PATCH 137/184] Minor documentation fix in MQTT --- src/apps/mqtt/mqtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index 08134116..b3c29467 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -2,7 +2,7 @@ * @file * MQTT client * - * @defgroup mqtt MQTT Client + * @defgroup mqtt MQTT client * @ingroup apps */ From 16b895b466a064fc3ac9cc3b250b9fcb006e0327 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Tue, 20 Dec 2016 10:48:19 +0100 Subject: [PATCH 138/184] Undo removal of mqtt_publish() from documentation in Simon's last commit (guess it was by accident) --- src/apps/mqtt/mqtt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index b3c29467..c49000e2 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -1027,6 +1027,7 @@ mqtt_tcp_connect_cb(void *arg, struct tcp_pcb *tpcb, err_t err) /** + * @ingroup mqtt * MQTT publish function. * @param client MQTT client * @param topic Publish topic string From be57134810ca44907b0ebe0d55e2eae1a5266e77 Mon Sep 17 00:00:00 2001 From: Thomas Mueller Date: Tue, 20 Dec 2016 14:21:26 +0100 Subject: [PATCH 139/184] Fixed bug #49895: Incorrect configuration detection in lwip/dns.h Signed-off-by: goldsimon --- src/include/lwip/dns.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/lwip/dns.h b/src/include/lwip/dns.h index 3753a53a..2d147afa 100644 --- a/src/include/lwip/dns.h +++ b/src/include/lwip/dns.h @@ -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 From dd96c71253f337a8dc9b956792f549308af38d02 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Mon, 19 Dec 2016 11:52:19 +0100 Subject: [PATCH 140/184] Fix a few -Wconversion warnings (there are many more to do) --- src/core/def.c | 2 +- src/core/ipv4/icmp.c | 8 ++++---- src/core/ipv4/ip4_addr.c | 6 +++--- src/core/ipv6/ip6.c | 2 +- src/core/ipv6/ip6_addr.c | 4 ++-- src/core/netif.c | 2 +- src/core/pbuf.c | 4 ++-- src/core/udp.c | 2 +- src/include/lwip/opt.h | 2 +- src/include/lwip/prot/tcp.h | 2 +- 10 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/core/def.c b/src/core/def.c index bdece2f9..70d3e580 100644 --- a/src/core/def.c +++ b/src/core/def.c @@ -101,7 +101,7 @@ 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 LWIP_CONST_CAST(char *, buffer); } diff --git a/src/core/ipv4/icmp.c b/src/core/ipv4/icmp.c index 6f5311d0..e030ecc9 100644 --- a/src/core/ipv4/icmp.c +++ b/src/core/ipv4/icmp.c @@ -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; diff --git a/src/core/ipv4/ip4_addr.c b/src/core/ipv4/ip4_addr.c index eb812afb..2d479923 100644 --- a/src/core/ipv4/ip4_addr.c +++ b/src/core/ipv4/ip4_addr.c @@ -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) { diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c index f17b6c85..a542a869 100644 --- a/src/core/ipv6/ip6.c +++ b/src/core/ipv6/ip6.c @@ -715,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")); diff --git a/src/core/ipv6/ip6_addr.c b/src/core/ipv6/ip6_addr.c index 964291ee..aa06659a 100644 --- a/src/core/ipv6/ip6_addr.c +++ b/src/core/ipv6/ip6_addr.c @@ -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; diff --git a/src/core/netif.c b/src/core/netif.c index f7211f9a..1d3de0ff 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -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 && diff --git a/src/core/pbuf.c b/src/core/pbuf.c index 52f088d2..60477383 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -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. */ diff --git a/src/core/udp.c b/src/core/udp.c index 52830c4f..a9164149 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -404,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 */ diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 0965e09b..174f9b79 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -1363,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 /** diff --git a/src/include/lwip/prot/tcp.h b/src/include/lwip/prot/tcp.h index c2c03aa4..67fe7b9e 100644 --- a/src/include/lwip/prot/tcp.h +++ b/src/include/lwip/prot/tcp.h @@ -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)) From 876720593b4cd1420b67de20b2114feb612d787e Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Tue, 20 Dec 2016 14:25:46 +0100 Subject: [PATCH 141/184] Update .gitignore once more for fuzz test --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2aa3170e..cb0ed534 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +*.o +*.a /doc/doxygen/output/html /src/apps/snmp/LwipMibCompiler/CCodeGeneration/bin/ /src/apps/snmp/LwipMibCompiler/CCodeGeneration/obj/ @@ -12,4 +14,5 @@ /src/apps/snmp/LwipMibCompiler/LwipMibCompiler.userprefs /src/apps/snmp/LwipMibCompiler/*.suo /test/fuzz/output -/test/lwip_fuzz +/test/fuzz/lwip_fuzz +/test/fuzz/.depend From d5bc856f452da40dddcf09b56ce01dcd75c4faae Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 20 Dec 2016 23:00:57 +0800 Subject: [PATCH 142/184] mqtt: Check conn_state before create request for sub_unsub This also avoid a request leak in client->conn_state == TCP_DISCONNECTED error path. Signed-off-by: Axel Lin --- src/apps/mqtt/mqtt.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index c49000e2..fa2ba8b7 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -1137,15 +1137,14 @@ mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_request_ LWIP_ERROR("mqtt_publish: total length overflow", (total_len <= 0xFFFF), return ERR_ARG); remaining_length = (u16_t)total_len; - pkt_id = msg_generate_packet_id(client); - r = mqtt_create_request(client->req_list, pkt_id, cb, arg); - LWIP_ASSERT("mqtt_sub_unsub: qos < 3", qos < 3); if(client->conn_state == TCP_DISCONNECTED) { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_sub_unsub: Can not (un)subscribe in disconnected state\n")); return ERR_CONN; } + pkt_id = msg_generate_packet_id(client); + r = mqtt_create_request(client->req_list, pkt_id, cb, arg); if(r == NULL) { return ERR_MEM; } From 71810d041524b4d296c0ba2b52f46165928110af Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Fri, 16 Dec 2016 21:26:32 +0000 Subject: [PATCH 143/184] ipv6: adjust MLD membership on address state changes If MLD support is enabled, each locally assigned IPv6 address in the appropriate state must be a member of the solicited-node multicast group corresponding to that address. Ensure that this is always the case by (re-)deciding on the membership upon every address state change. By doing so, this patch enforces that user-initiated state changes to addresses (e.g., deletion) never cause a desynchronization with the corresponding solicited-node multicast group membership, thereby making such user-initiated state changes simpler and safer. --- src/core/ipv6/nd6.c | 47 ++++++++++++++++++++++++++++++------------ src/core/netif.c | 7 +++++++ src/include/lwip/nd6.h | 3 +++ 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index ca7d8e91..23cbf5f3 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -171,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)) { @@ -871,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 */ @@ -2074,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 */ diff --git a/src/core/netif.c b/src/core/netif.c index 1d3de0ff..428b1484 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -1096,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 diff --git a/src/include/lwip/nd6.h b/src/include/lwip/nd6.h index 817dfb9e..8204fa4c 100644 --- a/src/include/lwip/nd6.h +++ b/src/include/lwip/nd6.h @@ -71,6 +71,9 @@ u16_t nd6_get_destination_mtu(const ip6_addr_t *ip6addr, struct netif *netif); 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 } From 24fa1c457e98a6959c9ca90317277d1dec22adb6 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Fri, 16 Dec 2016 21:53:35 +0000 Subject: [PATCH 144/184] opt.h: provide some hints regarding MLD settings --- src/include/lwip/opt.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 174f9b79..f30bd269 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -2245,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 From 5be91de56c6bf32eb987aeebb1afca0fdd6abb69 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 21 Dec 2016 08:49:24 +0800 Subject: [PATCH 145/184] mqtt: Trivial error message fix Fix trivial copy-paste mistake. Signed-off-by: Axel Lin --- src/apps/mqtt/mqtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index fa2ba8b7..11ca6e31 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -1134,7 +1134,7 @@ mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_request_ topic_len = (u16_t)topic_strlen; /* Topic string, pkt_id, qos for subscribe */ total_len = topic_len + 2 + 2 + (sub != 0); - LWIP_ERROR("mqtt_publish: total length overflow", (total_len <= 0xFFFF), return ERR_ARG); + LWIP_ERROR("mqtt_sub_unsub: total length overflow", (total_len <= 0xFFFF), return ERR_ARG); remaining_length = (u16_t)total_len; LWIP_ASSERT("mqtt_sub_unsub: qos < 3", qos < 3); From ec1450bac407d67f0a0a3aeadc42a60df4894652 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 21 Dec 2016 09:29:47 +0100 Subject: [PATCH 146/184] Add mqtt documentation from Erik Anderson, rev 4b84fff --- doc/mqtt_client.txt | 162 +++++++++++++++++++++++++++++++++++++++++++ src/apps/mqtt/mqtt.c | 1 + 2 files changed, 163 insertions(+) create mode 100644 doc/mqtt_client.txt diff --git a/doc/mqtt_client.txt b/doc/mqtt_client.txt new file mode 100644 index 00000000..21e974f7 --- /dev/null +++ b/doc/mqtt_client.txt @@ -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 port number 1883 and MQTT version 3.1.1 is always used */ + + err = mqtt_client_connect(client, "192.168.0.55", 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) diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index 11ca6e31..3e3a8126 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -4,6 +4,7 @@ * * @defgroup mqtt MQTT client * @ingroup apps + * @verbinclude mqtt_client.txt */ /* From 6e219b6b11b43ddadabb7c3ba4032ae9ce5f8d1b Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 21 Dec 2016 09:36:28 +0100 Subject: [PATCH 147/184] Change signature of mqtt_client_connect() to take an IP addr instead of a string --- doc/mqtt_client.txt | 2 +- src/apps/mqtt/mqtt.c | 13 ++++--------- src/include/lwip/apps/mqtt.h | 2 +- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/doc/mqtt_client.txt b/doc/mqtt_client.txt index 21e974f7..eb096a32 100644 --- a/doc/mqtt_client.txt +++ b/doc/mqtt_client.txt @@ -38,7 +38,7 @@ void example_do_connect(mqtt_client_t *client) to establish a connection with the server. For now port number 1883 and MQTT version 3.1.1 is always used */ - err = mqtt_client_connect(client, "192.168.0.55", mqtt_connection_cb, 0, &ci); + err = mqtt_client_connect(client, ip_addr, mqtt_connection_cb, 0, &ci); /* For now just print the result code if something goes wrong if(err != ERR_OK) { diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index 3e3a8126..a8a9cab7 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -1218,11 +1218,10 @@ mqtt_client_new(void) * @return ERR_OK if successful, @see err_t enum for other results */ err_t -mqtt_client_connect(mqtt_client_t *client, const char *host, mqtt_connection_cb_t cb, void *arg, +mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, mqtt_connection_cb_t cb, void *arg, const struct mqtt_connect_client_info_t *client_info) { err_t err; - ip_addr_t ip_addr; size_t len; u16_t client_id_length; u16_t port = 1883; @@ -1231,7 +1230,7 @@ mqtt_client_connect(mqtt_client_t *client, const char *host, mqtt_connection_cb_ u8_t flags = 0, will_topic_len = 0, will_msg_len = 0; LWIP_ASSERT("mqtt_client_connect: client != NULL", client != NULL); - LWIP_ASSERT("mqtt_client_connect: host != NULL", host != NULL); + LWIP_ASSERT("mqtt_client_connect: ip_addr != NULL", ip_addr != NULL); LWIP_ASSERT("mqtt_client_connect: client_info != NULL", client_info != NULL); LWIP_ASSERT("mqtt_client_connect: client_info->client_id != NULL", client_info->client_id != NULL); @@ -1240,10 +1239,6 @@ mqtt_client_connect(mqtt_client_t *client, const char *host, mqtt_connection_cb_ return ERR_ISCONN; } - if(ipaddr_aton(host, &ip_addr) == 0) { - LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Illegal hostname: %s\n", host)); - return ERR_ARG; - } /* Wipe clean */ memset(client, 0, sizeof(mqtt_client_t)); client->connect_arg = arg; @@ -1296,10 +1291,10 @@ mqtt_client_connect(mqtt_client_t *client, const char *host, mqtt_connection_cb_ LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Error binding to local ip/port, %d\n", err)); goto tcp_fail; } - LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Connecting to host: %s at port:%d\n", host, port)); + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Connecting to host: %s at port:%d\n", ipaddr_ntoa(ip_addr), port)); /* Connect to server */ - err = tcp_connect(client->conn, &ip_addr, port, mqtt_tcp_connect_cb); + err = tcp_connect(client->conn, ip_addr, port, mqtt_tcp_connect_cb); if(err != ERR_OK) { LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Error connecting to remote ip/port, %d\n", err)); goto tcp_fail; diff --git a/src/include/lwip/apps/mqtt.h b/src/include/lwip/apps/mqtt.h index f7412f62..a0e48bd7 100644 --- a/src/include/lwip/apps/mqtt.h +++ b/src/include/lwip/apps/mqtt.h @@ -204,7 +204,7 @@ struct mqtt_client_t /** Connect to server */ -err_t mqtt_client_connect(mqtt_client_t *client, const char *host, mqtt_connection_cb_t cb, void *arg, +err_t mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ipaddr, mqtt_connection_cb_t cb, void *arg, const struct mqtt_connect_client_info_t *client_info); /** Disconnect from server */ From 3a557baedd94152bdaba60eb23c7117a463c7f7a Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 21 Dec 2016 09:42:25 +0100 Subject: [PATCH 148/184] Move a few MQTT options from mqtt.c to mqtt_opts.h --- src/apps/mqtt/mqtt.c | 32 +++---------------------------- src/include/lwip/apps/mqtt_opts.h | 28 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index a8a9cab7..a0d4f953 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -69,31 +69,6 @@ #define MQTT_DEBUG_WARN_STATE (MQTT_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE) #define MQTT_DEBUG_SERIOUS (MQTT_DEBUG | LWIP_DBG_LEVEL_SERIOUS) - -/** - * 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 - - static void mqtt_cyclic_timer(void *arg); /** @@ -1211,7 +1186,7 @@ mqtt_client_new(void) * @ingroup mqtt * Connect to MQTT server * @param client MQTT client - * @param host String containing server IP + * @param ip_addr Server IP * @param cb Connection state change callback * @param arg User supplied argument to connection callback * @param client_info Client identification and connection options @@ -1224,7 +1199,6 @@ mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, mqtt_connec err_t err; size_t len; u16_t client_id_length; - u16_t port = 1883; /* Length is the sum of 2+"MQTT", protocol level, flags and keep alive */ u16_t remaining_length = 2 + 4 + 1 + 1 + 2; u8_t flags = 0, will_topic_len = 0, will_msg_len = 0; @@ -1291,10 +1265,10 @@ mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, mqtt_connec LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Error binding to local ip/port, %d\n", err)); goto tcp_fail; } - LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Connecting to host: %s at port:%d\n", ipaddr_ntoa(ip_addr), port)); + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Connecting to host: %s at port:%d\n", ipaddr_ntoa(ip_addr), MQTT_PORT)); /* Connect to server */ - err = tcp_connect(client->conn, ip_addr, port, mqtt_tcp_connect_cb); + err = tcp_connect(client->conn, ip_addr, MQTT_PORT, mqtt_tcp_connect_cb); if(err != ERR_OK) { LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Error connecting to remote ip/port, %d\n", err)); goto tcp_fail; diff --git a/src/include/lwip/apps/mqtt_opts.h b/src/include/lwip/apps/mqtt_opts.h index 028ef7c2..7d7d29d9 100644 --- a/src/include/lwip/apps/mqtt_opts.h +++ b/src/include/lwip/apps/mqtt_opts.h @@ -71,6 +71,34 @@ extern "C" { #define MQTT_REQ_MAX_IN_FLIGHT 4 #endif +/** + * MQTT server port to connect to + */ +#ifndef MQTT_PORT +#define MQTT_PORT 1883 +#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 + /** * @} */ From 4e34851c57c754d2a91aac4b920f094aabd62f5a Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 22 Dec 2016 21:19:53 +0100 Subject: [PATCH 149/184] Fix bug #49914: lwip_sendmsg uses PBUF_REF pbufs Use PBUF_RAM and create private copy of the data --- src/api/sockets.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index 24b3b5fa..e415d087 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -181,7 +181,7 @@ static void sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* #else #define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval #define LWIP_SO_SNDRCVTIMEO_SET(optval, val) do { \ - s32_t loc = (val); \ + u32_t loc = (u32_t)(val); \ ((struct timeval *)(optval))->tv_sec = (loc) / 1000U; \ ((struct timeval *)(optval))->tv_usec = ((loc) % 1000U) * 1000U; }while(0) #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000U) + (((const struct timeval *)(optval))->tv_usec / 1000U)) @@ -1068,14 +1068,15 @@ lwip_sendmsg(int s, const struct msghdr *msg, int flags) /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain manually to avoid having to allocate, chain, and delete a netbuf for each iov */ for (i = 0; i < msg->msg_iovlen; i++) { - struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); + struct pbuf *p; + + LWIP_ASSERT("iov_len < u16_t", msg->msg_iov[i].iov_len <= 0xFFFF); + p = pbuf_alloc(PBUF_TRANSPORT, msg->msg_iov[i].iov_len, PBUF_RAM); if (p == NULL) { err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */ break; } - p->payload = msg->msg_iov[i].iov_base; - LWIP_ASSERT("iov_len < u16_t", msg->msg_iov[i].iov_len <= 0xFFFF); - p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len; + pbuf_take(p, msg->msg_iov[i].iov_base, (u16_t)msg->msg_iov[i].iov_len); /* netbuf empty, add new pbuf */ if (chain_buf->p == NULL) { chain_buf->p = chain_buf->ptr = p; @@ -1467,7 +1468,7 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, /* Wait forever */ msectimeout = 0; } else { - msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); + msectimeout = (u32_t)((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); if (msectimeout == 0) { /* Wait 1ms at least (0 means wait forever) */ msectimeout = 1; From 2e4b368c8ca5766d8bf0d8b3edfde54219d69879 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Fri, 23 Dec 2016 09:51:26 +0100 Subject: [PATCH 150/184] Revert "Fix bug #49914: lwip_sendmsg uses PBUF_REF pbufs" This reverts commit 4e34851c57c754d2a91aac4b920f094aabd62f5a. --- src/api/sockets.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index e415d087..24b3b5fa 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -181,7 +181,7 @@ static void sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* #else #define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval #define LWIP_SO_SNDRCVTIMEO_SET(optval, val) do { \ - u32_t loc = (u32_t)(val); \ + s32_t loc = (val); \ ((struct timeval *)(optval))->tv_sec = (loc) / 1000U; \ ((struct timeval *)(optval))->tv_usec = ((loc) % 1000U) * 1000U; }while(0) #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000U) + (((const struct timeval *)(optval))->tv_usec / 1000U)) @@ -1068,15 +1068,14 @@ lwip_sendmsg(int s, const struct msghdr *msg, int flags) /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain manually to avoid having to allocate, chain, and delete a netbuf for each iov */ for (i = 0; i < msg->msg_iovlen; i++) { - struct pbuf *p; - - LWIP_ASSERT("iov_len < u16_t", msg->msg_iov[i].iov_len <= 0xFFFF); - p = pbuf_alloc(PBUF_TRANSPORT, msg->msg_iov[i].iov_len, PBUF_RAM); + struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); if (p == NULL) { err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */ break; } - pbuf_take(p, msg->msg_iov[i].iov_base, (u16_t)msg->msg_iov[i].iov_len); + p->payload = msg->msg_iov[i].iov_base; + LWIP_ASSERT("iov_len < u16_t", msg->msg_iov[i].iov_len <= 0xFFFF); + p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len; /* netbuf empty, add new pbuf */ if (chain_buf->p == NULL) { chain_buf->p = chain_buf->ptr = p; @@ -1468,7 +1467,7 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, /* Wait forever */ msectimeout = 0; } else { - msectimeout = (u32_t)((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); + msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); if (msectimeout == 0) { /* Wait 1ms at least (0 means wait forever) */ msectimeout = 1; From bfa0358a52e7c8eec3713101e74384e6c5752ecc Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 23 Dec 2016 08:52:28 +0800 Subject: [PATCH 151/184] mqtt: Allow setting server port to connect This is a mqtt client, so it does not make sense to determinate the server port at compile time. Update mqtt_client_connect() function to allow setting server port. Signed-off-by: Axel Lin --- src/apps/mqtt/mqtt.c | 7 ++++--- src/include/lwip/apps/mqtt.h | 2 +- src/include/lwip/apps/mqtt_opts.h | 7 ------- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index a0d4f953..1929a6dc 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -1187,13 +1187,14 @@ mqtt_client_new(void) * Connect to MQTT server * @param client MQTT client * @param ip_addr Server IP + * @param port Server port * @param cb Connection state change callback * @param arg User supplied argument to connection callback * @param client_info Client identification and connection options * @return ERR_OK if successful, @see err_t enum for other results */ err_t -mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, mqtt_connection_cb_t cb, void *arg, +mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, u16_t port, mqtt_connection_cb_t cb, void *arg, const struct mqtt_connect_client_info_t *client_info) { err_t err; @@ -1265,10 +1266,10 @@ mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, mqtt_connec LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Error binding to local ip/port, %d\n", err)); goto tcp_fail; } - LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Connecting to host: %s at port:%d\n", ipaddr_ntoa(ip_addr), MQTT_PORT)); + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Connecting to host: %s at port:%"U16_F"\n", ipaddr_ntoa(ip_addr), port)); /* Connect to server */ - err = tcp_connect(client->conn, ip_addr, MQTT_PORT, mqtt_tcp_connect_cb); + err = tcp_connect(client->conn, ip_addr, port, mqtt_tcp_connect_cb); if(err != ERR_OK) { LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Error connecting to remote ip/port, %d\n", err)); goto tcp_fail; diff --git a/src/include/lwip/apps/mqtt.h b/src/include/lwip/apps/mqtt.h index a0e48bd7..70289903 100644 --- a/src/include/lwip/apps/mqtt.h +++ b/src/include/lwip/apps/mqtt.h @@ -204,7 +204,7 @@ struct mqtt_client_t /** Connect to server */ -err_t mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ipaddr, mqtt_connection_cb_t cb, void *arg, +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 */ diff --git a/src/include/lwip/apps/mqtt_opts.h b/src/include/lwip/apps/mqtt_opts.h index 7d7d29d9..ffefacd2 100644 --- a/src/include/lwip/apps/mqtt_opts.h +++ b/src/include/lwip/apps/mqtt_opts.h @@ -71,13 +71,6 @@ extern "C" { #define MQTT_REQ_MAX_IN_FLIGHT 4 #endif -/** - * MQTT server port to connect to - */ -#ifndef MQTT_PORT -#define MQTT_PORT 1883 -#endif - /** * Seconds between each cyclic timer call. */ From 83b1c397a0d358e0c780feaa8ff393445b74ecec Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Sat, 24 Dec 2016 12:05:27 +0100 Subject: [PATCH 152/184] Add #define with default MQTT port for convenience --- src/include/lwip/apps/mqtt.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/include/lwip/apps/mqtt.h b/src/include/lwip/apps/mqtt.h index 70289903..3d3fcb74 100644 --- a/src/include/lwip/apps/mqtt.h +++ b/src/include/lwip/apps/mqtt.h @@ -46,6 +46,8 @@ extern "C" { typedef struct mqtt_client_t mqtt_client_t; +#define MQTT_PORT 1883 + /*---------------------------------------------------------------------------------------------- */ /* Connection with server */ From c1d16c61ebbe7f24b49b382b2c63f93958bf69c6 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Sat, 24 Dec 2016 12:06:53 +0100 Subject: [PATCH 153/184] Forgot documentation on MQTT port #define --- src/include/lwip/apps/mqtt.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/include/lwip/apps/mqtt.h b/src/include/lwip/apps/mqtt.h index 3d3fcb74..ce8c6ca7 100644 --- a/src/include/lwip/apps/mqtt.h +++ b/src/include/lwip/apps/mqtt.h @@ -46,6 +46,8 @@ extern "C" { typedef struct mqtt_client_t mqtt_client_t; +/** @ingroup mqtt + * Default MQTT port */ #define MQTT_PORT 1883 /*---------------------------------------------------------------------------------------------- */ From 7b40d1eb6fbaa020cc2d1a889fb918c27f88269f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 24 Dec 2016 21:50:16 +0800 Subject: [PATCH 154/184] doc: mqtt_client: Update example code after adding port parameter to mqtt_client_connect() Signed-off-by: Axel Lin --- doc/mqtt_client.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/mqtt_client.txt b/doc/mqtt_client.txt index eb096a32..3e67defd 100644 --- a/doc/mqtt_client.txt +++ b/doc/mqtt_client.txt @@ -36,9 +36,9 @@ void example_do_connect(mqtt_client_t *client) /* 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 port number 1883 and MQTT version 3.1.1 is always used */ + For now MQTT version 3.1.1 is always used */ - err = mqtt_client_connect(client, ip_addr, mqtt_connection_cb, 0, &ci); + 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) { From df365adf9a8970c109e051c4e3309644506b04c2 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Mon, 26 Dec 2016 10:53:41 +0100 Subject: [PATCH 155/184] Trivial typo fix in arch.h docs --- src/include/lwip/arch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index 940ab62a..4e921fc5 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -50,7 +50,7 @@ /** * @defgroup compiler_abstraction Compiler/platform abstraction * @ingroup sys_layer - * All defines related to this section must not be places in lwipopts.h, + * All defines related to this section must not be placed in lwipopts.h, * but in arch/cc.h! * @{ */ From 45ad6f2e61c631fcc1192a1d77e186cc1f1d1933 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 28 Dec 2016 09:53:11 +0100 Subject: [PATCH 156/184] Minor documentation updates in lwip/arch.h --- src/include/lwip/arch.h | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index 4e921fc5..33c4e281 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -56,9 +56,10 @@ */ /** 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. 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. + * include stddef.h header to get size_t. You need to typedef size_t + * by yourself in this case. + * 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). */ @@ -71,9 +72,10 @@ #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. + * the stdint.h header. You need to typedef the generic types listed in + * lwip/arch.h yourself in this case (u8_t, u16_t...). + * 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). */ @@ -94,9 +96,10 @@ 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. + * the inttypes.h header. You need to define the format strings listed in + * lwip/arch.h yourself in this case (X8_F, U16_F...). + * 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). */ @@ -133,7 +136,7 @@ typedef uintptr_t mem_ptr_t; #endif #endif -/** C++ const_cast(val) equivalent to remove constness from a value */ +/** C++ const_cast(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 @@ -154,10 +157,10 @@ typedef uintptr_t mem_ptr_t; * 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 From 55199fc62c6b49233279c3285c47be184e63648e Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 28 Dec 2016 10:14:36 +0100 Subject: [PATCH 157/184] More documentation updates in lwip/arch.h --- src/include/lwip/arch.h | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index 33c4e281..3c056f47 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -52,16 +52,37 @@ * @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. + */ +#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 */ +#ifndef LWIP_PLATFORM_DIAG +#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0) +#endif + +/** Platform specific assertion handling */ +#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) +#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. - * 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). */ #ifndef LWIP_NO_STDDEF_H #define LWIP_NO_STDDEF_H 0 @@ -74,10 +95,6 @@ /** Define this to 1 in arch/cc.h of your port if your compiler does not provide * the stdint.h header. You need to typedef the generic types listed in * lwip/arch.h yourself in this case (u8_t, u16_t...). - * 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). */ #ifndef LWIP_NO_STDINT_H #define LWIP_NO_STDINT_H 0 @@ -98,10 +115,6 @@ typedef uintptr_t mem_ptr_t; /** Define this to 1 in arch/cc.h of your port if your compiler does not provide * the inttypes.h header. You need to define the format strings listed in * lwip/arch.h yourself in this case (X8_F, U16_F...). - * 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). */ #ifndef LWIP_NO_INTTYPES_H #define LWIP_NO_INTTYPES_H 0 @@ -249,7 +262,7 @@ extern "C" { #endif /* PACK_STRUCT_FLD_S */ -/** Eliminates compiler warning about unused arguments. */ +/** Eliminates compiler warning about unused arguments (GCC -Wextra -Wunused). */ #ifndef LWIP_UNUSED_ARG #define LWIP_UNUSED_ARG(x) (void)x #endif /* LWIP_UNUSED_ARG */ From 211a71cf11f4154635480d62b505cb04ca62399d Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 28 Dec 2016 21:52:10 +0100 Subject: [PATCH 158/184] Minor documentation update in lwip/arch.h --- src/include/lwip/arch.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index 3c056f47..8469440d 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -59,6 +59,7 @@ /** 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 From c1258e5c72e626fa3ed7d60004e48036ddcea42b Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 29 Dec 2016 09:05:52 +0100 Subject: [PATCH 159/184] Compile fix in lwip/arch.h "extra tokens at end of #ifndef directive" --- src/include/lwip/arch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index 8469440d..690559a0 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -66,7 +66,7 @@ #endif /** Define random number generator function of your system */ -#ifndef LWIP_RAND() +#ifndef LWIP_RAND #define LWIP_RAND() ((u32_t)rand()) #endif From 3a8368ef045f82fc993602f7bfcced1f302cfaaf Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 29 Dec 2016 09:28:28 +0100 Subject: [PATCH 160/184] Provide struct packing macros on GCC/clang out of the box --- src/include/lwip/arch.h | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index 690559a0..2289c782 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -209,54 +209,58 @@ 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 - * Porting to GCC/clang: Nothing to do. + * 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 - * Porting to GCC/clang: Nothing to do. + * 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 - * Porting to GCC/clang: \#define PACK_STRUCT_STRUCT \_\_attribute\_\_((packed)) + * 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 - * Porting to GCC/clang: Nothing to do. + * 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 */ /** 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 - * Porting to GCC/clang: Nothing to do. + * 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 */ /** 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 - * Porting to GCC/clang: Nothing to do. + * 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) From 1fd69ddee998739b403a8511abc708ec33cd44fe Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 29 Dec 2016 09:28:45 +0100 Subject: [PATCH 161/184] Minor documentation update in def.c --- src/core/def.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/def.c b/src/core/def.c index 70d3e580..8125313f 100644 --- a/src/core/def.c +++ b/src/core/def.c @@ -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. */ /* From 748e2e925b2855681b0db1bc3fa5265efce837a7 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 29 Dec 2016 09:29:24 +0100 Subject: [PATCH 162/184] Create documentation section "porting" and move it under lwIP section (instead of infrastructure) --- src/core/sys.c | 38 ++++++++++++++++++++++++++++++++++++++ src/include/lwip/sys.h | 38 -------------------------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/core/sys.c b/src/core/sys.c index f1777372..7059b4de 100644 --- a/src/core/sys.c +++ b/src/core/sys.c @@ -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" diff --git a/src/include/lwip/sys.h b/src/include/lwip/sys.h index bb06a404..d12bae0f 100644 --- a/src/include/lwip/sys.h +++ b/src/include/lwip/sys.h @@ -34,44 +34,6 @@ * Author: Adam Dunkels */ -/** - * @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 From 1466b7ac619133f53f04447e186e1955d5e131f5 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 29 Dec 2016 09:44:07 +0100 Subject: [PATCH 163/184] Several mqtt documentation fixes found by clang --- src/apps/mqtt/mqtt.c | 8 ++++---- src/include/lwip/apps/mqtt.h | 3 --- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index 1929a6dc..2e4132cb 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -139,7 +139,8 @@ static const char * const mqtt_message_type_str[15] = /** * Message type value to string - * @param msg_type @see mqtt_message_type + * @param msg_type see enum mqtt_message_type + * * @return Control message type text string */ static const char * @@ -447,7 +448,7 @@ mqtt_output_append_string(struct mqtt_ringbuf_t *rb, const char *str, u16_t leng /** * Append fixed header * @param rb Output ring buffer - * @param msg_type @see mqtt_message_type + * @param msg_type see enum mqtt_message_type * @param dup MQTT DUP flag * @param qos MQTT QoS field * @param retain MQTT retain flag @@ -613,7 +614,6 @@ pub_ack_rec_rel_response(mqtt_client_t *client, u8_t msg, u16_t pkt_id, u8_t qos /** * Subscribe response from server - * @param client MQTT client * @param r Matching request * @param result Result code from server */ @@ -629,7 +629,7 @@ mqtt_incomming_suback(struct mqtt_request_t *r, u8_t result) /** * Complete MQTT message received or buffer full * @param client MQTT client - * @param var_hdr_payload Pointer to beginning of variable headers and optional payload + * @param fixed_hdr_idx header index * @param length length received part * @param remaining_length Remaining length of complete message */ diff --git a/src/include/lwip/apps/mqtt.h b/src/include/lwip/apps/mqtt.h index ce8c6ca7..8d7c457e 100644 --- a/src/include/lwip/apps/mqtt.h +++ b/src/include/lwip/apps/mqtt.h @@ -114,7 +114,6 @@ enum { * Function prototype for MQTT incoming publish data callback function. Called when data * arrives to a subscribed topic @see mqtt_subscribe * - * @param client MQTT client itself * @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 @@ -130,11 +129,9 @@ typedef void (*mqtt_incoming_data_cb_t)(void *arg, const u8_t *data, u16_t len, * Function prototype for MQTT incoming publish function. Called when an incoming publish * arrives to a subscribed topic @see mqtt_subscribe * - * @param client MQTT client itself * @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 - * @return Optional numerical topic identifier to be used in data callback */ typedef void (*mqtt_incoming_publish_cb_t)(void *arg, const char *topic, u32_t tot_len); From 1884c7e83f687266059ece7492733675a09a2695 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Sat, 31 Dec 2016 11:46:27 +0100 Subject: [PATCH 164/184] Fix TCP unit tests after changes from "Add hook for TCP Initial Sequence Number generation" commit (pcb->lastack and friends are not initialized during allocation any more, but by connect() / bind() call) --- test/unit/tcp/tcp_helper.c | 9 +++++++++ test/unit/tcp/test_tcp.c | 2 -- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/test/unit/tcp/tcp_helper.c b/test/unit/tcp/tcp_helper.c index fc7e67f8..aa7c84a9 100644 --- a/test/unit/tcp/tcp_helper.c +++ b/test/unit/tcp/tcp_helper.c @@ -141,9 +141,18 @@ void tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, ip_addr_t* local_ip, ip_addr_t* remote_ip, u16_t local_port, u16_t remote_port) { + u32_t iss; + /* @todo: are these all states? */ /* @todo: remove from previous list */ pcb->state = state; + + iss = tcp_next_iss(pcb); + pcb->snd_wl2 = iss; + pcb->snd_nxt = iss; + pcb->lastack = iss; + pcb->snd_lbb = iss; + if (state == ESTABLISHED) { TCP_REG(&tcp_active_pcbs, pcb); pcb->local_ip.addr = local_ip->addr; diff --git a/test/unit/tcp/test_tcp.c b/test/unit/tcp/test_tcp.c index 81953466..1e5ef03d 100644 --- a/test/unit/tcp/test_tcp.c +++ b/test/unit/tcp/test_tcp.c @@ -418,7 +418,6 @@ START_TEST(test_tcp_fast_rexmit_wraparound) tcp_ticks = SEQNO1 - ISS; pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); - EXPECT(pcb->lastack == SEQNO1); tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); pcb->mss = TCP_MSS; /* disable initial congestion window (we don't send a SYN here...) */ @@ -517,7 +516,6 @@ START_TEST(test_tcp_rto_rexmit_wraparound) tcp_ticks = SEQNO1 - tcp_next_iss(NULL); pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); - EXPECT(pcb->lastack == SEQNO1); tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); pcb->mss = TCP_MSS; /* disable initial congestion window (we don't send a SYN here...) */ From 98fc82fa7128fabc9f592447cc1d60269b76ffa8 Mon Sep 17 00:00:00 2001 From: sg Date: Sat, 31 Dec 2016 15:36:31 +0100 Subject: [PATCH 165/184] added function tcp_listen_with_backlog_and_err() to get the error reason when listening fails (bug #49861) --- CHANGELOG | 6 +++++- src/api/api_msg.c | 15 ++++++++------ src/core/tcp.c | 44 ++++++++++++++++++++++++++++++++++++------ src/include/lwip/tcp.h | 1 + 4 files changed, 53 insertions(+), 13 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4371f02e..051f7ae4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,8 +6,12 @@ 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) + * 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() diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 10092285..4927ee50 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -1307,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 @@ -1319,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)) { diff --git a/src/core/tcp.c b/src/core/tcp.c index f72597bb..63e44457 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -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,16 @@ 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; + 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 +718,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; } diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index 35584b45..3fd44678 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -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) From a2a16d419353fcd60bb3c660ea6d4399f1b3ae92 Mon Sep 17 00:00:00 2001 From: sg Date: Sat, 31 Dec 2016 15:51:59 +0100 Subject: [PATCH 166/184] nd6 rdnss: fixed dual-stack compilation --- src/core/ipv6/nd6.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 23cbf5f3..7d7a9570 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -546,10 +546,10 @@ nd6_input(struct pbuf *p, struct netif *inp) rdnss_opt = (struct rdnss_option *)buffer; num = (rdnss_opt->length - 1) / 2; for (n = 0; (rdnss_server_idx < DNS_MAX_SERVERS) && (n < num); n++) { - ip6_addr_t rdnss_address; + ip_addr_t rdnss_address; /* Get a memory-aligned copy of the prefix. */ - ip6_addr_set(&rdnss_address, &(rdnss_opt->rdnss_address[n])); + ip_addr_copy_from_ip6(rdnss_address, rdnss_opt->rdnss_address[n]); if (htonl(rdnss_opt->lifetime) > 0) { /* TODO implement Lifetime > 0 */ From ee034bd811b542551fbf840c1a500f91d16bad08 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Sun, 1 Jan 2017 12:31:02 +0100 Subject: [PATCH 167/184] Document PACK_STRUCT_USE_INCLUDES #define --- src/include/lwip/arch.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index 2289c782..d8b13a57 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -266,6 +266,17 @@ extern "C" { #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 From f874d15185247b73578ace434b462ff422d510f7 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Sun, 1 Jan 2017 12:38:34 +0100 Subject: [PATCH 168/184] Add #include in snmp_netconn.c because memset() is used --- src/apps/snmp/snmp_netconn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/apps/snmp/snmp_netconn.c b/src/apps/snmp/snmp_netconn.c index 27c004df..24c3e265 100644 --- a/src/apps/snmp/snmp_netconn.c +++ b/src/apps/snmp/snmp_netconn.c @@ -36,6 +36,7 @@ #if LWIP_SNMP && SNMP_USE_NETCONN +#include #include "lwip/api.h" #include "lwip/ip.h" #include "lwip/udp.h" From b8bc7b7c7159485aa3e0ae917435323b9fed4d29 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Sun, 1 Jan 2017 12:40:23 +0100 Subject: [PATCH 169/184] arch.h: Add #includes necessary for default implentation of LWIP_PLATFORM_DIAG and LWIP_PLATFORM_ASSERT --- src/include/lwip/arch.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index d8b13a57..447d90bb 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -73,12 +73,16 @@ /** Platform specific diagnostic output */ #ifndef LWIP_PLATFORM_DIAG #define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0) +#include +#include #endif /** Platform specific assertion handling */ #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 +#include #endif /** Define this to 1 in arch/cc.h of your port if you do not want to From edfeab7932070f71e25f4e680660843a307702c8 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 1 Jan 2017 22:06:13 +0800 Subject: [PATCH 170/184] mqtt: Trivial coding style fix Add proper blank for if/for/while statements. Signed-off-by: Axel Lin --- src/apps/mqtt/mqtt.c | 194 +++++++++++++++++++++---------------------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index 2e4132cb..da70967d 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -146,7 +146,7 @@ static const char * const mqtt_message_type_str[15] = static const char * mqtt_msg_type_to_str(u8_t msg_type) { - if(msg_type >= LWIP_ARRAYSIZE(mqtt_message_type_str)) { + if (msg_type >= LWIP_ARRAYSIZE(mqtt_message_type_str)) { msg_type = 0; } return mqtt_message_type_str[msg_type]; @@ -164,7 +164,7 @@ static u16_t msg_generate_packet_id(mqtt_client_t *client) { client->pkt_id_seq++; - if(client->pkt_id_seq == 0) { + if (client->pkt_id_seq == 0) { client->pkt_id_seq++; } return client->pkt_id_seq; @@ -208,28 +208,28 @@ mqtt_output_send(struct mqtt_ringbuf_t *rb, struct tcp_pcb *tpcb) u16_t send_len = tcp_sndbuf(tpcb); LWIP_ASSERT("mqtt_output_send: tpcb != NULL", tpcb != NULL); - if(send_len == 0 || ringbuf_lin_len == 0) { + if (send_len == 0 || ringbuf_lin_len == 0) { return; } LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_output_send: tcp_sndbuf: %d bytes, ringbuf_linear_available: %d, get %d, put %d\n", send_len, ringbuf_lin_len, ((rb)->get & MQTT_RINGBUF_IDX_MASK), ((rb)->put & MQTT_RINGBUF_IDX_MASK))); - if(send_len > ringbuf_lin_len) { + if (send_len > ringbuf_lin_len) { /* Space in TCP output buffer is larger than available in ring buffer linear portion */ send_len = ringbuf_lin_len; /* Wrap around if more data in ring buffer after linear portion */ wrap = (mqtt_ringbuf_len(rb) > ringbuf_lin_len); } err = tcp_write(tpcb, mqtt_ringbuf_get_ptr(rb), send_len, TCP_WRITE_FLAG_COPY | (wrap ? TCP_WRITE_FLAG_MORE : 0)); - if((err == ERR_OK) && wrap) { + if ((err == ERR_OK) && wrap) { mqtt_ringbuf_advance_get_idx(rb, send_len); /* Use the lesser one of ring buffer linear length and TCP send buffer size */ send_len = LWIP_MIN(tcp_sndbuf(tpcb), mqtt_ringbuf_linear_read_length(rb)); err = tcp_write(tpcb, mqtt_ringbuf_get_ptr(rb), send_len, TCP_WRITE_FLAG_COPY); } - if(err == ERR_OK) { + if (err == ERR_OK) { mqtt_ringbuf_advance_get_idx(rb, send_len); /* Flush */ tcp_output(tpcb); @@ -257,9 +257,9 @@ mqtt_create_request(struct mqtt_request_t *r_objs, u16_t pkt_id, mqtt_request_cb struct mqtt_request_t *r = NULL; u8_t n; LWIP_ASSERT("mqtt_create_request: r_objs != NULL", r_objs != NULL); - for(n = 0; n < MQTT_REQ_MAX_IN_FLIGHT && r == NULL; n++) { + for (n = 0; n < MQTT_REQ_MAX_IN_FLIGHT && r == NULL; n++) { /* Item point to itself if not in use */ - if(r_objs[n].next == &r_objs[n]) { + if (r_objs[n].next == &r_objs[n]) { r = &r_objs[n]; r->next = NULL; r->cb = cb; @@ -286,14 +286,14 @@ mqtt_append_request(struct mqtt_request_t **tail, struct mqtt_request_t *r) LWIP_ASSERT("mqtt_append_request: tail != NULL", tail != NULL); /* Iterate trough queue to find head, and count total timeout time */ - for(iter = *tail; iter != NULL; iter = iter->next) { + for (iter = *tail; iter != NULL; iter = iter->next) { time_before += iter->timeout_diff; head = iter; } LWIP_ASSERT("mqtt_append_request: time_before <= MQTT_REQ_TIMEOUT", time_before <= MQTT_REQ_TIMEOUT); r->timeout_diff = MQTT_REQ_TIMEOUT - time_before; - if(head == NULL) { + if (head == NULL) { *tail = r; } else { head->next = r; @@ -308,7 +308,7 @@ mqtt_append_request(struct mqtt_request_t **tail, struct mqtt_request_t *r) static void mqtt_delete_request(struct mqtt_request_t *r) { - if(r != NULL) { + if (r != NULL) { r->next = r; } } @@ -325,23 +325,23 @@ mqtt_take_request(struct mqtt_request_t **tail, u16_t pkt_id) struct mqtt_request_t *iter = NULL, *prev = NULL; LWIP_ASSERT("mqtt_take_request: tail != NULL", tail != NULL); /* Search all request for pkt_id */ - for(iter = *tail; iter != NULL; iter = iter->next) { - if(iter->pkt_id == pkt_id) { + for (iter = *tail; iter != NULL; iter = iter->next) { + if (iter->pkt_id == pkt_id) { break; } prev = iter; } /* If request was found */ - if(iter != NULL) { + if (iter != NULL) { /* unchain */ - if(prev == NULL) { + if (prev == NULL) { *tail= iter->next; } else { prev->next = iter->next; } /* If exists, add remaining timeout time for the request to next */ - if(iter->next != NULL) { + if (iter->next != NULL) { iter->next->timeout_diff += iter->timeout_diff; } iter->next = NULL; @@ -359,13 +359,13 @@ mqtt_request_time_elapsed(struct mqtt_request_t **tail, u8_t t) { struct mqtt_request_t *r = *tail; LWIP_ASSERT("mqtt_request_time_elapsed: tail != NULL", tail != NULL); - while(t > 0 && r != NULL) { - if(t >= r->timeout_diff) { + while (t > 0 && r != NULL) { + if (t >= r->timeout_diff) { t -= (u8_t)r->timeout_diff; /* Unchain */ *tail = r->next; /* Notify upper layer about timeout */ - if(r->cb != NULL) { + if (r->cb != NULL) { r->cb(r->arg, ERR_TIMEOUT); } mqtt_delete_request(r); @@ -387,7 +387,7 @@ mqtt_clear_requests(struct mqtt_request_t **tail) { struct mqtt_request_t *iter, *next; LWIP_ASSERT("mqtt_clear_requests: tail != NULL", tail != NULL); - for(iter = *tail; iter != NULL; iter = next) { + for (iter = *tail; iter != NULL; iter = next) { next = iter->next; mqtt_delete_request(iter); } @@ -402,7 +402,7 @@ mqtt_init_requests(struct mqtt_request_t *r_objs) { u8_t n; LWIP_ASSERT("mqtt_init_requests: r_objs != NULL", r_objs != NULL); - for(n = 0; n < MQTT_REQ_MAX_IN_FLIGHT; n++) { + for (n = 0; n < MQTT_REQ_MAX_IN_FLIGHT; n++) { /* Item pointing to itself indicates unused */ r_objs[n].next = &r_objs[n]; } @@ -429,7 +429,7 @@ static void mqtt_output_append_buf(struct mqtt_ringbuf_t *rb, const void *data, u16_t length) { u16_t n; - for(n=0; n < length; n++) { + for (n = 0; n < length; n++) { mqtt_ringbuf_put(rb, ((const u8_t *)data)[n]); } } @@ -440,7 +440,7 @@ mqtt_output_append_string(struct mqtt_ringbuf_t *rb, const char *str, u16_t leng u16_t n; mqtt_ringbuf_put(rb, length >> 8); mqtt_ringbuf_put(rb, length & 0xff); - for(n=0; n < length; n++) { + for (n = 0; n < length; n++) { mqtt_ringbuf_put(rb, str[n]); } } @@ -465,7 +465,7 @@ mqtt_output_append_fixed_header(struct mqtt_ringbuf_t *rb, u8_t msg_type, u8_t d do { mqtt_output_append_u8(rb, (r_length & 0x7f) | (r_length >= 128 ? 0x80 : 0)); r_length >>= 7; - } while(r_length > 0); + } while (r_length > 0); } @@ -487,7 +487,7 @@ mqtt_output_check_space(struct mqtt_ringbuf_t *rb, u16_t r_length) do { total_len++; r_length >>= 7; - } while(r_length > 0); + } while (r_length > 0); return (total_len <= mqtt_ringbuf_free(rb)); } @@ -504,13 +504,13 @@ mqtt_close(mqtt_client_t *client, mqtt_connection_status_t reason) LWIP_ASSERT("mqtt_close: client != NULL", client != NULL); /* Bring down TCP connection if not already done */ - if(client->conn != NULL) { + if (client->conn != NULL) { err_t res; tcp_recv(client->conn, NULL); tcp_err(client->conn, NULL); tcp_sent(client->conn, NULL); res = tcp_close(client->conn); - if(res != ERR_OK) { + if (res != ERR_OK) { tcp_abort(client->conn); LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_close: Close err=%s\n", lwip_strerr(res))); } @@ -523,10 +523,10 @@ mqtt_close(mqtt_client_t *client, mqtt_connection_status_t reason) sys_untimeout(mqtt_cyclic_timer, client); /* Notify upper layer of disconnection if changed state */ - if(client->conn_state != TCP_DISCONNECTED) { + if (client->conn_state != TCP_DISCONNECTED) { client->conn_state = TCP_DISCONNECTED; - if(client->connect_cb != NULL) { + if (client->connect_cb != NULL) { client->connect_cb(client, client->connect_arg, reason); } } @@ -544,33 +544,33 @@ mqtt_cyclic_timer(void *arg) mqtt_client_t *client = (mqtt_client_t *)arg; LWIP_ASSERT("mqtt_cyclic_timer: client != NULL", client != NULL); - if(client->conn_state == MQTT_CONNECTING) { + if (client->conn_state == MQTT_CONNECTING) { client->cyclic_tick++; - if((client->cyclic_tick * MQTT_CYCLIC_TIMER_INTERVAL) >= MQTT_CONNECT_TIMOUT) { + if ((client->cyclic_tick * MQTT_CYCLIC_TIMER_INTERVAL) >= MQTT_CONNECT_TIMOUT) { LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_cyclic_timer: CONNECT attempt to server timed out\n")); /* Disconnect TCP */ mqtt_close(client, MQTT_CONNECT_TIMEOUT); restart_timer = 0; } - } else if(client->conn_state == MQTT_CONNECTED) { + } else if (client->conn_state == MQTT_CONNECTED) { /* Handle timeout for pending requests */ mqtt_request_time_elapsed(&client->pend_req_queue, MQTT_CYCLIC_TIMER_INTERVAL); /* keep_alive > 0 means keep alive functionality shall be used */ - if(client->keep_alive > 0) { + if (client->keep_alive > 0) { client->server_watchdog++; /* If reception from server has been idle for 1.5*keep_alive time, server is considered unresponsive */ - if((client->server_watchdog * MQTT_CYCLIC_TIMER_INTERVAL) > (client->keep_alive + client->keep_alive/2)) { + if ((client->server_watchdog * MQTT_CYCLIC_TIMER_INTERVAL) > (client->keep_alive + client->keep_alive/2)) { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_cyclic_timer: Server incoming keep-alive timeout\n")); mqtt_close(client, MQTT_CONNECT_TIMEOUT); restart_timer = 0; } /* If time for a keep alive message to be sent, transmission has been idle for keep_alive time */ - if((client->cyclic_tick * MQTT_CYCLIC_TIMER_INTERVAL) >= client->keep_alive) { + if ((client->cyclic_tick * MQTT_CYCLIC_TIMER_INTERVAL) >= client->keep_alive) { LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_cyclic_timer: Sending keep-alive message to server\n")); - if(mqtt_output_check_space(&client->output, 0) != 0) { + if (mqtt_output_check_space(&client->output, 0) != 0) { mqtt_output_append_fixed_header(&client->output, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0, 0); client->cyclic_tick = 0; } @@ -582,7 +582,7 @@ mqtt_cyclic_timer(void *arg) LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_cyclic_timer: Timer should not be running in state %d\n", client->conn_state)); restart_timer = 0; } - if(restart_timer) { + if (restart_timer) { sys_timeout(MQTT_CYCLIC_TIMER_INTERVAL*1000, mqtt_cyclic_timer, arg); } } @@ -600,7 +600,7 @@ static err_t pub_ack_rec_rel_response(mqtt_client_t *client, u8_t msg, u16_t pkt_id, u8_t qos) { err_t err = ERR_OK; - if(mqtt_output_check_space(&client->output, 2)) { + if (mqtt_output_check_space(&client->output, 2)) { mqtt_output_append_fixed_header(&client->output, msg, 0, qos, 0, 2); mqtt_output_append_u16(&client->output, pkt_id); mqtt_output_send(&client->output, client->conn); @@ -620,7 +620,7 @@ pub_ack_rec_rel_response(mqtt_client_t *client, u8_t msg, u16_t pkt_id, u8_t qos static void mqtt_incomming_suback(struct mqtt_request_t *r, u8_t result) { - if(r->cb != NULL) { + if (r->cb != NULL) { r->cb(r->arg, result < 3 ? ERR_OK : ERR_ABRT); } } @@ -644,32 +644,32 @@ mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_idx, u16_t length, u u8_t pkt_type = MQTT_CTL_PACKET_TYPE(client->rx_buffer[0]); u16_t pkt_id = 0; - if(pkt_type == MQTT_MSG_TYPE_CONNACK) { - if(client->conn_state == MQTT_CONNECTING) { + if (pkt_type == MQTT_MSG_TYPE_CONNACK) { + if (client->conn_state == MQTT_CONNECTING) { /* Get result code from CONNACK */ res = (mqtt_connection_status_t)var_hdr_payload[1]; LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_message_received: Connect response code %d\n", res)); - if(res == MQTT_CONNECT_ACCEPTED) { + if (res == MQTT_CONNECT_ACCEPTED) { /* Reset cyclic_tick when changing to connected state */ client->cyclic_tick = 0; client->conn_state = MQTT_CONNECTED; /* Notify upper layer */ - if(client->connect_cb != 0) { + if (client->connect_cb != 0) { client->connect_cb(client, client->connect_arg, res); } } } else { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_message_received: Received CONNACK in connected state\n")); } - } else if(pkt_type == MQTT_MSG_TYPE_PINGRESP) { + } else if (pkt_type == MQTT_MSG_TYPE_PINGRESP) { LWIP_DEBUGF(MQTT_DEBUG_TRACE,( "mqtt_message_received: Received PINGRESP from server\n")); - } else if(pkt_type == MQTT_MSG_TYPE_PUBLISH) { + } else if (pkt_type == MQTT_MSG_TYPE_PUBLISH) { u16_t payload_offset = 0; u16_t payload_length = length; u8_t qos = MQTT_CTL_PACKET_QOS(client->rx_buffer[0]); - if(client->msg_idx <= MQTT_VAR_HEADER_BUFFER_LEN) { + if (client->msg_idx <= MQTT_VAR_HEADER_BUFFER_LEN) { /* Should have topic and pkt id*/ uint8_t *topic; uint16_t after_topic; @@ -680,13 +680,13 @@ mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_idx, u16_t length, u topic = var_hdr_payload + 2; after_topic = 2 + topic_len; /* Check length, add one byte even for QoS 0 so that zero termination will fit */ - if((after_topic + qos ? 2 : 1) > length) { + if ((after_topic + qos ? 2 : 1) > length) { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_message_received: Receive buffer can not fit topic + pkt_id\n")); goto out_disconnect; } /* id for QoS 1 and 2 */ - if(qos > 0) { + if (qos > 0) { client->inpub_pkt_id = ((u16_t)var_hdr_payload[after_topic] << 8) + (u16_t)var_hdr_payload[after_topic + 1]; after_topic += 2; } else { @@ -702,16 +702,16 @@ mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_idx, u16_t length, u LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_incomming_publish: Received message with QoS %d at topic: %s, payload length %d\n", qos, topic, remaining_length + payload_length)); - if(client->pub_cb != NULL) { + if (client->pub_cb != NULL) { client->pub_cb(client->inpub_arg, (const char *)topic, remaining_length + payload_length); } /* Restore byte after topic */ topic[topic_len] = bkp; } - if(payload_length > 0 || remaining_length == 0) { + if (payload_length > 0 || remaining_length == 0) { client->data_cb(client->inpub_arg, var_hdr_payload + payload_offset, payload_length, remaining_length == 0 ? MQTT_DATA_FLAG_LAST : 0); /* Reply if QoS > 0 */ - if(remaining_length == 0 && qos > 0) { + if (remaining_length == 0 && qos > 0) { /* Send PUBACK for QoS 1 or PUBREC for QoS 2 */ u8_t resp_msg = (qos == 1) ? MQTT_MSG_TYPE_PUBACK : MQTT_MSG_TYPE_PUBREC; LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_incomming_publish: Sending publish response: %s with pkt_id: %d\n", @@ -723,31 +723,31 @@ mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_idx, u16_t length, u /* Get packet identifier */ pkt_id = (u16_t)var_hdr_payload[0] << 8; pkt_id |= (u16_t)var_hdr_payload[1]; - if(pkt_id == 0) { + if (pkt_id == 0) { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_message_received: Got message with illegal packet identifier: 0\n")); goto out_disconnect; } - if(pkt_type == MQTT_MSG_TYPE_PUBREC) { + if (pkt_type == MQTT_MSG_TYPE_PUBREC) { LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_message_received: PUBREC, sending PUBREL with pkt_id: %d\n",pkt_id)); pub_ack_rec_rel_response(client, MQTT_MSG_TYPE_PUBREL, pkt_id, 1); - } else if(pkt_type == MQTT_MSG_TYPE_PUBREL) { + } else if (pkt_type == MQTT_MSG_TYPE_PUBREL) { LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_message_received: PUBREL, sending PUBCOMP response with pkt_id: %d\n",pkt_id)); pub_ack_rec_rel_response(client, MQTT_MSG_TYPE_PUBCOMP, pkt_id, 0); - } else if(pkt_type == MQTT_MSG_TYPE_SUBACK || pkt_type == MQTT_MSG_TYPE_UNSUBACK || + } else if (pkt_type == MQTT_MSG_TYPE_SUBACK || pkt_type == MQTT_MSG_TYPE_UNSUBACK || pkt_type == MQTT_MSG_TYPE_PUBCOMP || pkt_type == MQTT_MSG_TYPE_PUBACK) { struct mqtt_request_t *r = mqtt_take_request(&client->pend_req_queue, pkt_id); - if(r != NULL) { + if (r != NULL) { LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_message_received: %s response with id %d\n", mqtt_msg_type_to_str(pkt_type), pkt_id)); - if(pkt_type == MQTT_MSG_TYPE_SUBACK) { - if(length < 3) { + if (pkt_type == MQTT_MSG_TYPE_SUBACK) { + if (length < 3) { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_message_received: To small SUBACK packet\n")); goto out_disconnect; } else { mqtt_incomming_suback(r, var_hdr_payload[2]); } - } else if(r->cb != NULL) { + } else if (r->cb != NULL) { r->cb(r->arg, ERR_OK); } mqtt_delete_request(r); @@ -779,10 +779,10 @@ mqtt_parse_incoming(mqtt_client_t *client, struct pbuf *p) u8_t fixed_hdr_idx = 0; u8_t b = 0; - while(p->tot_len > in_offset) { - if((fixed_hdr_idx < 2) || ((b & 0x80) != 0)) { + while (p->tot_len > in_offset) { + if ((fixed_hdr_idx < 2) || ((b & 0x80) != 0)) { - if(fixed_hdr_idx < client->msg_idx) { + if (fixed_hdr_idx < client->msg_idx) { b = client->rx_buffer[fixed_hdr_idx]; } else { b = pbuf_get_at(p, in_offset++); @@ -790,11 +790,11 @@ mqtt_parse_incoming(mqtt_client_t *client, struct pbuf *p) } fixed_hdr_idx++; - if(fixed_hdr_idx >= 2) { + if (fixed_hdr_idx >= 2) { msg_rem_len |= (u32_t)(b & 0x7f) << ((fixed_hdr_idx - 2) * 7); - if((b & 0x80) == 0) { + if ((b & 0x80) == 0) { LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_parse_incoming: Remaining length after fixed header: %d\n", msg_rem_len)); - if(msg_rem_len == 0) { + if (msg_rem_len == 0) { /* Complete message with no extra headers of payload received */ mqtt_message_received(client, fixed_hdr_idx, 0, 0); client->msg_idx = 0; @@ -815,7 +815,7 @@ mqtt_parse_incoming(mqtt_client_t *client, struct pbuf *p) /* Limit to available space in buffer */ buffer_space = MQTT_VAR_HEADER_BUFFER_LEN - cpy_start; - if(cpy_len > buffer_space) { + if (cpy_len > buffer_space) { cpy_len = buffer_space; } pbuf_copy_partial(p, client->rx_buffer+cpy_start, cpy_len, in_offset); @@ -826,13 +826,13 @@ mqtt_parse_incoming(mqtt_client_t *client, struct pbuf *p) msg_rem_len -= cpy_len; LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_parse_incoming: msg_idx: %d, cpy_len: %d, remaining %d\n", client->msg_idx, cpy_len, msg_rem_len)); - if(msg_rem_len == 0 || cpy_len == buffer_space) { + if (msg_rem_len == 0 || cpy_len == buffer_space) { /* Whole message received or buffer is full */ mqtt_connection_status_t res = mqtt_message_received(client, fixed_hdr_idx, (cpy_start + cpy_len) - fixed_hdr_idx, msg_rem_len); - if(res != MQTT_CONNECT_ACCEPTED) { + if (res != MQTT_CONNECT_ACCEPTED) { return res; } - if(msg_rem_len == 0) { + if (msg_rem_len == 0) { /* Reset parser state */ client->msg_idx = 0; //msg_tot_len = 0; @@ -859,12 +859,12 @@ mqtt_tcp_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) LWIP_ASSERT("mqtt_tcp_recv_cb: client != NULL", client != NULL); LWIP_ASSERT("mqtt_tcp_recv_cb: client->conn == pcb", client->conn == pcb); - if(p == NULL) { + if (p == NULL) { LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_tcp_recv_cb: Recv pbuf=NULL, remote has closed connection\n")); mqtt_close(client, MQTT_CONNECT_DISCONNECTED); } else { mqtt_connection_status_t res; - if(err != ERR_OK) { + if (err != ERR_OK) { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_tcp_recv_cb: Recv err=%d\n", err)); pbuf_free(p); return err; @@ -875,11 +875,11 @@ mqtt_tcp_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) res = mqtt_parse_incoming(client, p); pbuf_free(p); - if(res != MQTT_CONNECT_ACCEPTED) { + if (res != MQTT_CONNECT_ACCEPTED) { mqtt_close(client, res); } /* If keep alive functionality is used */ - if(client->keep_alive != 0) { + if (client->keep_alive != 0) { /* Reset server alive watchdog */ client->server_watchdog = 0; } @@ -904,16 +904,16 @@ mqtt_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t len) LWIP_UNUSED_ARG(tpcb); LWIP_UNUSED_ARG(len); - if(client->conn_state == MQTT_CONNECTED) { + if (client->conn_state == MQTT_CONNECTED) { struct mqtt_request_t *r; /* Reset keep-alive send timer and server watchdog */ client->cyclic_tick = 0; client->server_watchdog = 0; /* QoS 0 publish has no response from server, so call its callbacks here */ - while((r = mqtt_take_request(&client->pend_req_queue, 0)) != NULL) { + while ((r = mqtt_take_request(&client->pend_req_queue, 0)) != NULL) { LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_tcp_sent_cb: Calling QoS 0 publish complete callback\n")); - if(r->cb != NULL) { + if (r->cb != NULL) { r->cb(r->arg, ERR_OK); } mqtt_delete_request(r); @@ -951,7 +951,7 @@ static err_t mqtt_tcp_poll_cb(void *arg, struct tcp_pcb *tpcb) { mqtt_client_t *client = (mqtt_client_t *)arg; - if(client->conn_state == MQTT_CONNECTED) { + if (client->conn_state == MQTT_CONNECTED) { /* Try send any remaining buffers from output queue */ mqtt_output_send(&client->output, tpcb); } @@ -969,7 +969,7 @@ mqtt_tcp_connect_cb(void *arg, struct tcp_pcb *tpcb, err_t err) { mqtt_client_t* client = (mqtt_client_t *)arg; - if(err != ERR_OK) { + if (err != ERR_OK) { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_tcp_connect_cb: TCP connect error %d\n", err)); return err; } @@ -1041,7 +1041,7 @@ mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_ LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_publish: Publish with payload length %d to topic \"%s\"\n", payload_length, topic)); - if(qos > 0) { + if (qos > 0) { remaining_length += 2; /* Generate pkt_id id for QoS1 and 2 */ pkt_id = msg_generate_packet_id(client); @@ -1051,11 +1051,11 @@ mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_ } r = mqtt_create_request(client->req_list, pkt_id, cb, arg); - if(r == NULL) { + if (r == NULL) { return ERR_MEM; } - if(mqtt_output_check_space(&client->output, remaining_length) == 0) { + if (mqtt_output_check_space(&client->output, remaining_length) == 0) { mqtt_delete_request(r); return ERR_MEM; } @@ -1066,12 +1066,12 @@ mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_ mqtt_output_append_string(&client->output, topic, topic_len); /* Append packet if for QoS 1 and 2*/ - if(qos > 0) { + if (qos > 0) { mqtt_output_append_u16(&client->output, pkt_id); } /* Append optional publish payload */ - if((payload != NULL) && (payload_length > 0)) { + if ((payload != NULL) && (payload_length > 0)) { mqtt_output_append_buf(&client->output, payload, payload_length); } @@ -1114,18 +1114,18 @@ mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_request_ remaining_length = (u16_t)total_len; LWIP_ASSERT("mqtt_sub_unsub: qos < 3", qos < 3); - if(client->conn_state == TCP_DISCONNECTED) { + if (client->conn_state == TCP_DISCONNECTED) { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_sub_unsub: Can not (un)subscribe in disconnected state\n")); return ERR_CONN; } pkt_id = msg_generate_packet_id(client); r = mqtt_create_request(client->req_list, pkt_id, cb, arg); - if(r == NULL) { + if (r == NULL) { return ERR_MEM; } - if(mqtt_output_check_space(&client->output, remaining_length) == 0) { + if (mqtt_output_check_space(&client->output, remaining_length) == 0) { mqtt_delete_request(r); return ERR_MEM; } @@ -1138,7 +1138,7 @@ mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_request_ /* Topic */ mqtt_output_append_string(&client->output, topic, topic_len); /* QoS */ - if(sub != 0) { + if (sub != 0) { mqtt_output_append_u8(&client->output, LWIP_MIN(qos, 2)); } @@ -1175,7 +1175,7 @@ mqtt_client_t * mqtt_client_new(void) { mqtt_client_t *client = (mqtt_client_t *)mem_malloc(sizeof(mqtt_client_t)); - if(client != NULL) { + if (client != NULL) { memset(client, 0, sizeof(mqtt_client_t)); } return client; @@ -1209,7 +1209,7 @@ mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, u16_t port, LWIP_ASSERT("mqtt_client_connect: client_info != NULL", client_info != NULL); LWIP_ASSERT("mqtt_client_connect: client_info->client_id != NULL", client_info->client_id != NULL); - if(client->conn_state != TCP_DISCONNECTED) { + if (client->conn_state != TCP_DISCONNECTED) { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Already connected\n")); return ERR_ISCONN; } @@ -1222,10 +1222,10 @@ mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, u16_t port, mqtt_init_requests(client->req_list); /* Build connect message */ - if(client_info->will_topic != NULL && client_info->will_msg != NULL) { + if (client_info->will_topic != NULL && client_info->will_msg != NULL) { flags |= MQTT_CONNECT_FLAG_WILL; flags |= (client_info->will_qos & 3) << 3; - if(client_info->will_retain) { + if (client_info->will_retain) { flags |= MQTT_CONNECT_FLAG_WILL_RETAIN; } len = strlen(client_info->will_topic); @@ -1249,12 +1249,12 @@ mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, u16_t port, LWIP_ERROR("mqtt_client_connect: remaining_length overflow", len <= 0xFFFF, return ERR_VAL); remaining_length = (u16_t)len; - if(mqtt_output_check_space(&client->output, remaining_length) == 0) { + if (mqtt_output_check_space(&client->output, remaining_length) == 0) { return ERR_MEM; } client->conn = tcp_new(); - if(client->conn == NULL) { + if (client->conn == NULL) { return ERR_MEM; } @@ -1262,7 +1262,7 @@ mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, u16_t port, tcp_arg(client->conn, client); /* Any local address, pick random local port number */ err = tcp_bind(client->conn, IP_ADDR_ANY, 0); - if(err != ERR_OK) { + if (err != ERR_OK) { LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Error binding to local ip/port, %d\n", err)); goto tcp_fail; } @@ -1270,7 +1270,7 @@ mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, u16_t port, /* Connect to server */ err = tcp_connect(client->conn, ip_addr, port, mqtt_tcp_connect_cb); - if(err != ERR_OK) { + if (err != ERR_OK) { LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Error connecting to remote ip/port, %d\n", err)); goto tcp_fail; } @@ -1291,7 +1291,7 @@ mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, u16_t port, /* Append client id */ mqtt_output_append_string(&client->output, client_info->client_id, client_id_length); /* Append will message if used */ - if(will_topic_len > 0) { + if (will_topic_len > 0) { mqtt_output_append_string(&client->output, client_info->will_topic, will_topic_len); mqtt_output_append_string(&client->output, client_info->will_msg, will_msg_len); } @@ -1314,7 +1314,7 @@ mqtt_disconnect(mqtt_client_t *client) { LWIP_ASSERT("mqtt_disconnect: client != NULL", client); /* If connection in not already closed */ - if(client->conn_state != TCP_DISCONNECTED) { + if (client->conn_state != TCP_DISCONNECTED) { /* Set conn_state before calling mqtt_close to prevent callback from being called */ client->conn_state = TCP_DISCONNECTED; mqtt_close(client, (mqtt_connection_status_t)0); From 1f3c18fcbe0a62643252e6ec2b72c995eefd02de Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 1 Jan 2017 15:41:53 +0800 Subject: [PATCH 171/184] tcp: Make tcp_listen_with_backlog_and_err return NULL if the address/port is already used The caller of tcp_listen_with_backlog_and_err() usually check if the return pcb is NULL before checking the err reason. I think the commit adding tcp_listen_with_backlog_and_err() accidently change the behavior, Fix it. Fixes: 98fc82fa7128 ("added function tcp_listen_with_backlog_and_err() to get the error reason when listening fails") Signed-off-by: Axel Lin --- src/core/tcp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/tcp.c b/src/core/tcp.c index 63e44457..75be86bb 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -684,6 +684,7 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) if ((lpcb->local_port == pcb->local_port) && ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) { /* this address/port is already used */ + lpcb = NULL; res = ERR_USE; goto done; } From 2096f1a657f303fb209bf5999d0dbb8c21718af3 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Sun, 1 Jan 2017 20:23:11 +0100 Subject: [PATCH 172/184] Fix C++ style comment in mqtt.c --- src/apps/mqtt/mqtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index da70967d..cd271b15 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -835,7 +835,7 @@ mqtt_parse_incoming(mqtt_client_t *client, struct pbuf *p) if (msg_rem_len == 0) { /* Reset parser state */ client->msg_idx = 0; - //msg_tot_len = 0; + /* msg_tot_len = 0; */ fixed_hdr_idx = 0; } } From e12bb2a4eb7b436a870f024c8b766a6664a5c577 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Sun, 1 Jan 2017 20:26:28 +0100 Subject: [PATCH 173/184] Fix comma at end of enum list in mqtt.h --- src/include/lwip/apps/mqtt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/lwip/apps/mqtt.h b/src/include/lwip/apps/mqtt.h index 8d7c457e..ee880405 100644 --- a/src/include/lwip/apps/mqtt.h +++ b/src/include/lwip/apps/mqtt.h @@ -106,7 +106,7 @@ typedef void (*mqtt_connection_cb_t)(mqtt_client_t *client, void *arg, mqtt_conn * Data callback flags */ enum { /** Flag set when last fragment of data arrives in data callback */ - MQTT_DATA_FLAG_LAST = 1, + MQTT_DATA_FLAG_LAST = 1 }; /** From e3c2b8a33901c74c26c4d5d6c70733b7e48986b7 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Mon, 2 Jan 2017 19:06:33 +0100 Subject: [PATCH 174/184] Add note about high resource-consumption in LWIP_PLATFORM_DIAG and LWIP_PLATFORM_ASSERT default implementations --- src/include/lwip/arch.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index 447d90bb..b59f521b 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -70,14 +70,22 @@ #define LWIP_RAND() ((u32_t)rand()) #endif -/** Platform specific diagnostic output */ +/** 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 #include #endif -/** Platform specific assertion handling */ +/** 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) From a3876314b72fa106d10769d5086a6458ffb97007 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Mon, 2 Jan 2017 19:25:23 +0100 Subject: [PATCH 175/184] Add debugging options to documentation --- src/include/lwip/debug.h | 50 ++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/src/include/lwip/debug.h b/src/include/lwip/debug.h index c6766120..8966d61f 100644 --- a/src/include/lwip/debug.h +++ b/src/include/lwip/debug.h @@ -40,18 +40,24 @@ #include "lwip/arch.h" #include "lwip/opt.h" -/** lower two bits indicate debug level - * - 0 all - * - 1 warning - * - 2 serious - * - 3 severe +/** + * @defgroup debugging Debugging + * @ingroup lwip + * @{ */ + +/** Debug level: ALL messages*/ #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, ... */ +/** 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 /** flag for LWIP_DEBUGF to enable that debug message */ #define LWIP_DBG_ON 0x80U @@ -68,9 +74,14 @@ #define LWIP_DBG_HALT 0x08U /** - * LWIP_NOASSERT: Disable LWIP_ASSERT checks. - * -- To disable assertions define LWIP_NOASSERT in arch/cc.h. + * 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 +92,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 +101,24 @@ #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. + * e.g. \#define LWIP_DEBUG (LWIP_DBG_ON | LWIP_DBG_LEVEL_ALL | LWIP_DBG_TRACE) + */ +#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) && \ @@ -118,5 +135,8 @@ #define LWIP_DEBUGF(debug, message) #endif /* LWIP_DEBUG */ -#endif /* LWIP_HDR_DEBUG_H */ +/** + * @} + */ +#endif /* LWIP_HDR_DEBUG_H */ From 644a21b8a5188ab405491bd120dcb1beea50877b Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Mon, 2 Jan 2017 19:32:56 +0100 Subject: [PATCH 176/184] Improve debugging options documentation --- src/include/lwip/debug.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/include/lwip/debug.h b/src/include/lwip/debug.h index 8966d61f..05ccf391 100644 --- a/src/include/lwip/debug.h +++ b/src/include/lwip/debug.h @@ -46,6 +46,9 @@ * @{ */ +/** @name Debug level + * @{ + */ /** Debug level: ALL messages*/ #define LWIP_DBG_LEVEL_ALL 0x00 /** Debug level: Warnings. bad checksums, dropped packets, ... */ @@ -54,16 +57,28 @@ #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 + * @{ + */ /** 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 + * @{ + */ /** 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) */ @@ -72,6 +87,9 @@ #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: From 4059748b4789fbda5970261bb075657565a1f381 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Mon, 2 Jan 2017 19:50:46 +0100 Subject: [PATCH 177/184] I was not satisfied with the previous debugging options structure. Improve it again. --- src/include/lwip/debug.h | 27 +++++++++++++++++---------- src/include/lwip/opt.h | 4 +++- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/include/lwip/debug.h b/src/include/lwip/debug.h index 05ccf391..a142f1cf 100644 --- a/src/include/lwip/debug.h +++ b/src/include/lwip/debug.h @@ -41,12 +41,12 @@ #include "lwip/opt.h" /** - * @defgroup debugging Debugging - * @ingroup lwip + * @defgroup debugging_levels LWIP_DBG_MIN_LEVEL and LWIP_DBG_TYPES_ON values + * @ingroup lwip_opts_debugmsg * @{ */ -/** @name Debug level +/** @name Debug level (LWIP_DBG_MIN_LEVEL) * @{ */ /** Debug level: ALL messages*/ @@ -65,7 +65,7 @@ /* compatibility define only */ #define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL -/** @name Enable/disable debug messages completely +/** @name Enable/disable debug messages completely (LWIP_DBG_TYPES_ON) * @{ */ /** flag for LWIP_DEBUGF to enable that debug message */ @@ -76,7 +76,7 @@ * @} */ -/** @name Debug message types +/** @name Debug message types (LWIP_DBG_TYPES_ON) * @{ */ /** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */ @@ -91,6 +91,15 @@ * @} */ +/** + * @} + */ + +/** + * @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. @@ -99,6 +108,9 @@ #define LWIP_NOASSERT #undef LWIP_NOASSERT #endif +/** + * @} + */ #ifndef LWIP_NOASSERT #define LWIP_ASSERT(message, assertion) do { if (!(assertion)) { \ @@ -126,7 +138,6 @@ /** Enable debug message printing, but only if debug message type is enabled * AND is of correct type AND is at least LWIP_DBG_LEVEL. - * e.g. \#define LWIP_DEBUG (LWIP_DBG_ON | LWIP_DBG_LEVEL_ALL | LWIP_DBG_TRACE) */ #ifdef __DOXYGEN__ #define LWIP_DEBUG @@ -153,8 +164,4 @@ #define LWIP_DEBUGF(debug, message) #endif /* LWIP_DEBUG */ -/** - * @} - */ - #endif /* LWIP_HDR_DEBUG_H */ diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index f30bd269..5abac30c 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -2594,7 +2594,7 @@ --------------------------------------- */ /** - * @defgroup lwip_opts_debugmsg Debugging + * @defgroup lwip_opts_debugmsg Debug messages * @ingroup lwip_opts_debug * @{ */ @@ -2602,6 +2602,7 @@ * 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__ #define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL @@ -2610,6 +2611,7 @@ /** * 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 From d2631e6a53362f98b239edd91640107b2a437096 Mon Sep 17 00:00:00 2001 From: Erik Ekman Date: Wed, 4 Jan 2017 00:23:25 +0100 Subject: [PATCH 178/184] mqtt: Fix pedantic enum warning src/apps/mqtt/mqtt.c:81:17: error: comma at end of enumerator list [-Werror=pedantic] --- src/apps/mqtt/mqtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/mqtt/mqtt.c b/src/apps/mqtt/mqtt.c index cd271b15..5f4a9eff 100644 --- a/src/apps/mqtt/mqtt.c +++ b/src/apps/mqtt/mqtt.c @@ -78,7 +78,7 @@ enum { TCP_DISCONNECTED, TCP_CONNECTING, MQTT_CONNECTING, - MQTT_CONNECTED, + MQTT_CONNECTED }; /** From 8760fb677f017a90295900121fae3580b231e944 Mon Sep 17 00:00:00 2001 From: sg Date: Wed, 4 Jan 2017 15:25:52 +0100 Subject: [PATCH 179/184] fixed warnings in mdns unit tests --- test/unit/mdns/test_mdns.c | 66 +++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/test/unit/mdns/test_mdns.c b/test/unit/mdns/test_mdns.c index 223520c1..ca9be64e 100644 --- a/test/unit/mdns/test_mdns.c +++ b/test/unit/mdns/test_mdns.c @@ -42,6 +42,7 @@ START_TEST(readname_basic) struct pbuf *p; struct mdns_domain domain; u16_t offset; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -60,6 +61,7 @@ START_TEST(readname_anydata) struct pbuf *p; struct mdns_domain domain; u16_t offset; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -78,6 +80,7 @@ START_TEST(readname_short_buf) struct pbuf *p; struct mdns_domain domain; u16_t offset; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -89,18 +92,20 @@ START_TEST(readname_short_buf) END_TEST START_TEST(readname_long_label) -{ static const u8_t data[] = { +{ + static const u8_t data[] = { 0x05, 'm', 'u', 'l', 't', 'i', 0x52, 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 0x00, + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 0x00 }; struct pbuf *p; struct mdns_domain domain; u16_t offset; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -151,11 +156,12 @@ START_TEST(readname_overflow) 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', - 0x00, + 0x00 }; struct pbuf *p; struct mdns_domain domain; u16_t offset; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -172,14 +178,15 @@ START_TEST(readname_jump_earlier) /* Some padding needed, not supported to jump to bytes containing dns header */ /* 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */ 0x0f, 0x0e, 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0xab, - /* 20 */ 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, 0x0c, + /* 20 */ 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, 0x0c }; static const u8_t fullname[] = { - 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00 }; struct pbuf *p; struct mdns_domain domain; u16_t offset; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -200,14 +207,15 @@ START_TEST(readname_jump_earlier_jump) /* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x03, 0x0b, 0x0a, 0xf2, /* 0x10 */ 0x04, 'c', 'a', 's', 't', 0x00, 0xc0, 0x10, - /* 0x18 */ 0x05, 'm', 'u', 'l', 't', 'i', 0xc0, 0x16, + /* 0x18 */ 0x05, 'm', 'u', 'l', 't', 'i', 0xc0, 0x16 }; static const u8_t fullname[] = { - 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x00, + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x00 }; struct pbuf *p; struct mdns_domain domain; u16_t offset; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -231,16 +239,17 @@ START_TEST(readname_jump_maxdepth) /* 0x18 */ 0x03, 'd', 'n', 's', 0xc0, 0x10, 0xc0, 0x10, /* 0x20 */ 0x04, 'd', 'e', 'e', 'p', 0xc0, 0x18, 0x00, /* 0x28 */ 0x04, 'c', 'a', 's', 't', 0xc0, 0x20, 0xb0, - /* 0x30 */ 0x05, 'm', 'u', 'l', 't', 'i', 0xc0, 0x28, + /* 0x30 */ 0x05, 'm', 'u', 'l', 't', 'i', 0xc0, 0x28 }; static const u8_t fullname[] = { 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x04, 'd', 'e', 'e', 'p', 0x03, 'd', 'n', 's', - 0x04, 'n', 'a', 'm', 'e', 0x00, + 0x04, 'n', 'a', 'm', 'e', 0x00 }; struct pbuf *p; struct mdns_domain domain; u16_t offset; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -258,14 +267,15 @@ START_TEST(readname_jump_later) { static const u8_t data[] = { /* 0x00 */ 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, 0x10, 0x00, 0x01, 0x40, - /* 0x10 */ 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0xab, + /* 0x10 */ 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0xab }; static const u8_t fullname[] = { - 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00 }; struct pbuf *p; struct mdns_domain domain; u16_t offset; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -282,11 +292,12 @@ END_TEST START_TEST(readname_half_jump) { static const u8_t data[] = { - 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0 }; struct pbuf *p; struct mdns_domain domain; u16_t offset; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -300,11 +311,12 @@ END_TEST START_TEST(readname_jump_toolong) { static const u8_t data[] = { - 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc2, 0x10, 0x00, 0x01, 0x40, + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc2, 0x10, 0x00, 0x01, 0x40 }; struct pbuf *p; struct mdns_domain domain; u16_t offset; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -319,11 +331,12 @@ START_TEST(readname_jump_loop_label) { static const u8_t data[] = { /* 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 10 */ 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, 0x10, + /* 10 */ 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, 0x10 }; struct pbuf *p; struct mdns_domain domain; u16_t offset; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -338,11 +351,12 @@ START_TEST(readname_jump_loop_jump) { static const u8_t data[] = { /* 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 10 */ 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, 0x15, + /* 10 */ 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, 0x15 }; struct pbuf *p; struct mdns_domain domain; u16_t offset; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -358,6 +372,7 @@ START_TEST(add_label_basic) static const u8_t data[] = { 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x00 }; struct mdns_domain domain; err_t res; + LWIP_UNUSED_ARG(_i); memset(&domain, 0, sizeof(domain)); res = mdns_domain_add_label(&domain, "multi", 5); @@ -376,6 +391,7 @@ START_TEST(add_label_long_label) static const char *toolong = "abcdefghijklmnopqrstuvwxyz0123456789-abcdefghijklmnopqrstuvwxyz0123456789-abcdefghijklmnopqrstuvwxyz0123456789-"; struct mdns_domain domain; err_t res; + LWIP_UNUSED_ARG(_i); memset(&domain, 0, sizeof(domain)); res = mdns_domain_add_label(&domain, "multi", 5); @@ -390,6 +406,7 @@ START_TEST(add_label_full) static const char *label = "0123456789abcdef0123456789abcdef"; struct mdns_domain domain; err_t res; + LWIP_UNUSED_ARG(_i); memset(&domain, 0, sizeof(domain)); res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label)); @@ -437,10 +454,11 @@ END_TEST START_TEST(domain_eq_basic) { static const u8_t data[] = { - 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x00, + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x00 }; struct mdns_domain domain1, domain2; err_t res; + LWIP_UNUSED_ARG(_i); memset(&domain1, 0, sizeof(domain1)); res = mdns_domain_add_label(&domain1, "multi", 5); @@ -467,6 +485,7 @@ START_TEST(domain_eq_diff) { struct mdns_domain domain1, domain2; err_t res; + LWIP_UNUSED_ARG(_i); memset(&domain1, 0, sizeof(domain1)); res = mdns_domain_add_label(&domain1, "multi", 5); @@ -492,6 +511,7 @@ START_TEST(domain_eq_case) { struct mdns_domain domain1, domain2; err_t res; + LWIP_UNUSED_ARG(_i); memset(&domain1, 0, sizeof(domain1)); res = mdns_domain_add_label(&domain1, "multi", 5); @@ -519,6 +539,7 @@ START_TEST(domain_eq_anydata) static const u8_t data2[] = { 0x7f, 0x8c, 0x01, 0xff, 0xcf }; struct mdns_domain domain1, domain2; err_t res; + LWIP_UNUSED_ARG(_i); memset(&domain1, 0, sizeof(domain1)); res = mdns_domain_add_label(&domain1, (const char*)data1, sizeof(data1)); @@ -548,6 +569,7 @@ START_TEST(domain_eq_length) { struct mdns_domain domain1, domain2; err_t res; + LWIP_UNUSED_ARG(_i); memset(&domain1, 0, sizeof(domain1)); memset(domain1.name, 0xAA, sizeof(MDNS_DOMAIN_MAXLEN)); @@ -578,6 +600,7 @@ START_TEST(compress_full_match) u16_t offset; u16_t length; err_t res; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -612,6 +635,7 @@ START_TEST(compress_full_match_subset) u16_t offset; u16_t length; err_t res; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -641,13 +665,14 @@ START_TEST(compress_full_match_jump) /* 0x00 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x10 */ 0x04, 'l', 'w', 'i', 'p', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0xc0, 0x00, 0x02, 0x00, - /* 0x20 */ 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0xc0, 0x15, + /* 0x20 */ 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0xc0, 0x15 }; struct pbuf *p; struct mdns_domain domain; u16_t offset; u16_t length; err_t res; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -682,6 +707,7 @@ START_TEST(compress_no_match) u16_t offset; u16_t length; err_t res; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -715,6 +741,7 @@ START_TEST(compress_2nd_label) u16_t offset; u16_t length; err_t res; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -749,6 +776,7 @@ START_TEST(compress_2nd_label_short) u16_t offset; u16_t length; err_t res; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -778,13 +806,14 @@ START_TEST(compress_jump_to_jump) /* 0x00 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x10 */ 0x04, 'l', 'w', 'i', 'p', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0xc0, 0x00, 0x02, 0x00, - /* 0x20 */ 0x07, 'b', 'a', 'n', 'a', 'n', 'a', 's', 0xc0, 0x15, + /* 0x20 */ 0x07, 'b', 'a', 'n', 'a', 'n', 'a', 's', 0xc0, 0x15 }; struct pbuf *p; struct mdns_domain domain; u16_t offset; u16_t length; err_t res; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; @@ -824,6 +853,7 @@ START_TEST(compress_long_match) u16_t offset; u16_t length; err_t res; + LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); p->payload = (void *)(size_t)data; From 803a711e6a744e11e226d6e87758a1d90acd68a4 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 5 Jan 2017 08:07:41 +0100 Subject: [PATCH 180/184] Fix warning that local variable may be used uninitialized in mem.c --- src/core/mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/mem.c b/src/core/mem.c index 9908c027..db3b7cc5 100644 --- a/src/core/mem.c +++ b/src/core/mem.c @@ -166,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)); From 72316bdb5bb204938c88fced49956d60fc63a39c Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 5 Jan 2017 08:09:00 +0100 Subject: [PATCH 181/184] Move macros to access DHCP and AUTOIP data to headers, users may want to access the members --- src/core/ipv4/autoip.c | 2 -- src/core/ipv4/dhcp.c | 2 -- src/include/lwip/autoip.h | 2 ++ src/include/lwip/dhcp.h | 2 ++ 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/ipv4/autoip.c b/src/core/ipv4/autoip.c index c5426ea2..10db8a34 100644 --- a/src/core/ipv4/autoip.c +++ b/src/core/ipv4/autoip.c @@ -94,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. diff --git a/src/core/ipv4/dhcp.c b/src/core/ipv4/dhcp.c index fadb8e72..dd354710 100644 --- a/src/core/ipv4/dhcp.c +++ b/src/core/ipv4/dhcp.c @@ -209,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) diff --git a/src/include/lwip/autoip.h b/src/include/lwip/autoip.h index 2f666989..1d85bccf 100644 --- a/src/include/lwip/autoip.h +++ b/src/include/lwip/autoip.h @@ -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 diff --git a/src/include/lwip/dhcp.h b/src/include/lwip/dhcp.h index f7503280..ac1b18e9 100644 --- a/src/include/lwip/dhcp.h +++ b/src/include/lwip/dhcp.h @@ -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 From e94c9ffa701b02f4ee3fe4a8794a33027e2a243b Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 5 Jan 2017 08:14:39 +0100 Subject: [PATCH 182/184] Fix warning about bad cast in pbuf_skip() --- src/core/pbuf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/pbuf.c b/src/core/pbuf.c index 60477383..af63e60d 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -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 LWIP_CONST_CAST(struct pbuf*, 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); } /** From 0ffaccaec3f369208a2f39b6441abfead3478384 Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 5 Jan 2017 08:53:26 +0100 Subject: [PATCH 183/184] Add missing #include in httpd.c for atoi() --- src/apps/httpd/httpd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/apps/httpd/httpd.c b/src/apps/httpd/httpd.c index bdffee32..aa2e9b7e 100644 --- a/src/apps/httpd/httpd.c +++ b/src/apps/httpd/httpd.c @@ -98,7 +98,8 @@ #include "lwip/ip.h" #include "lwip/tcp.h" -#include +#include /* memset */ +#include /* atoi */ #include #if LWIP_TCP From 3a20ae38308871cfe1a1e870666e47b11e9d987d Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Thu, 5 Jan 2017 08:55:12 +0100 Subject: [PATCH 184/184] Add missing #include in netdb.c for atoi() --- src/api/netdb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/netdb.c b/src/api/netdb.c index ac1d8c79..ccd9586f 100644 --- a/src/api/netdb.c +++ b/src/api/netdb.c @@ -46,7 +46,8 @@ #include "lwip/api.h" #include "lwip/dns.h" -#include +#include /* memset */ +#include /* atoi */ /** helper struct for gethostbyname_r to access the char* buffer */ struct gethostbyname_r_helper {