2 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
\r
3 * All rights reserved.
\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
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
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
27 * This file is part of the lwIP TCP/IP stack.
\r
29 * Author: Adam Dunkels <adam@sics.se>
\r
33 #include "lwip/opt.h"
\r
34 #include "lwip/arch.h"
\r
35 #include "lwip/api_msg.h"
\r
36 #include "lwip/memp.h"
\r
37 #include "lwip/sys.h"
\r
38 #include "lwip/tcpip.h"
\r
42 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
\r
43 struct ip_addr *addr)
\r
46 struct netconn *conn;
\r
49 if (!conn) return 0;
\r
51 if (conn->recvmbox != SYS_MBOX_NULL) {
\r
52 if (!(buf = memp_malloc(MEMP_NETBUF))) {
\r
58 buf->fromaddr = addr;
\r
59 buf->fromport = pcb->protocol;
\r
61 conn->recv_avail += p->tot_len;
\r
62 /* Register event with callback */
\r
64 (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
\r
65 sys_mbox_post(conn->recvmbox, buf);
\r
68 return 0; /* do not eat the packet */
\r
73 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
\r
74 struct ip_addr *addr, u16_t port)
\r
77 struct netconn *conn;
\r
85 if (conn->recvmbox != SYS_MBOX_NULL) {
\r
86 buf = memp_malloc(MEMP_NETBUF);
\r
93 buf->fromaddr = addr;
\r
94 buf->fromport = port;
\r
97 conn->recv_avail += p->tot_len;
\r
98 /* Register event with callback */
\r
100 (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
\r
101 sys_mbox_post(conn->recvmbox, buf);
\r
104 #endif /* LWIP_UDP */
\r
108 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
\r
110 struct netconn *conn;
\r
115 if (conn == NULL) {
\r
120 if (conn->recvmbox != SYS_MBOX_NULL) {
\r
125 conn->recv_avail += len;
\r
129 /* Register event with callback */
\r
130 if (conn->callback)
\r
131 (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, len);
\r
132 sys_mbox_post(conn->recvmbox, p);
\r
139 poll_tcp(void *arg, struct tcp_pcb *pcb)
\r
141 struct netconn *conn;
\r
144 if (conn != NULL &&
\r
145 (conn->state == NETCONN_WRITE || conn->state == NETCONN_CLOSE) &&
\r
146 conn->sem != SYS_SEM_NULL) {
\r
147 sys_sem_signal(conn->sem);
\r
153 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
\r
155 struct netconn *conn;
\r
158 if (conn != NULL && conn->sem != SYS_SEM_NULL) {
\r
159 sys_sem_signal(conn->sem);
\r
162 if (conn && conn->callback)
\r
163 if (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)
\r
164 (*conn->callback)(conn, NETCONN_EVT_SENDPLUS, len);
\r
170 err_tcp(void *arg, err_t err)
\r
172 struct netconn *conn;
\r
176 conn->pcb.tcp = NULL;
\r
180 if (conn->recvmbox != SYS_MBOX_NULL) {
\r
181 /* Register event with callback */
\r
182 if (conn->callback)
\r
183 (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
\r
184 sys_mbox_post(conn->recvmbox, NULL);
\r
186 if (conn->mbox != SYS_MBOX_NULL) {
\r
187 sys_mbox_post(conn->mbox, NULL);
\r
189 if (conn->acceptmbox != SYS_MBOX_NULL) {
\r
190 /* Register event with callback */
\r
191 if (conn->callback)
\r
192 (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
\r
193 sys_mbox_post(conn->acceptmbox, NULL);
\r
195 if (conn->sem != SYS_SEM_NULL) {
\r
196 sys_sem_signal(conn->sem);
\r
201 setup_tcp(struct netconn *conn)
\r
203 struct tcp_pcb *pcb;
\r
205 pcb = conn->pcb.tcp;
\r
206 tcp_arg(pcb, conn);
\r
207 tcp_recv(pcb, recv_tcp);
\r
208 tcp_sent(pcb, sent_tcp);
\r
209 tcp_poll(pcb, poll_tcp, 4);
\r
210 tcp_err(pcb, err_tcp);
\r
214 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
\r
217 struct netconn *newconn;
\r
218 struct netconn *conn;
\r
222 tcp_debug_print_state(newpcb->state);
\r
223 #endif /* TCP_DEBUG */
\r
224 #endif /* API_MSG_DEBUG */
\r
225 conn = (struct netconn *)arg;
\r
226 mbox = conn->acceptmbox;
\r
227 newconn = memp_malloc(MEMP_NETCONN);
\r
228 if (newconn == NULL) {
\r
231 newconn->recvmbox = sys_mbox_new();
\r
232 if (newconn->recvmbox == SYS_MBOX_NULL) {
\r
233 memp_free(MEMP_NETCONN, newconn);
\r
236 newconn->mbox = sys_mbox_new();
\r
237 if (newconn->mbox == SYS_MBOX_NULL) {
\r
238 sys_mbox_free(newconn->recvmbox);
\r
239 memp_free(MEMP_NETCONN, newconn);
\r
242 newconn->sem = sys_sem_new(0);
\r
243 if (newconn->sem == SYS_SEM_NULL) {
\r
244 sys_mbox_free(newconn->recvmbox);
\r
245 sys_mbox_free(newconn->mbox);
\r
246 memp_free(MEMP_NETCONN, newconn);
\r
249 /* Allocations were OK, setup the PCB etc */
\r
250 newconn->type = NETCONN_TCP;
\r
251 newconn->pcb.tcp = newpcb;
\r
252 setup_tcp(newconn);
\r
253 newconn->acceptmbox = SYS_MBOX_NULL;
\r
254 newconn->err = err;
\r
255 /* Register event with callback */
\r
256 if (conn->callback)
\r
258 (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
\r
260 /* We have to set the callback here even though
\r
261 * the new socket is unknown. Mark the socket as -1. */
\r
262 newconn->callback = conn->callback;
\r
263 newconn->socket = -1;
\r
264 newconn->recv_avail = 0;
\r
266 sys_mbox_post(mbox, newconn);
\r
269 #endif /* LWIP_TCP */
\r
272 do_newconn(struct api_msg_msg *msg)
\r
274 if(msg->conn->pcb.tcp != NULL) {
\r
275 /* This "new" connection already has a PCB allocated. */
\r
276 /* Is this an error condition? Should it be deleted?
\r
277 We currently just are happy and return. */
\r
278 sys_mbox_post(msg->conn->mbox, NULL);
\r
282 msg->conn->err = ERR_OK;
\r
284 /* Allocate a PCB for this connection */
\r
285 switch(msg->conn->type) {
\r
288 msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field */
\r
289 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
\r
293 case NETCONN_UDPLITE:
\r
294 msg->conn->pcb.udp = udp_new();
\r
295 if(msg->conn->pcb.udp == NULL) {
\r
296 msg->conn->err = ERR_MEM;
\r
299 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
\r
300 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
302 case NETCONN_UDPNOCHKSUM:
\r
303 msg->conn->pcb.udp = udp_new();
\r
304 if(msg->conn->pcb.udp == NULL) {
\r
305 msg->conn->err = ERR_MEM;
\r
308 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
\r
309 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
312 msg->conn->pcb.udp = udp_new();
\r
313 if(msg->conn->pcb.udp == NULL) {
\r
314 msg->conn->err = ERR_MEM;
\r
317 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
319 #endif /* LWIP_UDP */
\r
322 msg->conn->pcb.tcp = tcp_new();
\r
323 if(msg->conn->pcb.tcp == NULL) {
\r
324 msg->conn->err = ERR_MEM;
\r
327 setup_tcp(msg->conn);
\r
333 sys_mbox_post(msg->conn->mbox, NULL);
\r
338 do_delconn(struct api_msg_msg *msg)
\r
340 if (msg->conn->pcb.tcp != NULL) {
\r
341 switch (msg->conn->type) {
\r
344 raw_remove(msg->conn->pcb.raw);
\r
348 case NETCONN_UDPLITE:
\r
350 case NETCONN_UDPNOCHKSUM:
\r
353 msg->conn->pcb.udp->recv_arg = NULL;
\r
354 udp_remove(msg->conn->pcb.udp);
\r
356 #endif /* LWIP_UDP */
\r
359 if (msg->conn->pcb.tcp->state == LISTEN) {
\r
360 tcp_arg(msg->conn->pcb.tcp, NULL);
\r
361 tcp_accept(msg->conn->pcb.tcp, NULL);
\r
362 tcp_close(msg->conn->pcb.tcp);
\r
364 tcp_arg(msg->conn->pcb.tcp, NULL);
\r
365 tcp_sent(msg->conn->pcb.tcp, NULL);
\r
366 tcp_recv(msg->conn->pcb.tcp, NULL);
\r
367 tcp_poll(msg->conn->pcb.tcp, NULL, 0);
\r
368 tcp_err(msg->conn->pcb.tcp, NULL);
\r
369 if (tcp_close(msg->conn->pcb.tcp) != ERR_OK) {
\r
370 tcp_abort(msg->conn->pcb.tcp);
\r
378 /* Trigger select() in socket layer */
\r
379 if (msg->conn->callback)
\r
381 (*msg->conn->callback)(msg->conn, NETCONN_EVT_RCVPLUS, 0);
\r
382 (*msg->conn->callback)(msg->conn, NETCONN_EVT_SENDPLUS, 0);
\r
385 if (msg->conn->mbox != SYS_MBOX_NULL) {
\r
386 sys_mbox_post(msg->conn->mbox, NULL);
\r
391 do_bind(struct api_msg_msg *msg)
\r
393 if (msg->conn->pcb.tcp == NULL) {
\r
394 switch (msg->conn->type) {
\r
397 msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */
\r
398 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
\r
402 case NETCONN_UDPLITE:
\r
403 msg->conn->pcb.udp = udp_new();
\r
404 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
\r
405 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
407 case NETCONN_UDPNOCHKSUM:
\r
408 msg->conn->pcb.udp = udp_new();
\r
409 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
\r
410 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
413 msg->conn->pcb.udp = udp_new();
\r
414 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
416 #endif /* LWIP_UDP */
\r
419 msg->conn->pcb.tcp = tcp_new();
\r
420 setup_tcp(msg->conn);
\r
421 #endif /* LWIP_TCP */
\r
426 switch (msg->conn->type) {
\r
429 msg->conn->err = raw_bind(msg->conn->pcb.raw,msg->msg.bc.ipaddr);
\r
433 case NETCONN_UDPLITE:
\r
435 case NETCONN_UDPNOCHKSUM:
\r
438 msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
\r
440 #endif /* LWIP_UDP */
\r
443 msg->conn->err = tcp_bind(msg->conn->pcb.tcp,
\r
444 msg->msg.bc.ipaddr, msg->msg.bc.port);
\r
445 #endif /* LWIP_TCP */
\r
449 sys_mbox_post(msg->conn->mbox, NULL);
\r
454 do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
\r
456 struct netconn *conn;
\r
460 if (conn == NULL) {
\r
465 if (conn->type == NETCONN_TCP && err == ERR_OK) {
\r
468 sys_mbox_post(conn->mbox, NULL);
\r
474 do_connect(struct api_msg_msg *msg)
\r
476 if (msg->conn->pcb.tcp == NULL) {
\r
477 switch (msg->conn->type) {
\r
480 msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */
\r
481 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
\r
485 case NETCONN_UDPLITE:
\r
486 msg->conn->pcb.udp = udp_new();
\r
487 if (msg->conn->pcb.udp == NULL) {
\r
488 msg->conn->err = ERR_MEM;
\r
489 sys_mbox_post(msg->conn->mbox, NULL);
\r
492 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
\r
493 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
495 case NETCONN_UDPNOCHKSUM:
\r
496 msg->conn->pcb.udp = udp_new();
\r
497 if (msg->conn->pcb.udp == NULL) {
\r
498 msg->conn->err = ERR_MEM;
\r
499 sys_mbox_post(msg->conn->mbox, NULL);
\r
502 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
\r
503 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
506 msg->conn->pcb.udp = udp_new();
\r
507 if (msg->conn->pcb.udp == NULL) {
\r
508 msg->conn->err = ERR_MEM;
\r
509 sys_mbox_post(msg->conn->mbox, NULL);
\r
512 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
514 #endif /* LWIP_UDP */
\r
517 msg->conn->pcb.tcp = tcp_new();
\r
518 if (msg->conn->pcb.tcp == NULL) {
\r
519 msg->conn->err = ERR_MEM;
\r
520 sys_mbox_post(msg->conn->mbox, NULL);
\r
528 switch (msg->conn->type) {
\r
531 raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
\r
532 sys_mbox_post(msg->conn->mbox, NULL);
\r
536 case NETCONN_UDPLITE:
\r
538 case NETCONN_UDPNOCHKSUM:
\r
541 udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
\r
542 sys_mbox_post(msg->conn->mbox, NULL);
\r
547 /* tcp_arg(msg->conn->pcb.tcp, msg->conn);*/
\r
548 setup_tcp(msg->conn);
\r
549 tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port,
\r
551 /*tcp_output(msg->conn->pcb.tcp);*/
\r
560 do_disconnect(struct api_msg_msg *msg)
\r
563 switch (msg->conn->type) {
\r
566 /* Do nothing as connecting is only a helper for upper lwip layers */
\r
570 case NETCONN_UDPLITE:
\r
572 case NETCONN_UDPNOCHKSUM:
\r
575 udp_disconnect(msg->conn->pcb.udp);
\r
581 sys_mbox_post(msg->conn->mbox, NULL);
\r
586 do_listen(struct api_msg_msg *msg)
\r
588 if (msg->conn->pcb.tcp != NULL) {
\r
589 switch (msg->conn->type) {
\r
592 LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: listen RAW: cannot listen for RAW.\n"));
\r
596 case NETCONN_UDPLITE:
\r
598 case NETCONN_UDPNOCHKSUM:
\r
601 LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: listen UDP: cannot listen for UDP.\n"));
\r
603 #endif /* LWIP_UDP */
\r
606 msg->conn->pcb.tcp = tcp_listen(msg->conn->pcb.tcp);
\r
607 if (msg->conn->pcb.tcp == NULL) {
\r
608 msg->conn->err = ERR_MEM;
\r
610 if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
\r
611 msg->conn->acceptmbox = sys_mbox_new();
\r
612 if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
\r
613 msg->conn->err = ERR_MEM;
\r
617 tcp_arg(msg->conn->pcb.tcp, msg->conn);
\r
618 tcp_accept(msg->conn->pcb.tcp, accept_function);
\r
625 sys_mbox_post(msg->conn->mbox, NULL);
\r
629 do_accept(struct api_msg_msg *msg)
\r
631 if (msg->conn->pcb.tcp != NULL) {
\r
632 switch (msg->conn->type) {
\r
635 LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: accept RAW: cannot accept for RAW.\n"));
\r
639 case NETCONN_UDPLITE:
\r
641 case NETCONN_UDPNOCHKSUM:
\r
644 LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: accept UDP: cannot accept for UDP.\n"));
\r
646 #endif /* LWIP_UDP */
\r
654 do_send(struct api_msg_msg *msg)
\r
656 if (msg->conn->pcb.tcp != NULL) {
\r
657 switch (msg->conn->type) {
\r
660 raw_send(msg->conn->pcb.raw, msg->msg.p);
\r
664 case NETCONN_UDPLITE:
\r
666 case NETCONN_UDPNOCHKSUM:
\r
669 udp_send(msg->conn->pcb.udp, msg->msg.p);
\r
671 #endif /* LWIP_UDP */
\r
676 sys_mbox_post(msg->conn->mbox, NULL);
\r
680 do_recv(struct api_msg_msg *msg)
\r
683 if (msg->conn->pcb.tcp != NULL) {
\r
684 if (msg->conn->type == NETCONN_TCP) {
\r
685 tcp_recved(msg->conn->pcb.tcp, msg->msg.len);
\r
689 sys_mbox_post(msg->conn->mbox, NULL);
\r
693 do_write(struct api_msg_msg *msg)
\r
698 if (msg->conn->pcb.tcp != NULL) {
\r
699 switch (msg->conn->type) {
\r
702 msg->conn->err = ERR_VAL;
\r
706 case NETCONN_UDPLITE:
\r
708 case NETCONN_UDPNOCHKSUM:
\r
711 msg->conn->err = ERR_VAL;
\r
713 #endif /* LWIP_UDP */
\r
716 err = tcp_write(msg->conn->pcb.tcp, msg->msg.w.dataptr,
\r
717 msg->msg.w.len, msg->msg.w.copy);
\r
718 /* This is the Nagle algorithm: inhibit the sending of new TCP
\r
719 segments when new outgoing data arrives from the user if any
\r
720 previously transmitted data on the connection remains
\r
722 if(err == ERR_OK && (msg->conn->pcb.tcp->unacked == NULL ||
\r
723 (msg->conn->pcb.tcp->flags & TF_NODELAY) ||
\r
724 (msg->conn->pcb.tcp->snd_queuelen) > 1)) {
\r
725 tcp_output(msg->conn->pcb.tcp);
\r
727 msg->conn->err = err;
\r
728 if (msg->conn->callback)
\r
731 if (tcp_sndbuf(msg->conn->pcb.tcp) <= TCP_SNDLOWAT)
\r
732 (*msg->conn->callback)(msg->conn, NETCONN_EVT_SENDMINUS, msg->msg.w.len);
\r
739 sys_mbox_post(msg->conn->mbox, NULL);
\r
743 do_close(struct api_msg_msg *msg)
\r
749 if (msg->conn->pcb.tcp != NULL) {
\r
750 switch (msg->conn->type) {
\r
756 case NETCONN_UDPLITE:
\r
758 case NETCONN_UDPNOCHKSUM:
\r
762 #endif /* LWIP_UDP */
\r
765 if (msg->conn->pcb.tcp->state == LISTEN) {
\r
766 err = tcp_close(msg->conn->pcb.tcp);
\r
768 else if (msg->conn->pcb.tcp->state == CLOSE_WAIT) {
\r
769 err = tcp_output(msg->conn->pcb.tcp);
\r
771 msg->conn->err = err;
\r
777 sys_mbox_post(msg->conn->mbox, NULL);
\r
780 typedef void (* api_msg_decode)(struct api_msg_msg *msg);
\r
781 static api_msg_decode decode[API_MSG_MAX] = {
\r
795 api_msg_input(struct api_msg *msg)
\r
797 decode[msg->type](&(msg->msg));
\r
801 api_msg_post(struct api_msg *msg)
\r