STM32F769IDiscovery  1.00
uDANTE Audio Networking with STM32F7 DISCO board
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 "lwip/opt.h"
40 
41 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
42 
43 #include "lwip/priv/api_msg.h"
44 
45 #include "lwip/ip.h"
46 #include "lwip/udp.h"
47 #include "lwip/tcp.h"
48 #include "lwip/raw.h"
49 
50 #include "lwip/memp.h"
51 #include "lwip/igmp.h"
52 #include "lwip/dns.h"
53 #include "lwip/mld6.h"
54 #include "lwip/priv/tcpip_priv.h"
55 
56 #include <string.h>
57 
58 /* netconns are polled once per second (e.g. continue write on memory error) */
59 #define NETCONN_TCP_POLL_INTERVAL 2
60 
61 #define SET_NONBLOCKING_CONNECT(conn, val) do { if (val) { \
62  (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \
63 } else { \
64  (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0)
65 #define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0)
66 
67 /* forward declarations */
68 #if LWIP_TCP
69 #if LWIP_TCPIP_CORE_LOCKING
70 #define WRITE_DELAYED , 1
71 #define WRITE_DELAYED_PARAM , u8_t delayed
72 #else /* LWIP_TCPIP_CORE_LOCKING */
73 #define WRITE_DELAYED
74 #define WRITE_DELAYED_PARAM
75 #endif /* LWIP_TCPIP_CORE_LOCKING */
76 static err_t lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM);
77 static err_t lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM);
78 #endif
79 
80 #if LWIP_RAW
81 
88 static u8_t
89 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
90  const ip_addr_t *addr)
91 {
92  struct pbuf *q;
93  struct netbuf *buf;
94  struct netconn *conn;
95 
96  LWIP_UNUSED_ARG(addr);
97  conn = (struct netconn *)arg;
98 
99  if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) {
100 #if LWIP_SO_RCVBUF
101  int recv_avail;
102  SYS_ARCH_GET(conn->recv_avail, recv_avail);
103  if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
104  return 0;
105  }
106 #endif /* LWIP_SO_RCVBUF */
107  /* copy the whole packet into new pbufs */
109  if (q != NULL) {
110  if (pbuf_copy(q, p) != ERR_OK) {
111  pbuf_free(q);
112  q = NULL;
113  }
114  }
115 
116  if (q != NULL) {
117  u16_t len;
118  buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
119  if (buf == NULL) {
120  pbuf_free(q);
121  return 0;
122  }
123 
124  buf->p = q;
125  buf->ptr = q;
126  ip_addr_copy(buf->addr, *ip_current_src_addr());
127  buf->port = pcb->protocol;
128 
129  len = q->tot_len;
130  if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
131  netbuf_delete(buf);
132  return 0;
133  } else {
134 #if LWIP_SO_RCVBUF
135  SYS_ARCH_INC(conn->recv_avail, len);
136 #endif /* LWIP_SO_RCVBUF */
137  /* Register event with callback */
138  API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
139  }
140  }
141  }
142 
143  return 0; /* do not eat the packet */
144 }
145 #endif /* LWIP_RAW*/
146 
147 #if LWIP_UDP
148 
154 static void
155 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
156  const ip_addr_t *addr, u16_t port)
157 {
158  struct netbuf *buf;
159  struct netconn *conn;
160  u16_t len;
161 #if LWIP_SO_RCVBUF
162  int recv_avail;
163 #endif /* LWIP_SO_RCVBUF */
164 
165  LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
166  LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
167  LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
168  conn = (struct netconn *)arg;
169  LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
170 
171 #if LWIP_SO_RCVBUF
172  SYS_ARCH_GET(conn->recv_avail, recv_avail);
173  if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) ||
174  ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
175 #else /* LWIP_SO_RCVBUF */
176  if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) {
177 #endif /* LWIP_SO_RCVBUF */
178  pbuf_free(p);
179  return;
180  }
181 
182  buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
183  if (buf == NULL) {
184  pbuf_free(p);
185  return;
186  } else {
187  buf->p = p;
188  buf->ptr = p;
189  ip_addr_set(&buf->addr, addr);
190  buf->port = port;
191 #if LWIP_NETBUF_RECVINFO
192  {
193  /* get the UDP header - always in the first pbuf, ensured by udp_input */
194  const struct udp_hdr* udphdr = (const struct udp_hdr*)ip_next_header_ptr();
195 #if LWIP_CHECKSUM_ON_COPY
196  buf->flags = NETBUF_FLAG_DESTADDR;
197 #endif /* LWIP_CHECKSUM_ON_COPY */
198  ip_addr_set(&buf->toaddr, ip_current_dest_addr());
199  buf->toport_chksum = udphdr->dest;
200  }
201 #endif /* LWIP_NETBUF_RECVINFO */
202  }
203 
204  len = p->tot_len;
205  if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
206  netbuf_delete(buf);
207  return;
208  } else {
209 #if LWIP_SO_RCVBUF
210  SYS_ARCH_INC(conn->recv_avail, len);
211 #endif /* LWIP_SO_RCVBUF */
212  /* Register event with callback */
213  API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
214  }
215 }
216 #endif /* LWIP_UDP */
217 
218 #if LWIP_TCP
219 
225 static err_t
226 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
227 {
228  struct netconn *conn;
229  u16_t len;
230 
231  LWIP_UNUSED_ARG(pcb);
232  LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
233  LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
234  conn = (struct netconn *)arg;
235 
236  if (conn == NULL) {
237  return ERR_VAL;
238  }
239  LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
240 
241  if (!sys_mbox_valid(&conn->recvmbox)) {
242  /* recvmbox already deleted */
243  if (p != NULL) {
244  tcp_recved(pcb, p->tot_len);
245  pbuf_free(p);
246  }
247  return ERR_OK;
248  }
249  /* Unlike for UDP or RAW pcbs, don't check for available space
250  using recv_avail since that could break the connection
251  (data is already ACKed) */
252 
253  /* don't overwrite fatal errors! */
254  if (err != ERR_OK) {
255  NETCONN_SET_SAFE_ERR(conn, err);
256  }
257 
258  if (p != NULL) {
259  len = p->tot_len;
260  } else {
261  len = 0;
262  }
263 
264  if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) {
265  /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
266  return ERR_MEM;
267  } else {
268 #if LWIP_SO_RCVBUF
269  SYS_ARCH_INC(conn->recv_avail, len);
270 #endif /* LWIP_SO_RCVBUF */
271  /* Register event with callback */
272  API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
273  }
274 
275  return ERR_OK;
276 }
277 
289 static err_t
290 poll_tcp(void *arg, struct tcp_pcb *pcb)
291 {
292  struct netconn *conn = (struct netconn *)arg;
293 
294  LWIP_UNUSED_ARG(pcb);
295  LWIP_ASSERT("conn != NULL", (conn != NULL));
296 
297  if (conn->state == NETCONN_WRITE) {
298  lwip_netconn_do_writemore(conn WRITE_DELAYED);
299  } else if (conn->state == NETCONN_CLOSE) {
300 #if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER
301  if (conn->current_msg && conn->current_msg->msg.sd.polls_left) {
302  conn->current_msg->msg.sd.polls_left--;
303  }
304 #endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */
305  lwip_netconn_do_close_internal(conn WRITE_DELAYED);
306  }
307  /* @todo: implement connect timeout here? */
308 
309  /* Did a nonblocking write fail before? Then check available write-space. */
310  if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
311  /* If the queued byte- or pbuf-count drops below the configured low-water limit,
312  let select mark this pcb as writable again. */
313  if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
314  (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
315  conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
316  API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
317  }
318  }
319 
320  return ERR_OK;
321 }
322 
330 static err_t
331 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
332 {
333  struct netconn *conn = (struct netconn *)arg;
334 
335  LWIP_UNUSED_ARG(pcb);
336  LWIP_ASSERT("conn != NULL", (conn != NULL));
337 
338  if (conn) {
339  if (conn->state == NETCONN_WRITE) {
340  lwip_netconn_do_writemore(conn WRITE_DELAYED);
341  } else if (conn->state == NETCONN_CLOSE) {
342  lwip_netconn_do_close_internal(conn WRITE_DELAYED);
343  }
344 
345  /* If the queued byte- or pbuf-count drops below the configured low-water limit,
346  let select mark this pcb as writable again. */
347  if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
348  (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
349  conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
350  API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
351  }
352  }
353 
354  return ERR_OK;
355 }
356 
364 static void
365 err_tcp(void *arg, err_t err)
366 {
367  struct netconn *conn;
368  enum netconn_state old_state;
369 
370  conn = (struct netconn *)arg;
371  LWIP_ASSERT("conn != NULL", (conn != NULL));
372 
373  conn->pcb.tcp = NULL;
374 
375  /* no check since this is always fatal! */
376  SYS_ARCH_SET(conn->last_err, err);
377 
378  /* reset conn->state now before waking up other threads */
379  old_state = conn->state;
380  conn->state = NETCONN_NONE;
381 
382  /* @todo: the type of NETCONN_EVT created should depend on 'old_state' */
383 
384  /* Notify the user layer about a connection error. Used to signal select. */
385  API_EVENT(conn, NETCONN_EVT_ERROR, 0);
386  /* Try to release selects pending on 'read' or 'write', too.
387  They will get an error if they actually try to read or write. */
388  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
389  API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
390 
391  /* pass NULL-message to recvmbox to wake up pending recv */
392  if (sys_mbox_valid(&conn->recvmbox)) {
393  /* use trypost to prevent deadlock */
394  sys_mbox_trypost(&conn->recvmbox, NULL);
395  }
396  /* pass NULL-message to acceptmbox to wake up pending accept */
397  if (sys_mbox_valid(&conn->acceptmbox)) {
398  /* use trypost to preven deadlock */
399  sys_mbox_trypost(&conn->acceptmbox, NULL);
400  }
401 
402  if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
403  (old_state == NETCONN_CONNECT)) {
404  /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary
405  since the pcb has already been deleted! */
406  int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
407  SET_NONBLOCKING_CONNECT(conn, 0);
408 
409  if (!was_nonblocking_connect) {
410  sys_sem_t* op_completed_sem;
411  /* set error return code */
412  LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
413  conn->current_msg->err = err;
414  op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
415  LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem));
416  conn->current_msg = NULL;
417  /* wake up the waiting task */
418  NETCONN_SET_SAFE_ERR(conn, err);
419  sys_sem_signal(op_completed_sem);
420  }
421  } else {
422  LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
423  }
424 }
425 
432 static void
433 setup_tcp(struct netconn *conn)
434 {
435  struct tcp_pcb *pcb;
436 
437  pcb = conn->pcb.tcp;
438  tcp_arg(pcb, conn);
439  tcp_recv(pcb, recv_tcp);
440  tcp_sent(pcb, sent_tcp);
441  tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL);
442  tcp_err(pcb, err_tcp);
443 }
444 
451 static err_t
452 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
453 {
454  struct netconn *newconn;
455  struct netconn *conn = (struct netconn *)arg;
456 
457  LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state)));
458 
459  if (!sys_mbox_valid(&conn->acceptmbox)) {
460  LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
461  return ERR_VAL;
462  }
463 
464  /* We have to set the callback here even though
465  * the new socket is unknown. conn->socket is marked as -1. */
466  newconn = netconn_alloc(conn->type, conn->callback);
467  if (newconn == NULL) {
468  return ERR_MEM;
469  }
470  newconn->pcb.tcp = newpcb;
471  setup_tcp(newconn);
472  /* no protection: when creating the pcb, the netconn is not yet known
473  to the application thread */
474  newconn->last_err = err;
475 
476  if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
477  /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
478  so do nothing here! */
479  /* remove all references to this netconn from the pcb */
480  struct tcp_pcb* pcb = newconn->pcb.tcp;
481  tcp_arg(pcb, NULL);
482  tcp_recv(pcb, NULL);
483  tcp_sent(pcb, NULL);
484  tcp_poll(pcb, NULL, 0);
485  tcp_err(pcb, NULL);
486  /* remove reference from to the pcb from this netconn */
487  newconn->pcb.tcp = NULL;
488  /* no need to drain since we know the recvmbox is empty. */
489  sys_mbox_free(&newconn->recvmbox);
490  sys_mbox_set_invalid(&newconn->recvmbox);
491  netconn_free(newconn);
492  return ERR_MEM;
493  } else {
494  /* Register event with callback */
495  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
496  }
497 
498  return ERR_OK;
499 }
500 #endif /* LWIP_TCP */
501 
509 static void
510 pcb_new(struct api_msg_msg *msg)
511 {
512  LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
513 
514  /* Allocate a PCB for this connection */
515  switch(NETCONNTYPE_GROUP(msg->conn->type)) {
516 #if LWIP_RAW
517  case NETCONN_RAW:
518  msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
519  if (msg->conn->pcb.raw != NULL) {
520  raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
521  }
522  break;
523 #endif /* LWIP_RAW */
524 #if LWIP_UDP
525  case NETCONN_UDP:
526  msg->conn->pcb.udp = udp_new();
527  if (msg->conn->pcb.udp != NULL) {
528 #if LWIP_UDPLITE
529  if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
530  udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
531  }
532 #endif /* LWIP_UDPLITE */
533  if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) {
534  udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
535  }
536  udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
537  }
538  break;
539 #endif /* LWIP_UDP */
540 #if LWIP_TCP
541  case NETCONN_TCP:
542  msg->conn->pcb.tcp = tcp_new();
543  if (msg->conn->pcb.tcp != NULL) {
544  setup_tcp(msg->conn);
545  }
546  break;
547 #endif /* LWIP_TCP */
548  default:
549  /* Unsupported netconn type, e.g. protocol disabled */
550  msg->err = ERR_VAL;
551  return;
552  }
553  if (msg->conn->pcb.ip == NULL) {
554  msg->err = ERR_MEM;
555  }
556 #if LWIP_IPV4 && LWIP_IPV6
557  else {
558  if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
559  ip_set_v6(msg->conn->pcb.ip, 1);
560  }
561  }
562 #endif /* LWIP_IPV4 && LWIP_IPV6 */
563 }
564 
571 void
572 lwip_netconn_do_newconn(struct api_msg_msg *msg)
573 {
574  msg->err = ERR_OK;
575  if (msg->conn->pcb.tcp == NULL) {
576  pcb_new(msg);
577  }
578  /* Else? This "new" connection already has a PCB allocated. */
579  /* Is this an error condition? Should it be deleted? */
580  /* We currently just are happy and return. */
581 
582  TCPIP_APIMSG_ACK(msg);
583 }
584 
595 struct netconn*
596 netconn_alloc(enum netconn_type t, netconn_callback callback)
597 {
598  struct netconn *conn;
599  int size;
600 
601  conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
602  if (conn == NULL) {
603  return NULL;
604  }
605 
606  conn->last_err = ERR_OK;
607  conn->type = t;
608  conn->pcb.tcp = NULL;
609 
610  /* If all sizes are the same, every compiler should optimize this switch to nothing */
611  switch(NETCONNTYPE_GROUP(t)) {
612 #if LWIP_RAW
613  case NETCONN_RAW:
615  break;
616 #endif /* LWIP_RAW */
617 #if LWIP_UDP
618  case NETCONN_UDP:
620  break;
621 #endif /* LWIP_UDP */
622 #if LWIP_TCP
623  case NETCONN_TCP:
625  break;
626 #endif /* LWIP_TCP */
627  default:
628  LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
629  goto free_and_return;
630  }
631 
632  if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
633  goto free_and_return;
634  }
635 #if !LWIP_NETCONN_SEM_PER_THREAD
636  if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
637  sys_mbox_free(&conn->recvmbox);
638  goto free_and_return;
639  }
640 #endif
641 
642 #if LWIP_TCP
643  sys_mbox_set_invalid(&conn->acceptmbox);
644 #endif
645  conn->state = NETCONN_NONE;
646 #if LWIP_SOCKET
647  /* initialize socket to -1 since 0 is a valid socket */
648  conn->socket = -1;
649 #endif /* LWIP_SOCKET */
650  conn->callback = callback;
651 #if LWIP_TCP
652  conn->current_msg = NULL;
653  conn->write_offset = 0;
654 #endif /* LWIP_TCP */
655 #if LWIP_SO_SNDTIMEO
656  conn->send_timeout = 0;
657 #endif /* LWIP_SO_SNDTIMEO */
658 #if LWIP_SO_RCVTIMEO
659  conn->recv_timeout = 0;
660 #endif /* LWIP_SO_RCVTIMEO */
661 #if LWIP_SO_RCVBUF
662  conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
663  conn->recv_avail = 0;
664 #endif /* LWIP_SO_RCVBUF */
665 #if LWIP_SO_LINGER
666  conn->linger = -1;
667 #endif /* LWIP_SO_LINGER */
668  conn->flags = 0;
669  return conn;
670 free_and_return:
671  memp_free(MEMP_NETCONN, conn);
672  return NULL;
673 }
674 
681 void
682 netconn_free(struct netconn *conn)
683 {
684  LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
685  LWIP_ASSERT("recvmbox must be deallocated before calling this function",
686  !sys_mbox_valid(&conn->recvmbox));
687 #if LWIP_TCP
688  LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
689  !sys_mbox_valid(&conn->acceptmbox));
690 #endif /* LWIP_TCP */
691 
692 #if !LWIP_NETCONN_SEM_PER_THREAD
693  sys_sem_free(&conn->op_completed);
694  sys_sem_set_invalid(&conn->op_completed);
695 #endif
696 
697  memp_free(MEMP_NETCONN, conn);
698 }
699 
708 static void
709 netconn_drain(struct netconn *conn)
710 {
711  void *mem;
712 #if LWIP_TCP
713  struct pbuf *p;
714 #endif /* LWIP_TCP */
715 
716  /* This runs in tcpip_thread, so we don't need to lock against rx packets */
717 
718  /* Delete and drain the recvmbox. */
719  if (sys_mbox_valid(&conn->recvmbox)) {
720  while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
721 #if LWIP_TCP
722  if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
723  if (mem != NULL) {
724  p = (struct pbuf*)mem;
725  /* pcb might be set to NULL already by err_tcp() */
726  if (conn->pcb.tcp != NULL) {
727  tcp_recved(conn->pcb.tcp, p->tot_len);
728  }
729  pbuf_free(p);
730  }
731  } else
732 #endif /* LWIP_TCP */
733  {
734  netbuf_delete((struct netbuf *)mem);
735  }
736  }
737  sys_mbox_free(&conn->recvmbox);
738  sys_mbox_set_invalid(&conn->recvmbox);
739  }
740 
741  /* Delete and drain the acceptmbox. */
742 #if LWIP_TCP
743  if (sys_mbox_valid(&conn->acceptmbox)) {
744  while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
745  struct netconn *newconn = (struct netconn *)mem;
746  /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
747  /* pcb might be set to NULL already by err_tcp() */
748  if (conn->pcb.tcp != NULL) {
749  tcp_accepted(conn->pcb.tcp);
750  }
751  /* drain recvmbox */
752  netconn_drain(newconn);
753  if (newconn->pcb.tcp != NULL) {
754  tcp_abort(newconn->pcb.tcp);
755  newconn->pcb.tcp = NULL;
756  }
757  netconn_free(newconn);
758  }
759  sys_mbox_free(&conn->acceptmbox);
760  sys_mbox_set_invalid(&conn->acceptmbox);
761  }
762 #endif /* LWIP_TCP */
763 }
764 
765 #if LWIP_TCP
766 
774 static err_t
775 lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM)
776 {
777  err_t err;
778  u8_t shut, shut_rx, shut_tx, close;
779  u8_t close_finished = 0;
780  struct tcp_pcb* tpcb;
781 #if LWIP_SO_LINGER
782  u8_t linger_wait_required = 0;
783 #endif /* LWIP_SO_LINGER */
784 
785  LWIP_ASSERT("invalid conn", (conn != NULL));
786  LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP));
787  LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
788  LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
789  LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
790 
791  tpcb = conn->pcb.tcp;
792  shut = conn->current_msg->msg.sd.shut;
793  shut_rx = shut & NETCONN_SHUT_RD;
794  shut_tx = shut & NETCONN_SHUT_WR;
795  /* shutting down both ends is the same as closing
796  (also if RD or WR side was shut down before already) */
797  if (shut == NETCONN_SHUT_RDWR) {
798  close = 1;
799  } else if (shut_rx &&
800  ((tpcb->state == FIN_WAIT_1) ||
801  (tpcb->state == FIN_WAIT_2) ||
802  (tpcb->state == CLOSING))) {
803  close = 1;
804  } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) {
805  close = 1;
806  } else {
807  close = 0;
808  }
809 
810  /* Set back some callback pointers */
811  if (close) {
812  tcp_arg(tpcb, NULL);
813  }
814  if (tpcb->state == LISTEN) {
815  tcp_accept(tpcb, NULL);
816  } else {
817  /* some callbacks have to be reset if tcp_close is not successful */
818  if (shut_rx) {
819  tcp_recv(tpcb, NULL);
820  tcp_accept(tpcb, NULL);
821  }
822  if (shut_tx) {
823  tcp_sent(tpcb, NULL);
824  }
825  if (close) {
826  tcp_poll(tpcb, NULL, 0);
827  tcp_err(tpcb, NULL);
828  }
829  }
830  /* Try to close the connection */
831  if (close) {
832 #if LWIP_SO_LINGER
833  /* check linger possibilites before calling tcp_close */
834  err = ERR_OK;
835  /* linger enabled/required at all? (i.e. is there untransmitted data left?) */
836  if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) {
837  if ((conn->linger == 0)) {
838  /* data left but linger prevents waiting */
839  tcp_abort(tpcb);
840  tpcb = NULL;
841  } else if (conn->linger > 0) {
842  /* data left and linger says we should wait */
843  if (netconn_is_nonblocking(conn)) {
844  /* data left on a nonblocking netconn -> cannot linger */
845  err = ERR_WOULDBLOCK;
846  } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >=
847  (conn->linger * 1000)) {
848  /* data left but linger timeout has expired (this happens on further
849  calls to this function through poll_tcp */
850  tcp_abort(tpcb);
851  tpcb = NULL;
852  } else {
853  /* data left -> need to wait for ACK after successful close */
854  linger_wait_required = 1;
855  }
856  }
857  }
858  if ((err == ERR_OK) && (tpcb != NULL))
859 #endif /* LWIP_SO_LINGER */
860  {
861  err = tcp_close(tpcb);
862  }
863  } else {
864  err = tcp_shutdown(tpcb, shut_rx, shut_tx);
865  }
866  if (err == ERR_OK) {
867  close_finished = 1;
868 #if LWIP_SO_LINGER
869  if (linger_wait_required) {
870  /* wait for ACK of all unsent/unacked data by just getting called again */
871  close_finished = 0;
872  err = ERR_INPROGRESS;
873  }
874 #endif /* LWIP_SO_LINGER */
875  } else {
876  if (err == ERR_MEM) {
877  /* Closing failed because of memory shortage */
878  if (netconn_is_nonblocking(conn)) {
879  /* Nonblocking close failed */
880  close_finished = 1;
881  err = ERR_WOULDBLOCK;
882  } else {
883  /* Blocking close, check the timeout */
884 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
886  /* this is kind of an lwip addition to the standard sockets: we wait
887  for some time when failing to allocate a segment for the FIN */
888 #if LWIP_SO_SNDTIMEO
889  if (conn->send_timeout > 0) {
890  close_timeout = conn->send_timeout;
891  }
892 #endif /* LWIP_SO_SNDTIMEO */
893 #if LWIP_SO_LINGER
894  if (conn->linger >= 0) {
895  /* use linger timeout (seconds) */
896  close_timeout = conn->linger * 1000U;
897  }
898 #endif
899  if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
900 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
901  if (conn->current_msg->msg.sd.polls_left == 0) {
902 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
903  close_finished = 1;
904  if (close) {
905  /* in this case, we want to RST the connection */
906  tcp_abort(tpcb);
907  err = ERR_OK;
908  }
909  }
910  }
911  } else {
912  /* Closing failed for a non-memory error: give up */
913  close_finished = 1;
914  }
915  }
916  if (close_finished) {
917  /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */
918  sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
919  conn->current_msg->err = err;
920  conn->current_msg = NULL;
921  conn->state = NETCONN_NONE;
922  if (err == ERR_OK) {
923  if (close) {
924  /* Set back some callback pointers as conn is going away */
925  conn->pcb.tcp = NULL;
926  /* Trigger select() in socket layer. Make sure everybody notices activity
927  on the connection, error first! */
928  API_EVENT(conn, NETCONN_EVT_ERROR, 0);
929  }
930  if (shut_rx) {
931  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
932  }
933  if (shut_tx) {
934  API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
935  }
936  }
937  NETCONN_SET_SAFE_ERR(conn, err);
938 #if LWIP_TCPIP_CORE_LOCKING
939  if (delayed)
940 #endif
941  {
942  /* wake up the application task */
943  sys_sem_signal(op_completed_sem);
944  }
945  return ERR_OK;
946  }
947  if (!close_finished) {
948  /* Closing failed and we want to wait: restore some of the callbacks */
949  /* Closing of listen pcb will never fail! */
950  LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN));
951  if (shut_tx) {
952  tcp_sent(tpcb, sent_tcp);
953  }
954  /* when waiting for close, set up poll interval to 500ms */
955  tcp_poll(tpcb, poll_tcp, 1);
956  tcp_err(tpcb, err_tcp);
957  tcp_arg(tpcb, conn);
958  /* don't restore recv callback: we don't want to receive any more data */
959  }
960  /* If closing didn't succeed, we get called again either
961  from poll_tcp or from sent_tcp */
962  LWIP_ASSERT("err != ERR_OK", err != ERR_OK);
963  return err;
964 }
965 #endif /* LWIP_TCP */
966 
973 void
974 lwip_netconn_do_delconn(struct api_msg_msg *msg)
975 {
976  enum netconn_state state = msg->conn->state;
977  LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */
978  (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP));
979 #if LWIP_NETCONN_FULLDUPLEX
980  /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */
981  if (state != NETCONN_NONE) {
982  if ((state == NETCONN_WRITE) ||
983  ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
984  /* close requested, abort running write/connect */
985  sys_sem_t* op_completed_sem;
986  LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
987  op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
988  msg->conn->current_msg->err = ERR_CLSD;
989  msg->conn->current_msg = NULL;
990  msg->conn->write_offset = 0;
991  msg->conn->state = NETCONN_NONE;
992  NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD);
993  sys_sem_signal(op_completed_sem);
994  }
995  }
996 #else /* LWIP_NETCONN_FULLDUPLEX */
997  if (((state != NETCONN_NONE) &&
998  (state != NETCONN_LISTEN) &&
999  (state != NETCONN_CONNECT)) ||
1000  ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1001  /* This means either a blocking write or blocking connect is running
1002  (nonblocking write returns and sets state to NONE) */
1003  msg->err = ERR_INPROGRESS;
1004  } else
1005 #endif /* LWIP_NETCONN_FULLDUPLEX */
1006  {
1007  LWIP_ASSERT("blocking connect in progress",
1008  (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
1009  msg->err = ERR_OK;
1010  /* Drain and delete mboxes */
1011  netconn_drain(msg->conn);
1012 
1013  if (msg->conn->pcb.tcp != NULL) {
1014 
1015  switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1016 #if LWIP_RAW
1017  case NETCONN_RAW:
1018  raw_remove(msg->conn->pcb.raw);
1019  break;
1020 #endif /* LWIP_RAW */
1021 #if LWIP_UDP
1022  case NETCONN_UDP:
1023  msg->conn->pcb.udp->recv_arg = NULL;
1024  udp_remove(msg->conn->pcb.udp);
1025  break;
1026 #endif /* LWIP_UDP */
1027 #if LWIP_TCP
1028  case NETCONN_TCP:
1029  LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
1030  msg->conn->write_offset == 0);
1031  msg->conn->state = NETCONN_CLOSE;
1032  msg->msg.sd.shut = NETCONN_SHUT_RDWR;
1033  msg->conn->current_msg = msg;
1034 #if LWIP_TCPIP_CORE_LOCKING
1035  if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
1036  LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
1038  sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1039  LOCK_TCPIP_CORE();
1040  LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1041  }
1042 #else /* LWIP_TCPIP_CORE_LOCKING */
1043  lwip_netconn_do_close_internal(msg->conn);
1044 #endif /* LWIP_TCPIP_CORE_LOCKING */
1045  /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing
1046  the application thread, so we can return at this point! */
1047  return;
1048 #endif /* LWIP_TCP */
1049  default:
1050  break;
1051  }
1052  msg->conn->pcb.tcp = NULL;
1053  }
1054  /* tcp netconns don't come here! */
1055 
1056  /* @todo: this lets select make the socket readable and writable,
1057  which is wrong! errfd instead? */
1058  API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
1059  API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
1060  }
1061  if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) {
1062  TCPIP_APIMSG_ACK(msg);
1063  }
1064 }
1065 
1073 void
1074 lwip_netconn_do_bind(struct api_msg_msg *msg)
1075 {
1076  if (ERR_IS_FATAL(msg->conn->last_err)) {
1077  msg->err = msg->conn->last_err;
1078  } else {
1079  msg->err = ERR_VAL;
1080  if (msg->conn->pcb.tcp != NULL) {
1081  switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1082 #if LWIP_RAW
1083  case NETCONN_RAW:
1084  msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1085  break;
1086 #endif /* LWIP_RAW */
1087 #if LWIP_UDP
1088  case NETCONN_UDP:
1089  msg->err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1090  break;
1091 #endif /* LWIP_UDP */
1092 #if LWIP_TCP
1093  case NETCONN_TCP:
1094  msg->err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1095  break;
1096 #endif /* LWIP_TCP */
1097  default:
1098  break;
1099  }
1100  }
1101  }
1102  TCPIP_APIMSG_ACK(msg);
1103 }
1104 
1105 #if LWIP_TCP
1106 
1112 static err_t
1113 lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
1114 {
1115  struct netconn *conn;
1116  int was_blocking;
1117  sys_sem_t* op_completed_sem = NULL;
1118 
1119  LWIP_UNUSED_ARG(pcb);
1120 
1121  conn = (struct netconn *)arg;
1122 
1123  if (conn == NULL) {
1124  return ERR_VAL;
1125  }
1126 
1127  LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
1128  LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
1129  (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
1130 
1131  if (conn->current_msg != NULL) {
1132  conn->current_msg->err = err;
1133  op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1134  }
1135  if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) {
1136  setup_tcp(conn);
1137  }
1138  was_blocking = !IN_NONBLOCKING_CONNECT(conn);
1139  SET_NONBLOCKING_CONNECT(conn, 0);
1140  LWIP_ASSERT("blocking connect state error",
1141  (was_blocking && op_completed_sem != NULL) ||
1142  (!was_blocking && op_completed_sem == NULL));
1143  conn->current_msg = NULL;
1144  conn->state = NETCONN_NONE;
1145  NETCONN_SET_SAFE_ERR(conn, ERR_OK);
1146  API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
1147 
1148  if (was_blocking) {
1149  sys_sem_signal(op_completed_sem);
1150  }
1151  return ERR_OK;
1152 }
1153 #endif /* LWIP_TCP */
1154 
1162 void
1163 lwip_netconn_do_connect(struct api_msg_msg *msg)
1164 {
1165  if (msg->conn->pcb.tcp == NULL) {
1166  /* This may happen when calling netconn_connect() a second time */
1167  msg->err = ERR_CLSD;
1168  } else {
1169  switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1170 #if LWIP_RAW
1171  case NETCONN_RAW:
1172  msg->err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1173  break;
1174 #endif /* LWIP_RAW */
1175 #if LWIP_UDP
1176  case NETCONN_UDP:
1177  msg->err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1178  break;
1179 #endif /* LWIP_UDP */
1180 #if LWIP_TCP
1181  case NETCONN_TCP:
1182  /* Prevent connect while doing any other action. */
1183  if (msg->conn->state == NETCONN_CONNECT) {
1184  msg->err = ERR_ALREADY;
1185  } else if (msg->conn->state != NETCONN_NONE) {
1186  msg->err = ERR_ISCONN;
1187  } else {
1188  setup_tcp(msg->conn);
1189  msg->err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr),
1190  msg->msg.bc.port, lwip_netconn_do_connected);
1191  if (msg->err == ERR_OK) {
1192  u8_t non_blocking = netconn_is_nonblocking(msg->conn);
1193  msg->conn->state = NETCONN_CONNECT;
1194  SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
1195  if (non_blocking) {
1196  msg->err = ERR_INPROGRESS;
1197  } else {
1198  msg->conn->current_msg = msg;
1199  /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()),
1200  when the connection is established! */
1201 #if LWIP_TCPIP_CORE_LOCKING
1202  LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT);
1204  sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1205  LOCK_TCPIP_CORE();
1206  LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT);
1207 #endif /* LWIP_TCPIP_CORE_LOCKING */
1208  return;
1209  }
1210  }
1211  }
1212  break;
1213 #endif /* LWIP_TCP */
1214  default:
1215  LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
1216  break;
1217  }
1218  }
1219  /* For all other protocols, netconn_connect() calls TCPIP_APIMSG(),
1220  so use TCPIP_APIMSG_ACK() here. */
1221  TCPIP_APIMSG_ACK(msg);
1222 }
1223 
1231 void
1232 lwip_netconn_do_disconnect(struct api_msg_msg *msg)
1233 {
1234 #if LWIP_UDP
1235  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1236  udp_disconnect(msg->conn->pcb.udp);
1237  msg->err = ERR_OK;
1238  } else
1239 #endif /* LWIP_UDP */
1240  {
1241  msg->err = ERR_VAL;
1242  }
1243  TCPIP_APIMSG_ACK(msg);
1244 }
1245 
1246 #if LWIP_TCP
1247 
1253 void
1254 lwip_netconn_do_listen(struct api_msg_msg *msg)
1255 {
1256  if (ERR_IS_FATAL(msg->conn->last_err)) {
1257  msg->err = msg->conn->last_err;
1258  } else {
1259  msg->err = ERR_CONN;
1260  if (msg->conn->pcb.tcp != NULL) {
1261  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1262  if (msg->conn->state == NETCONN_NONE) {
1263  struct tcp_pcb* lpcb;
1264  if (msg->conn->pcb.tcp->state != CLOSED) {
1265  /* connection is not closed, cannot listen */
1266  msg->err = ERR_VAL;
1267  } else {
1268 #if LWIP_IPV6
1269  if ((msg->conn->flags & NETCONN_FLAG_IPV6_V6ONLY) == 0) {
1270 #if TCP_LISTEN_BACKLOG
1271  lpcb = tcp_listen_dual_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
1272 #else /* TCP_LISTEN_BACKLOG */
1273  lpcb = tcp_listen_dual(msg->conn->pcb.tcp);
1274 #endif /* TCP_LISTEN_BACKLOG */
1275  } else
1276 #endif /* LWIP_IPV6 */
1277  {
1278 #if TCP_LISTEN_BACKLOG
1279  lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
1280 #else /* TCP_LISTEN_BACKLOG */
1281  lpcb = tcp_listen(msg->conn->pcb.tcp);
1282 #endif /* TCP_LISTEN_BACKLOG */
1283  }
1284  if (lpcb == NULL) {
1285  /* in this case, the old pcb is still allocated */
1286  msg->err = ERR_MEM;
1287  } else {
1288  /* delete the recvmbox and allocate the acceptmbox */
1289  if (sys_mbox_valid(&msg->conn->recvmbox)) {
1291  sys_mbox_free(&msg->conn->recvmbox);
1292  sys_mbox_set_invalid(&msg->conn->recvmbox);
1293  }
1294  msg->err = ERR_OK;
1295  if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
1296  msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
1297  }
1298  if (msg->err == ERR_OK) {
1299  msg->conn->state = NETCONN_LISTEN;
1300  msg->conn->pcb.tcp = lpcb;
1301  tcp_arg(msg->conn->pcb.tcp, msg->conn);
1302  tcp_accept(msg->conn->pcb.tcp, accept_function);
1303  } else {
1304  /* since the old pcb is already deallocated, free lpcb now */
1305  tcp_close(lpcb);
1306  msg->conn->pcb.tcp = NULL;
1307  }
1308  }
1309  }
1310  }
1311  } else {
1312  msg->err = ERR_ARG;
1313  }
1314  }
1315  }
1316  TCPIP_APIMSG_ACK(msg);
1317 }
1318 #endif /* LWIP_TCP */
1319 
1326 void
1327 lwip_netconn_do_send(struct api_msg_msg *msg)
1328 {
1329  if (ERR_IS_FATAL(msg->conn->last_err)) {
1330  msg->err = msg->conn->last_err;
1331  } else {
1332  msg->err = ERR_CONN;
1333  if (msg->conn->pcb.tcp != NULL) {
1334  switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1335 #if LWIP_RAW
1336  case NETCONN_RAW:
1337  if (ip_addr_isany(&msg->msg.b->addr)) {
1338  msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
1339  } else {
1340  msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
1341  }
1342  break;
1343 #endif
1344 #if LWIP_UDP
1345  case NETCONN_UDP:
1346 #if LWIP_CHECKSUM_ON_COPY
1347  if (ip_addr_isany(&msg->msg.b->addr)) {
1348  msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1349  msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1350  } else {
1351  msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1352  &msg->msg.b->addr, msg->msg.b->port,
1353  msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1354  }
1355 #else /* LWIP_CHECKSUM_ON_COPY */
1356  if (ip_addr_isany_val(msg->msg.b->addr)) {
1357  msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
1358  } else {
1359  msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
1360  }
1361 #endif /* LWIP_CHECKSUM_ON_COPY */
1362  break;
1363 #endif /* LWIP_UDP */
1364  default:
1365  break;
1366  }
1367  }
1368  }
1369  TCPIP_APIMSG_ACK(msg);
1370 }
1371 
1372 #if LWIP_TCP
1373 
1379 void
1380 lwip_netconn_do_recv(struct api_msg_msg *msg)
1381 {
1382  msg->err = ERR_OK;
1383  if (msg->conn->pcb.tcp != NULL) {
1384  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1385 #if TCP_LISTEN_BACKLOG
1386  if (msg->conn->pcb.tcp->state == LISTEN) {
1387  tcp_accepted(msg->conn->pcb.tcp);
1388  } else
1389 #endif /* TCP_LISTEN_BACKLOG */
1390  {
1391  u32_t remaining = msg->msg.r.len;
1392  do {
1393  u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
1394  tcp_recved(msg->conn->pcb.tcp, recved);
1395  remaining -= recved;
1396  } while (remaining != 0);
1397  }
1398  }
1399  }
1400  TCPIP_APIMSG_ACK(msg);
1401 }
1402 
1415 static err_t
1416 lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM)
1417 {
1418  err_t err;
1419  const void *dataptr;
1420  u16_t len, available;
1421  u8_t write_finished = 0;
1422  size_t diff;
1423  u8_t dontblock;
1424  u8_t apiflags;
1425 
1426  LWIP_ASSERT("conn != NULL", conn != NULL);
1427  LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
1428  LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
1429  LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
1430  LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
1431  conn->write_offset < conn->current_msg->msg.w.len);
1432 
1433  dontblock = netconn_is_nonblocking(conn) ||
1434  (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK);
1435  apiflags = conn->current_msg->msg.w.apiflags;
1436 
1437 #if LWIP_SO_SNDTIMEO
1438  if ((conn->send_timeout != 0) &&
1439  ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
1440  write_finished = 1;
1441  if (conn->write_offset == 0) {
1442  /* nothing has been written */
1443  err = ERR_WOULDBLOCK;
1444  conn->current_msg->msg.w.len = 0;
1445  } else {
1446  /* partial write */
1447  err = ERR_OK;
1448  conn->current_msg->msg.w.len = conn->write_offset;
1449  conn->write_offset = 0;
1450  }
1451  } else
1452 #endif /* LWIP_SO_SNDTIMEO */
1453  {
1454  dataptr = (const u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
1455  diff = conn->current_msg->msg.w.len - conn->write_offset;
1456  if (diff > 0xffffUL) { /* max_u16_t */
1457  len = 0xffff;
1458  apiflags |= TCP_WRITE_FLAG_MORE;
1459  } else {
1460  len = (u16_t)diff;
1461  }
1462  available = tcp_sndbuf(conn->pcb.tcp);
1463  if (available < len) {
1464  /* don't try to write more than sendbuf */
1465  len = available;
1466  if (dontblock) {
1467  if (!len) {
1468  err = ERR_WOULDBLOCK;
1469  goto err_mem;
1470  }
1471  } else {
1472  apiflags |= TCP_WRITE_FLAG_MORE;
1473  }
1474  }
1475  LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
1476  err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
1477  /* if OK or memory error, check available space */
1478  if ((err == ERR_OK) || (err == ERR_MEM)) {
1479 err_mem:
1480  if (dontblock && (len < conn->current_msg->msg.w.len)) {
1481  /* non-blocking write did not write everything: mark the pcb non-writable
1482  and let poll_tcp check writable space to mark the pcb writable again */
1483  API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
1484  conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
1485  } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
1486  (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
1487  /* The queued byte- or pbuf-count exceeds the configured low-water limit,
1488  let select mark this pcb as non-writable. */
1489  API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
1490  }
1491  }
1492 
1493  if (err == ERR_OK) {
1494  err_t out_err;
1495  conn->write_offset += len;
1496  if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) {
1497  /* return sent length */
1498  conn->current_msg->msg.w.len = conn->write_offset;
1499  /* everything was written */
1500  write_finished = 1;
1501  conn->write_offset = 0;
1502  }
1503  out_err = tcp_output(conn->pcb.tcp);
1504  if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) {
1505  /* If tcp_output fails with fatal error or no route is found,
1506  don't try writing any more but return the error
1507  to the application thread. */
1508  err = out_err;
1509  write_finished = 1;
1510  conn->current_msg->msg.w.len = 0;
1511  }
1512  } else if ((err == ERR_MEM) && !dontblock) {
1513  /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
1514  we do NOT return to the application thread, since ERR_MEM is
1515  only a temporary error! */
1516 
1517  /* tcp_write returned ERR_MEM, try tcp_output anyway */
1518  err_t out_err = tcp_output(conn->pcb.tcp);
1519  if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) {
1520  /* If tcp_output fails with fatal error or no route is found,
1521  don't try writing any more but return the error
1522  to the application thread. */
1523  err = out_err;
1524  write_finished = 1;
1525  conn->current_msg->msg.w.len = 0;
1526  } else {
1527  }
1528  } else {
1529  /* On errors != ERR_MEM, we don't try writing any more but return
1530  the error to the application thread. */
1531  write_finished = 1;
1532  conn->current_msg->msg.w.len = 0;
1533  }
1534  }
1535  if (write_finished) {
1536  /* everything was written: set back connection state
1537  and back to application task */
1538  sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1539  conn->current_msg->err = err;
1540  conn->current_msg = NULL;
1541  conn->state = NETCONN_NONE;
1542  NETCONN_SET_SAFE_ERR(conn, err);
1543 #if LWIP_TCPIP_CORE_LOCKING
1544  if (delayed)
1545 #endif
1546  {
1547  sys_sem_signal(op_completed_sem);
1548  }
1549  }
1550 #if LWIP_TCPIP_CORE_LOCKING
1551  else {
1552  return ERR_MEM;
1553  }
1554 #endif
1555  return ERR_OK;
1556 }
1557 #endif /* LWIP_TCP */
1558 
1565 void
1566 lwip_netconn_do_write(struct api_msg_msg *msg)
1567 {
1568  if (ERR_IS_FATAL(msg->conn->last_err)) {
1569  msg->err = msg->conn->last_err;
1570  } else {
1571  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1572 #if LWIP_TCP
1573  if (msg->conn->state != NETCONN_NONE) {
1574  /* netconn is connecting, closing or in blocking write */
1575  msg->err = ERR_INPROGRESS;
1576  } else if (msg->conn->pcb.tcp != NULL) {
1577  msg->conn->state = NETCONN_WRITE;
1578  /* set all the variables used by lwip_netconn_do_writemore */
1579  LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
1580  msg->conn->write_offset == 0);
1581  LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
1582  msg->conn->current_msg = msg;
1583  msg->conn->write_offset = 0;
1584 #if LWIP_TCPIP_CORE_LOCKING
1585  if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) {
1586  LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
1588  sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1589  LOCK_TCPIP_CORE();
1590  LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE);
1591  }
1592 #else /* LWIP_TCPIP_CORE_LOCKING */
1593  lwip_netconn_do_writemore(msg->conn);
1594 #endif /* LWIP_TCPIP_CORE_LOCKING */
1595  /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG
1596  since lwip_netconn_do_writemore ACKs it! */
1597  return;
1598  } else {
1599  msg->err = ERR_CONN;
1600  }
1601 #else /* LWIP_TCP */
1602  msg->err = ERR_VAL;
1603 #endif /* LWIP_TCP */
1604 #if (LWIP_UDP || LWIP_RAW)
1605  } else {
1606  msg->err = ERR_VAL;
1607 #endif /* (LWIP_UDP || LWIP_RAW) */
1608  }
1609  }
1610  TCPIP_APIMSG_ACK(msg);
1611 }
1612 
1619 void
1620 lwip_netconn_do_getaddr(struct api_msg_msg *msg)
1621 {
1622  if (msg->conn->pcb.ip != NULL) {
1623  if (msg->msg.ad.local) {
1624  ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
1625  msg->conn->pcb.ip->local_ip);
1626  } else {
1627  ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
1628  msg->conn->pcb.ip->remote_ip);
1629  }
1630  msg->err = ERR_OK;
1631  switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1632 #if LWIP_RAW
1633  case NETCONN_RAW:
1634  if (msg->msg.ad.local) {
1635  API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
1636  } else {
1637  /* return an error as connecting is only a helper for upper layers */
1638  msg->err = ERR_CONN;
1639  }
1640  break;
1641 #endif /* LWIP_RAW */
1642 #if LWIP_UDP
1643  case NETCONN_UDP:
1644  if (msg->msg.ad.local) {
1645  API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
1646  } else {
1647  if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
1648  msg->err = ERR_CONN;
1649  } else {
1650  API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
1651  }
1652  }
1653  break;
1654 #endif /* LWIP_UDP */
1655 #if LWIP_TCP
1656  case NETCONN_TCP:
1657  if ((msg->msg.ad.local == 0) &&
1658  ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) {
1659  /* pcb is not connected and remote name is requested */
1660  msg->err = ERR_CONN;
1661  } else {
1662  API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port);
1663  }
1664  break;
1665 #endif /* LWIP_TCP */
1666  default:
1667  LWIP_ASSERT("invalid netconn_type", 0);
1668  break;
1669  }
1670  } else {
1671  msg->err = ERR_CONN;
1672  }
1673  TCPIP_APIMSG_ACK(msg);
1674 }
1675 
1683 void
1684 lwip_netconn_do_close(struct api_msg_msg *msg)
1685 {
1686 #if LWIP_TCP
1687  enum netconn_state state = msg->conn->state;
1688  /* First check if this is a TCP netconn and if it is in a correct state
1689  (LISTEN doesn't support half shutdown) */
1690  if ((msg->conn->pcb.tcp != NULL) &&
1691  (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) &&
1692  ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) {
1693  /* Check if we are in a connected state */
1694  if (state == NETCONN_CONNECT) {
1695  /* TCP connect in progress: cannot shutdown */
1696  msg->err = ERR_CONN;
1697  } else if (state == NETCONN_WRITE) {
1698 #if LWIP_NETCONN_FULLDUPLEX
1699  if (msg->msg.sd.shut & NETCONN_SHUT_WR) {
1700  /* close requested, abort running write */
1701  sys_sem_t* op_completed_sem;
1702  LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
1703  op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
1704  msg->conn->current_msg->err = ERR_CLSD;
1705  msg->conn->current_msg = NULL;
1706  msg->conn->write_offset = 0;
1707  msg->conn->state = NETCONN_NONE;
1708  NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD);
1709  sys_sem_signal(op_completed_sem);
1710  } else {
1711  LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD);
1712  /* In this case, let the write continue and do not interfere with
1713  conn->current_msg or conn->state! */
1714  msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0);
1715  }
1716 #else /* LWIP_NETCONN_FULLDUPLEX */
1717  msg->err = ERR_INPROGRESS;
1718 #endif /* LWIP_NETCONN_FULLDUPLEX */
1719  } else {
1720  if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
1721  /* Drain and delete mboxes */
1722  netconn_drain(msg->conn);
1723  }
1724  LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
1725  msg->conn->write_offset == 0);
1726  msg->conn->state = NETCONN_CLOSE;
1727  msg->conn->current_msg = msg;
1728 #if LWIP_TCPIP_CORE_LOCKING
1729  if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
1730  LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
1732  sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1733  LOCK_TCPIP_CORE();
1734  LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1735  }
1736 #else /* LWIP_TCPIP_CORE_LOCKING */
1737  lwip_netconn_do_close_internal(msg->conn);
1738 #endif /* LWIP_TCPIP_CORE_LOCKING */
1739  /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */
1740  return;
1741  }
1742  } else
1743 #endif /* LWIP_TCP */
1744  {
1745  msg->err = ERR_CONN;
1746  }
1747  TCPIP_APIMSG_ACK(msg);
1748 }
1749 
1750 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
1751 
1757 void
1758 lwip_netconn_do_join_leave_group(struct api_msg_msg *msg)
1759 {
1760  if (ERR_IS_FATAL(msg->conn->last_err)) {
1761  msg->err = msg->conn->last_err;
1762  } else {
1763  if (msg->conn->pcb.tcp != NULL) {
1764  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1765 #if LWIP_UDP
1766 #if LWIP_IPV6 && LWIP_IPV6_MLD
1767  if (PCB_ISIPV6(msg->conn->pcb.udp)) {
1768  if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
1769  msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
1770  ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
1771  } else {
1772  msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
1773  ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
1774  }
1775  }
1776  else
1777 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
1778  {
1779 #if LWIP_IGMP
1780  if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
1781  msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
1782  ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
1783  } else {
1784  msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
1785  ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
1786  }
1787 #endif /* LWIP_IGMP */
1788  }
1789 #endif /* LWIP_UDP */
1790 #if (LWIP_TCP || LWIP_RAW)
1791  } else {
1792  msg->err = ERR_VAL;
1793 #endif /* (LWIP_TCP || LWIP_RAW) */
1794  }
1795  } else {
1796  msg->err = ERR_CONN;
1797  }
1798  }
1799  TCPIP_APIMSG_ACK(msg);
1800 }
1801 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
1802 
1803 #if LWIP_DNS
1804 
1809 static void
1810 lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg)
1811 {
1812  struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1813 
1814  /* we trust the internal implementation to be correct :-) */
1815  LWIP_UNUSED_ARG(name);
1816 
1817  if (ipaddr == NULL) {
1818  /* timeout or memory error */
1819  API_EXPR_DEREF(msg->err) = ERR_VAL;
1820  } else {
1821  /* address was resolved */
1822  API_EXPR_DEREF(msg->err) = ERR_OK;
1823  API_EXPR_DEREF(msg->addr) = *ipaddr;
1824  }
1825  /* wake up the application task waiting in netconn_gethostbyname */
1826  sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
1827 }
1828 
1835 void
1836 lwip_netconn_do_gethostbyname(void *arg)
1837 {
1838  struct dns_api_msg *msg = (struct dns_api_msg*)arg;
1839  u8_t addrtype =
1840 #if LWIP_IPV4 && LWIP_IPV6
1841  msg->dns_addrtype;
1842 #else
1843  LWIP_DNS_ADDRTYPE_DEFAULT;
1844 #endif
1845 
1846  API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name,
1847  API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype);
1848  if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) {
1849  /* on error or immediate success, wake up the application
1850  * task waiting in netconn_gethostbyname */
1851  sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
1852  }
1853 }
1854 #endif /* LWIP_DNS */
1855 
1856 #endif /* LWIP_NETCONN */
1857 
#define ERR_ISCONN
Definition: err.h:62
#define ERR_CONN
Definition: err.h:64
#define SYS_ARCH_SET(var, val)
Definition: sys.h:345
#define ip_addr_isany(ipaddr)
Definition: ip_addr.h:215
#define ip_2_ip6(ipaddr)
Definition: ip_addr.h:200
#define ip_addr_isany_val(ipaddr)
Definition: ip_addr.h:216
int sys_mbox_valid(sys_mbox_t *mbox)
Definition: sys_arch.c:205
#define ERR_CLSD
Definition: err.h:69
#define LOCK_TCPIP_CORE()
Definition: tcpip_priv.h:91
#define ERR_VAL
Definition: err.h:58
void sys_sem_set_invalid(sys_sem_t *sem)
Definition: sys_arch.c:321
#define sys_mbox_tryfetch(mbox, msg)
Definition: sys.h:214
#define API_EXPR_REF(expr)
Definition: tcpip_priv.h:130
if(LCD_Lock==DISABLE)
Definition: lcd_log.c:249
#define DEFAULT_UDP_RECVMBOX_SIZE
Definition: lwipopts.h:240
void memp_free(memp_t type, void *mem)
Definition: memp.c:399
#define TCP_SNDLOWAT
Definition: opt.h:1064
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:199
#define ip_current_dest_addr()
Definition: ip.h:238
Definition: pbuf.h:77
void sys_sem_free(sys_sem_t *sem)
Definition: sys_arch.c:303
err_t sys_sem_new(sys_sem_t *sem, u8_t count)
Definition: sys_arch.c:221
int sys_sem_valid(sys_sem_t *sem)
Definition: sys_arch.c:312
#define ERR_IS_FATAL(e)
Definition: err.h:65
#define TCPIP_APIMSG_ACK(m)
Definition: tcpip_priv.h:95
#define NULL
Definition: usbd_def.h:53
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:652
Definition: pbuf.h:68
err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
Definition: pbuf.c:886
#define PCB_ISIPV6(pcb)
Definition: ip.h:89
#define ip_addr_copy(dest, src)
Definition: ip_addr.h:203
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
Definition: sys_arch.c:52
unsigned long u32_t
Definition: cc.h:42
#define ERR_RTE
Definition: err.h:56
#define SYS_MBOX_EMPTY
Definition: sys.h:87
#define API_EXPR_DEREF(expr)
Definition: tcpip_priv.h:132
#define ERR_OK
Definition: err.h:52
u16_t tot_len
Definition: pbuf.h:122
Definition: pbuf.h:108
s8_t err_t
Definition: err.h:47
#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT
Definition: opt.h:1632
osSemaphoreId sys_sem_t
Definition: sys_arch.h:44
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:70
#define ip_addr_set(dest, src)
Definition: ip_addr.h:205
#define UNLOCK_TCPIP_CORE()
Definition: tcpip_priv.h:92
#define ERR_WOULDBLOCK
Definition: err.h:59
u32_t sys_now(void)
#define ERR_ARG
Definition: err.h:71
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
Definition: sys_arch.c:263
#define ip_current_src_addr()
Definition: ip.h:236
#define TCP_SNDQUEUELOWAT
Definition: opt.h:1073
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
Definition: sys_arch.c:106
#define ERR_ALREADY
Definition: err.h:61
unsigned char u8_t
Definition: cc.h:38
ip6_addr_t ip_addr_t
Definition: ip_addr.h:194
#define SYS_ARCH_INC(var, val)
Definition: sys.h:318
#define DEFAULT_TCP_RECVMBOX_SIZE
Definition: lwipopts.h:241
Definition: mem.c:179
#define LWIP_ERROR(message, expression, handler)
Definition: debug.h:89
#define RECV_BUFSIZE_DEFAULT
Definition: opt.h:1625
#define DEFAULT_RAW_RECVMBOX_SIZE
Definition: opt.h:1434
#define ERR_INPROGRESS
Definition: err.h:57
signed long s32_t
Definition: cc.h:43
#define API_MSG_DEBUG
Definition: opt.h:2802
#define SYS_ARCH_GET(var, ret)
Definition: sys.h:336
void sys_sem_signal(sys_sem_t *sem)
Definition: sys_arch.c:296
void * memp_malloc(memp_t type)
Definition: memp.c:303
void sys_mbox_set_invalid(sys_mbox_t *mbox)
Definition: sys_arch.c:213
#define API_EXPR_REF_SEM(expr)
Definition: tcpip_priv.h:131
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:113
#define ERR_MEM
Definition: err.h:53
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:89
void sys_mbox_free(sys_mbox_t *mbox)
Definition: sys_arch.c:76
#define DEFAULT_ACCEPTMBOX_SIZE
Definition: lwipopts.h:242
unsigned short u16_t
Definition: cc.h:40