From 48e62e25e9a3223cf7e07f9bb51c8bc2aac9ec19 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Fri, 21 Dec 2007 14:59:10 +0000 Subject: [PATCH] sys.h, api_lib.c, api_msg.c, sockets.c: fix bug #21698: "netconn->recv_avail is not protected" by using new macros for interlocked access to modify/test netconn->recv_avail. --- CHANGELOG | 7 ++++++- src/api/api_lib.c | 4 ++-- src/api/api_msg.c | 18 +++++++++++++----- src/api/sockets.c | 2 +- src/include/lwip/sys.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 64 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2b1e44fb..f89222ac 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -526,8 +526,13 @@ HISTORY ++ Bug fixes: + 2007-12-21 Simon Goldschmidt + * sys.h, api_lib.c, api_msg.c, sockets.c: fix bug #21698: "netconn->recv_avail + is not protected" by using new macros for interlocked access to modify/test + netconn->recv_avail. + 2007-12-20 Kieran Mansley (based on patch from Oleg Tyshev) - * tcp_in.c: fix bug# 21535 (nrtx not reset correctly in SYN_SENT stat)e + * tcp_in.c: fix bug# 21535 (nrtx not reset correctly in SYN_SENT state) 2007-12-20 Kieran Mansley (based on patch from Per-Henrik Lundbolm) * tcp.c, tcp_in.c, tcp_out.c, tcp.h: fix bug #20199 (better handling diff --git a/src/api/api_lib.c b/src/api/api_lib.c index d832db4f..bc6acd4f 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -358,7 +358,7 @@ netconn_recv(struct netconn *conn) if (p != NULL) { len = p->tot_len; - conn->recv_avail -= len; + SYS_ARCH_DEC(conn->recv_avail, len); } else { len = 0; } @@ -401,7 +401,7 @@ netconn_recv(struct netconn *conn) sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, 0); #endif /* LWIP_SO_RCVTIMEO*/ if (buf!=NULL) { - conn->recv_avail -= buf->p->tot_len; + SYS_ARCH_DEC(conn->recv_avail, buf->p->tot_len); /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len); } diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 91171c82..373c9989 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -72,12 +72,16 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, { struct netbuf *buf; struct netconn *conn; +#if LWIP_SO_RCVBUF + int recv_avail; +#endif /* LWIP_SO_RCVBUF */ conn = arg; #if LWIP_SO_RCVBUF + SYS_ARCH_GET(conn->recv_avail, recv_avail); if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) && - (((int)(conn->recv_avail) + (int)(p->tot_len)) <= conn->recv_bufsize)) { + ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) { #else /* LWIP_SO_RCVBUF */ if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) { #endif /* LWIP_SO_RCVBUF */ @@ -91,7 +95,7 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, buf->addr = addr; buf->port = pcb->protocol; - conn->recv_avail += p->tot_len; + SYS_ARCH_INC(conn->recv_avail, p->tot_len); /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len); sys_mbox_post(conn->recvmbox, buf); @@ -114,6 +118,9 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, { struct netbuf *buf; struct netconn *conn; +#if LWIP_SO_RCVBUF + int recv_avail; +#endif /* LWIP_SO_RCVBUF */ LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); @@ -122,8 +129,9 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); #if LWIP_SO_RCVBUF + SYS_ARCH_GET(conn->recv_avail, recv_avail); if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) || - (((int)(conn->recv_avail) + (int)(p->tot_len)) > conn->recv_bufsize)) { + ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { #else /* LWIP_SO_RCVBUF */ if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) { #endif /* LWIP_SO_RCVBUF */ @@ -142,7 +150,7 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, buf->port = port; } - conn->recv_avail += p->tot_len; + SYS_ARCH_INC(conn->recv_avail, p->tot_len); /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len); sys_mbox_post(conn->recvmbox, buf); @@ -176,7 +184,7 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) conn->err = err; if (p != NULL) { len = p->tot_len; - conn->recv_avail += len; + SYS_ARCH_INC(conn->recv_avail, len); } else { len = 0; } diff --git a/src/api/sockets.c b/src/api/sockets.c index 5cb73e2c..cea473c6 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -1872,7 +1872,7 @@ lwip_ioctl(int s, long cmd, void *argp) return -1; } - *((u16_t*)argp) = sock->conn->recv_avail; + SYS_ARCH_GET(sock->conn->recv_avail, *((u16_t*)argp)); /* Check if there is data left from the last recv operation. /maq 041215 */ if (sock->lastdata) { diff --git a/src/include/lwip/sys.h b/src/include/lwip/sys.h index 052ee046..6927886e 100644 --- a/src/include/lwip/sys.h +++ b/src/include/lwip/sys.h @@ -193,6 +193,48 @@ void sys_arch_unprotect(sys_prot_t pval); #endif /* SYS_ARCH_PROTECT */ +/* + * Macros to set/get and increase/decrease variables in a thread-safe way. + * Use these for accessing variable that are used from more than one thread. + */ + +#ifndef SYS_ARCH_INC +#define SYS_ARCH_INC(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var += val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_INC */ + +#ifndef SYS_ARCH_DEC +#define SYS_ARCH_DEC(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var -= val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_DEC */ + +#ifndef SYS_ARCH_GET +#define SYS_ARCH_GET(var, ret) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + ret = var; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_GET */ + +#ifndef SYS_ARCH_SET +#define SYS_ARCH_SET(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var = val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_SET */ + + #ifdef __cplusplus } #endif