Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_api_msg.c Source File

lwip_api_msg.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Sequential API Internal module
00004  *
00005  */
00006 
00007 /*
00008  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00009  * All rights reserved.
00010  *
00011  * Redistribution and use in source and binary forms, with or without modification,
00012  * are permitted provided that the following conditions are met:
00013  *
00014  * 1. Redistributions of source code must retain the above copyright notice,
00015  *    this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright notice,
00017  *    this list of conditions and the following disclaimer in the documentation
00018  *    and/or other materials provided with the distribution.
00019  * 3. The name of the author may not be used to endorse or promote products
00020  *    derived from this software without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00023  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00024  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00025  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00026  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00027  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00030  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00031  * OF SUCH DAMAGE.
00032  *
00033  * This file is part of the lwIP TCP/IP stack.
00034  *
00035  * Author: Adam Dunkels <adam@sics.se>
00036  *
00037  */
00038 
00039 #include "lwip/opt.h"
00040 
00041 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
00042 
00043 #include "lwip/priv/api_msg.h"
00044 
00045 #include "lwip/ip.h"
00046 #include "lwip/ip_addr.h"
00047 #include "lwip/udp.h"
00048 #include "lwip/tcp.h"
00049 #include "lwip/raw.h"
00050 
00051 #include "lwip/memp.h"
00052 #include "lwip/igmp.h"
00053 #include "lwip/dns.h"
00054 #include "lwip/mld6.h"
00055 #include "lwip/priv/tcpip_priv.h"
00056 
00057 #include <string.h>
00058 
00059 /* netconns are polled once per second (e.g. continue write on memory error) */
00060 #define NETCONN_TCP_POLL_INTERVAL 2
00061 
00062 #define SET_NONBLOCKING_CONNECT(conn, val)  do { if (val) { \
00063   netconn_set_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); \
00064 } else { \
00065   netconn_clear_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); }} while(0)
00066 #define IN_NONBLOCKING_CONNECT(conn) netconn_is_flag_set(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT)
00067 
00068 #if LWIP_NETCONN_FULLDUPLEX
00069 #define NETCONN_MBOX_VALID(conn, mbox) (sys_mbox_valid(mbox) && ((conn->flags & NETCONN_FLAG_MBOXINVALID) == 0))
00070 #else
00071 #define NETCONN_MBOX_VALID(conn, mbox) sys_mbox_valid(mbox)
00072 #endif
00073 
00074 /* forward declarations */
00075 #if LWIP_TCP
00076 #if LWIP_TCPIP_CORE_LOCKING
00077 #define WRITE_DELAYED         , 1
00078 #define WRITE_DELAYED_PARAM   , u8_t delayed
00079 #else /* LWIP_TCPIP_CORE_LOCKING */
00080 #define WRITE_DELAYED
00081 #define WRITE_DELAYED_PARAM
00082 #endif /* LWIP_TCPIP_CORE_LOCKING */
00083 static err_t lwip_netconn_do_writemore(struct netconn *conn  WRITE_DELAYED_PARAM);
00084 static err_t lwip_netconn_do_close_internal(struct netconn *conn  WRITE_DELAYED_PARAM);
00085 #endif
00086 
00087 static void netconn_drain(struct netconn *conn);
00088 
00089 #if LWIP_TCPIP_CORE_LOCKING
00090 #define TCPIP_APIMSG_ACK(m)
00091 #else /* LWIP_TCPIP_CORE_LOCKING */
00092 #define TCPIP_APIMSG_ACK(m)   do { sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0)
00093 #endif /* LWIP_TCPIP_CORE_LOCKING */
00094 
00095 #if LWIP_NETCONN_FULLDUPLEX
00096 const u8_t netconn_deleted = 0;
00097 
00098 int
00099 lwip_netconn_is_deallocated_msg(void *msg)
00100 {
00101   if (msg == &netconn_deleted) {
00102     return 1;
00103   }
00104   return 0;
00105 }
00106 #endif /* LWIP_NETCONN_FULLDUPLEX */
00107 
00108 #if LWIP_TCP
00109 const u8_t netconn_aborted = 0;
00110 const u8_t netconn_reset = 0;
00111 const u8_t netconn_closed = 0;
00112 
00113 /** Translate an error to a unique void* passed via an mbox */
00114 static void *
00115 lwip_netconn_err_to_msg(err_t err)
00116 {
00117   switch (err) {
00118     case ERR_ABRT:
00119       return LWIP_CONST_CAST(void *, &netconn_aborted);
00120     case ERR_RST:
00121       return LWIP_CONST_CAST(void *, &netconn_reset);
00122     case ERR_CLSD:
00123       return LWIP_CONST_CAST(void *, &netconn_closed);
00124     default:
00125       LWIP_ASSERT("unhandled error", err == ERR_OK);
00126       return NULL;
00127   }
00128 }
00129 
00130 int
00131 lwip_netconn_is_err_msg(void *msg, err_t *err)
00132 {
00133   LWIP_ASSERT("err != NULL", err != NULL);
00134 
00135   if (msg == &netconn_aborted) {
00136     *err = ERR_ABRT;
00137     return 1;
00138   } else if (msg == &netconn_reset) {
00139     *err = ERR_RST;
00140     return 1;
00141   } else if (msg == &netconn_closed) {
00142     *err = ERR_CLSD;
00143     return 1;
00144   }
00145   return 0;
00146 }
00147 #endif /* LWIP_TCP */
00148 
00149 
00150 #if LWIP_RAW
00151 /**
00152  * Receive callback function for RAW netconns.
00153  * Doesn't 'eat' the packet, only copies it and sends it to
00154  * conn->recvmbox
00155  *
00156  * @see raw.h (struct raw_pcb.recv) for parameters and return value
00157  */
00158 static u8_t
00159 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
00160          const ip_addr_t *addr)
00161 {
00162   struct pbuf *q;
00163   struct netbuf *buf;
00164   struct netconn *conn;
00165 
00166   LWIP_UNUSED_ARG(addr);
00167   conn = (struct netconn *)arg;
00168 
00169   if ((conn != NULL) && NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
00170 #if LWIP_SO_RCVBUF
00171     int recv_avail;
00172     SYS_ARCH_GET(conn->recv_avail, recv_avail);
00173     if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
00174       return 0;
00175     }
00176 #endif /* LWIP_SO_RCVBUF */
00177     /* copy the whole packet into new pbufs */
00178     q = pbuf_clone(PBUF_RAW, PBUF_RAM, p);
00179     if (q != NULL) {
00180       u16_t len;
00181       buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
00182       if (buf == NULL) {
00183         pbuf_free(q);
00184         return 0;
00185       }
00186 
00187       buf->p = q;
00188       buf->ptr = q;
00189       ip_addr_copy(buf->addr, *ip_current_src_addr());
00190       buf->port = pcb->protocol;
00191 
00192       len = q->tot_len;
00193       if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
00194         netbuf_delete(buf);
00195         return 0;
00196       } else {
00197 #if LWIP_SO_RCVBUF
00198         SYS_ARCH_INC(conn->recv_avail, len);
00199 #endif /* LWIP_SO_RCVBUF */
00200         /* Register event with callback */
00201         API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
00202       }
00203     }
00204   }
00205 
00206   return 0; /* do not eat the packet */
00207 }
00208 #endif /* LWIP_RAW*/
00209 
00210 #if LWIP_UDP
00211 /**
00212  * Receive callback function for UDP netconns.
00213  * Posts the packet to conn->recvmbox or deletes it on memory error.
00214  *
00215  * @see udp.h (struct udp_pcb.recv) for parameters
00216  */
00217 static void
00218 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
00219          const ip_addr_t *addr, u16_t port)
00220 {
00221   struct netbuf *buf;
00222   struct netconn *conn;
00223   u16_t len;
00224 #if LWIP_SO_RCVBUF
00225   int recv_avail;
00226 #endif /* LWIP_SO_RCVBUF */
00227 
00228   LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
00229   LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
00230   LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
00231   conn = (struct netconn *)arg;
00232 
00233   if (conn == NULL) {
00234     pbuf_free(p);
00235     return;
00236   }
00237 
00238   LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
00239 
00240 #if LWIP_SO_RCVBUF
00241   SYS_ARCH_GET(conn->recv_avail, recv_avail);
00242   if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox) ||
00243       ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
00244 #else  /* LWIP_SO_RCVBUF */
00245   if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
00246 #endif /* LWIP_SO_RCVBUF */
00247     pbuf_free(p);
00248     return;
00249   }
00250 
00251   buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
00252   if (buf == NULL) {
00253     pbuf_free(p);
00254     return;
00255   } else {
00256     buf->p = p;
00257     buf->ptr = p;
00258     ip_addr_set(&buf->addr, addr);
00259     buf->port = port;
00260 #if LWIP_NETBUF_RECVINFO
00261     if (conn->flags & NETCONN_FLAG_PKTINFO) {
00262       /* get the UDP header - always in the first pbuf, ensured by udp_input */
00263       const struct udp_hdr *udphdr = (const struct udp_hdr *)ip_next_header_ptr();
00264       buf->flags = NETBUF_FLAG_DESTADDR;
00265       ip_addr_set(&buf->toaddr, ip_current_dest_addr());
00266       buf->toport_chksum = udphdr->dest;
00267     }
00268 #endif /* LWIP_NETBUF_RECVINFO */
00269   }
00270 
00271   len = p->tot_len;
00272   if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
00273     netbuf_delete(buf);
00274     return;
00275   } else {
00276 #if LWIP_SO_RCVBUF
00277     SYS_ARCH_INC(conn->recv_avail, len);
00278 #endif /* LWIP_SO_RCVBUF */
00279     /* Register event with callback */
00280     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
00281   }
00282 }
00283 #endif /* LWIP_UDP */
00284 
00285 #if LWIP_TCP
00286 /**
00287  * Receive callback function for TCP netconns.
00288  * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
00289  *
00290  * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
00291  */
00292 static err_t
00293 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
00294 {
00295   struct netconn *conn;
00296   u16_t len;
00297   void *msg;
00298 
00299   LWIP_UNUSED_ARG(pcb);
00300   LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
00301   LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
00302   LWIP_ASSERT("err != ERR_OK unhandled", err == ERR_OK);
00303   LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */
00304   conn = (struct netconn *)arg;
00305 
00306   if (conn == NULL) {
00307     return ERR_VAL;
00308   }
00309   LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
00310 
00311   if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
00312     /* recvmbox already deleted */
00313     if (p != NULL) {
00314       tcp_recved(pcb, p->tot_len);
00315       pbuf_free(p);
00316     }
00317     return ERR_OK;
00318   }
00319   /* Unlike for UDP or RAW pcbs, don't check for available space
00320      using recv_avail since that could break the connection
00321      (data is already ACKed) */
00322 
00323   if (p != NULL) {
00324     msg = p;
00325     len = p->tot_len;
00326   } else {
00327     msg = LWIP_CONST_CAST(void *, &netconn_closed);
00328     len = 0;
00329   }
00330 
00331   if (sys_mbox_trypost(&conn->recvmbox, msg) != ERR_OK) {
00332     /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
00333     return ERR_MEM;
00334   } else {
00335 #if LWIP_SO_RCVBUF
00336     SYS_ARCH_INC(conn->recv_avail, len);
00337 #endif /* LWIP_SO_RCVBUF */
00338     /* Register event with callback */
00339     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
00340   }
00341 
00342   return ERR_OK;
00343 }
00344 
00345 /**
00346  * Poll callback function for TCP netconns.
00347  * Wakes up an application thread that waits for a connection to close
00348  * or data to be sent. The application thread then takes the
00349  * appropriate action to go on.
00350  *
00351  * Signals the conn->sem.
00352  * netconn_close waits for conn->sem if closing failed.
00353  *
00354  * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
00355  */
00356 static err_t
00357 poll_tcp(void *arg, struct tcp_pcb *pcb)
00358 {
00359   struct netconn *conn = (struct netconn *)arg;
00360 
00361   LWIP_UNUSED_ARG(pcb);
00362   LWIP_ASSERT("conn != NULL", (conn != NULL));
00363 
00364   if (conn->state == NETCONN_WRITE) {
00365     lwip_netconn_do_writemore(conn  WRITE_DELAYED);
00366   } else if (conn->state == NETCONN_CLOSE) {
00367 #if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER
00368     if (conn->current_msg && conn->current_msg->msg.sd.polls_left) {
00369       conn->current_msg->msg.sd.polls_left--;
00370     }
00371 #endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */
00372     lwip_netconn_do_close_internal(conn  WRITE_DELAYED);
00373   }
00374   /* @todo: implement connect timeout here? */
00375 
00376   /* Did a nonblocking write fail before? Then check available write-space. */
00377   if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
00378     /* If the queued byte- or pbuf-count drops below the configured low-water limit,
00379        let select mark this pcb as writable again. */
00380     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
00381         (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
00382       netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE);
00383       API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
00384     }
00385   }
00386 
00387   return ERR_OK;
00388 }
00389 
00390 /**
00391  * Sent callback function for TCP netconns.
00392  * Signals the conn->sem and calls API_EVENT.
00393  * netconn_write waits for conn->sem if send buffer is low.
00394  *
00395  * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
00396  */
00397 static err_t
00398 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
00399 {
00400   struct netconn *conn = (struct netconn *)arg;
00401 
00402   LWIP_UNUSED_ARG(pcb);
00403   LWIP_ASSERT("conn != NULL", (conn != NULL));
00404 
00405   if (conn) {
00406     if (conn->state == NETCONN_WRITE) {
00407       lwip_netconn_do_writemore(conn  WRITE_DELAYED);
00408     } else if (conn->state == NETCONN_CLOSE) {
00409       lwip_netconn_do_close_internal(conn  WRITE_DELAYED);
00410     }
00411 
00412     /* If the queued byte- or pbuf-count drops below the configured low-water limit,
00413        let select mark this pcb as writable again. */
00414     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
00415         (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
00416       netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE);
00417       API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
00418     }
00419   }
00420 
00421   return ERR_OK;
00422 }
00423 
00424 /**
00425  * Error callback function for TCP netconns.
00426  * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
00427  * The application thread has then to decide what to do.
00428  *
00429  * @see tcp.h (struct tcp_pcb.err) for parameters
00430  */
00431 static void
00432 err_tcp(void *arg, err_t err)
00433 {
00434   struct netconn *conn;
00435   enum netconn_state old_state;
00436   void *mbox_msg;
00437   SYS_ARCH_DECL_PROTECT(lev);
00438 
00439   conn = (struct netconn *)arg;
00440   LWIP_ASSERT("conn != NULL", (conn != NULL));
00441 
00442   SYS_ARCH_PROTECT(lev);
00443 
00444   /* when err is called, the pcb is deallocated, so delete the reference */
00445   conn->pcb.tcp = NULL;
00446   /* store pending error */
00447   conn->pending_err = err;
00448   /* prevent application threads from blocking on 'recvmbox'/'acceptmbox' */
00449   conn->flags |= NETCONN_FLAG_MBOXCLOSED;
00450 
00451   /* reset conn->state now before waking up other threads */
00452   old_state = conn->state;
00453   conn->state = NETCONN_NONE;
00454 
00455   SYS_ARCH_UNPROTECT(lev);
00456 
00457   /* Notify the user layer about a connection error. Used to signal select. */
00458   API_EVENT(conn, NETCONN_EVT_ERROR, 0);
00459   /* Try to release selects pending on 'read' or 'write', too.
00460      They will get an error if they actually try to read or write. */
00461   API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
00462   API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
00463 
00464   mbox_msg = lwip_netconn_err_to_msg(err);
00465   /* pass error message to recvmbox to wake up pending recv */
00466   if (NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
00467     /* use trypost to prevent deadlock */
00468     sys_mbox_trypost(&conn->recvmbox, mbox_msg);
00469   }
00470   /* pass error message to acceptmbox to wake up pending accept */
00471   if (NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) {
00472     /* use trypost to preven deadlock */
00473     sys_mbox_trypost(&conn->acceptmbox, mbox_msg);
00474   }
00475 
00476   if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
00477       (old_state == NETCONN_CONNECT)) {
00478     /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary
00479        since the pcb has already been deleted! */
00480     int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
00481     SET_NONBLOCKING_CONNECT(conn, 0);
00482 
00483     if (!was_nonblocking_connect) {
00484       sys_sem_t *op_completed_sem;
00485       /* set error return code */
00486       LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
00487       if (old_state == NETCONN_CLOSE) {
00488         /* let close succeed: the connection is closed after all... */
00489         conn->current_msg->err = ERR_OK;
00490       } else {
00491         /* Write and connect fail */
00492         conn->current_msg->err = err;
00493       }
00494       op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
00495       LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem));
00496       conn->current_msg = NULL;
00497       /* wake up the waiting task */
00498       sys_sem_signal(op_completed_sem);
00499     } else {
00500       /* @todo: test what happens for error on nonblocking connect */
00501     }
00502   } else {
00503     LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
00504   }
00505 }
00506 
00507 /**
00508  * Setup a tcp_pcb with the correct callback function pointers
00509  * and their arguments.
00510  *
00511  * @param conn the TCP netconn to setup
00512  */
00513 static void
00514 setup_tcp(struct netconn *conn)
00515 {
00516   struct tcp_pcb *pcb;
00517 
00518   pcb = conn->pcb.tcp;
00519   tcp_arg(pcb, conn);
00520   tcp_recv(pcb, recv_tcp);
00521   tcp_sent(pcb, sent_tcp);
00522   tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL);
00523   tcp_err(pcb, err_tcp);
00524 }
00525 
00526 /**
00527  * Accept callback function for TCP netconns.
00528  * Allocates a new netconn and posts that to conn->acceptmbox.
00529  *
00530  * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
00531  */
00532 static err_t
00533 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
00534 {
00535   struct netconn *newconn;
00536   struct netconn *conn = (struct netconn *)arg;
00537 
00538   if (conn == NULL) {
00539     return ERR_VAL;
00540   }
00541   if (!NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) {
00542     LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
00543     return ERR_VAL;
00544   }
00545 
00546   if (newpcb == NULL) {
00547     /* out-of-pcbs during connect: pass on this error to the application */
00548     if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) {
00549       /* Register event with callback */
00550       API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
00551     }
00552     return ERR_VAL;
00553   }
00554   LWIP_ASSERT("expect newpcb == NULL or err == ERR_OK", err == ERR_OK);
00555   LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */
00556 
00557   LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->state: %s\n", tcp_debug_state_str(newpcb->state)));
00558 
00559   /* We have to set the callback here even though
00560    * the new socket is unknown. newconn->socket is marked as -1. */
00561   newconn = netconn_alloc(conn->type, conn->callback);
00562   if (newconn == NULL) {
00563     /* outof netconns: pass on this error to the application */
00564     if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) {
00565       /* Register event with callback */
00566       API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
00567     }
00568     return ERR_MEM;
00569   }
00570   newconn->pcb.tcp = newpcb;
00571   setup_tcp(newconn);
00572 
00573   /* handle backlog counter */
00574   tcp_backlog_delayed(newpcb);
00575 
00576   if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
00577     /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
00578        so do nothing here! */
00579     /* remove all references to this netconn from the pcb */
00580     struct tcp_pcb *pcb = newconn->pcb.tcp;
00581     tcp_arg(pcb, NULL);
00582     tcp_recv(pcb, NULL);
00583     tcp_sent(pcb, NULL);
00584     tcp_poll(pcb, NULL, 0);
00585     tcp_err(pcb, NULL);
00586     /* remove reference from to the pcb from this netconn */
00587     newconn->pcb.tcp = NULL;
00588     /* no need to drain since we know the recvmbox is empty. */
00589     sys_mbox_free(&newconn->recvmbox);
00590     sys_mbox_set_invalid(&newconn->recvmbox);
00591     netconn_free(newconn);
00592     return ERR_MEM;
00593   } else {
00594     /* Register event with callback */
00595     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
00596   }
00597 
00598   return ERR_OK;
00599 }
00600 #endif /* LWIP_TCP */
00601 
00602 /**
00603  * Create a new pcb of a specific type.
00604  * Called from lwip_netconn_do_newconn().
00605  *
00606  * @param msg the api_msg describing the connection type
00607  */
00608 static void
00609 pcb_new(struct api_msg *msg)
00610 {
00611   enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4;
00612 
00613   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
00614 
00615 #if LWIP_IPV6 && LWIP_IPV4
00616   /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */
00617   if (NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) {
00618     iptype = IPADDR_TYPE_ANY;
00619   }
00620 #endif
00621 
00622   /* Allocate a PCB for this connection */
00623   switch (NETCONNTYPE_GROUP(msg->conn->type)) {
00624 #if LWIP_RAW
00625     case NETCONN_RAW:
00626       msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto);
00627       if (msg->conn->pcb.raw != NULL) {
00628 #if LWIP_IPV6
00629         /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */
00630         if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) {
00631           msg->conn->pcb.raw->chksum_reqd = 1;
00632           msg->conn->pcb.raw->chksum_offset = 2;
00633         }
00634 #endif /* LWIP_IPV6 */
00635         raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
00636       }
00637       break;
00638 #endif /* LWIP_RAW */
00639 #if LWIP_UDP
00640     case NETCONN_UDP:
00641       msg->conn->pcb.udp = udp_new_ip_type(iptype);
00642       if (msg->conn->pcb.udp != NULL) {
00643 #if LWIP_UDPLITE
00644         if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
00645           udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
00646         }
00647 #endif /* LWIP_UDPLITE */
00648         if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) {
00649           udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
00650         }
00651         udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
00652       }
00653       break;
00654 #endif /* LWIP_UDP */
00655 #if LWIP_TCP
00656     case NETCONN_TCP:
00657       msg->conn->pcb.tcp = tcp_new_ip_type(iptype);
00658       if (msg->conn->pcb.tcp != NULL) {
00659         setup_tcp(msg->conn);
00660       }
00661       break;
00662 #endif /* LWIP_TCP */
00663     default:
00664       /* Unsupported netconn type, e.g. protocol disabled */
00665       msg->err = ERR_VAL;
00666       return;
00667   }
00668   if (msg->conn->pcb.ip == NULL) {
00669     msg->err = ERR_MEM;
00670   }
00671 }
00672 
00673 /**
00674  * Create a new pcb of a specific type inside a netconn.
00675  * Called from netconn_new_with_proto_and_callback.
00676  *
00677  * @param m the api_msg describing the connection type
00678  */
00679 void
00680 lwip_netconn_do_newconn(void *m)
00681 {
00682   struct api_msg *msg = (struct api_msg *)m;
00683 
00684   msg->err = ERR_OK;
00685   if (msg->conn->pcb.tcp == NULL) {
00686     pcb_new(msg);
00687   }
00688   /* Else? This "new" connection already has a PCB allocated. */
00689   /* Is this an error condition? Should it be deleted? */
00690   /* We currently just are happy and return. */
00691 
00692   TCPIP_APIMSG_ACK(msg);
00693 }
00694 
00695 /**
00696  * Create a new netconn (of a specific type) that has a callback function.
00697  * The corresponding pcb is NOT created!
00698  *
00699  * @param t the type of 'connection' to create (@see enum netconn_type)
00700  * @param callback a function to call on status changes (RX available, TX'ed)
00701  * @return a newly allocated struct netconn or
00702  *         NULL on memory error
00703  */
00704 struct netconn *
00705 netconn_alloc(enum netconn_type t, netconn_callback callback)
00706 {
00707   struct netconn *conn;
00708   int size;
00709   u8_t init_flags = 0;
00710 
00711   conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
00712   if (conn == NULL) {
00713     return NULL;
00714   }
00715 
00716   conn->pending_err = ERR_OK;
00717   conn->type = t;
00718   conn->pcb.tcp = NULL;
00719 
00720   /* If all sizes are the same, every compiler should optimize this switch to nothing */
00721   switch (NETCONNTYPE_GROUP(t)) {
00722 #if LWIP_RAW
00723     case NETCONN_RAW:
00724       size = DEFAULT_RAW_RECVMBOX_SIZE;
00725       break;
00726 #endif /* LWIP_RAW */
00727 #if LWIP_UDP
00728     case NETCONN_UDP:
00729       size = DEFAULT_UDP_RECVMBOX_SIZE;
00730 #if LWIP_NETBUF_RECVINFO
00731       init_flags |= NETCONN_FLAG_PKTINFO;
00732 #endif /* LWIP_NETBUF_RECVINFO */
00733       break;
00734 #endif /* LWIP_UDP */
00735 #if LWIP_TCP
00736     case NETCONN_TCP:
00737       size = DEFAULT_TCP_RECVMBOX_SIZE;
00738       break;
00739 #endif /* LWIP_TCP */
00740     default:
00741       LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
00742       goto free_and_return;
00743   }
00744 
00745   if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
00746     goto free_and_return;
00747   }
00748 #if !LWIP_NETCONN_SEM_PER_THREAD
00749   if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
00750     sys_mbox_free(&conn->recvmbox);
00751     goto free_and_return;
00752   }
00753 #endif
00754 
00755 #if LWIP_TCP
00756   sys_mbox_set_invalid(&conn->acceptmbox);
00757 #endif
00758   conn->state        = NETCONN_NONE;
00759 #if LWIP_SOCKET
00760   /* initialize socket to -1 since 0 is a valid socket */
00761   conn->socket       = -1;
00762 #endif /* LWIP_SOCKET */
00763   conn->callback     = callback;
00764 #if LWIP_TCP
00765   conn->current_msg  = NULL;
00766 #endif /* LWIP_TCP */
00767 #if LWIP_SO_SNDTIMEO
00768   conn->send_timeout = 0;
00769 #endif /* LWIP_SO_SNDTIMEO */
00770 #if LWIP_SO_RCVTIMEO
00771   conn->recv_timeout = 0;
00772 #endif /* LWIP_SO_RCVTIMEO */
00773 #if LWIP_SO_RCVBUF
00774   conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
00775   conn->recv_avail   = 0;
00776 #endif /* LWIP_SO_RCVBUF */
00777 #if LWIP_SO_LINGER
00778   conn->linger = -1;
00779 #endif /* LWIP_SO_LINGER */
00780   conn->flags = init_flags;
00781   return conn;
00782 free_and_return:
00783   memp_free(MEMP_NETCONN, conn);
00784   return NULL;
00785 }
00786 
00787 /**
00788  * Delete a netconn and all its resources.
00789  * The pcb is NOT freed (since we might not be in the right thread context do this).
00790  *
00791  * @param conn the netconn to free
00792  */
00793 void
00794 netconn_free(struct netconn *conn)
00795 {
00796   LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
00797 
00798 #if LWIP_NETCONN_FULLDUPLEX
00799   /* in fullduplex, netconn is drained here */
00800   netconn_drain(conn);
00801 #endif /* LWIP_NETCONN_FULLDUPLEX */
00802 
00803   LWIP_ASSERT("recvmbox must be deallocated before calling this function",
00804               !sys_mbox_valid(&conn->recvmbox));
00805 #if LWIP_TCP
00806   LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
00807               !sys_mbox_valid(&conn->acceptmbox));
00808 #endif /* LWIP_TCP */
00809 
00810 #if !LWIP_NETCONN_SEM_PER_THREAD
00811   sys_sem_free(&conn->op_completed);
00812   sys_sem_set_invalid(&conn->op_completed);
00813 #endif
00814 
00815   memp_free(MEMP_NETCONN, conn);
00816 }
00817 
00818 /**
00819  * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
00820  * these mboxes
00821  *
00822  * @param conn the netconn to free
00823  * @bytes_drained bytes drained from recvmbox
00824  * @accepts_drained pending connections drained from acceptmbox
00825  */
00826 static void
00827 netconn_drain(struct netconn *conn)
00828 {
00829   void *mem;
00830 
00831   /* This runs when mbox and netconn are marked as closed,
00832      so we don't need to lock against rx packets */
00833 #if LWIP_NETCONN_FULLDUPLEX
00834   LWIP_ASSERT("netconn marked closed", conn->flags & NETCONN_FLAG_MBOXINVALID);
00835 #endif /* LWIP_NETCONN_FULLDUPLEX */
00836 
00837   /* Delete and drain the recvmbox. */
00838   if (sys_mbox_valid(&conn->recvmbox)) {
00839     while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
00840 #if LWIP_NETCONN_FULLDUPLEX
00841       if (!lwip_netconn_is_deallocated_msg(mem))
00842 #endif /* LWIP_NETCONN_FULLDUPLEX */
00843       {
00844 #if LWIP_TCP
00845         if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
00846           err_t err;
00847           if (!lwip_netconn_is_err_msg(mem, &err)) {
00848             pbuf_free((struct pbuf *)mem);
00849           }
00850         } else
00851 #endif /* LWIP_TCP */
00852         {
00853           netbuf_delete((struct netbuf *)mem);
00854         }
00855       }
00856     }
00857     sys_mbox_free(&conn->recvmbox);
00858     sys_mbox_set_invalid(&conn->recvmbox);
00859   }
00860 
00861   /* Delete and drain the acceptmbox. */
00862 #if LWIP_TCP
00863   if (sys_mbox_valid(&conn->acceptmbox)) {
00864     while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
00865 #if LWIP_NETCONN_FULLDUPLEX
00866       if (!lwip_netconn_is_deallocated_msg(mem))
00867 #endif /* LWIP_NETCONN_FULLDUPLEX */
00868       {
00869         err_t err;
00870         if (!lwip_netconn_is_err_msg(mem, &err)) {
00871           struct netconn *newconn = (struct netconn *)mem;
00872           /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
00873           /* pcb might be set to NULL already by err_tcp() */
00874           /* drain recvmbox */
00875           netconn_drain(newconn);
00876           if (newconn->pcb.tcp != NULL) {
00877             tcp_abort(newconn->pcb.tcp);
00878             newconn->pcb.tcp = NULL;
00879           }
00880           netconn_free(newconn);
00881         }
00882       }
00883     }
00884     sys_mbox_free(&conn->acceptmbox);
00885     sys_mbox_set_invalid(&conn->acceptmbox);
00886   }
00887 #endif /* LWIP_TCP */
00888 }
00889 
00890 #if LWIP_NETCONN_FULLDUPLEX
00891 static void
00892 netconn_mark_mbox_invalid(struct netconn *conn)
00893 {
00894   int i, num_waiting;
00895   void *msg = LWIP_CONST_CAST(void *, &netconn_deleted);
00896 
00897   /* Prevent new calls/threads from reading from the mbox */
00898   conn->flags |= NETCONN_FLAG_MBOXINVALID;
00899 
00900   SYS_ARCH_LOCKED(num_waiting = conn->mbox_threads_waiting);
00901   for (i = 0; i < num_waiting; i++) {
00902     if (sys_mbox_valid_val(conn->recvmbox)) {
00903       sys_mbox_trypost(&conn->recvmbox, msg);
00904     } else {
00905       sys_mbox_trypost(&conn->acceptmbox, msg);
00906     }
00907   }
00908 }
00909 #endif /* LWIP_NETCONN_FULLDUPLEX */
00910 
00911 #if LWIP_TCP
00912 /**
00913  * Internal helper function to close a TCP netconn: since this sometimes
00914  * doesn't work at the first attempt, this function is called from multiple
00915  * places.
00916  *
00917  * @param conn the TCP netconn to close
00918  */
00919 static err_t
00920 lwip_netconn_do_close_internal(struct netconn *conn  WRITE_DELAYED_PARAM)
00921 {
00922   err_t err;
00923   u8_t shut, shut_rx, shut_tx, shut_close;
00924   u8_t close_finished = 0;
00925   struct tcp_pcb *tpcb;
00926 #if LWIP_SO_LINGER
00927   u8_t linger_wait_required = 0;
00928 #endif /* LWIP_SO_LINGER */
00929 
00930   LWIP_ASSERT("invalid conn", (conn != NULL));
00931   LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP));
00932   LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
00933   LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
00934   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
00935 
00936   tpcb = conn->pcb.tcp;
00937   shut = conn->current_msg->msg.sd.shut;
00938   shut_rx = shut & NETCONN_SHUT_RD;
00939   shut_tx = shut & NETCONN_SHUT_WR;
00940   /* shutting down both ends is the same as closing
00941      (also if RD or WR side was shut down before already) */
00942   if (shut == NETCONN_SHUT_RDWR) {
00943     shut_close = 1;
00944   } else if (shut_rx &&
00945              ((tpcb->state == FIN_WAIT_1) ||
00946               (tpcb->state == FIN_WAIT_2) ||
00947               (tpcb->state == CLOSING))) {
00948     shut_close = 1;
00949   } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) {
00950     shut_close = 1;
00951   } else {
00952     shut_close = 0;
00953   }
00954 
00955   /* Set back some callback pointers */
00956   if (shut_close) {
00957     tcp_arg(tpcb, NULL);
00958   }
00959   if (tpcb->state == LISTEN) {
00960     tcp_accept(tpcb, NULL);
00961   } else {
00962     /* some callbacks have to be reset if tcp_close is not successful */
00963     if (shut_rx) {
00964       tcp_recv(tpcb, NULL);
00965       tcp_accept(tpcb, NULL);
00966     }
00967     if (shut_tx) {
00968       tcp_sent(tpcb, NULL);
00969     }
00970     if (shut_close) {
00971       tcp_poll(tpcb, NULL, 0);
00972       tcp_err(tpcb, NULL);
00973     }
00974   }
00975   /* Try to close the connection */
00976   if (shut_close) {
00977 #if LWIP_SO_LINGER
00978     /* check linger possibilites before calling tcp_close */
00979     err = ERR_OK;
00980     /* linger enabled/required at all? (i.e. is there untransmitted data left?) */
00981     if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) {
00982       if ((conn->linger == 0)) {
00983         /* data left but linger prevents waiting */
00984         tcp_abort(tpcb);
00985         tpcb = NULL;
00986       } else if (conn->linger > 0) {
00987         /* data left and linger says we should wait */
00988         if (netconn_is_nonblocking(conn)) {
00989           /* data left on a nonblocking netconn -> cannot linger */
00990           err = ERR_WOULDBLOCK;
00991         } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >=
00992                    (conn->linger * 1000)) {
00993           /* data left but linger timeout has expired (this happens on further
00994              calls to this function through poll_tcp */
00995           tcp_abort(tpcb);
00996           tpcb = NULL;
00997         } else {
00998           /* data left -> need to wait for ACK after successful close */
00999           linger_wait_required = 1;
01000         }
01001       }
01002     }
01003     if ((err == ERR_OK) && (tpcb != NULL))
01004 #endif /* LWIP_SO_LINGER */
01005     {
01006       err = tcp_close(tpcb);
01007     }
01008   } else {
01009     err = tcp_shutdown(tpcb, shut_rx, shut_tx);
01010   }
01011   if (err == ERR_OK) {
01012     close_finished = 1;
01013 #if LWIP_SO_LINGER
01014     if (linger_wait_required) {
01015       /* wait for ACK of all unsent/unacked data by just getting called again */
01016       close_finished = 0;
01017       err = ERR_INPROGRESS;
01018     }
01019 #endif /* LWIP_SO_LINGER */
01020   } else {
01021     if (err == ERR_MEM) {
01022       /* Closing failed because of memory shortage, try again later. Even for
01023          nonblocking netconns, we have to wait since no standard socket application
01024          is prepared for close failing because of resource shortage.
01025          Check the timeout: this is kind of an lwip addition to the standard sockets:
01026          we wait for some time when failing to allocate a segment for the FIN */
01027 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
01028       s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT;
01029 #if LWIP_SO_SNDTIMEO
01030       if (conn->send_timeout > 0) {
01031         close_timeout = conn->send_timeout;
01032       }
01033 #endif /* LWIP_SO_SNDTIMEO */
01034 #if LWIP_SO_LINGER
01035       if (conn->linger >= 0) {
01036         /* use linger timeout (seconds) */
01037         close_timeout = conn->linger * 1000U;
01038       }
01039 #endif
01040       if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
01041 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
01042       if (conn->current_msg->msg.sd.polls_left == 0) {
01043 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
01044         close_finished = 1;
01045         if (shut_close) {
01046           /* in this case, we want to RST the connection */
01047           tcp_abort(tpcb);
01048           err = ERR_OK;
01049         }
01050       }
01051     } else {
01052       /* Closing failed for a non-memory error: give up */
01053       close_finished = 1;
01054     }
01055   }
01056   if (close_finished) {
01057     /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */
01058     sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
01059     conn->current_msg->err = err;
01060     conn->current_msg = NULL;
01061     conn->state = NETCONN_NONE;
01062     if (err == ERR_OK) {
01063       if (shut_close) {
01064         /* Set back some callback pointers as conn is going away */
01065         conn->pcb.tcp = NULL;
01066         /* Trigger select() in socket layer. Make sure everybody notices activity
01067          on the connection, error first! */
01068         API_EVENT(conn, NETCONN_EVT_ERROR, 0);
01069       }
01070       if (shut_rx) {
01071         API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
01072       }
01073       if (shut_tx) {
01074         API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
01075       }
01076     }
01077 #if LWIP_TCPIP_CORE_LOCKING
01078     if (delayed)
01079 #endif
01080     {
01081       /* wake up the application task */
01082       sys_sem_signal(op_completed_sem);
01083     }
01084     return ERR_OK;
01085   }
01086   if (!close_finished) {
01087     /* Closing failed and we want to wait: restore some of the callbacks */
01088     /* Closing of listen pcb will never fail! */
01089     LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN));
01090     if (shut_tx) {
01091       tcp_sent(tpcb, sent_tcp);
01092     }
01093     /* when waiting for close, set up poll interval to 500ms */
01094     tcp_poll(tpcb, poll_tcp, 1);
01095     tcp_err(tpcb, err_tcp);
01096     tcp_arg(tpcb, conn);
01097     /* don't restore recv callback: we don't want to receive any more data */
01098   }
01099   /* If closing didn't succeed, we get called again either
01100      from poll_tcp or from sent_tcp */
01101   LWIP_ASSERT("err != ERR_OK", err != ERR_OK);
01102   return err;
01103 }
01104 #endif /* LWIP_TCP */
01105 
01106 /**
01107  * Delete the pcb inside a netconn.
01108  * Called from netconn_delete.
01109  *
01110  * @param m the api_msg pointing to the connection
01111  */
01112 void
01113 lwip_netconn_do_delconn(void *m)
01114 {
01115   struct api_msg *msg = (struct api_msg *)m;
01116 
01117   enum netconn_state state = msg->conn->state;
01118   LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */
01119               (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP));
01120 #if LWIP_NETCONN_FULLDUPLEX
01121   /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */
01122   if (state != NETCONN_NONE) {
01123     if ((state == NETCONN_WRITE) ||
01124         ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
01125       /* close requested, abort running write/connect */
01126       sys_sem_t *op_completed_sem;
01127       LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
01128       op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
01129       msg->conn->current_msg->err = ERR_CLSD;
01130       msg->conn->current_msg = NULL;
01131       msg->conn->state = NETCONN_NONE;
01132       sys_sem_signal(op_completed_sem);
01133     }
01134   }
01135 #else /* LWIP_NETCONN_FULLDUPLEX */
01136   if (((state != NETCONN_NONE) &&
01137        (state != NETCONN_LISTEN) &&
01138        (state != NETCONN_CONNECT)) ||
01139       ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
01140     /* This means either a blocking write or blocking connect is running
01141        (nonblocking write returns and sets state to NONE) */
01142     msg->err = ERR_INPROGRESS;
01143   } else
01144 #endif /* LWIP_NETCONN_FULLDUPLEX */
01145   {
01146     LWIP_ASSERT("blocking connect in progress",
01147                 (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
01148     msg->err = ERR_OK;
01149 #if LWIP_NETCONN_FULLDUPLEX
01150     /* Mark mboxes invalid */
01151     netconn_mark_mbox_invalid(msg->conn);
01152 #else /* LWIP_NETCONN_FULLDUPLEX */
01153     netconn_drain(msg->conn);
01154 #endif /* LWIP_NETCONN_FULLDUPLEX */
01155 
01156     if (msg->conn->pcb.tcp != NULL) {
01157 
01158       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01159 #if LWIP_RAW
01160         case NETCONN_RAW:
01161           raw_remove(msg->conn->pcb.raw);
01162           break;
01163 #endif /* LWIP_RAW */
01164 #if LWIP_UDP
01165         case NETCONN_UDP:
01166           msg->conn->pcb.udp->recv_arg = NULL;
01167           udp_remove(msg->conn->pcb.udp);
01168           break;
01169 #endif /* LWIP_UDP */
01170 #if LWIP_TCP
01171         case NETCONN_TCP:
01172           LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL);
01173           msg->conn->state = NETCONN_CLOSE;
01174           msg->msg.sd.shut = NETCONN_SHUT_RDWR;
01175           msg->conn->current_msg = msg;
01176 #if LWIP_TCPIP_CORE_LOCKING
01177           if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
01178             LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
01179             UNLOCK_TCPIP_CORE();
01180             sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
01181             LOCK_TCPIP_CORE();
01182             LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
01183           }
01184 #else /* LWIP_TCPIP_CORE_LOCKING */
01185           lwip_netconn_do_close_internal(msg->conn);
01186 #endif /* LWIP_TCPIP_CORE_LOCKING */
01187           /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing
01188              the application thread, so we can return at this point! */
01189           return;
01190 #endif /* LWIP_TCP */
01191         default:
01192           break;
01193       }
01194       msg->conn->pcb.tcp = NULL;
01195     }
01196     /* tcp netconns don't come here! */
01197 
01198     /* @todo: this lets select make the socket readable and writable,
01199        which is wrong! errfd instead? */
01200     API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
01201     API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
01202   }
01203   if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) {
01204     TCPIP_APIMSG_ACK(msg);
01205   }
01206 }
01207 
01208 /**
01209  * Bind a pcb contained in a netconn
01210  * Called from netconn_bind.
01211  *
01212  * @param m the api_msg pointing to the connection and containing
01213  *          the IP address and port to bind to
01214  */
01215 void
01216 lwip_netconn_do_bind(void *m)
01217 {
01218   struct api_msg *msg = (struct api_msg *)m;
01219   err_t err;
01220 
01221   if (msg->conn->pcb.tcp != NULL) {
01222     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01223 #if LWIP_RAW
01224       case NETCONN_RAW:
01225         err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
01226         break;
01227 #endif /* LWIP_RAW */
01228 #if LWIP_UDP
01229       case NETCONN_UDP:
01230         err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
01231         break;
01232 #endif /* LWIP_UDP */
01233 #if LWIP_TCP
01234       case NETCONN_TCP:
01235         err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
01236         break;
01237 #endif /* LWIP_TCP */
01238       default:
01239         err = ERR_VAL;
01240         break;
01241     }
01242   } else {
01243     err = ERR_VAL;
01244   }
01245   msg->err = err;
01246   TCPIP_APIMSG_ACK(msg);
01247 }
01248 /**
01249  * Bind a pcb contained in a netconn to an interface
01250  * Called from netconn_bind_if.
01251  *
01252  * @param m the api_msg pointing to the connection and containing
01253  *          the IP address and port to bind to
01254  */
01255 void
01256 lwip_netconn_do_bind_if(void *m)
01257 {
01258   struct netif *netif;
01259   struct api_msg *msg = (struct api_msg *)m;
01260   err_t err;
01261 
01262   netif = netif_get_by_index(msg->msg.bc.if_idx);
01263 
01264   if ((netif != NULL) && (msg->conn->pcb.tcp != NULL)) {
01265     err = ERR_OK;
01266     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01267 #if LWIP_RAW
01268       case NETCONN_RAW:
01269         raw_bind_netif(msg->conn->pcb.raw, netif);
01270         break;
01271 #endif /* LWIP_RAW */
01272 #if LWIP_UDP
01273       case NETCONN_UDP:
01274         udp_bind_netif(msg->conn->pcb.udp, netif);
01275         break;
01276 #endif /* LWIP_UDP */
01277 #if LWIP_TCP
01278       case NETCONN_TCP:
01279         tcp_bind_netif(msg->conn->pcb.tcp, netif);
01280         break;
01281 #endif /* LWIP_TCP */
01282       default:
01283         err = ERR_VAL;
01284         break;
01285     }
01286   } else {
01287     err = ERR_VAL;
01288   }
01289   msg->err = err;
01290   TCPIP_APIMSG_ACK(msg);
01291 }
01292 
01293 #if LWIP_TCP
01294 /**
01295  * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has
01296  * been established (or reset by the remote host).
01297  *
01298  * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
01299  */
01300 static err_t
01301 lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
01302 {
01303   struct netconn *conn;
01304   int was_blocking;
01305   sys_sem_t *op_completed_sem = NULL;
01306 
01307   LWIP_UNUSED_ARG(pcb);
01308 
01309   conn = (struct netconn *)arg;
01310 
01311   if (conn == NULL) {
01312     return ERR_VAL;
01313   }
01314 
01315   LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
01316   LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
01317               (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
01318 
01319   if (conn->current_msg != NULL) {
01320     conn->current_msg->err = err;
01321     op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
01322   }
01323   if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) {
01324     setup_tcp(conn);
01325   }
01326   was_blocking = !IN_NONBLOCKING_CONNECT(conn);
01327   SET_NONBLOCKING_CONNECT(conn, 0);
01328   LWIP_ASSERT("blocking connect state error",
01329               (was_blocking && op_completed_sem != NULL) ||
01330               (!was_blocking && op_completed_sem == NULL));
01331   conn->current_msg = NULL;
01332   conn->state = NETCONN_NONE;
01333   API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
01334 
01335   if (was_blocking && op_completed_sem != NULL) {
01336     sys_sem_signal(op_completed_sem);
01337   }
01338   return ERR_OK;
01339 }
01340 #endif /* LWIP_TCP */
01341 
01342 /**
01343  * Connect a pcb contained inside a netconn
01344  * Called from netconn_connect.
01345  *
01346  * @param m the api_msg pointing to the connection and containing
01347  *          the IP address and port to connect to
01348  */
01349 void
01350 lwip_netconn_do_connect(void *m)
01351 {
01352   struct api_msg *msg = (struct api_msg *)m;
01353   err_t err;
01354 
01355   if (msg->conn->pcb.tcp == NULL) {
01356     /* This may happen when calling netconn_connect() a second time */
01357     err = ERR_CLSD;
01358   } else {
01359     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01360 #if LWIP_RAW
01361       case NETCONN_RAW:
01362         err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
01363         break;
01364 #endif /* LWIP_RAW */
01365 #if LWIP_UDP
01366       case NETCONN_UDP:
01367         err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
01368         break;
01369 #endif /* LWIP_UDP */
01370 #if LWIP_TCP
01371       case NETCONN_TCP:
01372         /* Prevent connect while doing any other action. */
01373         if (msg->conn->state == NETCONN_CONNECT) {
01374           err = ERR_ALREADY;
01375         } else if (msg->conn->state != NETCONN_NONE) {
01376           err = ERR_ISCONN;
01377         } else {
01378           setup_tcp(msg->conn);
01379           err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr),
01380                             msg->msg.bc.port, lwip_netconn_do_connected);
01381           if (err == ERR_OK) {
01382             u8_t non_blocking = netconn_is_nonblocking(msg->conn);
01383             msg->conn->state = NETCONN_CONNECT;
01384             SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
01385             if (non_blocking) {
01386               err = ERR_INPROGRESS;
01387             } else {
01388               msg->conn->current_msg = msg;
01389               /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()),
01390                  when the connection is established! */
01391 #if LWIP_TCPIP_CORE_LOCKING
01392               LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT);
01393               UNLOCK_TCPIP_CORE();
01394               sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
01395               LOCK_TCPIP_CORE();
01396               LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT);
01397 #endif /* LWIP_TCPIP_CORE_LOCKING */
01398               return;
01399             }
01400           }
01401         }
01402         break;
01403 #endif /* LWIP_TCP */
01404       default:
01405         LWIP_ERROR("Invalid netconn type", 0, do {
01406           err = ERR_VAL;
01407         } while (0));
01408         break;
01409     }
01410   }
01411   msg->err = err;
01412   /* For all other protocols, netconn_connect() calls netconn_apimsg(),
01413      so use TCPIP_APIMSG_ACK() here. */
01414   TCPIP_APIMSG_ACK(msg);
01415 }
01416 
01417 /**
01418  * Disconnect a pcb contained inside a netconn
01419  * Only used for UDP netconns.
01420  * Called from netconn_disconnect.
01421  *
01422  * @param m the api_msg pointing to the connection to disconnect
01423  */
01424 void
01425 lwip_netconn_do_disconnect(void *m)
01426 {
01427   struct api_msg *msg = (struct api_msg *)m;
01428 
01429 #if LWIP_UDP
01430   if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
01431     udp_disconnect(msg->conn->pcb.udp);
01432     msg->err = ERR_OK;
01433   } else
01434 #endif /* LWIP_UDP */
01435   {
01436     msg->err = ERR_VAL;
01437   }
01438   TCPIP_APIMSG_ACK(msg);
01439 }
01440 
01441 #if LWIP_TCP
01442 /**
01443  * Set a TCP pcb contained in a netconn into listen mode
01444  * Called from netconn_listen.
01445  *
01446  * @param m the api_msg pointing to the connection
01447  */
01448 void
01449 lwip_netconn_do_listen(void *m)
01450 {
01451   struct api_msg *msg = (struct api_msg *)m;
01452   err_t err;
01453 
01454   if (msg->conn->pcb.tcp != NULL) {
01455     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
01456       if (msg->conn->state == NETCONN_NONE) {
01457         struct tcp_pcb *lpcb;
01458         if (msg->conn->pcb.tcp->state != CLOSED) {
01459           /* connection is not closed, cannot listen */
01460           err = ERR_VAL;
01461         } else {
01462           u8_t backlog;
01463 #if TCP_LISTEN_BACKLOG
01464           backlog = msg->msg.lb.backlog;
01465 #else  /* TCP_LISTEN_BACKLOG */
01466           backlog = TCP_DEFAULT_LISTEN_BACKLOG;
01467 #endif /* TCP_LISTEN_BACKLOG */
01468 #if LWIP_IPV4 && LWIP_IPV6
01469           /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
01470             * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
01471             */
01472           if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) &&
01473               (netconn_get_ipv6only(msg->conn) == 0)) {
01474             /* change PCB type to IPADDR_TYPE_ANY */
01475             IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip,  IPADDR_TYPE_ANY);
01476             IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY);
01477           }
01478 #endif /* LWIP_IPV4 && LWIP_IPV6 */
01479 
01480           lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
01481 
01482           if (lpcb == NULL) {
01483             /* in this case, the old pcb is still allocated */
01484           } else {
01485             /* delete the recvmbox and allocate the acceptmbox */
01486             if (sys_mbox_valid(&msg->conn->recvmbox)) {
01487               /** @todo: should we drain the recvmbox here? */
01488               sys_mbox_free(&msg->conn->recvmbox);
01489               sys_mbox_set_invalid(&msg->conn->recvmbox);
01490             }
01491             err = ERR_OK;
01492             if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
01493               err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
01494             }
01495             if (err == ERR_OK) {
01496               msg->conn->state = NETCONN_LISTEN;
01497               msg->conn->pcb.tcp = lpcb;
01498               tcp_arg(msg->conn->pcb.tcp, msg->conn);
01499               tcp_accept(msg->conn->pcb.tcp, accept_function);
01500             } else {
01501               /* since the old pcb is already deallocated, free lpcb now */
01502               tcp_close(lpcb);
01503               msg->conn->pcb.tcp = NULL;
01504             }
01505           }
01506         }
01507       } else if (msg->conn->state == NETCONN_LISTEN) {
01508         /* already listening, allow updating of the backlog */
01509         err = ERR_OK;
01510         tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog);
01511       } else {
01512         err = ERR_CONN;
01513       }
01514     } else {
01515       err = ERR_ARG;
01516     }
01517   } else {
01518     err = ERR_CONN;
01519   }
01520   msg->err = err;
01521   TCPIP_APIMSG_ACK(msg);
01522 }
01523 #endif /* LWIP_TCP */
01524 
01525 /**
01526  * Send some data on a RAW or UDP pcb contained in a netconn
01527  * Called from netconn_send
01528  *
01529  * @param m the api_msg pointing to the connection
01530  */
01531 void
01532 lwip_netconn_do_send(void *m)
01533 {
01534   struct api_msg *msg = (struct api_msg *)m;
01535 
01536   err_t err = netconn_err(msg->conn);
01537   if (err == ERR_OK) {
01538     if (msg->conn->pcb.tcp != NULL) {
01539       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01540 #if LWIP_RAW
01541         case NETCONN_RAW:
01542           if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
01543             err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
01544           } else {
01545             err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
01546           }
01547           break;
01548 #endif
01549 #if LWIP_UDP
01550         case NETCONN_UDP:
01551 #if LWIP_CHECKSUM_ON_COPY
01552           if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
01553             err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
01554                                   msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
01555           } else {
01556             err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
01557                                     &msg->msg.b->addr, msg->msg.b->port,
01558                                     msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
01559           }
01560 #else /* LWIP_CHECKSUM_ON_COPY */
01561           if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
01562             err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
01563           } else {
01564             err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
01565           }
01566 #endif /* LWIP_CHECKSUM_ON_COPY */
01567           break;
01568 #endif /* LWIP_UDP */
01569         default:
01570           err = ERR_CONN;
01571           break;
01572       }
01573     } else {
01574       err = ERR_CONN;
01575     }
01576   }
01577   msg->err = err;
01578   TCPIP_APIMSG_ACK(msg);
01579 }
01580 
01581 #if LWIP_TCP
01582 /**
01583  * Indicate data has been received from a TCP pcb contained in a netconn
01584  * Called from netconn_recv
01585  *
01586  * @param m the api_msg pointing to the connection
01587  */
01588 void
01589 lwip_netconn_do_recv(void *m)
01590 {
01591   struct api_msg *msg = (struct api_msg *)m;
01592 
01593   msg->err = ERR_OK;
01594   if (msg->conn->pcb.tcp != NULL) {
01595     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
01596       size_t remaining = msg->msg.r.len;
01597       do {
01598         u16_t recved = (u16_t)((remaining > 0xffff) ? 0xffff : remaining);
01599         tcp_recved(msg->conn->pcb.tcp, recved);
01600         remaining -= recved;
01601       } while (remaining != 0);
01602     }
01603   }
01604   TCPIP_APIMSG_ACK(msg);
01605 }
01606 
01607 #if TCP_LISTEN_BACKLOG
01608 /** Indicate that a TCP pcb has been accepted
01609  * Called from netconn_accept
01610  *
01611  * @param m the api_msg pointing to the connection
01612  */
01613 void
01614 lwip_netconn_do_accepted(void *m)
01615 {
01616   struct api_msg *msg = (struct api_msg *)m;
01617 
01618   msg->err = ERR_OK;
01619   if (msg->conn->pcb.tcp != NULL) {
01620     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
01621       tcp_backlog_accepted(msg->conn->pcb.tcp);
01622     }
01623   }
01624   TCPIP_APIMSG_ACK(msg);
01625 }
01626 #endif /* TCP_LISTEN_BACKLOG */
01627 
01628 /**
01629  * See if more data needs to be written from a previous call to netconn_write.
01630  * Called initially from lwip_netconn_do_write. If the first call can't send all data
01631  * (because of low memory or empty send-buffer), this function is called again
01632  * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
01633  * blocking application thread (waiting in netconn_write) is released.
01634  *
01635  * @param conn netconn (that is currently in state NETCONN_WRITE) to process
01636  * @return ERR_OK
01637  *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
01638  */
01639 static err_t
01640 lwip_netconn_do_writemore(struct netconn *conn  WRITE_DELAYED_PARAM)
01641 {
01642   err_t err;
01643   const void *dataptr;
01644   u16_t len, available;
01645   u8_t write_finished = 0;
01646   size_t diff;
01647   u8_t dontblock;
01648   u8_t apiflags;
01649   u8_t write_more;
01650 
01651   LWIP_ASSERT("conn != NULL", conn != NULL);
01652   LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
01653   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
01654   LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
01655   LWIP_ASSERT("conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len",
01656               conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len);
01657   LWIP_ASSERT("conn->current_msg->msg.w.vector_cnt > 0", conn->current_msg->msg.w.vector_cnt > 0);
01658 
01659   apiflags = conn->current_msg->msg.w.apiflags;
01660   dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
01661 
01662 #if LWIP_SO_SNDTIMEO
01663   if ((conn->send_timeout != 0) &&
01664       ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
01665     write_finished = 1;
01666     if (conn->current_msg->msg.w.offset == 0) {
01667       /* nothing has been written */
01668       err = ERR_WOULDBLOCK;
01669     } else {
01670       /* partial write */
01671       err = ERR_OK;
01672     }
01673   } else
01674 #endif /* LWIP_SO_SNDTIMEO */
01675   {
01676     do {
01677       dataptr = (const u8_t *)conn->current_msg->msg.w.vector->ptr + conn->current_msg->msg.w.vector_off;
01678       diff = conn->current_msg->msg.w.vector->len - conn->current_msg->msg.w.vector_off;
01679       if (diff > 0xffffUL) { /* max_u16_t */
01680         len = 0xffff;
01681         apiflags |= TCP_WRITE_FLAG_MORE;
01682       } else {
01683         len = (u16_t)diff;
01684       }
01685       available = tcp_sndbuf(conn->pcb.tcp);
01686       if (available < len) {
01687         /* don't try to write more than sendbuf */
01688         len = available;
01689         if (dontblock) {
01690           if (!len) {
01691             /* set error according to partial write or not */
01692             err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK;
01693             goto err_mem;
01694           }
01695         } else {
01696           apiflags |= TCP_WRITE_FLAG_MORE;
01697         }
01698       }
01699       LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!",
01700                   ((conn->current_msg->msg.w.vector_off + len) <= conn->current_msg->msg.w.vector->len));
01701       /* we should loop around for more sending in the following cases:
01702            1) We couldn't finish the current vector because of 16-bit size limitations.
01703               tcp_write() and tcp_sndbuf() both are limited to 16-bit sizes
01704            2) We are sending the remainder of the current vector and have more */
01705       if ((len == 0xffff && diff > 0xffffUL) ||
01706           (len == (u16_t)diff && conn->current_msg->msg.w.vector_cnt > 1)) {
01707         write_more = 1;
01708         apiflags |= TCP_WRITE_FLAG_MORE;
01709       } else {
01710         write_more = 0;
01711       }
01712       err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
01713       if (err == ERR_OK) {
01714         conn->current_msg->msg.w.offset += len;
01715         conn->current_msg->msg.w.vector_off += len;
01716         /* check if current vector is finished */
01717         if (conn->current_msg->msg.w.vector_off == conn->current_msg->msg.w.vector->len) {
01718           conn->current_msg->msg.w.vector_cnt--;
01719           /* if we have additional vectors, move on to them */
01720           if (conn->current_msg->msg.w.vector_cnt > 0) {
01721             conn->current_msg->msg.w.vector++;
01722             conn->current_msg->msg.w.vector_off = 0;
01723           }
01724         }
01725       }
01726     } while (write_more && err == ERR_OK);
01727     /* if OK or memory error, check available space */
01728     if ((err == ERR_OK) || (err == ERR_MEM)) {
01729 err_mem:
01730       if (dontblock && (conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len)) {
01731         /* non-blocking write did not write everything: mark the pcb non-writable
01732            and let poll_tcp check writable space to mark the pcb writable again */
01733         API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
01734         conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
01735       } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
01736                  (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
01737         /* The queued byte- or pbuf-count exceeds the configured low-water limit,
01738            let select mark this pcb as non-writable. */
01739         API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
01740       }
01741     }
01742 
01743     if (err == ERR_OK) {
01744       err_t out_err;
01745       if ((conn->current_msg->msg.w.offset == conn->current_msg->msg.w.len) || dontblock) {
01746         /* return sent length (caller reads length from msg.w.offset) */
01747         write_finished = 1;
01748       }
01749       out_err = tcp_output(conn->pcb.tcp);
01750       if (out_err == ERR_RTE) {
01751         /* If tcp_output fails because no route is found,
01752            don't try writing any more but return the error
01753            to the application thread. */
01754         err = out_err;
01755         write_finished = 1;
01756       }
01757     } else if (err == ERR_MEM) {
01758       /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called.
01759          For blocking sockets, we do NOT return to the application
01760          thread, since ERR_MEM is only a temporary error! Non-blocking
01761          will remain non-writable until sent_tcp/poll_tcp is called */
01762 
01763       /* tcp_write returned ERR_MEM, try tcp_output anyway */
01764       err_t out_err = tcp_output(conn->pcb.tcp);
01765       if (out_err == ERR_RTE) {
01766         /* If tcp_output fails because no route is found,
01767            don't try writing any more but return the error
01768            to the application thread. */
01769         err = out_err;
01770         write_finished = 1;
01771       } else if (dontblock) {
01772         /* non-blocking write is done on ERR_MEM, set error according
01773            to partial write or not */
01774         err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK;
01775         write_finished = 1;
01776       }
01777     } else {
01778       /* On errors != ERR_MEM, we don't try writing any more but return
01779          the error to the application thread. */
01780       write_finished = 1;
01781     }
01782   }
01783   if (write_finished) {
01784     /* everything was written: set back connection state
01785        and back to application task */
01786     sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
01787     conn->current_msg->err = err;
01788     conn->current_msg = NULL;
01789     conn->state = NETCONN_NONE;
01790 #if LWIP_TCPIP_CORE_LOCKING
01791     if (delayed)
01792 #endif
01793     {
01794       sys_sem_signal(op_completed_sem);
01795     }
01796   }
01797 #if LWIP_TCPIP_CORE_LOCKING
01798   else {
01799     return ERR_MEM;
01800   }
01801 #endif
01802   return ERR_OK;
01803 }
01804 #endif /* LWIP_TCP */
01805 
01806 /**
01807  * Send some data on a TCP pcb contained in a netconn
01808  * Called from netconn_write
01809  *
01810  * @param m the api_msg pointing to the connection
01811  */
01812 void
01813 lwip_netconn_do_write(void *m)
01814 {
01815   struct api_msg *msg = (struct api_msg *)m;
01816 
01817   err_t err = netconn_err(msg->conn);
01818   if (err == ERR_OK) {
01819     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
01820 #if LWIP_TCP
01821       if (msg->conn->state != NETCONN_NONE) {
01822         /* netconn is connecting, closing or in blocking write */
01823         err = ERR_INPROGRESS;
01824       } else if (msg->conn->pcb.tcp != NULL) {
01825         msg->conn->state = NETCONN_WRITE;
01826         /* set all the variables used by lwip_netconn_do_writemore */
01827         LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL);
01828         LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
01829         msg->conn->current_msg = msg;
01830 #if LWIP_TCPIP_CORE_LOCKING
01831         if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) {
01832           LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
01833           UNLOCK_TCPIP_CORE();
01834           sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
01835           LOCK_TCPIP_CORE();
01836           LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE);
01837         }
01838 #else /* LWIP_TCPIP_CORE_LOCKING */
01839         lwip_netconn_do_writemore(msg->conn);
01840 #endif /* LWIP_TCPIP_CORE_LOCKING */
01841         /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG
01842            since lwip_netconn_do_writemore ACKs it! */
01843         return;
01844       } else {
01845         err = ERR_CONN;
01846       }
01847 #else /* LWIP_TCP */
01848       err = ERR_VAL;
01849 #endif /* LWIP_TCP */
01850 #if (LWIP_UDP || LWIP_RAW)
01851     } else {
01852       err = ERR_VAL;
01853 #endif /* (LWIP_UDP || LWIP_RAW) */
01854     }
01855   }
01856   msg->err = err;
01857   TCPIP_APIMSG_ACK(msg);
01858 }
01859 
01860 /**
01861  * Return a connection's local or remote address
01862  * Called from netconn_getaddr
01863  *
01864  * @param m the api_msg pointing to the connection
01865  */
01866 void
01867 lwip_netconn_do_getaddr(void *m)
01868 {
01869   struct api_msg *msg = (struct api_msg *)m;
01870 
01871   if (msg->conn->pcb.ip != NULL) {
01872     if (msg->msg.ad.local) {
01873       ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
01874                    msg->conn->pcb.ip->local_ip);
01875     } else {
01876       ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
01877                    msg->conn->pcb.ip->remote_ip);
01878     }
01879 
01880     msg->err = ERR_OK;
01881     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
01882 #if LWIP_RAW
01883       case NETCONN_RAW:
01884         if (msg->msg.ad.local) {
01885           API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
01886         } else {
01887           /* return an error as connecting is only a helper for upper layers */
01888           msg->err = ERR_CONN;
01889         }
01890         break;
01891 #endif /* LWIP_RAW */
01892 #if LWIP_UDP
01893       case NETCONN_UDP:
01894         if (msg->msg.ad.local) {
01895           API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
01896         } else {
01897           if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
01898             msg->err = ERR_CONN;
01899           } else {
01900             API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
01901           }
01902         }
01903         break;
01904 #endif /* LWIP_UDP */
01905 #if LWIP_TCP
01906       case NETCONN_TCP:
01907         if ((msg->msg.ad.local == 0) &&
01908             ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) {
01909           /* pcb is not connected and remote name is requested */
01910           msg->err = ERR_CONN;
01911         } else {
01912           API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port);
01913         }
01914         break;
01915 #endif /* LWIP_TCP */
01916       default:
01917         LWIP_ASSERT("invalid netconn_type", 0);
01918         break;
01919     }
01920   } else {
01921     msg->err = ERR_CONN;
01922   }
01923   TCPIP_APIMSG_ACK(msg);
01924 }
01925 
01926 /**
01927  * Close or half-shutdown a TCP pcb contained in a netconn
01928  * Called from netconn_close
01929  * In contrast to closing sockets, the netconn is not deallocated.
01930  *
01931  * @param m the api_msg pointing to the connection
01932  */
01933 void
01934 lwip_netconn_do_close(void *m)
01935 {
01936   struct api_msg *msg = (struct api_msg *)m;
01937 
01938 #if LWIP_TCP
01939   enum netconn_state state = msg->conn->state;
01940   /* First check if this is a TCP netconn and if it is in a correct state
01941       (LISTEN doesn't support half shutdown) */
01942   if ((msg->conn->pcb.tcp != NULL) &&
01943       (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) &&
01944       ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) {
01945     /* Check if we are in a connected state */
01946     if (state == NETCONN_CONNECT) {
01947       /* TCP connect in progress: cannot shutdown */
01948       msg->err = ERR_CONN;
01949     } else if (state == NETCONN_WRITE) {
01950 #if LWIP_NETCONN_FULLDUPLEX
01951       if (msg->msg.sd.shut & NETCONN_SHUT_WR) {
01952         /* close requested, abort running write */
01953         sys_sem_t *write_completed_sem;
01954         LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
01955         write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
01956         msg->conn->current_msg->err = ERR_CLSD;
01957         msg->conn->current_msg = NULL;
01958         msg->conn->state = NETCONN_NONE;
01959         state = NETCONN_NONE;
01960         sys_sem_signal(write_completed_sem);
01961       } else {
01962         LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD);
01963         /* In this case, let the write continue and do not interfere with
01964            conn->current_msg or conn->state! */
01965         msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0);
01966       }
01967     }
01968     if (state == NETCONN_NONE) {
01969 #else /* LWIP_NETCONN_FULLDUPLEX */
01970       msg->err = ERR_INPROGRESS;
01971     } else {
01972 #endif /* LWIP_NETCONN_FULLDUPLEX */
01973       if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
01974 #if LWIP_NETCONN_FULLDUPLEX
01975         /* Mark mboxes invalid */
01976         netconn_mark_mbox_invalid(msg->conn);
01977 #else /* LWIP_NETCONN_FULLDUPLEX */
01978         netconn_drain(msg->conn);
01979 #endif /* LWIP_NETCONN_FULLDUPLEX */
01980       }
01981       LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL);
01982       msg->conn->state = NETCONN_CLOSE;
01983       msg->conn->current_msg = msg;
01984 #if LWIP_TCPIP_CORE_LOCKING
01985       if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
01986         LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
01987         UNLOCK_TCPIP_CORE();
01988         sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
01989         LOCK_TCPIP_CORE();
01990         LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
01991       }
01992 #else /* LWIP_TCPIP_CORE_LOCKING */
01993       lwip_netconn_do_close_internal(msg->conn);
01994 #endif /* LWIP_TCPIP_CORE_LOCKING */
01995       /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */
01996       return;
01997     }
01998   } else
01999 #endif /* LWIP_TCP */
02000   {
02001     msg->err = ERR_CONN;
02002   }
02003   TCPIP_APIMSG_ACK(msg);
02004 }
02005 
02006 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
02007 /**
02008  * Join multicast groups for UDP netconns.
02009  * Called from netconn_join_leave_group
02010  *
02011  * @param m the api_msg pointing to the connection
02012  */
02013 void
02014 lwip_netconn_do_join_leave_group(void *m)
02015 {
02016   struct api_msg *msg = (struct api_msg *)m;
02017 
02018   msg->err = ERR_CONN;
02019   if (msg->conn->pcb.tcp != NULL) {
02020     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
02021 #if LWIP_UDP
02022 #if LWIP_IPV6 && LWIP_IPV6_MLD
02023       if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
02024         if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
02025           msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
02026                                     ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
02027         } else {
02028           msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
02029                                      ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
02030         }
02031       } else
02032 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
02033       {
02034 #if LWIP_IGMP
02035         if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
02036           msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
02037                                     ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
02038         } else {
02039           msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
02040                                      ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
02041         }
02042 #endif /* LWIP_IGMP */
02043       }
02044 #endif /* LWIP_UDP */
02045 #if (LWIP_TCP || LWIP_RAW)
02046     } else {
02047       msg->err = ERR_VAL;
02048 #endif /* (LWIP_TCP || LWIP_RAW) */
02049     }
02050   }
02051   TCPIP_APIMSG_ACK(msg);
02052 }
02053 /**
02054  * Join multicast groups for UDP netconns.
02055  * Called from netconn_join_leave_group_netif
02056  *
02057  * @param m the api_msg pointing to the connection
02058  */
02059 void
02060 lwip_netconn_do_join_leave_group_netif(void *m)
02061 {
02062   struct api_msg *msg = (struct api_msg *)m;
02063   struct netif *netif;
02064 
02065   netif = netif_get_by_index(msg->msg.jl.if_idx);
02066   if (netif == NULL) {
02067     msg->err = ERR_IF;
02068     goto done;
02069   }
02070 
02071   msg->err = ERR_CONN;
02072   if (msg->conn->pcb.tcp != NULL) {
02073     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
02074 #if LWIP_UDP
02075 #if LWIP_IPV6 && LWIP_IPV6_MLD
02076       if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
02077         if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
02078           msg->err = mld6_joingroup_netif(netif,
02079                                           ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
02080         } else {
02081           msg->err = mld6_leavegroup_netif(netif,
02082                                            ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
02083         }
02084       } else
02085 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
02086       {
02087 #if LWIP_IGMP
02088         if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
02089           msg->err = igmp_joingroup_netif(netif,
02090                                           ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
02091         } else {
02092           msg->err = igmp_leavegroup_netif(netif,
02093                                            ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
02094         }
02095 #endif /* LWIP_IGMP */
02096       }
02097 #endif /* LWIP_UDP */
02098 #if (LWIP_TCP || LWIP_RAW)
02099     } else {
02100       msg->err = ERR_VAL;
02101 #endif /* (LWIP_TCP || LWIP_RAW) */
02102     }
02103   }
02104 
02105 done:
02106   TCPIP_APIMSG_ACK(msg);
02107 }
02108 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
02109 
02110 #if LWIP_DNS
02111 #if LWIP_FULL_DNS
02112 /**
02113  * Callback function that is called when DNS name is resolved
02114  * (or on timeout). A waiting application thread is waked up by
02115  * signaling the semaphore.
02116  */
02117 static void
02118 lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg)
02119 {
02120   struct dns_api_msg *msg = (struct dns_api_msg *)arg;
02121 
02122   /* we trust the internal implementation to be correct :-) */
02123   LWIP_UNUSED_ARG(name);
02124 
02125   if (ipaddr == NULL) {
02126     /* timeout or memory error */
02127     API_EXPR_DEREF(msg->err) = ERR_VAL;
02128   } else {
02129     /* address was resolved */
02130     API_EXPR_DEREF(msg->err) = ERR_OK;
02131     API_EXPR_DEREF(msg->addr) = *ipaddr;
02132   }
02133   /* wake up the application task waiting in netconn_gethostbyname */
02134   sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
02135 }
02136 
02137 /**
02138  * Execute a DNS query
02139  * Called from netconn_gethostbyname
02140  *
02141  * @param arg the dns_api_msg pointing to the query
02142  */
02143 void
02144 lwip_netconn_do_gethostbyname(void *arg)
02145 {
02146   struct dns_api_msg *msg = (struct dns_api_msg *)arg;
02147   u8_t addrtype =
02148 #if LWIP_IPV4 && LWIP_IPV6
02149     msg->dns_addrtype;
02150 #else
02151     LWIP_DNS_ADDRTYPE_DEFAULT;
02152 #endif
02153 
02154   API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name,
02155                              API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype);
02156 #if LWIP_TCPIP_CORE_LOCKING
02157   /* For core locking, only block if we need to wait for answer/timeout */
02158   if (API_EXPR_DEREF(msg->err) == ERR_INPROGRESS) {
02159     UNLOCK_TCPIP_CORE();
02160     sys_sem_wait(API_EXPR_REF_SEM(msg->sem));
02161     LOCK_TCPIP_CORE();
02162     LWIP_ASSERT("do_gethostbyname still in progress!!", API_EXPR_DEREF(msg->err) != ERR_INPROGRESS);
02163   }
02164 #else /* LWIP_TCPIP_CORE_LOCKING */
02165   if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) {
02166     /* on error or immediate success, wake up the application
02167      * task waiting in netconn_gethostbyname */
02168     sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
02169   }
02170 #endif /* LWIP_TCPIP_CORE_LOCKING */
02171 }
02172 #endif /* LWIP_DNS */
02173 #endif /* LWIP_FULL_DNS */
02174 
02175 #endif /* LWIP_NETCONN */