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