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
87 if (conn->recvmbox != SYS_MBOX_NULL) {
\r
88 buf = memp_malloc(MEMP_NETBUF);
\r
95 buf->fromaddr = addr;
\r
96 buf->fromport = port;
\r
99 conn->recv_avail += p->tot_len;
\r
100 /* Register event with callback */
\r
101 if (conn->callback)
\r
102 (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
\r
103 sys_mbox_post(conn->recvmbox, buf);
\r
106 #endif /* LWIP_UDP */
\r
110 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
\r
112 struct netconn *conn;
\r
119 if (conn == NULL) {
\r
124 if (conn->recvmbox != SYS_MBOX_NULL) {
\r
129 conn->recv_avail += len;
\r
133 /* Register event with callback */
\r
134 if (conn->callback)
\r
135 (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, len);
\r
136 sys_mbox_post(conn->recvmbox, p);
\r
143 poll_tcp(void *arg, struct tcp_pcb *pcb)
\r
145 struct netconn *conn;
\r
150 if (conn != NULL &&
\r
151 (conn->state == NETCONN_WRITE || conn->state == NETCONN_CLOSE) &&
\r
152 conn->sem != SYS_SEM_NULL) {
\r
153 sys_sem_signal(conn->sem);
\r
159 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
\r
161 struct netconn *conn;
\r
166 if (conn != NULL && conn->sem != SYS_SEM_NULL) {
\r
167 sys_sem_signal(conn->sem);
\r
170 if (conn && conn->callback)
\r
171 if (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)
\r
172 (*conn->callback)(conn, NETCONN_EVT_SENDPLUS, len);
\r
178 err_tcp(void *arg, err_t err)
\r
180 struct netconn *conn;
\r
184 conn->pcb.tcp = NULL;
\r
188 if (conn->recvmbox != SYS_MBOX_NULL) {
\r
189 /* Register event with callback */
\r
190 if (conn->callback)
\r
191 (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
\r
192 sys_mbox_post(conn->recvmbox, NULL);
\r
194 if (conn->mbox != SYS_MBOX_NULL) {
\r
195 sys_mbox_post(conn->mbox, NULL);
\r
197 if (conn->acceptmbox != SYS_MBOX_NULL) {
\r
198 /* Register event with callback */
\r
199 if (conn->callback)
\r
200 (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
\r
201 sys_mbox_post(conn->acceptmbox, NULL);
\r
203 if (conn->sem != SYS_SEM_NULL) {
\r
204 sys_sem_signal(conn->sem);
\r
209 setup_tcp(struct netconn *conn)
\r
211 struct tcp_pcb *pcb;
\r
213 pcb = conn->pcb.tcp;
\r
214 tcp_arg(pcb, conn);
\r
215 tcp_recv(pcb, recv_tcp);
\r
216 tcp_sent(pcb, sent_tcp);
\r
217 tcp_poll(pcb, poll_tcp, 4);
\r
218 tcp_err(pcb, err_tcp);
\r
222 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
\r
225 struct netconn *newconn;
\r
226 struct netconn *conn;
\r
230 tcp_debug_print_state(newpcb->state);
\r
231 #endif /* TCP_DEBUG */
\r
232 #endif /* API_MSG_DEBUG */
\r
233 conn = (struct netconn *)arg;
\r
234 mbox = conn->acceptmbox;
\r
235 newconn = memp_malloc(MEMP_NETCONN);
\r
236 if (newconn == NULL) {
\r
239 newconn->type = NETCONN_TCP;
\r
240 newconn->pcb.tcp = newpcb;
\r
241 setup_tcp(newconn);
\r
242 newconn->recvmbox = sys_mbox_new();
\r
243 if (newconn->recvmbox == SYS_MBOX_NULL) {
\r
244 memp_free(MEMP_NETCONN, newconn);
\r
247 newconn->mbox = sys_mbox_new();
\r
248 if (newconn->mbox == SYS_MBOX_NULL) {
\r
249 sys_mbox_free(newconn->recvmbox);
\r
250 memp_free(MEMP_NETCONN, newconn);
\r
253 newconn->sem = sys_sem_new(0);
\r
254 if (newconn->sem == SYS_SEM_NULL) {
\r
255 sys_mbox_free(newconn->recvmbox);
\r
256 sys_mbox_free(newconn->mbox);
\r
257 memp_free(MEMP_NETCONN, newconn);
\r
260 newconn->acceptmbox = SYS_MBOX_NULL;
\r
261 newconn->err = err;
\r
262 /* Register event with callback */
\r
263 if (conn->callback)
\r
265 (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
\r
266 /* We have to set the callback here even though
\r
267 * the new socket is unknown. Mark the socket as -1. */
\r
268 newconn->callback = conn->callback;
\r
269 newconn->socket = -1;
\r
272 sys_mbox_post(mbox, newconn);
\r
275 #endif /* LWIP_TCP */
\r
278 do_newconn(struct api_msg_msg *msg)
\r
280 if(msg->conn->pcb.tcp != NULL) {
\r
281 /* This "new" connection already has a PCB allocated. */
\r
282 /* Is this an error condition? Should it be deleted?
\r
283 We currently just are happy and return. */
\r
284 sys_mbox_post(msg->conn->mbox, NULL);
\r
288 msg->conn->err = ERR_OK;
\r
290 /* Allocate a PCB for this connection */
\r
291 switch(msg->conn->type) {
\r
294 msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field */
\r
295 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
\r
299 case NETCONN_UDPLITE:
\r
300 msg->conn->pcb.udp = udp_new();
\r
301 if(msg->conn->pcb.udp == NULL) {
\r
302 msg->conn->err = ERR_MEM;
\r
305 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
\r
306 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
308 case NETCONN_UDPNOCHKSUM:
\r
309 msg->conn->pcb.udp = udp_new();
\r
310 if(msg->conn->pcb.udp == NULL) {
\r
311 msg->conn->err = ERR_MEM;
\r
314 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
\r
315 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
318 msg->conn->pcb.udp = udp_new();
\r
319 if(msg->conn->pcb.udp == NULL) {
\r
320 msg->conn->err = ERR_MEM;
\r
323 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
325 #endif /* LWIP_UDP */
\r
328 msg->conn->pcb.tcp = tcp_new();
\r
329 if(msg->conn->pcb.tcp == NULL) {
\r
330 msg->conn->err = ERR_MEM;
\r
333 setup_tcp(msg->conn);
\r
339 sys_mbox_post(msg->conn->mbox, NULL);
\r
344 do_delconn(struct api_msg_msg *msg)
\r
346 if (msg->conn->pcb.tcp != NULL) {
\r
347 switch (msg->conn->type) {
\r
350 raw_remove(msg->conn->pcb.raw);
\r
354 case NETCONN_UDPLITE:
\r
356 case NETCONN_UDPNOCHKSUM:
\r
359 msg->conn->pcb.udp->recv_arg = NULL;
\r
360 udp_remove(msg->conn->pcb.udp);
\r
362 #endif /* LWIP_UDP */
\r
365 if (msg->conn->pcb.tcp->state == LISTEN) {
\r
366 tcp_arg(msg->conn->pcb.tcp, NULL);
\r
367 tcp_accept(msg->conn->pcb.tcp, NULL);
\r
368 tcp_close(msg->conn->pcb.tcp);
\r
370 tcp_arg(msg->conn->pcb.tcp, NULL);
\r
371 tcp_sent(msg->conn->pcb.tcp, NULL);
\r
372 tcp_recv(msg->conn->pcb.tcp, NULL);
\r
373 tcp_poll(msg->conn->pcb.tcp, NULL, 0);
\r
374 tcp_err(msg->conn->pcb.tcp, NULL);
\r
375 if (tcp_close(msg->conn->pcb.tcp) != ERR_OK) {
\r
376 tcp_abort(msg->conn->pcb.tcp);
\r
384 /* Trigger select() in socket layer */
\r
385 if (msg->conn->callback)
\r
387 (*msg->conn->callback)(msg->conn, NETCONN_EVT_RCVPLUS, 0);
\r
388 (*msg->conn->callback)(msg->conn, NETCONN_EVT_SENDPLUS, 0);
\r
391 if (msg->conn->mbox != SYS_MBOX_NULL) {
\r
392 sys_mbox_post(msg->conn->mbox, NULL);
\r
397 do_bind(struct api_msg_msg *msg)
\r
399 if (msg->conn->pcb.tcp == NULL) {
\r
400 switch (msg->conn->type) {
\r
403 msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */
\r
404 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
\r
408 case NETCONN_UDPLITE:
\r
409 msg->conn->pcb.udp = udp_new();
\r
410 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
\r
411 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
413 case NETCONN_UDPNOCHKSUM:
\r
414 msg->conn->pcb.udp = udp_new();
\r
415 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
\r
416 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
419 msg->conn->pcb.udp = udp_new();
\r
420 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
422 #endif /* LWIP_UDP */
\r
425 msg->conn->pcb.tcp = tcp_new();
\r
426 setup_tcp(msg->conn);
\r
427 #endif /* LWIP_TCP */
\r
432 switch (msg->conn->type) {
\r
435 msg->conn->err = raw_bind(msg->conn->pcb.raw,msg->msg.bc.ipaddr);
\r
439 case NETCONN_UDPLITE:
\r
441 case NETCONN_UDPNOCHKSUM:
\r
444 msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
\r
446 #endif /* LWIP_UDP */
\r
449 msg->conn->err = tcp_bind(msg->conn->pcb.tcp,
\r
450 msg->msg.bc.ipaddr, msg->msg.bc.port);
\r
451 #endif /* LWIP_TCP */
\r
455 sys_mbox_post(msg->conn->mbox, NULL);
\r
460 do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
\r
462 struct netconn *conn;
\r
468 if (conn == NULL) {
\r
473 if (conn->type == NETCONN_TCP && err == ERR_OK) {
\r
476 sys_mbox_post(conn->mbox, NULL);
\r
482 do_connect(struct api_msg_msg *msg)
\r
484 if (msg->conn->pcb.tcp == NULL) {
\r
485 switch (msg->conn->type) {
\r
488 msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */
\r
489 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
\r
493 case NETCONN_UDPLITE:
\r
494 msg->conn->pcb.udp = udp_new();
\r
495 if (msg->conn->pcb.udp == NULL) {
\r
496 msg->conn->err = ERR_MEM;
\r
497 sys_mbox_post(msg->conn->mbox, NULL);
\r
500 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
\r
501 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
503 case NETCONN_UDPNOCHKSUM:
\r
504 msg->conn->pcb.udp = udp_new();
\r
505 if (msg->conn->pcb.udp == NULL) {
\r
506 msg->conn->err = ERR_MEM;
\r
507 sys_mbox_post(msg->conn->mbox, NULL);
\r
510 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
\r
511 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
514 msg->conn->pcb.udp = udp_new();
\r
515 if (msg->conn->pcb.udp == NULL) {
\r
516 msg->conn->err = ERR_MEM;
\r
517 sys_mbox_post(msg->conn->mbox, NULL);
\r
520 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
\r
522 #endif /* LWIP_UDP */
\r
525 msg->conn->pcb.tcp = tcp_new();
\r
526 if (msg->conn->pcb.tcp == NULL) {
\r
527 msg->conn->err = ERR_MEM;
\r
528 sys_mbox_post(msg->conn->mbox, NULL);
\r
536 switch (msg->conn->type) {
\r
539 raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
\r
540 sys_mbox_post(msg->conn->mbox, NULL);
\r
544 case NETCONN_UDPLITE:
\r
546 case NETCONN_UDPNOCHKSUM:
\r
549 udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
\r
550 sys_mbox_post(msg->conn->mbox, NULL);
\r
555 /* tcp_arg(msg->conn->pcb.tcp, msg->conn);*/
\r
556 setup_tcp(msg->conn);
\r
557 tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port,
\r
559 /*tcp_output(msg->conn->pcb.tcp);*/
\r
568 do_disconnect(struct api_msg_msg *msg)
\r
571 switch (msg->conn->type) {
\r
574 /* Do nothing as connecting is only a helper for upper lwip layers */
\r
578 case NETCONN_UDPLITE:
\r
580 case NETCONN_UDPNOCHKSUM:
\r
583 udp_disconnect(msg->conn->pcb.udp);
\r
589 sys_mbox_post(msg->conn->mbox, NULL);
\r
594 do_listen(struct api_msg_msg *msg)
\r
596 if (msg->conn->pcb.tcp != NULL) {
\r
597 switch (msg->conn->type) {
\r
600 LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: listen RAW: cannot listen for RAW.\n"));
\r
604 case NETCONN_UDPLITE:
\r
606 case NETCONN_UDPNOCHKSUM:
\r
609 LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: listen UDP: cannot listen for UDP.\n"));
\r
611 #endif /* LWIP_UDP */
\r
614 msg->conn->pcb.tcp = tcp_listen(msg->conn->pcb.tcp);
\r
615 if (msg->conn->pcb.tcp == NULL) {
\r
616 msg->conn->err = ERR_MEM;
\r
618 if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
\r
619 msg->conn->acceptmbox = sys_mbox_new();
\r
620 if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
\r
621 msg->conn->err = ERR_MEM;
\r
625 tcp_arg(msg->conn->pcb.tcp, msg->conn);
\r
626 tcp_accept(msg->conn->pcb.tcp, accept_function);
\r
633 sys_mbox_post(msg->conn->mbox, NULL);
\r
637 do_accept(struct api_msg_msg *msg)
\r
639 if (msg->conn->pcb.tcp != NULL) {
\r
640 switch (msg->conn->type) {
\r
643 LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: accept RAW: cannot accept for RAW.\n"));
\r
647 case NETCONN_UDPLITE:
\r
649 case NETCONN_UDPNOCHKSUM:
\r
652 LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: accept UDP: cannot accept for UDP.\n"));
\r
654 #endif /* LWIP_UDP */
\r
662 do_send(struct api_msg_msg *msg)
\r
664 if (msg->conn->pcb.tcp != NULL) {
\r
665 switch (msg->conn->type) {
\r
668 raw_send(msg->conn->pcb.raw, msg->msg.p);
\r
672 case NETCONN_UDPLITE:
\r
674 case NETCONN_UDPNOCHKSUM:
\r
677 udp_send(msg->conn->pcb.udp, msg->msg.p);
\r
679 #endif /* LWIP_UDP */
\r
684 sys_mbox_post(msg->conn->mbox, NULL);
\r
688 do_recv(struct api_msg_msg *msg)
\r
691 if (msg->conn->pcb.tcp != NULL) {
\r
692 if (msg->conn->type == NETCONN_TCP) {
\r
693 tcp_recved(msg->conn->pcb.tcp, msg->msg.len);
\r
697 sys_mbox_post(msg->conn->mbox, NULL);
\r
701 do_write(struct api_msg_msg *msg)
\r
706 if (msg->conn->pcb.tcp != NULL) {
\r
707 switch (msg->conn->type) {
\r
710 msg->conn->err = ERR_VAL;
\r
714 case NETCONN_UDPLITE:
\r
716 case NETCONN_UDPNOCHKSUM:
\r
719 msg->conn->err = ERR_VAL;
\r
721 #endif /* LWIP_UDP */
\r
724 err = tcp_write(msg->conn->pcb.tcp, msg->msg.w.dataptr,
\r
725 msg->msg.w.len, msg->msg.w.copy);
\r
726 /* This is the Nagle algorithm: inhibit the sending of new TCP
\r
727 segments when new outgoing data arrives from the user if any
\r
728 previously transmitted data on the connection remains
\r
730 if(err == ERR_OK && (msg->conn->pcb.tcp->unacked == NULL || (msg->conn->pcb.tcp->flags & TF_NODELAY)) ) {
\r
731 tcp_output(msg->conn->pcb.tcp);
\r
733 msg->conn->err = err;
\r
734 if (msg->conn->callback)
\r
737 if (tcp_sndbuf(msg->conn->pcb.tcp) <= TCP_SNDLOWAT)
\r
738 (*msg->conn->callback)(msg->conn, NETCONN_EVT_SENDMINUS, msg->msg.w.len);
\r
745 sys_mbox_post(msg->conn->mbox, NULL);
\r
749 do_close(struct api_msg_msg *msg)
\r
755 if (msg->conn->pcb.tcp != NULL) {
\r
756 switch (msg->conn->type) {
\r
762 case NETCONN_UDPLITE:
\r
764 case NETCONN_UDPNOCHKSUM:
\r
768 #endif /* LWIP_UDP */
\r
771 if (msg->conn->pcb.tcp->state == LISTEN) {
\r
772 err = tcp_close(msg->conn->pcb.tcp);
\r
774 msg->conn->err = err;
\r
780 sys_mbox_post(msg->conn->mbox, NULL);
\r
783 typedef void (* api_msg_decode)(struct api_msg_msg *msg);
\r
784 static api_msg_decode decode[API_MSG_MAX] = {
\r
798 api_msg_input(struct api_msg *msg)
\r
800 decode[msg->type](&(msg->msg));
\r
804 api_msg_post(struct api_msg *msg)
\r