1 /**
2 * @file
3 * Sequential API Internal module
4 *
5 */
6
7 /*
8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31 * OF SUCH DAMAGE.
32 *
33 * This file is part of the lwIP TCP/IP stack.
34 *
35 * Author: Adam Dunkels <adam@sics.se>
36 *
37 */
38
39 #include "lwip/opt.h"
40
41 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
42
43 #include "lwip/priv/api_msg.h"
44
45 #include "lwip/ip.h"
46 #include "lwip/ip_addr.h"
47 #include "lwip/udp.h"
48 #include "lwip/tcp.h"
49 #include "lwip/raw.h"
50
51 #include "lwip/memp.h"
52 #include "lwip/igmp.h"
53 #include "lwip/dns.h"
54 #include "lwip/mld6.h"
55 #include "lwip/priv/tcpip_priv.h"
56 #include "netif/etharp.h"
57
58 #include <string.h>
59
60 /* netconns are polled once per second (e.g. continue write on memory error) */
61 #define NETCONN_TCP_POLL_INTERVAL 2
62
63 #define SET_NONBLOCKING_CONNECT(conn, val) do { if (val) { \
64 netconn_set_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); \
65 } else { \
66 netconn_clear_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); }} while(0)
67 #define IN_NONBLOCKING_CONNECT(conn) netconn_is_flag_set(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT)
68
69 #if LWIP_NETCONN_FULLDUPLEX
70 #define NETCONN_MBOX_VALID(conn, mbox) (sys_mbox_valid(mbox) && ((conn->flags & NETCONN_FLAG_MBOXINVALID) == 0))
71 #else
72 #define NETCONN_MBOX_VALID(conn, mbox) sys_mbox_valid(mbox)
73 #endif
74
75 /* forward declarations */
76 #if LWIP_TCP
77 #if LWIP_TCPIP_CORE_LOCKING
78 #define WRITE_DELAYED , 1
79 #define WRITE_DELAYED_PARAM , u8_t delayed
80 #else /* LWIP_TCPIP_CORE_LOCKING */
81 #define WRITE_DELAYED
82 #define WRITE_DELAYED_PARAM
83 #endif /* LWIP_TCPIP_CORE_LOCKING */
84 static err_t lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM);
85 static err_t lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM);
86 #endif
87
88 static void netconn_drain(struct netconn *conn);
89
90 #if LWIP_TCPIP_CORE_LOCKING
91 #define TCPIP_APIMSG_ACK(m) NETCONN_SET_SAFE_ERR((m)->conn, (m)->err)
92 #else /* LWIP_TCPIP_CORE_LOCKING */
93 #define TCPIP_APIMSG_ACK(m) do { \
94 NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); \
95 sys_sem_signal(LWIP_API_MSG_SEM(m)); \
96 } while (0)
97 #endif /* LWIP_TCPIP_CORE_LOCKING */
98
99 #if LWIP_NETCONN_FULLDUPLEX
100 const u8_t netconn_deleted = 0;
101
102 int
lwip_netconn_is_deallocated_msg(void * msg)103 lwip_netconn_is_deallocated_msg(void *msg)
104 {
105 if (msg == &netconn_deleted) {
106 return 1;
107 }
108 return 0;
109 }
110 #endif /* LWIP_NETCONN_FULLDUPLEX */
111
112 #if LWIP_TCP
113 const u8_t netconn_aborted = 0;
114 const u8_t netconn_reset = 0;
115 const u8_t netconn_closed = 0;
116
117 /** Translate an error to a unique void* passed via an mbox */
118 static void *
lwip_netconn_err_to_msg(err_t err)119 lwip_netconn_err_to_msg(err_t err)
120 {
121 switch (err) {
122 case ERR_ABRT:
123 return LWIP_CONST_CAST(void *, &netconn_aborted);
124 case ERR_RST:
125 return LWIP_CONST_CAST(void *, &netconn_reset);
126 case ERR_CLSD:
127 return LWIP_CONST_CAST(void *, &netconn_closed);
128 default:
129 LWIP_ASSERT("unhandled error", err == ERR_OK);
130 return NULL;
131 }
132 }
133
134 int
lwip_netconn_is_err_msg(void * msg,err_t * err)135 lwip_netconn_is_err_msg(void *msg, err_t *err)
136 {
137 LWIP_ASSERT("err != NULL", err != NULL);
138
139 if (msg == &netconn_aborted) {
140 *err = ERR_ABRT;
141 return 1;
142 } else if (msg == &netconn_reset) {
143 *err = ERR_RST;
144 return 1;
145 } else if (msg == &netconn_closed) {
146 *err = ERR_CLSD;
147 return 1;
148 }
149 return 0;
150 }
151 #endif /* LWIP_TCP */
152
153
154 #if LWIP_RAW
155
156 #ifndef IPPROTO_RAW
157 #define IPPROTO_RAW 255
158 #endif
159
160 /**
161 * Receive callback function for RAW netconns.
162 * Doesn't 'eat' the packet, only copies it and sends it to
163 * conn->recvmbox
164 *
165 * @see raw.h (struct raw_pcb.recv) for parameters and return value
166 */
167 static u8_t
recv_raw(void * arg,struct raw_pcb * pcb,struct pbuf * p,const ip_addr_t * addr)168 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
169 const ip_addr_t *addr)
170 {
171 struct pbuf *q;
172 struct netbuf *buf;
173 struct netconn *conn;
174 #if LWIP_SO_RCVBUF
175 int recv_avail;
176 #endif
177 #if LWIP_SOCK_FILTER && PF_PKT_SUPPORT
178 s32_t ret_filter;
179 #endif /* LWIP_SOCK_FILTER && PF_PKT_SUPPORT */
180
181 LWIP_UNUSED_ARG(addr);
182 conn = (struct netconn *)arg;
183
184 if ((conn != NULL) && NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
185 #if LWIP_SOCK_FILTER && PF_PKT_SUPPORT
186 /* do filter at the very beginning to make decision to accept or drop packets */
187 if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_PKT_RAW) && (conn->sk_filter.filter) &&
188 (pbuf_header(p, -ETH_PAD_SIZE) == 0)) {
189 /* drop the PAD size bytes */
190 ret_filter = sock_filter(conn, p);
191 (void)pbuf_header(p, ETH_PAD_SIZE);
192 if (ret_filter == EPERM) {
193 return 0;
194 }
195 }
196 #endif /* LWIP_SOCK_FILTER && PF_PKT_SUPPORT */
197 #if LWIP_SO_RCVBUF
198 SYS_ARCH_GET(conn->recv_avail, recv_avail);
199 if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
200 return 0;
201 }
202 #endif /* LWIP_SO_RCVBUF */
203 /* copy the whole packet into new pbufs */
204 q = pbuf_clone(PBUF_RAW, PBUF_RAM, p);
205 if (q != NULL) {
206 u16_t len;
207 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
208 if (buf == NULL) {
209 pbuf_free(q);
210 return 0;
211 }
212
213 #if PF_PKT_SUPPORT
214 /* To get the pkt type filtered in ethernet_input */
215 q->flags = p->flags;
216 #if ETH_PAD_SIZE
217 /* exclude the begining two padding bytes in struct eth_hdr */
218 if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_PKT_RAW) && (pbuf_header(q, -ETH_PAD_SIZE))) {
219 (void)pbuf_free(q);
220 memp_free(MEMP_NETBUF, buf);
221 return 0;
222 }
223 #endif
224 #endif
225
226 buf->p = q;
227 buf->ptr = q;
228 #if PF_PKT_SUPPORT
229 /* IP addr is NULL only when RAW packets are received for PF_PACKET sockets */
230 if (addr == NULL) {
231 ip_addr_set_any(IP_IS_V6_VAL(buf->addr), &buf->addr);
232 buf->port = eth_current_hdr()->type;
233 buf->hatype = eth_current_netif()->link_layer_type;
234 buf->netifindex = eth_current_netif()->ifindex;
235 } else {
236 ip_addr_copy(buf->addr, *ip_current_src_addr());
237 buf->port = pcb->raw_proto;
238 }
239 #else
240 ip_addr_copy(buf->addr, *ip_current_src_addr());
241 buf->port = pcb->protocol;
242 #endif
243
244 len = q->tot_len;
245 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
246 netbuf_delete(buf);
247 return 0;
248 } else {
249 #if LWIP_SO_RCVBUF
250 SYS_ARCH_INC(conn->recv_avail, len);
251 #endif /* LWIP_SO_RCVBUF */
252 /* Register event with callback */
253 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
254 return 1;
255 }
256 }
257 }
258
259 return 0; /* do not eat the packet */
260 }
261 #endif /* LWIP_RAW*/
262
263 #if LWIP_UDP
264 /**
265 * Receive callback function for UDP netconns.
266 * Posts the packet to conn->recvmbox or deletes it on memory error.
267 *
268 * @see udp.h (struct udp_pcb.recv) for parameters
269 */
270 void
recv_udp(void * arg,struct udp_pcb * pcb,struct pbuf * p,const ip_addr_t * addr,u16_t port)271 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
272 const ip_addr_t *addr, u16_t port)
273 {
274 struct netbuf *buf;
275 struct netconn *conn;
276 u16_t len;
277 #if LWIP_SO_RCVBUF
278 int recv_avail;
279 #endif /* LWIP_SO_RCVBUF */
280
281 LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
282 LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
283 LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
284 conn = (struct netconn *)arg;
285
286 if (conn == NULL) {
287 pbuf_free(p);
288 return;
289 }
290
291 LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
292
293 #if LWIP_SO_RCVBUF
294 SYS_ARCH_GET(conn->recv_avail, recv_avail);
295 if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox) ||
296 ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
297 #else /* LWIP_SO_RCVBUF */
298 if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
299 #endif /* LWIP_SO_RCVBUF */
300 pbuf_free(p);
301 return;
302 }
303
304 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
305 if (buf == NULL) {
306 pbuf_free(p);
307 return;
308 } else {
309 buf->p = p;
310 buf->ptr = p;
311 ip_addr_set(&buf->addr, addr);
312 buf->port = port;
313 #if LWIP_NETBUF_RECVINFO
314 if (conn->flags & NETCONN_FLAG_PKTINFO) {
315 /* get the UDP header - always in the first pbuf, ensured by udp_input */
316 const struct udp_hdr *udphdr = (const struct udp_hdr *)ip_next_header_ptr();
317 buf->flags = NETBUF_FLAG_DESTADDR;
318 ip_addr_set(&buf->toaddr, ip_current_dest_addr());
319 buf->toport_chksum = udphdr->dest;
320 }
321 #endif /* LWIP_NETBUF_RECVINFO */
322 }
323
324 len = p->tot_len;
325 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
326 netbuf_delete(buf);
327 return;
328 } else {
329 #if LWIP_SO_RCVBUF
330 SYS_ARCH_INC(conn->recv_avail, len);
331 #endif /* LWIP_SO_RCVBUF */
332 /* Register event with callback */
333 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
334 }
335 }
336 #endif /* LWIP_UDP */
337
338 #if LWIP_TCP
339 /**
340 * Receive callback function for TCP netconns.
341 * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
342 *
343 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
344 */
345 static err_t
346 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
347 {
348 struct netconn *conn;
349 u16_t len;
350 void *msg;
351
352 LWIP_UNUSED_ARG(pcb);
353 LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
354 LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
355 LWIP_ASSERT("err != ERR_OK unhandled", err == ERR_OK);
356 LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */
357 conn = (struct netconn *)arg;
358
359 if (conn == NULL) {
360 return ERR_VAL;
361 }
362 LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
363
364 if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
365 /* recvmbox already deleted */
366 if (p != NULL) {
367 tcp_recved(pcb, p->tot_len);
368 pbuf_free(p);
369 }
370 return ERR_OK;
371 }
372 /* Unlike for UDP or RAW pcbs, don't check for available space
373 using recv_avail since that could break the connection
374 (data is already ACKed) */
375
376 if (p != NULL) {
377 msg = p;
378 len = p->tot_len;
379 } else {
380 conn->shutdown = RCV_SHUTDOWN;
381 msg = LWIP_CONST_CAST(void *, &netconn_closed);
382 len = 0;
383 }
384
385 if (sys_mbox_trypost(&conn->recvmbox, msg) != ERR_OK) {
386 /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
387 return ERR_MEM;
388 } else {
389 #if LWIP_SO_RCVBUF
390 SYS_ARCH_INC(conn->recv_avail, len);
391 #endif /* LWIP_SO_RCVBUF */
392 /* Register event with callback */
393 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
394 }
395
396 return ERR_OK;
397 }
398
399 /**
400 * Poll callback function for TCP netconns.
401 * Wakes up an application thread that waits for a connection to close
402 * or data to be sent. The application thread then takes the
403 * appropriate action to go on.
404 *
405 * Signals the conn->sem.
406 * netconn_close waits for conn->sem if closing failed.
407 *
408 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
409 */
410 static err_t
411 poll_tcp(void *arg, struct tcp_pcb *pcb)
412 {
413 struct netconn *conn = (struct netconn *)arg;
414
415 LWIP_UNUSED_ARG(pcb);
416 LWIP_ASSERT("conn != NULL", (conn != NULL));
417
418 if (conn->state == NETCONN_WRITE) {
419 lwip_netconn_do_writemore(conn WRITE_DELAYED);
420 } else if (conn->state == NETCONN_CLOSE) {
421 #if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER
422 if (conn->current_msg && conn->current_msg->msg.sd.polls_left) {
423 conn->current_msg->msg.sd.polls_left--;
424 }
425 #endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */
426 lwip_netconn_do_close_internal(conn WRITE_DELAYED);
427 }
428 /* @todo: implement connect timeout here? */
429
430 /* Did a nonblocking write fail before? Then check available write-space. */
431 if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
432 /* If the queued byte- or pbuf-count drops below the configured low-water limit,
433 let select mark this pcb as writable again. */
434 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
435 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
436 netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE);
437 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
438 }
439 }
440
441 return ERR_OK;
442 }
443
444 #if LWIP_LOWPOWER
445 /* check wether need to poll tcp */
446 u8_t
447 poll_tcp_needed(void *arg, struct tcp_pcb *pcb)
448 {
449 struct netconn *conn = (struct netconn *)arg;
450 u8_t ret = 0;
451
452 LWIP_UNUSED_ARG(pcb);
453 if (conn == NULL) {
454 return 0;
455 }
456 if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) {
457 ret = 1;
458 }
459
460 /* Did a nonblocking write fail before? Then check available write-space. */
461 if ((conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) != 0) {
462 /* If the queued byte- or pbuf-count drops below the configured low-water limit,
463 let select mark this pcb as writable again. */
464 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > conn->pcb.tcp->snd_buf_lowat) &&
465 (tcp_sndqueuelen(conn->pcb.tcp) < conn->pcb.tcp->snd_queuelen_lowat)) {
466 ret = 1;
467 }
468 }
469 return ret;
470 }
471 #endif /* LWIP_LOWPOWER */
472
473 /**
474 * Sent callback function for TCP netconns.
475 * Signals the conn->sem and calls API_EVENT.
476 * netconn_write waits for conn->sem if send buffer is low.
477 *
478 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
479 */
480 static err_t
481 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
482 {
483 struct netconn *conn = (struct netconn *)arg;
484
485 LWIP_UNUSED_ARG(pcb);
486 LWIP_ASSERT("conn != NULL", (conn != NULL));
487
488 if (conn) {
489 if (conn->state == NETCONN_WRITE) {
490 lwip_netconn_do_writemore(conn WRITE_DELAYED);
491 } else if (conn->state == NETCONN_CLOSE) {
492 lwip_netconn_do_close_internal(conn WRITE_DELAYED);
493 }
494
495 /* If the queued byte- or pbuf-count drops below the configured low-water limit,
496 let select mark this pcb as writable again. */
497 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
498 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
499 netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE);
500 API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
501 }
502 }
503
504 return ERR_OK;
505 }
506
507 /**
508 * Error callback function for TCP netconns.
509 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
510 * The application thread has then to decide what to do.
511 *
512 * @see tcp.h (struct tcp_pcb.err) for parameters
513 */
514 static void
515 err_tcp(void *arg, err_t err)
516 {
517 struct netconn *conn;
518 enum netconn_state old_state;
519 void *mbox_msg;
520 SYS_ARCH_DECL_PROTECT(lev);
521
522 conn = (struct netconn *)arg;
523 LWIP_ASSERT("conn != NULL", (conn != NULL));
524
525 SYS_ARCH_PROTECT(lev);
526
527 if (err == ERR_RST) {
528 conn->refused_data = conn->pcb.tcp->refused_data;
529 conn->pcb.tcp->refused_data = NULL;
530 conn->pending_err = NETCONN_PENDING_ERR_RST;
531 }
532
533 if (conn->pcb.tcp->tcp_pcb_flag & TCP_PBUF_FLAG_TCP_FIN_RECV_SYSPOST_FAIL) {
534 conn->pending_err = NETCONN_PENDING_ERR_FIN_RST;
535 }
536
537 /* when err is called, the pcb is deallocated, so delete the reference */
538 conn->pcb.tcp = NULL;
539 /* store pending error */
540 conn->last_err = err;
541 /* prevent application threads from blocking on 'recvmbox'/'acceptmbox' */
542 conn->flags |= NETCONN_FLAG_MBOXCLOSED;
543
544 /* reset conn->state now before waking up other threads */
545 old_state = conn->state;
546 conn->state = NETCONN_NONE;
547
548 /* close both direction for tcp connection in err state */
549 conn->shutdown = SHUTDOWN_MASK;
550
551 if (old_state == NETCONN_CLOSE) {
552 /* RST during close: let close return success & dealloc the netconn */
553 err = ERR_OK;
554 NETCONN_SET_SAFE_ERR_VAL(conn, ERR_OK);
555 } else {
556 /* no check since this is always fatal! */
557 SYS_ARCH_SET(conn->last_err, err);
558 }
559
560 SYS_ARCH_UNPROTECT(lev);
561
562 /* Notify the user layer about a connection error. Used to signal select. */
563 API_EVENT(conn, NETCONN_EVT_ERROR, 0);
564 /* Try to release selects pending on 'read' or 'write', too.
565 They will get an error if they actually try to read or write. */
566 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
567 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
568
569 mbox_msg = lwip_netconn_err_to_msg(err);
570 /* pass error message to recvmbox to wake up pending recv */
571 if (NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
572 /* use trypost to prevent deadlock */
573 /* [Bug: 50912] No need to worry about whether post is success or not here.
574 * Scenario 1) When DATA is already made the recvmbox full and RST is received.
575 * ----Flag pending_error is marked NETCONN_PENDING_ERR_RST which upon user calling
576 * recv() will ensure that the refused data will be given to user and the final recv() will
577 * return with -1 and errno -104
578 * Scenario 2) When DATA is already made the recvmbox full and FIN and RST is received (Both FIN post
579 * and RST post has failed)
580 * ---- Flag pending_error is marked NETCONN_PENDING_ERR_FIN_RST which upon user calling
581 * recv() will ensure that the refused data will be given to user and the subsequent first
582 * recv() will return 0 to user for FIN and mnest subsequent recv() will return with -1
583 * and errno -104
584 */
585 sys_mbox_trypost(&conn->recvmbox, mbox_msg);
586 }
587 /* pass error message to acceptmbox to wake up pending accept */
588 if (NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) {
589 /* use trypost to preven deadlock */
590 sys_mbox_trypost(&conn->acceptmbox, mbox_msg);
591 }
592
593 if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
594 (old_state == NETCONN_CONNECT)) {
595 /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary
596 since the pcb has already been deleted! */
597 int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
598 SET_NONBLOCKING_CONNECT(conn, 0);
599
600 if (!was_nonblocking_connect) {
601 sys_sem_t *op_completed_sem;
602 /* set error return code */
603 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
604 if (old_state == NETCONN_CLOSE) {
605 /* let close succeed: the connection is closed after all... */
606 conn->current_msg->err = ERR_OK;
607 } else {
608 /* Write and connect fail */
609 conn->current_msg->err = err;
610 }
611 op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
612 LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem));
613 conn->current_msg = NULL;
614 /* wake up the waiting task */
615 sys_sem_signal(op_completed_sem);
616 } else {
617 /* @todo: test what happens for error on nonblocking connect */
618 }
619 } else {
620 LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
621 }
622 }
623
624 #if DRIVER_STATUS_CHECK
625 void update_tcp_sndplus_event(void *arg, const struct tcp_pcb *pcb)
626 {
627 struct netconn *conn = (struct netconn *)arg;
628
629 LWIP_UNUSED_ARG(pcb);
630 LWIP_ASSERT("conn != NULL", (conn != NULL));
631
632 if (netconn_is_nonblocking(conn)) {
633 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
634 }
635 return;
636 }
637 #endif
638
639 /**
640 * Setup a tcp_pcb with the correct callback function pointers
641 * and their arguments.
642 *
643 * @param conn the TCP netconn to setup
644 */
645 static void
646 setup_tcp(struct netconn *conn)
647 {
648 struct tcp_pcb *pcb;
649
650 pcb = conn->pcb.tcp;
651 tcp_arg(pcb, conn);
652 tcp_recv(pcb, recv_tcp);
653 tcp_sent(pcb, sent_tcp);
654 tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL);
655 tcp_err(pcb, err_tcp);
656 #if DRIVER_STATUS_CHECK
657 pcb->sndplus = update_tcp_sndplus_event;
658 #endif
659 }
660
661 /**
662 * Accept callback function for TCP netconns.
663 * Allocates a new netconn and posts that to conn->acceptmbox.
664 *
665 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
666 */
667 static err_t
668 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
669 {
670 struct netconn *newconn;
671 struct netconn *conn = (struct netconn *)arg;
672
673 if (conn == NULL) {
674 return ERR_VAL;
675 }
676
677 if (NETCONNTYPE_GROUP(NETCONN_TYPE(conn)) != NETCONN_TCP) {
678 return ERR_VAL;
679 }
680
681 if (!NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) {
682 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
683 return ERR_VAL;
684 }
685
686 if (newpcb == NULL) {
687 /* out-of-pcbs during connect: pass on this error to the application */
688 if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) {
689 /* Register event with callback */
690 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
691 }
692 /* connection will be aborted here */
693 tcp_err(newpcb, NULL);
694 tcp_arg(newpcb, NULL);
695 return ERR_VAL;
696 }
697 LWIP_ASSERT("expect newpcb == NULL or err == ERR_OK", err == ERR_OK);
698 LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */
699
700 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->state: %s\n", tcp_debug_state_str(newpcb->state)));
701
702 /* We have to set the callback here even though
703 * the new socket is unknown. newconn->socket is marked as -1. */
704 newconn = netconn_alloc(conn->type, conn->callback);
705 if (newconn == NULL) {
706 /* outof netconns: pass on this error to the application */
707 if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) {
708 /* Register event with callback */
709 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
710 }
711 return ERR_MEM;
712 }
713 newconn->pcb.tcp = newpcb;
714 setup_tcp(newconn);
715 (void)atomic_set(&newconn->tcp_connected, 1);
716 /* no protection: when creating the pcb, the netconn is not yet known
717 to the application thread */
718 newconn->last_err = err;
719
720 ip_addr_copy(newconn->remote_ip, newpcb->remote_ip);
721 newconn->remote_port = newpcb->remote_port;
722
723 /* handle backlog counter */
724 tcp_backlog_delayed(newpcb);
725
726 if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
727 /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
728 so do nothing here! */
729 /* remove all references to this netconn from the pcb */
730 struct tcp_pcb *pcb = newconn->pcb.tcp;
731 tcp_arg(pcb, NULL);
732 tcp_recv(pcb, NULL);
733 tcp_sent(pcb, NULL);
734 tcp_poll(pcb, NULL, 0);
735 tcp_err(pcb, NULL);
736 /* remove reference from to the pcb from this netconn */
737 newconn->pcb.tcp = NULL;
738 /* no need to drain since we know the recvmbox is empty. */
739 sys_mbox_free(&newconn->recvmbox);
740 sys_mbox_set_invalid(&newconn->recvmbox);
741 netconn_free(newconn);
742 return ERR_MEM;
743 } else {
744 #if LWIP_SO_RCVBUF
745 SYS_ARCH_INC(conn->recv_avail, 1);
746 #endif /* LWIP_SO_RCVBUF */
747 /* Register event with callback */
748 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
749 }
750
751 return ERR_OK;
752 }
753 #endif /* LWIP_TCP */
754
755 /**
756 * Create a new pcb of a specific type.
757 * Called from lwip_netconn_do_newconn().
758 *
759 * @param msg the api_msg describing the connection type
760 */
761 static void
762 pcb_new(struct api_msg *msg)
763 {
764 enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4;
765
766 LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
767
768 #if LWIP_IPV6 && LWIP_IPV4
769 /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */
770 if (NETCONNTYPE_ISIPV6(NETCONN_TYPE(msg->conn))) {
771 iptype = IPADDR_TYPE_ANY;
772 }
773 #endif
774
775 /* Allocate a PCB for this connection */
776 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
777 #if LWIP_RAW
778 case NETCONN_RAW:
779 msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto);
780 if (msg->conn->pcb.raw != NULL) {
781 #if LWIP_IPV6
782 #if LWIP_SOCK_OPT_ICMP6_FILTER
783 /* rfc3542. Section: 3.2. ICMPv6 Type Filtering */
784 u32_t i;
785 for (i = 0; i < ICMP_FILTER_LENGTH; i++) {
786 msg->conn->pcb.raw->icmp6_filter.icmp6_filt[i] = 0x00;
787 }
788 #endif
789 /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */
790 if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->raw_proto == IP6_NEXTH_ICMP6) {
791 msg->conn->pcb.raw->chksum_reqd = 1;
792 msg->conn->pcb.raw->chksum_offset = RAW_CHKSUM_OFFSET;
793 }
794 #endif /* LWIP_IPV6 */
795
796 #if LWIP_IPV4
797 /* IP_HDRINCL is enabled by default */
798 if (!(NETCONNTYPE_ISIPV6(msg->conn->type)) && (msg->msg.n.proto == IPPROTO_RAW)) {
799 raw_set_flags(msg->conn->pcb.raw, RAW_FLAGS_HDRINCL);
800 }
801 #endif
802 #if LWIP_SO_PRIORITY
803 msg->conn->pcb.raw->priority = LWIP_PKT_PRIORITY_DEFAULT;
804 #endif /* LWIP_SO_PRIORITY */
805 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
806 }
807 break;
808
809 #if PF_PKT_SUPPORT
810 case NETCONN_PKT_RAW:
811 msg->conn->pcb.pkt_raw = raw_pkt_new(msg->msg.n.proto);
812 if (msg->conn->pcb.pkt_raw == NULL) {
813 msg->err = ERR_MEM;
814 break;
815 }
816 raw_recv(msg->conn->pcb.pkt_raw, recv_raw, msg->conn);
817 break;
818 #endif
819 #endif /* LWIP_RAW */
820 #if LWIP_UDP
821 case NETCONN_UDP:
822 msg->conn->pcb.udp = udp_new_ip_type(iptype);
823 if (msg->conn->pcb.udp != NULL) {
824 #if LWIP_UDPLITE
825 if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
826 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
827 }
828 #endif /* LWIP_UDPLITE */
829 if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) {
830 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
831 }
832 #if LWIP_SO_PRIORITY
833 msg->conn->pcb.udp->priority = LWIP_PKT_PRIORITY_DEFAULT;
834 #endif /* LWIP_SO_PRIORITY */
835
836 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
837 }
838 break;
839 #endif /* LWIP_UDP */
840 #if LWIP_TCP
841 case NETCONN_TCP:
842 msg->conn->pcb.tcp = tcp_new_ip_type(iptype);
843 if (msg->conn->pcb.tcp != NULL) {
844 #if LWIP_SO_PRIORITY
845 msg->conn->pcb.tcp->priority = LWIP_PKT_PRIORITY_DEFAULT;
846 #endif /* LWIP_SO_PRIORITY */
847
848 setup_tcp(msg->conn);
849 }
850 break;
851 #endif /* LWIP_TCP */
852 default:
853 /* Unsupported netconn type, e.g. protocol disabled */
854 msg->err = ERR_VAL;
855 return;
856 }
857 if (msg->conn->pcb.ip == NULL) {
858 msg->err = ERR_MEM;
859 }
860 }
861
862 /**
863 * Create a new pcb of a specific type inside a netconn.
864 * Called from netconn_new_with_proto_and_callback.
865 *
866 * @param m the api_msg describing the connection type
867 */
868 void
869 lwip_netconn_do_newconn(void *m)
870 {
871 struct api_msg *msg = (struct api_msg *)m;
872
873 msg->err = ERR_OK;
874 if (msg->conn->pcb.tcp == NULL) {
875 pcb_new(msg);
876 }
877 /* Else? This "new" connection already has a PCB allocated. */
878 /* Is this an error condition? Should it be deleted? */
879 /* We currently just are happy and return. */
880
881 TCPIP_APIMSG_ACK(msg);
882 }
883
884 /**
885 * Create a new netconn (of a specific type) that has a callback function.
886 * The corresponding pcb is NOT created!
887 *
888 * @param t the type of 'connection' to create (@see enum netconn_type)
889 * @param callback a function to call on status changes (RX available, TX'ed)
890 * @return a newly allocated struct netconn or
891 * NULL on memory error
892 */
893 struct netconn *
894 netconn_alloc(enum netconn_type t, netconn_callback callback)
895 {
896 struct netconn *conn;
897 int size;
898 u8_t init_flags = 0;
899
900 conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
901 if (conn == NULL) {
902 return NULL;
903 }
904
905 conn->last_err = ERR_OK;
906 conn->type = t;
907 conn->pcb.tcp = NULL;
908 #if LWIP_NETCONN_FULLDUPLEX
909 conn->mbox_threads_waiting = 0;
910 #endif
911
912 /* If all sizes are the same, every compiler should optimize this switch to nothing */
913 switch (NETCONNTYPE_GROUP(t)) {
914 #if LWIP_RAW
915 #if PF_PKT_SUPPORT
916 case NETCONN_PKT_RAW:
917 #endif
918 case NETCONN_RAW:
919 size = DEFAULT_RAW_RECVMBOX_SIZE;
920 break;
921 #endif /* LWIP_RAW */
922 #if LWIP_UDP
923 case NETCONN_UDP:
924 size = DEFAULT_UDP_RECVMBOX_SIZE;
925 #if LWIP_NETBUF_RECVINFO
926 init_flags |= NETCONN_FLAG_PKTINFO;
927 #endif /* LWIP_NETBUF_RECVINFO */
928 break;
929 #endif /* LWIP_UDP */
930 #if LWIP_TCP
931 case NETCONN_TCP:
932 size = DEFAULT_TCP_RECVMBOX_SIZE;
933 break;
934 #endif /* LWIP_TCP */
935 default:
936 LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
937 goto free_and_return;
938 }
939
940 if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
941 goto free_and_return;
942 }
943 #if !LWIP_NETCONN_SEM_PER_THREAD
944 if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
945 sys_mbox_free(&conn->recvmbox);
946 goto free_and_return;
947 }
948 #endif
949
950 #if LWIP_TCP
951 sys_mbox_set_invalid(&conn->acceptmbox);
952 #endif
953 conn->state = NETCONN_NONE;
954 #if LWIP_SOCKET
955 /* initialize socket to -1 since 0 is a valid socket */
956 conn->socket = -1;
957 #endif /* LWIP_SOCKET */
958 conn->callback = callback;
959 #if LWIP_TCP
960 conn->current_msg = NULL;
961 conn->write_offset = 0;
962 (void)atomic_set(&conn->tcp_connected, 0);
963 #endif /* LWIP_TCP */
964 #if LWIP_SO_SNDTIMEO
965 conn->send_timeout = 0;
966 #endif /* LWIP_SO_SNDTIMEO */
967 #if LWIP_SO_RCVTIMEO
968 conn->recv_timeout = 0;
969 #endif /* LWIP_SO_RCVTIMEO */
970 #if LWIP_SO_RCVBUF
971 conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
972 conn->recv_avail = 0;
973 #endif /* LWIP_SO_RCVBUF */
974 #if LWIP_SO_LINGER
975 conn->linger = -1;
976 #endif /* LWIP_SO_LINGER */
977 conn->flags = init_flags;
978 conn->shutdown = NON_SHUTDOWN;
979
980 #if LWIP_SOCK_FILTER
981 conn->sk_filter.len = 0;
982 conn->sk_filter.filter = NULL;
983 #endif
984 #if LWIP_TCP
985 conn->pending_err = 0;
986 conn->refused_data = NULL;
987 ip_addr_set_zero(&conn->remote_ip);
988 conn->remote_port = 0;
989 #endif
990
991 return conn;
992 free_and_return:
993 memp_free(MEMP_NETCONN, conn);
994 return NULL;
995 }
996
997 /**
998 * Delete a netconn and all its resources.
999 * The pcb is NOT freed (since we might not be in the right thread context do this).
1000 *
1001 * @param conn the netconn to free
1002 */
1003 void
1004 netconn_free(struct netconn *conn)
1005 {
1006 LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
1007
1008 #if LWIP_NETCONN_FULLDUPLEX
1009 /* in fullduplex, netconn is drained here */
1010 netconn_drain(conn);
1011 #endif /* LWIP_NETCONN_FULLDUPLEX */
1012
1013 LWIP_ASSERT("recvmbox must be deallocated before calling this function",
1014 !sys_mbox_valid(&conn->recvmbox));
1015 #if LWIP_TCP
1016 LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
1017 !sys_mbox_valid(&conn->acceptmbox));
1018 #endif /* LWIP_TCP */
1019
1020 #if LWIP_TCP
1021 if (conn->refused_data != NULL) {
1022 (void)pbuf_free(conn->refused_data);
1023 conn->refused_data = NULL;
1024 }
1025 #endif
1026
1027 #if !LWIP_NETCONN_SEM_PER_THREAD
1028 sys_sem_free(&conn->op_completed);
1029 sys_sem_set_invalid(&conn->op_completed);
1030 #endif
1031 #if LWIP_SOCK_FILTER
1032 if (conn->sk_filter.filter != NULL) {
1033 mem_free(conn->sk_filter.filter);
1034 conn->sk_filter.filter = NULL;
1035 conn->sk_filter.len = 0;
1036 }
1037 #endif
1038
1039 memp_free(MEMP_NETCONN, conn);
1040 }
1041
1042 /**
1043 * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
1044 * these mboxes
1045 *
1046 * @param conn the netconn to free
1047 * @bytes_drained bytes drained from recvmbox
1048 * @accepts_drained pending connections drained from acceptmbox
1049 */
1050 static void
1051 netconn_drain(struct netconn *conn)
1052 {
1053 void *mem;
1054
1055 /* This runs when mbox and netconn are marked as closed,
1056 so we don't need to lock against rx packets */
1057 #if LWIP_NETCONN_FULLDUPLEX
1058 LWIP_ASSERT("netconn marked closed", conn->flags & NETCONN_FLAG_MBOXINVALID);
1059 #endif /* LWIP_NETCONN_FULLDUPLEX */
1060
1061 /* Delete and drain the recvmbox. */
1062 if (sys_mbox_valid(&conn->recvmbox)) {
1063 while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
1064 #if LWIP_NETCONN_FULLDUPLEX
1065 if (!lwip_netconn_is_deallocated_msg(mem))
1066 #endif /* LWIP_NETCONN_FULLDUPLEX */
1067 {
1068 #if LWIP_TCP
1069 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
1070 err_t err;
1071 if (!lwip_netconn_is_err_msg(mem, &err)) {
1072 pbuf_free((struct pbuf *)mem);
1073 }
1074 } else
1075 #endif /* LWIP_TCP */
1076 {
1077 netbuf_delete((struct netbuf *)mem);
1078 }
1079 }
1080 }
1081 sys_mbox_free(&conn->recvmbox);
1082 sys_mbox_set_invalid(&conn->recvmbox);
1083 }
1084
1085 /* Delete and drain the acceptmbox. */
1086 #if LWIP_TCP
1087 if (sys_mbox_valid(&conn->acceptmbox)) {
1088 while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
1089 #if LWIP_NETCONN_FULLDUPLEX
1090 if (!lwip_netconn_is_deallocated_msg(mem))
1091 #endif /* LWIP_NETCONN_FULLDUPLEX */
1092 {
1093 err_t err;
1094 if (!lwip_netconn_is_err_msg(mem, &err)) {
1095 struct netconn *newconn = (struct netconn *)mem;
1096 /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
1097 /* pcb might be set to NULL already by err_tcp() */
1098 /* drain recvmbox */
1099 netconn_drain(newconn);
1100 if (newconn->pcb.tcp != NULL) {
1101 tcp_abort(newconn->pcb.tcp);
1102 newconn->pcb.tcp = NULL;
1103 }
1104 netconn_free(newconn);
1105 }
1106 }
1107 }
1108 sys_mbox_free(&conn->acceptmbox);
1109 sys_mbox_set_invalid(&conn->acceptmbox);
1110 }
1111 #endif /* LWIP_TCP */
1112 }
1113
1114 #if LWIP_NETCONN_FULLDUPLEX
1115 static void
1116 netconn_mark_mbox_invalid(struct netconn *conn)
1117 {
1118 int i, num_waiting;
1119 void *msg = LWIP_CONST_CAST(void *, &netconn_deleted);
1120
1121 /* Prevent new calls/threads from reading from the mbox */
1122 conn->flags |= NETCONN_FLAG_MBOXINVALID;
1123
1124 SYS_ARCH_LOCKED(num_waiting = conn->mbox_threads_waiting);
1125 for (i = 0; i < num_waiting; i++) {
1126 if (sys_mbox_valid_val(conn->recvmbox)) {
1127 sys_mbox_trypost(&conn->recvmbox, msg);
1128 #if LWIP_TCP
1129 } else if (sys_mbox_valid_val(conn->acceptmbox)) {
1130 sys_mbox_trypost(&conn->acceptmbox, msg);
1131 #endif
1132 } else {
1133 LWIP_DEBUGF(API_MSG_DEBUG, ("warning: mbox already marked invalid\n"));
1134 }
1135 }
1136 }
1137 #endif /* LWIP_NETCONN_FULLDUPLEX */
1138
1139 #if LWIP_TCP
1140 /**
1141 * Internal helper function to close a TCP netconn: since this sometimes
1142 * doesn't work at the first attempt, this function is called from multiple
1143 * places.
1144 *
1145 * @param conn the TCP netconn to close
1146 */
1147 static err_t
1148 lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM)
1149 {
1150 err_t err;
1151 u8_t shut, shut_rx, shut_tx, shut_close;
1152 u8_t close_finished = 0;
1153 struct tcp_pcb *tpcb;
1154 #if LWIP_SO_LINGER
1155 u8_t linger_wait_required = 0;
1156 #endif /* LWIP_SO_LINGER */
1157
1158 LWIP_ASSERT("invalid conn", (conn != NULL));
1159 LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP));
1160 LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
1161 LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
1162 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
1163
1164 tpcb = conn->pcb.tcp;
1165 shut = conn->current_msg->msg.sd.shut;
1166 shut_rx = shut & NETCONN_SHUT_RD;
1167 shut_tx = shut & NETCONN_SHUT_WR;
1168 /* shutting down both ends is the same as closing
1169 (also if RD or WR side was shut down before already) */
1170 if (shut == NETCONN_SHUT_RDWR) {
1171 shut_close = 1;
1172 } else if (shut_rx &&
1173 ((tpcb->state == FIN_WAIT_1) ||
1174 (tpcb->state == FIN_WAIT_2) ||
1175 (tpcb->state == CLOSING) ||
1176 (tpcb->state == LAST_ACK) ||
1177 (((tpcb->state == SYN_RCVD) ||
1178 (tpcb->state == ESTABLISHED) ||
1179 (tpcb->state == CLOSE_WAIT)) &&
1180 (tpcb->flags & TF_CLOSEPEND)))) {
1181 shut_close = 1;
1182 } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) {
1183 shut_close = 1;
1184 } else {
1185 shut_close = 0;
1186 }
1187
1188 /* Set back some callback pointers */
1189 if (shut_close) {
1190 tcp_arg(tpcb, NULL);
1191 }
1192 if (tpcb->state == LISTEN) {
1193 tcp_accept(tpcb, NULL);
1194 } else {
1195 /* some callbacks have to be reset if tcp_close is not successful */
1196 if (shut_rx) {
1197 tcp_recv(tpcb, NULL);
1198 tcp_accept(tpcb, NULL);
1199 }
1200 if (shut_tx) {
1201 tcp_sent(tpcb, NULL);
1202 }
1203 if (shut_close) {
1204 tcp_poll(tpcb, NULL, 0);
1205 tcp_err(tpcb, NULL);
1206 }
1207 }
1208 /* Try to close the connection */
1209 if (shut_close) {
1210 #if LWIP_SO_LINGER
1211 /* check linger possibilites before calling tcp_close */
1212 err = ERR_OK;
1213 /* linger enabled/required at all? (i.e. is there untransmitted data left?) */
1214 if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) {
1215 if ((conn->linger == 0)) {
1216 /* data left but linger prevents waiting */
1217 tcp_abort(tpcb);
1218 tpcb = NULL;
1219 } else if (conn->linger > 0) {
1220 /* data left and linger says we should wait */
1221 if (netconn_is_nonblocking(conn)) {
1222 /* data left on a nonblocking netconn -> cannot linger */
1223 err = ERR_WOULDBLOCK;
1224 } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >=
1225 (conn->linger * 1000)) {
1226 /* data left but linger timeout has expired (this happens on further
1227 calls to this function through poll_tcp */
1228 tcp_abort(tpcb);
1229 tpcb = NULL;
1230 } else {
1231 /* data left -> need to wait for ACK after successful close */
1232 linger_wait_required = 1;
1233 }
1234 }
1235 }
1236 if ((err == ERR_OK) && (tpcb != NULL))
1237 #endif /* LWIP_SO_LINGER */
1238 {
1239 err = tcp_close(tpcb);
1240 }
1241 } else {
1242 err = tcp_shutdown(tpcb, shut_rx, shut_tx);
1243 }
1244 if (err == ERR_OK) {
1245 close_finished = 1;
1246 #if LWIP_SO_LINGER
1247 if (linger_wait_required) {
1248 /* wait for ACK of all unsent/unacked data by just getting called again */
1249 close_finished = 0;
1250 err = ERR_INPROGRESS;
1251 }
1252 #endif /* LWIP_SO_LINGER */
1253 } else {
1254 if (err == ERR_MEM) {
1255 /* Closing failed because of memory shortage, try again later. Even for
1256 nonblocking netconns, we have to wait since no standard socket application
1257 is prepared for close failing because of resource shortage.
1258 Check the timeout: this is kind of an lwip addition to the standard sockets:
1259 we wait for some time when failing to allocate a segment for the FIN */
1260 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
1261 s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT;
1262 #if LWIP_SO_SNDTIMEO
1263 if (conn->send_timeout > 0) {
1264 close_timeout = conn->send_timeout;
1265 }
1266 #endif /* LWIP_SO_SNDTIMEO */
1267 #if LWIP_SO_LINGER
1268 if (conn->linger >= 0) {
1269 /* use linger timeout (seconds) */
1270 close_timeout = conn->linger * 1000U;
1271 }
1272 #endif
1273 if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
1274 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1275 if (conn->current_msg->msg.sd.polls_left == 0) {
1276 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1277 close_finished = 1;
1278 if (shut_close) {
1279 /* in this case, we want to RST the connection */
1280 tcp_abort(tpcb);
1281 err = ERR_OK;
1282 }
1283 }
1284 } else {
1285 /* Closing failed for a non-memory error: give up */
1286 close_finished = 1;
1287 }
1288 }
1289 if (close_finished) {
1290 /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */
1291 sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1292 conn->current_msg->err = err;
1293 conn->current_msg = NULL;
1294 conn->state = NETCONN_NONE;
1295 if (err == ERR_OK) {
1296 if (shut_close) {
1297 /* Set back some callback pointers as conn is going away */
1298 conn->pcb.tcp = NULL;
1299 /* Trigger select() in socket layer. Make sure everybody notices activity
1300 on the connection, error first! */
1301 API_EVENT(conn, NETCONN_EVT_ERROR, 0);
1302 }
1303 if (shut_rx) {
1304 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
1305 }
1306 if (shut_tx) {
1307 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
1308 }
1309 }
1310 #if LWIP_TCPIP_CORE_LOCKING
1311 if (delayed)
1312 #endif
1313 {
1314 /* wake up the application task */
1315 sys_sem_signal(op_completed_sem);
1316 }
1317 return ERR_OK;
1318 }
1319 if (!close_finished) {
1320 /* Closing failed and we want to wait: restore some of the callbacks */
1321 /* Closing of listen pcb will never fail! */
1322 LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN));
1323 if (shut_tx) {
1324 tcp_sent(tpcb, sent_tcp);
1325 }
1326 /* when waiting for close, set up poll interval to 500ms */
1327 tcp_poll(tpcb, poll_tcp, 1);
1328 tcp_err(tpcb, err_tcp);
1329 tcp_arg(tpcb, conn);
1330 /* don't restore recv callback: we don't want to receive any more data */
1331 }
1332 /* If closing didn't succeed, we get called again either
1333 from poll_tcp or from sent_tcp */
1334 LWIP_ASSERT("err != ERR_OK", err != ERR_OK);
1335 return err;
1336 }
1337 #endif /* LWIP_TCP */
1338
1339 /**
1340 * Delete the pcb inside a netconn.
1341 * Called from netconn_delete.
1342 *
1343 * @param m the api_msg pointing to the connection
1344 */
1345 void
1346 lwip_netconn_do_delconn(void *m)
1347 {
1348 struct api_msg *msg = (struct api_msg *)m;
1349
1350 enum netconn_state state = msg->conn->state;
1351 LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */
1352 (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP));
1353 #if LWIP_NETCONN_FULLDUPLEX
1354 #if LWIP_TCP
1355 /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */
1356 if (state != NETCONN_NONE) {
1357 if ((state == NETCONN_WRITE) ||
1358 ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1359 /* close requested, abort running write/connect */
1360 if (msg->conn->current_msg != NULL) {
1361 sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
1362 msg->conn->current_msg->err = ERR_CLSD;
1363 msg->conn->current_msg = NULL;
1364 msg->conn->write_offset = 0;
1365 msg->conn->state = NETCONN_NONE;
1366 sys_sem_signal(op_completed_sem);
1367 }
1368 }
1369 }
1370 #endif /* LWIP_TCP */
1371 #else /* LWIP_NETCONN_FULLDUPLEX */
1372 if (((state != NETCONN_NONE) &&
1373 (state != NETCONN_LISTEN) &&
1374 (state != NETCONN_CONNECT)) ||
1375 ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1376 /* This means either a blocking write or blocking connect is running
1377 (nonblocking write returns and sets state to NONE) */
1378 msg->err = ERR_INPROGRESS;
1379 } else
1380 #endif /* LWIP_NETCONN_FULLDUPLEX */
1381 {
1382 LWIP_ASSERT("blocking connect in progress",
1383 (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
1384 msg->err = ERR_OK;
1385 #if LWIP_NETCONN_FULLDUPLEX
1386 /* Mark mboxes invalid */
1387 netconn_mark_mbox_invalid(msg->conn);
1388 #else /* LWIP_NETCONN_FULLDUPLEX */
1389 netconn_drain(msg->conn);
1390 #endif /* LWIP_NETCONN_FULLDUPLEX */
1391
1392 if (msg->conn->pcb.tcp != NULL) {
1393
1394 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1395 #if LWIP_RAW
1396 case NETCONN_RAW:
1397 raw_remove(msg->conn->pcb.raw);
1398 break;
1399 #if PF_PKT_SUPPORT
1400 case NETCONN_PKT_RAW:
1401 raw_pkt_remove(msg->conn->pcb.pkt_raw);
1402 break;
1403 #endif
1404 #endif /* LWIP_RAW */
1405 #if LWIP_UDP
1406 case NETCONN_UDP:
1407 msg->conn->pcb.udp->recv_arg = NULL;
1408 udp_remove(msg->conn->pcb.udp);
1409 break;
1410 #endif /* LWIP_UDP */
1411 #if LWIP_TCP
1412 case NETCONN_TCP:
1413 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
1414 msg->conn->write_offset == 0);
1415 msg->conn->state = NETCONN_CLOSE;
1416 msg->msg.sd.shut = NETCONN_SHUT_RDWR;
1417 msg->conn->current_msg = msg;
1418 #if LWIP_TCPIP_CORE_LOCKING
1419 if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
1420 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
1421 UNLOCK_TCPIP_CORE();
1422 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1423 LOCK_TCPIP_CORE();
1424 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1425 }
1426 #else /* LWIP_TCPIP_CORE_LOCKING */
1427 lwip_netconn_do_close_internal(msg->conn);
1428 #endif /* LWIP_TCPIP_CORE_LOCKING */
1429 /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing
1430 the application thread, so we can return at this point! */
1431 return;
1432 #endif /* LWIP_TCP */
1433 default:
1434 break;
1435 }
1436 msg->conn->pcb.tcp = NULL;
1437 }
1438 /* tcp netconns don't come here! */
1439
1440 /* @todo: this lets select make the socket readable and writable,
1441 which is wrong! errfd instead? */
1442 API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
1443 API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
1444 }
1445 if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) {
1446 TCPIP_APIMSG_ACK(msg);
1447 }
1448 }
1449
1450 /**
1451 * Bind a pcb contained in a netconn
1452 * Called from netconn_bind.
1453 *
1454 * @param m the api_msg pointing to the connection and containing
1455 * the IP address and port to bind to
1456 */
1457 void
1458 lwip_netconn_do_bind(void *m)
1459 {
1460 struct api_msg *msg = (struct api_msg *)m;
1461 struct netif *netif = NULL;
1462 netif = netif_find_by_ipaddr(API_EXPR_REF(msg->msg.bc.ipaddr));
1463
1464 if (ERR_IS_FATAL(msg->conn->last_err)) {
1465 msg->err = (err_t)((msg->conn->state == NETCONN_CLOSED) ? ERR_VAL : msg->conn->last_err);
1466 } else if (!(ip_addr_isany(API_EXPR_REF(msg->msg.bc.ipaddr)) ||
1467 ip_addr_ismulticast(API_EXPR_REF(msg->msg.bc.ipaddr)) ||
1468 netif_ipaddr_isbrdcast(API_EXPR_REF(msg->msg.bc.ipaddr)) ||
1469 ((netif != NULL) && netif_is_up(netif)))) {
1470 msg->err = ERR_NOADDR;
1471 } else {
1472 msg->err = ERR_VAL;
1473 if (msg->conn->pcb.tcp != NULL) {
1474 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1475 #if LWIP_RAW
1476 case NETCONN_RAW:
1477 msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1478 break;
1479 #if PF_PKT_SUPPORT
1480 case NETCONN_PKT_RAW:
1481 msg->err = raw_pkt_bind(msg->conn->pcb.pkt_raw, msg->msg.bc.if_idx, msg->msg.bc.port);
1482 break;
1483 #endif
1484 #endif /* LWIP_RAW */
1485 #if LWIP_UDP
1486 case NETCONN_UDP:
1487 msg->err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1488 break;
1489 #endif /* LWIP_UDP */
1490 #if LWIP_TCP
1491 case NETCONN_TCP:
1492 if (msg->conn->pcb.tcp->local_port == 0) {
1493 msg->err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1494 } else {
1495 msg->err = ERR_VAL;
1496 }
1497
1498 break;
1499 #endif /* LWIP_TCP */
1500 default:
1501 msg->err = ERR_OPNOTSUPP;
1502 break;
1503 }
1504 }
1505 }
1506 TCPIP_APIMSG_ACK(msg);
1507 }
1508 /**
1509 * Bind a pcb contained in a netconn to an interface
1510 * Called from netconn_bind_if.
1511 *
1512 * @param m the api_msg pointing to the connection and containing
1513 * the IP address and port to bind to
1514 */
1515 void
1516 lwip_netconn_do_bind_if(void *m)
1517 {
1518 struct netif *netif;
1519 struct api_msg *msg = (struct api_msg *)m;
1520 err_t err;
1521
1522 netif = netif_get_by_index(msg->msg.bc.if_idx);
1523
1524 if ((netif != NULL) && (msg->conn->pcb.tcp != NULL)) {
1525 err = ERR_OK;
1526 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1527 #if LWIP_RAW
1528 case NETCONN_RAW:
1529 raw_bind_netif(msg->conn->pcb.raw, netif);
1530 break;
1531 #endif /* LWIP_RAW */
1532 #if LWIP_UDP
1533 case NETCONN_UDP:
1534 udp_bind_netif(msg->conn->pcb.udp, netif);
1535 break;
1536 #endif /* LWIP_UDP */
1537 #if LWIP_TCP
1538 case NETCONN_TCP:
1539 tcp_bind_netif(msg->conn->pcb.tcp, netif);
1540 break;
1541 #endif /* LWIP_TCP */
1542 default:
1543 err = ERR_VAL;
1544 break;
1545 }
1546 } else {
1547 err = ERR_VAL;
1548 }
1549 msg->err = err;
1550 TCPIP_APIMSG_ACK(msg);
1551 }
1552
1553 #if LWIP_TCP
1554 /**
1555 * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has
1556 * been established (or reset by the remote host).
1557 *
1558 * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
1559 */
1560 static err_t
1561 lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
1562 {
1563 struct netconn *conn;
1564 int was_blocking;
1565 sys_sem_t *op_completed_sem = NULL;
1566
1567 LWIP_UNUSED_ARG(pcb);
1568
1569 conn = (struct netconn *)arg;
1570
1571 if (conn == NULL) {
1572 return ERR_VAL;
1573 }
1574
1575 LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
1576 LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
1577 (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
1578
1579 if (conn->current_msg != NULL) {
1580 conn->current_msg->err = err;
1581 op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1582 }
1583 if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) {
1584 setup_tcp(conn);
1585 #if LWIP_SO_SNDBUF
1586 tcp_sndbuf_init(pcb);
1587 #endif
1588 ip_addr_copy(conn->remote_ip, pcb->remote_ip);
1589 conn->remote_port = pcb->remote_port;
1590 (void)atomic_set(&conn->tcp_connected, 1);
1591 }
1592 was_blocking = !IN_NONBLOCKING_CONNECT(conn);
1593 SET_NONBLOCKING_CONNECT(conn, 0);
1594 LWIP_ASSERT("blocking connect state error",
1595 (was_blocking && op_completed_sem != NULL) ||
1596 (!was_blocking && op_completed_sem == NULL));
1597 conn->current_msg = NULL;
1598 conn->state = NETCONN_NONE;
1599 NETCONN_SET_SAFE_ERR_VAL(conn, err);
1600 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
1601
1602 if (was_blocking && (op_completed_sem != NULL)) {
1603 sys_sem_signal(op_completed_sem);
1604 }
1605 return ERR_OK;
1606 }
1607 #endif /* LWIP_TCP */
1608
1609 /**
1610 * Connect a pcb contained inside a netconn
1611 * Called from netconn_connect.
1612 *
1613 * @param m the api_msg pointing to the connection and containing
1614 * the IP address and port to connect to
1615 */
1616 void
1617 lwip_netconn_do_connect(void *m)
1618 {
1619 struct api_msg *msg = (struct api_msg *)m;
1620 err_t err;
1621 if (ERR_IS_FATAL(msg->conn->last_err)) {
1622 msg->err = msg->conn->last_err;
1623 TCPIP_APIMSG_ACK(msg);
1624 return;
1625 }
1626
1627 if (msg->conn->pcb.tcp == NULL) {
1628 /* This may happen when calling netconn_connect() a second time */
1629 err = ERR_CLSD;
1630 } else {
1631 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1632 #if LWIP_RAW
1633 case NETCONN_RAW:
1634 err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1635 break;
1636 #endif /* LWIP_RAW */
1637 #if LWIP_UDP
1638 case NETCONN_UDP:
1639 err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1640 break;
1641 #endif /* LWIP_UDP */
1642 #if LWIP_TCP
1643 case NETCONN_TCP:
1644 /* Prevent connect while doing any other action. */
1645 if (msg->conn->state == NETCONN_CONNECT) {
1646 err = ERR_ALREADY;
1647 } else if (msg->conn->state == NETCONN_LISTEN) {
1648 err = ERR_OPNOTSUPP;
1649 } else if (msg->conn->state != NETCONN_NONE) {
1650 err = ERR_ISCONN;
1651 } else {
1652 setup_tcp(msg->conn);
1653 err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr),
1654 msg->msg.bc.port, lwip_netconn_do_connected);
1655 if (err == ERR_OK) {
1656 u8_t non_blocking = netconn_is_nonblocking(msg->conn);
1657 msg->conn->state = NETCONN_CONNECT;
1658 SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
1659 if (non_blocking) {
1660 err = ERR_INPROGRESS;
1661 } else {
1662 msg->conn->current_msg = msg;
1663 /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()),
1664 when the connection is established! */
1665 #if LWIP_TCPIP_CORE_LOCKING
1666 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT);
1667 UNLOCK_TCPIP_CORE();
1668 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1669 LOCK_TCPIP_CORE();
1670 LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT);
1671 #endif /* LWIP_TCPIP_CORE_LOCKING */
1672 return;
1673 }
1674 }
1675 }
1676 break;
1677 #endif /* LWIP_TCP */
1678 default:
1679 LWIP_ERROR("Invalid netconn type", 0, do {
1680 err = ERR_VAL;
1681 } while (0));
1682 break;
1683 }
1684 }
1685 msg->err = err;
1686 /* For all other protocols, netconn_connect() calls netconn_apimsg(),
1687 so use TCPIP_APIMSG_ACK() here. */
1688 TCPIP_APIMSG_ACK(msg);
1689 }
1690
1691 /**
1692 * Disconnect a pcb contained inside a netconn
1693 * Only used for UDP netconns.
1694 * Called from netconn_disconnect.
1695 *
1696 * @param m the api_msg pointing to the connection to disconnect
1697 */
1698 void
1699 lwip_netconn_do_disconnect(void *m)
1700 {
1701 struct api_msg *msg = (struct api_msg *)m;
1702
1703 #if LWIP_UDP
1704 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1705 udp_disconnect(msg->conn->pcb.udp);
1706 msg->err = ERR_OK;
1707 } else
1708 #endif /* LWIP_UDP */
1709 {
1710 msg->err = ERR_VAL;
1711 }
1712 TCPIP_APIMSG_ACK(msg);
1713 }
1714
1715 #if LWIP_TCP
1716 /**
1717 * Set a TCP pcb contained in a netconn into listen mode
1718 * Called from netconn_listen.
1719 *
1720 * @param m the api_msg pointing to the connection
1721 */
1722 void
1723 lwip_netconn_do_listen(void *m)
1724 {
1725 struct api_msg *msg = (struct api_msg *)m;
1726 err_t err;
1727
1728 if (ERR_IS_FATAL(msg->conn->last_err)) {
1729 err = msg->conn->last_err;
1730 goto SEND_ERROR;
1731 }
1732
1733 if (msg->conn->pcb.tcp != NULL) {
1734 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1735 if (msg->conn->pcb.tcp->local_port == 0) {
1736 err = ERR_NODEST;
1737 goto SEND_ERROR;
1738 }
1739 if (msg->conn->state == NETCONN_NONE) {
1740 struct tcp_pcb *lpcb;
1741 if (msg->conn->pcb.tcp->state != CLOSED) {
1742 /* connection is not closed, cannot listen */
1743 err = ERR_VAL;
1744 } else {
1745 u8_t backlog;
1746 u32_t added;
1747 #if TCP_LISTEN_BACKLOG
1748 backlog = msg->msg.lb.backlog;
1749 #else /* TCP_LISTEN_BACKLOG */
1750 backlog = TCP_DEFAULT_LISTEN_BACKLOG;
1751 #endif /* TCP_LISTEN_BACKLOG */
1752
1753 err = ERR_OK;
1754 added = 0;
1755 if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
1756 err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
1757 if (err != ERR_OK) {
1758 err = ERR_BUF;
1759 goto SEND_ERROR;
1760 }
1761 added = 1;
1762 }
1763
1764 lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
1765
1766 if (lpcb == NULL) {
1767 /* in this case, the old pcb is still allocated */
1768 if (added) {
1769 sys_mbox_free(&msg->conn->acceptmbox);
1770 sys_mbox_set_invalid(&msg->conn->acceptmbox);
1771 }
1772 } else {
1773 /* delete the recvmbox and allocate the acceptmbox */
1774 if (sys_mbox_valid(&msg->conn->recvmbox)) {
1775 /** @todo: should we drain the recvmbox here? */
1776 sys_mbox_free(&msg->conn->recvmbox);
1777 sys_mbox_set_invalid(&msg->conn->recvmbox);
1778 }
1779
1780 msg->conn->state = NETCONN_LISTEN;
1781 msg->conn->pcb.tcp = lpcb;
1782 tcp_arg(msg->conn->pcb.tcp, msg->conn);
1783 tcp_accept(msg->conn->pcb.tcp, accept_function);
1784 }
1785
1786 #if LWIP_IPV4 && LWIP_IPV6
1787 /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
1788 * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
1789 */
1790 if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) &&
1791 (netconn_get_ipv6only(msg->conn) == 0)) {
1792 /* change PCB type to IPADDR_TYPE_ANY */
1793 IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip, IPADDR_TYPE_ANY);
1794 IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY);
1795 }
1796 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1797 }
1798 } else if (msg->conn->state == NETCONN_LISTEN) {
1799 /* already listening, allow updating of the backlog */
1800 err = ERR_OK;
1801 tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog);
1802 } else {
1803 err = ERR_CONN;
1804 }
1805 } else {
1806 err = ERR_OPNOTSUPP;
1807 }
1808 } else {
1809 err = ERR_CONN;
1810 }
1811
1812 SEND_ERROR:
1813 msg->err = err;
1814 TCPIP_APIMSG_ACK(msg);
1815 }
1816 #endif /* LWIP_TCP */
1817
1818 /**
1819 * Send some data on a RAW or UDP pcb contained in a netconn
1820 * Called from netconn_send
1821 *
1822 * @param m the api_msg pointing to the connection
1823 */
1824 void
1825 lwip_netconn_do_send(void *m)
1826 {
1827 struct api_msg *msg = (struct api_msg *)m;
1828
1829 err_t err = netconn_err(msg->conn);
1830 if (!ERR_IS_FATAL(err)) {
1831 err = ERR_CLSD;
1832 if (msg->conn->pcb.tcp != NULL) {
1833 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1834 #if LWIP_RAW
1835 case NETCONN_RAW:
1836 if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1837 struct ip_hdr *iphdr = NULL;
1838 ip_addr_t dest_addr;
1839
1840 if (!(msg->conn->pcb.raw->flags & RAW_FLAGS_CONNECTED) ||
1841 ip_addr_isany(&msg->conn->pcb.raw->remote_ip)) {
1842 if (raw_is_flag_set(msg->conn->pcb.raw, RAW_FLAGS_HDRINCL)) {
1843 if (msg->msg.b->p->len < IP_HLEN) {
1844 err = ERR_MSGSIZE;
1845 break;
1846 }
1847
1848 /* IP header already included in p */
1849 iphdr = (struct ip_hdr *)msg->msg.b->p->payload;
1850 ip_addr_copy_from_ip4(dest_addr, iphdr->dest);
1851 err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &dest_addr);
1852 break;
1853 }
1854
1855 err = ERR_NODEST;
1856 break;
1857 }
1858
1859 err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
1860 } else {
1861 err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
1862 }
1863 break;
1864 #if PF_PKT_SUPPORT
1865 case NETCONN_PKT_RAW:
1866 /* Check if its for sending RAW packets for PF_PACKET family */
1867 if (msg->msg.b->flags & NETBUF_FLAG_IFINDEX) {
1868 err = raw_pkt_sendto(msg->conn->pcb.pkt_raw, msg->msg.b->p, msg->msg.b->netifindex);
1869 } else {
1870 err = raw_pkt_sendto(msg->conn->pcb.pkt_raw, msg->msg.b->p, 0);
1871 }
1872 break;
1873 #endif
1874 #endif
1875 #if LWIP_UDP
1876 case NETCONN_UDP:
1877 #if LWIP_CHECKSUM_ON_COPY
1878 if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1879 if (!udp_is_flag_set(msg->conn->pcb.udp, UDP_FLAGS_CONNECTED)) {
1880 err = ERR_NODEST;
1881 break;
1882 }
1883 err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1884 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1885 } else {
1886 err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1887 &msg->msg.b->addr, msg->msg.b->port,
1888 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1889 }
1890 #else /* LWIP_CHECKSUM_ON_COPY */
1891 if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1892 if (!udp_is_flag_set(msg->conn->pcb.udp, UDP_FLAGS_CONNECTED)) {
1893 err = ERR_NODEST;
1894 break;
1895 }
1896 err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
1897 } else {
1898 err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
1899 }
1900 #endif /* LWIP_CHECKSUM_ON_COPY */
1901 break;
1902 #endif /* LWIP_UDP */
1903 default:
1904 err = ERR_CONN;
1905 break;
1906 }
1907 } else {
1908 err = ERR_CONN;
1909 }
1910 }
1911 msg->err = err;
1912 TCPIP_APIMSG_ACK(msg);
1913 }
1914
1915 #if LWIP_TCP
1916 /**
1917 * Indicate data has been received from a TCP pcb contained in a netconn
1918 * Called from netconn_recv
1919 *
1920 * @param m the api_msg pointing to the connection
1921 */
1922 void
1923 lwip_netconn_do_recv(void *m)
1924 {
1925 struct api_msg *msg = (struct api_msg *)m;
1926
1927 msg->err = ERR_OK;
1928 if (ERR_IS_FATAL(msg->conn->last_err)) {
1929 msg->err = msg->conn->last_err;
1930 } else if (msg->conn->pcb.tcp != NULL) {
1931 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1932 size_t remaining = msg->msg.r.len;
1933 do {
1934 u16_t recved = (u16_t)((remaining > 0xffff) ? 0xffff : remaining);
1935 tcp_recved(msg->conn->pcb.tcp, recved);
1936 remaining -= recved;
1937 } while (remaining != 0);
1938 }
1939 }
1940 TCPIP_APIMSG_ACK(msg);
1941 }
1942
1943 #if TCP_LISTEN_BACKLOG
1944 /** Indicate that a TCP pcb has been accepted
1945 * Called from netconn_accept
1946 *
1947 * @param m the api_msg pointing to the connection
1948 */
1949 void
1950 lwip_netconn_do_accepted(void *m)
1951 {
1952 struct api_msg *msg = (struct api_msg *)m;
1953
1954 msg->err = ERR_OK;
1955 if (msg->conn->pcb.tcp != NULL) {
1956 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1957 tcp_backlog_accepted(msg->conn->pcb.tcp);
1958 }
1959 }
1960 TCPIP_APIMSG_ACK(msg);
1961 }
1962 #endif /* TCP_LISTEN_BACKLOG */
1963
1964 /**
1965 * See if more data needs to be written from a previous call to netconn_write.
1966 * Called initially from lwip_netconn_do_write. If the first call can't send all data
1967 * (because of low memory or empty send-buffer), this function is called again
1968 * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
1969 * blocking application thread (waiting in netconn_write) is released.
1970 *
1971 * @param conn netconn (that is currently in state NETCONN_WRITE) to process
1972 * @return ERR_OK
1973 * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
1974 */
1975 static err_t
1976 lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM)
1977 {
1978 err_t err;
1979 const void *dataptr;
1980 u32_t len, available;
1981 u8_t write_finished = 0;
1982 size_t diff;
1983 u8_t dontblock;
1984 u8_t apiflags;
1985 u8_t write_more;
1986
1987 LWIP_ASSERT("conn != NULL", conn != NULL);
1988 LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
1989 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
1990 LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
1991 LWIP_ASSERT("conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len",
1992 conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len);
1993 LWIP_ASSERT("conn->current_msg->msg.w.vector_cnt > 0", conn->current_msg->msg.w.vector_cnt > 0);
1994
1995 apiflags = conn->current_msg->msg.w.apiflags;
1996 dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
1997
1998 #if DRIVER_STATUS_CHECK
1999 if (dontblock && (conn->pcb.tcp->drv_status == DRV_NOT_READY)) {
2000 sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
2001 u8_t dontblock_sock = netconn_is_nonblocking(conn);
2002
2003 if (dontblock_sock) {
2004 LWIP_DEBUGF(DRV_STS_DEBUG, ("Driver Not Ready. So sending SENDMINUS event\n"));
2005 API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
2006 }
2007
2008 /* check for state, and ensure correct errno is set while returning ... */
2009 if (!atomic_read(&conn->tcp_connected)) {
2010 err = ERR_CONN;
2011 LWIP_DEBUGF(DRV_STS_DEBUG, ("Driver Not Ready. But connection is also not established, So returning ERR_CONN\n"));
2012 } else {
2013 LWIP_DEBUGF(DRV_STS_DEBUG, ("Driver Not Ready. So returning ERR_WOULDBLOCK\n"));
2014 err = ERR_WOULDBLOCK;
2015 }
2016
2017 conn->current_msg->err = err;
2018 conn->current_msg = NULL;
2019 conn->state = NETCONN_NONE;
2020
2021 sys_sem_signal(op_completed_sem);
2022 return err;
2023 }
2024 #else
2025 if (!atomic_read(&conn->tcp_connected)) {
2026 sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
2027 /* check for state, and ensure correct errno is set while returning ... */
2028 err = ERR_CONN;
2029 LWIP_DEBUGF(DRV_STS_DEBUG, ("Connection is also not established, So returning ERR_CONN\n"));
2030
2031 conn->current_msg->err = err;
2032 conn->current_msg = NULL;
2033 conn->state = NETCONN_NONE;
2034
2035 sys_sem_signal(op_completed_sem);
2036 return err;
2037 }
2038 #endif
2039
2040 #if LWIP_SO_SNDTIMEO
2041 if ((conn->send_timeout != 0) &&
2042 ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
2043 write_finished = 1;
2044 if (conn->current_msg->msg.w.offset == 0) {
2045 /* nothing has been written */
2046 err = ERR_WOULDBLOCK;
2047 } else {
2048 /* partial write */
2049 err = ERR_OK;
2050 }
2051 } else
2052 #endif /* LWIP_SO_SNDTIMEO */
2053 {
2054 do {
2055 dataptr = (const u8_t *)conn->current_msg->msg.w.vector->ptr + conn->current_msg->msg.w.vector_off;
2056 diff = conn->current_msg->msg.w.vector->len - conn->current_msg->msg.w.vector_off;
2057 if (diff > 0xffffUL) { /* max_u16_t */
2058 len = 0xffff;
2059 apiflags |= TCP_WRITE_FLAG_MORE;
2060 } else {
2061 len = (u16_t)diff;
2062 }
2063 available = tcp_sndbuf(conn->pcb.tcp);
2064 if (available < len) {
2065 /* don't try to write more than sendbuf */
2066 len = available;
2067 if (dontblock) {
2068 if (!len) {
2069 /* set error according to partial write or not */
2070 err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK;
2071 goto err_mem;
2072 }
2073 } else {
2074 apiflags |= TCP_WRITE_FLAG_MORE;
2075 }
2076 }
2077 LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!",
2078 ((conn->current_msg->msg.w.vector_off + len) <= conn->current_msg->msg.w.vector->len));
2079 /* we should loop around for more sending in the following cases:
2080 1) We couldn't finish the current vector because of 16-bit size limitations.
2081 tcp_write() and tcp_sndbuf() both are limited to 16-bit sizes
2082 2) We are sending the remainder of the current vector and have more */
2083 if ((len == 0xffff && diff > 0xffffUL) ||
2084 (len == (u16_t)diff && conn->current_msg->msg.w.vector_cnt > 1)) {
2085 write_more = 1;
2086 apiflags |= TCP_WRITE_FLAG_MORE;
2087 } else {
2088 write_more = 0;
2089 }
2090 err = tcp_write(conn->pcb.tcp, dataptr, (u16_t)len, apiflags);
2091 if (err == ERR_OK) {
2092 conn->current_msg->msg.w.offset += len;
2093 conn->current_msg->msg.w.vector_off += len;
2094 /* check if current vector is finished */
2095 if (conn->current_msg->msg.w.vector_off == conn->current_msg->msg.w.vector->len) {
2096 conn->current_msg->msg.w.vector_cnt--;
2097 /* if we have additional vectors, move on to them */
2098 if (conn->current_msg->msg.w.vector_cnt > 0) {
2099 conn->current_msg->msg.w.vector++;
2100 conn->current_msg->msg.w.vector_off = 0;
2101 }
2102 }
2103 }
2104 } while (write_more && err == ERR_OK);
2105 /* if OK or memory error, check available space */
2106 if ((err == ERR_OK) || (err == ERR_MEM)) {
2107 err_mem:
2108 if (dontblock && (conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len)) {
2109 /* non-blocking write did not write everything: mark the pcb non-writable
2110 and let poll_tcp check writable space to mark the pcb writable again */
2111 API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
2112 conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
2113 } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
2114 (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
2115 /* The queued byte- or pbuf-count exceeds the configured low-water limit,
2116 let select mark this pcb as non-writable. */
2117 API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
2118 }
2119 }
2120
2121 if (err == ERR_OK) {
2122 err_t out_err;
2123 if ((conn->current_msg->msg.w.offset == conn->current_msg->msg.w.len) || dontblock) {
2124 /* return sent length (caller reads length from msg.w.offset) */
2125 write_finished = 1;
2126 }
2127 out_err = tcp_output(conn->pcb.tcp);
2128 if (ERR_IS_FATAL(out_err) || out_err == ERR_RTE) {
2129 /* If tcp_output fails with fatal error or no route is found,
2130 don't try writing any more but return the error
2131 to the application thread. */
2132 err = out_err;
2133 write_finished = 1;
2134 }
2135 } else if (err == ERR_MEM) {
2136 /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called.
2137 For blocking sockets, we do NOT return to the application
2138 thread, since ERR_MEM is only a temporary error! Non-blocking
2139 will remain non-writable until sent_tcp/poll_tcp is called */
2140
2141 /* tcp_write returned ERR_MEM, try tcp_output anyway */
2142 err_t out_err = tcp_output(conn->pcb.tcp);
2143 if (ERR_IS_FATAL(out_err) || out_err == ERR_RTE) {
2144 /* If tcp_output fails with fatal error or no route is found,
2145 don't try writing any more but return the error
2146 to the application thread. */
2147 err = out_err;
2148 write_finished = 1;
2149 } else if (dontblock) {
2150 /* non-blocking write is done on ERR_MEM, set error according
2151 to partial write or not */
2152 err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK;
2153 write_finished = 1;
2154 }
2155 } else {
2156 /* On errors != ERR_MEM, we don't try writing any more but return
2157 the error to the application thread. */
2158 write_finished = 1;
2159 }
2160 }
2161 if (write_finished) {
2162 /* everything was written: set back connection state
2163 and back to application task */
2164 sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
2165 conn->current_msg->err = err;
2166 conn->current_msg = NULL;
2167 conn->state = NETCONN_NONE;
2168 #if LWIP_TCPIP_CORE_LOCKING
2169 if (delayed)
2170 #endif
2171 {
2172 sys_sem_signal(op_completed_sem);
2173 }
2174 }
2175 #if LWIP_TCPIP_CORE_LOCKING
2176 else {
2177 return ERR_MEM;
2178 }
2179 #endif
2180 return ERR_OK;
2181 }
2182 #endif /* LWIP_TCP */
2183
2184 /**
2185 * Send some data on a TCP pcb contained in a netconn
2186 * Called from netconn_write
2187 *
2188 * @param m the api_msg pointing to the connection
2189 */
2190 void
2191 lwip_netconn_do_write(void *m)
2192 {
2193 struct api_msg *msg = (struct api_msg *)m;
2194 err_t err;
2195 if (ERR_IS_FATAL(msg->conn->last_err)) {
2196 err = (err_t)((msg->conn->last_err == ERR_CLSD) ? ERR_PIPE : msg->conn->last_err);
2197 } else {
2198 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
2199 #if LWIP_TCP
2200 if (msg->conn->state != NETCONN_NONE) {
2201 /* netconn is connecting, closing or in blocking write */
2202 err = ((msg->conn->state == NETCONN_LISTEN) ? ERR_PIPE : ERR_INPROGRESS);
2203 err = (err_t)((msg->conn->state == NETCONN_CONNECT) ? ERR_CONN : err);
2204 } else if (msg->conn->pcb.tcp != NULL) {
2205 msg->conn->state = NETCONN_WRITE;
2206 /* set all the variables used by lwip_netconn_do_writemore */
2207 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
2208 msg->conn->write_offset == 0);
2209 LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
2210 msg->conn->current_msg = msg;
2211 msg->conn->write_offset = 0;
2212 #if LWIP_TCPIP_CORE_LOCKING
2213 if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) {
2214 LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
2215 UNLOCK_TCPIP_CORE();
2216 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
2217 LOCK_TCPIP_CORE();
2218 LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE);
2219 }
2220 #else /* LWIP_TCPIP_CORE_LOCKING */
2221 lwip_netconn_do_writemore(msg->conn);
2222 #endif /* LWIP_TCPIP_CORE_LOCKING */
2223 /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG
2224 since lwip_netconn_do_writemore ACKs it! */
2225 return;
2226 } else {
2227 err = ERR_PIPE;
2228 }
2229 #else /* LWIP_TCP */
2230 err = ERR_VAL;
2231 #endif /* LWIP_TCP */
2232 #if (LWIP_UDP || LWIP_RAW)
2233 } else {
2234 err = ERR_VAL;
2235 #endif /* (LWIP_UDP || LWIP_RAW) */
2236 }
2237 }
2238 msg->err = err;
2239 TCPIP_APIMSG_ACK(msg);
2240 }
2241
2242 /**
2243 * Return a connection's local or remote address
2244 * Called from netconn_getaddr
2245 *
2246 * @param m the api_msg pointing to the connection
2247 */
2248 void
2249 lwip_netconn_do_getaddr(void *m)
2250 {
2251 struct api_msg *msg = (struct api_msg *)m;
2252
2253 if ((msg->conn == NULL) || (msg->conn->pcb.tcp == NULL)) {
2254 msg->err = ERR_CONN;
2255 TCPIP_APIMSG_ACK(msg);
2256 return;
2257 }
2258 if (msg->conn->pcb.ip != NULL) {
2259 if (msg->msg.ad.local) {
2260 ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
2261 msg->conn->pcb.ip->local_ip);
2262 } else {
2263 ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
2264 msg->conn->pcb.ip->remote_ip);
2265 }
2266
2267 msg->err = ERR_OK;
2268 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
2269 #if LWIP_RAW
2270 case NETCONN_RAW:
2271 if (msg->msg.ad.local) {
2272 ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
2273 msg->conn->pcb.raw->local_ip);
2274 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->raw_proto;
2275 } else {
2276 if (raw_is_flag_set(msg->conn->pcb.raw, RAW_FLAGS_CONNECTED)) {
2277 ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
2278 msg->conn->pcb.raw->remote_ip);
2279 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->raw_proto;
2280 } else {
2281 /* return an error as connecting is only a helper for upper layers */
2282 msg->err = ERR_CONN;
2283 }
2284 }
2285 break;
2286 #endif /* LWIP_RAW */
2287 #if LWIP_UDP
2288 case NETCONN_UDP:
2289 if (msg->msg.ad.local) {
2290 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
2291 } else {
2292 if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
2293 msg->err = ERR_CONN;
2294 } else {
2295 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
2296 }
2297 }
2298 break;
2299 #endif /* LWIP_UDP */
2300 #if LWIP_TCP
2301 case NETCONN_TCP:
2302 if ((msg->msg.ad.local == 0) &&
2303 ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) {
2304 /* pcb is not connected and remote name is requested */
2305 msg->err = ERR_CONN;
2306 } else {
2307 API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port);
2308 }
2309 break;
2310 #endif /* LWIP_TCP */
2311 default:
2312 msg->err = ERR_OPNOTSUPP;
2313 LWIP_ASSERT("invalid netconn_type", 0);
2314 break;
2315 }
2316 } else {
2317 msg->err = ERR_CLSD;
2318 }
2319 TCPIP_APIMSG_ACK(msg);
2320 }
2321
2322 #if PF_PKT_SUPPORT
2323 /**
2324 * Return a pf pkt socket's local address
2325 * Called from netconn_getaddr
2326 *
2327 * @param m the api_msg pointing to the connection
2328 */
2329 void
2330 lwip_netconn_do_getaddr_pfpkt(void *m)
2331 {
2332 struct api_msg *msg = (struct api_msg *)m;
2333 struct pf_pkt_ll ll;
2334 msg->err = ERR_OK;
2335 if (msg->conn->pcb.ip != NULL) {
2336 /* Non standard way of do it, but doing it :( */
2337 if (msg->msg.adpkt.local) {
2338 ll.sll_protocol = msg->conn->pcb.pkt_raw->proto.eth_proto;
2339 ll.if_idx = msg->conn->pcb.pkt_raw->netifindex;
2340 struct netif *netif = netif_find_by_ifindex(msg->conn->pcb.pkt_raw->netifindex);
2341 if (netif == NULL) {
2342 LWIP_DEBUGF(SOCKETS_DEBUG,
2343 ("lwip_getaddrname:netif not found for given ifindex (%u)\n",
2344 msg->conn->pcb.pkt_raw->netifindex));
2345 ll.sll_halen = 0;
2346 ll.sll_hatype = 0;
2347 } else {
2348 ll.sll_hatype = netif->link_layer_type;
2349 ll.sll_halen = NETIF_MAX_HWADDR_LEN;
2350 (void)memcpy_s(ll.sll_addr, ll.sll_halen, netif->hwaddr, NETIF_MAX_HWADDR_LEN);
2351 }
2352 API_EXPR_DEREF(msg->msg.adpkt.ll) = ll;
2353 } else {
2354 msg->err = ERR_OPNOTSUPP;
2355 }
2356 } else {
2357 msg->err = ERR_CONN;
2358 }
2359 TCPIP_APIMSG_ACK(msg);
2360 }
2361 #endif
2362
2363 /**
2364 * Close or half-shutdown a TCP pcb contained in a netconn
2365 * Called from netconn_close
2366 * In contrast to closing sockets, the netconn is not deallocated.
2367 *
2368 * @param m the api_msg pointing to the connection
2369 */
2370 void
2371 lwip_netconn_do_close(void *m)
2372 {
2373 struct api_msg *msg = (struct api_msg *)m;
2374
2375 #if LWIP_TCP
2376 enum netconn_state state = msg->conn->state;
2377 /* First check if this is a TCP netconn and if it is in a correct state
2378 (LISTEN doesn't support half shutdown) */
2379 if ((msg->conn->pcb.tcp != NULL) &&
2380 (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) &&
2381 ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) {
2382
2383 LWIP_ERROR("lwip_netconn_do_close: shutdown can not be done when in CLOSED state",
2384 msg->conn->net_tcp_state != CLOSED,
2385 msg->err = ERR_CONN; TCPIP_APIMSG_ACK(msg); return);
2386 /* Check if we are in a connected state */
2387 if (state == NETCONN_CONNECT) {
2388 /* TCP connect in progress: cannot shutdown */
2389 int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(msg->conn);
2390 SET_NONBLOCKING_CONNECT(msg->conn, 0);
2391
2392 if ((msg->msg.sd.shut & NETCONN_SHUT_WR) && !was_nonblocking_connect && (msg->conn->current_msg != NULL)) {
2393 sys_sem_t *op_completed_sem = NULL;
2394 msg->conn->current_msg->err = ERR_ABRT;
2395 op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
2396 LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem));
2397 msg->conn->current_msg = NULL;
2398 /* wake up the waiting task */
2399 sys_sem_signal(op_completed_sem);
2400 }
2401 msg->err = ERR_CONN;
2402 } else if (state == NETCONN_WRITE) {
2403 #if LWIP_NETCONN_FULLDUPLEX
2404 if (msg->msg.sd.shut & NETCONN_SHUT_WR) {
2405 /* close requested, abort running write */
2406 sys_sem_t *write_completed_sem;
2407 LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
2408 write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
2409 msg->conn->current_msg->err = ERR_CLSD;
2410 msg->conn->current_msg = NULL;
2411 msg->conn->write_offset = 0;
2412 msg->conn->state = NETCONN_NONE;
2413 state = NETCONN_NONE;
2414 sys_sem_signal(write_completed_sem);
2415 } else {
2416 LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD);
2417 /* In this case, let the write continue and do not interfere with
2418 conn->current_msg or conn->state! */
2419 msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0);
2420 }
2421 }
2422 if ((state == NETCONN_NONE) || (state == NETCONN_LISTEN)) {
2423 #else /* LWIP_NETCONN_FULLDUPLEX */
2424 msg->err = ERR_INPROGRESS;
2425 } else {
2426 #endif /* LWIP_NETCONN_FULLDUPLEX */
2427 if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
2428 msg->conn->shutdown = RCV_SHUTDOWN;
2429 #if LWIP_NETCONN_FULLDUPLEX
2430 /* Mark mboxes invalid */
2431 netconn_mark_mbox_invalid(msg->conn);
2432 #else /* LWIP_NETCONN_FULLDUPLEX */
2433 netconn_drain(msg->conn);
2434 #endif /* LWIP_NETCONN_FULLDUPLEX */
2435 }
2436 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
2437 msg->conn->write_offset == 0);
2438 msg->conn->state = NETCONN_CLOSE;
2439 msg->conn->current_msg = msg;
2440 #if LWIP_TCPIP_CORE_LOCKING
2441 if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
2442 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
2443 UNLOCK_TCPIP_CORE();
2444 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
2445 LOCK_TCPIP_CORE();
2446 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
2447 }
2448 #else /* LWIP_TCPIP_CORE_LOCKING */
2449 lwip_netconn_do_close_internal(msg->conn);
2450 #endif /* LWIP_TCPIP_CORE_LOCKING */
2451 /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */
2452 return;
2453 }
2454 } else
2455 #endif /* LWIP_TCP */
2456 {
2457 msg->err = ERR_CLSD;
2458 if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) {
2459 /* LISTEN doesn't support half shutdown */
2460 msg->err = ERR_CONN;
2461 }
2462 }
2463 TCPIP_APIMSG_ACK(msg);
2464 }
2465
2466 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
2467 /*
2468 * Leave multicast groups for UDP netconns.
2469 * Called from netconn_leave_group and netconn_leave_group_netif
2470 *
2471 * @param m the api_msg_msg pointing to the connection
2472 */
2473 void
2474 lwip_netconn_do_leave_group(void *m)
2475 {
2476 struct api_msg *msg = (struct api_msg*)m;
2477
2478
2479 msg->err = ERR_CONN;
2480 if (ERR_IS_FATAL(msg->conn->last_err)) {
2481 msg->err = msg->conn->last_err;
2482 } else {
2483 if (msg->conn->pcb.udp != NULL) {
2484 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
2485 #if LWIP_UDP
2486 #if LWIP_IPV6 && LWIP_IPV6_MLD
2487 if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
2488 struct netif *netif = NULL;
2489
2490 netif = netif_get_by_index(msg->msg.jl.if_idx);
2491 if (netif == NULL) {
2492 msg->err = ERR_IF;
2493 TCPIP_APIMSG_ACK(msg);
2494 return;
2495 }
2496
2497 if (msg->msg.jl.join_or_leave == NETCONN_LEAVE) {
2498 msg->err = mld6_leavegroup_netif(netif,
2499 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
2500 }
2501 }
2502 else
2503 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
2504 {
2505 #if LWIP_IGMP
2506 if (msg->msg.jl.join_or_leave == NETCONN_LEAVE) {
2507 msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
2508 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
2509 }
2510 #endif /* LWIP_IGMP */
2511 }
2512 #endif /* LWIP_UDP */
2513 #if (LWIP_TCP || LWIP_RAW)
2514 } else {
2515 msg->err = ERR_VAL;
2516 #endif /* (LWIP_TCP || LWIP_RAW) */
2517 }
2518 } else {
2519 msg->err = ERR_CONN;
2520 }
2521 }
2522 TCPIP_APIMSG_ACK(msg);
2523 }
2524 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
2525
2526 #if LWIP_DNS
2527 /**
2528 * Callback function that is called when DNS name is resolved
2529 * (or on timeout). A waiting application thread is waked up by
2530 * signaling the semaphore.
2531 */
2532 static void
2533 lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, u32_t count, void *arg)
2534 {
2535 struct dns_api_msg *msg = (struct dns_api_msg *)arg;
2536 u32_t i;
2537
2538 /* we trust the internal implementation to be correct :-) */
2539 LWIP_UNUSED_ARG(name);
2540
2541 if (ipaddr == NULL) {
2542 /* If ipaddr = NULL, then count will contain the reason of error
2543 * that will be eventually set to h_errno or h_errnop */
2544 if (count != 0) {
2545 /* Incase of known errors */
2546 API_EXPR_DEREF(msg->err) = (err_t)(count);
2547 } else {
2548 /* Incase of unknown errors */
2549 API_EXPR_DEREF(msg->err) = EINVAL;
2550 }
2551 } else {
2552 /* address was resolved */
2553 API_EXPR_DEREF(msg->err) = ERR_OK;
2554 for (i = 0; i < count; i++) {
2555 msg->addr[i] = ipaddr[i];
2556 }
2557 }
2558 API_EXPR_DEREF(msg->count) = API_EXPR_DEREF(&count);
2559 /* wake up the application task waiting in netconn_gethostbyname */
2560 sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
2561 }
2562
2563 /**
2564 * Execute a DNS query
2565 * Called from netconn_gethostbyname
2566 *
2567 * @param arg the dns_api_msg pointing to the query
2568 */
2569 void
2570 lwip_netconn_do_gethostbyname(void *arg)
2571 {
2572 struct dns_api_msg *msg = (struct dns_api_msg *)arg;
2573 u8_t addrtype =
2574 #if LWIP_IPV4 && LWIP_IPV6
2575 msg->dns_addrtype;
2576 #else
2577 LWIP_DNS_ADDRTYPE_DEFAULT;
2578 #endif
2579
2580 API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name, API_EXPR_REF(msg->addr), msg->count,
2581 lwip_netconn_do_dns_found, msg, addrtype);
2582 #if LWIP_TCPIP_CORE_LOCKING
2583 /* For core locking, only block if we need to wait for answer/timeout */
2584 if (API_EXPR_DEREF(msg->err) == ERR_INPROGRESS) {
2585 UNLOCK_TCPIP_CORE();
2586 sys_sem_wait(API_EXPR_REF_SEM(msg->sem));
2587 LOCK_TCPIP_CORE();
2588 LWIP_ASSERT("do_gethostbyname still in progress!!", API_EXPR_DEREF(msg->err) != ERR_INPROGRESS);
2589 }
2590 #else /* LWIP_TCPIP_CORE_LOCKING */
2591 if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) {
2592 /* on error or immediate success, wake up the application
2593 * task waiting in netconn_gethostbyname */
2594 sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
2595 }
2596 #endif /* LWIP_TCPIP_CORE_LOCKING */
2597 }
2598
2599 void
2600 lwip_netconn_do_reverse_dns_found(const char *hostname, u32_t count, void *arg)
2601 {
2602 struct reverse_dns_api_msg *msg = (struct reverse_dns_api_msg*)arg;
2603
2604 if (hostname != NULL) {
2605 size_t namelen = strlen(hostname);
2606 if (namelen < NI_MAXHOST) {
2607 if (strncpy_s(msg->hostname, NI_MAXHOST, hostname, namelen) != EOK) {
2608 API_EXPR_DEREF(msg->err) = EINVAL;
2609 } else {
2610 API_EXPR_DEREF(msg->err) = ERR_OK;
2611 }
2612 } else {
2613
2614 API_EXPR_DEREF(msg->err) = EINVAL;
2615 }
2616 } else {
2617 /* If hostname is NULL, then count will contain the error code (because h_errno is not implemented yet) */
2618 if (count != 0) {
2619 /* Incase of known errors */
2620 API_EXPR_DEREF(msg->err) = (err_t)(count);
2621 } else {
2622 /* Incase of unknown errors */
2623 API_EXPR_DEREF(msg->err) = EINVAL;
2624 }
2625 }
2626
2627 sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
2628 }
2629
2630 #if LWIP_DNS_REVERSE
2631 void
2632 lwip_netconn_do_getnamebyhost(void *arg)
2633 {
2634 struct reverse_dns_api_msg *msg = (struct reverse_dns_api_msg*)arg;
2635
2636 API_EXPR_DEREF(msg->err) = reverse_dns_getnamebyhost(API_EXPR_REF(msg->addr), msg->hostname,
2637 lwip_netconn_do_reverse_dns_found, msg);
2638 if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) {
2639 /* on error or immediate success, wake up the application
2640 * task waiting in netconn_gethostbyname */
2641 sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
2642 }
2643 }
2644 #endif /* LWIP_DNS_REVERSE */
2645 #endif /* LWIP_DNS */
2646
2647 static err_t
2648 do_get_tcpconninfo(struct api_msg *msg)
2649 {
2650 struct tcp_pcb *tcp = msg->conn->pcb.tcp;
2651 struct tcpip_conn *conn_info = msg->msg.conn_info;
2652 if (tcp == NULL) {
2653 msg->err = ERR_CLSD;
2654 return msg->err;
2655 }
2656 if (tcp->state == LISTEN) {
2657 msg->err = ERR_VAL;
2658 return msg->err;
2659 }
2660
2661 if ((msg->conn->pcb.tcp->state == CLOSED) ||
2662 (msg->conn->pcb.tcp->state == TIME_WAIT)) {
2663 msg->err = ERR_CONN;
2664 return msg->err;
2665 }
2666 ip_addr_copy(conn_info->dst_ip, tcp->remote_ip);
2667 ip_addr_copy(conn_info->src_ip, tcp->local_ip);
2668 conn_info->srcport = tcp->local_port;
2669 conn_info->dstport = tcp->remote_port;
2670 if (tcp->state == SYN_SENT) {
2671 conn_info->seqnum = tcp->lastack; /* seqnum of last ACKED byte */
2672 } else {
2673 conn_info->seqnum = (u32_t)(tcp->lastack - 1);
2674 }
2675 conn_info->acknum = tcp->rcv_nxt; /* Last acknowledged number sent */
2676 conn_info->tcpwin = tcp->snd_wnd;
2677 conn_info->last_payload_len = tcp->last_payload_len;
2678 conn_info->tsval = 0 ;
2679 conn_info->tsecr = 0;
2680 conn_info->ipid = ip4_last_ip_id();
2681 return ERR_OK;
2682 }
2683
2684 static err_t
2685 do_get_udpconninfo(struct api_msg *msg)
2686 {
2687 struct udp_pcb *udp = msg->conn->pcb.udp;
2688 struct tcpip_conn *conn_info = msg->msg.conn_info;
2689 if (udp == NULL) {
2690 msg->err = ERR_CLSD;
2691 return msg->err;
2692 }
2693 ip_addr_copy(conn_info->dst_ip, udp->remote_ip);
2694 ip_addr_copy(conn_info->src_ip, udp->local_ip);
2695 conn_info->srcport = udp->local_port;
2696 conn_info->dstport = udp->remote_port;
2697 conn_info->seqnum = 0; /* Last sent Sequence number */
2698 conn_info->acknum = 0; /* Last acknowledged number sent */
2699 conn_info->tcpwin = 0;
2700 conn_info->last_payload_len = udp->last_payload_len;
2701 conn_info->tsval = 0;
2702 conn_info->tsecr = 0;
2703 conn_info->ipid = ip4_last_ip_id();
2704 return ERR_OK;
2705 }
2706
2707 void
2708 do_getconninfo(void *m)
2709 {
2710 struct api_msg *msg = (struct api_msg*)m;
2711 ip_addr_t *dst_addr = NULL;
2712 ip_addr_t *src_addr = NULL;
2713
2714 const ip4_addr_t *ip_add = NULL;
2715 struct tcpip_conn *conn_info = NULL;
2716 struct eth_addr *tdst_mac = NULL;
2717 struct eth_addr invalid_mac = {{0, 0, 0, 0, 0, 0}};
2718 s8_t ret;
2719 err_t err;
2720 conn_info = msg->msg.conn_info;
2721 tdst_mac = &conn_info->dst_mac;
2722 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
2723 err = do_get_udpconninfo(msg);
2724 dst_addr = &(msg->conn->pcb.udp->remote_ip);
2725 src_addr = &(msg->conn->pcb.udp->local_ip);
2726 if (err != ERR_OK) {
2727 goto RETURN;
2728 }
2729
2730 } else if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
2731 err = do_get_tcpconninfo(msg);
2732 dst_addr = &(msg->conn->pcb.tcp->remote_ip);
2733 src_addr = &(msg->conn->pcb.tcp->local_ip);
2734 if (err != ERR_OK) {
2735 goto RETURN;
2736 }
2737 } else {
2738 msg->err = ERR_VAL;
2739 goto RETURN;
2740 }
2741
2742 if (ip_addr_isany(dst_addr)) {
2743 tdst_mac = &invalid_mac;
2744 (void)memcpy_s(&conn_info->dst_mac, sizeof(struct eth_addr), tdst_mac, sizeof(struct eth_addr));
2745 msg->err = ERR_OK;
2746 goto RETURN;
2747 }
2748
2749 if (NETCONNTYPE_ISIPV6(NETCONN_TYPE(msg->conn))) {
2750 ret = netif_find_dst_ip6addr_mac_addr(src_addr, &dst_addr, &tdst_mac);
2751 } else {
2752 ret = netif_find_dst_ipaddr(src_addr, &dst_addr);
2753 if (ret == 0) {
2754 ret = (s8_t)etharp_find_addr(NULL, ip_2_ip4(dst_addr), &tdst_mac, &ip_add);
2755 }
2756 }
2757
2758 if (ret == -1) {
2759 tdst_mac = &invalid_mac;
2760 }
2761
2762 (void)memcpy_s(&conn_info->dst_mac, sizeof(struct eth_addr), tdst_mac, sizeof(struct eth_addr));
2763 msg->err = ERR_OK;
2764
2765 RETURN:
2766 TCPIP_APIMSG_ACK(msg);
2767 }
2768
2769 #endif /* LWIP_NETCONN */
2770