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