Author: Artem Pisarenko src/api/api_lib.c | 232 +++++++++++++++++++++++++++++--------------- src/api/api_msg.c | 62 ++++++------ src/api/netifapi.c | 83 ++++++++++------ src/api/sockets.c | 95 ++++++------------ src/api/tcpip.c | 26 +++-- src/core/dhcp.c | 15 ++- src/core/memp.c | 1 + src/include/lwip/api_msg.h | 16 +-- src/include/lwip/memp_std.h | 10 ++ src/include/lwip/netifapi.h | 6 +- src/include/lwip/opt.h | 9 ++ src/include/lwip/sockets.h | 45 +++++++++ 12 files changed, 376 insertions(+), 224 deletions(-) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index adaaad4..a34a4a3 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -68,14 +68,18 @@ struct netconn* netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) { struct netconn *conn; - struct api_msg msg; conn = netconn_alloc(t, callback); if (conn != NULL) { err_t err; - msg.msg.msg.n.proto = proto; - msg.msg.conn = conn; - TCPIP_APIMSG((&msg), lwip_netconn_do_newconn, err); + struct api_msg *msg = (struct api_msg *)memp_malloc(MEMP_TCPIP_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->msg.msg.n.proto = proto; + msg->msg.conn = conn; + TCPIP_APIMSG(msg, lwip_netconn_do_newconn, err); + memp_free(MEMP_TCPIP_API_MSG_DATA, msg); if (err != ERR_OK) { LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed)); @@ -103,16 +107,21 @@ netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_cal err_t netconn_delete(struct netconn *conn) { - struct api_msg msg; + struct api_msg *msg; /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ if (conn == NULL) { return ERR_OK; } - msg.function = lwip_netconn_do_delconn; - msg.msg.conn = conn; - tcpip_apimsg(&msg); + msg = (struct api_msg *)memp_malloc(MEMP_TCPIP_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->function = lwip_netconn_do_delconn; + msg->msg.conn = conn; + tcpip_apimsg(msg); + memp_free(MEMP_TCPIP_API_MSG_DATA, msg); netconn_free(conn); @@ -135,18 +144,23 @@ netconn_delete(struct netconn *conn) err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) { - struct api_msg msg; + struct api_msg *msg; err_t err; LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;); - msg.msg.conn = conn; - msg.msg.msg.ad.ipaddr = ip_2_ipX(addr); - msg.msg.msg.ad.port = port; - msg.msg.msg.ad.local = local; - TCPIP_APIMSG(&msg, lwip_netconn_do_getaddr, err); + msg = (struct api_msg *)memp_malloc(MEMP_TCPIP_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->msg.conn = conn; + msg->msg.msg.ad.local = local; + TCPIP_APIMSG(msg, lwip_netconn_do_getaddr, err); + *addr = *ipX_2_ip(&(msg->msg.msg.ad.ipaddr)); + *port = msg->msg.msg.ad.port; + memp_free(MEMP_TCPIP_API_MSG_DATA, msg); NETCONN_SET_SAFE_ERR(conn, err); return err; @@ -165,15 +179,20 @@ netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) err_t netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port) { - struct api_msg msg; + struct api_msg *msg; err_t err; LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); - msg.msg.conn = conn; - msg.msg.msg.bc.ipaddr = addr; - msg.msg.msg.bc.port = port; - TCPIP_APIMSG(&msg, lwip_netconn_do_bind, err); + msg = (struct api_msg *)memp_malloc(MEMP_TCPIP_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->msg.conn = conn; + msg->msg.msg.bc.ipaddr = *addr; + msg->msg.msg.bc.port = port; + TCPIP_APIMSG(msg, lwip_netconn_do_bind, err); + memp_free(MEMP_TCPIP_API_MSG_DATA, msg); NETCONN_SET_SAFE_ERR(conn, err); return err; @@ -190,14 +209,18 @@ netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port) err_t netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port) { - struct api_msg msg; + struct api_msg *msg; err_t err; LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); - msg.msg.conn = conn; - msg.msg.msg.bc.ipaddr = addr; - msg.msg.msg.bc.port = port; + msg = (struct api_msg *)memp_malloc(MEMP_TCPIP_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->msg.conn = conn; + msg->msg.msg.bc.ipaddr = *addr; + msg->msg.msg.bc.port = port; #if LWIP_TCP #if (LWIP_UDP || LWIP_RAW) if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) @@ -205,8 +228,8 @@ netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port) { /* The TCP version waits for the connect to succeed, so always needs to use message passing. */ - msg.function = lwip_netconn_do_connect; - err = tcpip_apimsg(&msg); + msg->function = lwip_netconn_do_connect; + err = tcpip_apimsg(msg); } #endif /* LWIP_TCP */ #if (LWIP_UDP || LWIP_RAW) && LWIP_TCP @@ -215,9 +238,10 @@ netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port) #if (LWIP_UDP || LWIP_RAW) { /* UDP and RAW only set flags, so we can use core-locking. */ - TCPIP_APIMSG(&msg, lwip_netconn_do_connect, err); + TCPIP_APIMSG(msg, lwip_netconn_do_connect, err); } #endif /* (LWIP_UDP || LWIP_RAW) */ + memp_free(MEMP_TCPIP_API_MSG_DATA, msg); NETCONN_SET_SAFE_ERR(conn, err); return err; @@ -232,13 +256,18 @@ netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port) err_t netconn_disconnect(struct netconn *conn) { - struct api_msg msg; + struct api_msg *msg; err_t err; LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); - msg.msg.conn = conn; - TCPIP_APIMSG(&msg, lwip_netconn_do_disconnect, err); + msg = (struct api_msg *)memp_malloc(MEMP_TCPIP_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->msg.conn = conn; + TCPIP_APIMSG(msg, lwip_netconn_do_disconnect, err); + memp_free(MEMP_TCPIP_API_MSG_DATA, msg); NETCONN_SET_SAFE_ERR(conn, err); return err; @@ -256,7 +285,7 @@ err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) { #if LWIP_TCP - struct api_msg msg; + struct api_msg *msg; err_t err; /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ @@ -264,11 +293,16 @@ netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;); - msg.msg.conn = conn; + msg = (struct api_msg *)memp_malloc(MEMP_TCPIP_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->msg.conn = conn; #if TCP_LISTEN_BACKLOG - msg.msg.msg.lb.backlog = backlog; + msg->msg.msg.lb.backlog = backlog; #endif /* TCP_LISTEN_BACKLOG */ - TCPIP_APIMSG(&msg, lwip_netconn_do_listen, err); + TCPIP_APIMSG(msg, lwip_netconn_do_listen, err); + memp_free(MEMP_TCPIP_API_MSG_DATA, msg); NETCONN_SET_SAFE_ERR(conn, err); return err; @@ -294,7 +328,7 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn) struct netconn *newconn; err_t err; #if TCP_LISTEN_BACKLOG - struct api_msg msg; + struct api_msg *msg; #endif /* TCP_LISTEN_BACKLOG */ LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;); @@ -327,9 +361,14 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn) } #if TCP_LISTEN_BACKLOG /* Let the stack know that we have accepted the connection. */ - msg.msg.conn = conn; + msg = (struct api_msg *)memp_malloc(MEMP_TCPIP_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->msg.conn = conn; /* don't care for the return value of lwip_netconn_do_recv */ - TCPIP_APIMSG_NOERR(&msg, lwip_netconn_do_recv); + TCPIP_APIMSG_NOERR(msg, lwip_netconn_do_recv); + memp_free(MEMP_TCPIP_API_MSG_DATA, msg); #endif /* TCP_LISTEN_BACKLOG */ *new_conn = newconn; @@ -358,7 +397,7 @@ netconn_recv_data(struct netconn *conn, void **new_buf) u16_t len; err_t err; #if LWIP_TCP - struct api_msg msg; + struct api_msg *msg; #endif /* LWIP_TCP */ LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); @@ -393,14 +432,19 @@ netconn_recv_data(struct netconn *conn, void **new_buf) /* Let the stack know that we have taken the data. */ /* TODO: Speedup: Don't block and wait for the answer here (to prevent multiple thread-switches). */ - msg.msg.conn = conn; + msg = (struct api_msg *)memp_malloc(MEMP_TCPIP_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->msg.conn = conn; if (buf != NULL) { - msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len; + msg->msg.msg.r.len = ((struct pbuf *)buf)->tot_len; } else { - msg.msg.msg.r.len = 1; + msg->msg.msg.r.len = 1; } /* don't care for the return value of lwip_netconn_do_recv */ - TCPIP_APIMSG_NOERR(&msg, lwip_netconn_do_recv); + TCPIP_APIMSG_NOERR(msg, lwip_netconn_do_recv); + memp_free(MEMP_TCPIP_API_MSG_DATA, msg); } /* If we are closed, we indicate that we no longer wish to use the socket */ @@ -531,14 +575,18 @@ netconn_recved(struct netconn *conn, u32_t length) #if LWIP_TCP if ((conn != NULL) && (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (netconn_get_noautorecved(conn))) { - struct api_msg msg; /* Let the stack know that we have taken the data. */ /* TODO: Speedup: Don't block and wait for the answer here (to prevent multiple thread-switches). */ - msg.msg.conn = conn; - msg.msg.msg.r.len = length; + struct api_msg *msg = (struct api_msg *)memp_malloc(MEMP_TCPIP_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->msg.conn = conn; + msg->msg.msg.r.len = length; /* don't care for the return value of lwip_netconn_do_recv */ - TCPIP_APIMSG_NOERR(&msg, lwip_netconn_do_recv); + TCPIP_APIMSG_NOERR(msg, lwip_netconn_do_recv); + memp_free(MEMP_TCPIP_API_MSG_DATA, msg); } #else /* LWIP_TCP */ LWIP_UNUSED_ARG(conn); @@ -577,15 +625,20 @@ netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t err_t netconn_send(struct netconn *conn, struct netbuf *buf) { - struct api_msg msg; + struct api_msg *msg; err_t err; 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)); - msg.msg.conn = conn; - msg.msg.msg.b = buf; - TCPIP_APIMSG(&msg, lwip_netconn_do_send, err); + msg = (struct api_msg *)memp_malloc(MEMP_TCPIP_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->msg.conn = conn; + msg->msg.msg.b = buf; + TCPIP_APIMSG(msg, lwip_netconn_do_send, err); + memp_free(MEMP_TCPIP_API_MSG_DATA, msg); NETCONN_SET_SAFE_ERR(conn, err); return err; @@ -608,7 +661,7 @@ err_t netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags, size_t *bytes_written) { - struct api_msg msg; + struct api_msg *msg; err_t err; u8_t dontblock; @@ -624,25 +677,29 @@ netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, return ERR_VAL; } + msg = (struct api_msg *)memp_malloc(MEMP_TCPIP_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } /* non-blocking write sends as much */ - msg.msg.conn = conn; - msg.msg.msg.w.dataptr = dataptr; - msg.msg.msg.w.apiflags = apiflags; - msg.msg.msg.w.len = size; + msg->msg.conn = conn; + msg->msg.msg.w.dataptr = dataptr; + msg->msg.msg.w.apiflags = apiflags; + msg->msg.msg.w.len = size; #if LWIP_SO_SNDTIMEO if (conn->send_timeout != 0) { /* get the time we started, which is later compared to sys_now() + conn->send_timeout */ - msg.msg.msg.w.time_started = sys_now(); + msg->msg.msg.w.time_started = sys_now(); } else { - msg.msg.msg.w.time_started = 0; + msg->msg.msg.w.time_started = 0; } #endif /* LWIP_SO_SNDTIMEO */ /* For locking the core: this _can_ be delayed on low memory/low send buffer, but if it is, this is done inside api_msg.c:do_write(), so we can use the non-blocking version here. */ - TCPIP_APIMSG(&msg, lwip_netconn_do_write, err); + TCPIP_APIMSG(msg, lwip_netconn_do_write, err); if ((err == ERR_OK) && (bytes_written != NULL)) { if (dontblock #if LWIP_SO_SNDTIMEO @@ -650,12 +707,13 @@ netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, #endif /* LWIP_SO_SNDTIMEO */ ) { /* nonblocking write: maybe the data has been sent partly */ - *bytes_written = msg.msg.msg.w.len; + *bytes_written = msg->msg.msg.w.len; } else { /* blocking call succeeded: all data has been sent if it */ *bytes_written = size; } } + memp_free(MEMP_TCPIP_API_MSG_DATA, msg); NETCONN_SET_SAFE_ERR(conn, err); return err; @@ -671,18 +729,23 @@ netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, static err_t netconn_close_shutdown(struct netconn *conn, u8_t how) { - struct api_msg msg; + struct api_msg *msg; err_t err; LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;); - msg.function = lwip_netconn_do_close; - msg.msg.conn = conn; + msg = (struct api_msg *)memp_malloc(MEMP_TCPIP_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->function = lwip_netconn_do_close; + msg->msg.conn = conn; /* shutting down both ends is the same as closing */ - msg.msg.msg.sd.shut = how; + msg->msg.msg.sd.shut = how; /* because of the LWIP_TCPIP_CORE_LOCKING implementation of lwip_netconn_do_close, don't use TCPIP_APIMSG here */ - err = tcpip_apimsg(&msg); + err = tcpip_apimsg(msg); + memp_free(MEMP_TCPIP_API_MSG_DATA, msg); NETCONN_SET_SAFE_ERR(conn, err); return err; @@ -730,16 +793,21 @@ netconn_join_leave_group(struct netconn *conn, ip_addr_t *netif_addr, enum netconn_igmp join_or_leave) { - struct api_msg msg; + struct api_msg *msg; err_t err; LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); - msg.msg.conn = conn; - msg.msg.msg.jl.multiaddr = ip_2_ipX(multiaddr); - msg.msg.msg.jl.netif_addr = ip_2_ipX(netif_addr); - msg.msg.msg.jl.join_or_leave = join_or_leave; - TCPIP_APIMSG(&msg, lwip_netconn_do_join_leave_group, err); + msg = (struct api_msg *)memp_malloc(MEMP_TCPIP_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->msg.conn = conn; + msg->msg.msg.jl.multiaddr = *ip_2_ipX(multiaddr); + msg->msg.msg.jl.netif_addr = *ip_2_ipX(netif_addr); + msg->msg.msg.jl.join_or_leave = join_or_leave; + TCPIP_APIMSG(msg, lwip_netconn_do_join_leave_group, err); + memp_free(MEMP_TCPIP_API_MSG_DATA, msg); NETCONN_SET_SAFE_ERR(conn, err); return err; @@ -760,26 +828,32 @@ netconn_join_leave_group(struct netconn *conn, err_t netconn_gethostbyname(const char *name, ip_addr_t *addr) { - struct dns_api_msg msg; + struct dns_api_msg *msg; err_t err; - sys_sem_t sem; LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); - err = sys_sem_new(&sem, 0); + msg = (struct dns_api_msg *)memp_malloc(MEMP_DNS_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->name = name; + msg->err = ERR_OK; + + err = sys_sem_new(&(msg->sem), 0); if (err != ERR_OK) { + memp_free(MEMP_DNS_API_MSG_DATA, msg); return err; } - msg.name = name; - msg.addr = addr; - msg.err = &err; - msg.sem = &sem; + tcpip_callback(lwip_netconn_do_gethostbyname, msg); + sys_sem_wait(&(msg->sem)); + sys_sem_free(&(msg->sem)); + err = msg->err; + *addr = msg->addr; - tcpip_callback(lwip_netconn_do_gethostbyname, &msg); - sys_sem_wait(&sem); - sys_sem_free(&sem); + memp_free(MEMP_DNS_API_MSG_DATA, msg); return err; } diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 8b6286d..b29f1f5 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -456,6 +456,14 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) { /* When returning != ERR_OK, the pcb is aborted in tcp_process(), so do nothing here! */ + /* remove all references to this netconn from the pcb */ + struct tcp_pcb* pcb = newconn->pcb.tcp; + tcp_arg(pcb, NULL); + tcp_recv(pcb, NULL); + tcp_sent(pcb, NULL); + tcp_poll(pcb, NULL, 4); + tcp_err(pcb, NULL); + /* remove reference from to the pcb from this netconn */ newconn->pcb.tcp = NULL; /* no need to drain since we know the recvmbox is empty. */ sys_mbox_free(&newconn->recvmbox); @@ -898,17 +906,17 @@ lwip_netconn_do_bind(struct api_msg_msg *msg) switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: - msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr); + msg->err = raw_bind(msg->conn->pcb.raw, &(msg->msg.bc.ipaddr)); break; #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: - msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); + msg->err = udp_bind(msg->conn->pcb.udp, &(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, msg->msg.bc.ipaddr, msg->msg.bc.port); + msg->err = tcp_bind(msg->conn->pcb.tcp, &(msg->msg.bc.ipaddr), msg->msg.bc.port); break; #endif /* LWIP_TCP */ default: @@ -988,12 +996,12 @@ lwip_netconn_do_connect(struct api_msg_msg *msg) switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: - msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr); + msg->err = raw_connect(msg->conn->pcb.raw, &(msg->msg.bc.ipaddr)); break; #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: - msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); + msg->err = udp_connect(msg->conn->pcb.udp, &(msg->msg.bc.ipaddr), msg->msg.bc.port); break; #endif /* LWIP_UDP */ #if LWIP_TCP @@ -1003,7 +1011,7 @@ lwip_netconn_do_connect(struct api_msg_msg *msg) msg->err = ERR_ISCONN; } else { setup_tcp(msg->conn); - msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, + msg->err = tcp_connect(msg->conn->pcb.tcp, &(msg->msg.bc.ipaddr), msg->msg.bc.port, lwip_netconn_do_connected); if (msg->err == ERR_OK) { u8_t non_blocking = netconn_is_nonblocking(msg->conn); @@ -1413,10 +1421,10 @@ lwip_netconn_do_getaddr(struct api_msg_msg *msg) { if (msg->conn->pcb.ip != NULL) { if (msg->msg.ad.local) { - ipX_addr_copy(PCB_ISIPV6(msg->conn->pcb.ip), *(msg->msg.ad.ipaddr), + ipX_addr_copy(PCB_ISIPV6(msg->conn->pcb.ip), msg->msg.ad.ipaddr, msg->conn->pcb.ip->local_ip); } else { - ipX_addr_copy(PCB_ISIPV6(msg->conn->pcb.ip), *(msg->msg.ad.ipaddr), + ipX_addr_copy(PCB_ISIPV6(msg->conn->pcb.ip), msg->msg.ad.ipaddr, msg->conn->pcb.ip->remote_ip); } msg->err = ERR_OK; @@ -1424,7 +1432,7 @@ lwip_netconn_do_getaddr(struct api_msg_msg *msg) #if LWIP_RAW case NETCONN_RAW: if (msg->msg.ad.local) { - *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; + msg->msg.ad.port = msg->conn->pcb.raw->protocol; } else { /* return an error as connecting is only a helper for upper layers */ msg->err = ERR_CONN; @@ -1434,19 +1442,19 @@ lwip_netconn_do_getaddr(struct api_msg_msg *msg) #if LWIP_UDP case NETCONN_UDP: if (msg->msg.ad.local) { - *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; + msg->msg.ad.port = msg->conn->pcb.udp->local_port; } else { if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { msg->err = ERR_CONN; } else { - *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; + msg->msg.ad.port = msg->conn->pcb.udp->remote_port; } } break; #endif /* LWIP_UDP */ #if LWIP_TCP case NETCONN_TCP: - *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port); + msg->msg.ad.port = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port); break; #endif /* LWIP_TCP */ default: @@ -1519,11 +1527,11 @@ lwip_netconn_do_join_leave_group(struct api_msg_msg *msg) #if LWIP_IPV6 && LWIP_IPV6_MLD if (PCB_ISIPV6(msg->conn->pcb.udp)) { if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { - msg->err = mld6_joingroup(ipX_2_ip6(msg->msg.jl.netif_addr), - ipX_2_ip6(msg->msg.jl.multiaddr)); + msg->err = mld6_joingroup(ipX_2_ip6(&(msg->msg.jl.netif_addr)), + ipX_2_ip6(&(msg->msg.jl.multiaddr))); } else { - msg->err = mld6_leavegroup(ipX_2_ip6(msg->msg.jl.netif_addr), - ipX_2_ip6(msg->msg.jl.multiaddr)); + msg->err = mld6_leavegroup(ipX_2_ip6(&(msg->msg.jl.netif_addr)), + ipX_2_ip6(&(msg->msg.jl.multiaddr))); } } else @@ -1531,11 +1539,11 @@ lwip_netconn_do_join_leave_group(struct api_msg_msg *msg) { #if LWIP_IGMP if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { - msg->err = igmp_joingroup(ipX_2_ip(msg->msg.jl.netif_addr), - ipX_2_ip(msg->msg.jl.multiaddr)); + msg->err = igmp_joingroup(ipX_2_ip(&(msg->msg.jl.netif_addr)), + ipX_2_ip(&(msg->msg.jl.multiaddr))); } else { - msg->err = igmp_leavegroup(ipX_2_ip(msg->msg.jl.netif_addr), - ipX_2_ip(msg->msg.jl.multiaddr)); + msg->err = igmp_leavegroup(ipX_2_ip(&(msg->msg.jl.netif_addr)), + ipX_2_ip(&(msg->msg.jl.multiaddr))); } #endif /* LWIP_IGMP */ } @@ -1569,14 +1577,14 @@ lwip_netconn_do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) if (ipaddr == NULL) { /* timeout or memory error */ - *msg->err = ERR_VAL; + msg->err = ERR_VAL; } else { /* address was resolved */ - *msg->err = ERR_OK; - *msg->addr = *ipaddr; + msg->err = ERR_OK; + msg->addr = *ipaddr; } /* wake up the application task waiting in netconn_gethostbyname */ - sys_sem_signal(msg->sem); + sys_sem_signal(&(msg->sem)); } /** @@ -1590,11 +1598,11 @@ lwip_netconn_do_gethostbyname(void *arg) { struct dns_api_msg *msg = (struct dns_api_msg*)arg; - *msg->err = dns_gethostbyname(msg->name, msg->addr, lwip_netconn_do_dns_found, msg); - if (*msg->err != ERR_INPROGRESS) { + msg->err = dns_gethostbyname(msg->name, &(msg->addr), lwip_netconn_do_dns_found, msg); + if (msg->err != ERR_INPROGRESS) { /* on error or immediate success, wake up the application * task waiting in netconn_gethostbyname */ - sys_sem_signal(msg->sem); + sys_sem_signal(&(msg->sem)); } } #endif /* LWIP_DNS */ diff --git a/src/api/netifapi.c b/src/api/netifapi.c index 81403f8..e0bab08 100644 --- a/src/api/netifapi.c +++ b/src/api/netifapi.c @@ -37,6 +37,7 @@ #include "lwip/netifapi.h" #include "lwip/tcpip.h" +#include "lwip/memp.h" /** * Call netif_add() inside the tcpip_thread context. @@ -45,9 +46,9 @@ static void netifapi_do_netif_add(struct netifapi_msg_msg *msg) { if (!netif_add( msg->netif, - msg->msg.add.ipaddr, - msg->msg.add.netmask, - msg->msg.add.gw, + &(msg->msg.add.ipaddr), + &(msg->msg.add.netmask), + &(msg->msg.add.gw), msg->msg.add.state, msg->msg.add.init, msg->msg.add.input)) { @@ -65,9 +66,9 @@ static void netifapi_do_netif_set_addr(struct netifapi_msg_msg *msg) { netif_set_addr( msg->netif, - msg->msg.add.ipaddr, - msg->msg.add.netmask, - msg->msg.add.gw); + &(msg->msg.add.ipaddr), + &(msg->msg.add.netmask), + &(msg->msg.add.gw)); msg->err = ERR_OK; TCPIP_NETIFAPI_ACK(msg); } @@ -103,17 +104,23 @@ netifapi_netif_add(struct netif *netif, netif_init_fn init, netif_input_fn input) { - struct netifapi_msg msg; - msg.function = netifapi_do_netif_add; - msg.msg.netif = netif; - msg.msg.msg.add.ipaddr = ipaddr; - msg.msg.msg.add.netmask = netmask; - msg.msg.msg.add.gw = gw; - msg.msg.msg.add.state = state; - msg.msg.msg.add.init = init; - msg.msg.msg.add.input = input; - TCPIP_NETIFAPI(&msg); - return msg.msg.err; + err_t err; + struct netifapi_msg *msg = (struct netifapi_msg *)memp_malloc(MEMP_NETIF_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->function = netifapi_do_netif_add; + msg->msg.netif = netif; + msg->msg.msg.add.ipaddr = *ipaddr; + msg->msg.msg.add.netmask = *netmask; + msg->msg.msg.add.gw = *gw; + msg->msg.msg.add.state = state; + msg->msg.msg.add.init = init; + msg->msg.msg.add.input = input; + TCPIP_NETIFAPI(msg); + err = msg->msg.err; + memp_free(MEMP_NETIF_API_MSG_DATA, msg); + return err; } /** @@ -128,14 +135,20 @@ netifapi_netif_set_addr(struct netif *netif, ip_addr_t *netmask, ip_addr_t *gw) { - struct netifapi_msg msg; - msg.function = netifapi_do_netif_set_addr; - msg.msg.netif = netif; - msg.msg.msg.add.ipaddr = ipaddr; - msg.msg.msg.add.netmask = netmask; - msg.msg.msg.add.gw = gw; - TCPIP_NETIFAPI(&msg); - return msg.msg.err; + err_t err; + struct netifapi_msg *msg = (struct netifapi_msg *)memp_malloc(MEMP_NETIF_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->function = netifapi_do_netif_set_addr; + msg->msg.netif = netif; + msg->msg.msg.add.ipaddr = *ipaddr; + msg->msg.msg.add.netmask = *netmask; + msg->msg.msg.add.gw = *gw; + TCPIP_NETIFAPI(msg); + err = msg->msg.err; + memp_free(MEMP_NETIF_API_MSG_DATA, msg); + return err; } /** @@ -148,13 +161,19 @@ err_t netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc, netifapi_errt_fn errtfunc) { - struct netifapi_msg msg; - msg.function = netifapi_do_netif_common; - msg.msg.netif = netif; - msg.msg.msg.common.voidfunc = voidfunc; - msg.msg.msg.common.errtfunc = errtfunc; - TCPIP_NETIFAPI(&msg); - return msg.msg.err; + err_t err; + struct netifapi_msg *msg = (struct netifapi_msg *)memp_malloc(MEMP_NETIF_API_MSG_DATA); + if (msg == NULL) { + return ERR_MEM; + } + msg->function = netifapi_do_netif_common; + msg->msg.netif = netif; + msg->msg.msg.common.voidfunc = voidfunc; + msg->msg.msg.common.errtfunc = errtfunc; + TCPIP_NETIFAPI(msg); + err = msg->msg.err; + memp_free(MEMP_NETIF_API_MSG_DATA, msg); + return err; } #endif /* LWIP_NETIF_API */ diff --git a/src/api/sockets.c b/src/api/sockets.c index 6603671..b0e2358 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -51,6 +51,7 @@ #include "lwip/raw.h" #include "lwip/udp.h" #include "lwip/tcpip.h" +#include "lwip/memp.h" #include "lwip/pbuf.h" #if LWIP_CHECKSUM_ON_COPY #include "lwip/inet_chksum.h" @@ -120,28 +121,6 @@ #define NUM_SOCKETS MEMP_NUM_NETCONN -/** Contains all internal pointers and states used for a socket */ -struct lwip_sock { - /** sockets currently are built on netconns, each socket has one netconn */ - struct netconn *conn; - /** data that was left from the previous read */ - void *lastdata; - /** offset in the data that was left from the previous read */ - u16_t lastoffset; - /** number of times data was received, set by event_callback(), - tested by the receive and select functions */ - s16_t rcvevent; - /** number of times data was ACKed (free send buffer), set by event_callback(), - tested by select */ - u16_t sendevent; - /** error happened for this socket, set by event_callback(), tested by select */ - u16_t errevent; - /** last error that occurred on this socket */ - int err; - /** counter of how many threads are waiting for this socket using select */ - int select_waiting; -}; - /** Description for a task waiting in select */ struct lwip_select_cb { /** Pointer to the next waiting task */ @@ -160,28 +139,6 @@ struct lwip_select_cb { sys_sem_t sem; }; -/** This struct is used to pass data to the set/getsockopt_internal - * functions running in tcpip_thread context (only a void* is allowed) */ -struct lwip_setgetsockopt_data { - /** socket struct for which to change options */ - struct lwip_sock *sock; -#ifdef LWIP_DEBUG - /** socket index for which to change options */ - int s; -#endif /* LWIP_DEBUG */ - /** level of the option to process */ - int level; - /** name of the option to process */ - int optname; - /** set: value to set the option to - * get: value of the option is stored here */ - void *optval; - /** size of *optval */ - socklen_t *optlen; - /** if an error occures, it is temporarily stored here */ - err_t err; -}; - /** A struct sockaddr replacement that has the same alignment as sockaddr_in/ * sockaddr_in6 if instantiated. */ @@ -1526,7 +1483,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) { err_t err = ERR_OK; struct lwip_sock *sock = get_socket(s); - struct lwip_setgetsockopt_data data; + struct lwip_setgetsockopt_data *data; if (!sock) { return -1; @@ -1724,19 +1681,24 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) } /* Now do the actual option processing */ - data.sock = sock; + data = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); + if (data == NULL) { + return ERR_MEM; + } + data->sock = sock; #ifdef LWIP_DEBUG - data.s = s; + data->s = s; #endif /* LWIP_DEBUG */ - data.level = level; - data.optname = optname; - data.optval = optval; - data.optlen = optlen; - data.err = err; - tcpip_callback(lwip_getsockopt_internal, &data); + data->level = level; + data->optname = optname; + data->optval = optval; + data->optlen = optlen; + data->err = err; + tcpip_callback(lwip_getsockopt_internal, data); sys_arch_sem_wait(&sock->conn->op_completed, 0); /* maybe lwip_getsockopt_internal has changed err */ - err = data.err; + err = data->err; + memp_free(MEMP_SOCKET_SETGETSOCKOPT_DATA, data); sock_set_errno(sock, err); return err ? -1 : 0; @@ -1972,7 +1934,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt { struct lwip_sock *sock = get_socket(s); err_t err = ERR_OK; - struct lwip_setgetsockopt_data data; + struct lwip_setgetsockopt_data *data; if (!sock) { return -1; @@ -2181,19 +2143,24 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt /* Now do the actual option processing */ - data.sock = sock; + data = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); + if (data == NULL) { + return ERR_MEM; + } + data->sock = sock; #ifdef LWIP_DEBUG - data.s = s; + data->s = s; #endif /* LWIP_DEBUG */ - data.level = level; - data.optname = optname; - data.optval = (void*)optval; - data.optlen = &optlen; - data.err = err; - tcpip_callback(lwip_setsockopt_internal, &data); + data->level = level; + data->optname = optname; + data->optval = (void*)optval; + data->optlen = &optlen; + data->err = err; + tcpip_callback(lwip_setsockopt_internal, data); sys_arch_sem_wait(&sock->conn->op_completed, 0); /* maybe lwip_setsockopt_internal has changed err */ - err = data.err; + err = data->err; + memp_free(MEMP_SOCKET_SETGETSOCKOPT_DATA, data); sock_set_errno(sock, err); return err ? -1 : 0; diff --git a/src/api/tcpip.c b/src/api/tcpip.c index 7c1c9ca..066e5f6 100644 --- a/src/api/tcpip.c +++ b/src/api/tcpip.c @@ -310,17 +310,21 @@ tcpip_untimeout(sys_timeout_handler h, void *arg) err_t tcpip_apimsg(struct api_msg *apimsg) { - struct tcpip_msg msg; #ifdef LWIP_DEBUG /* catch functions that don't set err */ apimsg->msg.err = ERR_VAL; #endif if (sys_mbox_valid(&mbox)) { - msg.type = TCPIP_MSG_API; - msg.msg.apimsg = apimsg; - sys_mbox_post(&mbox, &msg); + struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); + if (msg == NULL) { + return ERR_MEM; + } + msg->type = TCPIP_MSG_API; + msg->msg.apimsg = apimsg; + sys_mbox_post(&mbox, msg); sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0); + memp_free(MEMP_TCPIP_MSG_API, msg); return apimsg->msg.err; } return ERR_VAL; @@ -340,20 +344,24 @@ tcpip_apimsg(struct api_msg *apimsg) err_t tcpip_netifapi(struct netifapi_msg* netifapimsg) { - struct tcpip_msg msg; - if (sys_mbox_valid(&mbox)) { + struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); + if (msg == NULL) { + return NULL; + } + err_t err = sys_sem_new(&netifapimsg->msg.sem, 0); if (err != ERR_OK) { netifapimsg->msg.err = err; return err; } - msg.type = TCPIP_MSG_NETIFAPI; - msg.msg.netifapimsg = netifapimsg; - sys_mbox_post(&mbox, &msg); + msg->type = TCPIP_MSG_NETIFAPI; + msg->msg.netifapimsg = netifapimsg; + sys_mbox_post(&mbox, msg); sys_sem_wait(&netifapimsg->msg.sem); sys_sem_free(&netifapimsg->msg.sem); + memp_free(MEMP_TCPIP_MSG_API, msg); return netifapimsg->msg.err; } return ERR_VAL; diff --git a/src/core/dhcp.c b/src/core/dhcp.c index f0f594f..279bcfb 100644 --- a/src/core/dhcp.c +++ b/src/core/dhcp.c @@ -960,6 +960,11 @@ dhcp_bind(struct netif *netif) LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000)); } + /* If we have sub 1 minute lease, t2 and t1 will kick in at the same time. */ + if ((dhcp->t1_timeout >= dhcp->t2_timeout) && (dhcp->t2_timeout > 0)) { + dhcp->t1_timeout = 0; + } + if (dhcp->subnet_mask_given) { /* copy offered network mask */ ip_addr_copy(sn_mask, dhcp->offered_sn_mask); @@ -1472,8 +1477,14 @@ decode_next: if (offset >= q->len) { offset -= q->len; offset_max -= q->len; - q = q->next; - options = (u8_t*)q->payload; + if ((offset < offset_max) && offset_max) { + q = q->next; + LWIP_ASSERT("next pbuf was null", q); + options = (u8_t*)q->payload; + } else { + // We've run out of bytes, probably no end marker. Don't proceed. + break; + } } } /* is this an overloaded message? */ diff --git a/src/core/memp.c b/src/core/memp.c index 1323463..d656936 100644 --- a/src/core/memp.c +++ b/src/core/memp.c @@ -48,6 +48,7 @@ #include "lwip/igmp.h" #include "lwip/api.h" #include "lwip/api_msg.h" +#include "lwip/sockets.h" #include "lwip/tcpip.h" #include "lwip/sys.h" #include "lwip/timers.h" diff --git a/src/include/lwip/api_msg.h b/src/include/lwip/api_msg.h index 8268036..4c02141 100644 --- a/src/include/lwip/api_msg.h +++ b/src/include/lwip/api_msg.h @@ -75,13 +75,13 @@ struct api_msg_msg { } n; /** used for lwip_netconn_do_bind and lwip_netconn_do_connect */ struct { - ip_addr_t *ipaddr; + ip_addr_t ipaddr; u16_t port; } bc; /** used for lwip_netconn_do_getaddr */ struct { - ipX_addr_t *ipaddr; - u16_t *port; + ipX_addr_t ipaddr; + u16_t port; u8_t local; } ad; /** used for lwip_netconn_do_write */ @@ -104,8 +104,8 @@ struct api_msg_msg { #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) /** used for lwip_netconn_do_join_leave_group */ struct { - ipX_addr_t *multiaddr; - ipX_addr_t *netif_addr; + ipX_addr_t multiaddr; + ipX_addr_t netif_addr; enum netconn_igmp join_or_leave; } jl; #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ @@ -136,12 +136,12 @@ struct dns_api_msg { /** Hostname to query or dotted IP address string */ const char *name; /** Rhe resolved address is stored here */ - ip_addr_t *addr; + ip_addr_t addr; /** This semaphore is posted when the name is resolved, the application thread should wait on it. */ - sys_sem_t *sem; + sys_sem_t sem; /** Errors are given back here */ - err_t *err; + err_t err; }; #endif /* LWIP_DNS */ diff --git a/src/include/lwip/memp_std.h b/src/include/lwip/memp_std.h index 592a282..2f632b7 100644 --- a/src/include/lwip/memp_std.h +++ b/src/include/lwip/memp_std.h @@ -58,6 +58,16 @@ LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), #if NO_SYS==0 LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API") +LWIP_MEMPOOL(TCPIP_API_MSG_DATA, MEMP_NUM_TCPIP_MSG_API, sizeof(struct api_msg), "TCPIP_API_MSG_DATA") +#if LWIP_DNS +LWIP_MEMPOOL(DNS_API_MSG_DATA, MEMP_NUM_TCPIP_MSG_API, sizeof(struct dns_api_msg), "DNS_API_MSG_DATA") +#endif +#if LWIP_SOCKET +LWIP_MEMPOOL(SOCKET_SETGETSOCKOPT_DATA, MEMP_NUM_SOCKET_API, sizeof(struct lwip_setgetsockopt_data), "SOCKET_SETGETSOCKOPT_DATA") +#endif +#if LWIP_NETIF_API +LWIP_MEMPOOL(NETIF_API_MSG_DATA, MEMP_NUM_TCPIP_MSG_API, sizeof(struct netifapi_msg), "NETIF_API_MSG_DATA") +#endif #if !LWIP_TCPIP_CORE_LOCKING_INPUT LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT") #endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ diff --git a/src/include/lwip/netifapi.h b/src/include/lwip/netifapi.h index 33318ef..c28092d 100644 --- a/src/include/lwip/netifapi.h +++ b/src/include/lwip/netifapi.h @@ -52,9 +52,9 @@ struct netifapi_msg_msg { struct netif *netif; union { struct { - ip_addr_t *ipaddr; - ip_addr_t *netmask; - ip_addr_t *gw; + ip_addr_t ipaddr; + ip_addr_t netmask; + ip_addr_t gw; void *state; netif_init_fn init; netif_input_fn input; diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index e51f8e5..d470606 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -351,6 +351,15 @@ #endif /** + * MEMP_NUM_SOCKET_API: the number of various structures, which are used + * for communication with application thread calling socket api functions. + * (only needed if you use sockets.c) + */ +#ifndef MEMP_NUM_SOCKET_API +#define MEMP_NUM_SOCKET_API 8 +#endif + +/** * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree. */ #ifndef MEMP_NUM_SNMP_NODE diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index 7346137..961b229 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -41,6 +41,7 @@ #include /* for size_t */ #include "lwip/ip_addr.h" +#include "lwip/err.h" #include "lwip/inet.h" #include "lwip/inet6.h" @@ -84,6 +85,50 @@ struct sockaddr { typedef u32_t socklen_t; #endif +/** Contains all internal pointers and states used for a socket */ +struct lwip_sock { + /** sockets currently are built on netconns, each socket has one netconn */ + struct netconn *conn; + /** data that was left from the previous read */ + void *lastdata; + /** offset in the data that was left from the previous read */ + u16_t lastoffset; + /** number of times data was received, set by event_callback(), + tested by the receive and select functions */ + s16_t rcvevent; + /** number of times data was ACKed (free send buffer), set by event_callback(), + tested by select */ + u16_t sendevent; + /** error happened for this socket, set by event_callback(), tested by select */ + u16_t errevent; + /** last error that occurred on this socket */ + int err; + /** counter of how many threads are waiting for this socket using select */ + int select_waiting; +}; + +/** This struct is used to pass data to the set/getsockopt_internal + * functions running in tcpip_thread context (only a void* is allowed) */ +struct lwip_setgetsockopt_data { + /** socket struct for which to change options */ + struct lwip_sock *sock; +#ifdef LWIP_DEBUG + /** socket index for which to change options */ + int s; +#endif /* LWIP_DEBUG */ + /** level of the option to process */ + int level; + /** name of the option to process */ + int optname; + /** set: value to set the option to + * get: value of the option is stored here */ + void *optval; + /** size of *optval */ + socklen_t *optlen; + /** if an error occures, it is temporarily stored here */ + err_t err; +}; + /* Socket protocol types (TCP/UDP/RAW) */ #define SOCK_STREAM 1 #define SOCK_DGRAM 2