| /* |
| * 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); |
| } |
| |
| |
| |