initial commit of lk (little kernel) project
diff --git a/lib/lwip/src/api/api_lib.c b/lib/lwip/src/api/api_lib.c
new file mode 100644
index 0000000..3d83d1e
--- /dev/null
+++ b/lib/lwip/src/api/api_lib.c
@@ -0,0 +1,729 @@
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+/* This is the part of the API that is linked with
+ the application */
+
+#include "lwip/opt.h"
+#include "lwip/api.h"
+#include "lwip/api_msg.h"
+#include "lwip/memp.h"
+
+
+struct
+netbuf *netbuf_new(void)
+{
+ struct netbuf *buf;
+
+ buf = memp_malloc(MEMP_NETBUF);
+ if (buf != NULL) {
+ buf->p = NULL;
+ buf->ptr = NULL;
+ return buf;
+ } else {
+ return NULL;
+ }
+}
+
+void
+netbuf_delete(struct netbuf *buf)
+{
+ if (buf != NULL) {
+ if (buf->p != NULL) {
+ pbuf_free(buf->p);
+ buf->p = buf->ptr = NULL;
+ }
+ memp_free(MEMP_NETBUF, buf);
+ }
+}
+
+void *
+netbuf_alloc(struct netbuf *buf, u16_t size)
+{
+ /* Deallocate any previously allocated memory. */
+ if (buf->p != NULL) {
+ pbuf_free(buf->p);
+ }
+ buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
+ if (buf->p == NULL) {
+ return NULL;
+ }
+ buf->ptr = buf->p;
+ return buf->p->payload;
+}
+
+void
+netbuf_free(struct netbuf *buf)
+{
+ if (buf->p != NULL) {
+ pbuf_free(buf->p);
+ }
+ buf->p = buf->ptr = NULL;
+}
+
+void
+netbuf_ref(struct netbuf *buf, void *dataptr, u16_t size)
+{
+ if (buf->p != NULL) {
+ pbuf_free(buf->p);
+ }
+ buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
+ buf->p->payload = dataptr;
+ buf->p->len = buf->p->tot_len = size;
+ buf->ptr = buf->p;
+}
+
+void
+netbuf_chain(struct netbuf *head, struct netbuf *tail)
+{
+ pbuf_chain(head->p, tail->p);
+ head->ptr = head->p;
+ memp_free(MEMP_NETBUF, tail);
+}
+
+u16_t
+netbuf_len(struct netbuf *buf)
+{
+ return buf->p->tot_len;
+}
+
+err_t
+netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
+{
+ if (buf->ptr == NULL) {
+ return ERR_BUF;
+ }
+ *dataptr = buf->ptr->payload;
+ *len = buf->ptr->len;
+ return ERR_OK;
+}
+
+s8_t
+netbuf_next(struct netbuf *buf)
+{
+ if (buf->ptr->next == NULL) {
+ return -1;
+ }
+ buf->ptr = buf->ptr->next;
+ if (buf->ptr->next == NULL) {
+ return 1;
+ }
+ return 0;
+}
+
+void
+netbuf_first(struct netbuf *buf)
+{
+ buf->ptr = buf->p;
+}
+
+void
+netbuf_copy_partial(struct netbuf *buf, void *dataptr, u16_t len, u16_t offset)
+{
+ struct pbuf *p;
+ u16_t i, left;
+
+ left = 0;
+
+ if(buf == NULL || dataptr == NULL) {
+ return;
+ }
+
+ /* This implementation is bad. It should use bcopy
+ instead. */
+ for(p = buf->p; left < len && p != NULL; p = p->next) {
+ if (offset != 0 && offset >= p->len) {
+ offset -= p->len;
+ } else {
+ for(i = offset; i < p->len; ++i) {
+ ((u8_t *)dataptr)[left] = ((u8_t *)p->payload)[i];
+ if (++left >= len) {
+ return;
+ }
+ }
+ offset = 0;
+ }
+ }
+}
+
+void
+netbuf_copy(struct netbuf *buf, void *dataptr, u16_t len)
+{
+ netbuf_copy_partial(buf, dataptr, len, 0);
+}
+
+struct ip_addr *
+netbuf_fromaddr(struct netbuf *buf)
+{
+ return buf->fromaddr;
+}
+
+u16_t
+netbuf_fromport(struct netbuf *buf)
+{
+ return buf->fromport;
+}
+
+struct
+netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u16_t proto,
+ void (*callback)(struct netconn *, enum netconn_evt, u16_t len))
+{
+ struct netconn *conn;
+ struct api_msg *msg;
+
+ conn = memp_malloc(MEMP_NETCONN);
+ if (conn == NULL) {
+ return NULL;
+ }
+
+ conn->err = ERR_OK;
+ conn->type = t;
+ conn->pcb.tcp = NULL;
+
+ if ((conn->mbox = sys_mbox_new()) == SYS_MBOX_NULL) {
+ memp_free(MEMP_NETCONN, conn);
+ return NULL;
+ }
+ conn->recvmbox = SYS_MBOX_NULL;
+ conn->acceptmbox = SYS_MBOX_NULL;
+ conn->sem = SYS_SEM_NULL;
+ conn->state = NETCONN_NONE;
+ conn->socket = 0;
+ conn->callback = callback;
+ conn->recv_avail = 0;
+
+ if((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+ memp_free(MEMP_NETCONN, conn);
+ return NULL;
+ }
+
+ msg->type = API_MSG_NEWCONN;
+ msg->msg.msg.bc.port = proto; /* misusing the port field */
+ msg->msg.conn = conn;
+ api_msg_post(msg);
+ sys_mbox_fetch(conn->mbox, NULL);
+ memp_free(MEMP_API_MSG, msg);
+
+ if ( conn->err != ERR_OK ) {
+ memp_free(MEMP_NETCONN, conn);
+ return NULL;
+ }
+
+ return conn;
+}
+
+
+struct
+netconn *netconn_new(enum netconn_type t)
+{
+ return netconn_new_with_proto_and_callback(t,0,NULL);
+}
+
+struct
+netconn *netconn_new_with_callback(enum netconn_type t,
+ void (*callback)(struct netconn *, enum netconn_evt, u16_t len))
+{
+ return netconn_new_with_proto_and_callback(t,0,callback);
+}
+
+
+err_t
+netconn_delete(struct netconn *conn)
+{
+ struct api_msg *msg;
+ void *mem;
+
+ if (conn == NULL) {
+ return ERR_OK;
+ }
+
+ if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+ return ERR_MEM;
+ }
+
+ msg->type = API_MSG_DELCONN;
+ msg->msg.conn = conn;
+ api_msg_post(msg);
+ sys_mbox_fetch(conn->mbox, NULL);
+ memp_free(MEMP_API_MSG, msg);
+
+ /* Drain the recvmbox. */
+ if (conn->recvmbox != SYS_MBOX_NULL) {
+ while (sys_arch_mbox_fetch(conn->recvmbox, &mem, 1) != SYS_ARCH_TIMEOUT) {
+ if (conn->type == NETCONN_TCP) {
+ if(mem != NULL)
+ pbuf_free((struct pbuf *)mem);
+ } else {
+ netbuf_delete((struct netbuf *)mem);
+ }
+ }
+ sys_mbox_free(conn->recvmbox);
+ conn->recvmbox = SYS_MBOX_NULL;
+ }
+
+
+ /* Drain the acceptmbox. */
+ if (conn->acceptmbox != SYS_MBOX_NULL) {
+ while (sys_arch_mbox_fetch(conn->acceptmbox, &mem, 1) != SYS_ARCH_TIMEOUT) {
+ netconn_delete((struct netconn *)mem);
+ }
+
+ sys_mbox_free(conn->acceptmbox);
+ conn->acceptmbox = SYS_MBOX_NULL;
+ }
+
+ sys_mbox_free(conn->mbox);
+ conn->mbox = SYS_MBOX_NULL;
+ if (conn->sem != SYS_SEM_NULL) {
+ sys_sem_free(conn->sem);
+ }
+ /* conn->sem = SYS_SEM_NULL;*/
+ memp_free(MEMP_NETCONN, conn);
+ return ERR_OK;
+}
+
+enum netconn_type
+netconn_type(struct netconn *conn)
+{
+ return conn->type;
+}
+
+err_t
+netconn_peer(struct netconn *conn, struct ip_addr *addr,
+ u16_t *port)
+{
+ switch (conn->type) {
+ case NETCONN_RAW:
+ /* return an error as connecting is only a helper for upper layers */
+ return ERR_CONN;
+ case NETCONN_UDPLITE:
+ case NETCONN_UDPNOCHKSUM:
+ case NETCONN_UDP:
+ if (conn->pcb.udp == NULL ||
+ ((conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0))
+ return ERR_CONN;
+ *addr = (conn->pcb.udp->remote_ip);
+ *port = conn->pcb.udp->remote_port;
+ break;
+ case NETCONN_TCP:
+ if (conn->pcb.tcp == NULL)
+ return ERR_CONN;
+ *addr = (conn->pcb.tcp->remote_ip);
+ *port = conn->pcb.tcp->remote_port;
+ break;
+ }
+ return (conn->err = ERR_OK);
+}
+
+err_t
+netconn_addr(struct netconn *conn, struct ip_addr **addr,
+ u16_t *port)
+{
+ switch (conn->type) {
+ case NETCONN_RAW:
+ *addr = &(conn->pcb.raw->local_ip);
+ *port = conn->pcb.raw->protocol;
+ break;
+ case NETCONN_UDPLITE:
+ case NETCONN_UDPNOCHKSUM:
+ case NETCONN_UDP:
+ *addr = &(conn->pcb.udp->local_ip);
+ *port = conn->pcb.udp->local_port;
+ break;
+ case NETCONN_TCP:
+ *addr = &(conn->pcb.tcp->local_ip);
+ *port = conn->pcb.tcp->local_port;
+ break;
+ }
+ return (conn->err = ERR_OK);
+}
+
+err_t
+netconn_bind(struct netconn *conn, struct ip_addr *addr,
+ u16_t port)
+{
+ struct api_msg *msg;
+
+ if (conn == NULL) {
+ return ERR_VAL;
+ }
+
+ if (conn->type != NETCONN_TCP &&
+ conn->recvmbox == SYS_MBOX_NULL) {
+ if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {
+ return ERR_MEM;
+ }
+ }
+
+ if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+ return (conn->err = ERR_MEM);
+ }
+ msg->type = API_MSG_BIND;
+ msg->msg.conn = conn;
+ msg->msg.msg.bc.ipaddr = addr;
+ msg->msg.msg.bc.port = port;
+ api_msg_post(msg);
+ sys_mbox_fetch(conn->mbox, NULL);
+ memp_free(MEMP_API_MSG, msg);
+ return conn->err;
+}
+
+
+err_t
+netconn_connect(struct netconn *conn, struct ip_addr *addr,
+ u16_t port)
+{
+ struct api_msg *msg;
+
+ if (conn == NULL) {
+ return ERR_VAL;
+ }
+
+
+ if (conn->recvmbox == SYS_MBOX_NULL) {
+ if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {
+ return ERR_MEM;
+ }
+ }
+
+ if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+ return ERR_MEM;
+ }
+ msg->type = API_MSG_CONNECT;
+ msg->msg.conn = conn;
+ msg->msg.msg.bc.ipaddr = addr;
+ msg->msg.msg.bc.port = port;
+ api_msg_post(msg);
+ sys_mbox_fetch(conn->mbox, NULL);
+ memp_free(MEMP_API_MSG, msg);
+ return conn->err;
+}
+
+err_t
+netconn_disconnect(struct netconn *conn)
+{
+ struct api_msg *msg;
+
+ if (conn == NULL) {
+ return ERR_VAL;
+ }
+
+ if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+ return ERR_MEM;
+ }
+ msg->type = API_MSG_DISCONNECT;
+ msg->msg.conn = conn;
+ api_msg_post(msg);
+ sys_mbox_fetch(conn->mbox, NULL);
+ memp_free(MEMP_API_MSG, msg);
+ return conn->err;
+
+}
+
+err_t
+netconn_listen(struct netconn *conn)
+{
+ struct api_msg *msg;
+
+ if (conn == NULL) {
+ return ERR_VAL;
+ }
+
+ if (conn->acceptmbox == SYS_MBOX_NULL) {
+ conn->acceptmbox = sys_mbox_new();
+ if (conn->acceptmbox == SYS_MBOX_NULL) {
+ return ERR_MEM;
+ }
+ }
+
+ if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+ return (conn->err = ERR_MEM);
+ }
+ msg->type = API_MSG_LISTEN;
+ msg->msg.conn = conn;
+ api_msg_post(msg);
+ sys_mbox_fetch(conn->mbox, NULL);
+ memp_free(MEMP_API_MSG, msg);
+ return conn->err;
+}
+
+struct netconn *
+netconn_accept(struct netconn *conn)
+{
+ struct netconn *newconn;
+
+ if (conn == NULL) {
+ return NULL;
+ }
+
+ sys_mbox_fetch(conn->acceptmbox, (void **)&newconn);
+ /* Register event with callback */
+ if (conn->callback)
+ (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, 0);
+
+ return newconn;
+}
+
+struct netbuf *
+netconn_recv(struct netconn *conn)
+{
+ struct api_msg *msg;
+ struct netbuf *buf;
+ struct pbuf *p;
+ u16_t len;
+
+ if (conn == NULL) {
+ return NULL;
+ }
+
+ if (conn->recvmbox == SYS_MBOX_NULL) {
+ conn->err = ERR_CONN;
+ return NULL;
+ }
+
+ if (conn->err != ERR_OK) {
+ return NULL;
+ }
+
+ if (conn->type == NETCONN_TCP) {
+ if (conn->pcb.tcp->state == LISTEN) {
+ conn->err = ERR_CONN;
+ return NULL;
+ }
+
+
+ buf = memp_malloc(MEMP_NETBUF);
+
+ if (buf == NULL) {
+ conn->err = ERR_MEM;
+ return NULL;
+ }
+
+ sys_mbox_fetch(conn->recvmbox, (void **)&p);
+
+ if (p != NULL)
+ {
+ len = p->tot_len;
+ conn->recv_avail -= len;
+ }
+ else
+ len = 0;
+
+ /* Register event with callback */
+ if (conn->callback)
+ (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, len);
+
+ /* If we are closed, we indicate that we no longer wish to receive
+ data by setting conn->recvmbox to SYS_MBOX_NULL. */
+ if (p == NULL) {
+ memp_free(MEMP_NETBUF, buf);
+ sys_mbox_free(conn->recvmbox);
+ conn->recvmbox = SYS_MBOX_NULL;
+ return NULL;
+ }
+
+ buf->p = p;
+ buf->ptr = p;
+ buf->fromport = 0;
+ buf->fromaddr = NULL;
+
+ /* Let the stack know that we have taken the data. */
+ if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+ conn->err = ERR_MEM;
+ return buf;
+ }
+ msg->type = API_MSG_RECV;
+ msg->msg.conn = conn;
+ if (buf != NULL) {
+ msg->msg.msg.len = buf->p->tot_len;
+ } else {
+ msg->msg.msg.len = 1;
+ }
+ api_msg_post(msg);
+
+ sys_mbox_fetch(conn->mbox, NULL);
+ memp_free(MEMP_API_MSG, msg);
+ } else {
+ sys_mbox_fetch(conn->recvmbox, (void **)&buf);
+ conn->recv_avail -= buf->p->tot_len;
+ /* Register event with callback */
+ if (conn->callback)
+ (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len);
+ }
+
+
+
+
+ LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err));
+
+
+ return buf;
+}
+
+err_t
+netconn_send(struct netconn *conn, struct netbuf *buf)
+{
+ struct api_msg *msg;
+
+ if (conn == NULL) {
+ return ERR_VAL;
+ }
+
+ if (conn->err != ERR_OK) {
+ return conn->err;
+ }
+
+ if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+ return (conn->err = ERR_MEM);
+ }
+
+ LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len));
+ msg->type = API_MSG_SEND;
+ msg->msg.conn = conn;
+ msg->msg.msg.p = buf->p;
+ api_msg_post(msg);
+
+ sys_mbox_fetch(conn->mbox, NULL);
+ memp_free(MEMP_API_MSG, msg);
+ return conn->err;
+}
+
+err_t
+netconn_write(struct netconn *conn, void *dataptr, u16_t size, u8_t copy)
+{
+ struct api_msg *msg;
+ u16_t len;
+
+ if (conn == NULL) {
+ return ERR_VAL;
+ }
+
+ if (conn->err != ERR_OK) {
+ return conn->err;
+ }
+
+ if (conn->sem == SYS_SEM_NULL) {
+ conn->sem = sys_sem_new(0);
+ if (conn->sem == SYS_SEM_NULL) {
+ return ERR_MEM;
+ }
+ }
+
+ if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+ return (conn->err = ERR_MEM);
+ }
+ msg->type = API_MSG_WRITE;
+ msg->msg.conn = conn;
+
+
+ conn->state = NETCONN_WRITE;
+ while (conn->err == ERR_OK && size > 0) {
+ msg->msg.msg.w.dataptr = dataptr;
+ msg->msg.msg.w.copy = copy;
+
+ if (conn->type == NETCONN_TCP) {
+ if (tcp_sndbuf(conn->pcb.tcp) == 0) {
+ sys_sem_wait(conn->sem);
+ if (conn->err != ERR_OK) {
+ goto ret;
+ }
+ }
+ if (size > tcp_sndbuf(conn->pcb.tcp)) {
+ /* We cannot send more than one send buffer's worth of data at a
+ time. */
+ len = tcp_sndbuf(conn->pcb.tcp);
+ } else {
+ len = size;
+ }
+ } else {
+ len = size;
+ }
+
+ LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_write: writing %d bytes (%d)\n", len, copy));
+ msg->msg.msg.w.len = len;
+ api_msg_post(msg);
+ sys_mbox_fetch(conn->mbox, NULL);
+ if (conn->err == ERR_OK) {
+ dataptr = (void *)((u8_t *)dataptr + len);
+ size -= len;
+ } else if (conn->err == ERR_MEM) {
+ conn->err = ERR_OK;
+ sys_sem_wait(conn->sem);
+ } else {
+ goto ret;
+ }
+ }
+ ret:
+ memp_free(MEMP_API_MSG, msg);
+ conn->state = NETCONN_NONE;
+ if (conn->sem != SYS_SEM_NULL) {
+ sys_sem_free(conn->sem);
+ conn->sem = SYS_SEM_NULL;
+ }
+
+ return conn->err;
+}
+
+err_t
+netconn_close(struct netconn *conn)
+{
+ struct api_msg *msg;
+
+ if (conn == NULL) {
+ return ERR_VAL;
+ }
+ if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {
+ return (conn->err = ERR_MEM);
+ }
+
+ conn->state = NETCONN_CLOSE;
+ again:
+ msg->type = API_MSG_CLOSE;
+ msg->msg.conn = conn;
+ api_msg_post(msg);
+ sys_mbox_fetch(conn->mbox, NULL);
+ if (conn->err == ERR_MEM &&
+ conn->sem != SYS_SEM_NULL) {
+ sys_sem_wait(conn->sem);
+ goto again;
+ }
+ conn->state = NETCONN_NONE;
+ memp_free(MEMP_API_MSG, msg);
+ return conn->err;
+}
+
+err_t
+netconn_err(struct netconn *conn)
+{
+ return conn->err;
+}
+
diff --git a/lib/lwip/src/api/api_msg.c b/lib/lwip/src/api/api_msg.c
new file mode 100644
index 0000000..0cbe626
--- /dev/null
+++ b/lib/lwip/src/api/api_msg.c
@@ -0,0 +1,800 @@
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+#include "lwip/arch.h"
+#include "lwip/api_msg.h"
+#include "lwip/memp.h"
+#include "lwip/sys.h"
+#include "lwip/tcpip.h"
+
+#if LWIP_RAW
+static u8_t
+recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
+ struct ip_addr *addr)
+{
+ struct netbuf *buf;
+ struct netconn *conn;
+
+ conn = arg;
+ if (!conn) return 0;
+
+ if (conn->recvmbox != SYS_MBOX_NULL) {
+ if (!(buf = memp_malloc(MEMP_NETBUF))) {
+ return 0;
+ }
+ pbuf_ref(p);
+ buf->p = p;
+ buf->ptr = p;
+ buf->fromaddr = addr;
+ buf->fromport = pcb->protocol;
+
+ conn->recv_avail += p->tot_len;
+ /* Register event with callback */
+ if (conn->callback)
+ (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
+ sys_mbox_post(conn->recvmbox, buf);
+ }
+
+ return 0; /* do not eat the packet */
+}
+#endif
+#if LWIP_UDP
+static void
+recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
+ struct ip_addr *addr, u16_t port)
+{
+ struct netbuf *buf;
+ struct netconn *conn;
+
+ conn = arg;
+
+ if (conn == NULL) {
+ pbuf_free(p);
+ return;
+ }
+ if (conn->recvmbox != SYS_MBOX_NULL) {
+ buf = memp_malloc(MEMP_NETBUF);
+ if (buf == NULL) {
+ pbuf_free(p);
+ return;
+ } else {
+ buf->p = p;
+ buf->ptr = p;
+ buf->fromaddr = addr;
+ buf->fromport = port;
+ }
+
+ conn->recv_avail += p->tot_len;
+ /* Register event with callback */
+ if (conn->callback)
+ (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
+ sys_mbox_post(conn->recvmbox, buf);
+ }
+}
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+
+static err_t
+recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
+{
+ struct netconn *conn;
+ u16_t len;
+
+ conn = arg;
+
+ if (conn == NULL) {
+ pbuf_free(p);
+ return ERR_VAL;
+ }
+
+ if (conn->recvmbox != SYS_MBOX_NULL) {
+
+ conn->err = err;
+ if (p != NULL) {
+ len = p->tot_len;
+ conn->recv_avail += len;
+ }
+ else
+ len = 0;
+ /* Register event with callback */
+ if (conn->callback)
+ (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, len);
+ sys_mbox_post(conn->recvmbox, p);
+ }
+ return ERR_OK;
+}
+
+
+static err_t
+poll_tcp(void *arg, struct tcp_pcb *pcb)
+{
+ struct netconn *conn;
+
+ conn = arg;
+ if (conn != NULL &&
+ (conn->state == NETCONN_WRITE || conn->state == NETCONN_CLOSE) &&
+ conn->sem != SYS_SEM_NULL) {
+ sys_sem_signal(conn->sem);
+ }
+ return ERR_OK;
+}
+
+static err_t
+sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
+{
+ struct netconn *conn;
+
+ conn = arg;
+ if (conn != NULL && conn->sem != SYS_SEM_NULL) {
+ sys_sem_signal(conn->sem);
+ }
+
+ if (conn && conn->callback)
+ if (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)
+ (*conn->callback)(conn, NETCONN_EVT_SENDPLUS, len);
+
+ return ERR_OK;
+}
+
+static void
+err_tcp(void *arg, err_t err)
+{
+ struct netconn *conn;
+
+ conn = arg;
+
+ conn->pcb.tcp = NULL;
+
+
+ conn->err = err;
+ if (conn->recvmbox != SYS_MBOX_NULL) {
+ /* Register event with callback */
+ if (conn->callback)
+ (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
+ sys_mbox_post(conn->recvmbox, NULL);
+ }
+ if (conn->mbox != SYS_MBOX_NULL) {
+ sys_mbox_post(conn->mbox, NULL);
+ }
+ if (conn->acceptmbox != SYS_MBOX_NULL) {
+ /* Register event with callback */
+ if (conn->callback)
+ (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
+ sys_mbox_post(conn->acceptmbox, NULL);
+ }
+ if (conn->sem != SYS_SEM_NULL) {
+ sys_sem_signal(conn->sem);
+ }
+}
+
+static void
+setup_tcp(struct netconn *conn)
+{
+ struct tcp_pcb *pcb;
+
+ pcb = conn->pcb.tcp;
+ tcp_arg(pcb, conn);
+ tcp_recv(pcb, recv_tcp);
+ tcp_sent(pcb, sent_tcp);
+ tcp_poll(pcb, poll_tcp, 4);
+ tcp_err(pcb, err_tcp);
+}
+
+static err_t
+accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
+{
+ sys_mbox_t mbox;
+ struct netconn *newconn;
+ struct netconn *conn;
+
+#if API_MSG_DEBUG
+#if TCP_DEBUG
+ tcp_debug_print_state(newpcb->state);
+#endif /* TCP_DEBUG */
+#endif /* API_MSG_DEBUG */
+ conn = (struct netconn *)arg;
+ mbox = conn->acceptmbox;
+ newconn = memp_malloc(MEMP_NETCONN);
+ if (newconn == NULL) {
+ return ERR_MEM;
+ }
+ newconn->type = NETCONN_TCP;
+ newconn->pcb.tcp = newpcb;
+ setup_tcp(newconn);
+ newconn->recvmbox = sys_mbox_new();
+ if (newconn->recvmbox == SYS_MBOX_NULL) {
+ memp_free(MEMP_NETCONN, newconn);
+ return ERR_MEM;
+ }
+ newconn->mbox = sys_mbox_new();
+ if (newconn->mbox == SYS_MBOX_NULL) {
+ sys_mbox_free(newconn->recvmbox);
+ memp_free(MEMP_NETCONN, newconn);
+ return ERR_MEM;
+ }
+ newconn->sem = sys_sem_new(0);
+ if (newconn->sem == SYS_SEM_NULL) {
+ sys_mbox_free(newconn->recvmbox);
+ sys_mbox_free(newconn->mbox);
+ memp_free(MEMP_NETCONN, newconn);
+ return ERR_MEM;
+ }
+ newconn->acceptmbox = SYS_MBOX_NULL;
+ newconn->err = err;
+ /* Register event with callback */
+ if (conn->callback)
+ {
+ (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
+ /* We have to set the callback here even though
+ * the new socket is unknown. Mark the socket as -1. */
+ newconn->callback = conn->callback;
+ newconn->socket = -1;
+ }
+
+ sys_mbox_post(mbox, newconn);
+ return ERR_OK;
+}
+#endif /* LWIP_TCP */
+
+static void
+do_newconn(struct api_msg_msg *msg)
+{
+ if(msg->conn->pcb.tcp != NULL) {
+ /* This "new" connection already has a PCB allocated. */
+ /* Is this an error condition? Should it be deleted?
+ We currently just are happy and return. */
+ sys_mbox_post(msg->conn->mbox, NULL);
+ return;
+ }
+
+ msg->conn->err = ERR_OK;
+
+ /* Allocate a PCB for this connection */
+ switch(msg->conn->type) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field */
+ raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
+ break;
+#endif
+#if LWIP_UDP
+ case NETCONN_UDPLITE:
+ msg->conn->pcb.udp = udp_new();
+ if(msg->conn->pcb.udp == NULL) {
+ msg->conn->err = ERR_MEM;
+ break;
+ }
+ udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
+ udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+ break;
+ case NETCONN_UDPNOCHKSUM:
+ msg->conn->pcb.udp = udp_new();
+ if(msg->conn->pcb.udp == NULL) {
+ msg->conn->err = ERR_MEM;
+ break;
+ }
+ udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
+ udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+ break;
+ case NETCONN_UDP:
+ msg->conn->pcb.udp = udp_new();
+ if(msg->conn->pcb.udp == NULL) {
+ msg->conn->err = ERR_MEM;
+ break;
+ }
+ udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+ break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ case NETCONN_TCP:
+ msg->conn->pcb.tcp = tcp_new();
+ if(msg->conn->pcb.tcp == NULL) {
+ msg->conn->err = ERR_MEM;
+ break;
+ }
+ setup_tcp(msg->conn);
+ break;
+#endif
+ }
+
+
+ sys_mbox_post(msg->conn->mbox, NULL);
+}
+
+
+static void
+do_delconn(struct api_msg_msg *msg)
+{
+ if (msg->conn->pcb.tcp != NULL) {
+ switch (msg->conn->type) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ raw_remove(msg->conn->pcb.raw);
+ break;
+#endif
+#if LWIP_UDP
+ case NETCONN_UDPLITE:
+ /* FALLTHROUGH */
+ case NETCONN_UDPNOCHKSUM:
+ /* FALLTHROUGH */
+ case NETCONN_UDP:
+ msg->conn->pcb.udp->recv_arg = NULL;
+ udp_remove(msg->conn->pcb.udp);
+ break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ case NETCONN_TCP:
+ if (msg->conn->pcb.tcp->state == LISTEN) {
+ tcp_arg(msg->conn->pcb.tcp, NULL);
+ tcp_accept(msg->conn->pcb.tcp, NULL);
+ tcp_close(msg->conn->pcb.tcp);
+ } else {
+ tcp_arg(msg->conn->pcb.tcp, NULL);
+ tcp_sent(msg->conn->pcb.tcp, NULL);
+ tcp_recv(msg->conn->pcb.tcp, NULL);
+ tcp_poll(msg->conn->pcb.tcp, NULL, 0);
+ tcp_err(msg->conn->pcb.tcp, NULL);
+ if (tcp_close(msg->conn->pcb.tcp) != ERR_OK) {
+ tcp_abort(msg->conn->pcb.tcp);
+ }
+ }
+#endif
+ default:
+ break;
+ }
+ }
+ /* Trigger select() in socket layer */
+ if (msg->conn->callback)
+ {
+ (*msg->conn->callback)(msg->conn, NETCONN_EVT_RCVPLUS, 0);
+ (*msg->conn->callback)(msg->conn, NETCONN_EVT_SENDPLUS, 0);
+ }
+
+ if (msg->conn->mbox != SYS_MBOX_NULL) {
+ sys_mbox_post(msg->conn->mbox, NULL);
+ }
+}
+
+static void
+do_bind(struct api_msg_msg *msg)
+{
+ if (msg->conn->pcb.tcp == NULL) {
+ switch (msg->conn->type) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */
+ raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
+ break;
+#endif
+#if LWIP_UDP
+ case NETCONN_UDPLITE:
+ msg->conn->pcb.udp = udp_new();
+ udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
+ udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+ break;
+ case NETCONN_UDPNOCHKSUM:
+ msg->conn->pcb.udp = udp_new();
+ udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
+ udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+ break;
+ case NETCONN_UDP:
+ msg->conn->pcb.udp = udp_new();
+ udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+ break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ case NETCONN_TCP:
+ msg->conn->pcb.tcp = tcp_new();
+ setup_tcp(msg->conn);
+#endif /* LWIP_TCP */
+ default:
+ break;
+ }
+ }
+ switch (msg->conn->type) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ msg->conn->err = raw_bind(msg->conn->pcb.raw,msg->msg.bc.ipaddr);
+ break;
+#endif
+#if LWIP_UDP
+ case NETCONN_UDPLITE:
+ /* FALLTHROUGH */
+ case NETCONN_UDPNOCHKSUM:
+ /* FALLTHROUGH */
+ case NETCONN_UDP:
+ msg->conn->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->conn->err = tcp_bind(msg->conn->pcb.tcp,
+ msg->msg.bc.ipaddr, msg->msg.bc.port);
+#endif /* LWIP_TCP */
+ default:
+ break;
+ }
+ sys_mbox_post(msg->conn->mbox, NULL);
+}
+#if LWIP_TCP
+
+static err_t
+do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
+{
+ struct netconn *conn;
+
+ conn = arg;
+
+ if (conn == NULL) {
+ return ERR_VAL;
+ }
+
+ conn->err = err;
+ if (conn->type == NETCONN_TCP && err == ERR_OK) {
+ setup_tcp(conn);
+ }
+ sys_mbox_post(conn->mbox, NULL);
+ return ERR_OK;
+}
+#endif
+
+static void
+do_connect(struct api_msg_msg *msg)
+{
+ if (msg->conn->pcb.tcp == NULL) {
+ switch (msg->conn->type) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */
+ raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
+ break;
+#endif
+#if LWIP_UDP
+ case NETCONN_UDPLITE:
+ msg->conn->pcb.udp = udp_new();
+ if (msg->conn->pcb.udp == NULL) {
+ msg->conn->err = ERR_MEM;
+ sys_mbox_post(msg->conn->mbox, NULL);
+ return;
+ }
+ udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
+ udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+ break;
+ case NETCONN_UDPNOCHKSUM:
+ msg->conn->pcb.udp = udp_new();
+ if (msg->conn->pcb.udp == NULL) {
+ msg->conn->err = ERR_MEM;
+ sys_mbox_post(msg->conn->mbox, NULL);
+ return;
+ }
+ udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
+ udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+ break;
+ case NETCONN_UDP:
+ msg->conn->pcb.udp = udp_new();
+ if (msg->conn->pcb.udp == NULL) {
+ msg->conn->err = ERR_MEM;
+ sys_mbox_post(msg->conn->mbox, NULL);
+ return;
+ }
+ udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+ break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ case NETCONN_TCP:
+ msg->conn->pcb.tcp = tcp_new();
+ if (msg->conn->pcb.tcp == NULL) {
+ msg->conn->err = ERR_MEM;
+ sys_mbox_post(msg->conn->mbox, NULL);
+ return;
+ }
+#endif
+ default:
+ break;
+ }
+ }
+ switch (msg->conn->type) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
+ sys_mbox_post(msg->conn->mbox, NULL);
+ break;
+#endif
+#if LWIP_UDP
+ case NETCONN_UDPLITE:
+ /* FALLTHROUGH */
+ case NETCONN_UDPNOCHKSUM:
+ /* FALLTHROUGH */
+ case NETCONN_UDP:
+ udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
+ sys_mbox_post(msg->conn->mbox, NULL);
+ break;
+#endif
+#if LWIP_TCP
+ case NETCONN_TCP:
+ /* tcp_arg(msg->conn->pcb.tcp, msg->conn);*/
+ setup_tcp(msg->conn);
+ tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port,
+ do_connected);
+ /*tcp_output(msg->conn->pcb.tcp);*/
+#endif
+
+ default:
+ break;
+ }
+}
+
+static void
+do_disconnect(struct api_msg_msg *msg)
+{
+
+ switch (msg->conn->type) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ /* Do nothing as connecting is only a helper for upper lwip layers */
+ break;
+#endif
+#if LWIP_UDP
+ case NETCONN_UDPLITE:
+ /* FALLTHROUGH */
+ case NETCONN_UDPNOCHKSUM:
+ /* FALLTHROUGH */
+ case NETCONN_UDP:
+ udp_disconnect(msg->conn->pcb.udp);
+ break;
+#endif
+ case NETCONN_TCP:
+ break;
+ }
+ sys_mbox_post(msg->conn->mbox, NULL);
+}
+
+
+static void
+do_listen(struct api_msg_msg *msg)
+{
+ if (msg->conn->pcb.tcp != NULL) {
+ switch (msg->conn->type) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: listen RAW: cannot listen for RAW.\n"));
+ break;
+#endif
+#if LWIP_UDP
+ case NETCONN_UDPLITE:
+ /* FALLTHROUGH */
+ case NETCONN_UDPNOCHKSUM:
+ /* FALLTHROUGH */
+ case NETCONN_UDP:
+ LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: listen UDP: cannot listen for UDP.\n"));
+ break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ case NETCONN_TCP:
+ msg->conn->pcb.tcp = tcp_listen(msg->conn->pcb.tcp);
+ if (msg->conn->pcb.tcp == NULL) {
+ msg->conn->err = ERR_MEM;
+ } else {
+ if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
+ msg->conn->acceptmbox = sys_mbox_new();
+ if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
+ msg->conn->err = ERR_MEM;
+ break;
+ }
+ }
+ tcp_arg(msg->conn->pcb.tcp, msg->conn);
+ tcp_accept(msg->conn->pcb.tcp, accept_function);
+ }
+#endif
+ default:
+ break;
+ }
+ }
+ sys_mbox_post(msg->conn->mbox, NULL);
+}
+
+static void
+do_accept(struct api_msg_msg *msg)
+{
+ if (msg->conn->pcb.tcp != NULL) {
+ switch (msg->conn->type) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: accept RAW: cannot accept for RAW.\n"));
+ break;
+#endif
+#if LWIP_UDP
+ case NETCONN_UDPLITE:
+ /* FALLTHROUGH */
+ case NETCONN_UDPNOCHKSUM:
+ /* FALLTHROUGH */
+ case NETCONN_UDP:
+ LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: accept UDP: cannot accept for UDP.\n"));
+ break;
+#endif /* LWIP_UDP */
+ case NETCONN_TCP:
+ break;
+ }
+ }
+}
+
+static void
+do_send(struct api_msg_msg *msg)
+{
+ if (msg->conn->pcb.tcp != NULL) {
+ switch (msg->conn->type) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ raw_send(msg->conn->pcb.raw, msg->msg.p);
+ break;
+#endif
+#if LWIP_UDP
+ case NETCONN_UDPLITE:
+ /* FALLTHROUGH */
+ case NETCONN_UDPNOCHKSUM:
+ /* FALLTHROUGH */
+ case NETCONN_UDP:
+ udp_send(msg->conn->pcb.udp, msg->msg.p);
+ break;
+#endif /* LWIP_UDP */
+ case NETCONN_TCP:
+ break;
+ }
+ }
+ sys_mbox_post(msg->conn->mbox, NULL);
+}
+
+static void
+do_recv(struct api_msg_msg *msg)
+{
+#if LWIP_TCP
+ if (msg->conn->pcb.tcp != NULL) {
+ if (msg->conn->type == NETCONN_TCP) {
+ tcp_recved(msg->conn->pcb.tcp, msg->msg.len);
+ }
+ }
+#endif
+ sys_mbox_post(msg->conn->mbox, NULL);
+}
+
+static void
+do_write(struct api_msg_msg *msg)
+{
+#if LWIP_TCP
+ err_t err;
+#endif
+ if (msg->conn->pcb.tcp != NULL) {
+ switch (msg->conn->type) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ msg->conn->err = ERR_VAL;
+ break;
+#endif
+#if LWIP_UDP
+ case NETCONN_UDPLITE:
+ /* FALLTHROUGH */
+ case NETCONN_UDPNOCHKSUM:
+ /* FALLTHROUGH */
+ case NETCONN_UDP:
+ msg->conn->err = ERR_VAL;
+ break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ case NETCONN_TCP:
+ err = tcp_write(msg->conn->pcb.tcp, msg->msg.w.dataptr,
+ msg->msg.w.len, msg->msg.w.copy);
+ /* This is the Nagle algorithm: inhibit the sending of new TCP
+ segments when new outgoing data arrives from the user if any
+ previously transmitted data on the connection remains
+ unacknowledged. */
+ if(err == ERR_OK && (msg->conn->pcb.tcp->unacked == NULL || (msg->conn->pcb.tcp->flags & TF_NODELAY)) ) {
+ tcp_output(msg->conn->pcb.tcp);
+ }
+ msg->conn->err = err;
+ if (msg->conn->callback)
+ if (err == ERR_OK)
+ {
+ if (tcp_sndbuf(msg->conn->pcb.tcp) <= TCP_SNDLOWAT)
+ (*msg->conn->callback)(msg->conn, NETCONN_EVT_SENDMINUS, msg->msg.w.len);
+ }
+#endif
+ default:
+ break;
+ }
+ }
+ sys_mbox_post(msg->conn->mbox, NULL);
+}
+
+static void
+do_close(struct api_msg_msg *msg)
+{
+ err_t err;
+
+ err = ERR_OK;
+
+ if (msg->conn->pcb.tcp != NULL) {
+ switch (msg->conn->type) {
+#if LWIP_RAW
+ case NETCONN_RAW:
+ break;
+#endif
+#if LWIP_UDP
+ case NETCONN_UDPLITE:
+ /* FALLTHROUGH */
+ case NETCONN_UDPNOCHKSUM:
+ /* FALLTHROUGH */
+ case NETCONN_UDP:
+ break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ case NETCONN_TCP:
+ if (msg->conn->pcb.tcp->state == LISTEN) {
+ err = tcp_close(msg->conn->pcb.tcp);
+ }
+ msg->conn->err = err;
+#endif
+ default:
+ break;
+ }
+ }
+ sys_mbox_post(msg->conn->mbox, NULL);
+}
+
+typedef void (* api_msg_decode)(struct api_msg_msg *msg);
+static api_msg_decode decode[API_MSG_MAX] = {
+ do_newconn,
+ do_delconn,
+ do_bind,
+ do_connect,
+ do_disconnect,
+ do_listen,
+ do_accept,
+ do_send,
+ do_recv,
+ do_write,
+ do_close
+ };
+void
+api_msg_input(struct api_msg *msg)
+{
+ decode[msg->type](&(msg->msg));
+}
+
+void
+api_msg_post(struct api_msg *msg)
+{
+ tcpip_apimsg(msg);
+}
+
+
+
diff --git a/lib/lwip/src/api/err.c b/lib/lwip/src/api/err.c
new file mode 100644
index 0000000..b582d88
--- /dev/null
+++ b/lib/lwip/src/api/err.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/err.h"
+
+#ifdef LWIP_DEBUG
+
+static char *err_strerr[] = {"Ok.",
+ "Out of memory error.",
+ "Buffer error.",
+ "Connection aborted.",
+ "Connection reset.",
+ "Connection closed.",
+ "Not connected.",
+ "Illegal value.",
+ "Illegal argument.",
+ "Routing problem.",
+ "Address in use."
+};
+
+
+char *
+lwip_strerr(err_t err)
+{
+ return err_strerr[-err];
+
+}
+
+
+#endif /* LWIP_DEBUG */
diff --git a/lib/lwip/src/api/sockets.c b/lib/lwip/src/api/sockets.c
new file mode 100644
index 0000000..b7333d9
--- /dev/null
+++ b/lib/lwip/src/api/sockets.c
@@ -0,0 +1,1362 @@
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
+ *
+ */
+
+#include <string.h>
+//#include <errno.h>
+
+#include "lwip/opt.h"
+#include "lwip/api.h"
+#include "lwip/arch.h"
+#include "lwip/sys.h"
+
+#include "lwip/sockets.h"
+
+#define NUM_SOCKETS MEMP_NUM_NETCONN
+
+struct lwip_socket {
+ struct netconn *conn;
+ struct netbuf *lastdata;
+ u16_t lastoffset;
+ u16_t rcvevent;
+ u16_t sendevent;
+ u16_t flags;
+ int err;
+};
+
+struct lwip_select_cb
+{
+ struct lwip_select_cb *next;
+ fd_set *readset;
+ fd_set *writeset;
+ fd_set *exceptset;
+ int sem_signalled;
+ sys_sem_t sem;
+};
+
+static struct lwip_socket sockets[NUM_SOCKETS];
+static struct lwip_select_cb *select_cb_list = 0;
+
+static sys_sem_t socksem = 0;
+static sys_sem_t selectsem = 0;
+
+static void
+event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
+
+static int err_to_errno_table[11] = {
+ 0, /* ERR_OK 0 No error, everything OK. */
+ ENOMEM, /* ERR_MEM -1 Out of memory error. */
+ ENOBUFS, /* ERR_BUF -2 Buffer error. */
+ ECONNABORTED, /* ERR_ABRT -3 Connection aborted. */
+ ECONNRESET, /* ERR_RST -4 Connection reset. */
+ ESHUTDOWN, /* ERR_CLSD -5 Connection closed. */
+ ENOTCONN, /* ERR_CONN -6 Not connected. */
+ EINVAL, /* ERR_VAL -7 Illegal value. */
+ EIO, /* ERR_ARG -8 Illegal argument. */
+ EHOSTUNREACH, /* ERR_RTE -9 Routing problem. */
+ EADDRINUSE /* ERR_USE -10 Address in use. */
+};
+
+#define ERR_TO_ERRNO_TABLE_SIZE \
+ (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
+
+#define err_to_errno(err) \
+ (-(err) >= 0 && -(err) < ERR_TO_ERRNO_TABLE_SIZE ? \
+ err_to_errno_table[-(err)] : EIO)
+
+#ifdef ERRNO
+#define set_errno(err) errno = (err)
+#else
+#define set_errno(err)
+#endif
+
+#define sock_set_errno(sk, e) do { \
+ sk->err = (e); \
+ set_errno(sk->err); \
+} while (0)
+
+
+static struct lwip_socket *
+get_socket(int s)
+{
+ struct lwip_socket *sock;
+
+ if ((s < 0) || (s > NUM_SOCKETS)) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
+ set_errno(EBADF);
+ return NULL;
+ }
+
+ sock = &sockets[s];
+
+ if (!sock->conn) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
+ set_errno(EBADF);
+ return NULL;
+ }
+
+ return sock;
+}
+
+static int
+alloc_socket(struct netconn *newconn)
+{
+ int i;
+
+ if (!socksem)
+ socksem = sys_sem_new(1);
+
+ /* Protect socket array */
+ sys_sem_wait(socksem);
+
+ /* allocate a new socket identifier */
+ for(i = 0; i < NUM_SOCKETS; ++i) {
+ if (!sockets[i].conn) {
+ sockets[i].conn = newconn;
+ sockets[i].lastdata = NULL;
+ sockets[i].lastoffset = 0;
+ sockets[i].rcvevent = 0;
+ sockets[i].sendevent = 1; /* TCP send buf is empty */
+ sockets[i].flags = 0;
+ sockets[i].err = 0;
+ sys_sem_signal(socksem);
+ return i;
+ }
+ }
+ sys_sem_signal(socksem);
+ return -1;
+}
+
+int
+lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+ struct lwip_socket *sock;
+ struct netconn *newconn;
+ struct ip_addr naddr;
+ u16_t port;
+ int newsock;
+ struct sockaddr_in sin;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
+ sock = get_socket(s);
+ if (!sock) {
+ set_errno(EBADF);
+ return -1;
+ }
+
+ newconn = netconn_accept(sock->conn);
+
+ /* get the IP address and port of the remote host */
+ netconn_peer(newconn, &naddr, &port);
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ sin.sin_addr.s_addr = naddr.addr;
+
+ if (*addrlen > sizeof(sin))
+ *addrlen = sizeof(sin);
+
+ memcpy(addr, &sin, *addrlen);
+
+ newsock = alloc_socket(newconn);
+ if (newsock == -1) {
+ netconn_delete(newconn);
+ sock_set_errno(sock, ENOBUFS);
+ return -1;
+ }
+ newconn->callback = event_callback;
+ sock = get_socket(newsock);
+
+ sys_sem_wait(socksem);
+ sock->rcvevent += -1 - newconn->socket;
+ newconn->socket = newsock;
+ sys_sem_signal(socksem);
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
+ ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", port));
+
+ sock_set_errno(sock, 0);
+ return newsock;
+}
+
+int
+lwip_bind(int s, struct sockaddr *name, socklen_t namelen)
+{
+ struct lwip_socket *sock;
+ struct ip_addr local_addr;
+ u16_t local_port;
+ err_t err;
+
+ sock = get_socket(s);
+ if (!sock) {
+ set_errno(EBADF);
+ return -1;
+ }
+
+ local_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
+ local_port = ((struct sockaddr_in *)name)->sin_port;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
+ ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(local_port)));
+
+ err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
+
+ if (err != ERR_OK) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
+ sock_set_errno(sock, err_to_errno(err));
+ return -1;
+ }
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
+ sock_set_errno(sock, 0);
+ return 0;
+}
+
+int
+lwip_close(int s)
+{
+ struct lwip_socket *sock;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
+ if (!socksem)
+ socksem = sys_sem_new(1);
+
+ /* We cannot allow multiple closes of the same socket. */
+ sys_sem_wait(socksem);
+
+ sock = get_socket(s);
+ if (!sock) {
+ sys_sem_signal(socksem);
+ set_errno(EBADF);
+ return -1;
+ }
+
+ netconn_delete(sock->conn);
+ if (sock->lastdata) {
+ netbuf_delete(sock->lastdata);
+ }
+ sock->lastdata = NULL;
+ sock->lastoffset = 0;
+ sock->conn = NULL;
+ sys_sem_signal(socksem);
+ sock_set_errno(sock, 0);
+ return 0;
+}
+
+int
+lwip_connect(int s, struct sockaddr *name, socklen_t namelen)
+{
+ struct lwip_socket *sock;
+ err_t err;
+
+ sock = get_socket(s);
+ if (!sock) {
+ set_errno(EBADF);
+ return -1;
+ }
+
+ if (((struct sockaddr_in *)name)->sin_family == AF_UNSPEC) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
+ err = netconn_disconnect(sock->conn);
+ } else {
+ struct ip_addr remote_addr;
+ u16_t remote_port;
+
+ remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
+ remote_port = ((struct sockaddr_in *)name)->sin_port;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
+ ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(remote_port)));
+
+ err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
+ }
+
+ if (err != ERR_OK) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
+ sock_set_errno(sock, err_to_errno(err));
+ return -1;
+ }
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
+ sock_set_errno(sock, 0);
+ return 0;
+}
+
+int
+lwip_listen(int s, int backlog)
+{
+ struct lwip_socket *sock;
+ err_t err;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
+ sock = get_socket(s);
+ if (!sock) {
+ set_errno(EBADF);
+ return -1;
+ }
+
+ err = netconn_listen(sock->conn);
+
+ if (err != ERR_OK) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
+ sock_set_errno(sock, err_to_errno(err));
+ return -1;
+ }
+
+ sock_set_errno(sock, 0);
+ return 0;
+}
+
+int
+lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
+ struct sockaddr *from, socklen_t *fromlen)
+{
+ struct lwip_socket *sock;
+ struct netbuf *buf;
+ u16_t buflen, copylen;
+ struct ip_addr *addr;
+ u16_t port;
+
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags));
+ sock = get_socket(s);
+ if (!sock) {
+ set_errno(EBADF);
+ return -1;
+ }
+
+ /* Check if there is data left from the last recv operation. */
+ if (sock->lastdata) {
+ buf = sock->lastdata;
+ } else {
+ /* If this is non-blocking call, then check first */
+ if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK))
+ && !sock->rcvevent)
+ {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
+ sock_set_errno(sock, EWOULDBLOCK);
+ return -1;
+ }
+
+ /* No data was left from the previous operation, so we try to get
+ some from the network. */
+ buf = netconn_recv(sock->conn);
+
+ if (!buf) {
+ /* We should really do some error checking here. */
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s));
+ sock_set_errno(sock, 0);
+ return 0;
+ }
+ }
+
+ buflen = netbuf_len(buf);
+
+ buflen -= sock->lastoffset;
+
+ if (len > buflen) {
+ copylen = buflen;
+ } else {
+ copylen = len;
+ }
+
+ /* copy the contents of the received buffer into
+ the supplied memory pointer mem */
+ netbuf_copy_partial(buf, mem, copylen, sock->lastoffset);
+
+ /* Check to see from where the data was. */
+ if (from && fromlen) {
+ struct sockaddr_in sin;
+
+ addr = netbuf_fromaddr(buf);
+ port = netbuf_fromport(buf);
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ sin.sin_addr.s_addr = addr->addr;
+
+ if (*fromlen > sizeof(sin))
+ *fromlen = sizeof(sin);
+
+ memcpy(from, &sin, *fromlen);
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
+ ip_addr_debug_print(SOCKETS_DEBUG, addr);
+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));
+ } else {
+#if SOCKETS_DEBUG
+ addr = netbuf_fromaddr(buf);
+ port = netbuf_fromport(buf);
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
+ ip_addr_debug_print(SOCKETS_DEBUG, addr);
+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));
+#endif
+
+ }
+
+ /* If this is a TCP socket, check if there is data left in the
+ buffer. If so, it should be saved in the sock structure for next
+ time around. */
+ if (netconn_type(sock->conn) == NETCONN_TCP && buflen - copylen > 0) {
+ sock->lastdata = buf;
+ sock->lastoffset += copylen;
+ } else {
+ sock->lastdata = NULL;
+ sock->lastoffset = 0;
+ netbuf_delete(buf);
+ }
+
+
+ sock_set_errno(sock, 0);
+ return copylen;
+}
+
+int
+lwip_read(int s, void *mem, int len)
+{
+ return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
+}
+
+int
+lwip_recv(int s, void *mem, int len, unsigned int flags)
+{
+ return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
+}
+
+int
+lwip_send(int s, void *data, int size, unsigned int flags)
+{
+ struct lwip_socket *sock;
+ struct netbuf *buf;
+ err_t err;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%d, flags=0x%x)\n", s, data, size, flags));
+
+ sock = get_socket(s);
+ if (!sock) {
+ set_errno(EBADF);
+ return -1;
+ }
+
+ switch (netconn_type(sock->conn)) {
+ case NETCONN_RAW:
+ case NETCONN_UDP:
+ case NETCONN_UDPLITE:
+ case NETCONN_UDPNOCHKSUM:
+ /* create a buffer */
+ buf = netbuf_new();
+
+ if (!buf) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) ENOBUFS\n", s));
+ sock_set_errno(sock, ENOBUFS);
+ return -1;
+ }
+
+ /* make the buffer point to the data that should
+ be sent */
+ netbuf_ref(buf, data, size);
+
+ /* send the data */
+ err = netconn_send(sock->conn, buf);
+
+ /* deallocated the buffer */
+ netbuf_delete(buf);
+ break;
+ case NETCONN_TCP:
+ err = netconn_write(sock->conn, data, size, NETCONN_COPY);
+ break;
+ default:
+ err = ERR_ARG;
+ break;
+ }
+ if (err != ERR_OK) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d\n", s, err));
+ sock_set_errno(sock, err_to_errno(err));
+ return -1;
+ }
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) ok size=%d\n", s, size));
+ sock_set_errno(sock, 0);
+ return size;
+}
+
+int
+lwip_sendto(int s, void *data, int size, unsigned int flags,
+ struct sockaddr *to, socklen_t tolen)
+{
+ struct lwip_socket *sock;
+ struct ip_addr remote_addr, addr;
+ u16_t remote_port, port;
+ int ret,connected;
+
+ sock = get_socket(s);
+ if (!sock) {
+ set_errno(EBADF);
+ return -1;
+ }
+
+ /* get the peer if currently connected */
+ connected = (netconn_peer(sock->conn, &addr, &port) == ERR_OK);
+
+ remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;
+ remote_port = ((struct sockaddr_in *)to)->sin_port;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, size=%d, flags=0x%x to=", s, data, size, flags));
+ ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", ntohs(remote_port)));
+
+ netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
+
+ ret = lwip_send(s, data, size, flags);
+
+ /* reset the remote address and port number
+ of the connection */
+ if (connected)
+ netconn_connect(sock->conn, &addr, port);
+ else
+ netconn_disconnect(sock->conn);
+ return ret;
+}
+
+int
+lwip_socket(int domain, int type, int protocol)
+{
+ struct netconn *conn;
+ int i;
+
+ /* create a netconn */
+ switch (type) {
+ case SOCK_RAW:
+ conn = netconn_new_with_proto_and_callback(NETCONN_RAW, protocol, event_callback);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
+ break;
+ case SOCK_DGRAM:
+ conn = netconn_new_with_callback(NETCONN_UDP, event_callback);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
+ break;
+ case SOCK_STREAM:
+ conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
+ break;
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", domain, type, protocol));
+ set_errno(EINVAL);
+ return -1;
+ }
+
+ if (!conn) {
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
+ set_errno(ENOBUFS);
+ return -1;
+ }
+
+ i = alloc_socket(conn);
+
+ if (i == -1) {
+ netconn_delete(conn);
+ set_errno(ENOBUFS);
+ return -1;
+ }
+ conn->socket = i;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
+ set_errno(0);
+ return i;
+}
+
+int
+lwip_write(int s, void *data, int size)
+{
+ return lwip_send(s, data, size, 0);
+}
+
+
+static int
+lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset)
+{
+ int i, nready = 0;
+ fd_set lreadset, lwriteset, lexceptset;
+ struct lwip_socket *p_sock;
+
+ FD_ZERO(&lreadset);
+ FD_ZERO(&lwriteset);
+ FD_ZERO(&lexceptset);
+
+ /* Go through each socket in each list to count number of sockets which
+ currently match */
+ for(i = 0; i < maxfdp1; i++)
+ {
+ if (FD_ISSET(i, readset))
+ {
+ /* See if netconn of this socket is ready for read */
+ p_sock = get_socket(i);
+ if (p_sock && (p_sock->lastdata || p_sock->rcvevent))
+ {
+ FD_SET(i, &lreadset);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
+ nready++;
+ }
+ }
+ if (FD_ISSET(i, writeset))
+ {
+ /* See if netconn of this socket is ready for write */
+ p_sock = get_socket(i);
+ if (p_sock && p_sock->sendevent)
+ {
+ FD_SET(i, &lwriteset);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
+ nready++;
+ }
+ }
+ }
+ *readset = lreadset;
+ *writeset = lwriteset;
+ FD_ZERO(exceptset);
+
+ return nready;
+}
+
+
+
+int
+lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
+ struct timeval *timeout)
+{
+ int i;
+ int nready;
+ fd_set lreadset, lwriteset, lexceptset;
+ u32_t msectimeout;
+ struct lwip_select_cb select_cb;
+ struct lwip_select_cb *p_selcb;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n", maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, timeout ? timeout->tv_sec : -1L, timeout ? timeout->tv_usec : -1L));
+
+ select_cb.next = 0;
+ select_cb.readset = readset;
+ select_cb.writeset = writeset;
+ select_cb.exceptset = exceptset;
+ select_cb.sem_signalled = 0;
+
+ /* Protect ourselves searching through the list */
+ if (!selectsem)
+ selectsem = sys_sem_new(1);
+ sys_sem_wait(selectsem);
+
+ if (readset)
+ lreadset = *readset;
+ else
+ FD_ZERO(&lreadset);
+ if (writeset)
+ lwriteset = *writeset;
+ else
+ FD_ZERO(&lwriteset);
+ if (exceptset)
+ lexceptset = *exceptset;
+ else
+ FD_ZERO(&lexceptset);
+
+ /* Go through each socket in each list to count number of sockets which
+ currently match */
+ nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
+
+ /* If we don't have any current events, then suspend if we are supposed to */
+ if (!nready)
+ {
+ if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
+ {
+ sys_sem_signal(selectsem);
+ if (readset)
+ FD_ZERO(readset);
+ if (writeset)
+ FD_ZERO(writeset);
+ if (exceptset)
+ FD_ZERO(exceptset);
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
+ set_errno(0);
+
+ return 0;
+ }
+
+ /* 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 */
+
+ select_cb.sem = sys_sem_new(0);
+ /* Note that we are still protected */
+ /* Put this select_cb on top of list */
+ select_cb.next = select_cb_list;
+ select_cb_list = &select_cb;
+
+ /* Now we can safely unprotect */
+ sys_sem_signal(selectsem);
+
+ /* Now just wait to be woken */
+ if (timeout == 0)
+ /* Wait forever */
+ msectimeout = 0;
+ else
+ msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
+
+ i = sys_sem_wait_timeout(select_cb.sem, msectimeout);
+
+ /* Take us off the list */
+ sys_sem_wait(selectsem);
+ if (select_cb_list == &select_cb)
+ select_cb_list = select_cb.next;
+ else
+ for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next)
+ if (p_selcb->next == &select_cb)
+ {
+ p_selcb->next = select_cb.next;
+ break;
+ }
+
+ sys_sem_signal(selectsem);
+
+ sys_sem_free(select_cb.sem);
+ if (i == 0) /* Timeout */
+ {
+ if (readset)
+ FD_ZERO(readset);
+ if (writeset)
+ FD_ZERO(writeset);
+ if (exceptset)
+ FD_ZERO(exceptset);
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
+ set_errno(0);
+
+ return 0;
+ }
+
+ if (readset)
+ lreadset = *readset;
+ else
+ FD_ZERO(&lreadset);
+ if (writeset)
+ lwriteset = *writeset;
+ else
+ FD_ZERO(&lwriteset);
+ if (exceptset)
+ lexceptset = *exceptset;
+ else
+ FD_ZERO(&lexceptset);
+
+ /* See what's set */
+ nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
+ }
+ else
+ sys_sem_signal(selectsem);
+
+ if (readset)
+ *readset = lreadset;
+ if (writeset)
+ *writeset = lwriteset;
+ if (exceptset)
+ *exceptset = lexceptset;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
+ set_errno(0);
+
+ return nready;
+}
+
+
+static void
+event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
+{
+ int s;
+ struct lwip_socket *sock;
+ struct lwip_select_cb *scb;
+
+ /* Get socket */
+ if (conn)
+ {
+ s = conn->socket;
+ if (s < 0)
+ {
+ /* Data comes in right away after an accept, even though
+ * the server task might not have created a new socket yet.
+ * Just count down (or up) if that's the case and we
+ * will use the data later. Note that only receive events
+ * can happen before the new socket is set up. */
+ if (evt == NETCONN_EVT_RCVPLUS)
+ conn->socket--;
+ return;
+ }
+
+ sock = get_socket(s);
+ if (!sock)
+ return;
+ }
+ else
+ return;
+
+ if (!selectsem)
+ selectsem = sys_sem_new(1);
+
+ sys_sem_wait(selectsem);
+ /* Set event as required */
+ switch (evt)
+ {
+ case NETCONN_EVT_RCVPLUS:
+ sock->rcvevent++;
+ break;
+ case NETCONN_EVT_RCVMINUS:
+ sock->rcvevent--;
+ break;
+ case NETCONN_EVT_SENDPLUS:
+ sock->sendevent = 1;
+ break;
+ case NETCONN_EVT_SENDMINUS:
+ sock->sendevent = 0;
+ break;
+ }
+ sys_sem_signal(selectsem);
+
+ /* Now decide if anyone is waiting for this socket */
+ /* NOTE: This code is written this way to protect the select link list
+ but to avoid a deadlock situation by releasing socksem before
+ signalling for the select. This means we need to go through the list
+ multiple times ONLY IF a select was actually waiting. We go through
+ the list the number of waiting select calls + 1. This list is
+ expected to be small. */
+ while (1)
+ {
+ sys_sem_wait(selectsem);
+ for (scb = select_cb_list; scb; scb = scb->next)
+ {
+ if (scb->sem_signalled == 0)
+ {
+ /* Test this select call for our socket */
+ if (scb->readset && FD_ISSET(s, scb->readset))
+ if (sock->rcvevent)
+ break;
+ if (scb->writeset && FD_ISSET(s, scb->writeset))
+ if (sock->sendevent)
+ break;
+ }
+ }
+ if (scb)
+ {
+ scb->sem_signalled = 1;
+ sys_sem_signal(selectsem);
+ sys_sem_signal(scb->sem);
+ } else {
+ sys_sem_signal(selectsem);
+ break;
+ }
+ }
+
+}
+
+
+
+
+int lwip_shutdown(int s, int how)
+{
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
+ return lwip_close(s); /* XXX temporary hack until proper implementation */
+}
+
+int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen)
+{
+ struct lwip_socket *sock;
+ struct sockaddr_in sin;
+ struct ip_addr naddr;
+
+ sock = get_socket(s);
+ if (!sock) {
+ set_errno(EBADF);
+ return -1;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+
+ /* get the IP address and port of the remote host */
+ netconn_peer(sock->conn, &naddr, &sin.sin_port);
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getpeername(%d, addr=", s));
+ ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));
+
+ sin.sin_port = htons(sin.sin_port);
+ sin.sin_addr.s_addr = naddr.addr;
+
+ if (*namelen > sizeof(sin))
+ *namelen = sizeof(sin);
+
+ memcpy(name, &sin, *namelen);
+ sock_set_errno(sock, 0);
+ return 0;
+}
+
+int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen)
+{
+ struct lwip_socket *sock;
+ struct sockaddr_in sin;
+ struct ip_addr *naddr;
+
+ sock = get_socket(s);
+ if (!sock) {
+ set_errno(EBADF);
+ return -1;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+
+ /* get the IP address and port of the remote host */
+ netconn_addr(sock->conn, &naddr, &sin.sin_port);
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockname(%d, addr=", s));
+ ip_addr_debug_print(SOCKETS_DEBUG, naddr);
+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));
+
+ sin.sin_port = htons(sin.sin_port);
+ sin.sin_addr.s_addr = naddr->addr;
+
+ if (*namelen > sizeof(sin))
+ *namelen = sizeof(sin);
+
+ memcpy(name, &sin, *namelen);
+ sock_set_errno(sock, 0);
+ return 0;
+}
+
+int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen)
+{
+ int err = 0;
+ struct lwip_socket *sock = get_socket(s);
+
+ if(!sock) {
+ set_errno(EBADF);
+ return -1;
+ }
+
+ if( NULL == optval || NULL == optlen ) {
+ sock_set_errno( sock, EFAULT );
+ return -1;
+ }
+
+ /* Do length and type checks for the various options first, to keep it readable. */
+ switch( level ) {
+
+/* Level: SOL_SOCKET */
+ case SOL_SOCKET:
+ switch(optname) {
+
+ case SO_ACCEPTCONN:
+ case SO_BROADCAST:
+ /* UNIMPL case SO_DEBUG: */
+ /* UNIMPL case SO_DONTROUTE: */
+ case SO_ERROR:
+ case SO_KEEPALIVE:
+ /* UNIMPL case SO_OOBINLINE: */
+ /* UNIMPL case SO_RCVBUF: */
+ /* UNIMPL case SO_SNDBUF: */
+ /* UNIMPL case SO_RCVLOWAT: */
+ /* UNIMPL case SO_SNDLOWAT: */
+#if SO_REUSE
+ case SO_REUSEADDR:
+ case SO_REUSEPORT:
+#endif /* SO_REUSE */
+ case SO_TYPE:
+ /* UNIMPL case SO_USELOOPBACK: */
+ if( *optlen < sizeof(int) ) {
+ err = EINVAL;
+ }
+ break;
+
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname));
+ err = ENOPROTOOPT;
+ } /* switch */
+ break;
+
+/* Level: IPPROTO_IP */
+ case IPPROTO_IP:
+ switch(optname) {
+ /* UNIMPL case IP_HDRINCL: */
+ /* UNIMPL case IP_RCVDSTADDR: */
+ /* UNIMPL case IP_RCVIF: */
+ case IP_TTL:
+ case IP_TOS:
+ if( *optlen < sizeof(int) ) {
+ err = EINVAL;
+ }
+ break;
+
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname));
+ err = ENOPROTOOPT;
+ } /* switch */
+ break;
+
+/* Level: IPPROTO_TCP */
+ case IPPROTO_TCP:
+ if( *optlen < sizeof(int) ) {
+ err = EINVAL;
+ break;
+ }
+
+ /* If this is no TCP socket, ignore any options. */
+ if ( sock->conn->type != NETCONN_TCP ) return 0;
+
+ switch( optname ) {
+ case TCP_NODELAY:
+ case TCP_KEEPALIVE:
+ break;
+
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname));
+ err = ENOPROTOOPT;
+ } /* switch */
+ break;
+
+/* UNDEFINED LEVEL */
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname));
+ err = ENOPROTOOPT;
+ } /* switch */
+
+
+ if( 0 != err ) {
+ sock_set_errno(sock, err);
+ return -1;
+ }
+
+
+
+ /* Now do the actual option processing */
+
+ switch(level) {
+
+/* Level: SOL_SOCKET */
+ case SOL_SOCKET:
+ switch( optname ) {
+
+ /* The option flags */
+ case SO_ACCEPTCONN:
+ case SO_BROADCAST:
+ /* UNIMPL case SO_DEBUG: */
+ /* UNIMPL case SO_DONTROUTE: */
+ case SO_KEEPALIVE:
+ /* UNIMPL case SO_OOBINCLUDE: */
+#if SO_REUSE
+ case SO_REUSEADDR:
+ case SO_REUSEPORT:
+#endif /* SO_REUSE */
+ /*case SO_USELOOPBACK: UNIMPL */
+ *(int*)optval = sock->conn->pcb.tcp->so_options & optname;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", s, optname, (*(int*)optval?"on":"off")));
+ break;
+
+ case SO_TYPE:
+ switch (sock->conn->type) {
+ case NETCONN_RAW:
+ *(int*)optval = SOCK_RAW;
+ break;
+ case NETCONN_TCP:
+ *(int*)optval = SOCK_STREAM;
+ break;
+ case NETCONN_UDP:
+ case NETCONN_UDPLITE:
+ case NETCONN_UDPNOCHKSUM:
+ *(int*)optval = SOCK_DGRAM;
+ break;
+ default: /* unrecognized socket type */
+ *(int*)optval = sock->conn->type;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", s, *(int *)optval));
+ } /* switch */
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", s, *(int *)optval));
+ break;
+
+ case SO_ERROR:
+ *(int *)optval = sock->err;
+ sock->err = 0;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", s, *(int *)optval));
+ break;
+ } /* switch */
+ break;
+
+/* Level: IPPROTO_IP */
+ case IPPROTO_IP:
+ switch( optname ) {
+ case IP_TTL:
+ *(int*)optval = sock->conn->pcb.tcp->ttl;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", s, *(int *)optval));
+ break;
+ case IP_TOS:
+ *(int*)optval = sock->conn->pcb.tcp->tos;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", s, *(int *)optval));
+ break;
+ } /* switch */
+ break;
+
+/* Level: IPPROTO_TCP */
+ case IPPROTO_TCP:
+ switch( optname ) {
+ case TCP_NODELAY:
+ *(int*)optval = (sock->conn->pcb.tcp->flags & TF_NODELAY);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", s, (*(int*)optval)?"on":"off") );
+ break;
+ case TCP_KEEPALIVE:
+ *(int*)optval = (int)sock->conn->pcb.tcp->keepalive;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", s, *(int *)optval));
+ break;
+ } /* switch */
+ break;
+ }
+
+
+ sock_set_errno(sock, err);
+ return err ? -1 : 0;
+}
+
+int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen)
+{
+ struct lwip_socket *sock = get_socket(s);
+ int err = 0;
+
+ if(!sock) {
+ set_errno(EBADF);
+ return -1;
+ }
+
+ if( NULL == optval ) {
+ sock_set_errno( sock, EFAULT );
+ return -1;
+ }
+
+
+ /* Do length and type checks for the various options first, to keep it readable. */
+ switch( level ) {
+
+/* Level: SOL_SOCKET */
+ case SOL_SOCKET:
+ switch(optname) {
+
+ case SO_BROADCAST:
+ /* UNIMPL case SO_DEBUG: */
+ /* UNIMPL case SO_DONTROUTE: */
+ case SO_KEEPALIVE:
+ /* UNIMPL case SO_OOBINLINE: */
+ /* UNIMPL case SO_RCVBUF: */
+ /* UNIMPL case SO_SNDBUF: */
+ /* UNIMPL case SO_RCVLOWAT: */
+ /* UNIMPL case SO_SNDLOWAT: */
+#if SO_REUSE
+ case SO_REUSEADDR:
+ case SO_REUSEPORT:
+#endif /* SO_REUSE */
+ /* UNIMPL case SO_USELOOPBACK: */
+ if( optlen < sizeof(int) ) {
+ err = EINVAL;
+ }
+ break;
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname));
+ err = ENOPROTOOPT;
+ } /* switch */
+ break;
+
+/* Level: IPPROTO_IP */
+ case IPPROTO_IP:
+ switch(optname) {
+ /* UNIMPL case IP_HDRINCL: */
+ /* UNIMPL case IP_RCVDSTADDR: */
+ /* UNIMPL case IP_RCVIF: */
+ case IP_TTL:
+ case IP_TOS:
+ if( optlen < sizeof(int) ) {
+ err = EINVAL;
+ }
+ break;
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname));
+ err = ENOPROTOOPT;
+ } /* switch */
+ break;
+
+/* Level: IPPROTO_TCP */
+ case IPPROTO_TCP:
+ if( optlen < sizeof(int) ) {
+ err = EINVAL;
+ break;
+ }
+
+ /* If this is no TCP socket, ignore any options. */
+ if ( sock->conn->type != NETCONN_TCP ) return 0;
+
+ switch( optname ) {
+ case TCP_NODELAY:
+ case TCP_KEEPALIVE:
+ break;
+
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname));
+ err = ENOPROTOOPT;
+ } /* switch */
+ break;
+
+/* UNDEFINED LEVEL */
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname));
+ err = ENOPROTOOPT;
+ } /* switch */
+
+
+ if( 0 != err ) {
+ sock_set_errno(sock, err);
+ return -1;
+ }
+
+
+
+ /* Now do the actual option processing */
+
+ switch(level) {
+
+/* Level: SOL_SOCKET */
+ case SOL_SOCKET:
+ switch(optname) {
+
+ /* The option flags */
+ case SO_BROADCAST:
+ /* UNIMPL case SO_DEBUG: */
+ /* UNIMPL case SO_DONTROUTE: */
+ case SO_KEEPALIVE:
+ /* UNIMPL case SO_OOBINCLUDE: */
+#if SO_REUSE
+ case SO_REUSEADDR:
+ case SO_REUSEPORT:
+#endif /* SO_REUSE */
+ /* UNIMPL case SO_USELOOPBACK: */
+ if ( *(int*)optval ) {
+ sock->conn->pcb.tcp->so_options |= optname;
+ } else {
+ sock->conn->pcb.tcp->so_options &= ~optname;
+ }
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", s, optname, (*(int*)optval?"on":"off")));
+ break;
+ } /* switch */
+ break;
+
+/* Level: IPPROTO_IP */
+ case IPPROTO_IP:
+ switch( optname ) {
+ case IP_TTL:
+ sock->conn->pcb.tcp->ttl = (u8_t)(*(int*)optval);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %u\n", s, sock->conn->pcb.tcp->ttl));
+ break;
+ case IP_TOS:
+ sock->conn->pcb.tcp->tos = (u8_t)(*(int*)optval);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n", s, sock->conn->pcb.tcp->tos));
+ break;
+ } /* switch */
+ break;
+
+/* Level: IPPROTO_TCP */
+ case IPPROTO_TCP:
+ switch( optname ) {
+ case TCP_NODELAY:
+ if ( *(int*)optval ) {
+ sock->conn->pcb.tcp->flags |= TF_NODELAY;
+ } else {
+ sock->conn->pcb.tcp->flags &= ~TF_NODELAY;
+ }
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", s, (*(int *)optval)?"on":"off") );
+ break;
+ case TCP_KEEPALIVE:
+ sock->conn->pcb.tcp->keepalive = (u32_t)(*(int*)optval);
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %lu\n", s, sock->conn->pcb.tcp->keepalive));
+ break;
+ } /* switch */
+ break;
+ } /* switch */
+
+ sock_set_errno(sock, err);
+ return err ? -1 : 0;
+}
+
+int lwip_ioctl(int s, long cmd, void *argp)
+{
+ struct lwip_socket *sock = get_socket(s);
+
+ if(!sock) {
+ set_errno(EBADF);
+ return -1;
+ }
+
+ switch (cmd) {
+ case FIONREAD:
+ if (!argp) {
+ sock_set_errno(sock, EINVAL);
+ return -1;
+ }
+
+ *((u16_t*)argp) = sock->conn->recv_avail;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %u\n", s, argp, *((u16_t*)argp)));
+ sock_set_errno(sock, 0);
+ return 0;
+
+ case FIONBIO:
+ if (argp && *(u32_t*)argp)
+ sock->flags |= O_NONBLOCK;
+ else
+ sock->flags &= ~O_NONBLOCK;
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK)));
+ sock_set_errno(sock, 0);
+ return 0;
+
+ default:
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
+ sock_set_errno(sock, ENOSYS); /* not yet implemented */
+ return -1;
+ }
+}
+
diff --git a/lib/lwip/src/api/tcpip.c b/lib/lwip/src/api/tcpip.c
new file mode 100644
index 0000000..ce8a2ca
--- /dev/null
+++ b/lib/lwip/src/api/tcpip.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/sys.h"
+
+#include "lwip/memp.h"
+#include "lwip/pbuf.h"
+
+#include "lwip/ip.h"
+#include "lwip/ip_frag.h"
+#include "lwip/udp.h"
+#include "lwip/tcp.h"
+
+#include "lwip/tcpip.h"
+
+static void (* tcpip_init_done)(void *arg) = NULL;
+static void *tcpip_init_done_arg;
+static sys_mbox_t mbox;
+
+#if LWIP_TCP
+static int tcpip_tcp_timer_active = 0;
+
+static void
+tcpip_tcp_timer(void *arg)
+{
+ (void)arg;
+
+ /* call TCP timer handler */
+ tcp_tmr();
+ /* timer still needed? */
+ if (tcp_active_pcbs || tcp_tw_pcbs) {
+ /* restart timer */
+ sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
+ } else {
+ /* disable timer */
+ tcpip_tcp_timer_active = 0;
+ }
+}
+
+#if !NO_SYS
+void
+tcp_timer_needed(void)
+{
+ /* timer is off but needed again? */
+ if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
+ /* enable and start timer */
+ tcpip_tcp_timer_active = 1;
+ sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
+ }
+}
+#endif /* !NO_SYS */
+#endif /* LWIP_TCP */
+
+#if IP_REASSEMBLY
+static void
+ip_timer(void *data)
+{
+ LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n"));
+ ip_reass_tmr();
+ sys_timeout(1000, ip_timer, NULL);
+}
+#endif
+
+static void
+tcpip_thread(void *arg)
+{
+ struct tcpip_msg *msg;
+
+ (void)arg;
+
+ ip_init();
+#if LWIP_UDP
+ udp_init();
+#endif
+#if LWIP_TCP
+ tcp_init();
+#endif
+#if IP_REASSEMBLY
+ sys_timeout(1000, ip_timer, NULL);
+#endif
+ if (tcpip_init_done != NULL) {
+ tcpip_init_done(tcpip_init_done_arg);
+ }
+
+ while (1) { /* MAIN Loop */
+ sys_mbox_fetch(mbox, (void *)&msg);
+ switch (msg->type) {
+ case TCPIP_MSG_API:
+ LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
+ api_msg_input(msg->msg.apimsg);
+ break;
+ case TCPIP_MSG_INPUT:
+ LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: IP packet %p\n", (void *)msg));
+ ip_input(msg->msg.inp.p, msg->msg.inp.netif);
+ break;
+ case TCPIP_MSG_CALLBACK:
+ LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
+ msg->msg.cb.f(msg->msg.cb.ctx);
+ break;
+ default:
+ break;
+ }
+ memp_free(MEMP_TCPIP_MSG, msg);
+ }
+}
+
+err_t
+tcpip_input(struct pbuf *p, struct netif *inp)
+{
+ struct tcpip_msg *msg;
+
+ msg = memp_malloc(MEMP_TCPIP_MSG);
+ if (msg == NULL) {
+ pbuf_free(p);
+ return ERR_MEM;
+ }
+
+ msg->type = TCPIP_MSG_INPUT;
+ msg->msg.inp.p = p;
+ msg->msg.inp.netif = inp;
+ sys_mbox_post(mbox, msg);
+ return ERR_OK;
+}
+
+err_t
+tcpip_callback(void (*f)(void *ctx), void *ctx)
+{
+ struct tcpip_msg *msg;
+
+ msg = memp_malloc(MEMP_TCPIP_MSG);
+ if (msg == NULL) {
+ return ERR_MEM;
+ }
+
+ msg->type = TCPIP_MSG_CALLBACK;
+ msg->msg.cb.f = f;
+ msg->msg.cb.ctx = ctx;
+ sys_mbox_post(mbox, msg);
+ return ERR_OK;
+}
+
+void
+tcpip_apimsg(struct api_msg *apimsg)
+{
+ struct tcpip_msg *msg;
+ msg = memp_malloc(MEMP_TCPIP_MSG);
+ if (msg == NULL) {
+ memp_free(MEMP_API_MSG, apimsg);
+ return;
+ }
+ msg->type = TCPIP_MSG_API;
+ msg->msg.apimsg = apimsg;
+ sys_mbox_post(mbox, msg);
+}
+
+void
+tcpip_init(void (* initfunc)(void *), void *arg)
+{
+ tcpip_init_done = initfunc;
+ tcpip_init_done_arg = arg;
+ mbox = sys_mbox_new();
+ sys_thread_new(tcpip_thread, NULL, TCPIP_THREAD_PRIO);
+}
+
+
+
+