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