diff options
author | Ambroz Bizjak <ambrop7@gmail.com> | 2017-09-26 00:27:28 +0300 |
---|---|---|
committer | Ambroz Bizjak <ambrop7@gmail.com> | 2017-09-26 00:27:28 +0300 |
commit | 79efa642ea431cbb207b8bff52412b942b6a75e3 (patch) | |
tree | 6d8a2ca60760e9440205ea1634dd26f520e97860 | |
parent | dce31a8e6a68d518a0fbed6bc644d14f2d548785 (diff) |
Update lwip to 1710fc1a89578dfaaff684a1aafbc4d16e346f79
-rw-r--r-- | lwip/lwip-base-version | 2 | ||||
-rw-r--r-- | lwip/src/api/sockets.c | 450 | ||||
-rw-r--r-- | lwip/src/apps/httpd/makefsdata/makefsdata.c | 6 | ||||
-rw-r--r-- | lwip/src/apps/sntp/sntp.c | 10 | ||||
-rw-r--r-- | lwip/src/core/altcp_tcp.c | 28 | ||||
-rw-r--r-- | lwip/src/core/ipv4/icmp.c | 2 | ||||
-rw-r--r-- | lwip/src/core/ipv6/icmp6.c | 8 | ||||
-rw-r--r-- | lwip/src/core/ipv6/ip6.c | 282 | ||||
-rw-r--r-- | lwip/src/core/ipv6/mld6.c | 4 | ||||
-rw-r--r-- | lwip/src/core/mem.c | 66 | ||||
-rw-r--r-- | lwip/src/core/tcp_in.c | 105 | ||||
-rw-r--r-- | lwip/src/core/tcp_out.c | 6 | ||||
-rw-r--r-- | lwip/src/include/lwip/apps/mqtt_opts.h | 2 | ||||
-rw-r--r-- | lwip/src/include/lwip/icmp6.h | 2 | ||||
-rw-r--r-- | lwip/src/include/lwip/opt.h | 46 | ||||
-rw-r--r-- | lwip/src/include/lwip/priv/memp_std.h | 4 | ||||
-rw-r--r-- | lwip/src/include/lwip/priv/sockets_priv.h | 15 | ||||
-rw-r--r-- | lwip/src/include/lwip/prot/ip6.h | 124 | ||||
-rw-r--r-- | lwip/src/include/lwip/prot/mld6.h | 1 | ||||
-rw-r--r-- | lwip/src/include/lwip/sockets.h | 35 | ||||
-rw-r--r-- | lwip/test/unit/core/test_mem.c | 103 | ||||
-rw-r--r-- | lwip/test/unit/lwipopts.h | 3 |
22 files changed, 1093 insertions, 211 deletions
diff --git a/lwip/lwip-base-version b/lwip/lwip-base-version index ce5f390..dde8268 100644 --- a/lwip/lwip-base-version +++ b/lwip/lwip-base-version @@ -1 +1 @@ -931b5e643c25820a99bb8df94ab37db6b58c446b +1710fc1a89578dfaaff684a1aafbc4d16e346f79 diff --git a/lwip/src/api/sockets.c b/lwip/src/api/sockets.c index 8cb096d..8b7370d 100644 --- a/lwip/src/api/sockets.c +++ b/lwip/src/api/sockets.c @@ -262,7 +262,7 @@ static void lwip_socket_drop_registered_mld6_memberships(int s); /** The global array of available sockets */ static struct lwip_sock sockets[NUM_SOCKETS]; -#if LWIP_SOCKET_SELECT +#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL #if LWIP_TCPIP_CORE_LOCKING /* protect the select_cb_list using core lock */ #define LWIP_SOCKET_SELECT_DECL_PROTECT(lev) @@ -279,7 +279,7 @@ static volatile int select_cb_ctr; #endif /* LWIP_TCPIP_CORE_LOCKING */ /** The global list of tasks waiting for select */ static struct lwip_select_cb *select_cb_list; -#endif /* LWIP_SOCKET_SELECT */ +#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ #define sock_set_errno(sk, e) do { \ const int sockerr = (e); \ @@ -287,10 +287,10 @@ static struct lwip_select_cb *select_cb_list; } while (0) /* Forward declaration of some functions */ -#if LWIP_SOCKET_SELECT +#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); #define DEFAULT_SOCKET_EVENTCB event_callback -static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent); +static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent, struct lwip_sock *sock); #else #define DEFAULT_SOCKET_EVENTCB NULL #endif @@ -1692,6 +1692,57 @@ lwip_writev(int s, const struct iovec *iov, int iovcnt) return lwip_sendmsg(s, &msg, 0); } +#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL +/* Add select_cb to select_cb_list. */ +static void +lwip_link_select_cb(struct lwip_select_cb *select_cb) +{ + LWIP_SOCKET_SELECT_DECL_PROTECT(lev); + + /* Protect the select_cb_list */ + LWIP_SOCKET_SELECT_PROTECT(lev); + + /* Put this select_cb on top of list */ + select_cb->next = select_cb_list; + if (select_cb_list != NULL) { + select_cb_list->prev = select_cb; + } + select_cb_list = select_cb; +#if !LWIP_TCPIP_CORE_LOCKING + /* Increasing this counter tells select_check_waiters that the list has changed. */ + select_cb_ctr++; +#endif + + /* Now we can safely unprotect */ + LWIP_SOCKET_SELECT_UNPROTECT(lev); +} + +/* Remove select_cb from select_cb_list. */ +static void +lwip_unlink_select_cb(struct lwip_select_cb *select_cb) +{ + LWIP_SOCKET_SELECT_DECL_PROTECT(lev); + + /* Take us off the list */ + LWIP_SOCKET_SELECT_PROTECT(lev); + if (select_cb->next != NULL) { + select_cb->next->prev = select_cb->prev; + } + if (select_cb_list == select_cb) { + LWIP_ASSERT("select_cb->prev == NULL", select_cb->prev == NULL); + select_cb_list = select_cb->next; + } else { + LWIP_ASSERT("select_cb->prev != NULL", select_cb->prev != NULL); + select_cb->prev->next = select_cb->next; + } +#if !LWIP_TCPIP_CORE_LOCKING + /* Increasing this counter tells select_check_waiters that the list has changed. */ + select_cb_ctr++; +#endif + LWIP_SOCKET_SELECT_UNPROTECT(lev); +} +#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ + #if LWIP_SOCKET_SELECT /** * Go through the readset and writeset lists and see which socket of the sockets @@ -1853,7 +1904,6 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, fd_set used_sockets; #endif SYS_ARCH_DECL_PROTECT(lev); - LWIP_SOCKET_SELECT_DECL_PROTECT(lev2); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, @@ -1892,14 +1942,12 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, to use local variables (unless we're running in MPU compatible mode). */ API_SELECT_CB_VAR_DECLARE(select_cb); - API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(ENOMEM); return -1); + API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(ENOMEM); lwip_select_dec_sockets_used(maxfdp1, &used_sockets); return -1); + memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb)); - API_SELECT_CB_VAR_REF(select_cb).next = NULL; - API_SELECT_CB_VAR_REF(select_cb).prev = NULL; API_SELECT_CB_VAR_REF(select_cb).readset = readset; API_SELECT_CB_VAR_REF(select_cb).writeset = writeset; API_SELECT_CB_VAR_REF(select_cb).exceptset = exceptset; - API_SELECT_CB_VAR_REF(select_cb).sem_signalled = 0; #if LWIP_NETCONN_SEM_PER_THREAD API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET(); #else /* LWIP_NETCONN_SEM_PER_THREAD */ @@ -1912,22 +1960,7 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, } #endif /* LWIP_NETCONN_SEM_PER_THREAD */ - /* Protect the select_cb_list */ - LWIP_SOCKET_SELECT_PROTECT(lev2); - - /* Put this select_cb on top of list */ - API_SELECT_CB_VAR_REF(select_cb).next = select_cb_list; - if (select_cb_list != NULL) { - select_cb_list->prev = &API_SELECT_CB_VAR_REF(select_cb); - } - select_cb_list = &API_SELECT_CB_VAR_REF(select_cb); -#if !LWIP_TCPIP_CORE_LOCKING - /* Increasing this counter tells select_check_waiters that the list has changed. */ - select_cb_ctr++; -#endif - - /* Now we can safely unprotect */ - LWIP_SOCKET_SELECT_UNPROTECT(lev2); + lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); /* Increase select_waiting for each socket we are interested in */ maxfdp2 = maxfdp1; @@ -2012,23 +2045,8 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, SYS_ARCH_UNPROTECT(lev); } } - /* Take us off the list */ - LWIP_SOCKET_SELECT_PROTECT(lev2); - if (API_SELECT_CB_VAR_REF(select_cb).next != NULL) { - API_SELECT_CB_VAR_REF(select_cb).next->prev = API_SELECT_CB_VAR_REF(select_cb).prev; - } - if (select_cb_list == &API_SELECT_CB_VAR_REF(select_cb)) { - LWIP_ASSERT("select_cb.prev == NULL", API_SELECT_CB_VAR_REF(select_cb).prev == NULL); - select_cb_list = API_SELECT_CB_VAR_REF(select_cb).next; - } else { - LWIP_ASSERT("select_cb.prev != NULL", API_SELECT_CB_VAR_REF(select_cb).prev != NULL); - API_SELECT_CB_VAR_REF(select_cb).prev->next = API_SELECT_CB_VAR_REF(select_cb).next; - } -#if !LWIP_TCPIP_CORE_LOCKING - /* Increasing this counter tells select_check_waiters that the list has changed. */ - select_cb_ctr++; -#endif - LWIP_SOCKET_SELECT_UNPROTECT(lev2); + + lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); #if LWIP_NETCONN_SEM_PER_THREAD if (API_SELECT_CB_VAR_REF(select_cb).sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { @@ -2072,8 +2090,310 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, } return nready; } +#endif /* LWIP_SOCKET_SELECT */ + +#if LWIP_SOCKET_POLL +/** Options for the lwip_pollscan function. */ +enum lwip_pollscan_opts +{ + /** Clear revents in each struct pollfd. */ + LWIP_POLLSCAN_CLEAR = 1, + + /** Increment select_waiting in each struct lwip_sock. */ + LWIP_POLLSCAN_INC_WAIT = 2, + + /** Decrement select_waiting in each struct lwip_sock. */ + LWIP_POLLSCAN_DEC_WAIT = 4 +}; /** + * Update revents in each struct pollfd. + * Optionally update select_waiting in struct lwip_sock. + * + * @param fds array of structures to update + * @param nfds number of structures in fds + * @param opts what to update and how + * @return number of structures that have revents != 0 + */ +static int +lwip_pollscan(struct pollfd *fds, nfds_t nfds, enum lwip_pollscan_opts opts) +{ + int nready = 0; + nfds_t fdi; + struct lwip_sock *sock; + SYS_ARCH_DECL_PROTECT(lev); + + /* Go through each struct pollfd in the array. */ + for (fdi = 0; fdi < nfds; fdi++) { + if ((opts & LWIP_POLLSCAN_CLEAR) != 0) { + fds[fdi].revents = 0; + } + + /* Negative fd means the caller wants us to ignore this struct. + POLLNVAL means we already detected that the fd is invalid; + if another thread has since opened a new socket with that fd, + we must not use that socket. */ + if (fds[fdi].fd >= 0 && (fds[fdi].revents & POLLNVAL) == 0) { + /* First get the socket's status (protected)... */ + SYS_ARCH_PROTECT(lev); + sock = tryget_socket_unconn(fds[fdi].fd); + if (sock != NULL) { + void* lastdata = sock->lastdata.pbuf; + s16_t rcvevent = sock->rcvevent; + u16_t sendevent = sock->sendevent; + u16_t errevent = sock->errevent; + + if ((opts & LWIP_POLLSCAN_INC_WAIT) != 0) { + sock->select_waiting++; + if (sock->select_waiting == 0) { + /* overflow - too many threads waiting */ + sock->select_waiting--; + done_socket(sock); + nready = -1; + SYS_ARCH_UNPROTECT(lev); + break; + } + done_socket(sock); + } else if ((opts & LWIP_POLLSCAN_DEC_WAIT) != 0) { + /* for now, handle select_waiting==0... */ + LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); + if (sock->select_waiting > 0) { + sock->select_waiting--; + } + done_socket(sock); + } + + SYS_ARCH_UNPROTECT(lev); + + /* ... then examine it: */ + /* See if netconn of this socket is ready for read */ + if ((fds[fdi].events & POLLIN) != 0 && ((lastdata != NULL) || (rcvevent > 0))) { + fds[fdi].revents |= POLLIN; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for reading\n", fds[fdi].fd)); + } + /* See if netconn of this socket is ready for write */ + if ((fds[fdi].events & POLLOUT) != 0 && (sendevent != 0)) { + fds[fdi].revents |= POLLOUT; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for writing\n", fds[fdi].fd)); + } + /* See if netconn of this socket had an error */ + if (errevent != 0) { + /* POLLERR is output only. */ + fds[fdi].revents |= POLLERR; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for exception\n", fds[fdi].fd)); + } + } else { + /* Not a valid socket */ + SYS_ARCH_UNPROTECT(lev); + /* POLLNVAL is output only. */ + fds[fdi].revents |= POLLNVAL; + return -1; + } + } + + /* Will return the number of structures that have events, + not the number of events. */ + if (fds[fdi].revents != 0) { + nready++; + } + } + + LWIP_ASSERT("nready >= 0", nready >= 0); + return nready; +} + +#if LWIP_NETCONN_FULLDUPLEX +/* Mark all sockets as used. + * + * All sockets are marked (and later unmarked), whether they are open or not. + * This is OK as lwip_pollscan aborts select when non-open sockets are found. + */ +static void +lwip_poll_inc_sockets_used(struct pollfd *fds, nfds_t nfds) +{ + nfds_t fdi; + SYS_ARCH_DECL_PROTECT(lev); + + if(fds) { + /* Go through each struct pollfd in the array. */ + for (fdi = 0; fdi < nfds; fdi++) { + SYS_ARCH_PROTECT(lev); + /* Increase the reference counter */ + tryget_socket_unconn(fds[fdi].fd); + SYS_ARCH_UNPROTECT(lev); + } + } +} + +/* Let go all sockets that were marked as used when starting poll */ +static void +lwip_poll_dec_sockets_used(struct pollfd *fds, nfds_t nfds) +{ + nfds_t fdi; + struct lwip_sock *sock; + SYS_ARCH_DECL_PROTECT(lev); + + if(fds) { + /* Go through each struct pollfd in the array. */ + for (fdi = 0; fdi < nfds; fdi++) { + sock = tryget_socket_unconn_nouse(fds[fdi].fd); + LWIP_ASSERT("socket gone at the end of select", sock != NULL); + if (sock != NULL) { + done_socket(sock); + } + } + } +} +#else /* LWIP_NETCONN_FULLDUPLEX */ +#define lwip_poll_inc_sockets_used(fds, nfds) +#define lwip_poll_dec_sockets_used(fds, nfds) +#endif /* LWIP_NETCONN_FULLDUPLEX */ + +int +lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout) +{ + u32_t waitres = 0; + int nready; + u32_t msectimeout; +#if LWIP_NETCONN_SEM_PER_THREAD + int waited = 0; +#endif + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll(%p, %d, %d)\n", + (void*)fds, (int)nfds, timeout)); + + lwip_poll_inc_sockets_used(fds, nfds); + + /* Go through each struct pollfd to count number of structures + which currently match */ + nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_CLEAR); + + if (nready < 0) { + lwip_poll_dec_sockets_used(fds, nfds); + return -1; + } + + /* If we don't have any current events, then suspend if we are supposed to */ + if (!nready) { + API_SELECT_CB_VAR_DECLARE(select_cb); + + if (timeout == 0) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: no timeout, returning 0\n")); + goto return_success; + } + API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(EAGAIN); lwip_poll_dec_sockets_used(fds, nfds); return -1); + memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb)); + + /* None ready: add our semaphore to list: + We don't actually need any dynamic memory. Our entry on the + list is only valid while we are in this function, so it's ok + to use local variables. */ + + API_SELECT_CB_VAR_REF(select_cb).poll_fds = fds; + API_SELECT_CB_VAR_REF(select_cb).poll_nfds = nfds; +#if LWIP_NETCONN_SEM_PER_THREAD + API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET(); +#else /* LWIP_NETCONN_SEM_PER_THREAD */ + if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) { + /* failed to create semaphore */ + set_errno(EAGAIN); + lwip_poll_dec_sockets_used(fds, nfds); + API_SELECT_CB_VAR_FREE(select_cb); + return -1; + } +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); + + /* Increase select_waiting for each socket we are interested in. + Also, check for events again: there could have been events between + the last scan (without us on the list) and putting us on the list! */ + nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_INC_WAIT); + + if (!nready) { + /* Still none ready, just wait to be woken */ + if (timeout < 0) { + /* Wait forever */ + msectimeout = 0; + } else { + /* timeout == 0 would have been handled earlier. */ + LWIP_ASSERT("timeout > 0", timeout > 0); + msectimeout = timeout; + } + waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout); +#if LWIP_NETCONN_SEM_PER_THREAD + waited = 1; +#endif + } + + /* Decrease select_waiting for each socket we are interested in, + and check which events occurred while we waited. */ + nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_DEC_WAIT); + + lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); + +#if LWIP_NETCONN_SEM_PER_THREAD + if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { + /* don't leave the thread-local semaphore signalled */ + sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1); + } +#else /* LWIP_NETCONN_SEM_PER_THREAD */ + sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem); +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + API_SELECT_CB_VAR_FREE(select_cb); + + if (nready < 0) { + /* This happens when a socket got closed while waiting */ + lwip_poll_dec_sockets_used(fds, nfds); + return -1; + } + + if (waitres == SYS_ARCH_TIMEOUT) { + /* Timeout */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: timeout expired\n")); + goto return_success; + } + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: nready=%d\n", nready)); +return_success: + lwip_poll_dec_sockets_used(fds, nfds); + set_errno(0); + return nready; +} + +/** + * Check whether event_callback should wake up a thread waiting in + * lwip_poll. + */ +static int +lwip_poll_should_wake(const struct lwip_select_cb *scb, int fd, struct lwip_sock *sock) +{ + nfds_t fdi; + for (fdi = 0; fdi < scb->poll_nfds; fdi++) { + const struct pollfd *pollfd = &scb->poll_fds[fdi]; + if (pollfd->fd == fd) { + /* Do not update pollfd->revents right here; + that would be a data race because lwip_pollscan + accesses revents without protecting. */ + if (sock->rcvevent > 0 && (pollfd->events & POLLIN) != 0) { + return 1; + } + if (sock->sendevent != 0 && (pollfd->events & POLLOUT) != 0) { + return 1; + } + if (sock->errevent != 0) { + /* POLLERR is output only. */ + return 1; + } + } + } + return 0; +} +#endif /* LWIP_SOCKET_POLL */ + +#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL +/** * Callback registered in the netconn layer for each socket-netconn. * Processes recvevent (data available) and wakes up tasks waiting for select. * @@ -2162,7 +2482,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) has_errevent = sock->errevent != 0; SYS_ARCH_UNPROTECT(lev); /* Check any select calls waiting on this socket */ - select_check_waiters(s, has_recvevent, has_sendevent, has_errevent); + select_check_waiters(s, has_recvevent, has_sendevent, has_errevent, sock); } else { SYS_ARCH_UNPROTECT(lev); } @@ -2182,7 +2502,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) * select_cb_list during our UNPROTECT/PROTECT. We use a generational counter to * detect this change and restart the list walk. The list is expected to be small */ -static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent) +static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent, struct lwip_sock *sock) { struct lwip_select_cb *scb; #if !LWIP_TCPIP_CORE_LOCKING @@ -2200,22 +2520,38 @@ again: if (scb->sem_signalled == 0) { /* semaphore not signalled yet */ int do_signal = 0; - /* Test this select call for our socket */ - if (has_recvevent) { - if (scb->readset && FD_ISSET(s, scb->readset)) { - do_signal = 1; - } +#if LWIP_SOCKET_POLL + if (scb->poll_fds != NULL) { + LWIP_UNUSED_ARG(has_recvevent); + LWIP_UNUSED_ARG(has_sendevent); + LWIP_UNUSED_ARG(has_errevent); + do_signal = lwip_poll_should_wake(scb, s, sock); } - if (has_sendevent) { - if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { - do_signal = 1; +#endif /* LWIP_SOCKET_POLL */ +#if LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL + else +#endif /* LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL */ +#if LWIP_SOCKET_SELECT + { + LWIP_UNUSED_ARG(sock); + /* Test this select call for our socket */ + if (has_recvevent) { + if (scb->readset && FD_ISSET(s, scb->readset)) { + do_signal = 1; + } } - } - if (has_errevent) { - if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { - do_signal = 1; + if (has_sendevent) { + if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { + do_signal = 1; + } + } + if (has_errevent) { + if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { + do_signal = 1; + } } } +#endif /* LWIP_SOCKET_SELECT */ if (do_signal) { scb->sem_signalled = 1; /* For !LWIP_TCPIP_CORE_LOCKING, we don't call SYS_ARCH_UNPROTECT() before signaling @@ -2241,7 +2577,7 @@ again: SYS_ARCH_UNPROTECT(lev); #endif } -#endif /* LWIP_SOCKET_SELECT */ +#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ /** * Close one end of a full-duplex connection. diff --git a/lwip/src/apps/httpd/makefsdata/makefsdata.c b/lwip/src/apps/httpd/makefsdata/makefsdata.c index 1efe89d..9af8bc9 100644 --- a/lwip/src/apps/httpd/makefsdata/makefsdata.c +++ b/lwip/src/apps/httpd/makefsdata/makefsdata.c @@ -421,7 +421,7 @@ int process_sub(FILE *data_file, FILE *struct_file) ret = tinydir_readfile_n(&dir, &file, i); if (ret == 0) { -#if (defined _MSC_VER || defined __MINGW32__) +#if (defined _MSC_VER || defined __MINGW32__) && (defined _UNICODE) size_t i; char currName[256]; wcstombs_s(&i, currName, sizeof(currName), file.name, sizeof(currName)); @@ -461,12 +461,12 @@ int process_sub(FILE *data_file, FILE *struct_file) if (ret == 0) { if (!file.is_dir) { -#if (defined _MSC_VER || defined __MINGW32__) +#if (defined _MSC_VER || defined __MINGW32__) && (defined _UNICODE) size_t i; char curName[256]; wcstombs_s(&i, curName, sizeof(curName), file.name, sizeof(curName)); #else - const char *currName = file.name; + const char *curName = file.name; #endif if (strcmp(curName, "fsdata.tmp") == 0) { diff --git a/lwip/src/apps/sntp/sntp.c b/lwip/src/apps/sntp/sntp.c index 480af60..3ebf3ac 100644 --- a/lwip/src/apps/sntp/sntp.c +++ b/lwip/src/apps/sntp/sntp.c @@ -71,9 +71,11 @@ #define SNTP_SUPPORT_MULTIPLE_SERVERS 0 #endif /* NTP_MAX_SERVERS > 1 */ -#if (SNTP_UPDATE_DELAY < 15000) && !defined(SNTP_SUPPRESS_DELAY_CHECK) +#ifndef SNTP_SUPPRESS_DELAY_CHECK +#if SNTP_UPDATE_DELAY < 15000 #error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!" #endif +#endif /* the various debug levels for this file */ #define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE) @@ -499,15 +501,17 @@ sntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, /* Set up timeout for next request (only if poll response was received)*/ if (sntp_opmode == SNTP_OPMODE_POLL) { + u32_t sntp_update_delay; sys_untimeout(sntp_try_next_server, NULL); sys_untimeout(sntp_request, NULL); /* Correct response, reset retry timeout */ SNTP_RESET_RETRY_TIMEOUT(); - sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL); + sntp_update_delay = (u32_t)SNTP_UPDATE_DELAY; + sys_timeout(sntp_update_delay, sntp_request, NULL); LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n", - (u32_t)SNTP_UPDATE_DELAY)); + sntp_update_delay)); } } else if (err == SNTP_ERR_KOD) { /* KOD errors are only processed in case of an explicit poll response */ diff --git a/lwip/src/core/altcp_tcp.c b/lwip/src/core/altcp_tcp.c index cbbc422..72be815 100644 --- a/lwip/src/core/altcp_tcp.c +++ b/lwip/src/core/altcp_tcp.c @@ -152,6 +152,17 @@ altcp_tcp_err(void *arg, err_t err) } /* setup functions */ + +static void +altcp_tcp_remove_callbacks(struct tcp_pcb *tpcb) +{ + tcp_arg(tpcb, NULL); + tcp_recv(tpcb, NULL); + tcp_sent(tpcb, NULL); + tcp_err(tpcb, NULL); + tcp_poll(tpcb, NULL, tpcb->pollinterval); +} + static void altcp_tcp_setup_callbacks(struct altcp_pcb *conn, struct tcp_pcb *tpcb) { @@ -288,7 +299,22 @@ altcp_tcp_close(struct altcp_pcb *conn) } ALTCP_TCP_ASSERT_CONN(conn); pcb = (struct tcp_pcb *)conn->state; - return tcp_close(pcb); + if (pcb) { + err_t err; + tcp_poll_fn oldpoll = pcb->poll; + altcp_tcp_remove_callbacks(pcb); + err = tcp_close(pcb); + if (err != ERR_OK) { + /* not closed, set up all callbacks again */ + altcp_tcp_setup_callbacks(conn, pcb); + /* poll callback is not included in the above */ + tcp_poll(pcb, oldpoll, pcb->pollinterval); + return err; + } + conn->state = NULL; /* unsafe to reference pcb after tcp_close(). */ + } + altcp_free(conn); + return ERR_OK; } static err_t diff --git a/lwip/src/core/ipv4/icmp.c b/lwip/src/core/ipv4/icmp.c index 3c9445d..3fe13cc 100644 --- a/lwip/src/core/ipv4/icmp.c +++ b/lwip/src/core/ipv4/icmp.c @@ -57,7 +57,7 @@ /** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be * used to modify and send a response packet (and to 1 if this is not the case, - * e.g. when link header is stripped of when receiving) */ + * e.g. when link header is stripped off when receiving) */ #ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN #define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1 #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ diff --git a/lwip/src/core/ipv6/icmp6.c b/lwip/src/core/ipv6/icmp6.c index 08db381..62be025 100644 --- a/lwip/src/core/ipv6/icmp6.c +++ b/lwip/src/core/ipv6/icmp6.c @@ -282,7 +282,8 @@ icmp6_time_exceeded_with_addrs(struct pbuf *p, enum icmp6_te_code c, * Send an icmpv6 'parameter problem' packet. * * This function must be used only in direct response to a packet that is being - * received right now. Otherwise, address zones would be lost. + * received right now. Otherwise, address zones would be lost and the calculated + * offset would be wrong (calculated against ip6_current_header()). * * @param p the input packet for which the 'param problem' should be sent, * p->payload pointing to the IP header @@ -290,9 +291,10 @@ icmp6_time_exceeded_with_addrs(struct pbuf *p, enum icmp6_te_code c, * @param pointer the pointer to the byte where the parameter is found */ void -icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer) +icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, const void *pointer) { - icmp6_send_response(p, c, pointer, ICMP6_TYPE_PP); + u32_t pointer_u32 = (u32_t)((const u8_t *)pointer - (const u8_t *)ip6_current_header()); + icmp6_send_response(p, c, pointer_u32, ICMP6_TYPE_PP); } /** diff --git a/lwip/src/core/ipv6/ip6.c b/lwip/src/core/ipv6/ip6.c index 907f0aa..d65de89 100644 --- a/lwip/src/core/ipv6/ip6.c +++ b/lwip/src/core/ipv6/ip6.c @@ -508,7 +508,7 @@ ip6_input(struct pbuf *p, struct netif *inp) { struct ip6_hdr *ip6hdr; struct netif *netif; - u8_t nexth; + const u8_t *nexth; u16_t hlen, hlen_tot; /* the current header length */ #if 0 /*IP_ACCEPT_LINK_LAYER_ADDRESSING*/ @todo @@ -695,7 +695,7 @@ netif_found: ip_data.current_netif = netif; /* Save next header type. */ - nexth = IP6H_NEXTH(ip6hdr); + nexth = &IP6H_NEXTH(ip6hdr); /* Init header length. */ hlen = hlen_tot = IP6_HLEN; @@ -704,13 +704,25 @@ netif_found: pbuf_remove_header(p, IP6_HLEN); /* Process known option extension headers, if present. */ - while (nexth != IP6_NEXTH_NONE) + while (*nexth != IP6_NEXTH_NONE) { - switch (nexth) { + switch (*nexth) { case IP6_NEXTH_HOPBYHOP: + { + s32_t opt_offset; + struct ip6_hbh_hdr *hbh_hdr; + struct ip6_opt_hdr *opt_hdr; LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Hop-by-Hop options header\n")); + /* Get and check the header length, while staying in packet bounds. */ - hlen = (u16_t)(8 * (1 + *((u8_t *)p->payload + 1))); + hbh_hdr = (struct ip6_hbh_hdr *)p->payload; + + /* Get next header type. */ + nexth = &IP6_HBH_NEXTH(hbh_hdr); + + /* Get the header length. */ + hlen = (u16_t)(8 * (1 + hbh_hdr->_hlen)); + if ((p->len < 8) || (hlen > p->len)) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", @@ -724,17 +736,82 @@ netif_found: hlen_tot = (u16_t)(hlen_tot + hlen); - /* Get next header type. */ - nexth = *((u8_t *)p->payload); + /* The extended option header starts right after Hop-by-Hop header. */ + opt_offset = IP6_HBH_HLEN; + while (opt_offset < hlen) + { + s32_t opt_dlen = 0; - /* Skip over this header. */ + opt_hdr = (struct ip6_opt_hdr *)((u8_t *)hbh_hdr + opt_offset); + + switch (IP6_OPT_TYPE(opt_hdr)) { + /* @todo: process IPV6 Hop-by-Hop option data */ + case IP6_PAD1_OPTION: + /* PAD1 option doesn't have length and value field */ + opt_dlen = -1; + break; + case IP6_PADN_OPTION: + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + case IP6_ROUTER_ALERT_OPTION: + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + case IP6_JUMBO_OPTION: + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + default: + /* Check 2 MSB of Hop-by-Hop header type. */ + switch (IP6_OPT_TYPE_ACTION(opt_hdr)) { + case 1: + /* Discard the packet. */ + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid Hop-by-Hop option type dropped.\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + case 2: + /* Send ICMP Parameter Problem */ + icmp6_param_problem(p, ICMP6_PP_OPTION, opt_hdr); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid Hop-by-Hop option type dropped.\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + case 3: + /* Send ICMP Parameter Problem if destination address is not a multicast address */ + if (!ip6_addr_ismulticast(ip6_current_dest_addr())) { + icmp6_param_problem(p, ICMP6_PP_OPTION, opt_hdr); + } + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid Hop-by-Hop option type dropped.\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + default: + /* Skip over this option. */ + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + } + break; + } + + /* Adjust the offset to move to the next extended option header */ + opt_offset = opt_offset + IP6_OPT_HLEN + opt_dlen; + } pbuf_remove_header(p, hlen); break; + } case IP6_NEXTH_DESTOPTS: + { + s32_t opt_offset; + struct ip6_dest_hdr *dest_hdr; + struct ip6_opt_hdr *opt_hdr; LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Destination options header\n")); - /* Get and check the header length, while staying in packet bounds. */ - hlen = (u16_t)(8 * (1 + *((u8_t *)p->payload + 1))); + dest_hdr = (struct ip6_dest_hdr *)p->payload; + + /* Get next header type. */ + nexth = &IP6_DEST_NEXTH(dest_hdr); + + /* Get the header length. */ + hlen = 8 * (1 + dest_hdr->_hlen); if ((p->len < 8) || (hlen > p->len)) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", @@ -748,17 +825,87 @@ netif_found: hlen_tot = (u16_t)(hlen_tot + hlen); - /* Get next header type. */ - nexth = *((u8_t *)p->payload); + /* The extended option header starts right after Destination header. */ + opt_offset = IP6_DEST_HLEN; + while (opt_offset < hlen) + { + s32_t opt_dlen = 0; + + opt_hdr = (struct ip6_opt_hdr *)((u8_t *)dest_hdr + opt_offset); + + switch (IP6_OPT_TYPE(opt_hdr)) + { + /* @todo: process IPV6 Destination option data */ + case IP6_PAD1_OPTION: + /* PAD1 option deosn't have length and value field */ + opt_dlen = -1; + break; + case IP6_PADN_OPTION: + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + case IP6_ROUTER_ALERT_OPTION: + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + case IP6_JUMBO_OPTION: + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + case IP6_HOME_ADDRESS_OPTION: + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + default: + /* Check 2 MSB of Destination header type. */ + switch (IP6_OPT_TYPE_ACTION(opt_hdr)) + { + case 1: + /* Discard the packet. */ + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid destination option type dropped.\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + case 2: + /* Send ICMP Parameter Problem */ + icmp6_param_problem(p, ICMP6_PP_OPTION, opt_hdr); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid destination option type dropped.\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + case 3: + /* Send ICMP Parameter Problem if destination address is not a multicast address */ + if (!ip6_addr_ismulticast(ip6_current_dest_addr())) { + icmp6_param_problem(p, ICMP6_PP_OPTION, opt_hdr); + } + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid destination option type dropped.\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + default: + /* Skip over this option. */ + opt_dlen = IP6_OPT_DLEN(opt_hdr); + break; + } + break; + } + + /* Adjust the offset to move to the next extended option header */ + opt_offset = opt_offset + IP6_OPT_HLEN + opt_dlen; + } - /* Skip over this header. */ pbuf_remove_header(p, hlen); break; + } case IP6_NEXTH_ROUTING: + { + struct ip6_rout_hdr *rout_hdr; LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Routing header\n")); - /* Get and check the header length, while staying in packet bounds. */ - hlen = (u16_t)(8 * (1 + *((u8_t *)p->payload + 1))); + rout_hdr = (struct ip6_rout_hdr *)p->payload; + + /* Get next header type. */ + nexth = &IP6_ROUT_NEXTH(rout_hdr); + + /* Get the header length. */ + hlen = 8 * (1 + rout_hdr->_hlen); + if ((p->len < 8) || (hlen > p->len)) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", @@ -770,20 +917,51 @@ netif_found: goto ip6_input_cleanup; } - /* Get next header type. */ - nexth = *((u8_t *)p->payload); - /* Skip over this header. */ hlen_tot = (u16_t)(hlen_tot + hlen); + /* if segment left value is 0 in routing header, ignore the option */ + if (IP6_ROUT_SEG_LEFT(rout_hdr)) { + /* The length field of routing option header must be even */ + if (rout_hdr->_hlen & 0x1) { + /* Discard and send parameter field error */ + icmp6_param_problem(p, ICMP6_PP_FIELD, &rout_hdr->_hlen); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid routing type dropped\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + + switch (IP6_ROUT_TYPE(rout_hdr)) + { + /* TODO: process routing by the type */ + case IP6_ROUT_TYPE2: + break; + case IP6_ROUT_RPL: + break; + default: + /* Discard unrecognized routing type and send parameter field error */ + icmp6_param_problem(p, ICMP6_PP_FIELD, &IP6_ROUT_TYPE(rout_hdr)); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid routing type dropped\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + } + pbuf_remove_header(p, hlen); break; - + } case IP6_NEXTH_FRAGMENT: { struct ip6_frag_hdr *frag_hdr; LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header\n")); + frag_hdr = (struct ip6_frag_hdr *)p->payload; + + /* Get next header type. */ + nexth = &IP6_FRAG_NEXTH(frag_hdr); + /* Fragment Header length. */ hlen = 8; @@ -801,10 +979,15 @@ netif_found: hlen_tot = (u16_t)(hlen_tot + hlen); - frag_hdr = (struct ip6_frag_hdr *)p->payload; - - /* Get next header type. */ - nexth = frag_hdr->_nexth; + /* check payload length is multiple of 8 octets when mbit is set */ + if (IP6_FRAG_MBIT(frag_hdr) && (IP6H_PLEN(ip6hdr) & 0x7)) { + /* ipv6 payload length is not multiple of 8 octets */ + icmp6_param_problem(p, ICMP6_PP_FIELD, &ip6hdr->_plen); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with invalid payload length dropped\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } /* Offset == 0 and more_fragments == 0? */ if ((frag_hdr->_fragment_offset & @@ -813,7 +996,6 @@ netif_found: pbuf_remove_header(p, hlen); } else { #if LWIP_IPV6_REASS - /* reassemble the packet */ ip_data.current_ip_header_tot_len = hlen_tot; p = ip6_reass(p); @@ -825,7 +1007,7 @@ netif_found: /* Returned p point to IPv6 header. * Update all our variables and pointers and continue. */ ip6hdr = (struct ip6_hdr *)p->payload; - nexth = IP6H_NEXTH(ip6hdr); + nexth = &IP6H_NEXTH(ip6hdr); hlen = hlen_tot = IP6_HLEN; pbuf_remove_header(p, IP6_HLEN); @@ -843,9 +1025,18 @@ netif_found: default: goto options_done; } + + if (*nexth == IP6_NEXTH_HOPBYHOP) { + /* Hop-by-Hop header comes only as a first option */ + icmp6_param_problem(p, ICMP6_PP_HEADER, nexth); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Hop-by-Hop options header dropped (only valid as a first option)\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } } -options_done: +options_done: if (hlen_tot >= 0x8000) { /* s16_t overflow */ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_input: header length overflow: %"U16_F"\n", hlen_tot)); @@ -873,7 +1064,7 @@ options_done: #else /* LWIP_RAW */ { #endif /* LWIP_RAW */ - switch (nexth) { + switch (*nexth) { case IP6_NEXTH_NONE: pbuf_free(p); break; @@ -902,7 +1093,7 @@ options_done: /* send ICMP parameter problem unless it was a multicast or ICMPv6 */ if ((!ip6_addr_ismulticast(ip6_current_dest_addr())) && (IP6H_NEXTH(ip6hdr) != IP6_NEXTH_ICMP6)) { - icmp6_param_problem(p, ICMP6_PP_HEADER, (u32_t)(hlen_tot - hlen)); + icmp6_param_problem(p, ICMP6_PP_HEADER, nexth); } #endif /* LWIP_ICMP */ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_input: Unsupported transport protocol %"U16_F"\n", (u16_t)IP6H_NEXTH(ip6hdr))); @@ -1207,25 +1398,42 @@ ip6_output_hinted(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, err_t ip6_options_add_hbh_ra(struct pbuf *p, u8_t nexth, u8_t value) { + u8_t *opt_data; + u32_t offset = 0; struct ip6_hbh_hdr *hbh_hdr; + struct ip6_opt_hdr *opt_hdr; + /* fixed 4 bytes for router alert option and 2 bytes padding */ + const u8_t hlen = (sizeof(struct ip6_opt_hdr) * 2) + IP6_ROUTER_ALERT_DLEN; /* Move pointer to make room for hop-by-hop options header. */ - if (pbuf_add_header(p, sizeof(struct ip6_hbh_hdr))) { + if (pbuf_add_header(p, sizeof(struct ip6_hbh_hdr) + hlen)) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_options: no space for options header\n")); IP6_STATS_INC(ip6.err); return ERR_BUF; } + /* Set fields of Hop-by-Hop header */ hbh_hdr = (struct ip6_hbh_hdr *)p->payload; - - /* Set fields. */ - hbh_hdr->_nexth = nexth; + IP6_HBH_NEXTH(hbh_hdr) = nexth; hbh_hdr->_hlen = 0; - hbh_hdr->_ra_opt_type = IP6_ROUTER_ALERT_OPTION; - hbh_hdr->_ra_opt_dlen = 2; - hbh_hdr->_ra_opt_data = value; - hbh_hdr->_padn_opt_type = IP6_PADN_ALERT_OPTION; - hbh_hdr->_padn_opt_dlen = 0; + offset = IP6_HBH_HLEN; + + /* Set router alert options to Hop-by-Hop extended option header */ + opt_hdr = (struct ip6_opt_hdr *)((u8_t *)hbh_hdr + offset); + IP6_OPT_TYPE(opt_hdr) = IP6_ROUTER_ALERT_OPTION; + IP6_OPT_DLEN(opt_hdr) = IP6_ROUTER_ALERT_DLEN; + offset += IP6_OPT_HLEN; + + /* Set router alert option data */ + opt_data = (u8_t *)hbh_hdr + offset; + opt_data[0] = value; + opt_data[1] = 0; + offset += IP6_OPT_DLEN(opt_hdr); + + /* add 2 bytes padding to make 8 bytes Hop-by-Hop header length */ + opt_hdr = (struct ip6_opt_hdr *)((u8_t *)hbh_hdr + offset); + IP6_OPT_TYPE(opt_hdr) = IP6_PADN_OPTION; + IP6_OPT_DLEN(opt_hdr) = 0; return ERR_OK; } diff --git a/lwip/src/core/ipv6/mld6.c b/lwip/src/core/ipv6/mld6.c index b5a159b..64a204d 100644 --- a/lwip/src/core/ipv6/mld6.c +++ b/lwip/src/core/ipv6/mld6.c @@ -554,14 +554,14 @@ mld6_send(struct netif *netif, struct mld_group *group, u8_t type) const ip6_addr_t *src_addr; /* Allocate a packet. Size is MLD header + IPv6 Hop-by-hop options header. */ - p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr), PBUF_RAM); + p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + MLD6_HBH_HLEN, PBUF_RAM); if (p == NULL) { MLD6_STATS_INC(mld6.memerr); return; } /* Move to make room for Hop-by-hop options header. */ - if (pbuf_remove_header(p, IP6_HBH_HLEN)) { + if (pbuf_remove_header(p, MLD6_HBH_HLEN)) { pbuf_free(p); MLD6_STATS_INC(mld6.lenerr); return; diff --git a/lwip/src/core/mem.c b/lwip/src/core/mem.c index 8a77a67..689d7f0 100644 --- a/lwip/src/core/mem.c +++ b/lwip/src/core/mem.c @@ -66,6 +66,11 @@ #include <stdlib.h> /* for malloc()/free() */ #endif +/* This is overridable for tests only... */ +#ifndef LWIP_MEM_ILLEGAL_FREE +#define LWIP_MEM_ILLEGAL_FREE(msg) LWIP_ASSERT(msg, 0) +#endif + #define MEM_STATS_INC_LOCKED(x) SYS_ARCH_LOCKED(MEM_STATS_INC(x)) #define MEM_STATS_INC_USED_LOCKED(x, y) SYS_ARCH_LOCKED(MEM_STATS_INC_USED(x, y)) #define MEM_STATS_DEC_USED_LOCKED(x, y) SYS_ARCH_LOCKED(MEM_STATS_DEC_USED(x, y)) @@ -413,6 +418,25 @@ mem_init(void) } } +/* Check if a struct mem is correctly linked. + * If not, double-free is a possible reason. + */ +static int +mem_link_valid(struct mem *mem) +{ + struct mem *nmem, *pmem; + mem_size_t rmem_idx; + rmem_idx = (mem_size_t)((u8_t *)mem - ram); + nmem = (struct mem *)(void *)&ram[mem->next]; + pmem = (struct mem *)(void *)&ram[mem->prev]; + if ((mem->next > MEM_SIZE_ALIGNED) || (mem->prev > MEM_SIZE_ALIGNED) || + ((mem->prev != rmem_idx) && (pmem->next != rmem_idx)) || + ((nmem != ram_end) && (nmem->prev != rmem_idx))) { + return 0; + } + return 1; +} + /** * Put a struct mem back on the heap * @@ -429,12 +453,20 @@ mem_free(void *rmem) LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n")); return; } - LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT - 1)) == 0); + if ((((mem_ptr_t)rmem) & (MEM_ALIGNMENT - 1)) != 0) { + LWIP_MEM_ILLEGAL_FREE("mem_free: sanity check alignment"); + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: sanity check alignment\n")); + /* protect mem stats from concurrent access */ + MEM_STATS_INC_LOCKED(illegal); + return; + } - LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram && - (u8_t *)rmem < (u8_t *)ram_end); + /* Get the corresponding struct mem: */ + /* cast through void* to get rid of alignment warnings */ + mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); - if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { + if ((u8_t *)mem < ram || (u8_t *)rmem + MIN_SIZE_ALIGNED > (u8_t *)ram_end) { + LWIP_MEM_ILLEGAL_FREE("mem_free: illegal memory"); LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n")); /* protect mem stats from concurrent access */ MEM_STATS_INC_LOCKED(illegal); @@ -442,12 +474,26 @@ mem_free(void *rmem) } /* protect the heap from concurrent access */ LWIP_MEM_FREE_PROTECT(); - /* Get the corresponding struct mem ... */ - /* cast through void* to get rid of alignment warnings */ - mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); - /* ... which has to be in a used state ... */ - LWIP_ASSERT("mem_free: mem->used", mem->used); - /* ... and is now unused. */ + /* mem has to be in a used state */ + if (!mem->used) { + LWIP_MEM_ILLEGAL_FREE("mem_free: illegal memory: double free"); + LWIP_MEM_FREE_UNPROTECT(); + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory: double free?\n")); + /* protect mem stats from concurrent access */ + MEM_STATS_INC_LOCKED(illegal); + return; + } + + if (!mem_link_valid(mem)) { + LWIP_MEM_ILLEGAL_FREE("mem_free: illegal memory: non-linked: double free"); + LWIP_MEM_FREE_UNPROTECT(); + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory: non-linked: double free?\n")); + /* protect mem stats from concurrent access */ + MEM_STATS_INC_LOCKED(illegal); + return; + } + + /* mem is now unused. */ mem->used = 0; if (mem < lfree) { diff --git a/lwip/src/core/tcp_in.c b/lwip/src/core/tcp_in.c index 5f502a1..c4ee51d 100644 --- a/lwip/src/core/tcp_in.c +++ b/lwip/src/core/tcp_in.c @@ -96,9 +96,9 @@ static int tcp_input_delayed_close(struct tcp_pcb *pcb); #if LWIP_TCP_SACK_OUT static void tcp_add_sack(struct tcp_pcb *pcb, u32_t left, u32_t right); static void tcp_remove_sacks_lt(struct tcp_pcb *pcb, u32_t seq); -#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS +#if defined(TCP_OOSEQ_BYTES_LIMIT) || defined(TCP_OOSEQ_PBUFS_LIMIT) static void tcp_remove_sacks_gt(struct tcp_pcb *pcb, u32_t seq); -#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ +#endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ #endif /* LWIP_TCP_SACK_OUT */ /** @@ -1112,19 +1112,9 @@ tcp_free_acked_segments(struct tcp_pcb *pcb, struct tcp_seg *seg_list, const cha static void tcp_receive(struct tcp_pcb *pcb) { -#if TCP_QUEUE_OOSEQ || TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS - struct tcp_seg *next; -#endif -#if TCP_QUEUE_OOSEQ - struct tcp_seg *prev, *cseg; -#endif /* TCP_QUEUE_OOSEQ */ s16_t m; u32_t right_wnd_edge; int found_dupack = 0; -#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS - u32_t ooseq_blen; - u16_t ooseq_qlen; -#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED); @@ -1481,21 +1471,22 @@ tcp_receive(struct tcp_pcb *pcb) tcp_seg_free(old_ooseq); } } else { - next = pcb->ooseq; + struct tcp_seg *next = pcb->ooseq; /* Remove all segments on ooseq that are covered by inseg already. * FIN is copied from ooseq to inseg if present. */ while (next && TCP_SEQ_GEQ(seqno + tcplen, next->tcphdr->seqno + next->len)) { + struct tcp_seg *tmp; /* inseg cannot have FIN here (already processed above) */ if ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0 && (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) { TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN); tcplen = TCP_TCPLEN(&inseg); } - prev = next; + tmp = next; next = next->next; - tcp_seg_free(prev); + tcp_seg_free(tmp); } /* Now trim right side of inseg if it overlaps with the first * segment on ooseq */ @@ -1552,7 +1543,7 @@ tcp_receive(struct tcp_pcb *pcb) while (pcb->ooseq != NULL && pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { - cseg = pcb->ooseq; + struct tcp_seg *cseg = pcb->ooseq; seqno = pcb->ooseq->tcphdr->seqno; pcb->rcv_nxt += TCP_TCPLEN(cseg); @@ -1653,7 +1644,7 @@ tcp_receive(struct tcp_pcb *pcb) It may start before the newly received segment (possibly adjusted below). */ u32_t sackbeg = TCP_SEQ_LT(seqno, pcb->ooseq->tcphdr->seqno) ? seqno : pcb->ooseq->tcphdr->seqno; #endif /* LWIP_TCP_SACK_OUT */ - prev = NULL; + struct tcp_seg *next, *prev = NULL; for (next = pcb->ooseq; next != NULL; next = next->next) { if (seqno == next->tcphdr->seqno) { /* The sequence number of the incoming segment is the @@ -1664,7 +1655,7 @@ tcp_receive(struct tcp_pcb *pcb) /* The incoming segment is larger than the old segment. We replace some segments with the new one. */ - cseg = tcp_seg_copy(&inseg); + struct tcp_seg *cseg = tcp_seg_copy(&inseg); if (cseg != NULL) { if (prev != NULL) { prev->next = cseg; @@ -1687,7 +1678,7 @@ tcp_receive(struct tcp_pcb *pcb) than the sequence number of the first segment on the queue. We put the incoming segment first on the queue. */ - cseg = tcp_seg_copy(&inseg); + struct tcp_seg *cseg = tcp_seg_copy(&inseg); if (cseg != NULL) { pcb->ooseq = cseg; tcp_oos_insert_segment(cseg, next); @@ -1703,7 +1694,7 @@ tcp_receive(struct tcp_pcb *pcb) the next segment on ->ooseq. We trim trim the previous segment, delete next segments that included in received segment and trim received, if needed. */ - cseg = tcp_seg_copy(&inseg); + struct tcp_seg *cseg = tcp_seg_copy(&inseg); if (cseg != NULL) { if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) { /* We need to trim the prev segment. */ @@ -1796,37 +1787,55 @@ tcp_receive(struct tcp_pcb *pcb) } #endif /* LWIP_TCP_SACK_OUT */ } -#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS - /* Check that the data on ooseq doesn't exceed one of the limits - and throw away everything above that limit. */ - ooseq_blen = 0; - ooseq_qlen = 0; - prev = NULL; - for (next = pcb->ooseq; next != NULL; prev = next, next = next->next) { - struct pbuf *p = next->p; - ooseq_blen += p->tot_len; - ooseq_qlen += pbuf_clen(p); - if ((ooseq_blen > TCP_OOSEQ_MAX_BYTES) || - (ooseq_qlen > TCP_OOSEQ_MAX_PBUFS)) { -#if LWIP_TCP_SACK_OUT - if (pcb->flags & TF_SACK) { - /* Let's remove all SACKs from next's seqno up. */ - tcp_remove_sacks_gt(pcb, next->tcphdr->seqno); +#if defined(TCP_OOSEQ_BYTES_LIMIT) || defined(TCP_OOSEQ_PBUFS_LIMIT) + { + /* Check that the data on ooseq doesn't exceed one of the limits + and throw away everything above that limit. */ +#ifdef TCP_OOSEQ_BYTES_LIMIT + const u32_t ooseq_max_blen = TCP_OOSEQ_BYTES_LIMIT(pcb); + u32_t ooseq_blen = 0; +#endif +#ifdef TCP_OOSEQ_PBUFS_LIMIT + const u16_t ooseq_max_qlen = TCP_OOSEQ_PBUFS_LIMIT(pcb); + u16_t ooseq_qlen = 0; +#endif + struct tcp_seg *next, *prev = NULL; + for (next = pcb->ooseq; next != NULL; prev = next, next = next->next) { + struct pbuf *p = next->p; + int stop_here = 0; +#ifdef TCP_OOSEQ_BYTES_LIMIT + ooseq_blen += p->tot_len; + if (ooseq_blen > ooseq_max_blen) { + stop_here = 1; + } +#endif +#ifdef TCP_OOSEQ_PBUFS_LIMIT + ooseq_qlen += pbuf_clen(p); + if (ooseq_qlen > ooseq_max_qlen) { + stop_here = 1; } +#endif + if (stop_here) { +#if LWIP_TCP_SACK_OUT + if (pcb->flags & TF_SACK) { + /* Let's remove all SACKs from next's seqno up. */ + tcp_remove_sacks_gt(pcb, next->tcphdr->seqno); + } #endif /* LWIP_TCP_SACK_OUT */ - /* too much ooseq data, dump this and everything after it */ - tcp_segs_free(next); - if (prev == NULL) { - /* first ooseq segment is too much, dump the whole queue */ - pcb->ooseq = NULL; - } else { - /* just dump 'next' and everything after it */ - prev->next = NULL; + /* too much ooseq data, dump this and everything after it */ + tcp_segs_free(next); + if (prev == NULL) { + /* first ooseq segment is too much, dump the whole queue */ + pcb->ooseq = NULL; + } else { + /* just dump 'next' and everything after it */ + prev->next = NULL; + } + break; } - break; } } -#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ +#endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ #endif /* TCP_QUEUE_OOSEQ */ /* We send the ACK packet after we've (potentially) dealt with SACKs, @@ -2092,7 +2101,7 @@ tcp_remove_sacks_lt(struct tcp_pcb *pcb, u32_t seq) } } -#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS +#if defined(TCP_OOSEQ_BYTES_LIMIT) || defined(TCP_OOSEQ_PBUFS_LIMIT) /** * Called to remove a range of SACKs. * @@ -2131,7 +2140,7 @@ tcp_remove_sacks_gt(struct tcp_pcb *pcb, u32_t seq) pcb->rcv_sacks[i].left = pcb->rcv_sacks[i].right = 0; } } -#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ +#endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ #endif /* LWIP_TCP_SACK_OUT */ diff --git a/lwip/src/core/tcp_out.c b/lwip/src/core/tcp_out.c index f72c03a..58fdaac 100644 --- a/lwip/src/core/tcp_out.c +++ b/lwip/src/core/tcp_out.c @@ -1221,15 +1221,15 @@ tcp_output(struct tcp_pcb *pcb) TCPH_SET_FLAG(seg->tcphdr, TCP_ACK); } -#if TCP_OVERSIZE_DBGCHECK - seg->oversize_left = 0; -#endif /* TCP_OVERSIZE_DBGCHECK */ err = tcp_output_segment(seg, pcb, netif); if (err != ERR_OK) { /* segment could not be sent, for whatever reason */ tcp_set_flags(pcb, TF_NAGLEMEMERR); return err; } +#if TCP_OVERSIZE_DBGCHECK + seg->oversize_left = 0; +#endif /* TCP_OVERSIZE_DBGCHECK */ pcb->unsent = seg->next; if (pcb->state != SYN_SENT) { tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); diff --git a/lwip/src/include/lwip/apps/mqtt_opts.h b/lwip/src/include/lwip/apps/mqtt_opts.h index ffefacd..4226d21 100644 --- a/lwip/src/include/lwip/apps/mqtt_opts.h +++ b/lwip/src/include/lwip/apps/mqtt_opts.h @@ -39,7 +39,7 @@ #include "lwip/opt.h" -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif diff --git a/lwip/src/include/lwip/icmp6.h b/lwip/src/include/lwip/icmp6.h index 374ff44..0ccb789 100644 --- a/lwip/src/include/lwip/icmp6.h +++ b/lwip/src/include/lwip/icmp6.h @@ -59,7 +59,7 @@ void icmp6_packet_too_big(struct pbuf *p, u32_t mtu); void icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c); void icmp6_time_exceeded_with_addrs(struct pbuf *p, enum icmp6_te_code c, const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr); -void icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer); +void icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, const void *pointer); #endif /* LWIP_ICMP6 && LWIP_IPV6 */ diff --git a/lwip/src/include/lwip/opt.h b/lwip/src/include/lwip/opt.h index 465a9c7..420985c 100644 --- a/lwip/src/include/lwip/opt.h +++ b/lwip/src/include/lwip/opt.h @@ -1300,22 +1300,52 @@ #endif /** - * TCP_OOSEQ_MAX_BYTES: The maximum number of bytes queued on ooseq per pcb. - * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==1. + * TCP_OOSEQ_MAX_BYTES: The default maximum number of bytes queued on ooseq per + * pcb if TCP_OOSEQ_BYTES_LIMIT is not defined. Default is 0 (no limit). + * Only valid for TCP_QUEUE_OOSEQ==1. */ #if !defined TCP_OOSEQ_MAX_BYTES || defined __DOXYGEN__ #define TCP_OOSEQ_MAX_BYTES 0 #endif /** - * TCP_OOSEQ_MAX_PBUFS: The maximum number of pbufs queued on ooseq per pcb. - * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==1. + * TCP_OOSEQ_BYTES_LIMIT(pcb): Return the maximum number of bytes to be queued + * on ooseq per pcb, given the pcb. Only valid for TCP_QUEUE_OOSEQ==1 && + * TCP_OOSEQ_MAX_BYTES==1. + * Use this to override TCP_OOSEQ_MAX_BYTES to a dynamic value per pcb. + */ +#if !defined TCP_OOSEQ_BYTES_LIMIT +#if TCP_OOSEQ_MAX_BYTES +#define TCP_OOSEQ_BYTES_LIMIT(pcb) TCP_OOSEQ_MAX_BYTES +#elif defined __DOXYGEN__ +#define TCP_OOSEQ_BYTES_LIMIT(pcb) +#endif +#endif + +/** + * TCP_OOSEQ_MAX_PBUFS: The default maximum number of pbufs queued on ooseq per + * pcb if TCP_OOSEQ_BYTES_LIMIT is not defined. Default is 0 (no limit). + * Only valid for TCP_QUEUE_OOSEQ==1. */ #if !defined TCP_OOSEQ_MAX_PBUFS || defined __DOXYGEN__ #define TCP_OOSEQ_MAX_PBUFS 0 #endif /** + * TCP_OOSEQ_PBUFS_LIMIT(pcb): Return the maximum number of pbufs to be queued + * on ooseq per pcb, given the pcb. Only valid for TCP_QUEUE_OOSEQ==1 && + * TCP_OOSEQ_MAX_PBUFS==1. + * Use this to override TCP_OOSEQ_MAX_PBUFS to a dynamic value per pcb. + */ +#if !defined TCP_OOSEQ_PBUFS_LIMIT +#if TCP_OOSEQ_MAX_PBUFS +#define TCP_OOSEQ_PBUFS_LIMIT(pcb) TCP_OOSEQ_MAX_PBUFS +#elif defined __DOXYGEN__ +#define TCP_OOSEQ_PBUFS_LIMIT(pcb) +#endif +#endif + +/** * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. */ #if !defined TCP_LISTEN_BACKLOG || defined __DOXYGEN__ @@ -1986,6 +2016,14 @@ #if !defined LWIP_SOCKET_SELECT || defined __DOXYGEN__ #define LWIP_SOCKET_SELECT 1 #endif + +/** + * LWIP_SOCKET_POLL==1 (default): enable poll() for sockets (including + * struct pollfd, nfds_t, and constants) + */ +#if !defined LWIP_SOCKET_POLL || defined __DOXYGEN__ +#define LWIP_SOCKET_POLL 1 +#endif /** * @} */ diff --git a/lwip/src/include/lwip/priv/memp_std.h b/lwip/src/include/lwip/priv/memp_std.h index 4ad0b6d..c694194 100644 --- a/lwip/src/include/lwip/priv/memp_std.h +++ b/lwip/src/include/lwip/priv/memp_std.h @@ -78,9 +78,9 @@ LWIP_MEMPOOL(DNS_API_MSG, MEMP_NUM_DNS_API_MSG, sizeof(struct dns_api_msg #if LWIP_SOCKET && !LWIP_TCPIP_CORE_LOCKING LWIP_MEMPOOL(SOCKET_SETGETSOCKOPT_DATA, MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA, sizeof(struct lwip_setgetsockopt_data), "SOCKET_SETGETSOCKOPT_DATA") #endif -#if LWIP_SOCKET && LWIP_SOCKET_SELECT +#if LWIP_SOCKET && (LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL) LWIP_MEMPOOL(SELECT_CB, MEMP_NUM_SELECT_CB, sizeof(struct lwip_select_cb), "SELECT_CB") -#endif /* LWIP_SOCKET && LWIP_SOCKET_SELECT */ +#endif /* LWIP_SOCKET && (LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL) */ #if LWIP_NETIF_API LWIP_MEMPOOL(NETIFAPI_MSG, MEMP_NUM_NETIFAPI_MSG, sizeof(struct netifapi_msg), "NETIFAPI_MSG") #endif diff --git a/lwip/src/include/lwip/priv/sockets_priv.h b/lwip/src/include/lwip/priv/sockets_priv.h index 9918aa2..d8f9904 100644 --- a/lwip/src/include/lwip/priv/sockets_priv.h +++ b/lwip/src/include/lwip/priv/sockets_priv.h @@ -69,7 +69,7 @@ struct lwip_sock { struct netconn *conn; /** data that was left from the previous read */ union lwip_sock_lastdata lastdata; -#if LWIP_SOCKET_SELECT +#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL /** number of times data was received, set by event_callback(), tested by the receive and select functions */ s16_t rcvevent; @@ -80,7 +80,7 @@ struct lwip_sock { u16_t errevent; /** counter of how many threads are waiting for this socket using select */ SELWAIT_T select_waiting; -#endif /* LWIP_SOCKET_SELECT */ +#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ #if LWIP_NETCONN_FULLDUPLEX /* counter of how many threads are using a struct lwip_sock (not the 'int') */ u8_t fd_used; @@ -133,6 +133,8 @@ struct lwip_setgetsockopt_data { struct lwip_sock* lwip_socket_dbg_get_socket(int fd); +#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL + #if LWIP_NETCONN_SEM_PER_THREAD #define SELECT_SEM_T sys_sem_t* #define SELECT_SEM_PTR(sem) (sem) @@ -147,17 +149,26 @@ struct lwip_select_cb { struct lwip_select_cb *next; /** Pointer to the previous waiting task */ struct lwip_select_cb *prev; +#if LWIP_SOCKET_SELECT /** readset passed to select */ fd_set *readset; /** writeset passed to select */ fd_set *writeset; /** unimplemented: exceptset passed to select */ fd_set *exceptset; +#endif /* LWIP_SOCKET_SELECT */ +#if LWIP_SOCKET_POLL + /** fds passed to poll; NULL if select */ + struct pollfd *poll_fds; + /** nfds passed to poll; 0 if select */ + nfds_t poll_nfds; +#endif /* LWIP_SOCKET_POLL */ /** don't signal the same semaphore twice: set to 1 when signalled */ int sem_signalled; /** semaphore to wake up a task waiting for select */ SELECT_SEM_T sem; }; +#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ #endif /* LWIP_SOCKET */ diff --git a/lwip/src/include/lwip/prot/ip6.h b/lwip/src/include/lwip/prot/ip6.h index 6e1e263..996bcca 100644 --- a/lwip/src/include/lwip/prot/ip6.h +++ b/lwip/src/include/lwip/prot/ip6.h @@ -94,13 +94,50 @@ PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif +#define IP6H_V(hdr) ((lwip_ntohl((hdr)->_v_tc_fl) >> 28) & 0x0f) +#define IP6H_TC(hdr) ((lwip_ntohl((hdr)->_v_tc_fl) >> 20) & 0xff) +#define IP6H_FL(hdr) (lwip_ntohl((hdr)->_v_tc_fl) & 0x000fffff) +#define IP6H_PLEN(hdr) (lwip_ntohs((hdr)->_plen)) +#define IP6H_NEXTH(hdr) ((hdr)->_nexth) +#define IP6H_NEXTH_P(hdr) ((u8_t *)(hdr) + 6) +#define IP6H_HOPLIM(hdr) ((hdr)->_hoplim) +#define IP6H_VTCFL_SET(hdr, v, tc, fl) (hdr)->_v_tc_fl = (lwip_htonl((((u32_t)(v)) << 28) | (((u32_t)(tc)) << 20) | (fl))) +#define IP6H_PLEN_SET(hdr, plen) (hdr)->_plen = lwip_htons(plen) +#define IP6H_NEXTH_SET(hdr, nexth) (hdr)->_nexth = (nexth) +#define IP6H_HOPLIM_SET(hdr, hl) (hdr)->_hoplim = (u8_t)(hl) + +/* ipv6 extended options header */ +#define IP6_PAD1_OPTION 0 +#define IP6_PADN_OPTION 1 +#define IP6_ROUTER_ALERT_OPTION 5 +#define IP6_JUMBO_OPTION 194 +#define IP6_HOME_ADDRESS_OPTION 201 +#define IP6_ROUTER_ALERT_DLEN 2 +#define IP6_ROUTER_ALERT_VALUE_MLD 0 + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_opt_hdr { + /* router alert option type */ + PACK_STRUCT_FLD_8(u8_t _opt_type); + /* router alert option data len */ + PACK_STRUCT_FLD_8(u8_t _opt_dlen); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define IP6_OPT_HLEN 2 +#define IP6_OPT_TYPE_ACTION(hdr) ((((hdr)->_opt_type) >> 6) & 0x3) +#define IP6_OPT_TYPE_CHANGE(hdr) ((((hdr)->_opt_type) >> 5) & 0x1) +#define IP6_OPT_TYPE(hdr) ((hdr)->_opt_type) +#define IP6_OPT_DLEN(hdr) ((hdr)->_opt_dlen) + +/* Hop-by-Hop header. */ +#define IP6_HBH_HLEN 2 -/* Hop-by-hop router alert option. */ -#define IP6_HBH_HLEN 8 -#define IP6_PAD1_OPTION 0 -#define IP6_PADN_ALERT_OPTION 1 -#define IP6_ROUTER_ALERT_OPTION 5 -#define IP6_ROUTER_ALERT_VALUE_MLD 0 #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif @@ -108,28 +145,65 @@ PACK_STRUCT_BEGIN struct ip6_hbh_hdr { /* next header */ PACK_STRUCT_FLD_8(u8_t _nexth); - /* header length */ + /* header length in 8-octet units */ PACK_STRUCT_FLD_8(u8_t _hlen); - /* router alert option type */ - PACK_STRUCT_FLD_8(u8_t _ra_opt_type); - /* router alert option data len */ - PACK_STRUCT_FLD_8(u8_t _ra_opt_dlen); - /* router alert option data */ - PACK_STRUCT_FIELD(u16_t _ra_opt_data); - /* PadN option type */ - PACK_STRUCT_FLD_8(u8_t _padn_opt_type); - /* PadN option data len */ - PACK_STRUCT_FLD_8(u8_t _padn_opt_dlen); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif +#define IP6_HBH_NEXTH(hdr) ((hdr)->_nexth) + +/* Destination header. */ +#define IP6_DEST_HLEN 2 + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_dest_hdr { + /* next header */ + PACK_STRUCT_FLD_8(u8_t _nexth); + /* header length in 8-octet units */ + PACK_STRUCT_FLD_8(u8_t _hlen); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define IP6_DEST_NEXTH(hdr) ((hdr)->_nexth) + +/* Routing header */ +#define IP6_ROUT_TYPE2 2 +#define IP6_ROUT_RPL 3 + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_rout_hdr { + /* next header */ + PACK_STRUCT_FLD_8(u8_t _nexth); + /* reserved */ + PACK_STRUCT_FLD_8(u8_t _hlen); + /* fragment offset */ + PACK_STRUCT_FIELD(u8_t _routing_type); + /* fragmented packet identification */ + PACK_STRUCT_FIELD(u8_t _segments_left); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define IP6_ROUT_NEXTH(hdr) ((hdr)->_nexth) +#define IP6_ROUT_TYPE(hdr) ((hdr)->_routing_type) +#define IP6_ROUT_SEG_LEFT(hdr) ((hdr)->_segments_left) /* Fragment header. */ #define IP6_FRAG_HLEN 8 #define IP6_FRAG_OFFSET_MASK 0xfff8 #define IP6_FRAG_MORE_FLAG 0x0001 + #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif @@ -148,19 +222,9 @@ PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif - -#define IP6H_V(hdr) ((lwip_ntohl((hdr)->_v_tc_fl) >> 28) & 0x0f) -#define IP6H_TC(hdr) ((lwip_ntohl((hdr)->_v_tc_fl) >> 20) & 0xff) -#define IP6H_FL(hdr) (lwip_ntohl((hdr)->_v_tc_fl) & 0x000fffff) -#define IP6H_PLEN(hdr) (lwip_ntohs((hdr)->_plen)) -#define IP6H_NEXTH(hdr) ((hdr)->_nexth) -#define IP6H_NEXTH_P(hdr) ((u8_t *)(hdr) + 6) -#define IP6H_HOPLIM(hdr) ((hdr)->_hoplim) - -#define IP6H_VTCFL_SET(hdr, v, tc, fl) (hdr)->_v_tc_fl = (lwip_htonl((((u32_t)(v)) << 28) | (((u32_t)(tc)) << 20) | (fl))) -#define IP6H_PLEN_SET(hdr, plen) (hdr)->_plen = lwip_htons(plen) -#define IP6H_NEXTH_SET(hdr, nexth) (hdr)->_nexth = (nexth) -#define IP6H_HOPLIM_SET(hdr, hl) (hdr)->_hoplim = (u8_t)(hl) +#define IP6_FRAG_NEXTH(hdr) ((hdr)->_nexth) +#define IP6_FRAG_MBIT(hdr) (lwip_ntohs((hdr)->_fragment_offset) & 0x1) +#define IP6_FRAG_ID(hdr) (lwip_ntohl((hdr)->_identification)) #ifdef __cplusplus } diff --git a/lwip/src/include/lwip/prot/mld6.h b/lwip/src/include/lwip/prot/mld6.h index be3a006..71f1dcb 100644 --- a/lwip/src/include/lwip/prot/mld6.h +++ b/lwip/src/include/lwip/prot/mld6.h @@ -44,6 +44,7 @@ extern "C" { #endif +#define MLD6_HBH_HLEN 8 /** Multicast listener report/query/done message header. */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" diff --git a/lwip/src/include/lwip/sockets.h b/lwip/src/include/lwip/sockets.h index d51cfb6..07d15ec 100644 --- a/lwip/src/include/lwip/sockets.h +++ b/lwip/src/include/lwip/sockets.h @@ -486,6 +486,23 @@ typedef struct fd_set #error "external FD_SETSIZE too small for number of sockets" #endif /* FD_SET */ +/* poll-related defines and types */ +/* @todo: find a better way to guard the definition of these defines and types if already defined */ +#if !defined(POLLIN) && !defined(POLLOUT) +#define POLLIN 1 +#define POLLOUT 2 +#define POLLERR 4 +#define POLLNVAL 8 +/* No support for POLLPRI, POLLHUP, POLLMSG, POLLRDBAND, POLLWRBAND. */ +typedef int nfds_t; +struct pollfd +{ + int fd; + short events; + short revents; +}; +#endif + /** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided * by your system, set this to 0 and include <sys/time.h> in cc.h */ #ifndef LWIP_TIMEVAL_PRIVATE @@ -522,8 +539,13 @@ void lwip_socket_thread_cleanup(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: destro #define lwip_sendmsg sendmsg #define lwip_sendto sendto #define lwip_socket socket +#if LWIP_SOCKET_SELECT #define lwip_select select -#define lwip_ioctlsocket ioctl +#endif +#if LWIP_SOCKET_POLL +#define lwip_poll poll +#endif +#define lwip_ioctl ioctlsocket #define lwip_inet_ntop inet_ntop #define lwip_inet_pton inet_pton @@ -536,7 +558,9 @@ void lwip_socket_thread_cleanup(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: destro #define lwip_close close #define closesocket(s) close(s) int fcntl(int s, int cmd, ...); +#undef lwip_ioctl #define lwip_ioctl ioctl +#define ioctlsocket ioctl #endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ #endif /* LWIP_COMPAT_SOCKETS == 2 */ @@ -567,6 +591,9 @@ ssize_t lwip_writev(int s, const struct iovec *iov, int iovcnt); int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout); #endif +#if LWIP_SOCKET_POLL +int lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout); +#endif int lwip_ioctl(int s, long cmd, void *argp); int lwip_fcntl(int s, int cmd, int val); const char *lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size); @@ -608,8 +635,14 @@ int lwip_inet_pton(int af, const char *src, void *dst); #define sendto(s,dataptr,size,flags,to,tolen) lwip_sendto(s,dataptr,size,flags,to,tolen) /** @ingroup socket */ #define socket(domain,type,protocol) lwip_socket(domain,type,protocol) +#if LWIP_SOCKET_SELECT /** @ingroup socket */ #define select(maxfdp1,readset,writeset,exceptset,timeout) lwip_select(maxfdp1,readset,writeset,exceptset,timeout) +#endif +#if LWIP_SOCKET_POLL +/** @ingroup socket */ +#define poll(fds,nfds,timeout) lwip_poll(fds,nfds,timeout) +#endif /** @ingroup socket */ #define ioctlsocket(s,cmd,argp) lwip_ioctl(s,cmd,argp) /** @ingroup socket */ diff --git a/lwip/test/unit/core/test_mem.c b/lwip/test/unit/core/test_mem.c index c362758..2aeb20c 100644 --- a/lwip/test/unit/core/test_mem.c +++ b/lwip/test/unit/core/test_mem.c @@ -111,13 +111,114 @@ START_TEST(test_mem_random) } END_TEST +START_TEST(test_mem_invalid_free) +{ + u8_t *ptr, *ptr_low, *ptr_high; + LWIP_UNUSED_ARG(_i); + + fail_unless(lwip_stats.mem.used == 0); + fail_unless(lwip_stats.mem.illegal == 0); + + ptr = (u8_t *)mem_malloc(1); + fail_unless(ptr != NULL); + fail_unless(lwip_stats.mem.used != 0); + + ptr_low = ptr - 0x10; + mem_free(ptr_low); + fail_unless(lwip_stats.mem.illegal == 1); + lwip_stats.mem.illegal = 0; + + ptr_high = ptr + (MEM_SIZE * 2); + mem_free(ptr_high); + fail_unless(lwip_stats.mem.illegal == 1); + lwip_stats.mem.illegal = 0; + + mem_free(ptr); + fail_unless(lwip_stats.mem.illegal == 0); + fail_unless(lwip_stats.mem.used == 0); +} +END_TEST + +START_TEST(test_mem_double_free) +{ + u8_t *ptr1b, *ptr1, *ptr2, *ptr3; + LWIP_UNUSED_ARG(_i); + + fail_unless(lwip_stats.mem.used == 0); + fail_unless(lwip_stats.mem.illegal == 0); + + ptr1 = (u8_t *)mem_malloc(1); + fail_unless(ptr1 != NULL); + fail_unless(lwip_stats.mem.used != 0); + + ptr2 = (u8_t *)mem_malloc(1); + fail_unless(ptr2 != NULL); + fail_unless(lwip_stats.mem.used != 0); + + ptr3 = (u8_t *)mem_malloc(1); + fail_unless(ptr3 != NULL); + fail_unless(lwip_stats.mem.used != 0); + + /* free the middle mem */ + mem_free(ptr2); + fail_unless(lwip_stats.mem.illegal == 0); + + /* double-free of middle mem: should fail */ + mem_free(ptr2); + fail_unless(lwip_stats.mem.illegal == 1); + lwip_stats.mem.illegal = 0; + + /* free upper memory and try again */ + mem_free(ptr3); + fail_unless(lwip_stats.mem.illegal == 0); + + mem_free(ptr2); + fail_unless(lwip_stats.mem.illegal == 1); + lwip_stats.mem.illegal = 0; + + /* free lower memory and try again */ + mem_free(ptr1); + fail_unless(lwip_stats.mem.illegal == 0); + fail_unless(lwip_stats.mem.used == 0); + + mem_free(ptr2); + fail_unless(lwip_stats.mem.illegal == 1); + fail_unless(lwip_stats.mem.used == 0); + lwip_stats.mem.illegal = 0; + + /* reallocate lowest memory, now overlapping already freed ptr2 */ +#ifndef MIN_SIZE +#define MIN_SIZE 12 +#endif + ptr1b = (u8_t *)mem_malloc(MIN_SIZE * 2); + fail_unless(ptr1b != NULL); + fail_unless(lwip_stats.mem.used != 0); + + mem_free(ptr2); + fail_unless(lwip_stats.mem.illegal == 1); + lwip_stats.mem.illegal = 0; + + memset(ptr1b, 1, MIN_SIZE * 2); + + mem_free(ptr2); + fail_unless(lwip_stats.mem.illegal == 1); + lwip_stats.mem.illegal = 0; + + mem_free(ptr1b); + fail_unless(lwip_stats.mem.illegal == 0); + fail_unless(lwip_stats.mem.used == 0); +} +END_TEST + /** Create the suite including all tests for this module */ Suite * mem_suite(void) { testfunc tests[] = { TESTFUNC(test_mem_one), - TESTFUNC(test_mem_random) + TESTFUNC(test_mem_random), + TESTFUNC(test_mem_invalid_free), + TESTFUNC(test_mem_double_free) }; return create_suite("MEM", tests, sizeof(tests)/sizeof(testfunc), mem_setup, mem_teardown); } diff --git a/lwip/test/unit/lwipopts.h b/lwip/test/unit/lwipopts.h index 7b82fd6..953c5d0 100644 --- a/lwip/test/unit/lwipopts.h +++ b/lwip/test/unit/lwipopts.h @@ -70,4 +70,7 @@ /* MIB2 stats are required to check IPv4 reassembly results */ #define MIB2_STATS 1 +/* Check lwip_stats.mem.illegal instead of asserting */ +#define LWIP_MEM_ILLEGAL_FREE(msg) /* to nothing */ + #endif /* LWIP_HDR_LWIPOPTS_H */ |