Update to V4.3.0 as described in http://www.FreeRTOS.org/History.txt
diff --git a/Demo/lwIP_MCF5235_GCC/lwip/src/api/api_lib.c b/Demo/lwIP_MCF5235_GCC/lwip/src/api/api_lib.c index 3d83d1e..d9cf7ef 100644 --- a/Demo/lwIP_MCF5235_GCC/lwip/src/api/api_lib.c +++ b/Demo/lwIP_MCF5235_GCC/lwip/src/api/api_lib.c
@@ -1,729 +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; -} - +/* + * 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/Demo/lwIP_MCF5235_GCC/lwip/src/api/api_msg.c b/Demo/lwIP_MCF5235_GCC/lwip/src/api/api_msg.c index 0cbe626..9b9bf9c 100644 --- a/Demo/lwIP_MCF5235_GCC/lwip/src/api/api_msg.c +++ b/Demo/lwIP_MCF5235_GCC/lwip/src/api/api_msg.c
@@ -1,800 +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); -} - - - +/* + * 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/Demo/lwIP_MCF5235_GCC/lwip/src/api/err.c b/Demo/lwIP_MCF5235_GCC/lwip/src/api/err.c index b582d88..cc63678 100644 --- a/Demo/lwIP_MCF5235_GCC/lwip/src/api/err.c +++ b/Demo/lwIP_MCF5235_GCC/lwip/src/api/err.c
@@ -1,59 +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 */ +/* + * 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/Demo/lwIP_MCF5235_GCC/lwip/src/api/sockets.c b/Demo/lwIP_MCF5235_GCC/lwip/src/api/sockets.c index 290a7b7..26e6d86 100644 --- a/Demo/lwIP_MCF5235_GCC/lwip/src/api/sockets.c +++ b/Demo/lwIP_MCF5235_GCC/lwip/src/api/sockets.c
@@ -1,1362 +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; - } -} - +/* + * 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/Demo/lwIP_MCF5235_GCC/lwip/src/api/tcpip.c b/Demo/lwIP_MCF5235_GCC/lwip/src/api/tcpip.c index ce8a2ca..db86cf4 100644 --- a/Demo/lwIP_MCF5235_GCC/lwip/src/api/tcpip.c +++ b/Demo/lwIP_MCF5235_GCC/lwip/src/api/tcpip.c
@@ -1,198 +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); -} - - - - +/* + * 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); +} + + + +