UbixOS V2  2.0
api_msg.c
Go to the documentation of this file.
1 
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 <net/opt.h>
40 
41 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
42 
43 #include <net/priv/api_msg.h>
44 
45 #include <net/ip.h>
46 #include <net/ip_addr.h>
47 #include <net/udp.h>
48 #include <net/tcp.h>
49 #include <net/raw.h>
50 
51 #include <net/memp.h>
52 #include <net/igmp.h>
53 #include <net/dns.h>
54 #include <net/mld6.h>
55 #include <net/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  (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \
64 } else { \
65  (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0)
66 #define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0)
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) NETCONN_SET_SAFE_ERR((m)->conn, (m)->err)
83 #else /* LWIP_TCPIP_CORE_LOCKING */
84 #define TCPIP_APIMSG_ACK(m) do { NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0)
85 #endif /* LWIP_TCPIP_CORE_LOCKING */
86 
87 #if LWIP_TCP
88 u8_t netconn_aborted;
89 #endif /* LWIP_TCP */
90 
91 #if LWIP_RAW
92 
99 static u8_t
100 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
101  const ip_addr_t *addr)
102 {
103  struct pbuf *q;
104  struct netbuf *buf;
105  struct netconn *conn;
106 
107  LWIP_UNUSED_ARG(addr);
108  conn = (struct netconn *)arg;
109 
110  if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) {
111 #if LWIP_SO_RCVBUF
112  int recv_avail;
113  SYS_ARCH_GET(conn->recv_avail, recv_avail);
114  if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
115  return 0;
116  }
117 #endif /* LWIP_SO_RCVBUF */
118  /* copy the whole packet into new pbufs */
120  if (q != NULL) {
121  if (pbuf_copy(q, p) != ERR_OK) {
122  pbuf_free(q);
123  q = NULL;
124  }
125  }
126 
127  if (q != NULL) {
128  u16_t len;
129  buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
130  if (buf == NULL) {
131  pbuf_free(q);
132  return 0;
133  }
134 
135  buf->p = q;
136  buf->ptr = q;
138  buf->port = pcb->protocol;
139 
140  len = q->tot_len;
141  if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
142  netbuf_delete(buf);
143  return 0;
144  } else {
145 #if LWIP_SO_RCVBUF
146  SYS_ARCH_INC(conn->recv_avail, len);
147 #endif /* LWIP_SO_RCVBUF */
148  /* Register event with callback */
149  API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
150  }
151  }
152  }
153 
154  return 0; /* do not eat the packet */
155 }
156 #endif /* LWIP_RAW*/
157 
158 #if LWIP_UDP
159 
165 static void
166 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
167  const ip_addr_t *addr, u16_t port)
168 {
169  struct netbuf *buf;
170  struct netconn *conn;
171  u16_t len;
172 #if LWIP_SO_RCVBUF
173  int recv_avail;
174 #endif /* LWIP_SO_RCVBUF */
175 
176  LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
177  LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
178  LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
179  conn = (struct netconn *)arg;
180 
181  if (conn == NULL) {
182  pbuf_free(p);
183  return;
184  }
185 
186  LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
187 
188 #if LWIP_SO_RCVBUF
189  SYS_ARCH_GET(conn->recv_avail, recv_avail);
190  if (!sys_mbox_valid(&conn->recvmbox) ||
191  ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
192 #else /* LWIP_SO_RCVBUF */
193  if (!sys_mbox_valid(&conn->recvmbox)) {
194 #endif /* LWIP_SO_RCVBUF */
195  pbuf_free(p);
196  return;
197  }
198 
199  buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
200  if (buf == NULL) {
201  pbuf_free(p);
202  return;
203  } else {
204  buf->p = p;
205  buf->ptr = p;
206  ip_addr_set(&buf->addr, addr);
207  buf->port = port;
208 #if LWIP_NETBUF_RECVINFO
209  {
210  /* get the UDP header - always in the first pbuf, ensured by udp_input */
211  const struct udp_hdr* udphdr = (const struct udp_hdr*)ip_next_header_ptr();
212 #if LWIP_CHECKSUM_ON_COPY
213  buf->flags = NETBUF_FLAG_DESTADDR;
214 #endif /* LWIP_CHECKSUM_ON_COPY */
215  ip_addr_set(&buf->toaddr, ip_current_dest_addr());
216  buf->toport_chksum = udphdr->dest;
217  }
218 #endif /* LWIP_NETBUF_RECVINFO */
219  }
220 
221  len = p->tot_len;
222  if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
223  netbuf_delete(buf);
224  return;
225  } else {
226 #if LWIP_SO_RCVBUF
227  SYS_ARCH_INC(conn->recv_avail, len);
228 #endif /* LWIP_SO_RCVBUF */
229  /* Register event with callback */
230  API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
231  }
232 }
233 #endif /* LWIP_UDP */
234 
235 #if LWIP_TCP
236 
242 static err_t
243 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
244 {
245  struct netconn *conn;
246  u16_t len;
247 
248  LWIP_UNUSED_ARG(pcb);
249  LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
250  LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
251  conn = (struct netconn *)arg;
252 
253  if (conn == NULL) {
254  return ERR_VAL;
255  }
256  LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
257 
258  if (!sys_mbox_valid(&conn->recvmbox)) {
259  /* recvmbox already deleted */
260  if (p != NULL) {
261  tcp_recved(pcb, p->tot_len);
262  pbuf_free(p);
263  }
264  return ERR_OK;
265  }
266  /* Unlike for UDP or RAW pcbs, don't check for available space
267  using recv_avail since that could break the connection
268  (data is already ACKed) */
269 
270  /* don't overwrite fatal errors! */
271  if (err != ERR_OK) {
272  NETCONN_SET_SAFE_ERR(conn, err);
273  }
274 
275  if (p != NULL) {
276  len = p->tot_len;
277  } else {
278  len = 0;
279  }
280 
281  if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) {
282  /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
283  return ERR_MEM;
284  } else {
285 #if LWIP_SO_RCVBUF
286  SYS_ARCH_INC(conn->recv_avail, len);
287 #endif /* LWIP_SO_RCVBUF */
288  /* Register event with callback */
289  API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
290  }
291 
292  return ERR_OK;
293 }
294 
306 static err_t
307 poll_tcp(void *arg, struct tcp_pcb *pcb)
308 {
309  struct netconn *conn = (struct netconn *)arg;
310 
311  LWIP_UNUSED_ARG(pcb);
312  LWIP_ASSERT("conn != NULL", (conn != NULL));
313 
314  if (conn->state == NETCONN_WRITE) {
315  lwip_netconn_do_writemore(conn WRITE_DELAYED);
316  } else if (conn->state == NETCONN_CLOSE) {
317 #if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER
318  if (conn->current_msg && conn->current_msg->msg.sd.polls_left) {
319  conn->current_msg->msg.sd.polls_left--;
320  }
321 #endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */
322  lwip_netconn_do_close_internal(conn WRITE_DELAYED);
323  }
324  /* @todo: implement connect timeout here? */
325 
326  /* Did a nonblocking write fail before? Then check available write-space. */
327  if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
328  /* If the queued byte- or pbuf-count drops below the configured low-water limit,
329  let select mark this pcb as writable again. */
330  if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
331  (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
332  conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
333  API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
334  }
335  }
336 
337  return ERR_OK;
338 }
339 
347 static err_t
348 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
349 {
350  struct netconn *conn = (struct netconn *)arg;
351 
352  LWIP_UNUSED_ARG(pcb);
353  LWIP_ASSERT("conn != NULL", (conn != NULL));
354 
355  if (conn) {
356  if (conn->state == NETCONN_WRITE) {
357  lwip_netconn_do_writemore(conn WRITE_DELAYED);
358  } else if (conn->state == NETCONN_CLOSE) {
359  lwip_netconn_do_close_internal(conn WRITE_DELAYED);
360  }
361 
362  /* If the queued byte- or pbuf-count drops below the configured low-water limit,
363  let select mark this pcb as writable again. */
364  if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
365  (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
366  conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
367  API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
368  }
369  }
370 
371  return ERR_OK;
372 }
373 
381 static void
382 err_tcp(void *arg, err_t err)
383 {
384  struct netconn *conn;
385  enum netconn_state old_state;
386 
387  conn = (struct netconn *)arg;
388  LWIP_ASSERT("conn != NULL", (conn != NULL));
389 
390  conn->pcb.tcp = NULL;
391 
392  /* reset conn->state now before waking up other threads */
393  old_state = conn->state;
394  conn->state = NETCONN_NONE;
395 
396  if (old_state == NETCONN_CLOSE) {
397  /* RST during close: let close return success & dealloc the netconn */
398  err = ERR_OK;
399  NETCONN_SET_SAFE_ERR(conn, ERR_OK);
400  } else {
401  /* no check since this is always fatal! */
402  SYS_ARCH_SET(conn->last_err, err);
403  }
404 
405  /* @todo: the type of NETCONN_EVT created should depend on 'old_state' */
406 
407  /* Notify the user layer about a connection error. Used to signal select. */
408  API_EVENT(conn, NETCONN_EVT_ERROR, 0);
409  /* Try to release selects pending on 'read' or 'write', too.
410  They will get an error if they actually try to read or write. */
411  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
412  API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
413 
414  /* pass NULL-message to recvmbox to wake up pending recv */
415  if (sys_mbox_valid(&conn->recvmbox)) {
416  /* use trypost to prevent deadlock */
417  sys_mbox_trypost(&conn->recvmbox, NULL);
418  }
419  /* pass NULL-message to acceptmbox to wake up pending accept */
420  if (sys_mbox_valid(&conn->acceptmbox)) {
421  /* use trypost to preven deadlock */
422  sys_mbox_trypost(&conn->acceptmbox, NULL);
423  }
424 
425  if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
426  (old_state == NETCONN_CONNECT)) {
427  /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary
428  since the pcb has already been deleted! */
429  int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
430  SET_NONBLOCKING_CONNECT(conn, 0);
431 
432  if (!was_nonblocking_connect) {
433  sys_sem_t* op_completed_sem;
434  /* set error return code */
435  LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
436  conn->current_msg->err = err;
437  op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
438  LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem));
439  conn->current_msg = NULL;
440  /* wake up the waiting task */
441  NETCONN_SET_SAFE_ERR(conn, err);
442  sys_sem_signal(op_completed_sem);
443  }
444  } else {
445  LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
446  }
447 }
448 
455 static void
456 setup_tcp(struct netconn *conn)
457 {
458  struct tcp_pcb *pcb;
459 
460  pcb = conn->pcb.tcp;
461  tcp_arg(pcb, conn);
462  tcp_recv(pcb, recv_tcp);
463  tcp_sent(pcb, sent_tcp);
464  tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL);
465  tcp_err(pcb, err_tcp);
466 }
467 
474 static err_t
475 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
476 {
477  struct netconn *newconn;
478  struct netconn *conn = (struct netconn *)arg;
479 
480  if (conn == NULL) {
481  return ERR_VAL;
482  }
483  if (!sys_mbox_valid(&conn->acceptmbox)) {
484  LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
485  return ERR_VAL;
486  }
487 
488  if (newpcb == NULL) {
489  /* out-of-pcbs during connect: pass on this error to the application */
490  if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) {
491  /* Register event with callback */
492  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
493  }
494  return ERR_VAL;
495  }
496 
497  LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state)));
498 
499  /* We have to set the callback here even though
500  * the new socket is unknown. newconn->socket is marked as -1. */
501  newconn = netconn_alloc(conn->type, conn->callback);
502  if (newconn == NULL) {
503  /* outof netconns: pass on this error to the application */
504  if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) {
505  /* Register event with callback */
506  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
507  }
508  return ERR_MEM;
509  }
510  newconn->pcb.tcp = newpcb;
511  setup_tcp(newconn);
512  /* no protection: when creating the pcb, the netconn is not yet known
513  to the application thread */
514  newconn->last_err = err;
515 
516  /* handle backlog counter */
517  tcp_backlog_delayed(newpcb);
518 
519  if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
520  /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
521  so do nothing here! */
522  /* remove all references to this netconn from the pcb */
523  struct tcp_pcb* pcb = newconn->pcb.tcp;
524  tcp_arg(pcb, NULL);
525  tcp_recv(pcb, NULL);
526  tcp_sent(pcb, NULL);
527  tcp_poll(pcb, NULL, 0);
528  tcp_err(pcb, NULL);
529  /* remove reference from to the pcb from this netconn */
530  newconn->pcb.tcp = NULL;
531  /* no need to drain since we know the recvmbox is empty. */
532  sys_mbox_free(&newconn->recvmbox);
533  sys_mbox_set_invalid(&newconn->recvmbox);
534  netconn_free(newconn);
535  return ERR_MEM;
536  } else {
537  /* Register event with callback */
538  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
539  }
540 
541  return ERR_OK;
542 }
543 #endif /* LWIP_TCP */
544 
551 static void
552 pcb_new(struct api_msg *msg)
553 {
554  enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4;
555 
556  LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
557 
558 #if LWIP_IPV6 && LWIP_IPV4
559  /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */
560  if(NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) {
561  iptype = IPADDR_TYPE_ANY;
562  }
563 #endif
564 
565  /* Allocate a PCB for this connection */
566  switch(NETCONNTYPE_GROUP(msg->conn->type)) {
567 #if LWIP_RAW
568  case NETCONN_RAW:
569  msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto);
570  if (msg->conn->pcb.raw != NULL) {
571 #if LWIP_IPV6
572  /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */
573  if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) {
574  msg->conn->pcb.raw->chksum_reqd = 1;
575  msg->conn->pcb.raw->chksum_offset = 2;
576  }
577 #endif /* LWIP_IPV6 */
578  raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
579  }
580  break;
581 #endif /* LWIP_RAW */
582 #if LWIP_UDP
583  case NETCONN_UDP:
584  msg->conn->pcb.udp = udp_new_ip_type(iptype);
585  if (msg->conn->pcb.udp != NULL) {
586 #if LWIP_UDPLITE
587  if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
588  udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
589  }
590 #endif /* LWIP_UDPLITE */
591  if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) {
592  udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
593  }
594  udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
595  }
596  break;
597 #endif /* LWIP_UDP */
598 #if LWIP_TCP
599  case NETCONN_TCP:
600  msg->conn->pcb.tcp = tcp_new_ip_type(iptype);
601  if (msg->conn->pcb.tcp != NULL) {
602  setup_tcp(msg->conn);
603  }
604  break;
605 #endif /* LWIP_TCP */
606  default:
607  /* Unsupported netconn type, e.g. protocol disabled */
608  msg->err = ERR_VAL;
609  return;
610  }
611  if (msg->conn->pcb.ip == NULL) {
612  msg->err = ERR_MEM;
613  }
614 }
615 
622 void
623 lwip_netconn_do_newconn(void *m)
624 {
625  struct api_msg *msg = (struct api_msg*)m;
626 
627  msg->err = ERR_OK;
628  if (msg->conn->pcb.tcp == NULL) {
629  pcb_new(msg);
630  }
631  /* Else? This "new" connection already has a PCB allocated. */
632  /* Is this an error condition? Should it be deleted? */
633  /* We currently just are happy and return. */
634 
635  TCPIP_APIMSG_ACK(msg);
636 }
637 
647 struct netconn*
648 netconn_alloc(enum netconn_type t, netconn_callback callback)
649 {
650  struct netconn *conn;
651  int size;
652 
653  conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
654  if (conn == NULL) {
655  return NULL;
656  }
657 
658  conn->last_err = ERR_OK;
659  conn->type = t;
660  conn->pcb.tcp = NULL;
661 
662  /* If all sizes are the same, every compiler should optimize this switch to nothing */
663  switch(NETCONNTYPE_GROUP(t)) {
664 #if LWIP_RAW
665  case NETCONN_RAW:
667  break;
668 #endif /* LWIP_RAW */
669 #if LWIP_UDP
670  case NETCONN_UDP:
672  break;
673 #endif /* LWIP_UDP */
674 #if LWIP_TCP
675  case NETCONN_TCP:
677  break;
678 #endif /* LWIP_TCP */
679  default:
680  LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
681  goto free_and_return;
682  }
683 
684  if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
685  goto free_and_return;
686  }
687 #if !LWIP_NETCONN_SEM_PER_THREAD
688  if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
689  sys_mbox_free(&conn->recvmbox);
690  goto free_and_return;
691  }
692 #endif
693 
694 #if LWIP_TCP
695  sys_mbox_set_invalid(&conn->acceptmbox);
696 #endif
697  conn->state = NETCONN_NONE;
698 #if LWIP_SOCKET
699  /* initialize socket to -1 since 0 is a valid socket */
700  conn->socket = -1;
701 #endif /* LWIP_SOCKET */
702  conn->callback = callback;
703 #if LWIP_TCP
704  conn->current_msg = NULL;
705  conn->write_offset = 0;
706 #endif /* LWIP_TCP */
707 #if LWIP_SO_SNDTIMEO
708  conn->send_timeout = 0;
709 #endif /* LWIP_SO_SNDTIMEO */
710 #if LWIP_SO_RCVTIMEO
711  conn->recv_timeout = 0;
712 #endif /* LWIP_SO_RCVTIMEO */
713 #if LWIP_SO_RCVBUF
714  conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
715  conn->recv_avail = 0;
716 #endif /* LWIP_SO_RCVBUF */
717 #if LWIP_SO_LINGER
718  conn->linger = -1;
719 #endif /* LWIP_SO_LINGER */
720  conn->flags = 0;
721  return conn;
722 free_and_return:
723  memp_free(MEMP_NETCONN, conn);
724  return NULL;
725 }
726 
733 void
734 netconn_free(struct netconn *conn)
735 {
736  LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
737  LWIP_ASSERT("recvmbox must be deallocated before calling this function",
738  !sys_mbox_valid(&conn->recvmbox));
739 #if LWIP_TCP
740  LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
741  !sys_mbox_valid(&conn->acceptmbox));
742 #endif /* LWIP_TCP */
743 
744 #if !LWIP_NETCONN_SEM_PER_THREAD
745  sys_sem_free(&conn->op_completed);
746  sys_sem_set_invalid(&conn->op_completed);
747 #endif
748 
749  memp_free(MEMP_NETCONN, conn);
750 }
751 
760 static void
761 netconn_drain(struct netconn *conn)
762 {
763  void *mem;
764 #if LWIP_TCP
765  struct pbuf *p;
766 #endif /* LWIP_TCP */
767 
768  /* This runs in tcpip_thread, so we don't need to lock against rx packets */
769 
770  /* Delete and drain the recvmbox. */
771  if (sys_mbox_valid(&conn->recvmbox)) {
772  while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
773 #if LWIP_TCP
774  if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
775  if (mem != NULL) {
776  p = (struct pbuf*)mem;
777  /* pcb might be set to NULL already by err_tcp() */
778  if (conn->pcb.tcp != NULL) {
779  tcp_recved(conn->pcb.tcp, p->tot_len);
780  }
781  pbuf_free(p);
782  }
783  } else
784 #endif /* LWIP_TCP */
785  {
786  netbuf_delete((struct netbuf *)mem);
787  }
788  }
789  sys_mbox_free(&conn->recvmbox);
790  sys_mbox_set_invalid(&conn->recvmbox);
791  }
792 
793  /* Delete and drain the acceptmbox. */
794 #if LWIP_TCP
795  if (sys_mbox_valid(&conn->acceptmbox)) {
796  while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
797  if (mem != &netconn_aborted) {
798  struct netconn *newconn = (struct netconn *)mem;
799  /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
800  /* pcb might be set to NULL already by err_tcp() */
801  /* drain recvmbox */
802  netconn_drain(newconn);
803  if (newconn->pcb.tcp != NULL) {
804  tcp_abort(newconn->pcb.tcp);
805  newconn->pcb.tcp = NULL;
806  }
807  netconn_free(newconn);
808  }
809  }
810  sys_mbox_free(&conn->acceptmbox);
811  sys_mbox_set_invalid(&conn->acceptmbox);
812  }
813 #endif /* LWIP_TCP */
814 }
815 
816 #if LWIP_TCP
817 
824 static err_t
825 lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM)
826 {
827  err_t err;
828  u8_t shut, shut_rx, shut_tx, close;
829  u8_t close_finished = 0;
830  struct tcp_pcb* tpcb;
831 #if LWIP_SO_LINGER
832  u8_t linger_wait_required = 0;
833 #endif /* LWIP_SO_LINGER */
834 
835  LWIP_ASSERT("invalid conn", (conn != NULL));
836  LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP));
837  LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
838  LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
839  LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
840 
841  tpcb = conn->pcb.tcp;
842  shut = conn->current_msg->msg.sd.shut;
843  shut_rx = shut & NETCONN_SHUT_RD;
844  shut_tx = shut & NETCONN_SHUT_WR;
845  /* shutting down both ends is the same as closing
846  (also if RD or WR side was shut down before already) */
847  if (shut == NETCONN_SHUT_RDWR) {
848  close = 1;
849  } else if (shut_rx &&
850  ((tpcb->state == FIN_WAIT_1) ||
851  (tpcb->state == FIN_WAIT_2) ||
852  (tpcb->state == CLOSING))) {
853  close = 1;
854  } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) {
855  close = 1;
856  } else {
857  close = 0;
858  }
859 
860  /* Set back some callback pointers */
861  if (close) {
862  tcp_arg(tpcb, NULL);
863  }
864  if (tpcb->state == LISTEN) {
865  tcp_accept(tpcb, NULL);
866  } else {
867  /* some callbacks have to be reset if tcp_close is not successful */
868  if (shut_rx) {
869  tcp_recv(tpcb, NULL);
870  tcp_accept(tpcb, NULL);
871  }
872  if (shut_tx) {
873  tcp_sent(tpcb, NULL);
874  }
875  if (close) {
876  tcp_poll(tpcb, NULL, 0);
877  tcp_err(tpcb, NULL);
878  }
879  }
880  /* Try to close the connection */
881  if (close) {
882 #if LWIP_SO_LINGER
883  /* check linger possibilites before calling tcp_close */
884  err = ERR_OK;
885  /* linger enabled/required at all? (i.e. is there untransmitted data left?) */
886  if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) {
887  if ((conn->linger == 0)) {
888  /* data left but linger prevents waiting */
889  tcp_abort(tpcb);
890  tpcb = NULL;
891  } else if (conn->linger > 0) {
892  /* data left and linger says we should wait */
893  if (netconn_is_nonblocking(conn)) {
894  /* data left on a nonblocking netconn -> cannot linger */
895  err = ERR_WOULDBLOCK;
896  } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >=
897  (conn->linger * 1000)) {
898  /* data left but linger timeout has expired (this happens on further
899  calls to this function through poll_tcp */
900  tcp_abort(tpcb);
901  tpcb = NULL;
902  } else {
903  /* data left -> need to wait for ACK after successful close */
904  linger_wait_required = 1;
905  }
906  }
907  }
908  if ((err == ERR_OK) && (tpcb != NULL))
909 #endif /* LWIP_SO_LINGER */
910  {
911  err = tcp_close(tpcb);
912  }
913  } else {
914  err = tcp_shutdown(tpcb, shut_rx, shut_tx);
915  }
916  if (err == ERR_OK) {
917  close_finished = 1;
918 #if LWIP_SO_LINGER
919  if (linger_wait_required) {
920  /* wait for ACK of all unsent/unacked data by just getting called again */
921  close_finished = 0;
922  err = ERR_INPROGRESS;
923  }
924 #endif /* LWIP_SO_LINGER */
925  } else {
926  if (err == ERR_MEM) {
927  /* Closing failed because of memory shortage, try again later. Even for
928  nonblocking netconns, we have to wait since no standard socket application
929  is prepared for close failing because of resource shortage.
930  Check the timeout: this is kind of an lwip addition to the standard sockets:
931  we wait for some time when failing to allocate a segment for the FIN */
932 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
934 #if LWIP_SO_SNDTIMEO
935  if (conn->send_timeout > 0) {
936  close_timeout = conn->send_timeout;
937  }
938 #endif /* LWIP_SO_SNDTIMEO */
939 #if LWIP_SO_LINGER
940  if (conn->linger >= 0) {
941  /* use linger timeout (seconds) */
942  close_timeout = conn->linger * 1000U;
943  }
944 #endif
945  if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
946 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
947  if (conn->current_msg->msg.sd.polls_left == 0) {
948 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
949  close_finished = 1;
950  if (close) {
951  /* in this case, we want to RST the connection */
952  tcp_abort(tpcb);
953  err = ERR_OK;
954  }
955  }
956  } else {
957  /* Closing failed for a non-memory error: give up */
958  close_finished = 1;
959  }
960  }
961  if (close_finished) {
962  /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */
963  sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
964  conn->current_msg->err = err;
965  conn->current_msg = NULL;
966  conn->state = NETCONN_NONE;
967  if (err == ERR_OK) {
968  if (close) {
969  /* Set back some callback pointers as conn is going away */
970  conn->pcb.tcp = NULL;
971  /* Trigger select() in socket layer. Make sure everybody notices activity
972  on the connection, error first! */
973  API_EVENT(conn, NETCONN_EVT_ERROR, 0);
974  }
975  if (shut_rx) {
976  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
977  }
978  if (shut_tx) {
979  API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
980  }
981  }
982  NETCONN_SET_SAFE_ERR(conn, err);
983 #if LWIP_TCPIP_CORE_LOCKING
984  if (delayed)
985 #endif
986  {
987  /* wake up the application task */
988  sys_sem_signal(op_completed_sem);
989  }
990  return ERR_OK;
991  }
992  if (!close_finished) {
993  /* Closing failed and we want to wait: restore some of the callbacks */
994  /* Closing of listen pcb will never fail! */
995  LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN));
996  if (shut_tx) {
997  tcp_sent(tpcb, sent_tcp);
998  }
999  /* when waiting for close, set up poll interval to 500ms */
1000  tcp_poll(tpcb, poll_tcp, 1);
1001  tcp_err(tpcb, err_tcp);
1002  tcp_arg(tpcb, conn);
1003  /* don't restore recv callback: we don't want to receive any more data */
1004  }
1005  /* If closing didn't succeed, we get called again either
1006  from poll_tcp or from sent_tcp */
1007  LWIP_ASSERT("err != ERR_OK", err != ERR_OK);
1008  return err;
1009 }
1010 #endif /* LWIP_TCP */
1011 
1018 void
1019 lwip_netconn_do_delconn(void *m)
1020 {
1021  struct api_msg *msg = (struct api_msg*)m;
1022 
1023  enum netconn_state state = msg->conn->state;
1024  LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */
1025  (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP));
1026 #if LWIP_NETCONN_FULLDUPLEX
1027  /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */
1028  if (state != NETCONN_NONE) {
1029  if ((state == NETCONN_WRITE) ||
1030  ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1031  /* close requested, abort running write/connect */
1032  sys_sem_t* op_completed_sem;
1033  LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
1034  op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
1035  msg->conn->current_msg->err = ERR_CLSD;
1036  msg->conn->current_msg = NULL;
1037  msg->conn->write_offset = 0;
1038  msg->conn->state = NETCONN_NONE;
1039  NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD);
1040  sys_sem_signal(op_completed_sem);
1041  }
1042  }
1043 #else /* LWIP_NETCONN_FULLDUPLEX */
1044  if (((state != NETCONN_NONE) &&
1045  (state != NETCONN_LISTEN) &&
1046  (state != NETCONN_CONNECT)) ||
1047  ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1048  /* This means either a blocking write or blocking connect is running
1049  (nonblocking write returns and sets state to NONE) */
1050  msg->err = ERR_INPROGRESS;
1051  } else
1052 #endif /* LWIP_NETCONN_FULLDUPLEX */
1053  {
1054  LWIP_ASSERT("blocking connect in progress",
1055  (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
1056  msg->err = ERR_OK;
1057  /* Drain and delete mboxes */
1058  netconn_drain(msg->conn);
1059 
1060  if (msg->conn->pcb.tcp != NULL) {
1061 
1062  switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1063 #if LWIP_RAW
1064  case NETCONN_RAW:
1065  raw_remove(msg->conn->pcb.raw);
1066  break;
1067 #endif /* LWIP_RAW */
1068 #if LWIP_UDP
1069  case NETCONN_UDP:
1070  msg->conn->pcb.udp->recv_arg = NULL;
1071  udp_remove(msg->conn->pcb.udp);
1072  break;
1073 #endif /* LWIP_UDP */
1074 #if LWIP_TCP
1075  case NETCONN_TCP:
1076  LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
1077  msg->conn->write_offset == 0);
1078  msg->conn->state = NETCONN_CLOSE;
1079  msg->msg.sd.shut = NETCONN_SHUT_RDWR;
1080  msg->conn->current_msg = msg;
1081 #if LWIP_TCPIP_CORE_LOCKING
1082  if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
1083  LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
1085  sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1086  LOCK_TCPIP_CORE();
1087  LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1088  }
1089 #else /* LWIP_TCPIP_CORE_LOCKING */
1090  lwip_netconn_do_close_internal(msg->conn);
1091 #endif /* LWIP_TCPIP_CORE_LOCKING */
1092  /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing
1093  the application thread, so we can return at this point! */
1094  return;
1095 #endif /* LWIP_TCP */
1096  default:
1097  break;
1098  }
1099  msg->conn->pcb.tcp = NULL;
1100  }
1101  /* tcp netconns don't come here! */
1102 
1103  /* @todo: this lets select make the socket readable and writable,
1104  which is wrong! errfd instead? */
1105  API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
1106  API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
1107  }
1108  if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) {
1109  TCPIP_APIMSG_ACK(msg);
1110  }
1111 }
1112 
1120 void
1121 lwip_netconn_do_bind(void *m)
1122 {
1123  struct api_msg *msg = (struct api_msg*)m;
1124 
1125  if (ERR_IS_FATAL(msg->conn->last_err)) {
1126  msg->err = msg->conn->last_err;
1127  } else {
1128  msg->err = ERR_VAL;
1129  if (msg->conn->pcb.tcp != NULL) {
1130  switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1131 #if LWIP_RAW
1132  case NETCONN_RAW:
1133  msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1134  break;
1135 #endif /* LWIP_RAW */
1136 #if LWIP_UDP
1137  case NETCONN_UDP:
1138  msg->err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1139  break;
1140 #endif /* LWIP_UDP */
1141 #if LWIP_TCP
1142  case NETCONN_TCP:
1143  msg->err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1144  break;
1145 #endif /* LWIP_TCP */
1146  default:
1147  break;
1148  }
1149  }
1150  }
1151  TCPIP_APIMSG_ACK(msg);
1152 }
1153 
1154 #if LWIP_TCP
1155 
1161 static err_t
1162 lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
1163 {
1164  struct netconn *conn;
1165  int was_blocking;
1166  sys_sem_t* op_completed_sem = NULL;
1167 
1168  LWIP_UNUSED_ARG(pcb);
1169 
1170  conn = (struct netconn *)arg;
1171 
1172  if (conn == NULL) {
1173  return ERR_VAL;
1174  }
1175 
1176  LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
1177  LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
1178  (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
1179 
1180  if (conn->current_msg != NULL) {
1181  conn->current_msg->err = err;
1182  op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1183  }
1184  if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) {
1185  setup_tcp(conn);
1186  }
1187  was_blocking = !IN_NONBLOCKING_CONNECT(conn);
1188  SET_NONBLOCKING_CONNECT(conn, 0);
1189  LWIP_ASSERT("blocking connect state error",
1190  (was_blocking && op_completed_sem != NULL) ||
1191  (!was_blocking && op_completed_sem == NULL));
1192  conn->current_msg = NULL;
1193  conn->state = NETCONN_NONE;
1194  NETCONN_SET_SAFE_ERR(conn, ERR_OK);
1195  API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
1196 
1197  if (was_blocking) {
1198  sys_sem_signal(op_completed_sem);
1199  }
1200  return ERR_OK;
1201 }
1202 #endif /* LWIP_TCP */
1203 
1211 void
1212 lwip_netconn_do_connect(void *m)
1213 {
1214  struct api_msg *msg = (struct api_msg*)m;
1215 
1216  if (msg->conn->pcb.tcp == NULL) {
1217  /* This may happen when calling netconn_connect() a second time */
1218  msg->err = ERR_CLSD;
1219  } else {
1220  switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1221 #if LWIP_RAW
1222  case NETCONN_RAW:
1223  msg->err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1224  break;
1225 #endif /* LWIP_RAW */
1226 #if LWIP_UDP
1227  case NETCONN_UDP:
1228  msg->err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1229  break;
1230 #endif /* LWIP_UDP */
1231 #if LWIP_TCP
1232  case NETCONN_TCP:
1233  /* Prevent connect while doing any other action. */
1234  if (msg->conn->state == NETCONN_CONNECT) {
1235  msg->err = ERR_ALREADY;
1236  } else if (msg->conn->state != NETCONN_NONE) {
1237  msg->err = ERR_ISCONN;
1238  } else {
1239  setup_tcp(msg->conn);
1240  msg->err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr),
1241  msg->msg.bc.port, lwip_netconn_do_connected);
1242  if (msg->err == ERR_OK) {
1243  u8_t non_blocking = netconn_is_nonblocking(msg->conn);
1244  msg->conn->state = NETCONN_CONNECT;
1245  SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
1246  if (non_blocking) {
1247  msg->err = ERR_INPROGRESS;
1248  } else {
1249  msg->conn->current_msg = msg;
1250  /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()),
1251  when the connection is established! */
1252 #if LWIP_TCPIP_CORE_LOCKING
1253  LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT);
1255  sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1256  LOCK_TCPIP_CORE();
1257  LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT);
1258 #endif /* LWIP_TCPIP_CORE_LOCKING */
1259  return;
1260  }
1261  }
1262  }
1263  break;
1264 #endif /* LWIP_TCP */
1265  default:
1266  LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
1267  break;
1268  }
1269  }
1270  /* For all other protocols, netconn_connect() calls TCPIP_APIMSG(),
1271  so use TCPIP_APIMSG_ACK() here. */
1272  TCPIP_APIMSG_ACK(msg);
1273 }
1274 
1282 void
1283 lwip_netconn_do_disconnect(void *m)
1284 {
1285  struct api_msg *msg = (struct api_msg*)m;
1286 
1287 #if LWIP_UDP
1288  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1289  udp_disconnect(msg->conn->pcb.udp);
1290  msg->err = ERR_OK;
1291  } else
1292 #endif /* LWIP_UDP */
1293  {
1294  msg->err = ERR_VAL;
1295  }
1296  TCPIP_APIMSG_ACK(msg);
1297 }
1298 
1299 #if LWIP_TCP
1300 
1306 void
1307 lwip_netconn_do_listen(void *m)
1308 {
1309  struct api_msg *msg = (struct api_msg*)m;
1310 
1311  if (ERR_IS_FATAL(msg->conn->last_err)) {
1312  msg->err = msg->conn->last_err;
1313  } else {
1314  msg->err = ERR_CONN;
1315  if (msg->conn->pcb.tcp != NULL) {
1316  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1317  if (msg->conn->state == NETCONN_NONE) {
1318  struct tcp_pcb* lpcb;
1319  if (msg->conn->pcb.tcp->state != CLOSED) {
1320  /* connection is not closed, cannot listen */
1321  msg->err = ERR_VAL;
1322  } else {
1323  err_t err;
1324  u8_t backlog;
1325 #if TCP_LISTEN_BACKLOG
1326  backlog = msg->msg.lb.backlog;
1327 #else /* TCP_LISTEN_BACKLOG */
1328  backlog = TCP_DEFAULT_LISTEN_BACKLOG;
1329 #endif /* TCP_LISTEN_BACKLOG */
1330 #if LWIP_IPV4 && LWIP_IPV6
1331  /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
1332  * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
1333  */
1334  if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) &&
1335  (netconn_get_ipv6only(msg->conn) == 0)) {
1336  /* change PCB type to IPADDR_TYPE_ANY */
1337  IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip, IPADDR_TYPE_ANY);
1338  IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY);
1339  }
1340 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1341 
1342  lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
1343 
1344  if (lpcb == NULL) {
1345  /* in this case, the old pcb is still allocated */
1346  msg->err = err;
1347  } else {
1348  /* delete the recvmbox and allocate the acceptmbox */
1349  if (sys_mbox_valid(&msg->conn->recvmbox)) {
1351  sys_mbox_free(&msg->conn->recvmbox);
1352  sys_mbox_set_invalid(&msg->conn->recvmbox);
1353  }
1354  msg->err = ERR_OK;
1355  if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
1356  msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
1357  }
1358  if (msg->err == ERR_OK) {
1359  msg->conn->state = NETCONN_LISTEN;
1360  msg->conn->pcb.tcp = lpcb;
1361  tcp_arg(msg->conn->pcb.tcp, msg->conn);
1362  tcp_accept(msg->conn->pcb.tcp, accept_function);
1363  } else {
1364  /* since the old pcb is already deallocated, free lpcb now */
1365  tcp_close(lpcb);
1366  msg->conn->pcb.tcp = NULL;
1367  }
1368  }
1369  }
1370  } else if (msg->conn->state == NETCONN_LISTEN) {
1371  /* already listening, allow updating of the backlog */
1372  msg->err = ERR_OK;
1373  tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog);
1374  }
1375  } else {
1376  msg->err = ERR_ARG;
1377  }
1378  }
1379  }
1380  TCPIP_APIMSG_ACK(msg);
1381 }
1382 #endif /* LWIP_TCP */
1383 
1390 void
1391 lwip_netconn_do_send(void *m)
1392 {
1393  struct api_msg *msg = (struct api_msg*)m;
1394 
1395  if (ERR_IS_FATAL(msg->conn->last_err)) {
1396  msg->err = msg->conn->last_err;
1397  } else {
1398  msg->err = ERR_CONN;
1399  if (msg->conn->pcb.tcp != NULL) {
1400  switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1401 #if LWIP_RAW
1402  case NETCONN_RAW:
1403  if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1404  msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
1405  } else {
1406  msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
1407  }
1408  break;
1409 #endif
1410 #if LWIP_UDP
1411  case NETCONN_UDP:
1412 #if LWIP_CHECKSUM_ON_COPY
1413  if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1414  msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1415  msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1416  } else {
1417  msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1418  &msg->msg.b->addr, msg->msg.b->port,
1419  msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1420  }
1421 #else /* LWIP_CHECKSUM_ON_COPY */
1422  if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1423  msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
1424  } else {
1425  msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
1426  }
1427 #endif /* LWIP_CHECKSUM_ON_COPY */
1428  break;
1429 #endif /* LWIP_UDP */
1430  default:
1431  break;
1432  }
1433  }
1434  }
1435  TCPIP_APIMSG_ACK(msg);
1436 }
1437 
1438 #if LWIP_TCP
1439 
1445 void
1446 lwip_netconn_do_recv(void *m)
1447 {
1448  struct api_msg *msg = (struct api_msg*)m;
1449 
1450  msg->err = ERR_OK;
1451  if (msg->conn->pcb.tcp != NULL) {
1452  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1453  u32_t remaining = msg->msg.r.len;
1454  do {
1455  u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
1456  tcp_recved(msg->conn->pcb.tcp, recved);
1457  remaining -= recved;
1458  } while (remaining != 0);
1459  }
1460  }
1461  TCPIP_APIMSG_ACK(msg);
1462 }
1463 
1464 #if TCP_LISTEN_BACKLOG
1465 
1470 void
1471 lwip_netconn_do_accepted(void *m)
1472 {
1473  struct api_msg *msg = (struct api_msg*)m;
1474 
1475  msg->err = ERR_OK;
1476  if (msg->conn->pcb.tcp != NULL) {
1477  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1478  tcp_backlog_accepted(msg->conn->pcb.tcp);
1479  }
1480  }
1481  TCPIP_APIMSG_ACK(msg);
1482 }
1483 #endif /* TCP_LISTEN_BACKLOG */
1484 
1496 static err_t
1497 lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM)
1498 {
1499  err_t err;
1500  const void *dataptr;
1501  u16_t len, available;
1502  u8_t write_finished = 0;
1503  size_t diff;
1504  u8_t dontblock;
1505  u8_t apiflags;
1506 
1507  LWIP_ASSERT("conn != NULL", conn != NULL);
1508  LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
1509  LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
1510  LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
1511  LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
1512  conn->write_offset < conn->current_msg->msg.w.len);
1513 
1514  apiflags = conn->current_msg->msg.w.apiflags;
1515  dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
1516 
1517 #if LWIP_SO_SNDTIMEO
1518  if ((conn->send_timeout != 0) &&
1519  ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
1520  write_finished = 1;
1521  if (conn->write_offset == 0) {
1522  /* nothing has been written */
1523  err = ERR_WOULDBLOCK;
1524  conn->current_msg->msg.w.len = 0;
1525  } else {
1526  /* partial write */
1527  err = ERR_OK;
1528  conn->current_msg->msg.w.len = conn->write_offset;
1529  conn->write_offset = 0;
1530  }
1531  } else
1532 #endif /* LWIP_SO_SNDTIMEO */
1533  {
1534  dataptr = (const u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
1535  diff = conn->current_msg->msg.w.len - conn->write_offset;
1536  if (diff > 0xffffUL) { /* max_u16_t */
1537  len = 0xffff;
1538  apiflags |= TCP_WRITE_FLAG_MORE;
1539  } else {
1540  len = (u16_t)diff;
1541  }
1542  available = tcp_sndbuf(conn->pcb.tcp);
1543  if (available < len) {
1544  /* don't try to write more than sendbuf */
1545  len = available;
1546  if (dontblock) {
1547  if (!len) {
1548  err = ERR_WOULDBLOCK;
1549  goto err_mem;
1550  }
1551  } else {
1552  apiflags |= TCP_WRITE_FLAG_MORE;
1553  }
1554  }
1555  LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
1556  err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
1557  /* if OK or memory error, check available space */
1558  if ((err == ERR_OK) || (err == ERR_MEM)) {
1559 err_mem:
1560  if (dontblock && (len < conn->current_msg->msg.w.len)) {
1561  /* non-blocking write did not write everything: mark the pcb non-writable
1562  and let poll_tcp check writable space to mark the pcb writable again */
1563  API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
1564  conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
1565  } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
1566  (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
1567  /* The queued byte- or pbuf-count exceeds the configured low-water limit,
1568  let select mark this pcb as non-writable. */
1569  API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
1570  }
1571  }
1572 
1573  if (err == ERR_OK) {
1574  err_t out_err;
1575  conn->write_offset += len;
1576  if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) {
1577  /* return sent length */
1578  conn->current_msg->msg.w.len = conn->write_offset;
1579  /* everything was written */
1580  write_finished = 1;
1581  }
1582  out_err = tcp_output(conn->pcb.tcp);
1583  if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) {
1584  /* If tcp_output fails with fatal error or no route is found,
1585  don't try writing any more but return the error
1586  to the application thread. */
1587  err = out_err;
1588  write_finished = 1;
1589  conn->current_msg->msg.w.len = 0;
1590  }
1591  } else if (err == ERR_MEM) {
1592  /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called.
1593  For blocking sockets, we do NOT return to the application
1594  thread, since ERR_MEM is only a temporary error! Non-blocking
1595  will remain non-writable until sent_tcp/poll_tcp is called */
1596 
1597  /* tcp_write returned ERR_MEM, try tcp_output anyway */
1598  err_t out_err = tcp_output(conn->pcb.tcp);
1599  if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) {
1600  /* If tcp_output fails with fatal error or no route is found,
1601  don't try writing any more but return the error
1602  to the application thread. */
1603  err = out_err;
1604  write_finished = 1;
1605  conn->current_msg->msg.w.len = 0;
1606  } else if (dontblock) {
1607  /* non-blocking write is done on ERR_MEM */
1608  err = ERR_WOULDBLOCK;
1609  write_finished = 1;
1610  conn->current_msg->msg.w.len = 0;
1611  }
1612  } else {
1613  /* On errors != ERR_MEM, we don't try writing any more but return
1614  the error to the application thread. */
1615  write_finished = 1;
1616  conn->current_msg->msg.w.len = 0;
1617  }
1618  }
1619  if (write_finished) {
1620  /* everything was written: set back connection state
1621  and back to application task */
1622  sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1623  conn->current_msg->err = err;
1624  conn->current_msg = NULL;
1625  conn->write_offset = 0;
1626  conn->state = NETCONN_NONE;
1627  NETCONN_SET_SAFE_ERR(conn, err);
1628 #if LWIP_TCPIP_CORE_LOCKING
1629  if (delayed)
1630 #endif
1631  {
1632  sys_sem_signal(op_completed_sem);
1633  }
1634  }
1635 #if LWIP_TCPIP_CORE_LOCKING
1636  else {
1637  return ERR_MEM;
1638  }
1639 #endif
1640  return ERR_OK;
1641 }
1642 #endif /* LWIP_TCP */
1643 
1650 void
1651 lwip_netconn_do_write(void *m)
1652 {
1653  struct api_msg *msg = (struct api_msg*)m;
1654 
1655  if (ERR_IS_FATAL(msg->conn->last_err)) {
1656  msg->err = msg->conn->last_err;
1657  } else {
1658  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1659 #if LWIP_TCP
1660  if (msg->conn->state != NETCONN_NONE) {
1661  /* netconn is connecting, closing or in blocking write */
1662  msg->err = ERR_INPROGRESS;
1663  } else if (msg->conn->pcb.tcp != NULL) {
1664  msg->conn->state = NETCONN_WRITE;
1665  /* set all the variables used by lwip_netconn_do_writemore */
1666  LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
1667  msg->conn->write_offset == 0);
1668  LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
1669  msg->conn->current_msg = msg;
1670  msg->conn->write_offset = 0;
1671 #if LWIP_TCPIP_CORE_LOCKING
1672  if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) {
1673  LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
1675  sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1676  LOCK_TCPIP_CORE();
1677  LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE);
1678  }
1679 #else /* LWIP_TCPIP_CORE_LOCKING */
1680  lwip_netconn_do_writemore(msg->conn);
1681 #endif /* LWIP_TCPIP_CORE_LOCKING */
1682  /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG
1683  since lwip_netconn_do_writemore ACKs it! */
1684  return;
1685  } else {
1686  msg->err = ERR_CONN;
1687  }
1688 #else /* LWIP_TCP */
1689  msg->err = ERR_VAL;
1690 #endif /* LWIP_TCP */
1691 #if (LWIP_UDP || LWIP_RAW)
1692  } else {
1693  msg->err = ERR_VAL;
1694 #endif /* (LWIP_UDP || LWIP_RAW) */
1695  }
1696  }
1697  TCPIP_APIMSG_ACK(msg);
1698 }
1699 
1706 void
1707 lwip_netconn_do_getaddr(void *m)
1708 {
1709  struct api_msg *msg = (struct api_msg*)m;
1710 
1711  if (msg->conn->pcb.ip != NULL) {
1712  if (msg->msg.ad.local) {
1713  ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
1714  msg->conn->pcb.ip->local_ip);
1715  } else {
1716  ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
1717  msg->conn->pcb.ip->remote_ip);
1718  }
1719 
1720  msg->err = ERR_OK;
1721  switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1722 #if LWIP_RAW
1723  case NETCONN_RAW:
1724  if (msg->msg.ad.local) {
1725  API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
1726  } else {
1727  /* return an error as connecting is only a helper for upper layers */
1728  msg->err = ERR_CONN;
1729  }
1730  break;
1731 #endif /* LWIP_RAW */
1732 #if LWIP_UDP
1733  case NETCONN_UDP:
1734  if (msg->msg.ad.local) {
1735  API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
1736  } else {
1737  if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
1738  msg->err = ERR_CONN;
1739  } else {
1740  API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
1741  }
1742  }
1743  break;
1744 #endif /* LWIP_UDP */
1745 #if LWIP_TCP
1746  case NETCONN_TCP:
1747  if ((msg->msg.ad.local == 0) &&
1748  ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) {
1749  /* pcb is not connected and remote name is requested */
1750  msg->err = ERR_CONN;
1751  } else {
1752  API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port);
1753  }
1754  break;
1755 #endif /* LWIP_TCP */
1756  default:
1757  LWIP_ASSERT("invalid netconn_type", 0);
1758  break;
1759  }
1760  } else {
1761  msg->err = ERR_CONN;
1762  }
1763  TCPIP_APIMSG_ACK(msg);
1764 }
1765 
1773 void
1774 lwip_netconn_do_close(void *m)
1775 {
1776  struct api_msg *msg = (struct api_msg*)m;
1777 
1778 #if LWIP_TCP
1779  enum netconn_state state = msg->conn->state;
1780  /* First check if this is a TCP netconn and if it is in a correct state
1781  (LISTEN doesn't support half shutdown) */
1782  if ((msg->conn->pcb.tcp != NULL) &&
1783  (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) &&
1784  ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) {
1785  /* Check if we are in a connected state */
1786  if (state == NETCONN_CONNECT) {
1787  /* TCP connect in progress: cannot shutdown */
1788  msg->err = ERR_CONN;
1789  } else if (state == NETCONN_WRITE) {
1790 #if LWIP_NETCONN_FULLDUPLEX
1791  if (msg->msg.sd.shut & NETCONN_SHUT_WR) {
1792  /* close requested, abort running write */
1793  sys_sem_t* write_completed_sem;
1794  LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
1795  write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
1796  msg->conn->current_msg->err = ERR_CLSD;
1797  msg->conn->current_msg = NULL;
1798  msg->conn->write_offset = 0;
1799  msg->conn->state = NETCONN_NONE;
1800  state = NETCONN_NONE;
1801  NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD);
1802  sys_sem_signal(write_completed_sem);
1803  } else {
1804  LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD);
1805  /* In this case, let the write continue and do not interfere with
1806  conn->current_msg or conn->state! */
1807  msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0);
1808  }
1809  }
1810  if (state == NETCONN_NONE) {
1811 #else /* LWIP_NETCONN_FULLDUPLEX */
1812  msg->err = ERR_INPROGRESS;
1813  } else {
1814 #endif /* LWIP_NETCONN_FULLDUPLEX */
1815  if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
1816  /* Drain and delete mboxes */
1817  netconn_drain(msg->conn);
1818  }
1819  LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
1820  msg->conn->write_offset == 0);
1821  msg->conn->state = NETCONN_CLOSE;
1822  msg->conn->current_msg = msg;
1823 #if LWIP_TCPIP_CORE_LOCKING
1824  if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
1825  LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
1827  sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1828  LOCK_TCPIP_CORE();
1829  LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1830  }
1831 #else /* LWIP_TCPIP_CORE_LOCKING */
1832  lwip_netconn_do_close_internal(msg->conn);
1833 #endif /* LWIP_TCPIP_CORE_LOCKING */
1834  /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */
1835  return;
1836  }
1837  } else
1838 #endif /* LWIP_TCP */
1839  {
1840  msg->err = ERR_CONN;
1841  }
1842  TCPIP_APIMSG_ACK(msg);
1843 }
1844 
1845 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
1846 
1852 void
1853 lwip_netconn_do_join_leave_group(void *m)
1854 {
1855  struct api_msg *msg = (struct api_msg*)m;
1856 
1857  if (ERR_IS_FATAL(msg->conn->last_err)) {
1858  msg->err = msg->conn->last_err;
1859  } else {
1860  if (msg->conn->pcb.tcp != NULL) {
1861  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1862 #if LWIP_UDP
1863 #if LWIP_IPV6 && LWIP_IPV6_MLD
1864  if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
1865  if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
1866  msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
1867  ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
1868  } else {
1869  msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
1870  ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
1871  }
1872  }
1873  else
1874 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
1875  {
1876 #if LWIP_IGMP
1877  if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
1878  msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
1879  ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
1880  } else {
1881  msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
1882  ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
1883  }
1884 #endif /* LWIP_IGMP */
1885  }
1886 #endif /* LWIP_UDP */
1887 #if (LWIP_TCP || LWIP_RAW)
1888  } else {
1889  msg->err = ERR_VAL;
1890 #endif /* (LWIP_TCP || LWIP_RAW) */
1891  }
1892  } else {
1893  msg->err = ERR_CONN;
1894  }
1895  }
1896  TCPIP_APIMSG_ACK(msg);
1897 }
1898 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
1899 
1900 #if LWIP_DNS
1901 
1906 static void
1907 lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg)
1908 {
1909  struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1910 
1911  /* we trust the internal implementation to be correct :-) */
1913 
1914  if (ipaddr == NULL) {
1915  /* timeout or memory error */
1916  API_EXPR_DEREF(msg->err) = ERR_VAL;
1917  } else {
1918  /* address was resolved */
1919  API_EXPR_DEREF(msg->err) = ERR_OK;
1920  API_EXPR_DEREF(msg->addr) = *ipaddr;
1921  }
1922  /* wake up the application task waiting in netconn_gethostbyname */
1923  sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
1924 }
1925 
1932 void
1933 lwip_netconn_do_gethostbyname(void *arg)
1934 {
1935  struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1936  u8_t addrtype =
1937 #if LWIP_IPV4 && LWIP_IPV6
1938  msg->dns_addrtype;
1939 #else
1940  LWIP_DNS_ADDRTYPE_DEFAULT;
1941 #endif
1942 
1943  API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name,
1944  API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype);
1945  if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) {
1946  /* on error or immediate success, wake up the application
1947  * task waiting in netconn_gethostbyname */
1948  sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
1949  }
1950 }
1951 #endif /* LWIP_DNS */
1952 
1953 #endif /* LWIP_NETCONN */
tcpip_priv.h
DEFAULT_RAW_RECVMBOX_SIZE
#define DEFAULT_RAW_RECVMBOX_SIZE
Definition: lwipopts.h:263
opt.h
API_EXPR_DEREF
#define API_EXPR_DEREF(expr)
Definition: tcpip_priv.h:90
ip_addr_cmp
#define ip_addr_cmp(addr1, addr2)
Definition: ip_addr.h:316
udp_hdr
Definition: udp.h:53
sys_sem_set_invalid
void sys_sem_set_invalid(struct sys_sem **s)
Definition: sys_arch.c:140
SYS_ARCH_SET
#define SYS_ARCH_SET(var, val)
Definition: sys.h:402
sys_mbox_free
void sys_mbox_free(struct sys_mbox **mb)
Definition: sys_arch.c:194
LWIP_ASSERT
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
sys_sem_new
err_t sys_sem_new(sys_sem_t **sem, u8_t count)
Definition: sys_arch.c:52
PBUF_RAW
Definition: pbuf.h:94
sys_sem_free
void sys_sem_free(sys_sem_t **sem)
Definition: sys_arch.c:75
ip_current_dest_addr
#define ip_current_dest_addr()
Definition: ip.h:212
ERR_IS_FATAL
#define ERR_IS_FATAL(e)
Definition: err.h:99
mem
Definition: mem.c:264
u16_t
uint16_t u16_t
Definition: arch.h:124
string.h
DEFAULT_TCP_RECVMBOX_SIZE
#define DEFAULT_TCP_RECVMBOX_SIZE
Definition: lwipopts.h:267
sys_sem_valid
int sys_sem_valid(struct sys_sem **s)
Definition: sys_arch.c:132
TCP_SNDLOWAT
#define TCP_SNDLOWAT
Definition: lwipopts.h:188
igmp.h
sys_arch_sem_wait
uint32_t sys_arch_sem_wait(struct sys_sem **s, uint32_t timeout)
Definition: sys_arch.c:105
ip_addr_set
#define ip_addr_set(dest, src)
Definition: ip_addr.h:307
IP_IS_ANY_TYPE_VAL
#define IP_IS_ANY_TYPE_VAL(ipaddr)
Definition: ip_addr.h:297
ip_addr_isany
#define ip_addr_isany(ipaddr)
Definition: ip_addr.h:317
pbuf::tot_len
u16_t tot_len
Definition: pbuf.h:156
sys_mbox_tryfetch
#define sys_mbox_tryfetch(mbox, msg)
Definition: sys.h:245
UNLOCK_TCPIP_CORE
#define UNLOCK_TCPIP_CORE()
Definition: tcpip.h:61
u32_t
uint32_t u32_t
Definition: arch.h:126
pbuf_free
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:715
memp_malloc
void * memp_malloc(memp_t type)
Definition: memp.c:385
raw.h
sys_sem
Definition: sem.h:36
memp_free
void memp_free(memp_t type, void *mem)
Definition: memp.c:469
ip_addr_isany_val
#define ip_addr_isany_val(ipaddr)
Definition: ip_addr.h:318
ERR_INPROGRESS
Definition: err.h:73
ERR_MEM
Definition: err.h:65
LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT
#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT
Definition: lwipopts.h:301
ERR_ISCONN
Definition: err.h:83
sys_now
u32_t sys_now(void)
Definition: sys_arch.c:497
LWIP_ERROR
#define LWIP_ERROR(message, expression, handler)
Definition: debug.h:135
mld6.h
ERR_CLSD
Definition: err.h:94
sys_sem_signal
void sys_sem_signal(struct sys_sem **s)
Definition: sys_arch.c:89
pbuf_alloc
struct pbuf * pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type)
Definition: pbuf.c:248
s32_t
int32_t s32_t
Definition: arch.h:127
u8_t
uint8_t u8_t
Definition: arch.h:122
ip_addr_t
ip6_addr_t ip_addr_t
Definition: ip_addr.h:290
ERR_CONN
Definition: err.h:85
IP6_NEXTH_ICMP6
#define IP6_NEXTH_ICMP6
Definition: ip6.h:70
buf
Definition: buf.h:35
API_EXPR_REF
#define API_EXPR_REF(expr)
Definition: tcpip_priv.h:88
ip_current_src_addr
#define ip_current_src_addr()
Definition: ip.h:210
DEFAULT_ACCEPTMBOX_SIZE
#define DEFAULT_ACCEPTMBOX_SIZE
Definition: lwipopts.h:269
ip_2_ip6
#define ip_2_ip6(ipaddr)
Definition: ip_addr.h:301
SYS_ARCH_INC
#define SYS_ARCH_INC(var, val)
Definition: sys.h:375
pbuf_copy
err_t pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from)
Definition: pbuf.c:949
ERR_ARG
Definition: err.h:96
LWIP_UNUSED_ARG
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:315
TCP_SNDQUEUELOWAT
#define TCP_SNDQUEUELOWAT
Definition: lwipopts.h:190
sys_mbox_valid
int sys_mbox_valid(struct sys_mbox **mb)
Definition: sys_arch.c:367
ERR_WOULDBLOCK
Definition: err.h:77
close
int close(struct thread *, struct close_args *)
Definition: descrip.c:162
PBUF_RAM
Definition: pbuf.h:108
sys_mbox_set_invalid
void sys_mbox_set_invalid(struct sys_mbox **mb)
Definition: sys_arch.c:375
ERR_OK
Definition: err.h:63
API_EXPR_REF_SEM
#define API_EXPR_REF_SEM(expr)
Definition: tcpip_priv.h:89
err_t
s8_t err_t
Definition: err.h:57
name
const char * name
Definition: pci.c:37
ip_addr_copy
#define ip_addr_copy(dest, src)
Definition: ip_addr.h:305
ip.h
tcp.h
API_MSG_DEBUG
#define API_MSG_DEBUG
Definition: lwipopts.h:439
udp.h
IP_SET_TYPE_VAL
#define IP_SET_TYPE_VAL(ipaddr, iptype)
Definition: ip_addr.h:298
RECV_BUFSIZE_DEFAULT
#define RECV_BUFSIZE_DEFAULT
Definition: lwipopts.h:299
TCP_DEFAULT_LISTEN_BACKLOG
#define TCP_DEFAULT_LISTEN_BACKLOG
Definition: lwipopts.h:198
SYS_MBOX_EMPTY
#define SYS_MBOX_EMPTY
Definition: sys.h:52
ERR_ALREADY
Definition: err.h:81
sys_mbox_new
err_t sys_mbox_new(struct sys_mbox **mb, int size)
Definition: sys_arch.c:161
memp.h
SYS_ARCH_GET
#define SYS_ARCH_GET(var, ret)
Definition: sys.h:393
DEFAULT_UDP_RECVMBOX_SIZE
#define DEFAULT_UDP_RECVMBOX_SIZE
Definition: lwipopts.h:265
IPADDR_TYPE_ANY
Definition: ip_addr.h:60
ERR_RTE
Definition: err.h:71
sys_mbox_trypost
err_t sys_mbox_trypost(struct sys_mbox **mb, void *msg)
Definition: sys_arch.c:251
dns.h
ERR_VAL
Definition: err.h:75
lwip_ip_addr_type
lwip_ip_addr_type
Definition: ip_addr.h:54
pbuf
Definition: pbuf.h:142
LWIP_DEBUGF
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:164
LOCK_TCPIP_CORE
#define LOCK_TCPIP_CORE()
Definition: tcpip.h:60
ip_addr.h
api_msg.h
IPADDR_TYPE_V4
Definition: ip_addr.h:56
NULL
#define NULL
Definition: fat_string.h:17