BadVPN – Blame information for rev 1

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