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