]> git.sur5r.net Git - freertos/blob - Demo/Common/ethernet/lwIP_130/src/api/api_msg.c
Start to re-arrange files to include FreeRTOS+ in main download.
[freertos] / Demo / Common / ethernet / lwIP_130 / src / api / api_msg.c
1 /**\r
2  * @file\r
3  * Sequential API Internal module\r
4  *\r
5  */\r
6 \r
7 /*\r
8  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
9  * All rights reserved.\r
10  *\r
11  * Redistribution and use in source and binary forms, with or without modification,\r
12  * are permitted provided that the following conditions are met:\r
13  *\r
14  * 1. Redistributions of source code must retain the above copyright notice,\r
15  *    this list of conditions and the following disclaimer.\r
16  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
17  *    this list of conditions and the following disclaimer in the documentation\r
18  *    and/or other materials provided with the distribution.\r
19  * 3. The name of the author may not be used to endorse or promote products\r
20  *    derived from this software without specific prior written permission.\r
21  *\r
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
23  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
25  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
27  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
30  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
31  * OF SUCH DAMAGE.\r
32  *\r
33  * This file is part of the lwIP TCP/IP stack.\r
34  *\r
35  * Author: Adam Dunkels <adam@sics.se>\r
36  *\r
37  */\r
38 \r
39 #include "lwip/opt.h"\r
40 \r
41 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */\r
42 \r
43 #include "lwip/api_msg.h"\r
44 \r
45 #include "lwip/ip.h"\r
46 #include "lwip/udp.h"\r
47 #include "lwip/tcp.h"\r
48 #include "lwip/raw.h"\r
49 \r
50 #include "lwip/memp.h"\r
51 #include "lwip/tcpip.h"\r
52 #include "lwip/igmp.h"\r
53 #include "lwip/dns.h"\r
54 \r
55 /* forward declarations */\r
56 #if LWIP_TCP\r
57 static err_t do_writemore(struct netconn *conn);\r
58 static void do_close_internal(struct netconn *conn);\r
59 #endif\r
60 \r
61 #if LWIP_RAW\r
62 /**\r
63  * Receive callback function for RAW netconns.\r
64  * Doesn't 'eat' the packet, only references it and sends it to\r
65  * conn->recvmbox\r
66  *\r
67  * @see raw.h (struct raw_pcb.recv) for parameters and return value\r
68  */\r
69 static u8_t\r
70 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,\r
71     struct ip_addr *addr)\r
72 {\r
73   struct pbuf *q;\r
74   struct netbuf *buf;\r
75   struct netconn *conn;\r
76 #if LWIP_SO_RCVBUF\r
77   int recv_avail;\r
78 #endif /* LWIP_SO_RCVBUF */\r
79 \r
80   LWIP_UNUSED_ARG(addr);\r
81   conn = arg;\r
82 \r
83 #if LWIP_SO_RCVBUF\r
84   SYS_ARCH_GET(conn->recv_avail, recv_avail);\r
85   if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) &&\r
86       ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) {\r
87 #else  /* LWIP_SO_RCVBUF */\r
88   if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) {\r
89 #endif /* LWIP_SO_RCVBUF */\r
90     /* copy the whole packet into new pbufs */\r
91     q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);\r
92     if(q != NULL) {\r
93       if (pbuf_copy(q, p) != ERR_OK) {\r
94         pbuf_free(q);\r
95         q = NULL;\r
96       }\r
97     }\r
98 \r
99     if(q != NULL) {\r
100       buf = memp_malloc(MEMP_NETBUF);\r
101       if (buf == NULL) {\r
102         pbuf_free(q);\r
103         return 0;\r
104       }\r
105 \r
106       buf->p = q;\r
107       buf->ptr = q;\r
108       buf->addr = &(((struct ip_hdr*)(q->payload))->src);\r
109       buf->port = pcb->protocol;\r
110 \r
111       SYS_ARCH_INC(conn->recv_avail, q->tot_len);\r
112       /* Register event with callback */\r
113       API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len);\r
114       if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {\r
115         netbuf_delete(buf);\r
116       }\r
117     }\r
118   }\r
119 \r
120   return 0; /* do not eat the packet */\r
121 }\r
122 #endif /* LWIP_RAW*/\r
123 \r
124 #if LWIP_UDP\r
125 /**\r
126  * Receive callback function for UDP netconns.\r
127  * Posts the packet to conn->recvmbox or deletes it on memory error.\r
128  *\r
129  * @see udp.h (struct udp_pcb.recv) for parameters\r
130  */\r
131 static void\r
132 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,\r
133    struct ip_addr *addr, u16_t port)\r
134 {\r
135   struct netbuf *buf;\r
136   struct netconn *conn;\r
137 #if LWIP_SO_RCVBUF\r
138   int recv_avail;\r
139 #endif /* LWIP_SO_RCVBUF */\r
140 \r
141   LWIP_UNUSED_ARG(pcb); /* only used for asserts... */\r
142   LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);\r
143   LWIP_ASSERT("recv_udp must have an argument", arg != NULL);\r
144   conn = arg;\r
145   LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);\r
146 \r
147 #if LWIP_SO_RCVBUF\r
148   SYS_ARCH_GET(conn->recv_avail, recv_avail);\r
149   if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) ||\r
150       ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {\r
151 #else  /* LWIP_SO_RCVBUF */\r
152   if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {\r
153 #endif /* LWIP_SO_RCVBUF */\r
154     pbuf_free(p);\r
155     return;\r
156   }\r
157 \r
158   buf = memp_malloc(MEMP_NETBUF);\r
159   if (buf == NULL) {\r
160     pbuf_free(p);\r
161     return;\r
162   } else {\r
163     buf->p = p;\r
164     buf->ptr = p;\r
165     buf->addr = addr;\r
166     buf->port = port;\r
167   }\r
168 \r
169   SYS_ARCH_INC(conn->recv_avail, p->tot_len);\r
170   /* Register event with callback */\r
171   API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len);\r
172   if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {\r
173     netbuf_delete(buf);\r
174     return;\r
175   }\r
176 }\r
177 #endif /* LWIP_UDP */\r
178 \r
179 #if LWIP_TCP\r
180 /**\r
181  * Receive callback function for TCP netconns.\r
182  * Posts the packet to conn->recvmbox, but doesn't delete it on errors.\r
183  *\r
184  * @see tcp.h (struct tcp_pcb.recv) for parameters and return value\r
185  */\r
186 static err_t\r
187 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)\r
188 {\r
189   struct netconn *conn;\r
190   u16_t len;\r
191 \r
192   LWIP_UNUSED_ARG(pcb);\r
193   LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);\r
194   LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);\r
195   conn = arg;\r
196   LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);\r
197 \r
198   if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {\r
199     return ERR_VAL;\r
200   }\r
201 \r
202   conn->err = err;\r
203   if (p != NULL) {\r
204     len = p->tot_len;\r
205     SYS_ARCH_INC(conn->recv_avail, len);\r
206   } else {\r
207     len = 0;\r
208   }\r
209   /* Register event with callback */\r
210   API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);\r
211   if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) {\r
212     return ERR_MEM;\r
213   }\r
214 \r
215   return ERR_OK;\r
216 }\r
217 \r
218 /**\r
219  * Poll callback function for TCP netconns.\r
220  * Wakes up an application thread that waits for a connection to close\r
221  * or data to be sent. The application thread then takes the\r
222  * appropriate action to go on.\r
223  *\r
224  * Signals the conn->sem.\r
225  * netconn_close waits for conn->sem if closing failed.\r
226  *\r
227  * @see tcp.h (struct tcp_pcb.poll) for parameters and return value\r
228  */\r
229 static err_t\r
230 poll_tcp(void *arg, struct tcp_pcb *pcb)\r
231 {\r
232   struct netconn *conn = arg;\r
233 \r
234   LWIP_UNUSED_ARG(pcb);\r
235   LWIP_ASSERT("conn != NULL", (conn != NULL));\r
236 \r
237   if (conn->state == NETCONN_WRITE) {\r
238     do_writemore(conn);\r
239   } else if (conn->state == NETCONN_CLOSE) {\r
240     do_close_internal(conn);\r
241   }\r
242 \r
243   return ERR_OK;\r
244 }\r
245 \r
246 /**\r
247  * Sent callback function for TCP netconns.\r
248  * Signals the conn->sem and calls API_EVENT.\r
249  * netconn_write waits for conn->sem if send buffer is low.\r
250  *\r
251  * @see tcp.h (struct tcp_pcb.sent) for parameters and return value\r
252  */\r
253 static err_t\r
254 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)\r
255 {\r
256   struct netconn *conn = arg;\r
257 \r
258   LWIP_UNUSED_ARG(pcb);\r
259   LWIP_ASSERT("conn != NULL", (conn != NULL));\r
260 \r
261   if (conn->state == NETCONN_WRITE) {\r
262     LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);\r
263     do_writemore(conn);\r
264   } else if (conn->state == NETCONN_CLOSE) {\r
265     do_close_internal(conn);\r
266   }\r
267 \r
268   if (conn) {\r
269     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)) {\r
270       API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);\r
271     }\r
272   }\r
273 \r
274   return ERR_OK;\r
275 }\r
276 \r
277 /**\r
278  * Error callback function for TCP netconns.\r
279  * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.\r
280  * The application thread has then to decide what to do.\r
281  *\r
282  * @see tcp.h (struct tcp_pcb.err) for parameters\r
283  */\r
284 static void\r
285 err_tcp(void *arg, err_t err)\r
286 {\r
287   struct netconn *conn;\r
288 \r
289   conn = arg;\r
290   LWIP_ASSERT("conn != NULL", (conn != NULL));\r
291 \r
292   conn->pcb.tcp = NULL;\r
293 \r
294   conn->err = err;\r
295   if (conn->recvmbox != SYS_MBOX_NULL) {\r
296     /* Register event with callback */\r
297     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);\r
298     sys_mbox_post(conn->recvmbox, NULL);\r
299   }\r
300   if (conn->op_completed != SYS_SEM_NULL && conn->state == NETCONN_CONNECT) {\r
301     conn->state = NETCONN_NONE;\r
302     sys_sem_signal(conn->op_completed);\r
303   }\r
304   if (conn->acceptmbox != SYS_MBOX_NULL) {\r
305     /* Register event with callback */\r
306     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);\r
307     sys_mbox_post(conn->acceptmbox, NULL);\r
308   }\r
309   if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) {\r
310     /* calling do_writemore/do_close_internal is not necessary\r
311        since the pcb has already been deleted! */\r
312     conn->state = NETCONN_NONE;\r
313     /* wake up the waiting task */\r
314     sys_sem_signal(conn->op_completed);\r
315   }\r
316 }\r
317 \r
318 /**\r
319  * Setup a tcp_pcb with the correct callback function pointers\r
320  * and their arguments.\r
321  *\r
322  * @param conn the TCP netconn to setup\r
323  */\r
324 static void\r
325 setup_tcp(struct netconn *conn)\r
326 {\r
327   struct tcp_pcb *pcb;\r
328 \r
329   pcb = conn->pcb.tcp;\r
330   tcp_arg(pcb, conn);\r
331   tcp_recv(pcb, recv_tcp);\r
332   tcp_sent(pcb, sent_tcp);\r
333   tcp_poll(pcb, poll_tcp, 4);\r
334   tcp_err(pcb, err_tcp);\r
335 }\r
336 \r
337 /**\r
338  * Accept callback function for TCP netconns.\r
339  * Allocates a new netconn and posts that to conn->acceptmbox.\r
340  *\r
341  * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value\r
342  */\r
343 static err_t\r
344 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)\r
345 {\r
346   struct netconn *newconn;\r
347   struct netconn *conn;\r
348 \r
349 #if API_MSG_DEBUG\r
350 #if TCP_DEBUG\r
351   tcp_debug_print_state(newpcb->state);\r
352 #endif /* TCP_DEBUG */\r
353 #endif /* API_MSG_DEBUG */\r
354   conn = (struct netconn *)arg;\r
355 \r
356   LWIP_ERROR("accept_function: invalid conn->acceptmbox",\r
357              conn->acceptmbox != SYS_MBOX_NULL, return ERR_VAL;);\r
358 \r
359   /* We have to set the callback here even though\r
360    * the new socket is unknown. conn->socket is marked as -1. */\r
361   newconn = netconn_alloc(conn->type, conn->callback);\r
362   if (newconn == NULL) {\r
363     return ERR_MEM;\r
364   }\r
365   newconn->pcb.tcp = newpcb;\r
366   setup_tcp(newconn);\r
367   newconn->err = err;\r
368   /* Register event with callback */\r
369   API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);\r
370 \r
371   if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {\r
372     /* When returning != ERR_OK, the connection is aborted in tcp_process(),\r
373        so do nothing here! */\r
374     newconn->pcb.tcp = NULL;\r
375     netconn_free(newconn);\r
376     return ERR_MEM;\r
377   }\r
378   return ERR_OK;\r
379 }\r
380 #endif /* LWIP_TCP */\r
381 \r
382 /**\r
383  * Create a new pcb of a specific type.\r
384  * Called from do_newconn().\r
385  *\r
386  * @param msg the api_msg_msg describing the connection type\r
387  * @return msg->conn->err, but the return value is currently ignored\r
388  */\r
389 static err_t\r
390 pcb_new(struct api_msg_msg *msg)\r
391 {\r
392    msg->conn->err = ERR_OK;\r
393 \r
394    LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);\r
395 \r
396    /* Allocate a PCB for this connection */\r
397    switch(NETCONNTYPE_GROUP(msg->conn->type)) {\r
398 #if LWIP_RAW\r
399    case NETCONN_RAW:\r
400      msg->conn->pcb.raw = raw_new(msg->msg.n.proto);\r
401      if(msg->conn->pcb.raw == NULL) {\r
402        msg->conn->err = ERR_MEM;\r
403        break;\r
404      }\r
405      raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);\r
406      break;\r
407 #endif /* LWIP_RAW */\r
408 #if LWIP_UDP\r
409    case NETCONN_UDP:\r
410      msg->conn->pcb.udp = udp_new();\r
411      if(msg->conn->pcb.udp == NULL) {\r
412        msg->conn->err = ERR_MEM;\r
413        break;\r
414      }\r
415 #if LWIP_UDPLITE\r
416      if (msg->conn->type==NETCONN_UDPLITE) {\r
417        udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);\r
418      }\r
419 #endif /* LWIP_UDPLITE */\r
420      if (msg->conn->type==NETCONN_UDPNOCHKSUM) {\r
421        udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);\r
422      }\r
423      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);\r
424      break;\r
425 #endif /* LWIP_UDP */\r
426 #if LWIP_TCP\r
427    case NETCONN_TCP:\r
428      msg->conn->pcb.tcp = tcp_new();\r
429      if(msg->conn->pcb.tcp == NULL) {\r
430        msg->conn->err = ERR_MEM;\r
431        break;\r
432      }\r
433      setup_tcp(msg->conn);\r
434      break;\r
435 #endif /* LWIP_TCP */\r
436    default:\r
437      /* Unsupported netconn type, e.g. protocol disabled */\r
438      msg->conn->err = ERR_VAL;\r
439      break;\r
440    }\r
441 \r
442   return msg->conn->err;\r
443 }\r
444 \r
445 /**\r
446  * Create a new pcb of a specific type inside a netconn.\r
447  * Called from netconn_new_with_proto_and_callback.\r
448  *\r
449  * @param msg the api_msg_msg describing the connection type\r
450  */\r
451 void\r
452 do_newconn(struct api_msg_msg *msg)\r
453 {\r
454    if(msg->conn->pcb.tcp == NULL) {\r
455      pcb_new(msg);\r
456    }\r
457    /* Else? This "new" connection already has a PCB allocated. */\r
458    /* Is this an error condition? Should it be deleted? */\r
459    /* We currently just are happy and return. */\r
460 \r
461    TCPIP_APIMSG_ACK(msg);\r
462 }\r
463 \r
464 /**\r
465  * Create a new netconn (of a specific type) that has a callback function.\r
466  * The corresponding pcb is NOT created!\r
467  *\r
468  * @param t the type of 'connection' to create (@see enum netconn_type)\r
469  * @param proto the IP protocol for RAW IP pcbs\r
470  * @param callback a function to call on status changes (RX available, TX'ed)\r
471  * @return a newly allocated struct netconn or\r
472  *         NULL on memory error\r
473  */\r
474 struct netconn*\r
475 netconn_alloc(enum netconn_type t, netconn_callback callback)\r
476 {\r
477   struct netconn *conn;\r
478   int size;\r
479 \r
480   conn = memp_malloc(MEMP_NETCONN);\r
481   if (conn == NULL) {\r
482     return NULL;\r
483   }\r
484 \r
485   conn->err = ERR_OK;\r
486   conn->type = t;\r
487   conn->pcb.tcp = NULL;\r
488 \r
489 #if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \\r
490     (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE)\r
491   size = DEFAULT_RAW_RECVMBOX_SIZE;\r
492 #else\r
493   switch(NETCONNTYPE_GROUP(t)) {\r
494 #if LWIP_RAW\r
495   case NETCONN_RAW:\r
496     size = DEFAULT_RAW_RECVMBOX_SIZE;\r
497     break;\r
498 #endif /* LWIP_RAW */\r
499 #if LWIP_UDP\r
500   case NETCONN_UDP:\r
501     size = DEFAULT_UDP_RECVMBOX_SIZE;\r
502     break;\r
503 #endif /* LWIP_UDP */\r
504 #if LWIP_TCP\r
505   case NETCONN_TCP:\r
506     size = DEFAULT_TCP_RECVMBOX_SIZE;\r
507     break;\r
508 #endif /* LWIP_TCP */\r
509   default:\r
510     LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);\r
511     break;\r
512   }\r
513 #endif\r
514 \r
515   if ((conn->op_completed = sys_sem_new(0)) == SYS_SEM_NULL) {\r
516     memp_free(MEMP_NETCONN, conn);\r
517     return NULL;\r
518   }\r
519   if ((conn->recvmbox = sys_mbox_new(size)) == SYS_MBOX_NULL) {\r
520     sys_sem_free(conn->op_completed);\r
521     memp_free(MEMP_NETCONN, conn);\r
522     return NULL;\r
523   }\r
524 \r
525   conn->acceptmbox   = SYS_MBOX_NULL;\r
526   conn->state        = NETCONN_NONE;\r
527   /* initialize socket to -1 since 0 is a valid socket */\r
528   conn->socket       = -1;\r
529   conn->callback     = callback;\r
530   conn->recv_avail   = 0;\r
531 #if LWIP_SO_RCVTIMEO\r
532   conn->recv_timeout = 0;\r
533 #endif /* LWIP_SO_RCVTIMEO */\r
534 #if LWIP_SO_RCVBUF\r
535   conn->recv_bufsize = INT_MAX;\r
536 #endif /* LWIP_SO_RCVBUF */\r
537   return conn;\r
538 }\r
539 \r
540 /**\r
541  * Delete a netconn and all its resources.\r
542  * The pcb is NOT freed (since we might not be in the right thread context do this).\r
543  *\r
544  * @param conn the netconn to free\r
545  */\r
546 void\r
547 netconn_free(struct netconn *conn)\r
548 {\r
549   void *mem;\r
550   LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);\r
551 \r
552   /* Drain the recvmbox. */\r
553   if (conn->recvmbox != SYS_MBOX_NULL) {\r
554     while (sys_mbox_tryfetch(conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {\r
555       if (conn->type == NETCONN_TCP) {\r
556         if(mem != NULL) {\r
557           pbuf_free((struct pbuf *)mem);\r
558         }\r
559       } else {\r
560         netbuf_delete((struct netbuf *)mem);\r
561       }\r
562     }\r
563     sys_mbox_free(conn->recvmbox);\r
564     conn->recvmbox = SYS_MBOX_NULL;\r
565   }\r
566 \r
567   /* Drain the acceptmbox. */\r
568   if (conn->acceptmbox != SYS_MBOX_NULL) {\r
569     while (sys_mbox_tryfetch(conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {\r
570       netconn_delete((struct netconn *)mem);\r
571     }\r
572     sys_mbox_free(conn->acceptmbox);\r
573     conn->acceptmbox = SYS_MBOX_NULL;\r
574   }\r
575 \r
576   sys_sem_free(conn->op_completed);\r
577   conn->op_completed = SYS_SEM_NULL;\r
578 \r
579   memp_free(MEMP_NETCONN, conn);\r
580 }\r
581 \r
582 #if LWIP_TCP\r
583 /**\r
584  * Internal helper function to close a TCP netconn: since this sometimes\r
585  * doesn't work at the first attempt, this function is called from multiple\r
586  * places.\r
587  *\r
588  * @param conn the TCP netconn to close\r
589  */\r
590 static void\r
591 do_close_internal(struct netconn *conn)\r
592 {\r
593   err_t err;\r
594 \r
595   LWIP_ASSERT("invalid conn", (conn != NULL));\r
596   LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));\r
597   LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));\r
598   LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));\r
599 \r
600   /* Set back some callback pointers */\r
601   if (conn->pcb.tcp->state == LISTEN) {\r
602     tcp_arg(conn->pcb.tcp, NULL);\r
603     tcp_accept(conn->pcb.tcp, NULL);\r
604   } else {\r
605     tcp_recv(conn->pcb.tcp, NULL);\r
606   }\r
607   /* Try to close the connection */\r
608   err = tcp_close(conn->pcb.tcp);\r
609   if (err == ERR_OK) {\r
610     /* Closing succeeded */\r
611     conn->state = NETCONN_NONE;\r
612     /* Set back some callback pointers as conn is going away */\r
613     tcp_err(conn->pcb.tcp, NULL);\r
614     tcp_poll(conn->pcb.tcp, NULL, 4);\r
615     tcp_sent(conn->pcb.tcp, NULL);\r
616     tcp_recv(conn->pcb.tcp, NULL);\r
617     tcp_arg(conn->pcb.tcp, NULL);\r
618     conn->pcb.tcp = NULL;\r
619     conn->err = ERR_OK;\r
620     /* Trigger select() in socket layer. This send should something else so the\r
621        errorfd is set, not the read and write fd! */\r
622     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);\r
623     API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);\r
624     /* wake up the application task */\r
625     sys_sem_signal(conn->op_completed);\r
626   }\r
627   /* If closing didn't succeed, we get called again either\r
628      from poll_tcp or from sent_tcp */\r
629 }\r
630 #endif /* LWIP_TCP */\r
631 \r
632 /**\r
633  * Delete the pcb inside a netconn.\r
634  * Called from netconn_delete.\r
635  *\r
636  * @param msg the api_msg_msg pointing to the connection\r
637  */\r
638 void\r
639 do_delconn(struct api_msg_msg *msg)\r
640 {\r
641   if (msg->conn->pcb.tcp != NULL) {\r
642     switch (NETCONNTYPE_GROUP(msg->conn->type)) {\r
643 #if LWIP_RAW\r
644     case NETCONN_RAW:\r
645       raw_remove(msg->conn->pcb.raw);\r
646       break;\r
647 #endif /* LWIP_RAW */\r
648 #if LWIP_UDP\r
649     case NETCONN_UDP:\r
650       msg->conn->pcb.udp->recv_arg = NULL;\r
651       udp_remove(msg->conn->pcb.udp);\r
652       break;\r
653 #endif /* LWIP_UDP */\r
654 #if LWIP_TCP\r
655     case NETCONN_TCP:\r
656       msg->conn->state = NETCONN_CLOSE;\r
657       do_close_internal(msg->conn);\r
658       /* API_EVENT is called inside do_close_internal, before releasing\r
659          the application thread, so we can return at this point! */\r
660       return;\r
661 #endif /* LWIP_TCP */\r
662     default:\r
663       break;\r
664     }\r
665   }\r
666   /* tcp netconns don't come here! */\r
667 \r
668   /* Trigger select() in socket layer. This send should something else so the\r
669      errorfd is set, not the read and write fd! */\r
670   API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);\r
671   API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);\r
672 \r
673   if (msg->conn->op_completed != SYS_SEM_NULL) {\r
674     sys_sem_signal(msg->conn->op_completed);\r
675   }\r
676 }\r
677 \r
678 /**\r
679  * Bind a pcb contained in a netconn\r
680  * Called from netconn_bind.\r
681  *\r
682  * @param msg the api_msg_msg pointing to the connection and containing\r
683  *            the IP address and port to bind to\r
684  */\r
685 void\r
686 do_bind(struct api_msg_msg *msg)\r
687 {\r
688   if (!ERR_IS_FATAL(msg->conn->err)) {\r
689     if (msg->conn->pcb.tcp != NULL) {\r
690       switch (NETCONNTYPE_GROUP(msg->conn->type)) {\r
691 #if LWIP_RAW\r
692       case NETCONN_RAW:\r
693         msg->conn->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);\r
694         break;\r
695 #endif /* LWIP_RAW */\r
696 #if LWIP_UDP\r
697       case NETCONN_UDP:\r
698         msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);\r
699         break;\r
700 #endif /* LWIP_UDP */\r
701 #if LWIP_TCP\r
702       case NETCONN_TCP:\r
703         msg->conn->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);\r
704         break;\r
705 #endif /* LWIP_TCP */\r
706       default:\r
707         break;\r
708       }\r
709     } else {\r
710       /* msg->conn->pcb is NULL */\r
711       msg->conn->err = ERR_VAL;\r
712     }\r
713   }\r
714   TCPIP_APIMSG_ACK(msg);\r
715 }\r
716 \r
717 #if LWIP_TCP\r
718 /**\r
719  * TCP callback function if a connection (opened by tcp_connect/do_connect) has\r
720  * been established (or reset by the remote host).\r
721  *\r
722  * @see tcp.h (struct tcp_pcb.connected) for parameters and return values\r
723  */\r
724 static err_t\r
725 do_connected(void *arg, struct tcp_pcb *pcb, err_t err)\r
726 {\r
727   struct netconn *conn;\r
728 \r
729   LWIP_UNUSED_ARG(pcb);\r
730 \r
731   conn = arg;\r
732 \r
733   if (conn == NULL) {\r
734     return ERR_VAL;\r
735   }\r
736 \r
737   conn->err = err;\r
738   if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {\r
739     setup_tcp(conn);\r
740   }\r
741   conn->state = NETCONN_NONE;\r
742   sys_sem_signal(conn->op_completed);\r
743   return ERR_OK;\r
744 }\r
745 #endif /* LWIP_TCP */\r
746 \r
747 /**\r
748  * Connect a pcb contained inside a netconn\r
749  * Called from netconn_connect.\r
750  *\r
751  * @param msg the api_msg_msg pointing to the connection and containing\r
752  *            the IP address and port to connect to\r
753  */\r
754 void\r
755 do_connect(struct api_msg_msg *msg)\r
756 {\r
757   if (msg->conn->pcb.tcp == NULL) {\r
758     sys_sem_signal(msg->conn->op_completed);\r
759     return;\r
760   }\r
761 \r
762   switch (NETCONNTYPE_GROUP(msg->conn->type)) {\r
763 #if LWIP_RAW\r
764   case NETCONN_RAW:\r
765     msg->conn->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);\r
766     sys_sem_signal(msg->conn->op_completed);\r
767     break;\r
768 #endif /* LWIP_RAW */\r
769 #if LWIP_UDP\r
770   case NETCONN_UDP:\r
771     msg->conn->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);\r
772     sys_sem_signal(msg->conn->op_completed);\r
773     break;\r
774 #endif /* LWIP_UDP */\r
775 #if LWIP_TCP\r
776   case NETCONN_TCP:\r
777     msg->conn->state = NETCONN_CONNECT;\r
778     setup_tcp(msg->conn);\r
779     msg->conn->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port,\r
780                                  do_connected);\r
781     /* sys_sem_signal() is called from do_connected (or err_tcp()),\r
782      * when the connection is established! */\r
783     break;\r
784 #endif /* LWIP_TCP */\r
785   default:\r
786     break;\r
787   }\r
788 }\r
789 \r
790 /**\r
791  * Connect a pcb contained inside a netconn\r
792  * Only used for UDP netconns.\r
793  * Called from netconn_disconnect.\r
794  *\r
795  * @param msg the api_msg_msg pointing to the connection to disconnect\r
796  */\r
797 void\r
798 do_disconnect(struct api_msg_msg *msg)\r
799 {\r
800 #if LWIP_UDP\r
801   if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {\r
802     udp_disconnect(msg->conn->pcb.udp);\r
803   }\r
804 #endif /* LWIP_UDP */\r
805   TCPIP_APIMSG_ACK(msg);\r
806 }\r
807 \r
808 /**\r
809  * Set a TCP pcb contained in a netconn into listen mode\r
810  * Called from netconn_listen.\r
811  *\r
812  * @param msg the api_msg_msg pointing to the connection\r
813  */\r
814 void\r
815 do_listen(struct api_msg_msg *msg)\r
816 {\r
817 #if LWIP_TCP\r
818   if (!ERR_IS_FATAL(msg->conn->err)) {\r
819     if (msg->conn->pcb.tcp != NULL) {\r
820       if (msg->conn->type == NETCONN_TCP) {\r
821         if (msg->conn->pcb.tcp->state == CLOSED) {\r
822 #if TCP_LISTEN_BACKLOG\r
823           struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);\r
824 #else  /* TCP_LISTEN_BACKLOG */\r
825           struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);\r
826 #endif /* TCP_LISTEN_BACKLOG */\r
827           if (lpcb == NULL) {\r
828             msg->conn->err = ERR_MEM;\r
829           } else {\r
830             /* delete the recvmbox and allocate the acceptmbox */\r
831             if (msg->conn->recvmbox != SYS_MBOX_NULL) {\r
832               /** @todo: should we drain the recvmbox here? */\r
833               sys_mbox_free(msg->conn->recvmbox);\r
834               msg->conn->recvmbox = SYS_MBOX_NULL;\r
835             }\r
836             if (msg->conn->acceptmbox == SYS_MBOX_NULL) {\r
837               if ((msg->conn->acceptmbox = sys_mbox_new(DEFAULT_ACCEPTMBOX_SIZE)) == SYS_MBOX_NULL) {\r
838                 msg->conn->err = ERR_MEM;\r
839               }\r
840             }\r
841             if (msg->conn->err == ERR_OK) {\r
842               msg->conn->state = NETCONN_LISTEN;\r
843               msg->conn->pcb.tcp = lpcb;\r
844               tcp_arg(msg->conn->pcb.tcp, msg->conn);\r
845               tcp_accept(msg->conn->pcb.tcp, accept_function);\r
846             }\r
847           }\r
848         } else {\r
849           msg->conn->err = ERR_CONN;\r
850         }\r
851       }\r
852     }\r
853   }\r
854 #endif /* LWIP_TCP */\r
855   TCPIP_APIMSG_ACK(msg);\r
856 }\r
857 \r
858 /**\r
859  * Send some data on a RAW or UDP pcb contained in a netconn\r
860  * Called from netconn_send\r
861  *\r
862  * @param msg the api_msg_msg pointing to the connection\r
863  */\r
864 void\r
865 do_send(struct api_msg_msg *msg)\r
866 {\r
867   if (!ERR_IS_FATAL(msg->conn->err)) {\r
868     if (msg->conn->pcb.tcp != NULL) {\r
869       switch (NETCONNTYPE_GROUP(msg->conn->type)) {\r
870 #if LWIP_RAW\r
871       case NETCONN_RAW:\r
872         if (msg->msg.b->addr == NULL) {\r
873           msg->conn->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);\r
874         } else {\r
875           msg->conn->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr);\r
876         }\r
877         break;\r
878 #endif\r
879 #if LWIP_UDP\r
880       case NETCONN_UDP:\r
881         if (msg->msg.b->addr == NULL) {\r
882           msg->conn->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);\r
883         } else {\r
884           msg->conn->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port);\r
885         }\r
886         break;\r
887 #endif /* LWIP_UDP */\r
888       default:\r
889         break;\r
890       }\r
891     }\r
892   }\r
893   TCPIP_APIMSG_ACK(msg);\r
894 }\r
895 \r
896 /**\r
897  * Recv some data from a RAW or UDP pcb contained in a netconn\r
898  * Called from netconn_recv\r
899  *\r
900  * @param msg the api_msg_msg pointing to the connection\r
901  */\r
902 void\r
903 do_recv(struct api_msg_msg *msg)\r
904 {\r
905 #if LWIP_TCP\r
906   if (!ERR_IS_FATAL(msg->conn->err)) {\r
907     if (msg->conn->pcb.tcp != NULL) {\r
908       if (msg->conn->type == NETCONN_TCP) {\r
909 #if TCP_LISTEN_BACKLOG\r
910         if (msg->conn->pcb.tcp->state == LISTEN) {\r
911           tcp_accepted(msg->conn->pcb.tcp);\r
912         } else\r
913 #endif /* TCP_LISTEN_BACKLOG */\r
914         {\r
915           tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len);\r
916         }\r
917       }\r
918     }\r
919   }\r
920 #endif /* LWIP_TCP */\r
921   TCPIP_APIMSG_ACK(msg);\r
922 }\r
923 \r
924 #if LWIP_TCP\r
925 /**\r
926  * See if more data needs to be written from a previous call to netconn_write.\r
927  * Called initially from do_write. If the first call can't send all data\r
928  * (because of low memory or empty send-buffer), this function is called again\r
929  * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the\r
930  * blocking application thread (waiting in netconn_write) is released.\r
931  *\r
932  * @param conn netconn (that is currently in state NETCONN_WRITE) to process\r
933  * @return ERR_OK\r
934  *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished\r
935  */\r
936 static err_t\r
937 do_writemore(struct netconn *conn)\r
938 {\r
939   err_t err;\r
940   void *dataptr;\r
941   u16_t len, available;\r
942   u8_t write_finished = 0;\r
943 \r
944   LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));\r
945 \r
946   dataptr = (u8_t*)conn->write_msg->msg.w.dataptr + conn->write_offset;\r
947   if ((conn->write_msg->msg.w.len - conn->write_offset > 0xffff)) { /* max_u16_t */\r
948     len = 0xffff;\r
949 #if LWIP_TCPIP_CORE_LOCKING\r
950     conn->write_delayed = 1;\r
951 #endif\r
952   } else {\r
953     len = conn->write_msg->msg.w.len - conn->write_offset;\r
954   }\r
955   available = tcp_sndbuf(conn->pcb.tcp);\r
956   if (available < len) {\r
957     /* don't try to write more than sendbuf */\r
958     len = available;\r
959 #if LWIP_TCPIP_CORE_LOCKING\r
960     conn->write_delayed = 1;\r
961 #endif\r
962   }\r
963 \r
964   err = tcp_write(conn->pcb.tcp, dataptr, len, conn->write_msg->msg.w.apiflags);\r
965   LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->write_msg->msg.w.len));\r
966   if (err == ERR_OK) {\r
967     conn->write_offset += len;\r
968     if (conn->write_offset == conn->write_msg->msg.w.len) {\r
969       /* everything was written */\r
970       write_finished = 1;\r
971       conn->write_msg = NULL;\r
972       conn->write_offset = 0;\r
973     }\r
974     err = tcp_output_nagle(conn->pcb.tcp);\r
975     conn->err = err;\r
976     if ((err == ERR_OK) && (tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT)) {\r
977       API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);\r
978     }\r
979   } else if (err == ERR_MEM) {\r
980     /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called\r
981        we do NOT return to the application thread, since ERR_MEM is\r
982        only a temporary error! */\r
983 \r
984     /* tcp_enqueue returned ERR_MEM, try tcp_output anyway */\r
985     err = tcp_output(conn->pcb.tcp);\r
986 \r
987 #if LWIP_TCPIP_CORE_LOCKING\r
988     conn->write_delayed = 1;\r
989 #endif\r
990   } else {\r
991     /* On errors != ERR_MEM, we don't try writing any more but return\r
992        the error to the application thread. */\r
993     conn->err = err;\r
994     write_finished = 1;\r
995   }\r
996 \r
997   if (write_finished) {\r
998     /* everything was written: set back connection state\r
999        and back to application task */\r
1000     conn->state = NETCONN_NONE;\r
1001 #if LWIP_TCPIP_CORE_LOCKING\r
1002     if (conn->write_delayed != 0)\r
1003 #endif\r
1004     {\r
1005       sys_sem_signal(conn->op_completed);\r
1006     }\r
1007   }\r
1008 #if LWIP_TCPIP_CORE_LOCKING\r
1009   else\r
1010     return ERR_MEM;\r
1011 #endif\r
1012   return ERR_OK;\r
1013 }\r
1014 #endif /* LWIP_TCP */\r
1015 \r
1016 /**\r
1017  * Send some data on a TCP pcb contained in a netconn\r
1018  * Called from netconn_write\r
1019  *\r
1020  * @param msg the api_msg_msg pointing to the connection\r
1021  */\r
1022 void\r
1023 do_write(struct api_msg_msg *msg)\r
1024 {\r
1025   if (!ERR_IS_FATAL(msg->conn->err)) {\r
1026     if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {\r
1027 #if LWIP_TCP\r
1028       msg->conn->state = NETCONN_WRITE;\r
1029       /* set all the variables used by do_writemore */\r
1030       msg->conn->write_msg = msg;\r
1031       msg->conn->write_offset = 0;\r
1032 #if LWIP_TCPIP_CORE_LOCKING\r
1033       msg->conn->write_delayed = 0;\r
1034       if (do_writemore(msg->conn) != ERR_OK) {\r
1035         LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);\r
1036         UNLOCK_TCPIP_CORE();\r
1037         sys_arch_sem_wait(msg->conn->op_completed, 0);\r
1038         LOCK_TCPIP_CORE();\r
1039         LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);\r
1040       }\r
1041 #else\r
1042       do_writemore(msg->conn);\r
1043 #endif\r
1044       /* for both cases: if do_writemore was called, don't ACK the APIMSG! */\r
1045       return;\r
1046 #endif /* LWIP_TCP */\r
1047 #if (LWIP_UDP || LWIP_RAW)\r
1048     } else {\r
1049       msg->conn->err = ERR_VAL;\r
1050 #endif /* (LWIP_UDP || LWIP_RAW) */\r
1051     }\r
1052   }\r
1053   TCPIP_APIMSG_ACK(msg);\r
1054 }\r
1055 \r
1056 /**\r
1057  * Return a connection's local or remote address\r
1058  * Called from netconn_getaddr\r
1059  *\r
1060  * @param msg the api_msg_msg pointing to the connection\r
1061  */\r
1062 void\r
1063 do_getaddr(struct api_msg_msg *msg)\r
1064 {\r
1065   if (msg->conn->pcb.ip != NULL) {\r
1066     *(msg->msg.ad.ipaddr) = (msg->msg.ad.local?msg->conn->pcb.ip->local_ip:msg->conn->pcb.ip->remote_ip);\r
1067 \r
1068     switch (NETCONNTYPE_GROUP(msg->conn->type)) {\r
1069 #if LWIP_RAW\r
1070     case NETCONN_RAW:\r
1071       if (msg->msg.ad.local) {\r
1072         *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;\r
1073       } else {\r
1074         /* return an error as connecting is only a helper for upper layers */\r
1075         msg->conn->err = ERR_CONN;\r
1076       }\r
1077       break;\r
1078 #endif /* LWIP_RAW */\r
1079 #if LWIP_UDP\r
1080     case NETCONN_UDP:\r
1081       if (msg->msg.ad.local) {\r
1082         *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;\r
1083       } else {\r
1084         if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {\r
1085           msg->conn->err = ERR_CONN;\r
1086         } else {\r
1087           *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;\r
1088         }\r
1089       }\r
1090       break;\r
1091 #endif /* LWIP_UDP */\r
1092 #if LWIP_TCP\r
1093     case NETCONN_TCP:\r
1094       *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port);\r
1095       break;\r
1096 #endif /* LWIP_TCP */\r
1097     }\r
1098   } else {\r
1099     msg->conn->err = ERR_CONN;\r
1100   }\r
1101   TCPIP_APIMSG_ACK(msg);\r
1102 }\r
1103 \r
1104 /**\r
1105  * Close a TCP pcb contained in a netconn\r
1106  * Called from netconn_close\r
1107  *\r
1108  * @param msg the api_msg_msg pointing to the connection\r
1109  */\r
1110 void\r
1111 do_close(struct api_msg_msg *msg)\r
1112 {\r
1113 #if LWIP_TCP\r
1114   if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {\r
1115       msg->conn->state = NETCONN_CLOSE;\r
1116       do_close_internal(msg->conn);\r
1117       /* for tcp netconns, do_close_internal ACKs the message */\r
1118   } else\r
1119 #endif /* LWIP_TCP */\r
1120   {\r
1121     msg->conn->err = ERR_VAL;\r
1122     TCPIP_APIMSG_ACK(msg);\r
1123   }\r
1124 }\r
1125 \r
1126 #if LWIP_IGMP\r
1127 /**\r
1128  * Join multicast groups for UDP netconns.\r
1129  * Called from netconn_join_leave_group\r
1130  *\r
1131  * @param msg the api_msg_msg pointing to the connection\r
1132  */\r
1133 void\r
1134 do_join_leave_group(struct api_msg_msg *msg)\r
1135 {\r
1136   if (!ERR_IS_FATAL(msg->conn->err)) {\r
1137     if (msg->conn->pcb.tcp != NULL) {\r
1138       if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {\r
1139 #if LWIP_UDP\r
1140         if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {\r
1141           msg->conn->err = igmp_joingroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);\r
1142         } else {\r
1143           msg->conn->err = igmp_leavegroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);\r
1144         }\r
1145 #endif /* LWIP_UDP */\r
1146 #if (LWIP_TCP || LWIP_RAW)\r
1147       } else {\r
1148         msg->conn->err = ERR_VAL;\r
1149 #endif /* (LWIP_TCP || LWIP_RAW) */\r
1150       }\r
1151     }\r
1152   }\r
1153   TCPIP_APIMSG_ACK(msg);\r
1154 }\r
1155 #endif /* LWIP_IGMP */\r
1156 \r
1157 #if LWIP_DNS\r
1158 /**\r
1159  * Callback function that is called when DNS name is resolved\r
1160  * (or on timeout). A waiting application thread is waked up by\r
1161  * signaling the semaphore.\r
1162  */\r
1163 static void\r
1164 do_dns_found(const char *name, struct ip_addr *ipaddr, void *arg)\r
1165 {\r
1166   struct dns_api_msg *msg = (struct dns_api_msg*)arg;\r
1167 \r
1168   LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0);\r
1169 \r
1170   if (ipaddr == NULL) {\r
1171     /* timeout or memory error */\r
1172     *msg->err = ERR_VAL;\r
1173   } else {\r
1174     /* address was resolved */\r
1175     *msg->err = ERR_OK;\r
1176     *msg->addr = *ipaddr;\r
1177   }\r
1178   /* wake up the application task waiting in netconn_gethostbyname */\r
1179   sys_sem_signal(msg->sem);\r
1180 }\r
1181 \r
1182 /**\r
1183  * Execute a DNS query\r
1184  * Called from netconn_gethostbyname\r
1185  *\r
1186  * @param arg the dns_api_msg pointing to the query\r
1187  */\r
1188 void\r
1189 do_gethostbyname(void *arg)\r
1190 {\r
1191   struct dns_api_msg *msg = (struct dns_api_msg*)arg;\r
1192 \r
1193   *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg);\r
1194   if (*msg->err != ERR_INPROGRESS) {\r
1195     /* on error or immediate success, wake up the application\r
1196      * task waiting in netconn_gethostbyname */\r
1197     sys_sem_signal(msg->sem);\r
1198   }\r
1199 }\r
1200 #endif /* LWIP_DNS */\r
1201 \r
1202 #endif /* LWIP_NETCONN */\r