xref: /minix3/minix/lib/liblwip/dist/src/api/api_msg.c (revision 5d5fbe79c1b60734f34c69330aec5496644e8651)
1*5d5fbe79SDavid van Moolenbroek /**
2*5d5fbe79SDavid van Moolenbroek  * @file
3*5d5fbe79SDavid van Moolenbroek  * Sequential API Internal module
4*5d5fbe79SDavid van Moolenbroek  *
5*5d5fbe79SDavid van Moolenbroek  */
6*5d5fbe79SDavid van Moolenbroek 
7*5d5fbe79SDavid van Moolenbroek /*
8*5d5fbe79SDavid van Moolenbroek  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9*5d5fbe79SDavid van Moolenbroek  * All rights reserved.
10*5d5fbe79SDavid van Moolenbroek  *
11*5d5fbe79SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without modification,
12*5d5fbe79SDavid van Moolenbroek  * are permitted provided that the following conditions are met:
13*5d5fbe79SDavid van Moolenbroek  *
14*5d5fbe79SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright notice,
15*5d5fbe79SDavid van Moolenbroek  *    this list of conditions and the following disclaimer.
16*5d5fbe79SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright notice,
17*5d5fbe79SDavid van Moolenbroek  *    this list of conditions and the following disclaimer in the documentation
18*5d5fbe79SDavid van Moolenbroek  *    and/or other materials provided with the distribution.
19*5d5fbe79SDavid van Moolenbroek  * 3. The name of the author may not be used to endorse or promote products
20*5d5fbe79SDavid van Moolenbroek  *    derived from this software without specific prior written permission.
21*5d5fbe79SDavid van Moolenbroek  *
22*5d5fbe79SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23*5d5fbe79SDavid van Moolenbroek  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24*5d5fbe79SDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25*5d5fbe79SDavid van Moolenbroek  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26*5d5fbe79SDavid van Moolenbroek  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27*5d5fbe79SDavid van Moolenbroek  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28*5d5fbe79SDavid van Moolenbroek  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29*5d5fbe79SDavid van Moolenbroek  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30*5d5fbe79SDavid van Moolenbroek  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31*5d5fbe79SDavid van Moolenbroek  * OF SUCH DAMAGE.
32*5d5fbe79SDavid van Moolenbroek  *
33*5d5fbe79SDavid van Moolenbroek  * This file is part of the lwIP TCP/IP stack.
34*5d5fbe79SDavid van Moolenbroek  *
35*5d5fbe79SDavid van Moolenbroek  * Author: Adam Dunkels <adam@sics.se>
36*5d5fbe79SDavid van Moolenbroek  *
37*5d5fbe79SDavid van Moolenbroek  */
38*5d5fbe79SDavid van Moolenbroek 
39*5d5fbe79SDavid van Moolenbroek #include "lwip/opt.h"
40*5d5fbe79SDavid van Moolenbroek 
41*5d5fbe79SDavid van Moolenbroek #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
42*5d5fbe79SDavid van Moolenbroek 
43*5d5fbe79SDavid van Moolenbroek #include "lwip/priv/api_msg.h"
44*5d5fbe79SDavid van Moolenbroek 
45*5d5fbe79SDavid van Moolenbroek #include "lwip/ip.h"
46*5d5fbe79SDavid van Moolenbroek #include "lwip/ip_addr.h"
47*5d5fbe79SDavid van Moolenbroek #include "lwip/udp.h"
48*5d5fbe79SDavid van Moolenbroek #include "lwip/tcp.h"
49*5d5fbe79SDavid van Moolenbroek #include "lwip/raw.h"
50*5d5fbe79SDavid van Moolenbroek 
51*5d5fbe79SDavid van Moolenbroek #include "lwip/memp.h"
52*5d5fbe79SDavid van Moolenbroek #include "lwip/igmp.h"
53*5d5fbe79SDavid van Moolenbroek #include "lwip/dns.h"
54*5d5fbe79SDavid van Moolenbroek #include "lwip/mld6.h"
55*5d5fbe79SDavid van Moolenbroek #include "lwip/priv/tcpip_priv.h"
56*5d5fbe79SDavid van Moolenbroek 
57*5d5fbe79SDavid van Moolenbroek #include <string.h>
58*5d5fbe79SDavid van Moolenbroek 
59*5d5fbe79SDavid van Moolenbroek /* netconns are polled once per second (e.g. continue write on memory error) */
60*5d5fbe79SDavid van Moolenbroek #define NETCONN_TCP_POLL_INTERVAL 2
61*5d5fbe79SDavid van Moolenbroek 
62*5d5fbe79SDavid van Moolenbroek #define SET_NONBLOCKING_CONNECT(conn, val)  do { if (val) { \
63*5d5fbe79SDavid van Moolenbroek   (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \
64*5d5fbe79SDavid van Moolenbroek } else { \
65*5d5fbe79SDavid van Moolenbroek   (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0)
66*5d5fbe79SDavid van Moolenbroek #define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0)
67*5d5fbe79SDavid van Moolenbroek 
68*5d5fbe79SDavid van Moolenbroek /* forward declarations */
69*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
70*5d5fbe79SDavid van Moolenbroek #if LWIP_TCPIP_CORE_LOCKING
71*5d5fbe79SDavid van Moolenbroek #define WRITE_DELAYED         , 1
72*5d5fbe79SDavid van Moolenbroek #define WRITE_DELAYED_PARAM   , u8_t delayed
73*5d5fbe79SDavid van Moolenbroek #else /* LWIP_TCPIP_CORE_LOCKING */
74*5d5fbe79SDavid van Moolenbroek #define WRITE_DELAYED
75*5d5fbe79SDavid van Moolenbroek #define WRITE_DELAYED_PARAM
76*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCPIP_CORE_LOCKING */
77*5d5fbe79SDavid van Moolenbroek static err_t lwip_netconn_do_writemore(struct netconn *conn  WRITE_DELAYED_PARAM);
78*5d5fbe79SDavid van Moolenbroek static err_t lwip_netconn_do_close_internal(struct netconn *conn  WRITE_DELAYED_PARAM);
79*5d5fbe79SDavid van Moolenbroek #endif
80*5d5fbe79SDavid van Moolenbroek 
81*5d5fbe79SDavid van Moolenbroek #if LWIP_TCPIP_CORE_LOCKING
82*5d5fbe79SDavid van Moolenbroek #define TCPIP_APIMSG_ACK(m)   NETCONN_SET_SAFE_ERR((m)->conn, (m)->err)
83*5d5fbe79SDavid van Moolenbroek #else /* LWIP_TCPIP_CORE_LOCKING */
84*5d5fbe79SDavid van Moolenbroek #define TCPIP_APIMSG_ACK(m)   do { NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0)
85*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCPIP_CORE_LOCKING */
86*5d5fbe79SDavid van Moolenbroek 
87*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
88*5d5fbe79SDavid van Moolenbroek u8_t netconn_aborted;
89*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
90*5d5fbe79SDavid van Moolenbroek 
91*5d5fbe79SDavid van Moolenbroek #if LWIP_RAW
92*5d5fbe79SDavid van Moolenbroek /**
93*5d5fbe79SDavid van Moolenbroek  * Receive callback function for RAW netconns.
94*5d5fbe79SDavid van Moolenbroek  * Doesn't 'eat' the packet, only copies it and sends it to
95*5d5fbe79SDavid van Moolenbroek  * conn->recvmbox
96*5d5fbe79SDavid van Moolenbroek  *
97*5d5fbe79SDavid van Moolenbroek  * @see raw.h (struct raw_pcb.recv) for parameters and return value
98*5d5fbe79SDavid van Moolenbroek  */
99*5d5fbe79SDavid van Moolenbroek static u8_t
recv_raw(void * arg,struct raw_pcb * pcb,struct pbuf * p,const ip_addr_t * addr)100*5d5fbe79SDavid van Moolenbroek recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
101*5d5fbe79SDavid van Moolenbroek     const ip_addr_t *addr)
102*5d5fbe79SDavid van Moolenbroek {
103*5d5fbe79SDavid van Moolenbroek   struct pbuf *q;
104*5d5fbe79SDavid van Moolenbroek   struct netbuf *buf;
105*5d5fbe79SDavid van Moolenbroek   struct netconn *conn;
106*5d5fbe79SDavid van Moolenbroek 
107*5d5fbe79SDavid van Moolenbroek   LWIP_UNUSED_ARG(addr);
108*5d5fbe79SDavid van Moolenbroek   conn = (struct netconn *)arg;
109*5d5fbe79SDavid van Moolenbroek 
110*5d5fbe79SDavid van Moolenbroek   if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) {
111*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_RCVBUF
112*5d5fbe79SDavid van Moolenbroek     int recv_avail;
113*5d5fbe79SDavid van Moolenbroek     SYS_ARCH_GET(conn->recv_avail, recv_avail);
114*5d5fbe79SDavid van Moolenbroek     if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
115*5d5fbe79SDavid van Moolenbroek       return 0;
116*5d5fbe79SDavid van Moolenbroek     }
117*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_RCVBUF */
118*5d5fbe79SDavid van Moolenbroek     /* copy the whole packet into new pbufs */
119*5d5fbe79SDavid van Moolenbroek     q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
120*5d5fbe79SDavid van Moolenbroek     if (q != NULL) {
121*5d5fbe79SDavid van Moolenbroek       if (pbuf_copy(q, p) != ERR_OK) {
122*5d5fbe79SDavid van Moolenbroek         pbuf_free(q);
123*5d5fbe79SDavid van Moolenbroek         q = NULL;
124*5d5fbe79SDavid van Moolenbroek       }
125*5d5fbe79SDavid van Moolenbroek     }
126*5d5fbe79SDavid van Moolenbroek 
127*5d5fbe79SDavid van Moolenbroek     if (q != NULL) {
128*5d5fbe79SDavid van Moolenbroek       u16_t len;
129*5d5fbe79SDavid van Moolenbroek       buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
130*5d5fbe79SDavid van Moolenbroek       if (buf == NULL) {
131*5d5fbe79SDavid van Moolenbroek         pbuf_free(q);
132*5d5fbe79SDavid van Moolenbroek         return 0;
133*5d5fbe79SDavid van Moolenbroek       }
134*5d5fbe79SDavid van Moolenbroek 
135*5d5fbe79SDavid van Moolenbroek       buf->p = q;
136*5d5fbe79SDavid van Moolenbroek       buf->ptr = q;
137*5d5fbe79SDavid van Moolenbroek       ip_addr_copy(buf->addr, *ip_current_src_addr());
138*5d5fbe79SDavid van Moolenbroek       buf->port = pcb->protocol;
139*5d5fbe79SDavid van Moolenbroek 
140*5d5fbe79SDavid van Moolenbroek       len = q->tot_len;
141*5d5fbe79SDavid van Moolenbroek       if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
142*5d5fbe79SDavid van Moolenbroek         netbuf_delete(buf);
143*5d5fbe79SDavid van Moolenbroek         return 0;
144*5d5fbe79SDavid van Moolenbroek       } else {
145*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_RCVBUF
146*5d5fbe79SDavid van Moolenbroek         SYS_ARCH_INC(conn->recv_avail, len);
147*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_RCVBUF */
148*5d5fbe79SDavid van Moolenbroek         /* Register event with callback */
149*5d5fbe79SDavid van Moolenbroek         API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
150*5d5fbe79SDavid van Moolenbroek       }
151*5d5fbe79SDavid van Moolenbroek     }
152*5d5fbe79SDavid van Moolenbroek   }
153*5d5fbe79SDavid van Moolenbroek 
154*5d5fbe79SDavid van Moolenbroek   return 0; /* do not eat the packet */
155*5d5fbe79SDavid van Moolenbroek }
156*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_RAW*/
157*5d5fbe79SDavid van Moolenbroek 
158*5d5fbe79SDavid van Moolenbroek #if LWIP_UDP
159*5d5fbe79SDavid van Moolenbroek /**
160*5d5fbe79SDavid van Moolenbroek  * Receive callback function for UDP netconns.
161*5d5fbe79SDavid van Moolenbroek  * Posts the packet to conn->recvmbox or deletes it on memory error.
162*5d5fbe79SDavid van Moolenbroek  *
163*5d5fbe79SDavid van Moolenbroek  * @see udp.h (struct udp_pcb.recv) for parameters
164*5d5fbe79SDavid van Moolenbroek  */
165*5d5fbe79SDavid van Moolenbroek static void
recv_udp(void * arg,struct udp_pcb * pcb,struct pbuf * p,const ip_addr_t * addr,u16_t port)166*5d5fbe79SDavid van Moolenbroek recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
167*5d5fbe79SDavid van Moolenbroek    const ip_addr_t *addr, u16_t port)
168*5d5fbe79SDavid van Moolenbroek {
169*5d5fbe79SDavid van Moolenbroek   struct netbuf *buf;
170*5d5fbe79SDavid van Moolenbroek   struct netconn *conn;
171*5d5fbe79SDavid van Moolenbroek   u16_t len;
172*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_RCVBUF
173*5d5fbe79SDavid van Moolenbroek   int recv_avail;
174*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_RCVBUF */
175*5d5fbe79SDavid van Moolenbroek 
176*5d5fbe79SDavid van Moolenbroek   LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
177*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
178*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
179*5d5fbe79SDavid van Moolenbroek   conn = (struct netconn *)arg;
180*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
181*5d5fbe79SDavid van Moolenbroek 
182*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_RCVBUF
183*5d5fbe79SDavid van Moolenbroek   SYS_ARCH_GET(conn->recv_avail, recv_avail);
184*5d5fbe79SDavid van Moolenbroek   if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) ||
185*5d5fbe79SDavid van Moolenbroek       ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
186*5d5fbe79SDavid van Moolenbroek #else  /* LWIP_SO_RCVBUF */
187*5d5fbe79SDavid van Moolenbroek   if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) {
188*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_RCVBUF */
189*5d5fbe79SDavid van Moolenbroek     pbuf_free(p);
190*5d5fbe79SDavid van Moolenbroek     return;
191*5d5fbe79SDavid van Moolenbroek   }
192*5d5fbe79SDavid van Moolenbroek 
193*5d5fbe79SDavid van Moolenbroek   buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
194*5d5fbe79SDavid van Moolenbroek   if (buf == NULL) {
195*5d5fbe79SDavid van Moolenbroek     pbuf_free(p);
196*5d5fbe79SDavid van Moolenbroek     return;
197*5d5fbe79SDavid van Moolenbroek   } else {
198*5d5fbe79SDavid van Moolenbroek     buf->p = p;
199*5d5fbe79SDavid van Moolenbroek     buf->ptr = p;
200*5d5fbe79SDavid van Moolenbroek     ip_addr_set(&buf->addr, addr);
201*5d5fbe79SDavid van Moolenbroek     buf->port = port;
202*5d5fbe79SDavid van Moolenbroek #if LWIP_NETBUF_RECVINFO
203*5d5fbe79SDavid van Moolenbroek     {
204*5d5fbe79SDavid van Moolenbroek       /* get the UDP header - always in the first pbuf, ensured by udp_input */
205*5d5fbe79SDavid van Moolenbroek       const struct udp_hdr* udphdr = (const struct udp_hdr*)ip_next_header_ptr();
206*5d5fbe79SDavid van Moolenbroek #if LWIP_CHECKSUM_ON_COPY
207*5d5fbe79SDavid van Moolenbroek       buf->flags = NETBUF_FLAG_DESTADDR;
208*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_CHECKSUM_ON_COPY */
209*5d5fbe79SDavid van Moolenbroek       ip_addr_set(&buf->toaddr, ip_current_dest_addr());
210*5d5fbe79SDavid van Moolenbroek       buf->toport_chksum = udphdr->dest;
211*5d5fbe79SDavid van Moolenbroek     }
212*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_NETBUF_RECVINFO */
213*5d5fbe79SDavid van Moolenbroek   }
214*5d5fbe79SDavid van Moolenbroek 
215*5d5fbe79SDavid van Moolenbroek   len = p->tot_len;
216*5d5fbe79SDavid van Moolenbroek   if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
217*5d5fbe79SDavid van Moolenbroek     netbuf_delete(buf);
218*5d5fbe79SDavid van Moolenbroek     return;
219*5d5fbe79SDavid van Moolenbroek   } else {
220*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_RCVBUF
221*5d5fbe79SDavid van Moolenbroek     SYS_ARCH_INC(conn->recv_avail, len);
222*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_RCVBUF */
223*5d5fbe79SDavid van Moolenbroek     /* Register event with callback */
224*5d5fbe79SDavid van Moolenbroek     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
225*5d5fbe79SDavid van Moolenbroek   }
226*5d5fbe79SDavid van Moolenbroek }
227*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_UDP */
228*5d5fbe79SDavid van Moolenbroek 
229*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
230*5d5fbe79SDavid van Moolenbroek /**
231*5d5fbe79SDavid van Moolenbroek  * Receive callback function for TCP netconns.
232*5d5fbe79SDavid van Moolenbroek  * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
233*5d5fbe79SDavid van Moolenbroek  *
234*5d5fbe79SDavid van Moolenbroek  * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
235*5d5fbe79SDavid van Moolenbroek  */
236*5d5fbe79SDavid van Moolenbroek static err_t
237*5d5fbe79SDavid van Moolenbroek recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
238*5d5fbe79SDavid van Moolenbroek {
239*5d5fbe79SDavid van Moolenbroek   struct netconn *conn;
240*5d5fbe79SDavid van Moolenbroek   u16_t len;
241*5d5fbe79SDavid van Moolenbroek 
242*5d5fbe79SDavid van Moolenbroek   LWIP_UNUSED_ARG(pcb);
243*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
244*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
245*5d5fbe79SDavid van Moolenbroek   conn = (struct netconn *)arg;
246*5d5fbe79SDavid van Moolenbroek 
247*5d5fbe79SDavid van Moolenbroek   if (conn == NULL) {
248*5d5fbe79SDavid van Moolenbroek     return ERR_VAL;
249*5d5fbe79SDavid van Moolenbroek   }
250*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
251*5d5fbe79SDavid van Moolenbroek 
252*5d5fbe79SDavid van Moolenbroek   if (!sys_mbox_valid(&conn->recvmbox)) {
253*5d5fbe79SDavid van Moolenbroek     /* recvmbox already deleted */
254*5d5fbe79SDavid van Moolenbroek     if (p != NULL) {
255*5d5fbe79SDavid van Moolenbroek       tcp_recved(pcb, p->tot_len);
256*5d5fbe79SDavid van Moolenbroek       pbuf_free(p);
257*5d5fbe79SDavid van Moolenbroek     }
258*5d5fbe79SDavid van Moolenbroek     return ERR_OK;
259*5d5fbe79SDavid van Moolenbroek   }
260*5d5fbe79SDavid van Moolenbroek   /* Unlike for UDP or RAW pcbs, don't check for available space
261*5d5fbe79SDavid van Moolenbroek      using recv_avail since that could break the connection
262*5d5fbe79SDavid van Moolenbroek      (data is already ACKed) */
263*5d5fbe79SDavid van Moolenbroek 
264*5d5fbe79SDavid van Moolenbroek   /* don't overwrite fatal errors! */
265*5d5fbe79SDavid van Moolenbroek   if (err != ERR_OK) {
266*5d5fbe79SDavid van Moolenbroek     NETCONN_SET_SAFE_ERR(conn, err);
267*5d5fbe79SDavid van Moolenbroek   }
268*5d5fbe79SDavid van Moolenbroek 
269*5d5fbe79SDavid van Moolenbroek   if (p != NULL) {
270*5d5fbe79SDavid van Moolenbroek     len = p->tot_len;
271*5d5fbe79SDavid van Moolenbroek   } else {
272*5d5fbe79SDavid van Moolenbroek     len = 0;
273*5d5fbe79SDavid van Moolenbroek   }
274*5d5fbe79SDavid van Moolenbroek 
275*5d5fbe79SDavid van Moolenbroek   if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) {
276*5d5fbe79SDavid van Moolenbroek     /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
277*5d5fbe79SDavid van Moolenbroek     return ERR_MEM;
278*5d5fbe79SDavid van Moolenbroek   } else {
279*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_RCVBUF
280*5d5fbe79SDavid van Moolenbroek     SYS_ARCH_INC(conn->recv_avail, len);
281*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_RCVBUF */
282*5d5fbe79SDavid van Moolenbroek     /* Register event with callback */
283*5d5fbe79SDavid van Moolenbroek     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
284*5d5fbe79SDavid van Moolenbroek   }
285*5d5fbe79SDavid van Moolenbroek 
286*5d5fbe79SDavid van Moolenbroek   return ERR_OK;
287*5d5fbe79SDavid van Moolenbroek }
288*5d5fbe79SDavid van Moolenbroek 
289*5d5fbe79SDavid van Moolenbroek /**
290*5d5fbe79SDavid van Moolenbroek  * Poll callback function for TCP netconns.
291*5d5fbe79SDavid van Moolenbroek  * Wakes up an application thread that waits for a connection to close
292*5d5fbe79SDavid van Moolenbroek  * or data to be sent. The application thread then takes the
293*5d5fbe79SDavid van Moolenbroek  * appropriate action to go on.
294*5d5fbe79SDavid van Moolenbroek  *
295*5d5fbe79SDavid van Moolenbroek  * Signals the conn->sem.
296*5d5fbe79SDavid van Moolenbroek  * netconn_close waits for conn->sem if closing failed.
297*5d5fbe79SDavid van Moolenbroek  *
298*5d5fbe79SDavid van Moolenbroek  * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
299*5d5fbe79SDavid van Moolenbroek  */
300*5d5fbe79SDavid van Moolenbroek static err_t
301*5d5fbe79SDavid van Moolenbroek poll_tcp(void *arg, struct tcp_pcb *pcb)
302*5d5fbe79SDavid van Moolenbroek {
303*5d5fbe79SDavid van Moolenbroek   struct netconn *conn = (struct netconn *)arg;
304*5d5fbe79SDavid van Moolenbroek 
305*5d5fbe79SDavid van Moolenbroek   LWIP_UNUSED_ARG(pcb);
306*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("conn != NULL", (conn != NULL));
307*5d5fbe79SDavid van Moolenbroek 
308*5d5fbe79SDavid van Moolenbroek   if (conn->state == NETCONN_WRITE) {
309*5d5fbe79SDavid van Moolenbroek     lwip_netconn_do_writemore(conn  WRITE_DELAYED);
310*5d5fbe79SDavid van Moolenbroek   } else if (conn->state == NETCONN_CLOSE) {
311*5d5fbe79SDavid van Moolenbroek #if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER
312*5d5fbe79SDavid van Moolenbroek     if (conn->current_msg && conn->current_msg->msg.sd.polls_left) {
313*5d5fbe79SDavid van Moolenbroek       conn->current_msg->msg.sd.polls_left--;
314*5d5fbe79SDavid van Moolenbroek     }
315*5d5fbe79SDavid van Moolenbroek #endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */
316*5d5fbe79SDavid van Moolenbroek     lwip_netconn_do_close_internal(conn  WRITE_DELAYED);
317*5d5fbe79SDavid van Moolenbroek   }
318*5d5fbe79SDavid van Moolenbroek   /* @todo: implement connect timeout here? */
319*5d5fbe79SDavid van Moolenbroek 
320*5d5fbe79SDavid van Moolenbroek   /* Did a nonblocking write fail before? Then check available write-space. */
321*5d5fbe79SDavid van Moolenbroek   if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
322*5d5fbe79SDavid van Moolenbroek     /* If the queued byte- or pbuf-count drops below the configured low-water limit,
323*5d5fbe79SDavid van Moolenbroek        let select mark this pcb as writable again. */
324*5d5fbe79SDavid van Moolenbroek     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
325*5d5fbe79SDavid van Moolenbroek       (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
326*5d5fbe79SDavid van Moolenbroek       conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
327*5d5fbe79SDavid van Moolenbroek       API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
328*5d5fbe79SDavid van Moolenbroek     }
329*5d5fbe79SDavid van Moolenbroek   }
330*5d5fbe79SDavid van Moolenbroek 
331*5d5fbe79SDavid van Moolenbroek   return ERR_OK;
332*5d5fbe79SDavid van Moolenbroek }
333*5d5fbe79SDavid van Moolenbroek 
334*5d5fbe79SDavid van Moolenbroek /**
335*5d5fbe79SDavid van Moolenbroek  * Sent callback function for TCP netconns.
336*5d5fbe79SDavid van Moolenbroek  * Signals the conn->sem and calls API_EVENT.
337*5d5fbe79SDavid van Moolenbroek  * netconn_write waits for conn->sem if send buffer is low.
338*5d5fbe79SDavid van Moolenbroek  *
339*5d5fbe79SDavid van Moolenbroek  * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
340*5d5fbe79SDavid van Moolenbroek  */
341*5d5fbe79SDavid van Moolenbroek static err_t
342*5d5fbe79SDavid van Moolenbroek sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
343*5d5fbe79SDavid van Moolenbroek {
344*5d5fbe79SDavid van Moolenbroek   struct netconn *conn = (struct netconn *)arg;
345*5d5fbe79SDavid van Moolenbroek 
346*5d5fbe79SDavid van Moolenbroek   LWIP_UNUSED_ARG(pcb);
347*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("conn != NULL", (conn != NULL));
348*5d5fbe79SDavid van Moolenbroek 
349*5d5fbe79SDavid van Moolenbroek   if (conn) {
350*5d5fbe79SDavid van Moolenbroek     if (conn->state == NETCONN_WRITE) {
351*5d5fbe79SDavid van Moolenbroek       lwip_netconn_do_writemore(conn  WRITE_DELAYED);
352*5d5fbe79SDavid van Moolenbroek     } else if (conn->state == NETCONN_CLOSE) {
353*5d5fbe79SDavid van Moolenbroek       lwip_netconn_do_close_internal(conn  WRITE_DELAYED);
354*5d5fbe79SDavid van Moolenbroek     }
355*5d5fbe79SDavid van Moolenbroek 
356*5d5fbe79SDavid van Moolenbroek     /* If the queued byte- or pbuf-count drops below the configured low-water limit,
357*5d5fbe79SDavid van Moolenbroek        let select mark this pcb as writable again. */
358*5d5fbe79SDavid van Moolenbroek     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
359*5d5fbe79SDavid van Moolenbroek       (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
360*5d5fbe79SDavid van Moolenbroek       conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
361*5d5fbe79SDavid van Moolenbroek       API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
362*5d5fbe79SDavid van Moolenbroek     }
363*5d5fbe79SDavid van Moolenbroek   }
364*5d5fbe79SDavid van Moolenbroek 
365*5d5fbe79SDavid van Moolenbroek   return ERR_OK;
366*5d5fbe79SDavid van Moolenbroek }
367*5d5fbe79SDavid van Moolenbroek 
368*5d5fbe79SDavid van Moolenbroek /**
369*5d5fbe79SDavid van Moolenbroek  * Error callback function for TCP netconns.
370*5d5fbe79SDavid van Moolenbroek  * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
371*5d5fbe79SDavid van Moolenbroek  * The application thread has then to decide what to do.
372*5d5fbe79SDavid van Moolenbroek  *
373*5d5fbe79SDavid van Moolenbroek  * @see tcp.h (struct tcp_pcb.err) for parameters
374*5d5fbe79SDavid van Moolenbroek  */
375*5d5fbe79SDavid van Moolenbroek static void
376*5d5fbe79SDavid van Moolenbroek err_tcp(void *arg, err_t err)
377*5d5fbe79SDavid van Moolenbroek {
378*5d5fbe79SDavid van Moolenbroek   struct netconn *conn;
379*5d5fbe79SDavid van Moolenbroek   enum netconn_state old_state;
380*5d5fbe79SDavid van Moolenbroek 
381*5d5fbe79SDavid van Moolenbroek   conn = (struct netconn *)arg;
382*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("conn != NULL", (conn != NULL));
383*5d5fbe79SDavid van Moolenbroek 
384*5d5fbe79SDavid van Moolenbroek   conn->pcb.tcp = NULL;
385*5d5fbe79SDavid van Moolenbroek 
386*5d5fbe79SDavid van Moolenbroek   /* reset conn->state now before waking up other threads */
387*5d5fbe79SDavid van Moolenbroek   old_state = conn->state;
388*5d5fbe79SDavid van Moolenbroek   conn->state = NETCONN_NONE;
389*5d5fbe79SDavid van Moolenbroek 
390*5d5fbe79SDavid van Moolenbroek   if (old_state == NETCONN_CLOSE) {
391*5d5fbe79SDavid van Moolenbroek     /* RST during close: let close return success & dealloc the netconn */
392*5d5fbe79SDavid van Moolenbroek     err = ERR_OK;
393*5d5fbe79SDavid van Moolenbroek     NETCONN_SET_SAFE_ERR(conn, ERR_OK);
394*5d5fbe79SDavid van Moolenbroek   } else {
395*5d5fbe79SDavid van Moolenbroek     /* no check since this is always fatal! */
396*5d5fbe79SDavid van Moolenbroek     SYS_ARCH_SET(conn->last_err, err);
397*5d5fbe79SDavid van Moolenbroek   }
398*5d5fbe79SDavid van Moolenbroek 
399*5d5fbe79SDavid van Moolenbroek   /* @todo: the type of NETCONN_EVT created should depend on 'old_state' */
400*5d5fbe79SDavid van Moolenbroek 
401*5d5fbe79SDavid van Moolenbroek   /* Notify the user layer about a connection error. Used to signal select. */
402*5d5fbe79SDavid van Moolenbroek   API_EVENT(conn, NETCONN_EVT_ERROR, 0);
403*5d5fbe79SDavid van Moolenbroek   /* Try to release selects pending on 'read' or 'write', too.
404*5d5fbe79SDavid van Moolenbroek      They will get an error if they actually try to read or write. */
405*5d5fbe79SDavid van Moolenbroek   API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
406*5d5fbe79SDavid van Moolenbroek   API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
407*5d5fbe79SDavid van Moolenbroek 
408*5d5fbe79SDavid van Moolenbroek   /* pass NULL-message to recvmbox to wake up pending recv */
409*5d5fbe79SDavid van Moolenbroek   if (sys_mbox_valid(&conn->recvmbox)) {
410*5d5fbe79SDavid van Moolenbroek     /* use trypost to prevent deadlock */
411*5d5fbe79SDavid van Moolenbroek     sys_mbox_trypost(&conn->recvmbox, NULL);
412*5d5fbe79SDavid van Moolenbroek   }
413*5d5fbe79SDavid van Moolenbroek   /* pass NULL-message to acceptmbox to wake up pending accept */
414*5d5fbe79SDavid van Moolenbroek   if (sys_mbox_valid(&conn->acceptmbox)) {
415*5d5fbe79SDavid van Moolenbroek     /* use trypost to preven deadlock */
416*5d5fbe79SDavid van Moolenbroek     sys_mbox_trypost(&conn->acceptmbox, NULL);
417*5d5fbe79SDavid van Moolenbroek   }
418*5d5fbe79SDavid van Moolenbroek 
419*5d5fbe79SDavid van Moolenbroek   if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
420*5d5fbe79SDavid van Moolenbroek       (old_state == NETCONN_CONNECT)) {
421*5d5fbe79SDavid van Moolenbroek     /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary
422*5d5fbe79SDavid van Moolenbroek        since the pcb has already been deleted! */
423*5d5fbe79SDavid van Moolenbroek     int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
424*5d5fbe79SDavid van Moolenbroek     SET_NONBLOCKING_CONNECT(conn, 0);
425*5d5fbe79SDavid van Moolenbroek 
426*5d5fbe79SDavid van Moolenbroek     if (!was_nonblocking_connect) {
427*5d5fbe79SDavid van Moolenbroek       sys_sem_t* op_completed_sem;
428*5d5fbe79SDavid van Moolenbroek       /* set error return code */
429*5d5fbe79SDavid van Moolenbroek       LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
430*5d5fbe79SDavid van Moolenbroek       conn->current_msg->err = err;
431*5d5fbe79SDavid van Moolenbroek       op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
432*5d5fbe79SDavid van Moolenbroek       LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem));
433*5d5fbe79SDavid van Moolenbroek       conn->current_msg = NULL;
434*5d5fbe79SDavid van Moolenbroek       /* wake up the waiting task */
435*5d5fbe79SDavid van Moolenbroek       NETCONN_SET_SAFE_ERR(conn, err);
436*5d5fbe79SDavid van Moolenbroek       sys_sem_signal(op_completed_sem);
437*5d5fbe79SDavid van Moolenbroek     }
438*5d5fbe79SDavid van Moolenbroek   } else {
439*5d5fbe79SDavid van Moolenbroek     LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
440*5d5fbe79SDavid van Moolenbroek   }
441*5d5fbe79SDavid van Moolenbroek }
442*5d5fbe79SDavid van Moolenbroek 
443*5d5fbe79SDavid van Moolenbroek /**
444*5d5fbe79SDavid van Moolenbroek  * Setup a tcp_pcb with the correct callback function pointers
445*5d5fbe79SDavid van Moolenbroek  * and their arguments.
446*5d5fbe79SDavid van Moolenbroek  *
447*5d5fbe79SDavid van Moolenbroek  * @param conn the TCP netconn to setup
448*5d5fbe79SDavid van Moolenbroek  */
449*5d5fbe79SDavid van Moolenbroek static void
450*5d5fbe79SDavid van Moolenbroek setup_tcp(struct netconn *conn)
451*5d5fbe79SDavid van Moolenbroek {
452*5d5fbe79SDavid van Moolenbroek   struct tcp_pcb *pcb;
453*5d5fbe79SDavid van Moolenbroek 
454*5d5fbe79SDavid van Moolenbroek   pcb = conn->pcb.tcp;
455*5d5fbe79SDavid van Moolenbroek   tcp_arg(pcb, conn);
456*5d5fbe79SDavid van Moolenbroek   tcp_recv(pcb, recv_tcp);
457*5d5fbe79SDavid van Moolenbroek   tcp_sent(pcb, sent_tcp);
458*5d5fbe79SDavid van Moolenbroek   tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL);
459*5d5fbe79SDavid van Moolenbroek   tcp_err(pcb, err_tcp);
460*5d5fbe79SDavid van Moolenbroek }
461*5d5fbe79SDavid van Moolenbroek 
462*5d5fbe79SDavid van Moolenbroek /**
463*5d5fbe79SDavid van Moolenbroek  * Accept callback function for TCP netconns.
464*5d5fbe79SDavid van Moolenbroek  * Allocates a new netconn and posts that to conn->acceptmbox.
465*5d5fbe79SDavid van Moolenbroek  *
466*5d5fbe79SDavid van Moolenbroek  * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
467*5d5fbe79SDavid van Moolenbroek  */
468*5d5fbe79SDavid van Moolenbroek static err_t
469*5d5fbe79SDavid van Moolenbroek accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
470*5d5fbe79SDavid van Moolenbroek {
471*5d5fbe79SDavid van Moolenbroek   struct netconn *newconn;
472*5d5fbe79SDavid van Moolenbroek   struct netconn *conn = (struct netconn *)arg;
473*5d5fbe79SDavid van Moolenbroek 
474*5d5fbe79SDavid van Moolenbroek   LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state)));
475*5d5fbe79SDavid van Moolenbroek 
476*5d5fbe79SDavid van Moolenbroek   if (conn == NULL) {
477*5d5fbe79SDavid van Moolenbroek     return ERR_VAL;
478*5d5fbe79SDavid van Moolenbroek   }
479*5d5fbe79SDavid van Moolenbroek   if (!sys_mbox_valid(&conn->acceptmbox)) {
480*5d5fbe79SDavid van Moolenbroek     LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
481*5d5fbe79SDavid van Moolenbroek     return ERR_VAL;
482*5d5fbe79SDavid van Moolenbroek   }
483*5d5fbe79SDavid van Moolenbroek 
484*5d5fbe79SDavid van Moolenbroek   if (newpcb == NULL) {
485*5d5fbe79SDavid van Moolenbroek     /* out-of-pcbs during connect: pass on this error to the application */
486*5d5fbe79SDavid van Moolenbroek     if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) {
487*5d5fbe79SDavid van Moolenbroek       /* Register event with callback */
488*5d5fbe79SDavid van Moolenbroek       API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
489*5d5fbe79SDavid van Moolenbroek     }
490*5d5fbe79SDavid van Moolenbroek     return ERR_VAL;
491*5d5fbe79SDavid van Moolenbroek   }
492*5d5fbe79SDavid van Moolenbroek 
493*5d5fbe79SDavid van Moolenbroek   /* We have to set the callback here even though
494*5d5fbe79SDavid van Moolenbroek    * the new socket is unknown. newconn->socket is marked as -1. */
495*5d5fbe79SDavid van Moolenbroek   newconn = netconn_alloc(conn->type, conn->callback);
496*5d5fbe79SDavid van Moolenbroek   if (newconn == NULL) {
497*5d5fbe79SDavid van Moolenbroek     /* outof netconns: pass on this error to the application */
498*5d5fbe79SDavid van Moolenbroek     if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) {
499*5d5fbe79SDavid van Moolenbroek       /* Register event with callback */
500*5d5fbe79SDavid van Moolenbroek       API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
501*5d5fbe79SDavid van Moolenbroek     }
502*5d5fbe79SDavid van Moolenbroek     return ERR_MEM;
503*5d5fbe79SDavid van Moolenbroek   }
504*5d5fbe79SDavid van Moolenbroek   newconn->pcb.tcp = newpcb;
505*5d5fbe79SDavid van Moolenbroek   setup_tcp(newconn);
506*5d5fbe79SDavid van Moolenbroek   /* no protection: when creating the pcb, the netconn is not yet known
507*5d5fbe79SDavid van Moolenbroek      to the application thread */
508*5d5fbe79SDavid van Moolenbroek   newconn->last_err = err;
509*5d5fbe79SDavid van Moolenbroek 
510*5d5fbe79SDavid van Moolenbroek   /* handle backlog counter */
511*5d5fbe79SDavid van Moolenbroek   tcp_backlog_delayed(newpcb);
512*5d5fbe79SDavid van Moolenbroek 
513*5d5fbe79SDavid van Moolenbroek   if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
514*5d5fbe79SDavid van Moolenbroek     /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
515*5d5fbe79SDavid van Moolenbroek        so do nothing here! */
516*5d5fbe79SDavid van Moolenbroek     /* remove all references to this netconn from the pcb */
517*5d5fbe79SDavid van Moolenbroek     struct tcp_pcb* pcb = newconn->pcb.tcp;
518*5d5fbe79SDavid van Moolenbroek     tcp_arg(pcb, NULL);
519*5d5fbe79SDavid van Moolenbroek     tcp_recv(pcb, NULL);
520*5d5fbe79SDavid van Moolenbroek     tcp_sent(pcb, NULL);
521*5d5fbe79SDavid van Moolenbroek     tcp_poll(pcb, NULL, 0);
522*5d5fbe79SDavid van Moolenbroek     tcp_err(pcb, NULL);
523*5d5fbe79SDavid van Moolenbroek     /* remove reference from to the pcb from this netconn */
524*5d5fbe79SDavid van Moolenbroek     newconn->pcb.tcp = NULL;
525*5d5fbe79SDavid van Moolenbroek     /* no need to drain since we know the recvmbox is empty. */
526*5d5fbe79SDavid van Moolenbroek     sys_mbox_free(&newconn->recvmbox);
527*5d5fbe79SDavid van Moolenbroek     sys_mbox_set_invalid(&newconn->recvmbox);
528*5d5fbe79SDavid van Moolenbroek     netconn_free(newconn);
529*5d5fbe79SDavid van Moolenbroek     return ERR_MEM;
530*5d5fbe79SDavid van Moolenbroek   } else {
531*5d5fbe79SDavid van Moolenbroek     /* Register event with callback */
532*5d5fbe79SDavid van Moolenbroek     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
533*5d5fbe79SDavid van Moolenbroek   }
534*5d5fbe79SDavid van Moolenbroek 
535*5d5fbe79SDavid van Moolenbroek   return ERR_OK;
536*5d5fbe79SDavid van Moolenbroek }
537*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
538*5d5fbe79SDavid van Moolenbroek 
539*5d5fbe79SDavid van Moolenbroek /**
540*5d5fbe79SDavid van Moolenbroek  * Create a new pcb of a specific type.
541*5d5fbe79SDavid van Moolenbroek  * Called from lwip_netconn_do_newconn().
542*5d5fbe79SDavid van Moolenbroek  *
543*5d5fbe79SDavid van Moolenbroek  * @param msg the api_msg_msg describing the connection type
544*5d5fbe79SDavid van Moolenbroek  */
545*5d5fbe79SDavid van Moolenbroek static void
546*5d5fbe79SDavid van Moolenbroek pcb_new(struct api_msg *msg)
547*5d5fbe79SDavid van Moolenbroek {
548*5d5fbe79SDavid van Moolenbroek   enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4;
549*5d5fbe79SDavid van Moolenbroek 
550*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
551*5d5fbe79SDavid van Moolenbroek 
552*5d5fbe79SDavid van Moolenbroek #if LWIP_IPV6 && LWIP_IPV4
553*5d5fbe79SDavid van Moolenbroek   /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */
554*5d5fbe79SDavid van Moolenbroek   if(NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) {
555*5d5fbe79SDavid van Moolenbroek     iptype = IPADDR_TYPE_ANY;
556*5d5fbe79SDavid van Moolenbroek   }
557*5d5fbe79SDavid van Moolenbroek #endif
558*5d5fbe79SDavid van Moolenbroek 
559*5d5fbe79SDavid van Moolenbroek   /* Allocate a PCB for this connection */
560*5d5fbe79SDavid van Moolenbroek   switch(NETCONNTYPE_GROUP(msg->conn->type)) {
561*5d5fbe79SDavid van Moolenbroek #if LWIP_RAW
562*5d5fbe79SDavid van Moolenbroek   case NETCONN_RAW:
563*5d5fbe79SDavid van Moolenbroek     msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto);
564*5d5fbe79SDavid van Moolenbroek     if (msg->conn->pcb.raw != NULL) {
565*5d5fbe79SDavid van Moolenbroek #if LWIP_IPV6
566*5d5fbe79SDavid van Moolenbroek       /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */
567*5d5fbe79SDavid van Moolenbroek       if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) {
568*5d5fbe79SDavid van Moolenbroek         msg->conn->pcb.raw->chksum_reqd = 1;
569*5d5fbe79SDavid van Moolenbroek         msg->conn->pcb.raw->chksum_offset = 2;
570*5d5fbe79SDavid van Moolenbroek       }
571*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_IPV6 */
572*5d5fbe79SDavid van Moolenbroek       raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
573*5d5fbe79SDavid van Moolenbroek     }
574*5d5fbe79SDavid van Moolenbroek     break;
575*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_RAW */
576*5d5fbe79SDavid van Moolenbroek #if LWIP_UDP
577*5d5fbe79SDavid van Moolenbroek   case NETCONN_UDP:
578*5d5fbe79SDavid van Moolenbroek     msg->conn->pcb.udp = udp_new_ip_type(iptype);
579*5d5fbe79SDavid van Moolenbroek     if (msg->conn->pcb.udp != NULL) {
580*5d5fbe79SDavid van Moolenbroek #if LWIP_UDPLITE
581*5d5fbe79SDavid van Moolenbroek       if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
582*5d5fbe79SDavid van Moolenbroek         udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
583*5d5fbe79SDavid van Moolenbroek       }
584*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_UDPLITE */
585*5d5fbe79SDavid van Moolenbroek       if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) {
586*5d5fbe79SDavid van Moolenbroek         udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
587*5d5fbe79SDavid van Moolenbroek       }
588*5d5fbe79SDavid van Moolenbroek       udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
589*5d5fbe79SDavid van Moolenbroek     }
590*5d5fbe79SDavid van Moolenbroek     break;
591*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_UDP */
592*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
593*5d5fbe79SDavid van Moolenbroek   case NETCONN_TCP:
594*5d5fbe79SDavid van Moolenbroek     msg->conn->pcb.tcp = tcp_new_ip_type(iptype);
595*5d5fbe79SDavid van Moolenbroek     if (msg->conn->pcb.tcp != NULL) {
596*5d5fbe79SDavid van Moolenbroek       setup_tcp(msg->conn);
597*5d5fbe79SDavid van Moolenbroek     }
598*5d5fbe79SDavid van Moolenbroek     break;
599*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
600*5d5fbe79SDavid van Moolenbroek   default:
601*5d5fbe79SDavid van Moolenbroek     /* Unsupported netconn type, e.g. protocol disabled */
602*5d5fbe79SDavid van Moolenbroek     msg->err = ERR_VAL;
603*5d5fbe79SDavid van Moolenbroek     return;
604*5d5fbe79SDavid van Moolenbroek   }
605*5d5fbe79SDavid van Moolenbroek   if (msg->conn->pcb.ip == NULL) {
606*5d5fbe79SDavid van Moolenbroek     msg->err = ERR_MEM;
607*5d5fbe79SDavid van Moolenbroek   }
608*5d5fbe79SDavid van Moolenbroek }
609*5d5fbe79SDavid van Moolenbroek 
610*5d5fbe79SDavid van Moolenbroek /**
611*5d5fbe79SDavid van Moolenbroek  * Create a new pcb of a specific type inside a netconn.
612*5d5fbe79SDavid van Moolenbroek  * Called from netconn_new_with_proto_and_callback.
613*5d5fbe79SDavid van Moolenbroek  *
614*5d5fbe79SDavid van Moolenbroek  * @param m the api_msg_msg describing the connection type
615*5d5fbe79SDavid van Moolenbroek  */
616*5d5fbe79SDavid van Moolenbroek void
617*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_newconn(void *m)
618*5d5fbe79SDavid van Moolenbroek {
619*5d5fbe79SDavid van Moolenbroek   struct api_msg *msg = (struct api_msg*)m;
620*5d5fbe79SDavid van Moolenbroek 
621*5d5fbe79SDavid van Moolenbroek   msg->err = ERR_OK;
622*5d5fbe79SDavid van Moolenbroek   if (msg->conn->pcb.tcp == NULL) {
623*5d5fbe79SDavid van Moolenbroek     pcb_new(msg);
624*5d5fbe79SDavid van Moolenbroek   }
625*5d5fbe79SDavid van Moolenbroek   /* Else? This "new" connection already has a PCB allocated. */
626*5d5fbe79SDavid van Moolenbroek   /* Is this an error condition? Should it be deleted? */
627*5d5fbe79SDavid van Moolenbroek   /* We currently just are happy and return. */
628*5d5fbe79SDavid van Moolenbroek 
629*5d5fbe79SDavid van Moolenbroek   TCPIP_APIMSG_ACK(msg);
630*5d5fbe79SDavid van Moolenbroek }
631*5d5fbe79SDavid van Moolenbroek 
632*5d5fbe79SDavid van Moolenbroek /**
633*5d5fbe79SDavid van Moolenbroek  * Create a new netconn (of a specific type) that has a callback function.
634*5d5fbe79SDavid van Moolenbroek  * The corresponding pcb is NOT created!
635*5d5fbe79SDavid van Moolenbroek  *
636*5d5fbe79SDavid van Moolenbroek  * @param t the type of 'connection' to create (@see enum netconn_type)
637*5d5fbe79SDavid van Moolenbroek  * @param callback a function to call on status changes (RX available, TX'ed)
638*5d5fbe79SDavid van Moolenbroek  * @return a newly allocated struct netconn or
639*5d5fbe79SDavid van Moolenbroek  *         NULL on memory error
640*5d5fbe79SDavid van Moolenbroek  */
641*5d5fbe79SDavid van Moolenbroek struct netconn*
642*5d5fbe79SDavid van Moolenbroek netconn_alloc(enum netconn_type t, netconn_callback callback)
643*5d5fbe79SDavid van Moolenbroek {
644*5d5fbe79SDavid van Moolenbroek   struct netconn *conn;
645*5d5fbe79SDavid van Moolenbroek   int size;
646*5d5fbe79SDavid van Moolenbroek 
647*5d5fbe79SDavid van Moolenbroek   conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
648*5d5fbe79SDavid van Moolenbroek   if (conn == NULL) {
649*5d5fbe79SDavid van Moolenbroek     return NULL;
650*5d5fbe79SDavid van Moolenbroek   }
651*5d5fbe79SDavid van Moolenbroek 
652*5d5fbe79SDavid van Moolenbroek   conn->last_err = ERR_OK;
653*5d5fbe79SDavid van Moolenbroek   conn->type = t;
654*5d5fbe79SDavid van Moolenbroek   conn->pcb.tcp = NULL;
655*5d5fbe79SDavid van Moolenbroek 
656*5d5fbe79SDavid van Moolenbroek   /* If all sizes are the same, every compiler should optimize this switch to nothing */
657*5d5fbe79SDavid van Moolenbroek   switch(NETCONNTYPE_GROUP(t)) {
658*5d5fbe79SDavid van Moolenbroek #if LWIP_RAW
659*5d5fbe79SDavid van Moolenbroek   case NETCONN_RAW:
660*5d5fbe79SDavid van Moolenbroek     size = DEFAULT_RAW_RECVMBOX_SIZE;
661*5d5fbe79SDavid van Moolenbroek     break;
662*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_RAW */
663*5d5fbe79SDavid van Moolenbroek #if LWIP_UDP
664*5d5fbe79SDavid van Moolenbroek   case NETCONN_UDP:
665*5d5fbe79SDavid van Moolenbroek     size = DEFAULT_UDP_RECVMBOX_SIZE;
666*5d5fbe79SDavid van Moolenbroek     break;
667*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_UDP */
668*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
669*5d5fbe79SDavid van Moolenbroek   case NETCONN_TCP:
670*5d5fbe79SDavid van Moolenbroek     size = DEFAULT_TCP_RECVMBOX_SIZE;
671*5d5fbe79SDavid van Moolenbroek     break;
672*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
673*5d5fbe79SDavid van Moolenbroek   default:
674*5d5fbe79SDavid van Moolenbroek     LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
675*5d5fbe79SDavid van Moolenbroek     goto free_and_return;
676*5d5fbe79SDavid van Moolenbroek   }
677*5d5fbe79SDavid van Moolenbroek 
678*5d5fbe79SDavid van Moolenbroek   if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
679*5d5fbe79SDavid van Moolenbroek     goto free_and_return;
680*5d5fbe79SDavid van Moolenbroek   }
681*5d5fbe79SDavid van Moolenbroek #if !LWIP_NETCONN_SEM_PER_THREAD
682*5d5fbe79SDavid van Moolenbroek   if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
683*5d5fbe79SDavid van Moolenbroek     sys_mbox_free(&conn->recvmbox);
684*5d5fbe79SDavid van Moolenbroek     goto free_and_return;
685*5d5fbe79SDavid van Moolenbroek   }
686*5d5fbe79SDavid van Moolenbroek #endif
687*5d5fbe79SDavid van Moolenbroek 
688*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
689*5d5fbe79SDavid van Moolenbroek   sys_mbox_set_invalid(&conn->acceptmbox);
690*5d5fbe79SDavid van Moolenbroek #endif
691*5d5fbe79SDavid van Moolenbroek   conn->state        = NETCONN_NONE;
692*5d5fbe79SDavid van Moolenbroek #if LWIP_SOCKET
693*5d5fbe79SDavid van Moolenbroek   /* initialize socket to -1 since 0 is a valid socket */
694*5d5fbe79SDavid van Moolenbroek   conn->socket       = -1;
695*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SOCKET */
696*5d5fbe79SDavid van Moolenbroek   conn->callback     = callback;
697*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
698*5d5fbe79SDavid van Moolenbroek   conn->current_msg  = NULL;
699*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
700*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_SNDTIMEO
701*5d5fbe79SDavid van Moolenbroek   conn->send_timeout = 0;
702*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_SNDTIMEO */
703*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_RCVTIMEO
704*5d5fbe79SDavid van Moolenbroek   conn->recv_timeout = 0;
705*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_RCVTIMEO */
706*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_RCVBUF
707*5d5fbe79SDavid van Moolenbroek   conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
708*5d5fbe79SDavid van Moolenbroek   conn->recv_avail   = 0;
709*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_RCVBUF */
710*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_LINGER
711*5d5fbe79SDavid van Moolenbroek   conn->linger = -1;
712*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_LINGER */
713*5d5fbe79SDavid van Moolenbroek   conn->flags = 0;
714*5d5fbe79SDavid van Moolenbroek   return conn;
715*5d5fbe79SDavid van Moolenbroek free_and_return:
716*5d5fbe79SDavid van Moolenbroek   memp_free(MEMP_NETCONN, conn);
717*5d5fbe79SDavid van Moolenbroek   return NULL;
718*5d5fbe79SDavid van Moolenbroek }
719*5d5fbe79SDavid van Moolenbroek 
720*5d5fbe79SDavid van Moolenbroek /**
721*5d5fbe79SDavid van Moolenbroek  * Delete a netconn and all its resources.
722*5d5fbe79SDavid van Moolenbroek  * The pcb is NOT freed (since we might not be in the right thread context do this).
723*5d5fbe79SDavid van Moolenbroek  *
724*5d5fbe79SDavid van Moolenbroek  * @param conn the netconn to free
725*5d5fbe79SDavid van Moolenbroek  */
726*5d5fbe79SDavid van Moolenbroek void
727*5d5fbe79SDavid van Moolenbroek netconn_free(struct netconn *conn)
728*5d5fbe79SDavid van Moolenbroek {
729*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
730*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("recvmbox must be deallocated before calling this function",
731*5d5fbe79SDavid van Moolenbroek     !sys_mbox_valid(&conn->recvmbox));
732*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
733*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
734*5d5fbe79SDavid van Moolenbroek     !sys_mbox_valid(&conn->acceptmbox));
735*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
736*5d5fbe79SDavid van Moolenbroek 
737*5d5fbe79SDavid van Moolenbroek #if !LWIP_NETCONN_SEM_PER_THREAD
738*5d5fbe79SDavid van Moolenbroek   sys_sem_free(&conn->op_completed);
739*5d5fbe79SDavid van Moolenbroek   sys_sem_set_invalid(&conn->op_completed);
740*5d5fbe79SDavid van Moolenbroek #endif
741*5d5fbe79SDavid van Moolenbroek 
742*5d5fbe79SDavid van Moolenbroek   memp_free(MEMP_NETCONN, conn);
743*5d5fbe79SDavid van Moolenbroek }
744*5d5fbe79SDavid van Moolenbroek 
745*5d5fbe79SDavid van Moolenbroek /**
746*5d5fbe79SDavid van Moolenbroek  * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
747*5d5fbe79SDavid van Moolenbroek  * these mboxes
748*5d5fbe79SDavid van Moolenbroek  *
749*5d5fbe79SDavid van Moolenbroek  * @param conn the netconn to free
750*5d5fbe79SDavid van Moolenbroek  * @bytes_drained bytes drained from recvmbox
751*5d5fbe79SDavid van Moolenbroek  * @accepts_drained pending connections drained from acceptmbox
752*5d5fbe79SDavid van Moolenbroek  */
753*5d5fbe79SDavid van Moolenbroek static void
754*5d5fbe79SDavid van Moolenbroek netconn_drain(struct netconn *conn)
755*5d5fbe79SDavid van Moolenbroek {
756*5d5fbe79SDavid van Moolenbroek   void *mem;
757*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
758*5d5fbe79SDavid van Moolenbroek   struct pbuf *p;
759*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
760*5d5fbe79SDavid van Moolenbroek 
761*5d5fbe79SDavid van Moolenbroek   /* This runs in tcpip_thread, so we don't need to lock against rx packets */
762*5d5fbe79SDavid van Moolenbroek 
763*5d5fbe79SDavid van Moolenbroek   /* Delete and drain the recvmbox. */
764*5d5fbe79SDavid van Moolenbroek   if (sys_mbox_valid(&conn->recvmbox)) {
765*5d5fbe79SDavid van Moolenbroek     while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
766*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
767*5d5fbe79SDavid van Moolenbroek       if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
768*5d5fbe79SDavid van Moolenbroek         if (mem != NULL) {
769*5d5fbe79SDavid van Moolenbroek           p = (struct pbuf*)mem;
770*5d5fbe79SDavid van Moolenbroek           /* pcb might be set to NULL already by err_tcp() */
771*5d5fbe79SDavid van Moolenbroek           if (conn->pcb.tcp != NULL) {
772*5d5fbe79SDavid van Moolenbroek             tcp_recved(conn->pcb.tcp, p->tot_len);
773*5d5fbe79SDavid van Moolenbroek           }
774*5d5fbe79SDavid van Moolenbroek           pbuf_free(p);
775*5d5fbe79SDavid van Moolenbroek         }
776*5d5fbe79SDavid van Moolenbroek       } else
777*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
778*5d5fbe79SDavid van Moolenbroek       {
779*5d5fbe79SDavid van Moolenbroek         netbuf_delete((struct netbuf *)mem);
780*5d5fbe79SDavid van Moolenbroek       }
781*5d5fbe79SDavid van Moolenbroek     }
782*5d5fbe79SDavid van Moolenbroek     sys_mbox_free(&conn->recvmbox);
783*5d5fbe79SDavid van Moolenbroek     sys_mbox_set_invalid(&conn->recvmbox);
784*5d5fbe79SDavid van Moolenbroek   }
785*5d5fbe79SDavid van Moolenbroek 
786*5d5fbe79SDavid van Moolenbroek   /* Delete and drain the acceptmbox. */
787*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
788*5d5fbe79SDavid van Moolenbroek   if (sys_mbox_valid(&conn->acceptmbox)) {
789*5d5fbe79SDavid van Moolenbroek     while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
790*5d5fbe79SDavid van Moolenbroek       if (mem != &netconn_aborted) {
791*5d5fbe79SDavid van Moolenbroek         struct netconn *newconn = (struct netconn *)mem;
792*5d5fbe79SDavid van Moolenbroek         /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
793*5d5fbe79SDavid van Moolenbroek         /* pcb might be set to NULL already by err_tcp() */
794*5d5fbe79SDavid van Moolenbroek         /* drain recvmbox */
795*5d5fbe79SDavid van Moolenbroek         netconn_drain(newconn);
796*5d5fbe79SDavid van Moolenbroek         if (newconn->pcb.tcp != NULL) {
797*5d5fbe79SDavid van Moolenbroek           tcp_abort(newconn->pcb.tcp);
798*5d5fbe79SDavid van Moolenbroek           newconn->pcb.tcp = NULL;
799*5d5fbe79SDavid van Moolenbroek         }
800*5d5fbe79SDavid van Moolenbroek         netconn_free(newconn);
801*5d5fbe79SDavid van Moolenbroek       }
802*5d5fbe79SDavid van Moolenbroek     }
803*5d5fbe79SDavid van Moolenbroek     sys_mbox_free(&conn->acceptmbox);
804*5d5fbe79SDavid van Moolenbroek     sys_mbox_set_invalid(&conn->acceptmbox);
805*5d5fbe79SDavid van Moolenbroek   }
806*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
807*5d5fbe79SDavid van Moolenbroek }
808*5d5fbe79SDavid van Moolenbroek 
809*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
810*5d5fbe79SDavid van Moolenbroek /**
811*5d5fbe79SDavid van Moolenbroek  * Internal helper function to close a TCP netconn: since this sometimes
812*5d5fbe79SDavid van Moolenbroek  * doesn't work at the first attempt, this function is called from multiple
813*5d5fbe79SDavid van Moolenbroek  * places.
814*5d5fbe79SDavid van Moolenbroek  *
815*5d5fbe79SDavid van Moolenbroek  * @param conn the TCP netconn to close
816*5d5fbe79SDavid van Moolenbroek  */
817*5d5fbe79SDavid van Moolenbroek static err_t
818*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_close_internal(struct netconn *conn  WRITE_DELAYED_PARAM)
819*5d5fbe79SDavid van Moolenbroek {
820*5d5fbe79SDavid van Moolenbroek   err_t err;
821*5d5fbe79SDavid van Moolenbroek   u8_t shut, shut_rx, shut_tx, close;
822*5d5fbe79SDavid van Moolenbroek   u8_t close_finished = 0;
823*5d5fbe79SDavid van Moolenbroek   struct tcp_pcb* tpcb;
824*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_LINGER
825*5d5fbe79SDavid van Moolenbroek   u8_t linger_wait_required = 0;
826*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_LINGER */
827*5d5fbe79SDavid van Moolenbroek 
828*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("invalid conn", (conn != NULL));
829*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP));
830*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
831*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
832*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
833*5d5fbe79SDavid van Moolenbroek 
834*5d5fbe79SDavid van Moolenbroek   tpcb = conn->pcb.tcp;
835*5d5fbe79SDavid van Moolenbroek   shut = conn->current_msg->msg.sd.shut;
836*5d5fbe79SDavid van Moolenbroek   shut_rx = shut & NETCONN_SHUT_RD;
837*5d5fbe79SDavid van Moolenbroek   shut_tx = shut & NETCONN_SHUT_WR;
838*5d5fbe79SDavid van Moolenbroek   /* shutting down both ends is the same as closing
839*5d5fbe79SDavid van Moolenbroek      (also if RD or WR side was shut down before already) */
840*5d5fbe79SDavid van Moolenbroek   if (shut == NETCONN_SHUT_RDWR) {
841*5d5fbe79SDavid van Moolenbroek     close = 1;
842*5d5fbe79SDavid van Moolenbroek   } else if (shut_rx &&
843*5d5fbe79SDavid van Moolenbroek              ((tpcb->state == FIN_WAIT_1) ||
844*5d5fbe79SDavid van Moolenbroek               (tpcb->state == FIN_WAIT_2) ||
845*5d5fbe79SDavid van Moolenbroek               (tpcb->state == CLOSING))) {
846*5d5fbe79SDavid van Moolenbroek     close = 1;
847*5d5fbe79SDavid van Moolenbroek   } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) {
848*5d5fbe79SDavid van Moolenbroek     close = 1;
849*5d5fbe79SDavid van Moolenbroek   } else {
850*5d5fbe79SDavid van Moolenbroek     close = 0;
851*5d5fbe79SDavid van Moolenbroek   }
852*5d5fbe79SDavid van Moolenbroek 
853*5d5fbe79SDavid van Moolenbroek   /* Set back some callback pointers */
854*5d5fbe79SDavid van Moolenbroek   if (close) {
855*5d5fbe79SDavid van Moolenbroek     tcp_arg(tpcb, NULL);
856*5d5fbe79SDavid van Moolenbroek   }
857*5d5fbe79SDavid van Moolenbroek   if (tpcb->state == LISTEN) {
858*5d5fbe79SDavid van Moolenbroek     tcp_accept(tpcb, NULL);
859*5d5fbe79SDavid van Moolenbroek   } else {
860*5d5fbe79SDavid van Moolenbroek     /* some callbacks have to be reset if tcp_close is not successful */
861*5d5fbe79SDavid van Moolenbroek     if (shut_rx) {
862*5d5fbe79SDavid van Moolenbroek       tcp_recv(tpcb, NULL);
863*5d5fbe79SDavid van Moolenbroek       tcp_accept(tpcb, NULL);
864*5d5fbe79SDavid van Moolenbroek     }
865*5d5fbe79SDavid van Moolenbroek     if (shut_tx) {
866*5d5fbe79SDavid van Moolenbroek       tcp_sent(tpcb, NULL);
867*5d5fbe79SDavid van Moolenbroek     }
868*5d5fbe79SDavid van Moolenbroek     if (close) {
869*5d5fbe79SDavid van Moolenbroek       tcp_poll(tpcb, NULL, 0);
870*5d5fbe79SDavid van Moolenbroek       tcp_err(tpcb, NULL);
871*5d5fbe79SDavid van Moolenbroek     }
872*5d5fbe79SDavid van Moolenbroek   }
873*5d5fbe79SDavid van Moolenbroek   /* Try to close the connection */
874*5d5fbe79SDavid van Moolenbroek   if (close) {
875*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_LINGER
876*5d5fbe79SDavid van Moolenbroek     /* check linger possibilites before calling tcp_close */
877*5d5fbe79SDavid van Moolenbroek     err = ERR_OK;
878*5d5fbe79SDavid van Moolenbroek     /* linger enabled/required at all? (i.e. is there untransmitted data left?) */
879*5d5fbe79SDavid van Moolenbroek     if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) {
880*5d5fbe79SDavid van Moolenbroek       if ((conn->linger == 0)) {
881*5d5fbe79SDavid van Moolenbroek         /* data left but linger prevents waiting */
882*5d5fbe79SDavid van Moolenbroek         tcp_abort(tpcb);
883*5d5fbe79SDavid van Moolenbroek         tpcb = NULL;
884*5d5fbe79SDavid van Moolenbroek       } else if (conn->linger > 0) {
885*5d5fbe79SDavid van Moolenbroek         /* data left and linger says we should wait */
886*5d5fbe79SDavid van Moolenbroek         if (netconn_is_nonblocking(conn)) {
887*5d5fbe79SDavid van Moolenbroek           /* data left on a nonblocking netconn -> cannot linger */
888*5d5fbe79SDavid van Moolenbroek           err = ERR_WOULDBLOCK;
889*5d5fbe79SDavid van Moolenbroek         } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >=
890*5d5fbe79SDavid van Moolenbroek           (conn->linger * 1000)) {
891*5d5fbe79SDavid van Moolenbroek           /* data left but linger timeout has expired (this happens on further
892*5d5fbe79SDavid van Moolenbroek              calls to this function through poll_tcp */
893*5d5fbe79SDavid van Moolenbroek           tcp_abort(tpcb);
894*5d5fbe79SDavid van Moolenbroek           tpcb = NULL;
895*5d5fbe79SDavid van Moolenbroek         } else {
896*5d5fbe79SDavid van Moolenbroek           /* data left -> need to wait for ACK after successful close */
897*5d5fbe79SDavid van Moolenbroek           linger_wait_required = 1;
898*5d5fbe79SDavid van Moolenbroek         }
899*5d5fbe79SDavid van Moolenbroek       }
900*5d5fbe79SDavid van Moolenbroek     }
901*5d5fbe79SDavid van Moolenbroek     if ((err == ERR_OK) && (tpcb != NULL))
902*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_LINGER */
903*5d5fbe79SDavid van Moolenbroek     {
904*5d5fbe79SDavid van Moolenbroek       err = tcp_close(tpcb);
905*5d5fbe79SDavid van Moolenbroek     }
906*5d5fbe79SDavid van Moolenbroek   } else {
907*5d5fbe79SDavid van Moolenbroek     err = tcp_shutdown(tpcb, shut_rx, shut_tx);
908*5d5fbe79SDavid van Moolenbroek   }
909*5d5fbe79SDavid van Moolenbroek   if (err == ERR_OK) {
910*5d5fbe79SDavid van Moolenbroek     close_finished = 1;
911*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_LINGER
912*5d5fbe79SDavid van Moolenbroek     if (linger_wait_required) {
913*5d5fbe79SDavid van Moolenbroek       /* wait for ACK of all unsent/unacked data by just getting called again */
914*5d5fbe79SDavid van Moolenbroek       close_finished = 0;
915*5d5fbe79SDavid van Moolenbroek       err = ERR_INPROGRESS;
916*5d5fbe79SDavid van Moolenbroek     }
917*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_LINGER */
918*5d5fbe79SDavid van Moolenbroek   } else {
919*5d5fbe79SDavid van Moolenbroek     if (err == ERR_MEM) {
920*5d5fbe79SDavid van Moolenbroek       /* Closing failed because of memory shortage, try again later. Even for
921*5d5fbe79SDavid van Moolenbroek          nonblocking netconns, we have to wait since no standard socket application
922*5d5fbe79SDavid van Moolenbroek          is prepared for close failing because of resource shortage.
923*5d5fbe79SDavid van Moolenbroek          Check the timeout: this is kind of an lwip addition to the standard sockets:
924*5d5fbe79SDavid van Moolenbroek          we wait for some time when failing to allocate a segment for the FIN */
925*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
926*5d5fbe79SDavid van Moolenbroek       s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT;
927*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_SNDTIMEO
928*5d5fbe79SDavid van Moolenbroek       if (conn->send_timeout > 0) {
929*5d5fbe79SDavid van Moolenbroek         close_timeout = conn->send_timeout;
930*5d5fbe79SDavid van Moolenbroek       }
931*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_SNDTIMEO */
932*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_LINGER
933*5d5fbe79SDavid van Moolenbroek       if (conn->linger >= 0) {
934*5d5fbe79SDavid van Moolenbroek         /* use linger timeout (seconds) */
935*5d5fbe79SDavid van Moolenbroek         close_timeout = conn->linger * 1000U;
936*5d5fbe79SDavid van Moolenbroek       }
937*5d5fbe79SDavid van Moolenbroek #endif
938*5d5fbe79SDavid van Moolenbroek       if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
939*5d5fbe79SDavid van Moolenbroek #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
940*5d5fbe79SDavid van Moolenbroek       if (conn->current_msg->msg.sd.polls_left == 0) {
941*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
942*5d5fbe79SDavid van Moolenbroek         close_finished = 1;
943*5d5fbe79SDavid van Moolenbroek         if (close) {
944*5d5fbe79SDavid van Moolenbroek           /* in this case, we want to RST the connection */
945*5d5fbe79SDavid van Moolenbroek           tcp_abort(tpcb);
946*5d5fbe79SDavid van Moolenbroek           err = ERR_OK;
947*5d5fbe79SDavid van Moolenbroek         }
948*5d5fbe79SDavid van Moolenbroek       }
949*5d5fbe79SDavid van Moolenbroek     } else {
950*5d5fbe79SDavid van Moolenbroek       /* Closing failed for a non-memory error: give up */
951*5d5fbe79SDavid van Moolenbroek       close_finished = 1;
952*5d5fbe79SDavid van Moolenbroek     }
953*5d5fbe79SDavid van Moolenbroek   }
954*5d5fbe79SDavid van Moolenbroek   if (close_finished) {
955*5d5fbe79SDavid van Moolenbroek     /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */
956*5d5fbe79SDavid van Moolenbroek     sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
957*5d5fbe79SDavid van Moolenbroek     conn->current_msg->err = err;
958*5d5fbe79SDavid van Moolenbroek     conn->current_msg = NULL;
959*5d5fbe79SDavid van Moolenbroek     conn->state = NETCONN_NONE;
960*5d5fbe79SDavid van Moolenbroek     if (err == ERR_OK) {
961*5d5fbe79SDavid van Moolenbroek       if (close) {
962*5d5fbe79SDavid van Moolenbroek         /* Set back some callback pointers as conn is going away */
963*5d5fbe79SDavid van Moolenbroek         conn->pcb.tcp = NULL;
964*5d5fbe79SDavid van Moolenbroek         /* Trigger select() in socket layer. Make sure everybody notices activity
965*5d5fbe79SDavid van Moolenbroek          on the connection, error first! */
966*5d5fbe79SDavid van Moolenbroek         API_EVENT(conn, NETCONN_EVT_ERROR, 0);
967*5d5fbe79SDavid van Moolenbroek       }
968*5d5fbe79SDavid van Moolenbroek       if (shut_rx) {
969*5d5fbe79SDavid van Moolenbroek         API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
970*5d5fbe79SDavid van Moolenbroek       }
971*5d5fbe79SDavid van Moolenbroek       if (shut_tx) {
972*5d5fbe79SDavid van Moolenbroek         API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
973*5d5fbe79SDavid van Moolenbroek       }
974*5d5fbe79SDavid van Moolenbroek     }
975*5d5fbe79SDavid van Moolenbroek     NETCONN_SET_SAFE_ERR(conn, err);
976*5d5fbe79SDavid van Moolenbroek #if LWIP_TCPIP_CORE_LOCKING
977*5d5fbe79SDavid van Moolenbroek     if (delayed)
978*5d5fbe79SDavid van Moolenbroek #endif
979*5d5fbe79SDavid van Moolenbroek     {
980*5d5fbe79SDavid van Moolenbroek       /* wake up the application task */
981*5d5fbe79SDavid van Moolenbroek       sys_sem_signal(op_completed_sem);
982*5d5fbe79SDavid van Moolenbroek     }
983*5d5fbe79SDavid van Moolenbroek     return ERR_OK;
984*5d5fbe79SDavid van Moolenbroek   }
985*5d5fbe79SDavid van Moolenbroek   if (!close_finished) {
986*5d5fbe79SDavid van Moolenbroek     /* Closing failed and we want to wait: restore some of the callbacks */
987*5d5fbe79SDavid van Moolenbroek     /* Closing of listen pcb will never fail! */
988*5d5fbe79SDavid van Moolenbroek     LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN));
989*5d5fbe79SDavid van Moolenbroek     if (shut_tx) {
990*5d5fbe79SDavid van Moolenbroek       tcp_sent(tpcb, sent_tcp);
991*5d5fbe79SDavid van Moolenbroek     }
992*5d5fbe79SDavid van Moolenbroek     /* when waiting for close, set up poll interval to 500ms */
993*5d5fbe79SDavid van Moolenbroek     tcp_poll(tpcb, poll_tcp, 1);
994*5d5fbe79SDavid van Moolenbroek     tcp_err(tpcb, err_tcp);
995*5d5fbe79SDavid van Moolenbroek     tcp_arg(tpcb, conn);
996*5d5fbe79SDavid van Moolenbroek     /* don't restore recv callback: we don't want to receive any more data */
997*5d5fbe79SDavid van Moolenbroek   }
998*5d5fbe79SDavid van Moolenbroek   /* If closing didn't succeed, we get called again either
999*5d5fbe79SDavid van Moolenbroek      from poll_tcp or from sent_tcp */
1000*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("err != ERR_OK", err != ERR_OK);
1001*5d5fbe79SDavid van Moolenbroek   return err;
1002*5d5fbe79SDavid van Moolenbroek }
1003*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
1004*5d5fbe79SDavid van Moolenbroek 
1005*5d5fbe79SDavid van Moolenbroek /**
1006*5d5fbe79SDavid van Moolenbroek  * Delete the pcb inside a netconn.
1007*5d5fbe79SDavid van Moolenbroek  * Called from netconn_delete.
1008*5d5fbe79SDavid van Moolenbroek  *
1009*5d5fbe79SDavid van Moolenbroek  * @param m the api_msg_msg pointing to the connection
1010*5d5fbe79SDavid van Moolenbroek  */
1011*5d5fbe79SDavid van Moolenbroek void
1012*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_delconn(void *m)
1013*5d5fbe79SDavid van Moolenbroek {
1014*5d5fbe79SDavid van Moolenbroek   struct api_msg *msg = (struct api_msg*)m;
1015*5d5fbe79SDavid van Moolenbroek 
1016*5d5fbe79SDavid van Moolenbroek   enum netconn_state state = msg->conn->state;
1017*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */
1018*5d5fbe79SDavid van Moolenbroek     (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP));
1019*5d5fbe79SDavid van Moolenbroek #if LWIP_NETCONN_FULLDUPLEX
1020*5d5fbe79SDavid van Moolenbroek   /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */
1021*5d5fbe79SDavid van Moolenbroek   if (state != NETCONN_NONE) {
1022*5d5fbe79SDavid van Moolenbroek     if ((state == NETCONN_WRITE) ||
1023*5d5fbe79SDavid van Moolenbroek         ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1024*5d5fbe79SDavid van Moolenbroek       /* close requested, abort running write/connect */
1025*5d5fbe79SDavid van Moolenbroek       sys_sem_t* op_completed_sem;
1026*5d5fbe79SDavid van Moolenbroek       LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
1027*5d5fbe79SDavid van Moolenbroek       op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
1028*5d5fbe79SDavid van Moolenbroek       msg->conn->current_msg->err = ERR_CLSD;
1029*5d5fbe79SDavid van Moolenbroek       msg->conn->current_msg = NULL;
1030*5d5fbe79SDavid van Moolenbroek       msg->conn->state = NETCONN_NONE;
1031*5d5fbe79SDavid van Moolenbroek       NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD);
1032*5d5fbe79SDavid van Moolenbroek       sys_sem_signal(op_completed_sem);
1033*5d5fbe79SDavid van Moolenbroek     }
1034*5d5fbe79SDavid van Moolenbroek   }
1035*5d5fbe79SDavid van Moolenbroek #else /* LWIP_NETCONN_FULLDUPLEX */
1036*5d5fbe79SDavid van Moolenbroek   if (((state != NETCONN_NONE) &&
1037*5d5fbe79SDavid van Moolenbroek        (state != NETCONN_LISTEN) &&
1038*5d5fbe79SDavid van Moolenbroek        (state != NETCONN_CONNECT)) ||
1039*5d5fbe79SDavid van Moolenbroek       ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1040*5d5fbe79SDavid van Moolenbroek     /* This means either a blocking write or blocking connect is running
1041*5d5fbe79SDavid van Moolenbroek        (nonblocking write returns and sets state to NONE) */
1042*5d5fbe79SDavid van Moolenbroek     msg->err = ERR_INPROGRESS;
1043*5d5fbe79SDavid van Moolenbroek   } else
1044*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_NETCONN_FULLDUPLEX */
1045*5d5fbe79SDavid van Moolenbroek   {
1046*5d5fbe79SDavid van Moolenbroek     LWIP_ASSERT("blocking connect in progress",
1047*5d5fbe79SDavid van Moolenbroek       (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
1048*5d5fbe79SDavid van Moolenbroek     msg->err = ERR_OK;
1049*5d5fbe79SDavid van Moolenbroek     /* Drain and delete mboxes */
1050*5d5fbe79SDavid van Moolenbroek     netconn_drain(msg->conn);
1051*5d5fbe79SDavid van Moolenbroek 
1052*5d5fbe79SDavid van Moolenbroek     if (msg->conn->pcb.tcp != NULL) {
1053*5d5fbe79SDavid van Moolenbroek 
1054*5d5fbe79SDavid van Moolenbroek       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1055*5d5fbe79SDavid van Moolenbroek #if LWIP_RAW
1056*5d5fbe79SDavid van Moolenbroek       case NETCONN_RAW:
1057*5d5fbe79SDavid van Moolenbroek         raw_remove(msg->conn->pcb.raw);
1058*5d5fbe79SDavid van Moolenbroek         break;
1059*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_RAW */
1060*5d5fbe79SDavid van Moolenbroek #if LWIP_UDP
1061*5d5fbe79SDavid van Moolenbroek       case NETCONN_UDP:
1062*5d5fbe79SDavid van Moolenbroek         msg->conn->pcb.udp->recv_arg = NULL;
1063*5d5fbe79SDavid van Moolenbroek         udp_remove(msg->conn->pcb.udp);
1064*5d5fbe79SDavid van Moolenbroek         break;
1065*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_UDP */
1066*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
1067*5d5fbe79SDavid van Moolenbroek       case NETCONN_TCP:
1068*5d5fbe79SDavid van Moolenbroek         LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL);
1069*5d5fbe79SDavid van Moolenbroek         msg->conn->state = NETCONN_CLOSE;
1070*5d5fbe79SDavid van Moolenbroek         msg->msg.sd.shut = NETCONN_SHUT_RDWR;
1071*5d5fbe79SDavid van Moolenbroek         msg->conn->current_msg = msg;
1072*5d5fbe79SDavid van Moolenbroek #if LWIP_TCPIP_CORE_LOCKING
1073*5d5fbe79SDavid van Moolenbroek         if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
1074*5d5fbe79SDavid van Moolenbroek           LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
1075*5d5fbe79SDavid van Moolenbroek           UNLOCK_TCPIP_CORE();
1076*5d5fbe79SDavid van Moolenbroek           sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1077*5d5fbe79SDavid van Moolenbroek           LOCK_TCPIP_CORE();
1078*5d5fbe79SDavid van Moolenbroek           LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1079*5d5fbe79SDavid van Moolenbroek         }
1080*5d5fbe79SDavid van Moolenbroek #else /* LWIP_TCPIP_CORE_LOCKING */
1081*5d5fbe79SDavid van Moolenbroek         lwip_netconn_do_close_internal(msg->conn);
1082*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCPIP_CORE_LOCKING */
1083*5d5fbe79SDavid van Moolenbroek         /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing
1084*5d5fbe79SDavid van Moolenbroek            the application thread, so we can return at this point! */
1085*5d5fbe79SDavid van Moolenbroek         return;
1086*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
1087*5d5fbe79SDavid van Moolenbroek       default:
1088*5d5fbe79SDavid van Moolenbroek         break;
1089*5d5fbe79SDavid van Moolenbroek       }
1090*5d5fbe79SDavid van Moolenbroek       msg->conn->pcb.tcp = NULL;
1091*5d5fbe79SDavid van Moolenbroek     }
1092*5d5fbe79SDavid van Moolenbroek     /* tcp netconns don't come here! */
1093*5d5fbe79SDavid van Moolenbroek 
1094*5d5fbe79SDavid van Moolenbroek     /* @todo: this lets select make the socket readable and writable,
1095*5d5fbe79SDavid van Moolenbroek        which is wrong! errfd instead? */
1096*5d5fbe79SDavid van Moolenbroek     API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
1097*5d5fbe79SDavid van Moolenbroek     API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
1098*5d5fbe79SDavid van Moolenbroek   }
1099*5d5fbe79SDavid van Moolenbroek   if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) {
1100*5d5fbe79SDavid van Moolenbroek     TCPIP_APIMSG_ACK(msg);
1101*5d5fbe79SDavid van Moolenbroek   }
1102*5d5fbe79SDavid van Moolenbroek }
1103*5d5fbe79SDavid van Moolenbroek 
1104*5d5fbe79SDavid van Moolenbroek /**
1105*5d5fbe79SDavid van Moolenbroek  * Bind a pcb contained in a netconn
1106*5d5fbe79SDavid van Moolenbroek  * Called from netconn_bind.
1107*5d5fbe79SDavid van Moolenbroek  *
1108*5d5fbe79SDavid van Moolenbroek  * @param m the api_msg_msg pointing to the connection and containing
1109*5d5fbe79SDavid van Moolenbroek  *          the IP address and port to bind to
1110*5d5fbe79SDavid van Moolenbroek  */
1111*5d5fbe79SDavid van Moolenbroek void
1112*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_bind(void *m)
1113*5d5fbe79SDavid van Moolenbroek {
1114*5d5fbe79SDavid van Moolenbroek   struct api_msg *msg = (struct api_msg*)m;
1115*5d5fbe79SDavid van Moolenbroek 
1116*5d5fbe79SDavid van Moolenbroek   if (ERR_IS_FATAL(msg->conn->last_err)) {
1117*5d5fbe79SDavid van Moolenbroek     msg->err = msg->conn->last_err;
1118*5d5fbe79SDavid van Moolenbroek   } else {
1119*5d5fbe79SDavid van Moolenbroek     msg->err = ERR_VAL;
1120*5d5fbe79SDavid van Moolenbroek     if (msg->conn->pcb.tcp != NULL) {
1121*5d5fbe79SDavid van Moolenbroek       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1122*5d5fbe79SDavid van Moolenbroek #if LWIP_RAW
1123*5d5fbe79SDavid van Moolenbroek       case NETCONN_RAW:
1124*5d5fbe79SDavid van Moolenbroek         msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1125*5d5fbe79SDavid van Moolenbroek         break;
1126*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_RAW */
1127*5d5fbe79SDavid van Moolenbroek #if LWIP_UDP
1128*5d5fbe79SDavid van Moolenbroek       case NETCONN_UDP:
1129*5d5fbe79SDavid van Moolenbroek         msg->err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1130*5d5fbe79SDavid van Moolenbroek         break;
1131*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_UDP */
1132*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
1133*5d5fbe79SDavid van Moolenbroek       case NETCONN_TCP:
1134*5d5fbe79SDavid van Moolenbroek         msg->err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1135*5d5fbe79SDavid van Moolenbroek         break;
1136*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
1137*5d5fbe79SDavid van Moolenbroek       default:
1138*5d5fbe79SDavid van Moolenbroek         break;
1139*5d5fbe79SDavid van Moolenbroek       }
1140*5d5fbe79SDavid van Moolenbroek     }
1141*5d5fbe79SDavid van Moolenbroek   }
1142*5d5fbe79SDavid van Moolenbroek   TCPIP_APIMSG_ACK(msg);
1143*5d5fbe79SDavid van Moolenbroek }
1144*5d5fbe79SDavid van Moolenbroek 
1145*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
1146*5d5fbe79SDavid van Moolenbroek /**
1147*5d5fbe79SDavid van Moolenbroek  * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has
1148*5d5fbe79SDavid van Moolenbroek  * been established (or reset by the remote host).
1149*5d5fbe79SDavid van Moolenbroek  *
1150*5d5fbe79SDavid van Moolenbroek  * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
1151*5d5fbe79SDavid van Moolenbroek  */
1152*5d5fbe79SDavid van Moolenbroek static err_t
1153*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
1154*5d5fbe79SDavid van Moolenbroek {
1155*5d5fbe79SDavid van Moolenbroek   struct netconn *conn;
1156*5d5fbe79SDavid van Moolenbroek   int was_blocking;
1157*5d5fbe79SDavid van Moolenbroek   sys_sem_t* op_completed_sem = NULL;
1158*5d5fbe79SDavid van Moolenbroek 
1159*5d5fbe79SDavid van Moolenbroek   LWIP_UNUSED_ARG(pcb);
1160*5d5fbe79SDavid van Moolenbroek 
1161*5d5fbe79SDavid van Moolenbroek   conn = (struct netconn *)arg;
1162*5d5fbe79SDavid van Moolenbroek 
1163*5d5fbe79SDavid van Moolenbroek   if (conn == NULL) {
1164*5d5fbe79SDavid van Moolenbroek     return ERR_VAL;
1165*5d5fbe79SDavid van Moolenbroek   }
1166*5d5fbe79SDavid van Moolenbroek 
1167*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
1168*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
1169*5d5fbe79SDavid van Moolenbroek     (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
1170*5d5fbe79SDavid van Moolenbroek 
1171*5d5fbe79SDavid van Moolenbroek   if (conn->current_msg != NULL) {
1172*5d5fbe79SDavid van Moolenbroek     conn->current_msg->err = err;
1173*5d5fbe79SDavid van Moolenbroek     op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1174*5d5fbe79SDavid van Moolenbroek   }
1175*5d5fbe79SDavid van Moolenbroek   if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) {
1176*5d5fbe79SDavid van Moolenbroek     setup_tcp(conn);
1177*5d5fbe79SDavid van Moolenbroek   }
1178*5d5fbe79SDavid van Moolenbroek   was_blocking = !IN_NONBLOCKING_CONNECT(conn);
1179*5d5fbe79SDavid van Moolenbroek   SET_NONBLOCKING_CONNECT(conn, 0);
1180*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("blocking connect state error",
1181*5d5fbe79SDavid van Moolenbroek     (was_blocking && op_completed_sem != NULL) ||
1182*5d5fbe79SDavid van Moolenbroek     (!was_blocking && op_completed_sem == NULL));
1183*5d5fbe79SDavid van Moolenbroek   conn->current_msg = NULL;
1184*5d5fbe79SDavid van Moolenbroek   conn->state = NETCONN_NONE;
1185*5d5fbe79SDavid van Moolenbroek   NETCONN_SET_SAFE_ERR(conn, ERR_OK);
1186*5d5fbe79SDavid van Moolenbroek   API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
1187*5d5fbe79SDavid van Moolenbroek 
1188*5d5fbe79SDavid van Moolenbroek   if (was_blocking) {
1189*5d5fbe79SDavid van Moolenbroek     sys_sem_signal(op_completed_sem);
1190*5d5fbe79SDavid van Moolenbroek   }
1191*5d5fbe79SDavid van Moolenbroek   return ERR_OK;
1192*5d5fbe79SDavid van Moolenbroek }
1193*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
1194*5d5fbe79SDavid van Moolenbroek 
1195*5d5fbe79SDavid van Moolenbroek /**
1196*5d5fbe79SDavid van Moolenbroek  * Connect a pcb contained inside a netconn
1197*5d5fbe79SDavid van Moolenbroek  * Called from netconn_connect.
1198*5d5fbe79SDavid van Moolenbroek  *
1199*5d5fbe79SDavid van Moolenbroek  * @param m the api_msg_msg pointing to the connection and containing
1200*5d5fbe79SDavid van Moolenbroek  *          the IP address and port to connect to
1201*5d5fbe79SDavid van Moolenbroek  */
1202*5d5fbe79SDavid van Moolenbroek void
1203*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_connect(void *m)
1204*5d5fbe79SDavid van Moolenbroek {
1205*5d5fbe79SDavid van Moolenbroek   struct api_msg *msg = (struct api_msg*)m;
1206*5d5fbe79SDavid van Moolenbroek 
1207*5d5fbe79SDavid van Moolenbroek   if (msg->conn->pcb.tcp == NULL) {
1208*5d5fbe79SDavid van Moolenbroek     /* This may happen when calling netconn_connect() a second time */
1209*5d5fbe79SDavid van Moolenbroek     msg->err = ERR_CLSD;
1210*5d5fbe79SDavid van Moolenbroek   } else {
1211*5d5fbe79SDavid van Moolenbroek     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1212*5d5fbe79SDavid van Moolenbroek #if LWIP_RAW
1213*5d5fbe79SDavid van Moolenbroek     case NETCONN_RAW:
1214*5d5fbe79SDavid van Moolenbroek       msg->err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1215*5d5fbe79SDavid van Moolenbroek       break;
1216*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_RAW */
1217*5d5fbe79SDavid van Moolenbroek #if LWIP_UDP
1218*5d5fbe79SDavid van Moolenbroek     case NETCONN_UDP:
1219*5d5fbe79SDavid van Moolenbroek       msg->err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1220*5d5fbe79SDavid van Moolenbroek       break;
1221*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_UDP */
1222*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
1223*5d5fbe79SDavid van Moolenbroek     case NETCONN_TCP:
1224*5d5fbe79SDavid van Moolenbroek       /* Prevent connect while doing any other action. */
1225*5d5fbe79SDavid van Moolenbroek       if (msg->conn->state == NETCONN_CONNECT) {
1226*5d5fbe79SDavid van Moolenbroek         msg->err = ERR_ALREADY;
1227*5d5fbe79SDavid van Moolenbroek       } else if (msg->conn->state != NETCONN_NONE) {
1228*5d5fbe79SDavid van Moolenbroek         msg->err = ERR_ISCONN;
1229*5d5fbe79SDavid van Moolenbroek       } else {
1230*5d5fbe79SDavid van Moolenbroek         setup_tcp(msg->conn);
1231*5d5fbe79SDavid van Moolenbroek         msg->err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr),
1232*5d5fbe79SDavid van Moolenbroek           msg->msg.bc.port, lwip_netconn_do_connected);
1233*5d5fbe79SDavid van Moolenbroek         if (msg->err == ERR_OK) {
1234*5d5fbe79SDavid van Moolenbroek           u8_t non_blocking = netconn_is_nonblocking(msg->conn);
1235*5d5fbe79SDavid van Moolenbroek           msg->conn->state = NETCONN_CONNECT;
1236*5d5fbe79SDavid van Moolenbroek           SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
1237*5d5fbe79SDavid van Moolenbroek           if (non_blocking) {
1238*5d5fbe79SDavid van Moolenbroek             msg->err = ERR_INPROGRESS;
1239*5d5fbe79SDavid van Moolenbroek           } else {
1240*5d5fbe79SDavid van Moolenbroek             msg->conn->current_msg = msg;
1241*5d5fbe79SDavid van Moolenbroek             /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()),
1242*5d5fbe79SDavid van Moolenbroek                when the connection is established! */
1243*5d5fbe79SDavid van Moolenbroek #if LWIP_TCPIP_CORE_LOCKING
1244*5d5fbe79SDavid van Moolenbroek             LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT);
1245*5d5fbe79SDavid van Moolenbroek             UNLOCK_TCPIP_CORE();
1246*5d5fbe79SDavid van Moolenbroek             sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1247*5d5fbe79SDavid van Moolenbroek             LOCK_TCPIP_CORE();
1248*5d5fbe79SDavid van Moolenbroek             LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT);
1249*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCPIP_CORE_LOCKING */
1250*5d5fbe79SDavid van Moolenbroek             return;
1251*5d5fbe79SDavid van Moolenbroek           }
1252*5d5fbe79SDavid van Moolenbroek         }
1253*5d5fbe79SDavid van Moolenbroek       }
1254*5d5fbe79SDavid van Moolenbroek       break;
1255*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
1256*5d5fbe79SDavid van Moolenbroek     default:
1257*5d5fbe79SDavid van Moolenbroek       LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
1258*5d5fbe79SDavid van Moolenbroek       break;
1259*5d5fbe79SDavid van Moolenbroek     }
1260*5d5fbe79SDavid van Moolenbroek   }
1261*5d5fbe79SDavid van Moolenbroek   /* For all other protocols, netconn_connect() calls TCPIP_APIMSG(),
1262*5d5fbe79SDavid van Moolenbroek      so use TCPIP_APIMSG_ACK() here. */
1263*5d5fbe79SDavid van Moolenbroek   TCPIP_APIMSG_ACK(msg);
1264*5d5fbe79SDavid van Moolenbroek }
1265*5d5fbe79SDavid van Moolenbroek 
1266*5d5fbe79SDavid van Moolenbroek /**
1267*5d5fbe79SDavid van Moolenbroek  * Disconnect a pcb contained inside a netconn
1268*5d5fbe79SDavid van Moolenbroek  * Only used for UDP netconns.
1269*5d5fbe79SDavid van Moolenbroek  * Called from netconn_disconnect.
1270*5d5fbe79SDavid van Moolenbroek  *
1271*5d5fbe79SDavid van Moolenbroek  * @param m the api_msg_msg pointing to the connection to disconnect
1272*5d5fbe79SDavid van Moolenbroek  */
1273*5d5fbe79SDavid van Moolenbroek void
1274*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_disconnect(void *m)
1275*5d5fbe79SDavid van Moolenbroek {
1276*5d5fbe79SDavid van Moolenbroek   struct api_msg *msg = (struct api_msg*)m;
1277*5d5fbe79SDavid van Moolenbroek 
1278*5d5fbe79SDavid van Moolenbroek #if LWIP_UDP
1279*5d5fbe79SDavid van Moolenbroek   if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1280*5d5fbe79SDavid van Moolenbroek     udp_disconnect(msg->conn->pcb.udp);
1281*5d5fbe79SDavid van Moolenbroek     msg->err = ERR_OK;
1282*5d5fbe79SDavid van Moolenbroek   } else
1283*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_UDP */
1284*5d5fbe79SDavid van Moolenbroek   {
1285*5d5fbe79SDavid van Moolenbroek     msg->err = ERR_VAL;
1286*5d5fbe79SDavid van Moolenbroek   }
1287*5d5fbe79SDavid van Moolenbroek   TCPIP_APIMSG_ACK(msg);
1288*5d5fbe79SDavid van Moolenbroek }
1289*5d5fbe79SDavid van Moolenbroek 
1290*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
1291*5d5fbe79SDavid van Moolenbroek /**
1292*5d5fbe79SDavid van Moolenbroek  * Set a TCP pcb contained in a netconn into listen mode
1293*5d5fbe79SDavid van Moolenbroek  * Called from netconn_listen.
1294*5d5fbe79SDavid van Moolenbroek  *
1295*5d5fbe79SDavid van Moolenbroek  * @param m the api_msg_msg pointing to the connection
1296*5d5fbe79SDavid van Moolenbroek  */
1297*5d5fbe79SDavid van Moolenbroek void
1298*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_listen(void *m)
1299*5d5fbe79SDavid van Moolenbroek {
1300*5d5fbe79SDavid van Moolenbroek   struct api_msg *msg = (struct api_msg*)m;
1301*5d5fbe79SDavid van Moolenbroek 
1302*5d5fbe79SDavid van Moolenbroek   if (ERR_IS_FATAL(msg->conn->last_err)) {
1303*5d5fbe79SDavid van Moolenbroek     msg->err = msg->conn->last_err;
1304*5d5fbe79SDavid van Moolenbroek   } else {
1305*5d5fbe79SDavid van Moolenbroek     msg->err = ERR_CONN;
1306*5d5fbe79SDavid van Moolenbroek     if (msg->conn->pcb.tcp != NULL) {
1307*5d5fbe79SDavid van Moolenbroek       if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1308*5d5fbe79SDavid van Moolenbroek         if (msg->conn->state == NETCONN_NONE) {
1309*5d5fbe79SDavid van Moolenbroek           struct tcp_pcb* lpcb;
1310*5d5fbe79SDavid van Moolenbroek           if (msg->conn->pcb.tcp->state != CLOSED) {
1311*5d5fbe79SDavid van Moolenbroek             /* connection is not closed, cannot listen */
1312*5d5fbe79SDavid van Moolenbroek             msg->err = ERR_VAL;
1313*5d5fbe79SDavid van Moolenbroek           } else {
1314*5d5fbe79SDavid van Moolenbroek             err_t err;
1315*5d5fbe79SDavid van Moolenbroek             u8_t backlog;
1316*5d5fbe79SDavid van Moolenbroek #if TCP_LISTEN_BACKLOG
1317*5d5fbe79SDavid van Moolenbroek             backlog = msg->msg.lb.backlog;
1318*5d5fbe79SDavid van Moolenbroek #else  /* TCP_LISTEN_BACKLOG */
1319*5d5fbe79SDavid van Moolenbroek             backlog = TCP_DEFAULT_LISTEN_BACKLOG;
1320*5d5fbe79SDavid van Moolenbroek #endif /* TCP_LISTEN_BACKLOG */
1321*5d5fbe79SDavid van Moolenbroek #if LWIP_IPV4 && LWIP_IPV6
1322*5d5fbe79SDavid van Moolenbroek             /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
1323*5d5fbe79SDavid van Moolenbroek              * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
1324*5d5fbe79SDavid van Moolenbroek              */
1325*5d5fbe79SDavid van Moolenbroek             if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) &&
1326*5d5fbe79SDavid van Moolenbroek                 (netconn_get_ipv6only(msg->conn) == 0)) {
1327*5d5fbe79SDavid van Moolenbroek               /* change PCB type to IPADDR_TYPE_ANY */
1328*5d5fbe79SDavid van Moolenbroek               IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip,  IPADDR_TYPE_ANY);
1329*5d5fbe79SDavid van Moolenbroek               IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY);
1330*5d5fbe79SDavid van Moolenbroek             }
1331*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_IPV4 && LWIP_IPV6 */
1332*5d5fbe79SDavid van Moolenbroek 
1333*5d5fbe79SDavid van Moolenbroek             lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
1334*5d5fbe79SDavid van Moolenbroek 
1335*5d5fbe79SDavid van Moolenbroek             if (lpcb == NULL) {
1336*5d5fbe79SDavid van Moolenbroek               /* in this case, the old pcb is still allocated */
1337*5d5fbe79SDavid van Moolenbroek               msg->err = err;
1338*5d5fbe79SDavid van Moolenbroek             } else {
1339*5d5fbe79SDavid van Moolenbroek               /* delete the recvmbox and allocate the acceptmbox */
1340*5d5fbe79SDavid van Moolenbroek               if (sys_mbox_valid(&msg->conn->recvmbox)) {
1341*5d5fbe79SDavid van Moolenbroek                 /** @todo: should we drain the recvmbox here? */
1342*5d5fbe79SDavid van Moolenbroek                 sys_mbox_free(&msg->conn->recvmbox);
1343*5d5fbe79SDavid van Moolenbroek                 sys_mbox_set_invalid(&msg->conn->recvmbox);
1344*5d5fbe79SDavid van Moolenbroek               }
1345*5d5fbe79SDavid van Moolenbroek               msg->err = ERR_OK;
1346*5d5fbe79SDavid van Moolenbroek               if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
1347*5d5fbe79SDavid van Moolenbroek                 msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
1348*5d5fbe79SDavid van Moolenbroek               }
1349*5d5fbe79SDavid van Moolenbroek               if (msg->err == ERR_OK) {
1350*5d5fbe79SDavid van Moolenbroek                 msg->conn->state = NETCONN_LISTEN;
1351*5d5fbe79SDavid van Moolenbroek                 msg->conn->pcb.tcp = lpcb;
1352*5d5fbe79SDavid van Moolenbroek                 tcp_arg(msg->conn->pcb.tcp, msg->conn);
1353*5d5fbe79SDavid van Moolenbroek                 tcp_accept(msg->conn->pcb.tcp, accept_function);
1354*5d5fbe79SDavid van Moolenbroek               } else {
1355*5d5fbe79SDavid van Moolenbroek                 /* since the old pcb is already deallocated, free lpcb now */
1356*5d5fbe79SDavid van Moolenbroek                 tcp_close(lpcb);
1357*5d5fbe79SDavid van Moolenbroek                 msg->conn->pcb.tcp = NULL;
1358*5d5fbe79SDavid van Moolenbroek               }
1359*5d5fbe79SDavid van Moolenbroek             }
1360*5d5fbe79SDavid van Moolenbroek           }
1361*5d5fbe79SDavid van Moolenbroek         } else if (msg->conn->state == NETCONN_LISTEN) {
1362*5d5fbe79SDavid van Moolenbroek           /* already listening, allow updating of the backlog */
1363*5d5fbe79SDavid van Moolenbroek           msg->err = ERR_OK;
1364*5d5fbe79SDavid van Moolenbroek           tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog);
1365*5d5fbe79SDavid van Moolenbroek         }
1366*5d5fbe79SDavid van Moolenbroek       } else {
1367*5d5fbe79SDavid van Moolenbroek         msg->err = ERR_ARG;
1368*5d5fbe79SDavid van Moolenbroek       }
1369*5d5fbe79SDavid van Moolenbroek     }
1370*5d5fbe79SDavid van Moolenbroek   }
1371*5d5fbe79SDavid van Moolenbroek   TCPIP_APIMSG_ACK(msg);
1372*5d5fbe79SDavid van Moolenbroek }
1373*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
1374*5d5fbe79SDavid van Moolenbroek 
1375*5d5fbe79SDavid van Moolenbroek /**
1376*5d5fbe79SDavid van Moolenbroek  * Send some data on a RAW or UDP pcb contained in a netconn
1377*5d5fbe79SDavid van Moolenbroek  * Called from netconn_send
1378*5d5fbe79SDavid van Moolenbroek  *
1379*5d5fbe79SDavid van Moolenbroek  * @param m the api_msg_msg pointing to the connection
1380*5d5fbe79SDavid van Moolenbroek  */
1381*5d5fbe79SDavid van Moolenbroek void
1382*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_send(void *m)
1383*5d5fbe79SDavid van Moolenbroek {
1384*5d5fbe79SDavid van Moolenbroek   struct api_msg *msg = (struct api_msg*)m;
1385*5d5fbe79SDavid van Moolenbroek 
1386*5d5fbe79SDavid van Moolenbroek   if (ERR_IS_FATAL(msg->conn->last_err)) {
1387*5d5fbe79SDavid van Moolenbroek     msg->err = msg->conn->last_err;
1388*5d5fbe79SDavid van Moolenbroek   } else {
1389*5d5fbe79SDavid van Moolenbroek     msg->err = ERR_CONN;
1390*5d5fbe79SDavid van Moolenbroek     if (msg->conn->pcb.tcp != NULL) {
1391*5d5fbe79SDavid van Moolenbroek       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1392*5d5fbe79SDavid van Moolenbroek #if LWIP_RAW
1393*5d5fbe79SDavid van Moolenbroek       case NETCONN_RAW:
1394*5d5fbe79SDavid van Moolenbroek         if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1395*5d5fbe79SDavid van Moolenbroek           msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
1396*5d5fbe79SDavid van Moolenbroek         } else {
1397*5d5fbe79SDavid van Moolenbroek           msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
1398*5d5fbe79SDavid van Moolenbroek         }
1399*5d5fbe79SDavid van Moolenbroek         break;
1400*5d5fbe79SDavid van Moolenbroek #endif
1401*5d5fbe79SDavid van Moolenbroek #if LWIP_UDP
1402*5d5fbe79SDavid van Moolenbroek       case NETCONN_UDP:
1403*5d5fbe79SDavid van Moolenbroek #if LWIP_CHECKSUM_ON_COPY
1404*5d5fbe79SDavid van Moolenbroek         if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1405*5d5fbe79SDavid van Moolenbroek           msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1406*5d5fbe79SDavid van Moolenbroek             msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1407*5d5fbe79SDavid van Moolenbroek         } else {
1408*5d5fbe79SDavid van Moolenbroek           msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1409*5d5fbe79SDavid van Moolenbroek             &msg->msg.b->addr, msg->msg.b->port,
1410*5d5fbe79SDavid van Moolenbroek             msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1411*5d5fbe79SDavid van Moolenbroek         }
1412*5d5fbe79SDavid van Moolenbroek #else /* LWIP_CHECKSUM_ON_COPY */
1413*5d5fbe79SDavid van Moolenbroek         if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1414*5d5fbe79SDavid van Moolenbroek           msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
1415*5d5fbe79SDavid van Moolenbroek         } else {
1416*5d5fbe79SDavid van Moolenbroek           msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
1417*5d5fbe79SDavid van Moolenbroek         }
1418*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_CHECKSUM_ON_COPY */
1419*5d5fbe79SDavid van Moolenbroek         break;
1420*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_UDP */
1421*5d5fbe79SDavid van Moolenbroek       default:
1422*5d5fbe79SDavid van Moolenbroek         break;
1423*5d5fbe79SDavid van Moolenbroek       }
1424*5d5fbe79SDavid van Moolenbroek     }
1425*5d5fbe79SDavid van Moolenbroek   }
1426*5d5fbe79SDavid van Moolenbroek   TCPIP_APIMSG_ACK(msg);
1427*5d5fbe79SDavid van Moolenbroek }
1428*5d5fbe79SDavid van Moolenbroek 
1429*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
1430*5d5fbe79SDavid van Moolenbroek /**
1431*5d5fbe79SDavid van Moolenbroek  * Indicate data has been received from a TCP pcb contained in a netconn
1432*5d5fbe79SDavid van Moolenbroek  * Called from netconn_recv
1433*5d5fbe79SDavid van Moolenbroek  *
1434*5d5fbe79SDavid van Moolenbroek  * @param m the api_msg_msg pointing to the connection
1435*5d5fbe79SDavid van Moolenbroek  */
1436*5d5fbe79SDavid van Moolenbroek void
1437*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_recv(void *m)
1438*5d5fbe79SDavid van Moolenbroek {
1439*5d5fbe79SDavid van Moolenbroek   struct api_msg *msg = (struct api_msg*)m;
1440*5d5fbe79SDavid van Moolenbroek 
1441*5d5fbe79SDavid van Moolenbroek   msg->err = ERR_OK;
1442*5d5fbe79SDavid van Moolenbroek   if (msg->conn->pcb.tcp != NULL) {
1443*5d5fbe79SDavid van Moolenbroek     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1444*5d5fbe79SDavid van Moolenbroek       u32_t remaining = msg->msg.r.len;
1445*5d5fbe79SDavid van Moolenbroek       do {
1446*5d5fbe79SDavid van Moolenbroek         u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
1447*5d5fbe79SDavid van Moolenbroek         tcp_recved(msg->conn->pcb.tcp, recved);
1448*5d5fbe79SDavid van Moolenbroek         remaining -= recved;
1449*5d5fbe79SDavid van Moolenbroek       } while (remaining != 0);
1450*5d5fbe79SDavid van Moolenbroek     }
1451*5d5fbe79SDavid van Moolenbroek   }
1452*5d5fbe79SDavid van Moolenbroek   TCPIP_APIMSG_ACK(msg);
1453*5d5fbe79SDavid van Moolenbroek }
1454*5d5fbe79SDavid van Moolenbroek 
1455*5d5fbe79SDavid van Moolenbroek #if TCP_LISTEN_BACKLOG
1456*5d5fbe79SDavid van Moolenbroek /** Indicate that a TCP pcb has been accepted
1457*5d5fbe79SDavid van Moolenbroek  * Called from netconn_accept
1458*5d5fbe79SDavid van Moolenbroek  *
1459*5d5fbe79SDavid van Moolenbroek  * @param m the api_msg_msg pointing to the connection
1460*5d5fbe79SDavid van Moolenbroek  */
1461*5d5fbe79SDavid van Moolenbroek void
1462*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_accepted(void *m)
1463*5d5fbe79SDavid van Moolenbroek {
1464*5d5fbe79SDavid van Moolenbroek   struct api_msg *msg = (struct api_msg*)m;
1465*5d5fbe79SDavid van Moolenbroek 
1466*5d5fbe79SDavid van Moolenbroek   msg->err = ERR_OK;
1467*5d5fbe79SDavid van Moolenbroek   if (msg->conn->pcb.tcp != NULL) {
1468*5d5fbe79SDavid van Moolenbroek     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1469*5d5fbe79SDavid van Moolenbroek       tcp_backlog_accepted(msg->conn->pcb.tcp);
1470*5d5fbe79SDavid van Moolenbroek     }
1471*5d5fbe79SDavid van Moolenbroek   }
1472*5d5fbe79SDavid van Moolenbroek   TCPIP_APIMSG_ACK(msg);
1473*5d5fbe79SDavid van Moolenbroek }
1474*5d5fbe79SDavid van Moolenbroek #endif /* TCP_LISTEN_BACKLOG */
1475*5d5fbe79SDavid van Moolenbroek 
1476*5d5fbe79SDavid van Moolenbroek /**
1477*5d5fbe79SDavid van Moolenbroek  * See if more data needs to be written from a previous call to netconn_write.
1478*5d5fbe79SDavid van Moolenbroek  * Called initially from lwip_netconn_do_write. If the first call can't send all data
1479*5d5fbe79SDavid van Moolenbroek  * (because of low memory or empty send-buffer), this function is called again
1480*5d5fbe79SDavid van Moolenbroek  * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
1481*5d5fbe79SDavid van Moolenbroek  * blocking application thread (waiting in netconn_write) is released.
1482*5d5fbe79SDavid van Moolenbroek  *
1483*5d5fbe79SDavid van Moolenbroek  * @param conn netconn (that is currently in state NETCONN_WRITE) to process
1484*5d5fbe79SDavid van Moolenbroek  * @return ERR_OK
1485*5d5fbe79SDavid van Moolenbroek  *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
1486*5d5fbe79SDavid van Moolenbroek  */
1487*5d5fbe79SDavid van Moolenbroek static err_t
1488*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_writemore(struct netconn *conn  WRITE_DELAYED_PARAM)
1489*5d5fbe79SDavid van Moolenbroek {
1490*5d5fbe79SDavid van Moolenbroek   err_t err;
1491*5d5fbe79SDavid van Moolenbroek   const void *dataptr;
1492*5d5fbe79SDavid van Moolenbroek   u16_t len, available;
1493*5d5fbe79SDavid van Moolenbroek   u8_t write_finished = 0;
1494*5d5fbe79SDavid van Moolenbroek   size_t diff;
1495*5d5fbe79SDavid van Moolenbroek   u8_t dontblock;
1496*5d5fbe79SDavid van Moolenbroek   u8_t apiflags;
1497*5d5fbe79SDavid van Moolenbroek   u8_t write_more;
1498*5d5fbe79SDavid van Moolenbroek 
1499*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("conn != NULL", conn != NULL);
1500*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
1501*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
1502*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
1503*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len",
1504*5d5fbe79SDavid van Moolenbroek     conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len);
1505*5d5fbe79SDavid van Moolenbroek   LWIP_ASSERT("conn->current_msg->msg.w.vector_cnt > 0", conn->current_msg->msg.w.vector_cnt > 0);
1506*5d5fbe79SDavid van Moolenbroek 
1507*5d5fbe79SDavid van Moolenbroek   apiflags = conn->current_msg->msg.w.apiflags;
1508*5d5fbe79SDavid van Moolenbroek   dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
1509*5d5fbe79SDavid van Moolenbroek 
1510*5d5fbe79SDavid van Moolenbroek #if LWIP_SO_SNDTIMEO
1511*5d5fbe79SDavid van Moolenbroek   if ((conn->send_timeout != 0) &&
1512*5d5fbe79SDavid van Moolenbroek       ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
1513*5d5fbe79SDavid van Moolenbroek     write_finished = 1;
1514*5d5fbe79SDavid van Moolenbroek     if (conn->current_msg->msg.w.offset == 0) {
1515*5d5fbe79SDavid van Moolenbroek       /* nothing has been written */
1516*5d5fbe79SDavid van Moolenbroek       err = ERR_WOULDBLOCK;
1517*5d5fbe79SDavid van Moolenbroek     } else {
1518*5d5fbe79SDavid van Moolenbroek       /* partial write */
1519*5d5fbe79SDavid van Moolenbroek       err = ERR_OK;
1520*5d5fbe79SDavid van Moolenbroek     }
1521*5d5fbe79SDavid van Moolenbroek   } else
1522*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_SO_SNDTIMEO */
1523*5d5fbe79SDavid van Moolenbroek   {
1524*5d5fbe79SDavid van Moolenbroek     do {
1525*5d5fbe79SDavid van Moolenbroek       dataptr = (const u8_t*)conn->current_msg->msg.w.vector->ptr + conn->current_msg->msg.w.vector_off;
1526*5d5fbe79SDavid van Moolenbroek       diff = conn->current_msg->msg.w.vector->len - conn->current_msg->msg.w.vector_off;
1527*5d5fbe79SDavid van Moolenbroek       if (diff > 0xffffUL) { /* max_u16_t */
1528*5d5fbe79SDavid van Moolenbroek         len = 0xffff;
1529*5d5fbe79SDavid van Moolenbroek         apiflags |= TCP_WRITE_FLAG_MORE;
1530*5d5fbe79SDavid van Moolenbroek       } else {
1531*5d5fbe79SDavid van Moolenbroek         len = (u16_t)diff;
1532*5d5fbe79SDavid van Moolenbroek       }
1533*5d5fbe79SDavid van Moolenbroek       available = tcp_sndbuf(conn->pcb.tcp);
1534*5d5fbe79SDavid van Moolenbroek       if (available < len) {
1535*5d5fbe79SDavid van Moolenbroek         /* don't try to write more than sendbuf */
1536*5d5fbe79SDavid van Moolenbroek         len = available;
1537*5d5fbe79SDavid van Moolenbroek         if (dontblock) {
1538*5d5fbe79SDavid van Moolenbroek           if (!len) {
1539*5d5fbe79SDavid van Moolenbroek             /* set error according to partial write or not */
1540*5d5fbe79SDavid van Moolenbroek             err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK;
1541*5d5fbe79SDavid van Moolenbroek             goto err_mem;
1542*5d5fbe79SDavid van Moolenbroek           }
1543*5d5fbe79SDavid van Moolenbroek         } else {
1544*5d5fbe79SDavid van Moolenbroek           apiflags |= TCP_WRITE_FLAG_MORE;
1545*5d5fbe79SDavid van Moolenbroek         }
1546*5d5fbe79SDavid van Moolenbroek       }
1547*5d5fbe79SDavid van Moolenbroek       LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!",
1548*5d5fbe79SDavid van Moolenbroek         ((conn->current_msg->msg.w.vector_off + len) <= conn->current_msg->msg.w.vector->len));
1549*5d5fbe79SDavid van Moolenbroek       /* we should loop around for more sending in the following cases:
1550*5d5fbe79SDavid van Moolenbroek            1) We couldn't finish the current vector because of 16-bit size limitations.
1551*5d5fbe79SDavid van Moolenbroek               tcp_write() and tcp_sndbuf() both are limited to 16-bit sizes
1552*5d5fbe79SDavid van Moolenbroek            2) We are sending the remainder of the current vector and have more */
1553*5d5fbe79SDavid van Moolenbroek       if ((len == 0xffff && diff > 0xffffUL) ||
1554*5d5fbe79SDavid van Moolenbroek           (len == (u16_t)diff && conn->current_msg->msg.w.vector_cnt > 1)) {
1555*5d5fbe79SDavid van Moolenbroek         write_more = 1;
1556*5d5fbe79SDavid van Moolenbroek         apiflags |= TCP_WRITE_FLAG_MORE;
1557*5d5fbe79SDavid van Moolenbroek       } else {
1558*5d5fbe79SDavid van Moolenbroek         write_more = 0;
1559*5d5fbe79SDavid van Moolenbroek       }
1560*5d5fbe79SDavid van Moolenbroek       err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
1561*5d5fbe79SDavid van Moolenbroek       if (err == ERR_OK) {
1562*5d5fbe79SDavid van Moolenbroek         conn->current_msg->msg.w.offset += len;
1563*5d5fbe79SDavid van Moolenbroek         conn->current_msg->msg.w.vector_off += len;
1564*5d5fbe79SDavid van Moolenbroek         /* check if current vector is finished */
1565*5d5fbe79SDavid van Moolenbroek         if (conn->current_msg->msg.w.vector_off == conn->current_msg->msg.w.vector->len) {
1566*5d5fbe79SDavid van Moolenbroek           conn->current_msg->msg.w.vector_cnt--;
1567*5d5fbe79SDavid van Moolenbroek           /* if we have additional vectors, move on to them */
1568*5d5fbe79SDavid van Moolenbroek           if (conn->current_msg->msg.w.vector_cnt > 0) {
1569*5d5fbe79SDavid van Moolenbroek             conn->current_msg->msg.w.vector++;
1570*5d5fbe79SDavid van Moolenbroek             conn->current_msg->msg.w.vector_off = 0;
1571*5d5fbe79SDavid van Moolenbroek           }
1572*5d5fbe79SDavid van Moolenbroek         }
1573*5d5fbe79SDavid van Moolenbroek       }
1574*5d5fbe79SDavid van Moolenbroek     } while (write_more && err == ERR_OK);
1575*5d5fbe79SDavid van Moolenbroek     /* if OK or memory error, check available space */
1576*5d5fbe79SDavid van Moolenbroek     if ((err == ERR_OK) || (err == ERR_MEM)) {
1577*5d5fbe79SDavid van Moolenbroek err_mem:
1578*5d5fbe79SDavid van Moolenbroek       if (dontblock && (conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len)) {
1579*5d5fbe79SDavid van Moolenbroek         /* non-blocking write did not write everything: mark the pcb non-writable
1580*5d5fbe79SDavid van Moolenbroek            and let poll_tcp check writable space to mark the pcb writable again */
1581*5d5fbe79SDavid van Moolenbroek         API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
1582*5d5fbe79SDavid van Moolenbroek         conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
1583*5d5fbe79SDavid van Moolenbroek       } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
1584*5d5fbe79SDavid van Moolenbroek                  (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
1585*5d5fbe79SDavid van Moolenbroek         /* The queued byte- or pbuf-count exceeds the configured low-water limit,
1586*5d5fbe79SDavid van Moolenbroek            let select mark this pcb as non-writable. */
1587*5d5fbe79SDavid van Moolenbroek         API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
1588*5d5fbe79SDavid van Moolenbroek       }
1589*5d5fbe79SDavid van Moolenbroek     }
1590*5d5fbe79SDavid van Moolenbroek 
1591*5d5fbe79SDavid van Moolenbroek     if (err == ERR_OK) {
1592*5d5fbe79SDavid van Moolenbroek       err_t out_err;
1593*5d5fbe79SDavid van Moolenbroek       if ((conn->current_msg->msg.w.offset == conn->current_msg->msg.w.len) || dontblock) {
1594*5d5fbe79SDavid van Moolenbroek         /* return sent length (caller reads length from msg.w.offset) */
1595*5d5fbe79SDavid van Moolenbroek         write_finished = 1;
1596*5d5fbe79SDavid van Moolenbroek       }
1597*5d5fbe79SDavid van Moolenbroek       out_err = tcp_output(conn->pcb.tcp);
1598*5d5fbe79SDavid van Moolenbroek       if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) {
1599*5d5fbe79SDavid van Moolenbroek         /* If tcp_output fails with fatal error or no route is found,
1600*5d5fbe79SDavid van Moolenbroek            don't try writing any more but return the error
1601*5d5fbe79SDavid van Moolenbroek            to the application thread. */
1602*5d5fbe79SDavid van Moolenbroek         err = out_err;
1603*5d5fbe79SDavid van Moolenbroek         write_finished = 1;
1604*5d5fbe79SDavid van Moolenbroek       }
1605*5d5fbe79SDavid van Moolenbroek     } else if (err == ERR_MEM) {
1606*5d5fbe79SDavid van Moolenbroek       /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called.
1607*5d5fbe79SDavid van Moolenbroek          For blocking sockets, we do NOT return to the application
1608*5d5fbe79SDavid van Moolenbroek          thread, since ERR_MEM is only a temporary error! Non-blocking
1609*5d5fbe79SDavid van Moolenbroek          will remain non-writable until sent_tcp/poll_tcp is called */
1610*5d5fbe79SDavid van Moolenbroek 
1611*5d5fbe79SDavid van Moolenbroek       /* tcp_write returned ERR_MEM, try tcp_output anyway */
1612*5d5fbe79SDavid van Moolenbroek       err_t out_err = tcp_output(conn->pcb.tcp);
1613*5d5fbe79SDavid van Moolenbroek       if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) {
1614*5d5fbe79SDavid van Moolenbroek         /* If tcp_output fails with fatal error or no route is found,
1615*5d5fbe79SDavid van Moolenbroek            don't try writing any more but return the error
1616*5d5fbe79SDavid van Moolenbroek            to the application thread. */
1617*5d5fbe79SDavid van Moolenbroek         err = out_err;
1618*5d5fbe79SDavid van Moolenbroek         write_finished = 1;
1619*5d5fbe79SDavid van Moolenbroek       } else if (dontblock) {
1620*5d5fbe79SDavid van Moolenbroek         /* non-blocking write is done on ERR_MEM, set error according
1621*5d5fbe79SDavid van Moolenbroek            to partial write or not */
1622*5d5fbe79SDavid van Moolenbroek         err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK;
1623*5d5fbe79SDavid van Moolenbroek         write_finished = 1;
1624*5d5fbe79SDavid van Moolenbroek       }
1625*5d5fbe79SDavid van Moolenbroek     } else {
1626*5d5fbe79SDavid van Moolenbroek       /* On errors != ERR_MEM, we don't try writing any more but return
1627*5d5fbe79SDavid van Moolenbroek          the error to the application thread. */
1628*5d5fbe79SDavid van Moolenbroek       write_finished = 1;
1629*5d5fbe79SDavid van Moolenbroek     }
1630*5d5fbe79SDavid van Moolenbroek   }
1631*5d5fbe79SDavid van Moolenbroek   if (write_finished) {
1632*5d5fbe79SDavid van Moolenbroek     /* everything was written: set back connection state
1633*5d5fbe79SDavid van Moolenbroek        and back to application task */
1634*5d5fbe79SDavid van Moolenbroek     sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1635*5d5fbe79SDavid van Moolenbroek     conn->current_msg->err = err;
1636*5d5fbe79SDavid van Moolenbroek     conn->current_msg = NULL;
1637*5d5fbe79SDavid van Moolenbroek     conn->state = NETCONN_NONE;
1638*5d5fbe79SDavid van Moolenbroek     NETCONN_SET_SAFE_ERR(conn, err);
1639*5d5fbe79SDavid van Moolenbroek #if LWIP_TCPIP_CORE_LOCKING
1640*5d5fbe79SDavid van Moolenbroek     if (delayed)
1641*5d5fbe79SDavid van Moolenbroek #endif
1642*5d5fbe79SDavid van Moolenbroek     {
1643*5d5fbe79SDavid van Moolenbroek       sys_sem_signal(op_completed_sem);
1644*5d5fbe79SDavid van Moolenbroek     }
1645*5d5fbe79SDavid van Moolenbroek   }
1646*5d5fbe79SDavid van Moolenbroek #if LWIP_TCPIP_CORE_LOCKING
1647*5d5fbe79SDavid van Moolenbroek   else {
1648*5d5fbe79SDavid van Moolenbroek     return ERR_MEM;
1649*5d5fbe79SDavid van Moolenbroek   }
1650*5d5fbe79SDavid van Moolenbroek #endif
1651*5d5fbe79SDavid van Moolenbroek   return ERR_OK;
1652*5d5fbe79SDavid van Moolenbroek }
1653*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
1654*5d5fbe79SDavid van Moolenbroek 
1655*5d5fbe79SDavid van Moolenbroek /**
1656*5d5fbe79SDavid van Moolenbroek  * Send some data on a TCP pcb contained in a netconn
1657*5d5fbe79SDavid van Moolenbroek  * Called from netconn_write
1658*5d5fbe79SDavid van Moolenbroek  *
1659*5d5fbe79SDavid van Moolenbroek  * @param m the api_msg_msg pointing to the connection
1660*5d5fbe79SDavid van Moolenbroek  */
1661*5d5fbe79SDavid van Moolenbroek void
1662*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_write(void *m)
1663*5d5fbe79SDavid van Moolenbroek {
1664*5d5fbe79SDavid van Moolenbroek   struct api_msg *msg = (struct api_msg*)m;
1665*5d5fbe79SDavid van Moolenbroek 
1666*5d5fbe79SDavid van Moolenbroek   if (ERR_IS_FATAL(msg->conn->last_err)) {
1667*5d5fbe79SDavid van Moolenbroek     msg->err = msg->conn->last_err;
1668*5d5fbe79SDavid van Moolenbroek   } else {
1669*5d5fbe79SDavid van Moolenbroek     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1670*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
1671*5d5fbe79SDavid van Moolenbroek       if (msg->conn->state != NETCONN_NONE) {
1672*5d5fbe79SDavid van Moolenbroek         /* netconn is connecting, closing or in blocking write */
1673*5d5fbe79SDavid van Moolenbroek         msg->err = ERR_INPROGRESS;
1674*5d5fbe79SDavid van Moolenbroek       } else if (msg->conn->pcb.tcp != NULL) {
1675*5d5fbe79SDavid van Moolenbroek         msg->conn->state = NETCONN_WRITE;
1676*5d5fbe79SDavid van Moolenbroek         /* set all the variables used by lwip_netconn_do_writemore */
1677*5d5fbe79SDavid van Moolenbroek         LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL);
1678*5d5fbe79SDavid van Moolenbroek         LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
1679*5d5fbe79SDavid van Moolenbroek         msg->conn->current_msg = msg;
1680*5d5fbe79SDavid van Moolenbroek #if LWIP_TCPIP_CORE_LOCKING
1681*5d5fbe79SDavid van Moolenbroek         if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) {
1682*5d5fbe79SDavid van Moolenbroek           LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
1683*5d5fbe79SDavid van Moolenbroek           UNLOCK_TCPIP_CORE();
1684*5d5fbe79SDavid van Moolenbroek           sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1685*5d5fbe79SDavid van Moolenbroek           LOCK_TCPIP_CORE();
1686*5d5fbe79SDavid van Moolenbroek           LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE);
1687*5d5fbe79SDavid van Moolenbroek         }
1688*5d5fbe79SDavid van Moolenbroek #else /* LWIP_TCPIP_CORE_LOCKING */
1689*5d5fbe79SDavid van Moolenbroek         lwip_netconn_do_writemore(msg->conn);
1690*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCPIP_CORE_LOCKING */
1691*5d5fbe79SDavid van Moolenbroek         /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG
1692*5d5fbe79SDavid van Moolenbroek            since lwip_netconn_do_writemore ACKs it! */
1693*5d5fbe79SDavid van Moolenbroek         return;
1694*5d5fbe79SDavid van Moolenbroek       } else {
1695*5d5fbe79SDavid van Moolenbroek         msg->err = ERR_CONN;
1696*5d5fbe79SDavid van Moolenbroek       }
1697*5d5fbe79SDavid van Moolenbroek #else /* LWIP_TCP */
1698*5d5fbe79SDavid van Moolenbroek       msg->err = ERR_VAL;
1699*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
1700*5d5fbe79SDavid van Moolenbroek #if (LWIP_UDP || LWIP_RAW)
1701*5d5fbe79SDavid van Moolenbroek     } else {
1702*5d5fbe79SDavid van Moolenbroek       msg->err = ERR_VAL;
1703*5d5fbe79SDavid van Moolenbroek #endif /* (LWIP_UDP || LWIP_RAW) */
1704*5d5fbe79SDavid van Moolenbroek     }
1705*5d5fbe79SDavid van Moolenbroek   }
1706*5d5fbe79SDavid van Moolenbroek   TCPIP_APIMSG_ACK(msg);
1707*5d5fbe79SDavid van Moolenbroek }
1708*5d5fbe79SDavid van Moolenbroek 
1709*5d5fbe79SDavid van Moolenbroek /**
1710*5d5fbe79SDavid van Moolenbroek  * Return a connection's local or remote address
1711*5d5fbe79SDavid van Moolenbroek  * Called from netconn_getaddr
1712*5d5fbe79SDavid van Moolenbroek  *
1713*5d5fbe79SDavid van Moolenbroek  * @param m the api_msg_msg pointing to the connection
1714*5d5fbe79SDavid van Moolenbroek  */
1715*5d5fbe79SDavid van Moolenbroek void
1716*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_getaddr(void *m)
1717*5d5fbe79SDavid van Moolenbroek {
1718*5d5fbe79SDavid van Moolenbroek   struct api_msg *msg = (struct api_msg*)m;
1719*5d5fbe79SDavid van Moolenbroek 
1720*5d5fbe79SDavid van Moolenbroek   if (msg->conn->pcb.ip != NULL) {
1721*5d5fbe79SDavid van Moolenbroek     if (msg->msg.ad.local) {
1722*5d5fbe79SDavid van Moolenbroek       ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
1723*5d5fbe79SDavid van Moolenbroek         msg->conn->pcb.ip->local_ip);
1724*5d5fbe79SDavid van Moolenbroek     } else {
1725*5d5fbe79SDavid van Moolenbroek       ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
1726*5d5fbe79SDavid van Moolenbroek         msg->conn->pcb.ip->remote_ip);
1727*5d5fbe79SDavid van Moolenbroek     }
1728*5d5fbe79SDavid van Moolenbroek 
1729*5d5fbe79SDavid van Moolenbroek     msg->err = ERR_OK;
1730*5d5fbe79SDavid van Moolenbroek     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1731*5d5fbe79SDavid van Moolenbroek #if LWIP_RAW
1732*5d5fbe79SDavid van Moolenbroek     case NETCONN_RAW:
1733*5d5fbe79SDavid van Moolenbroek       if (msg->msg.ad.local) {
1734*5d5fbe79SDavid van Moolenbroek         API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
1735*5d5fbe79SDavid van Moolenbroek       } else {
1736*5d5fbe79SDavid van Moolenbroek         /* return an error as connecting is only a helper for upper layers */
1737*5d5fbe79SDavid van Moolenbroek         msg->err = ERR_CONN;
1738*5d5fbe79SDavid van Moolenbroek       }
1739*5d5fbe79SDavid van Moolenbroek       break;
1740*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_RAW */
1741*5d5fbe79SDavid van Moolenbroek #if LWIP_UDP
1742*5d5fbe79SDavid van Moolenbroek     case NETCONN_UDP:
1743*5d5fbe79SDavid van Moolenbroek       if (msg->msg.ad.local) {
1744*5d5fbe79SDavid van Moolenbroek         API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
1745*5d5fbe79SDavid van Moolenbroek       } else {
1746*5d5fbe79SDavid van Moolenbroek         if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
1747*5d5fbe79SDavid van Moolenbroek           msg->err = ERR_CONN;
1748*5d5fbe79SDavid van Moolenbroek         } else {
1749*5d5fbe79SDavid van Moolenbroek           API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
1750*5d5fbe79SDavid van Moolenbroek         }
1751*5d5fbe79SDavid van Moolenbroek       }
1752*5d5fbe79SDavid van Moolenbroek       break;
1753*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_UDP */
1754*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
1755*5d5fbe79SDavid van Moolenbroek     case NETCONN_TCP:
1756*5d5fbe79SDavid van Moolenbroek       if ((msg->msg.ad.local == 0) &&
1757*5d5fbe79SDavid van Moolenbroek           ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) {
1758*5d5fbe79SDavid van Moolenbroek         /* pcb is not connected and remote name is requested */
1759*5d5fbe79SDavid van Moolenbroek         msg->err = ERR_CONN;
1760*5d5fbe79SDavid van Moolenbroek       } else {
1761*5d5fbe79SDavid van Moolenbroek         API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port);
1762*5d5fbe79SDavid van Moolenbroek       }
1763*5d5fbe79SDavid van Moolenbroek       break;
1764*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
1765*5d5fbe79SDavid van Moolenbroek     default:
1766*5d5fbe79SDavid van Moolenbroek       LWIP_ASSERT("invalid netconn_type", 0);
1767*5d5fbe79SDavid van Moolenbroek       break;
1768*5d5fbe79SDavid van Moolenbroek     }
1769*5d5fbe79SDavid van Moolenbroek   } else {
1770*5d5fbe79SDavid van Moolenbroek     msg->err = ERR_CONN;
1771*5d5fbe79SDavid van Moolenbroek   }
1772*5d5fbe79SDavid van Moolenbroek   TCPIP_APIMSG_ACK(msg);
1773*5d5fbe79SDavid van Moolenbroek }
1774*5d5fbe79SDavid van Moolenbroek 
1775*5d5fbe79SDavid van Moolenbroek /**
1776*5d5fbe79SDavid van Moolenbroek  * Close or half-shutdown a TCP pcb contained in a netconn
1777*5d5fbe79SDavid van Moolenbroek  * Called from netconn_close
1778*5d5fbe79SDavid van Moolenbroek  * In contrast to closing sockets, the netconn is not deallocated.
1779*5d5fbe79SDavid van Moolenbroek  *
1780*5d5fbe79SDavid van Moolenbroek  * @param m the api_msg_msg pointing to the connection
1781*5d5fbe79SDavid van Moolenbroek  */
1782*5d5fbe79SDavid van Moolenbroek void
1783*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_close(void *m)
1784*5d5fbe79SDavid van Moolenbroek {
1785*5d5fbe79SDavid van Moolenbroek   struct api_msg *msg = (struct api_msg*)m;
1786*5d5fbe79SDavid van Moolenbroek 
1787*5d5fbe79SDavid van Moolenbroek #if LWIP_TCP
1788*5d5fbe79SDavid van Moolenbroek   enum netconn_state state = msg->conn->state;
1789*5d5fbe79SDavid van Moolenbroek   /* First check if this is a TCP netconn and if it is in a correct state
1790*5d5fbe79SDavid van Moolenbroek       (LISTEN doesn't support half shutdown) */
1791*5d5fbe79SDavid van Moolenbroek   if ((msg->conn->pcb.tcp != NULL) &&
1792*5d5fbe79SDavid van Moolenbroek       (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) &&
1793*5d5fbe79SDavid van Moolenbroek       ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) {
1794*5d5fbe79SDavid van Moolenbroek     /* Check if we are in a connected state */
1795*5d5fbe79SDavid van Moolenbroek     if (state == NETCONN_CONNECT) {
1796*5d5fbe79SDavid van Moolenbroek       /* TCP connect in progress: cannot shutdown */
1797*5d5fbe79SDavid van Moolenbroek       msg->err = ERR_CONN;
1798*5d5fbe79SDavid van Moolenbroek     } else if (state == NETCONN_WRITE) {
1799*5d5fbe79SDavid van Moolenbroek #if LWIP_NETCONN_FULLDUPLEX
1800*5d5fbe79SDavid van Moolenbroek       if (msg->msg.sd.shut & NETCONN_SHUT_WR) {
1801*5d5fbe79SDavid van Moolenbroek         /* close requested, abort running write */
1802*5d5fbe79SDavid van Moolenbroek         sys_sem_t* write_completed_sem;
1803*5d5fbe79SDavid van Moolenbroek         LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
1804*5d5fbe79SDavid van Moolenbroek         write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
1805*5d5fbe79SDavid van Moolenbroek         msg->conn->current_msg->err = ERR_CLSD;
1806*5d5fbe79SDavid van Moolenbroek         msg->conn->current_msg = NULL;
1807*5d5fbe79SDavid van Moolenbroek         msg->conn->state = NETCONN_NONE;
1808*5d5fbe79SDavid van Moolenbroek         state = NETCONN_NONE;
1809*5d5fbe79SDavid van Moolenbroek         NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD);
1810*5d5fbe79SDavid van Moolenbroek         sys_sem_signal(write_completed_sem);
1811*5d5fbe79SDavid van Moolenbroek       } else {
1812*5d5fbe79SDavid van Moolenbroek         LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD);
1813*5d5fbe79SDavid van Moolenbroek         /* In this case, let the write continue and do not interfere with
1814*5d5fbe79SDavid van Moolenbroek            conn->current_msg or conn->state! */
1815*5d5fbe79SDavid van Moolenbroek         msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0);
1816*5d5fbe79SDavid van Moolenbroek       }
1817*5d5fbe79SDavid van Moolenbroek     }
1818*5d5fbe79SDavid van Moolenbroek     if (state == NETCONN_NONE) {
1819*5d5fbe79SDavid van Moolenbroek #else /* LWIP_NETCONN_FULLDUPLEX */
1820*5d5fbe79SDavid van Moolenbroek       msg->err = ERR_INPROGRESS;
1821*5d5fbe79SDavid van Moolenbroek     } else {
1822*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_NETCONN_FULLDUPLEX */
1823*5d5fbe79SDavid van Moolenbroek       if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
1824*5d5fbe79SDavid van Moolenbroek         /* Drain and delete mboxes */
1825*5d5fbe79SDavid van Moolenbroek         netconn_drain(msg->conn);
1826*5d5fbe79SDavid van Moolenbroek       }
1827*5d5fbe79SDavid van Moolenbroek       LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL);
1828*5d5fbe79SDavid van Moolenbroek       msg->conn->state = NETCONN_CLOSE;
1829*5d5fbe79SDavid van Moolenbroek       msg->conn->current_msg = msg;
1830*5d5fbe79SDavid van Moolenbroek #if LWIP_TCPIP_CORE_LOCKING
1831*5d5fbe79SDavid van Moolenbroek       if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
1832*5d5fbe79SDavid van Moolenbroek         LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
1833*5d5fbe79SDavid van Moolenbroek         UNLOCK_TCPIP_CORE();
1834*5d5fbe79SDavid van Moolenbroek         sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1835*5d5fbe79SDavid van Moolenbroek         LOCK_TCPIP_CORE();
1836*5d5fbe79SDavid van Moolenbroek         LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1837*5d5fbe79SDavid van Moolenbroek       }
1838*5d5fbe79SDavid van Moolenbroek #else /* LWIP_TCPIP_CORE_LOCKING */
1839*5d5fbe79SDavid van Moolenbroek       lwip_netconn_do_close_internal(msg->conn);
1840*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCPIP_CORE_LOCKING */
1841*5d5fbe79SDavid van Moolenbroek       /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */
1842*5d5fbe79SDavid van Moolenbroek       return;
1843*5d5fbe79SDavid van Moolenbroek     }
1844*5d5fbe79SDavid van Moolenbroek   } else
1845*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_TCP */
1846*5d5fbe79SDavid van Moolenbroek   {
1847*5d5fbe79SDavid van Moolenbroek     msg->err = ERR_CONN;
1848*5d5fbe79SDavid van Moolenbroek   }
1849*5d5fbe79SDavid van Moolenbroek   TCPIP_APIMSG_ACK(msg);
1850*5d5fbe79SDavid van Moolenbroek }
1851*5d5fbe79SDavid van Moolenbroek 
1852*5d5fbe79SDavid van Moolenbroek #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
1853*5d5fbe79SDavid van Moolenbroek /**
1854*5d5fbe79SDavid van Moolenbroek  * Join multicast groups for UDP netconns.
1855*5d5fbe79SDavid van Moolenbroek  * Called from netconn_join_leave_group
1856*5d5fbe79SDavid van Moolenbroek  *
1857*5d5fbe79SDavid van Moolenbroek  * @param m the api_msg_msg pointing to the connection
1858*5d5fbe79SDavid van Moolenbroek  */
1859*5d5fbe79SDavid van Moolenbroek void
1860*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_join_leave_group(void *m)
1861*5d5fbe79SDavid van Moolenbroek {
1862*5d5fbe79SDavid van Moolenbroek   struct api_msg *msg = (struct api_msg*)m;
1863*5d5fbe79SDavid van Moolenbroek 
1864*5d5fbe79SDavid van Moolenbroek   if (ERR_IS_FATAL(msg->conn->last_err)) {
1865*5d5fbe79SDavid van Moolenbroek     msg->err = msg->conn->last_err;
1866*5d5fbe79SDavid van Moolenbroek   } else {
1867*5d5fbe79SDavid van Moolenbroek     if (msg->conn->pcb.tcp != NULL) {
1868*5d5fbe79SDavid van Moolenbroek       if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1869*5d5fbe79SDavid van Moolenbroek #if LWIP_UDP
1870*5d5fbe79SDavid van Moolenbroek #if LWIP_IPV6 && LWIP_IPV6_MLD
1871*5d5fbe79SDavid van Moolenbroek         if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
1872*5d5fbe79SDavid van Moolenbroek           if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
1873*5d5fbe79SDavid van Moolenbroek             msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
1874*5d5fbe79SDavid van Moolenbroek               ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
1875*5d5fbe79SDavid van Moolenbroek           } else {
1876*5d5fbe79SDavid van Moolenbroek             msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
1877*5d5fbe79SDavid van Moolenbroek               ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
1878*5d5fbe79SDavid van Moolenbroek           }
1879*5d5fbe79SDavid van Moolenbroek         }
1880*5d5fbe79SDavid van Moolenbroek         else
1881*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
1882*5d5fbe79SDavid van Moolenbroek         {
1883*5d5fbe79SDavid van Moolenbroek #if LWIP_IGMP
1884*5d5fbe79SDavid van Moolenbroek           if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
1885*5d5fbe79SDavid van Moolenbroek             msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
1886*5d5fbe79SDavid van Moolenbroek               ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
1887*5d5fbe79SDavid van Moolenbroek           } else {
1888*5d5fbe79SDavid van Moolenbroek             msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
1889*5d5fbe79SDavid van Moolenbroek               ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
1890*5d5fbe79SDavid van Moolenbroek           }
1891*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_IGMP */
1892*5d5fbe79SDavid van Moolenbroek         }
1893*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_UDP */
1894*5d5fbe79SDavid van Moolenbroek #if (LWIP_TCP || LWIP_RAW)
1895*5d5fbe79SDavid van Moolenbroek       } else {
1896*5d5fbe79SDavid van Moolenbroek         msg->err = ERR_VAL;
1897*5d5fbe79SDavid van Moolenbroek #endif /* (LWIP_TCP || LWIP_RAW) */
1898*5d5fbe79SDavid van Moolenbroek       }
1899*5d5fbe79SDavid van Moolenbroek     } else {
1900*5d5fbe79SDavid van Moolenbroek       msg->err = ERR_CONN;
1901*5d5fbe79SDavid van Moolenbroek     }
1902*5d5fbe79SDavid van Moolenbroek   }
1903*5d5fbe79SDavid van Moolenbroek   TCPIP_APIMSG_ACK(msg);
1904*5d5fbe79SDavid van Moolenbroek }
1905*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
1906*5d5fbe79SDavid van Moolenbroek 
1907*5d5fbe79SDavid van Moolenbroek #if LWIP_DNS
1908*5d5fbe79SDavid van Moolenbroek /**
1909*5d5fbe79SDavid van Moolenbroek  * Callback function that is called when DNS name is resolved
1910*5d5fbe79SDavid van Moolenbroek  * (or on timeout). A waiting application thread is waked up by
1911*5d5fbe79SDavid van Moolenbroek  * signaling the semaphore.
1912*5d5fbe79SDavid van Moolenbroek  */
1913*5d5fbe79SDavid van Moolenbroek static void
1914*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg)
1915*5d5fbe79SDavid van Moolenbroek {
1916*5d5fbe79SDavid van Moolenbroek   struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1917*5d5fbe79SDavid van Moolenbroek 
1918*5d5fbe79SDavid van Moolenbroek   /* we trust the internal implementation to be correct :-) */
1919*5d5fbe79SDavid van Moolenbroek   LWIP_UNUSED_ARG(name);
1920*5d5fbe79SDavid van Moolenbroek 
1921*5d5fbe79SDavid van Moolenbroek   if (ipaddr == NULL) {
1922*5d5fbe79SDavid van Moolenbroek     /* timeout or memory error */
1923*5d5fbe79SDavid van Moolenbroek     API_EXPR_DEREF(msg->err) = ERR_VAL;
1924*5d5fbe79SDavid van Moolenbroek   } else {
1925*5d5fbe79SDavid van Moolenbroek     /* address was resolved */
1926*5d5fbe79SDavid van Moolenbroek     API_EXPR_DEREF(msg->err) = ERR_OK;
1927*5d5fbe79SDavid van Moolenbroek     API_EXPR_DEREF(msg->addr) = *ipaddr;
1928*5d5fbe79SDavid van Moolenbroek   }
1929*5d5fbe79SDavid van Moolenbroek   /* wake up the application task waiting in netconn_gethostbyname */
1930*5d5fbe79SDavid van Moolenbroek   sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
1931*5d5fbe79SDavid van Moolenbroek }
1932*5d5fbe79SDavid van Moolenbroek 
1933*5d5fbe79SDavid van Moolenbroek /**
1934*5d5fbe79SDavid van Moolenbroek  * Execute a DNS query
1935*5d5fbe79SDavid van Moolenbroek  * Called from netconn_gethostbyname
1936*5d5fbe79SDavid van Moolenbroek  *
1937*5d5fbe79SDavid van Moolenbroek  * @param arg the dns_api_msg pointing to the query
1938*5d5fbe79SDavid van Moolenbroek  */
1939*5d5fbe79SDavid van Moolenbroek void
1940*5d5fbe79SDavid van Moolenbroek lwip_netconn_do_gethostbyname(void *arg)
1941*5d5fbe79SDavid van Moolenbroek {
1942*5d5fbe79SDavid van Moolenbroek   struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1943*5d5fbe79SDavid van Moolenbroek   u8_t addrtype =
1944*5d5fbe79SDavid van Moolenbroek #if LWIP_IPV4 && LWIP_IPV6
1945*5d5fbe79SDavid van Moolenbroek     msg->dns_addrtype;
1946*5d5fbe79SDavid van Moolenbroek #else
1947*5d5fbe79SDavid van Moolenbroek     LWIP_DNS_ADDRTYPE_DEFAULT;
1948*5d5fbe79SDavid van Moolenbroek #endif
1949*5d5fbe79SDavid van Moolenbroek 
1950*5d5fbe79SDavid van Moolenbroek   API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name,
1951*5d5fbe79SDavid van Moolenbroek     API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype);
1952*5d5fbe79SDavid van Moolenbroek   if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) {
1953*5d5fbe79SDavid van Moolenbroek     /* on error or immediate success, wake up the application
1954*5d5fbe79SDavid van Moolenbroek      * task waiting in netconn_gethostbyname */
1955*5d5fbe79SDavid van Moolenbroek     sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
1956*5d5fbe79SDavid van Moolenbroek   }
1957*5d5fbe79SDavid van Moolenbroek }
1958*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_DNS */
1959*5d5fbe79SDavid van Moolenbroek 
1960*5d5fbe79SDavid van Moolenbroek #endif /* LWIP_NETCONN */
1961