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