]> git.sur5r.net Git - freertos/blob - Demo/Common/ethernet/lwIP/api/api_lib.c
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@82 1d2547de-c912-0410-9cb9...
[freertos] / Demo / Common / ethernet / lwIP / api / api_lib.c
1 /*\r
2  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
3  * All rights reserved. \r
4  * \r
5  * Redistribution and use in source and binary forms, with or without modification, \r
6  * are permitted provided that the following conditions are met:\r
7  *\r
8  * 1. Redistributions of source code must retain the above copyright notice,\r
9  *    this list of conditions and the following disclaimer.\r
10  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
11  *    this list of conditions and the following disclaimer in the documentation\r
12  *    and/or other materials provided with the distribution.\r
13  * 3. The name of the author may not be used to endorse or promote products\r
14  *    derived from this software without specific prior written permission. \r
15  *\r
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
19  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
21  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
25  * OF SUCH DAMAGE.\r
26  *\r
27  * This file is part of the lwIP TCP/IP stack.\r
28  * \r
29  * Author: Adam Dunkels <adam@sics.se>\r
30  *\r
31  */\r
32 \r
33 /* This is the part of the API that is linked with\r
34    the application */\r
35 \r
36 #include "lwip/opt.h"\r
37 #include "lwip/api.h"\r
38 #include "lwip/api_msg.h"\r
39 #include "lwip/memp.h"\r
40 \r
41 \r
42 struct\r
43 netbuf *netbuf_new(void)\r
44 {\r
45   struct netbuf *buf;\r
46 \r
47   buf = memp_malloc(MEMP_NETBUF);\r
48   if (buf != NULL) {\r
49     buf->p = NULL;\r
50     buf->ptr = NULL;\r
51     return buf;\r
52   } else {\r
53     return NULL;\r
54   }\r
55 }\r
56 \r
57 void\r
58 netbuf_delete(struct netbuf *buf)\r
59 {\r
60   if (buf != NULL) {\r
61     if (buf->p != NULL) {\r
62       pbuf_free(buf->p);\r
63       buf->p = buf->ptr = NULL;\r
64     }\r
65     memp_free(MEMP_NETBUF, buf);\r
66   }\r
67 }\r
68 \r
69 void *\r
70 netbuf_alloc(struct netbuf *buf, u16_t size)\r
71 {\r
72   /* Deallocate any previously allocated memory. */\r
73   if (buf->p != NULL) {\r
74     pbuf_free(buf->p);\r
75   }\r
76   buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);\r
77   if (buf->p == NULL) {\r
78      return NULL;\r
79   }\r
80   buf->ptr = buf->p;\r
81   return buf->p->payload;\r
82 }\r
83 \r
84 void\r
85 netbuf_free(struct netbuf *buf)\r
86 {\r
87   if (buf->p != NULL) {\r
88     pbuf_free(buf->p);\r
89   }\r
90   buf->p = buf->ptr = NULL;\r
91 }\r
92 \r
93 void\r
94 netbuf_ref(struct netbuf *buf, void *dataptr, u16_t size)\r
95 {\r
96   if (buf->p != NULL) {\r
97     pbuf_free(buf->p);\r
98   }\r
99   buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);\r
100   buf->p->payload = dataptr;\r
101   buf->p->len = buf->p->tot_len = size;\r
102   buf->ptr = buf->p;\r
103 }\r
104 \r
105 void\r
106 netbuf_chain(struct netbuf *head, struct netbuf *tail)\r
107 {\r
108   pbuf_chain(head->p, tail->p);\r
109   head->ptr = head->p;\r
110   memp_free(MEMP_NETBUF, tail);\r
111 }\r
112 \r
113 u16_t\r
114 netbuf_len(struct netbuf *buf)\r
115 {\r
116   return buf->p->tot_len;\r
117 }\r
118 \r
119 err_t\r
120 netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)\r
121 {\r
122   if (buf->ptr == NULL) {\r
123     return ERR_BUF;\r
124   }\r
125   *dataptr = buf->ptr->payload;\r
126   *len = buf->ptr->len;\r
127   return ERR_OK;\r
128 }\r
129 \r
130 s8_t\r
131 netbuf_next(struct netbuf *buf)\r
132 {\r
133   if (buf->ptr->next == NULL) {\r
134     return -1;\r
135   }\r
136   buf->ptr = buf->ptr->next;\r
137   if (buf->ptr->next == NULL) {\r
138     return 1;\r
139   }\r
140   return 0;\r
141 }\r
142 \r
143 void\r
144 netbuf_first(struct netbuf *buf)\r
145 {\r
146   buf->ptr = buf->p;\r
147 }\r
148 \r
149 void\r
150 netbuf_copy_partial(struct netbuf *buf, void *dataptr, u16_t len, u16_t offset)\r
151 {\r
152   struct pbuf *p;\r
153   u16_t i, left;\r
154 \r
155   left = 0;\r
156 \r
157   if(buf == NULL || dataptr == NULL) {\r
158     return;\r
159   }\r
160   \r
161   /* This implementation is bad. It should use bcopy\r
162      instead. */\r
163   for(p = buf->p; left < len && p != NULL; p = p->next) {\r
164     if (offset != 0 && offset >= p->len) {\r
165       offset -= p->len;\r
166     } else {    \r
167       for(i = offset; i < p->len; ++i) {\r
168   ((u8_t *)dataptr)[left] = ((u8_t *)p->payload)[i];\r
169   if (++left >= len) {\r
170     return;\r
171   }\r
172       }\r
173       offset = 0;\r
174     }\r
175   }\r
176 }\r
177 \r
178 void\r
179 netbuf_copy(struct netbuf *buf, void *dataptr, u16_t len)\r
180 {\r
181   netbuf_copy_partial(buf, dataptr, len, 0);\r
182 }\r
183 \r
184 struct ip_addr *\r
185 netbuf_fromaddr(struct netbuf *buf)\r
186 {\r
187   return buf->fromaddr;\r
188 }\r
189 \r
190 u16_t\r
191 netbuf_fromport(struct netbuf *buf)\r
192 {\r
193   return buf->fromport;\r
194 }\r
195 \r
196 struct\r
197 netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u16_t proto,\r
198                                    void (*callback)(struct netconn *, enum netconn_evt, u16_t len))\r
199 {\r
200   struct netconn *conn;\r
201   struct api_msg *msg;\r
202 \r
203   conn = memp_malloc(MEMP_NETCONN);\r
204   if (conn == NULL) {\r
205     return NULL;\r
206   }\r
207   \r
208   conn->err = ERR_OK;\r
209   conn->type = t;\r
210   conn->pcb.tcp = NULL;\r
211 \r
212   if ((conn->mbox = sys_mbox_new()) == SYS_MBOX_NULL) {\r
213     memp_free(MEMP_NETCONN, conn);\r
214     return NULL;\r
215   }\r
216   conn->recvmbox = SYS_MBOX_NULL;\r
217   conn->acceptmbox = SYS_MBOX_NULL;\r
218   conn->sem = sys_sem_new(0);\r
219   if (conn->sem == SYS_SEM_NULL) {\r
220     memp_free(MEMP_NETCONN, conn);\r
221     return NULL;\r
222   }\r
223   conn->state = NETCONN_NONE;\r
224   conn->socket = 0;\r
225   conn->callback = callback;\r
226   conn->recv_avail = 0;\r
227 \r
228   if((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
229     memp_free(MEMP_NETCONN, conn);\r
230     return NULL;\r
231   }\r
232   \r
233   msg->type = API_MSG_NEWCONN;\r
234   msg->msg.msg.bc.port = proto; /* misusing the port field */\r
235   msg->msg.conn = conn;\r
236   api_msg_post(msg);  \r
237   sys_mbox_fetch(conn->mbox, NULL);\r
238   memp_free(MEMP_API_MSG, msg);\r
239 \r
240   if ( conn->err != ERR_OK ) {\r
241     memp_free(MEMP_NETCONN, conn);\r
242     return NULL;\r
243   }\r
244 \r
245   return conn;\r
246 }\r
247 \r
248 \r
249 struct\r
250 netconn *netconn_new(enum netconn_type t)\r
251 {\r
252   return netconn_new_with_proto_and_callback(t,0,NULL);\r
253 }\r
254 \r
255 struct\r
256 netconn *netconn_new_with_callback(enum netconn_type t,\r
257                                    void (*callback)(struct netconn *, enum netconn_evt, u16_t len))\r
258 {\r
259   return netconn_new_with_proto_and_callback(t,0,callback);\r
260 }\r
261 \r
262 \r
263 err_t\r
264 netconn_delete(struct netconn *conn)\r
265 {\r
266   struct api_msg *msg;\r
267   void *mem;\r
268   \r
269   if (conn == NULL) {\r
270     return ERR_OK;\r
271   }\r
272   \r
273   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
274     return ERR_MEM;\r
275   }\r
276   \r
277   msg->type = API_MSG_DELCONN;\r
278   msg->msg.conn = conn;\r
279   api_msg_post(msg);  \r
280   sys_mbox_fetch(conn->mbox, NULL);\r
281   memp_free(MEMP_API_MSG, msg);\r
282 \r
283   /* Drain the recvmbox. */\r
284   if (conn->recvmbox != SYS_MBOX_NULL) {\r
285     while (sys_arch_mbox_fetch(conn->recvmbox, &mem, 1) != SYS_ARCH_TIMEOUT) {\r
286       if (conn->type == NETCONN_TCP) {\r
287         if(mem != NULL)\r
288           pbuf_free((struct pbuf *)mem);\r
289       } else {\r
290         netbuf_delete((struct netbuf *)mem);\r
291       }\r
292     }\r
293     sys_mbox_free(conn->recvmbox);\r
294     conn->recvmbox = SYS_MBOX_NULL;\r
295   }\r
296  \r
297 \r
298   /* Drain the acceptmbox. */\r
299   if (conn->acceptmbox != SYS_MBOX_NULL) {\r
300     while (sys_arch_mbox_fetch(conn->acceptmbox, &mem, 1) != SYS_ARCH_TIMEOUT) {\r
301       netconn_delete((struct netconn *)mem);\r
302     }\r
303     \r
304     sys_mbox_free(conn->acceptmbox);\r
305     conn->acceptmbox = SYS_MBOX_NULL;\r
306   }\r
307 \r
308   sys_mbox_free(conn->mbox);\r
309   conn->mbox = SYS_MBOX_NULL;\r
310   if (conn->sem != SYS_SEM_NULL) {\r
311     sys_sem_free(conn->sem);\r
312   }\r
313   /*  conn->sem = SYS_SEM_NULL;*/\r
314   memp_free(MEMP_NETCONN, conn);\r
315   return ERR_OK;\r
316 }\r
317 \r
318 enum netconn_type\r
319 netconn_type(struct netconn *conn)\r
320 {\r
321   return conn->type;\r
322 }\r
323 \r
324 err_t\r
325 netconn_peer(struct netconn *conn, struct ip_addr *addr,\r
326        u16_t *port)\r
327 {\r
328   switch (conn->type) {\r
329   case NETCONN_RAW:\r
330     /* return an error as connecting is only a helper for upper layers */\r
331     return ERR_CONN;\r
332   case NETCONN_UDPLITE:\r
333   case NETCONN_UDPNOCHKSUM:\r
334   case NETCONN_UDP:\r
335     if (conn->pcb.udp == NULL ||\r
336   ((conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0))\r
337      return ERR_CONN;\r
338     *addr = (conn->pcb.udp->remote_ip);\r
339     *port = conn->pcb.udp->remote_port;\r
340     break;\r
341   case NETCONN_TCP:\r
342     if (conn->pcb.tcp == NULL)\r
343       return ERR_CONN;\r
344     *addr = (conn->pcb.tcp->remote_ip);\r
345     *port = conn->pcb.tcp->remote_port;\r
346     break;\r
347   }\r
348   return (conn->err = ERR_OK);\r
349 }\r
350 \r
351 err_t\r
352 netconn_addr(struct netconn *conn, struct ip_addr **addr,\r
353        u16_t *port)\r
354 {\r
355   switch (conn->type) {\r
356   case NETCONN_RAW:\r
357     *addr = &(conn->pcb.raw->local_ip);\r
358     *port = conn->pcb.raw->protocol;\r
359     break;\r
360   case NETCONN_UDPLITE:\r
361   case NETCONN_UDPNOCHKSUM:\r
362   case NETCONN_UDP:\r
363     *addr = &(conn->pcb.udp->local_ip);\r
364     *port = conn->pcb.udp->local_port;\r
365     break;\r
366   case NETCONN_TCP:\r
367     *addr = &(conn->pcb.tcp->local_ip);\r
368     *port = conn->pcb.tcp->local_port;\r
369     break;\r
370   }\r
371   return (conn->err = ERR_OK);\r
372 }\r
373 \r
374 err_t\r
375 netconn_bind(struct netconn *conn, struct ip_addr *addr,\r
376       u16_t port)\r
377 {\r
378   struct api_msg *msg;\r
379 \r
380   if (conn == NULL) {\r
381     return ERR_VAL;\r
382   }\r
383 \r
384   if (conn->type != NETCONN_TCP &&\r
385      conn->recvmbox == SYS_MBOX_NULL) {\r
386     if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {\r
387       return ERR_MEM;\r
388     }\r
389   }\r
390   \r
391   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
392     return (conn->err = ERR_MEM);\r
393   }\r
394   msg->type = API_MSG_BIND;\r
395   msg->msg.conn = conn;\r
396   msg->msg.msg.bc.ipaddr = addr;\r
397   msg->msg.msg.bc.port = port;\r
398   api_msg_post(msg);\r
399   sys_mbox_fetch(conn->mbox, NULL);\r
400   memp_free(MEMP_API_MSG, msg);\r
401   return conn->err;\r
402 }\r
403 \r
404 \r
405 err_t\r
406 netconn_connect(struct netconn *conn, struct ip_addr *addr,\r
407        u16_t port)\r
408 {\r
409   struct api_msg *msg;\r
410   \r
411   if (conn == NULL) {\r
412     return ERR_VAL;\r
413   }\r
414 \r
415 \r
416   if (conn->recvmbox == SYS_MBOX_NULL) {\r
417     if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {\r
418       return ERR_MEM;\r
419     }\r
420   }\r
421   \r
422   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
423     return ERR_MEM;\r
424   }\r
425   msg->type = API_MSG_CONNECT;\r
426   msg->msg.conn = conn;  \r
427   msg->msg.msg.bc.ipaddr = addr;\r
428   msg->msg.msg.bc.port = port;\r
429   api_msg_post(msg);\r
430   sys_mbox_fetch(conn->mbox, NULL);\r
431   memp_free(MEMP_API_MSG, msg);\r
432   return conn->err;\r
433 }\r
434 \r
435 err_t\r
436 netconn_disconnect(struct netconn *conn)\r
437 {\r
438   struct api_msg *msg;\r
439   \r
440   if (conn == NULL) {\r
441     return ERR_VAL;\r
442   }\r
443 \r
444   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
445     return ERR_MEM;\r
446   }\r
447   msg->type = API_MSG_DISCONNECT;\r
448   msg->msg.conn = conn;  \r
449   api_msg_post(msg);\r
450   sys_mbox_fetch(conn->mbox, NULL);\r
451   memp_free(MEMP_API_MSG, msg);\r
452   return conn->err;\r
453 \r
454 }\r
455 \r
456 err_t\r
457 netconn_listen(struct netconn *conn)\r
458 {\r
459   struct api_msg *msg;\r
460 \r
461   if (conn == NULL) {\r
462     return ERR_VAL;\r
463   }\r
464 \r
465   if (conn->acceptmbox == SYS_MBOX_NULL) {\r
466     conn->acceptmbox = sys_mbox_new();\r
467     if (conn->acceptmbox == SYS_MBOX_NULL) {\r
468       return ERR_MEM;\r
469     }\r
470   }\r
471   \r
472   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
473     return (conn->err = ERR_MEM);\r
474   }\r
475   msg->type = API_MSG_LISTEN;\r
476   msg->msg.conn = conn;\r
477   api_msg_post(msg);\r
478   sys_mbox_fetch(conn->mbox, NULL);\r
479   memp_free(MEMP_API_MSG, msg);\r
480   return conn->err;\r
481 }\r
482 \r
483 struct netconn *\r
484 netconn_accept(struct netconn *conn)\r
485 {\r
486   struct netconn *newconn;\r
487   \r
488   if (conn == NULL) {\r
489     return NULL;\r
490   }\r
491   \r
492   sys_mbox_fetch(conn->acceptmbox, (void *)&newconn);\r
493   /* Register event with callback */\r
494   if (conn->callback)\r
495       (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, 0);\r
496   \r
497   return newconn;\r
498 }\r
499 \r
500 struct netbuf *\r
501 netconn_recv(struct netconn *conn)\r
502 {\r
503   struct api_msg *msg;\r
504   struct netbuf *buf;\r
505   struct pbuf *p;\r
506   u16_t len;\r
507     \r
508   if (conn == NULL) {\r
509     return NULL;\r
510   }\r
511   \r
512   if (conn->recvmbox == SYS_MBOX_NULL) {\r
513     conn->err = ERR_CONN;\r
514     return NULL;\r
515   }\r
516 \r
517   if (conn->err != ERR_OK) {\r
518     return NULL;\r
519   }\r
520 \r
521   if (conn->type == NETCONN_TCP) {\r
522     if (conn->pcb.tcp->state == LISTEN) {\r
523       conn->err = ERR_CONN;\r
524       return NULL;\r
525     }\r
526 \r
527 \r
528     buf = memp_malloc(MEMP_NETBUF);\r
529 \r
530     if (buf == NULL) {\r
531       conn->err = ERR_MEM;\r
532       return NULL;\r
533     }\r
534     \r
535     sys_mbox_fetch(conn->recvmbox, (void *)&p);\r
536 \r
537     if (p != NULL)\r
538     {\r
539         len = p->tot_len;\r
540         conn->recv_avail -= len;\r
541     }\r
542     else\r
543         len = 0;\r
544     \r
545     /* Register event with callback */\r
546       if (conn->callback)\r
547         (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, len);\r
548 \r
549     /* If we are closed, we indicate that we no longer wish to receive\r
550        data by setting conn->recvmbox to SYS_MBOX_NULL. */\r
551     if (p == NULL) {\r
552       memp_free(MEMP_NETBUF, buf);\r
553       sys_mbox_free(conn->recvmbox);\r
554       conn->recvmbox = SYS_MBOX_NULL;\r
555       return NULL;\r
556     }\r
557 \r
558     buf->p = p;\r
559     buf->ptr = p;\r
560     buf->fromport = 0;\r
561     buf->fromaddr = NULL;\r
562 \r
563     /* Let the stack know that we have taken the data. */\r
564     if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
565       conn->err = ERR_MEM;\r
566       return buf;\r
567     }\r
568     msg->type = API_MSG_RECV;\r
569     msg->msg.conn = conn;\r
570     if (buf != NULL) {\r
571       msg->msg.msg.len = buf->p->tot_len;\r
572     } else {\r
573       msg->msg.msg.len = 1;\r
574     }\r
575     api_msg_post(msg);\r
576 \r
577     sys_mbox_fetch(conn->mbox, NULL);\r
578     memp_free(MEMP_API_MSG, msg);\r
579   } else {\r
580     sys_mbox_fetch(conn->recvmbox, (void *)&buf);\r
581   conn->recv_avail -= buf->p->tot_len;\r
582     /* Register event with callback */\r
583     if (conn->callback)\r
584         (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len);\r
585   }\r
586 \r
587   \r
588 \r
589     \r
590   LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err));\r
591 \r
592 \r
593   return buf;\r
594 }\r
595 \r
596 err_t\r
597 netconn_send(struct netconn *conn, struct netbuf *buf)\r
598 {\r
599   struct api_msg *msg;\r
600 \r
601   if (conn == NULL) {\r
602     return ERR_VAL;\r
603   }\r
604 \r
605   if (conn->err != ERR_OK) {\r
606     return conn->err;\r
607   }\r
608 \r
609   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
610     return (conn->err = ERR_MEM);\r
611   }\r
612 \r
613   LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len));\r
614   msg->type = API_MSG_SEND;\r
615   msg->msg.conn = conn;\r
616   msg->msg.msg.p = buf->p;\r
617   api_msg_post(msg);\r
618 \r
619   sys_mbox_fetch(conn->mbox, NULL);\r
620   memp_free(MEMP_API_MSG, msg);\r
621   return conn->err;\r
622 }\r
623 \r
624 err_t\r
625 netconn_write(struct netconn *conn, void *dataptr, u16_t size, u8_t copy)\r
626 {\r
627   struct api_msg *msg;\r
628   u16_t len;\r
629   \r
630   if (conn == NULL) {\r
631     return ERR_VAL;\r
632   }\r
633 \r
634   if (conn->err != ERR_OK) {\r
635     return conn->err;\r
636   }\r
637 \r
638   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
639     return (conn->err = ERR_MEM);\r
640   }\r
641   msg->type = API_MSG_WRITE;\r
642   msg->msg.conn = conn;\r
643         \r
644 \r
645   conn->state = NETCONN_WRITE;\r
646   while (conn->err == ERR_OK && size > 0) {\r
647     msg->msg.msg.w.dataptr = dataptr;\r
648     msg->msg.msg.w.copy = copy;\r
649     \r
650     if (conn->type == NETCONN_TCP) {\r
651       if (tcp_sndbuf(conn->pcb.tcp) == 0) {\r
652   sys_sem_wait(conn->sem);\r
653   if (conn->err != ERR_OK) {\r
654     goto ret;\r
655   }\r
656       }\r
657       if (size > tcp_sndbuf(conn->pcb.tcp)) {\r
658   /* We cannot send more than one send buffer's worth of data at a\r
659      time. */\r
660   len = tcp_sndbuf(conn->pcb.tcp);\r
661       } else {\r
662   len = size;\r
663       }\r
664     } else {\r
665       len = size;\r
666     }\r
667     \r
668     LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_write: writing %d bytes (%d)\n", len, copy));\r
669     msg->msg.msg.w.len = len;\r
670     api_msg_post(msg);\r
671     sys_mbox_fetch(conn->mbox, NULL);    \r
672     if (conn->err == ERR_OK) {\r
673       dataptr = (void *)((u8_t *)dataptr + len);\r
674       size -= len;\r
675     } else if (conn->err == ERR_MEM) {\r
676       conn->err = ERR_OK;\r
677       sys_sem_wait(conn->sem);\r
678     } else {\r
679       goto ret;\r
680     }\r
681   }\r
682  ret:\r
683   memp_free(MEMP_API_MSG, msg);\r
684   conn->state = NETCONN_NONE;\r
685   \r
686   return conn->err;\r
687 }\r
688 \r
689 err_t\r
690 netconn_close(struct netconn *conn)\r
691 {\r
692   struct api_msg *msg;\r
693 \r
694   if (conn == NULL) {\r
695     return ERR_VAL;\r
696   }\r
697   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
698     return (conn->err = ERR_MEM);\r
699   }\r
700 \r
701   conn->state = NETCONN_CLOSE;\r
702  again:\r
703   msg->type = API_MSG_CLOSE;\r
704   msg->msg.conn = conn;\r
705   api_msg_post(msg);\r
706   sys_mbox_fetch(conn->mbox, NULL);\r
707   if (conn->err == ERR_MEM &&\r
708      conn->sem != SYS_SEM_NULL) {\r
709     sys_sem_wait(conn->sem);\r
710     goto again;\r
711   }\r
712   conn->state = NETCONN_NONE;\r
713   memp_free(MEMP_API_MSG, msg);\r
714   return conn->err;\r
715 }\r
716 \r
717 err_t\r
718 netconn_err(struct netconn *conn)\r
719 {\r
720   return conn->err;\r
721 }\r
722 \r