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