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/priv/api_msg.h" 44 45#include "lwip/ip.h" 46#include "lwip/ip_addr.h" 47#include "lwip/udp.h" 48#include "lwip/tcp.h" 49#include "lwip/raw.h" 50 51#include "lwip/memp.h" 52#include "lwip/igmp.h" 53#include "lwip/dns.h" 54#include "lwip/mld6.h" 55#include "lwip/priv/tcpip_priv.h" 56 57#include <string.h> 58 59/* netconns are polled once per second (e.g. continue write on memory error) */ 60#define NETCONN_TCP_POLL_INTERVAL 2 61 62#define SET_NONBLOCKING_CONNECT(conn, val) do { if (val) { \ 63 netconn_set_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); \ 64} else { \ 65 netconn_clear_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); }} while(0) 66#define IN_NONBLOCKING_CONNECT(conn) netconn_is_flag_set(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT) 67 68#if LWIP_NETCONN_FULLDUPLEX 69#define NETCONN_MBOX_VALID(conn, mbox) (sys_mbox_valid(mbox) && ((conn->flags & NETCONN_FLAG_MBOXINVALID) == 0)) 70#else 71#define NETCONN_MBOX_VALID(conn, mbox) sys_mbox_valid(mbox) 72#endif 73 74/* forward declarations */ 75#if LWIP_TCP 76#if LWIP_TCPIP_CORE_LOCKING 77#define WRITE_DELAYED , 1 78#define WRITE_DELAYED_PARAM , u8_t delayed 79#else /* LWIP_TCPIP_CORE_LOCKING */ 80#define WRITE_DELAYED 81#define WRITE_DELAYED_PARAM 82#endif /* LWIP_TCPIP_CORE_LOCKING */ 83static err_t lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM); 84static err_t lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM); 85#endif 86 87static void netconn_drain(struct netconn *conn); 88 89#if LWIP_TCPIP_CORE_LOCKING 90#define TCPIP_APIMSG_ACK(m) 91#else /* LWIP_TCPIP_CORE_LOCKING */ 92#define TCPIP_APIMSG_ACK(m) do { sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0) 93#endif /* LWIP_TCPIP_CORE_LOCKING */ 94 95#if LWIP_NETCONN_FULLDUPLEX 96const u8_t netconn_deleted = 0; 97 98int 99lwip_netconn_is_deallocated_msg(void *msg) 100{ 101 if (msg == &netconn_deleted) { 102 return 1; 103 } 104 return 0; 105} 106#endif /* LWIP_NETCONN_FULLDUPLEX */ 107 108#if LWIP_TCP 109const u8_t netconn_aborted = 0; 110const u8_t netconn_reset = 0; 111const u8_t netconn_closed = 0; 112 113/** Translate an error to a unique void* passed via an mbox */ 114static void * 115lwip_netconn_err_to_msg(err_t err) 116{ 117 switch (err) { 118 case ERR_ABRT: 119 return LWIP_CONST_CAST(void *, &netconn_aborted); 120 case ERR_RST: 121 return LWIP_CONST_CAST(void *, &netconn_reset); 122 case ERR_CLSD: 123 return LWIP_CONST_CAST(void *, &netconn_closed); 124 default: 125 LWIP_ASSERT("unhandled error", err == ERR_OK); 126 return NULL; 127 } 128} 129 130int 131lwip_netconn_is_err_msg(void *msg, err_t *err) 132{ 133 LWIP_ASSERT("err != NULL", err != NULL); 134 135 if (msg == &netconn_aborted) { 136 *err = ERR_ABRT; 137 return 1; 138 } else if (msg == &netconn_reset) { 139 *err = ERR_RST; 140 return 1; 141 } else if (msg == &netconn_closed) { 142 *err = ERR_CLSD; 143 return 1; 144 } 145 return 0; 146} 147#endif /* LWIP_TCP */ 148 149 150#if LWIP_RAW 151/** 152 * Receive callback function for RAW netconns. 153 * Doesn't 'eat' the packet, only copies it and sends it to 154 * conn->recvmbox 155 * 156 * @see raw.h (struct raw_pcb.recv) for parameters and return value 157 */ 158static u8_t 159recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, 160 const ip_addr_t *addr) 161{ 162 struct pbuf *q; 163 struct netbuf *buf; 164 struct netconn *conn; 165 166 LWIP_UNUSED_ARG(addr); 167 conn = (struct netconn *)arg; 168 169 if ((conn != NULL) && NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { 170#if LWIP_SO_RCVBUF 171 int recv_avail; 172 SYS_ARCH_GET(conn->recv_avail, recv_avail); 173 if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) { 174 return 0; 175 } 176#endif /* LWIP_SO_RCVBUF */ 177 /* copy the whole packet into new pbufs */ 178 q = pbuf_clone(PBUF_RAW, PBUF_RAM, p); 179 if (q != NULL) { 180 u16_t len; 181 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 182 if (buf == NULL) { 183 pbuf_free(q); 184 return 0; 185 } 186 187 buf->p = q; 188 buf->ptr = q; 189 ip_addr_copy(buf->addr, *ip_current_src_addr()); 190 buf->port = pcb->protocol; 191 192 len = q->tot_len; 193 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { 194 netbuf_delete(buf); 195 return 0; 196 } else { 197#if LWIP_SO_RCVBUF 198 SYS_ARCH_INC(conn->recv_avail, len); 199#endif /* LWIP_SO_RCVBUF */ 200 /* Register event with callback */ 201 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 202 } 203 } 204 } 205 206 return 0; /* do not eat the packet */ 207} 208#endif /* LWIP_RAW*/ 209 210#if LWIP_UDP 211/** 212 * Receive callback function for UDP netconns. 213 * Posts the packet to conn->recvmbox or deletes it on memory error. 214 * 215 * @see udp.h (struct udp_pcb.recv) for parameters 216 */ 217static void 218recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, 219 const ip_addr_t *addr, u16_t port) 220{ 221 struct netbuf *buf; 222 struct netconn *conn; 223 u16_t len; 224#if LWIP_SO_RCVBUF 225 int recv_avail; 226#endif /* LWIP_SO_RCVBUF */ 227 228 LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ 229 LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); 230 LWIP_ASSERT("recv_udp must have an argument", arg != NULL); 231 conn = (struct netconn *)arg; 232 233 if (conn == NULL) { 234 pbuf_free(p); 235 return; 236 } 237 238 LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); 239 240#if LWIP_SO_RCVBUF 241 SYS_ARCH_GET(conn->recv_avail, recv_avail); 242 if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox) || 243 ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { 244#else /* LWIP_SO_RCVBUF */ 245 if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { 246#endif /* LWIP_SO_RCVBUF */ 247 pbuf_free(p); 248 return; 249 } 250 251 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 252 if (buf == NULL) { 253 pbuf_free(p); 254 return; 255 } else { 256 buf->p = p; 257 buf->ptr = p; 258 ip_addr_set(&buf->addr, addr); 259 buf->port = port; 260#if LWIP_NETBUF_RECVINFO 261 if (conn->flags & NETCONN_FLAG_PKTINFO) { 262 /* get the UDP header - always in the first pbuf, ensured by udp_input */ 263 const struct udp_hdr *udphdr = (const struct udp_hdr *)ip_next_header_ptr(); 264 buf->flags = NETBUF_FLAG_DESTADDR; 265 ip_addr_set(&buf->toaddr, ip_current_dest_addr()); 266 buf->toport_chksum = udphdr->dest; 267 } 268#endif /* LWIP_NETBUF_RECVINFO */ 269 } 270 271 len = p->tot_len; 272 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { 273 netbuf_delete(buf); 274 return; 275 } else { 276#if LWIP_SO_RCVBUF 277 SYS_ARCH_INC(conn->recv_avail, len); 278#endif /* LWIP_SO_RCVBUF */ 279 /* Register event with callback */ 280 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 281 } 282} 283#endif /* LWIP_UDP */ 284 285#if LWIP_TCP 286/** 287 * Receive callback function for TCP netconns. 288 * Posts the packet to conn->recvmbox, but doesn't delete it on errors. 289 * 290 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value 291 */ 292static err_t 293recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) 294{ 295 struct netconn *conn; 296 u16_t len; 297 void *msg; 298 299 LWIP_UNUSED_ARG(pcb); 300 LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); 301 LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); 302 LWIP_ASSERT("err != ERR_OK unhandled", err == ERR_OK); 303 LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */ 304 conn = (struct netconn *)arg; 305 306 if (conn == NULL) { 307 return ERR_VAL; 308 } 309 LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); 310 311 if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { 312 /* recvmbox already deleted */ 313 if (p != NULL) { 314 tcp_recved(pcb, p->tot_len); 315 pbuf_free(p); 316 } 317 return ERR_OK; 318 } 319 /* Unlike for UDP or RAW pcbs, don't check for available space 320 using recv_avail since that could break the connection 321 (data is already ACKed) */ 322 323 if (p != NULL) { 324 msg = p; 325 len = p->tot_len; 326 } else { 327 msg = LWIP_CONST_CAST(void *, &netconn_closed); 328 len = 0; 329 } 330 331 if (sys_mbox_trypost(&conn->recvmbox, msg) != ERR_OK) { 332 /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */ 333 return ERR_MEM; 334 } else { 335#if LWIP_SO_RCVBUF 336 SYS_ARCH_INC(conn->recv_avail, len); 337#endif /* LWIP_SO_RCVBUF */ 338 /* Register event with callback */ 339 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 340 } 341 342 return ERR_OK; 343} 344 345/** 346 * Poll callback function for TCP netconns. 347 * Wakes up an application thread that waits for a connection to close 348 * or data to be sent. The application thread then takes the 349 * appropriate action to go on. 350 * 351 * Signals the conn->sem. 352 * netconn_close waits for conn->sem if closing failed. 353 * 354 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value 355 */ 356static err_t 357poll_tcp(void *arg, struct tcp_pcb *pcb) 358{ 359 struct netconn *conn = (struct netconn *)arg; 360 361 LWIP_UNUSED_ARG(pcb); 362 LWIP_ASSERT("conn != NULL", (conn != NULL)); 363 364 if (conn->state == NETCONN_WRITE) { 365 lwip_netconn_do_writemore(conn WRITE_DELAYED); 366 } else if (conn->state == NETCONN_CLOSE) { 367#if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER 368 if (conn->current_msg && conn->current_msg->msg.sd.polls_left) { 369 conn->current_msg->msg.sd.polls_left--; 370 } 371#endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */ 372 lwip_netconn_do_close_internal(conn WRITE_DELAYED); 373 } 374 /* @todo: implement connect timeout here? */ 375 376 /* Did a nonblocking write fail before? Then check available write-space. */ 377 if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) { 378 /* If the queued byte- or pbuf-count drops below the configured low-water limit, 379 let select mark this pcb as writable again. */ 380 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && 381 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { 382 netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE); 383 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 384 } 385 } 386 387 return ERR_OK; 388} 389 390#if LWIP_LOWPOWER 391/* check wether need to poll tcp */ 392u8_t 393poll_tcp_needed(void *arg, struct tcp_pcb *pcb) 394{ 395 struct netconn *conn = (struct netconn *)arg; 396 u8_t ret = 0; 397 398 LWIP_UNUSED_ARG(pcb); 399 if (conn == NULL) { 400 return 0; 401 } 402 if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) { 403 ret = 1; 404 } 405 406 /* Did a nonblocking write fail before? Then check available write-space. */ 407 if ((conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) != 0) { 408 /* If the queued byte- or pbuf-count drops below the configured low-water limit, 409 let select mark this pcb as writable again. */ 410 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && 411 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { 412 ret = 1; 413 } 414 } 415 return ret; 416} 417#endif /* LWIP_LOWPOWER */ 418 419/** 420 * Sent callback function for TCP netconns. 421 * Signals the conn->sem and calls API_EVENT. 422 * netconn_write waits for conn->sem if send buffer is low. 423 * 424 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value 425 */ 426static err_t 427sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) 428{ 429 struct netconn *conn = (struct netconn *)arg; 430 431 LWIP_UNUSED_ARG(pcb); 432 LWIP_ASSERT("conn != NULL", (conn != NULL)); 433 434 if (conn) { 435 if (conn->state == NETCONN_WRITE) { 436 lwip_netconn_do_writemore(conn WRITE_DELAYED); 437 } else if (conn->state == NETCONN_CLOSE) { 438 lwip_netconn_do_close_internal(conn WRITE_DELAYED); 439 } 440 441 /* If the queued byte- or pbuf-count drops below the configured low-water limit, 442 let select mark this pcb as writable again. */ 443 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && 444 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { 445 netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE); 446 API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); 447 } 448 } 449 450 return ERR_OK; 451} 452 453/** 454 * Error callback function for TCP netconns. 455 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. 456 * The application thread has then to decide what to do. 457 * 458 * @see tcp.h (struct tcp_pcb.err) for parameters 459 */ 460static void 461err_tcp(void *arg, err_t err) 462{ 463 struct netconn *conn; 464 enum netconn_state old_state; 465 void *mbox_msg; 466 SYS_ARCH_DECL_PROTECT(lev); 467 468 conn = (struct netconn *)arg; 469 LWIP_ASSERT("conn != NULL", (conn != NULL)); 470 471 SYS_ARCH_PROTECT(lev); 472 473 /* when err is called, the pcb is deallocated, so delete the reference */ 474 conn->pcb.tcp = NULL; 475 /* store pending error */ 476 conn->pending_err = err; 477 /* prevent application threads from blocking on 'recvmbox'/'acceptmbox' */ 478 conn->flags |= NETCONN_FLAG_MBOXCLOSED; 479 480 /* reset conn->state now before waking up other threads */ 481 old_state = conn->state; 482 conn->state = NETCONN_NONE; 483 484 SYS_ARCH_UNPROTECT(lev); 485 486 /* Notify the user layer about a connection error. Used to signal select. */ 487 API_EVENT(conn, NETCONN_EVT_ERROR, 0); 488 /* Try to release selects pending on 'read' or 'write', too. 489 They will get an error if they actually try to read or write. */ 490 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 491 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 492 493 mbox_msg = lwip_netconn_err_to_msg(err); 494 /* pass error message to recvmbox to wake up pending recv */ 495 if (NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { 496 /* use trypost to prevent deadlock */ 497 sys_mbox_trypost(&conn->recvmbox, mbox_msg); 498 } 499 /* pass error message to acceptmbox to wake up pending accept */ 500 if (NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) { 501 /* use trypost to preven deadlock */ 502 sys_mbox_trypost(&conn->acceptmbox, mbox_msg); 503 } 504 505 if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || 506 (old_state == NETCONN_CONNECT)) { 507 /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary 508 since the pcb has already been deleted! */ 509 int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn); 510 SET_NONBLOCKING_CONNECT(conn, 0); 511 512 if (!was_nonblocking_connect) { 513 sys_sem_t *op_completed_sem; 514 /* set error return code */ 515 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 516 if (old_state == NETCONN_CLOSE) { 517 /* let close succeed: the connection is closed after all... */ 518 conn->current_msg->err = ERR_OK; 519 } else { 520 /* Write and connect fail */ 521 conn->current_msg->err = err; 522 } 523 op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 524 LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem)); 525 conn->current_msg = NULL; 526 /* wake up the waiting task */ 527 sys_sem_signal(op_completed_sem); 528 } else { 529 /* @todo: test what happens for error on nonblocking connect */ 530 } 531 } else { 532 LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL); 533 } 534} 535 536/** 537 * Setup a tcp_pcb with the correct callback function pointers 538 * and their arguments. 539 * 540 * @param conn the TCP netconn to setup 541 */ 542static void 543setup_tcp(struct netconn *conn) 544{ 545 struct tcp_pcb *pcb; 546 547 pcb = conn->pcb.tcp; 548 tcp_arg(pcb, conn); 549 tcp_recv(pcb, recv_tcp); 550 tcp_sent(pcb, sent_tcp); 551 tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL); 552 tcp_err(pcb, err_tcp); 553} 554 555/** 556 * Accept callback function for TCP netconns. 557 * Allocates a new netconn and posts that to conn->acceptmbox. 558 * 559 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value 560 */ 561static err_t 562accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) 563{ 564 struct netconn *newconn; 565 struct netconn *conn = (struct netconn *)arg; 566 567 if (conn == NULL) { 568 return ERR_VAL; 569 } 570 if (!NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) { 571 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n")); 572 return ERR_VAL; 573 } 574 575 if (newpcb == NULL) { 576 /* out-of-pcbs during connect: pass on this error to the application */ 577 if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) { 578 /* Register event with callback */ 579 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 580 } 581 return ERR_VAL; 582 } 583 LWIP_ASSERT("expect newpcb == NULL or err == ERR_OK", err == ERR_OK); 584 LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */ 585 586 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->state: %s\n", tcp_debug_state_str(newpcb->state))); 587 588 /* We have to set the callback here even though 589 * the new socket is unknown. newconn->socket is marked as -1. */ 590 newconn = netconn_alloc(conn->type, conn->callback); 591 if (newconn == NULL) { 592 /* outof netconns: pass on this error to the application */ 593 if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) { 594 /* Register event with callback */ 595 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 596 } 597 return ERR_MEM; 598 } 599 newconn->pcb.tcp = newpcb; 600 setup_tcp(newconn); 601 602 /* handle backlog counter */ 603 tcp_backlog_delayed(newpcb); 604 605 if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) { 606 /* When returning != ERR_OK, the pcb is aborted in tcp_process(), 607 so do nothing here! */ 608 /* remove all references to this netconn from the pcb */ 609 struct tcp_pcb *pcb = newconn->pcb.tcp; 610 tcp_arg(pcb, NULL); 611 tcp_recv(pcb, NULL); 612 tcp_sent(pcb, NULL); 613 tcp_poll(pcb, NULL, 0); 614 tcp_err(pcb, NULL); 615 /* remove reference from to the pcb from this netconn */ 616 newconn->pcb.tcp = NULL; 617 /* no need to drain since we know the recvmbox is empty. */ 618 sys_mbox_free(&newconn->recvmbox); 619 sys_mbox_set_invalid(&newconn->recvmbox); 620 netconn_free(newconn); 621 return ERR_MEM; 622 } else { 623 /* Register event with callback */ 624 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 625 } 626 627 return ERR_OK; 628} 629#endif /* LWIP_TCP */ 630 631/** 632 * Create a new pcb of a specific type. 633 * Called from lwip_netconn_do_newconn(). 634 * 635 * @param msg the api_msg describing the connection type 636 */ 637static void 638#ifdef LOSCFG_NET_CONTAINER 639pcb_new(struct api_msg *msg, struct net_group *group) 640#else 641pcb_new(struct api_msg *msg) 642#endif 643{ 644 enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4; 645 646 LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); 647 648#if LWIP_IPV6 && LWIP_IPV4 649 /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */ 650 if (NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) { 651 iptype = IPADDR_TYPE_ANY; 652 } 653#endif 654 655 /* Allocate a PCB for this connection */ 656 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 657#if LWIP_RAW 658 case NETCONN_RAW: 659 msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto); 660 if (msg->conn->pcb.raw != NULL) { 661#ifdef LOSCFG_NET_CONTAINER 662 set_raw_pcb_net_group(msg->conn->pcb.raw, group); 663#endif 664#if LWIP_IPV6 665 /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */ 666 if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) { 667 msg->conn->pcb.raw->chksum_reqd = 1; 668 msg->conn->pcb.raw->chksum_offset = 2; 669 } 670#endif /* LWIP_IPV6 */ 671 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); 672 } 673 break; 674#endif /* LWIP_RAW */ 675#if LWIP_UDP 676 case NETCONN_UDP: 677 msg->conn->pcb.udp = udp_new_ip_type(iptype); 678 if (msg->conn->pcb.udp != NULL) { 679#ifdef LOSCFG_NET_CONTAINER 680 set_udp_pcb_net_group(msg->conn->pcb.udp, group); 681#endif 682#if LWIP_UDPLITE 683 if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) { 684 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); 685 } 686#endif /* LWIP_UDPLITE */ 687 if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) { 688 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); 689 } 690 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); 691 } 692 break; 693#endif /* LWIP_UDP */ 694#if LWIP_TCP 695 case NETCONN_TCP: 696 msg->conn->pcb.tcp = tcp_new_ip_type(iptype); 697 if (msg->conn->pcb.tcp != NULL) { 698#ifdef LOSCFG_NET_CONTAINER 699 set_tcp_pcb_net_group(msg->conn->pcb.tcp, group); 700#endif 701 setup_tcp(msg->conn); 702 } 703 break; 704#endif /* LWIP_TCP */ 705 default: 706 /* Unsupported netconn type, e.g. protocol disabled */ 707 msg->err = ERR_VAL; 708 return; 709 } 710 if (msg->conn->pcb.ip == NULL) { 711 msg->err = ERR_MEM; 712 } 713} 714 715/** 716 * Create a new pcb of a specific type inside a netconn. 717 * Called from netconn_new_with_proto_and_callback. 718 * 719 * @param m the api_msg describing the connection type 720 */ 721void 722lwip_netconn_do_newconn(void *m) 723{ 724 struct api_msg *msg = (struct api_msg *)m; 725 726 msg->err = ERR_OK; 727 if (msg->conn->pcb.tcp == NULL) { 728#ifdef LOSCFG_NET_CONTAINER 729 pcb_new(msg, get_curr_process_net_group()); 730#else 731 pcb_new(msg); 732#endif 733 } 734 /* Else? This "new" connection already has a PCB allocated. */ 735 /* Is this an error condition? Should it be deleted? */ 736 /* We currently just are happy and return. */ 737 738 TCPIP_APIMSG_ACK(msg); 739} 740 741/** 742 * Create a new netconn (of a specific type) that has a callback function. 743 * The corresponding pcb is NOT created! 744 * 745 * @param t the type of 'connection' to create (@see enum netconn_type) 746 * @param callback a function to call on status changes (RX available, TX'ed) 747 * @return a newly allocated struct netconn or 748 * NULL on memory error 749 */ 750struct netconn * 751netconn_alloc(enum netconn_type t, netconn_callback callback) 752{ 753 struct netconn *conn; 754 int size; 755 u8_t init_flags = 0; 756 757 conn = (struct netconn *)memp_malloc(MEMP_NETCONN); 758 if (conn == NULL) { 759 return NULL; 760 } 761 762 conn->pending_err = ERR_OK; 763 conn->type = t; 764 conn->pcb.tcp = NULL; 765#if LWIP_NETCONN_FULLDUPLEX 766 conn->mbox_threads_waiting = 0; 767#endif 768 769 /* If all sizes are the same, every compiler should optimize this switch to nothing */ 770 switch (NETCONNTYPE_GROUP(t)) { 771#if LWIP_RAW 772 case NETCONN_RAW: 773 size = DEFAULT_RAW_RECVMBOX_SIZE; 774 break; 775#endif /* LWIP_RAW */ 776#if LWIP_UDP 777 case NETCONN_UDP: 778 size = DEFAULT_UDP_RECVMBOX_SIZE; 779#if LWIP_NETBUF_RECVINFO 780 init_flags |= NETCONN_FLAG_PKTINFO; 781#endif /* LWIP_NETBUF_RECVINFO */ 782 break; 783#endif /* LWIP_UDP */ 784#if LWIP_TCP 785 case NETCONN_TCP: 786 size = DEFAULT_TCP_RECVMBOX_SIZE; 787 break; 788#endif /* LWIP_TCP */ 789 default: 790 LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); 791 goto free_and_return; 792 } 793 794 if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { 795 goto free_and_return; 796 } 797#if !LWIP_NETCONN_SEM_PER_THREAD 798 if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { 799 sys_mbox_free(&conn->recvmbox); 800 goto free_and_return; 801 } 802#endif 803 804#if LWIP_TCP 805 sys_mbox_set_invalid(&conn->acceptmbox); 806#endif 807 conn->state = NETCONN_NONE; 808#if LWIP_SOCKET 809 /* initialize socket to -1 since 0 is a valid socket */ 810 conn->socket = -1; 811#endif /* LWIP_SOCKET */ 812 conn->callback = callback; 813#if LWIP_TCP 814 conn->current_msg = NULL; 815#endif /* LWIP_TCP */ 816#if LWIP_SO_SNDTIMEO 817 conn->send_timeout = 0; 818#endif /* LWIP_SO_SNDTIMEO */ 819#if LWIP_SO_RCVTIMEO 820 conn->recv_timeout = 0; 821#endif /* LWIP_SO_RCVTIMEO */ 822#if LWIP_SO_RCVBUF 823 conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; 824 conn->recv_avail = 0; 825#endif /* LWIP_SO_RCVBUF */ 826#if LWIP_SO_LINGER 827 conn->linger = -1; 828#endif /* LWIP_SO_LINGER */ 829 conn->flags = init_flags; 830 return conn; 831free_and_return: 832 memp_free(MEMP_NETCONN, conn); 833 return NULL; 834} 835 836/** 837 * Delete a netconn and all its resources. 838 * The pcb is NOT freed (since we might not be in the right thread context do this). 839 * 840 * @param conn the netconn to free 841 */ 842void 843netconn_free(struct netconn *conn) 844{ 845 LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); 846 847#if LWIP_NETCONN_FULLDUPLEX 848 /* in fullduplex, netconn is drained here */ 849 netconn_drain(conn); 850#endif /* LWIP_NETCONN_FULLDUPLEX */ 851 852 LWIP_ASSERT("recvmbox must be deallocated before calling this function", 853 !sys_mbox_valid(&conn->recvmbox)); 854#if LWIP_TCP 855 LWIP_ASSERT("acceptmbox must be deallocated before calling this function", 856 !sys_mbox_valid(&conn->acceptmbox)); 857#endif /* LWIP_TCP */ 858 859#if !LWIP_NETCONN_SEM_PER_THREAD 860 sys_sem_free(&conn->op_completed); 861 sys_sem_set_invalid(&conn->op_completed); 862#endif 863 864 memp_free(MEMP_NETCONN, conn); 865} 866 867/** 868 * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in 869 * these mboxes 870 * 871 * @param conn the netconn to free 872 * @bytes_drained bytes drained from recvmbox 873 * @accepts_drained pending connections drained from acceptmbox 874 */ 875static void 876netconn_drain(struct netconn *conn) 877{ 878 void *mem; 879 880 /* This runs when mbox and netconn are marked as closed, 881 so we don't need to lock against rx packets */ 882#if LWIP_NETCONN_FULLDUPLEX 883 LWIP_ASSERT("netconn marked closed", conn->flags & NETCONN_FLAG_MBOXINVALID); 884#endif /* LWIP_NETCONN_FULLDUPLEX */ 885 886 /* Delete and drain the recvmbox. */ 887 if (sys_mbox_valid(&conn->recvmbox)) { 888 while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { 889#if LWIP_NETCONN_FULLDUPLEX 890 if (!lwip_netconn_is_deallocated_msg(mem)) 891#endif /* LWIP_NETCONN_FULLDUPLEX */ 892 { 893#if LWIP_TCP 894 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) { 895 err_t err; 896 if (!lwip_netconn_is_err_msg(mem, &err)) { 897 pbuf_free((struct pbuf *)mem); 898 } 899 } else 900#endif /* LWIP_TCP */ 901 { 902 netbuf_delete((struct netbuf *)mem); 903 } 904 } 905 } 906 sys_mbox_free(&conn->recvmbox); 907 sys_mbox_set_invalid(&conn->recvmbox); 908 } 909 910 /* Delete and drain the acceptmbox. */ 911#if LWIP_TCP 912 if (sys_mbox_valid(&conn->acceptmbox)) { 913 while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { 914#if LWIP_NETCONN_FULLDUPLEX 915 if (!lwip_netconn_is_deallocated_msg(mem)) 916#endif /* LWIP_NETCONN_FULLDUPLEX */ 917 { 918 err_t err; 919 if (!lwip_netconn_is_err_msg(mem, &err)) { 920 struct netconn *newconn = (struct netconn *)mem; 921 /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ 922 /* pcb might be set to NULL already by err_tcp() */ 923 /* drain recvmbox */ 924 netconn_drain(newconn); 925 if (newconn->pcb.tcp != NULL) { 926 tcp_abort(newconn->pcb.tcp); 927 newconn->pcb.tcp = NULL; 928 } 929 netconn_free(newconn); 930 } 931 } 932 } 933 sys_mbox_free(&conn->acceptmbox); 934 sys_mbox_set_invalid(&conn->acceptmbox); 935 } 936#endif /* LWIP_TCP */ 937} 938 939#if LWIP_NETCONN_FULLDUPLEX 940static void 941netconn_mark_mbox_invalid(struct netconn *conn) 942{ 943 int i, num_waiting; 944 void *msg = LWIP_CONST_CAST(void *, &netconn_deleted); 945 946 /* Prevent new calls/threads from reading from the mbox */ 947 conn->flags |= NETCONN_FLAG_MBOXINVALID; 948 949 SYS_ARCH_LOCKED(num_waiting = conn->mbox_threads_waiting); 950 for (i = 0; i < num_waiting; i++) { 951 if (sys_mbox_valid_val(conn->recvmbox)) { 952 sys_mbox_trypost(&conn->recvmbox, msg); 953 } else { 954 sys_mbox_trypost(&conn->acceptmbox, msg); 955 } 956 } 957} 958#endif /* LWIP_NETCONN_FULLDUPLEX */ 959 960#if LWIP_TCP 961/** 962 * Internal helper function to close a TCP netconn: since this sometimes 963 * doesn't work at the first attempt, this function is called from multiple 964 * places. 965 * 966 * @param conn the TCP netconn to close 967 */ 968static err_t 969lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM) 970{ 971 err_t err; 972 u8_t shut, shut_rx, shut_tx, shut_close; 973 u8_t close_finished = 0; 974 struct tcp_pcb *tpcb; 975#if LWIP_SO_LINGER 976 u8_t linger_wait_required = 0; 977#endif /* LWIP_SO_LINGER */ 978 979 LWIP_ASSERT("invalid conn", (conn != NULL)); 980 LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)); 981 LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); 982 LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); 983 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 984 985 tpcb = conn->pcb.tcp; 986 shut = conn->current_msg->msg.sd.shut; 987 shut_rx = shut & NETCONN_SHUT_RD; 988 shut_tx = shut & NETCONN_SHUT_WR; 989 /* shutting down both ends is the same as closing 990 (also if RD or WR side was shut down before already) */ 991 if (shut == NETCONN_SHUT_RDWR) { 992 shut_close = 1; 993 } else if (shut_rx && 994 ((tpcb->state == FIN_WAIT_1) || 995 (tpcb->state == FIN_WAIT_2) || 996 (tpcb->state == CLOSING))) { 997 shut_close = 1; 998 } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) { 999 shut_close = 1; 1000 } else { 1001 shut_close = 0; 1002 } 1003 1004 /* Set back some callback pointers */ 1005 if (shut_close) { 1006 tcp_arg(tpcb, NULL); 1007 } 1008 if (tpcb->state == LISTEN) { 1009 tcp_accept(tpcb, NULL); 1010 } else { 1011 /* some callbacks have to be reset if tcp_close is not successful */ 1012 if (shut_rx) { 1013 tcp_recv(tpcb, NULL); 1014 tcp_accept(tpcb, NULL); 1015 } 1016 if (shut_tx) { 1017 tcp_sent(tpcb, NULL); 1018 } 1019 if (shut_close) { 1020 tcp_poll(tpcb, NULL, 0); 1021 tcp_err(tpcb, NULL); 1022 } 1023 } 1024 /* Try to close the connection */ 1025 if (shut_close) { 1026#if LWIP_SO_LINGER 1027 /* check linger possibilites before calling tcp_close */ 1028 err = ERR_OK; 1029 /* linger enabled/required at all? (i.e. is there untransmitted data left?) */ 1030 if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) { 1031 if ((conn->linger == 0)) { 1032 /* data left but linger prevents waiting */ 1033 tcp_abort(tpcb); 1034 tpcb = NULL; 1035 } else if (conn->linger > 0) { 1036 /* data left and linger says we should wait */ 1037 if (netconn_is_nonblocking(conn)) { 1038 /* data left on a nonblocking netconn -> cannot linger */ 1039 err = ERR_WOULDBLOCK; 1040 } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= 1041 (conn->linger * 1000)) { 1042 /* data left but linger timeout has expired (this happens on further 1043 calls to this function through poll_tcp */ 1044 tcp_abort(tpcb); 1045 tpcb = NULL; 1046 } else { 1047 /* data left -> need to wait for ACK after successful close */ 1048 linger_wait_required = 1; 1049 } 1050 } 1051 } 1052 if ((err == ERR_OK) && (tpcb != NULL)) 1053#endif /* LWIP_SO_LINGER */ 1054 { 1055 err = tcp_close(tpcb); 1056 } 1057 } else { 1058 err = tcp_shutdown(tpcb, shut_rx, shut_tx); 1059 } 1060 if (err == ERR_OK) { 1061 close_finished = 1; 1062#if LWIP_SO_LINGER 1063 if (linger_wait_required) { 1064 /* wait for ACK of all unsent/unacked data by just getting called again */ 1065 close_finished = 0; 1066 err = ERR_INPROGRESS; 1067 } 1068#endif /* LWIP_SO_LINGER */ 1069 } else { 1070 if (err == ERR_MEM) { 1071 /* Closing failed because of memory shortage, try again later. Even for 1072 nonblocking netconns, we have to wait since no standard socket application 1073 is prepared for close failing because of resource shortage. 1074 Check the timeout: this is kind of an lwip addition to the standard sockets: 1075 we wait for some time when failing to allocate a segment for the FIN */ 1076#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER 1077 s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT; 1078#if LWIP_SO_SNDTIMEO 1079 if (conn->send_timeout > 0) { 1080 close_timeout = conn->send_timeout; 1081 } 1082#endif /* LWIP_SO_SNDTIMEO */ 1083#if LWIP_SO_LINGER 1084 if (conn->linger >= 0) { 1085 /* use linger timeout (seconds) */ 1086 close_timeout = conn->linger * 1000U; 1087 } 1088#endif 1089 if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) { 1090#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 1091 if (conn->current_msg->msg.sd.polls_left == 0) { 1092#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 1093 close_finished = 1; 1094 if (shut_close) { 1095 /* in this case, we want to RST the connection */ 1096 tcp_abort(tpcb); 1097 err = ERR_OK; 1098 } 1099 } 1100 } else { 1101 /* Closing failed for a non-memory error: give up */ 1102 close_finished = 1; 1103 } 1104 } 1105 if (close_finished) { 1106 /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */ 1107 sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 1108 conn->current_msg->err = err; 1109 conn->current_msg = NULL; 1110 conn->state = NETCONN_NONE; 1111 if (err == ERR_OK) { 1112 if (shut_close) { 1113 /* Set back some callback pointers as conn is going away */ 1114 conn->pcb.tcp = NULL; 1115 /* Trigger select() in socket layer. Make sure everybody notices activity 1116 on the connection, error first! */ 1117 API_EVENT(conn, NETCONN_EVT_ERROR, 0); 1118 } 1119 if (shut_rx) { 1120 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 1121 } 1122 if (shut_tx) { 1123 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 1124 } 1125 } 1126#if LWIP_TCPIP_CORE_LOCKING 1127 if (delayed) 1128#endif 1129 { 1130 /* wake up the application task */ 1131 sys_sem_signal(op_completed_sem); 1132 } 1133 return ERR_OK; 1134 } 1135 if (!close_finished) { 1136 /* Closing failed and we want to wait: restore some of the callbacks */ 1137 /* Closing of listen pcb will never fail! */ 1138 LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN)); 1139 if (shut_tx) { 1140 tcp_sent(tpcb, sent_tcp); 1141 } 1142 /* when waiting for close, set up poll interval to 500ms */ 1143 tcp_poll(tpcb, poll_tcp, 1); 1144 tcp_err(tpcb, err_tcp); 1145 tcp_arg(tpcb, conn); 1146 /* don't restore recv callback: we don't want to receive any more data */ 1147 } 1148 /* If closing didn't succeed, we get called again either 1149 from poll_tcp or from sent_tcp */ 1150 LWIP_ASSERT("err != ERR_OK", err != ERR_OK); 1151 return err; 1152} 1153#endif /* LWIP_TCP */ 1154 1155/** 1156 * Delete the pcb inside a netconn. 1157 * Called from netconn_delete. 1158 * 1159 * @param m the api_msg pointing to the connection 1160 */ 1161void 1162lwip_netconn_do_delconn(void *m) 1163{ 1164 struct api_msg *msg = (struct api_msg *)m; 1165 1166 enum netconn_state state = msg->conn->state; 1167 LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */ 1168 (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP)); 1169#if LWIP_NETCONN_FULLDUPLEX 1170 /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */ 1171 if (state != NETCONN_NONE) { 1172 if ((state == NETCONN_WRITE) || 1173 ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) { 1174 /* close requested, abort running write/connect */ 1175 sys_sem_t *op_completed_sem; 1176 LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL); 1177 op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg); 1178 msg->conn->current_msg->err = ERR_CLSD; 1179 msg->conn->current_msg = NULL; 1180 msg->conn->state = NETCONN_NONE; 1181 sys_sem_signal(op_completed_sem); 1182 } 1183 } 1184#else /* LWIP_NETCONN_FULLDUPLEX */ 1185 if (((state != NETCONN_NONE) && 1186 (state != NETCONN_LISTEN) && 1187 (state != NETCONN_CONNECT)) || 1188 ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) { 1189 /* This means either a blocking write or blocking connect is running 1190 (nonblocking write returns and sets state to NONE) */ 1191 msg->err = ERR_INPROGRESS; 1192 } else 1193#endif /* LWIP_NETCONN_FULLDUPLEX */ 1194 { 1195 LWIP_ASSERT("blocking connect in progress", 1196 (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); 1197 msg->err = ERR_OK; 1198#if LWIP_NETCONN_FULLDUPLEX 1199 /* Mark mboxes invalid */ 1200 netconn_mark_mbox_invalid(msg->conn); 1201#else /* LWIP_NETCONN_FULLDUPLEX */ 1202 netconn_drain(msg->conn); 1203#endif /* LWIP_NETCONN_FULLDUPLEX */ 1204 1205 if (msg->conn->pcb.tcp != NULL) { 1206 1207 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1208#if LWIP_RAW 1209 case NETCONN_RAW: 1210 raw_remove(msg->conn->pcb.raw); 1211 break; 1212#endif /* LWIP_RAW */ 1213#if LWIP_UDP 1214 case NETCONN_UDP: 1215 msg->conn->pcb.udp->recv_arg = NULL; 1216 udp_remove(msg->conn->pcb.udp); 1217 break; 1218#endif /* LWIP_UDP */ 1219#if LWIP_TCP 1220 case NETCONN_TCP: 1221 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL); 1222 msg->conn->state = NETCONN_CLOSE; 1223 msg->msg.sd.shut = NETCONN_SHUT_RDWR; 1224 msg->conn->current_msg = msg; 1225#if LWIP_TCPIP_CORE_LOCKING 1226 if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) { 1227 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE); 1228 UNLOCK_TCPIP_CORE(); 1229 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 1230 LOCK_TCPIP_CORE(); 1231 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); 1232 } 1233#else /* LWIP_TCPIP_CORE_LOCKING */ 1234 lwip_netconn_do_close_internal(msg->conn); 1235#endif /* LWIP_TCPIP_CORE_LOCKING */ 1236 /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing 1237 the application thread, so we can return at this point! */ 1238 return; 1239#endif /* LWIP_TCP */ 1240 default: 1241 break; 1242 } 1243 msg->conn->pcb.tcp = NULL; 1244 } 1245 /* tcp netconns don't come here! */ 1246 1247 /* @todo: this lets select make the socket readable and writable, 1248 which is wrong! errfd instead? */ 1249 API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); 1250 API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); 1251 } 1252 if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) { 1253 TCPIP_APIMSG_ACK(msg); 1254 } 1255} 1256 1257/** 1258 * Bind a pcb contained in a netconn 1259 * Called from netconn_bind. 1260 * 1261 * @param m the api_msg pointing to the connection and containing 1262 * the IP address and port to bind to 1263 */ 1264void 1265lwip_netconn_do_bind(void *m) 1266{ 1267 struct api_msg *msg = (struct api_msg *)m; 1268 err_t err; 1269 1270 if (msg->conn->pcb.tcp != NULL) { 1271 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1272#if LWIP_RAW 1273 case NETCONN_RAW: 1274 err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); 1275 break; 1276#endif /* LWIP_RAW */ 1277#if LWIP_UDP 1278 case NETCONN_UDP: 1279 err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); 1280 break; 1281#endif /* LWIP_UDP */ 1282#if LWIP_TCP 1283 case NETCONN_TCP: 1284 err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); 1285 break; 1286#endif /* LWIP_TCP */ 1287 default: 1288 err = ERR_VAL; 1289 break; 1290 } 1291 } else { 1292 err = ERR_VAL; 1293 } 1294 msg->err = err; 1295 TCPIP_APIMSG_ACK(msg); 1296} 1297 1298/** 1299 * Bind a pcb contained in a netconn to an interface 1300 * Called from netconn_bind_if. 1301 * 1302 * @param m the api_msg pointing to the connection and containing 1303 * the IP address and port to bind to 1304 */ 1305void 1306lwip_netconn_do_bind_if(void *m) 1307{ 1308 struct netif *netif; 1309 struct api_msg *msg = (struct api_msg *)m; 1310 err_t err; 1311#ifdef LOSCFG_NET_CONTAINER 1312 struct net_group *group = get_net_group_from_ippcb(msg->conn->pcb.ip); 1313 1314 if (group != NULL) { 1315 netif = netif_get_by_index(msg->msg.bc.if_idx, group); 1316 } else { 1317 netif = NULL; 1318 } 1319#else 1320 netif = netif_get_by_index(msg->msg.bc.if_idx); 1321#endif 1322 1323 if ((netif != NULL) && (msg->conn->pcb.tcp != NULL)) { 1324 err = ERR_OK; 1325 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1326#if LWIP_RAW 1327 case NETCONN_RAW: 1328 raw_bind_netif(msg->conn->pcb.raw, netif); 1329 break; 1330#endif /* LWIP_RAW */ 1331#if LWIP_UDP 1332 case NETCONN_UDP: 1333 udp_bind_netif(msg->conn->pcb.udp, netif); 1334 break; 1335#endif /* LWIP_UDP */ 1336#if LWIP_TCP 1337 case NETCONN_TCP: 1338 tcp_bind_netif(msg->conn->pcb.tcp, netif); 1339 break; 1340#endif /* LWIP_TCP */ 1341 default: 1342 err = ERR_VAL; 1343 break; 1344 } 1345 } else { 1346 err = ERR_VAL; 1347 } 1348 msg->err = err; 1349 TCPIP_APIMSG_ACK(msg); 1350} 1351 1352#if LWIP_TCP 1353/** 1354 * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has 1355 * been established (or reset by the remote host). 1356 * 1357 * @see tcp.h (struct tcp_pcb.connected) for parameters and return values 1358 */ 1359static err_t 1360lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) 1361{ 1362 struct netconn *conn; 1363 int was_blocking; 1364 sys_sem_t *op_completed_sem = NULL; 1365 1366 LWIP_UNUSED_ARG(pcb); 1367 1368 conn = (struct netconn *)arg; 1369 1370 if (conn == NULL) { 1371 return ERR_VAL; 1372 } 1373 1374 LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); 1375 LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", 1376 (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); 1377 1378 if (conn->current_msg != NULL) { 1379 conn->current_msg->err = err; 1380 op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 1381 } 1382 if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) { 1383 setup_tcp(conn); 1384 } 1385 was_blocking = !IN_NONBLOCKING_CONNECT(conn); 1386 SET_NONBLOCKING_CONNECT(conn, 0); 1387 LWIP_ASSERT("blocking connect state error", 1388 (was_blocking && op_completed_sem != NULL) || 1389 (!was_blocking && op_completed_sem == NULL)); 1390 conn->current_msg = NULL; 1391 conn->state = NETCONN_NONE; 1392 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 1393 1394 if (was_blocking) { 1395 sys_sem_signal(op_completed_sem); 1396 } 1397 return ERR_OK; 1398} 1399#endif /* LWIP_TCP */ 1400 1401/** 1402 * Connect a pcb contained inside a netconn 1403 * Called from netconn_connect. 1404 * 1405 * @param m the api_msg pointing to the connection and containing 1406 * the IP address and port to connect to 1407 */ 1408void 1409lwip_netconn_do_connect(void *m) 1410{ 1411 struct api_msg *msg = (struct api_msg *)m; 1412 err_t err; 1413 1414 if (msg->conn->pcb.tcp == NULL) { 1415 /* This may happen when calling netconn_connect() a second time */ 1416 err = ERR_CLSD; 1417 } else { 1418 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1419#if LWIP_RAW 1420 case NETCONN_RAW: 1421 err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); 1422 break; 1423#endif /* LWIP_RAW */ 1424#if LWIP_UDP 1425 case NETCONN_UDP: 1426 err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); 1427 break; 1428#endif /* LWIP_UDP */ 1429#if LWIP_TCP 1430 case NETCONN_TCP: 1431 /* Prevent connect while doing any other action. */ 1432 if (msg->conn->state == NETCONN_CONNECT) { 1433 err = ERR_ALREADY; 1434 } else if (msg->conn->state != NETCONN_NONE) { 1435 err = ERR_ISCONN; 1436 } else { 1437 setup_tcp(msg->conn); 1438 err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), 1439 msg->msg.bc.port, lwip_netconn_do_connected); 1440 if (err == ERR_OK) { 1441 u8_t non_blocking = netconn_is_nonblocking(msg->conn); 1442 msg->conn->state = NETCONN_CONNECT; 1443 SET_NONBLOCKING_CONNECT(msg->conn, non_blocking); 1444 if (non_blocking) { 1445 err = ERR_INPROGRESS; 1446 } else { 1447 msg->conn->current_msg = msg; 1448 /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()), 1449 when the connection is established! */ 1450#if LWIP_TCPIP_CORE_LOCKING 1451 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT); 1452 UNLOCK_TCPIP_CORE(); 1453 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 1454 LOCK_TCPIP_CORE(); 1455 LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT); 1456#endif /* LWIP_TCPIP_CORE_LOCKING */ 1457 return; 1458 } 1459 } 1460 } 1461 break; 1462#endif /* LWIP_TCP */ 1463 default: 1464 LWIP_ERROR("Invalid netconn type", 0, do { 1465 err = ERR_VAL; 1466 } while (0)); 1467 break; 1468 } 1469 } 1470 msg->err = err; 1471 /* For all other protocols, netconn_connect() calls netconn_apimsg(), 1472 so use TCPIP_APIMSG_ACK() here. */ 1473 TCPIP_APIMSG_ACK(msg); 1474} 1475 1476/** 1477 * Disconnect a pcb contained inside a netconn 1478 * Only used for UDP netconns. 1479 * Called from netconn_disconnect. 1480 * 1481 * @param m the api_msg pointing to the connection to disconnect 1482 */ 1483void 1484lwip_netconn_do_disconnect(void *m) 1485{ 1486 struct api_msg *msg = (struct api_msg *)m; 1487 1488#if LWIP_UDP 1489 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 1490 udp_disconnect(msg->conn->pcb.udp); 1491 msg->err = ERR_OK; 1492 } else 1493#endif /* LWIP_UDP */ 1494 { 1495 msg->err = ERR_VAL; 1496 } 1497 TCPIP_APIMSG_ACK(msg); 1498} 1499 1500#if LWIP_TCP 1501/** 1502 * Set a TCP pcb contained in a netconn into listen mode 1503 * Called from netconn_listen. 1504 * 1505 * @param m the api_msg pointing to the connection 1506 */ 1507void 1508lwip_netconn_do_listen(void *m) 1509{ 1510 struct api_msg *msg = (struct api_msg *)m; 1511 err_t err; 1512 1513 if (msg->conn->pcb.tcp != NULL) { 1514 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 1515 if (msg->conn->state == NETCONN_NONE) { 1516 struct tcp_pcb *lpcb; 1517 if (msg->conn->pcb.tcp->state != CLOSED) { 1518 /* connection is not closed, cannot listen */ 1519 err = ERR_VAL; 1520 } else { 1521 u8_t backlog; 1522#if TCP_LISTEN_BACKLOG 1523 backlog = msg->msg.lb.backlog; 1524#else /* TCP_LISTEN_BACKLOG */ 1525 backlog = TCP_DEFAULT_LISTEN_BACKLOG; 1526#endif /* TCP_LISTEN_BACKLOG */ 1527#if LWIP_IPV4 && LWIP_IPV6 1528 /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY, 1529 * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen 1530 */ 1531 if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) && 1532 (netconn_get_ipv6only(msg->conn) == 0)) { 1533 /* change PCB type to IPADDR_TYPE_ANY */ 1534 IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip, IPADDR_TYPE_ANY); 1535 IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY); 1536 } 1537#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1538 1539 lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err); 1540 1541 if (lpcb == NULL) { 1542 /* in this case, the old pcb is still allocated */ 1543 } else { 1544 /* delete the recvmbox and allocate the acceptmbox */ 1545 if (sys_mbox_valid(&msg->conn->recvmbox)) { 1546 /** @todo: should we drain the recvmbox here? */ 1547 sys_mbox_free(&msg->conn->recvmbox); 1548 sys_mbox_set_invalid(&msg->conn->recvmbox); 1549 } 1550 err = ERR_OK; 1551 if (!sys_mbox_valid(&msg->conn->acceptmbox)) { 1552 err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE); 1553 } 1554 if (err == ERR_OK) { 1555 msg->conn->state = NETCONN_LISTEN; 1556 msg->conn->pcb.tcp = lpcb; 1557 tcp_arg(msg->conn->pcb.tcp, msg->conn); 1558 tcp_accept(msg->conn->pcb.tcp, accept_function); 1559 } else { 1560 /* since the old pcb is already deallocated, free lpcb now */ 1561 tcp_close(lpcb); 1562 msg->conn->pcb.tcp = NULL; 1563 } 1564 } 1565 } 1566 } else if (msg->conn->state == NETCONN_LISTEN) { 1567 /* already listening, allow updating of the backlog */ 1568 err = ERR_OK; 1569 tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog); 1570 } else { 1571 err = ERR_CONN; 1572 } 1573 } else { 1574 err = ERR_ARG; 1575 } 1576 } else { 1577 err = ERR_CONN; 1578 } 1579 msg->err = err; 1580 TCPIP_APIMSG_ACK(msg); 1581} 1582#endif /* LWIP_TCP */ 1583 1584/** 1585 * Send some data on a RAW or UDP pcb contained in a netconn 1586 * Called from netconn_send 1587 * 1588 * @param m the api_msg pointing to the connection 1589 */ 1590void 1591lwip_netconn_do_send(void *m) 1592{ 1593 struct api_msg *msg = (struct api_msg *)m; 1594 1595 err_t err = netconn_err(msg->conn); 1596 if (err == ERR_OK) { 1597 if (msg->conn->pcb.tcp != NULL) { 1598 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1599#if LWIP_RAW 1600 case NETCONN_RAW: 1601 if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { 1602 err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); 1603 } else { 1604 err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); 1605 } 1606 break; 1607#endif 1608#if LWIP_UDP 1609 case NETCONN_UDP: 1610#if LWIP_CHECKSUM_ON_COPY 1611 if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { 1612 err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, 1613 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); 1614 } else { 1615 err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, 1616 &msg->msg.b->addr, msg->msg.b->port, 1617 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); 1618 } 1619#else /* LWIP_CHECKSUM_ON_COPY */ 1620 if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { 1621 err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); 1622 } else { 1623 err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port); 1624 } 1625#endif /* LWIP_CHECKSUM_ON_COPY */ 1626 break; 1627#endif /* LWIP_UDP */ 1628 default: 1629 err = ERR_CONN; 1630 break; 1631 } 1632 } else { 1633 err = ERR_CONN; 1634 } 1635 } 1636 msg->err = err; 1637 TCPIP_APIMSG_ACK(msg); 1638} 1639 1640#if LWIP_TCP 1641/** 1642 * Indicate data has been received from a TCP pcb contained in a netconn 1643 * Called from netconn_recv 1644 * 1645 * @param m the api_msg pointing to the connection 1646 */ 1647void 1648lwip_netconn_do_recv(void *m) 1649{ 1650 struct api_msg *msg = (struct api_msg *)m; 1651 1652 msg->err = ERR_OK; 1653 if (msg->conn->pcb.tcp != NULL) { 1654 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 1655 size_t remaining = msg->msg.r.len; 1656 do { 1657 u16_t recved = (u16_t)((remaining > 0xffff) ? 0xffff : remaining); 1658 tcp_recved(msg->conn->pcb.tcp, recved); 1659 remaining -= recved; 1660 } while (remaining != 0); 1661 } 1662 } 1663 TCPIP_APIMSG_ACK(msg); 1664} 1665 1666#if TCP_LISTEN_BACKLOG 1667/** Indicate that a TCP pcb has been accepted 1668 * Called from netconn_accept 1669 * 1670 * @param m the api_msg pointing to the connection 1671 */ 1672void 1673lwip_netconn_do_accepted(void *m) 1674{ 1675 struct api_msg *msg = (struct api_msg *)m; 1676 1677 msg->err = ERR_OK; 1678 if (msg->conn->pcb.tcp != NULL) { 1679 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 1680 tcp_backlog_accepted(msg->conn->pcb.tcp); 1681 } 1682 } 1683 TCPIP_APIMSG_ACK(msg); 1684} 1685#endif /* TCP_LISTEN_BACKLOG */ 1686 1687/** 1688 * See if more data needs to be written from a previous call to netconn_write. 1689 * Called initially from lwip_netconn_do_write. If the first call can't send all data 1690 * (because of low memory or empty send-buffer), this function is called again 1691 * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the 1692 * blocking application thread (waiting in netconn_write) is released. 1693 * 1694 * @param conn netconn (that is currently in state NETCONN_WRITE) to process 1695 * @return ERR_OK 1696 * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished 1697 */ 1698static err_t 1699lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM) 1700{ 1701 err_t err; 1702 const void *dataptr; 1703 u16_t len, available; 1704 u8_t write_finished = 0; 1705 size_t diff; 1706 u8_t dontblock; 1707 u8_t apiflags; 1708 u8_t write_more; 1709 1710 LWIP_ASSERT("conn != NULL", conn != NULL); 1711 LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); 1712 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 1713 LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); 1714 LWIP_ASSERT("conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len", 1715 conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len); 1716 LWIP_ASSERT("conn->current_msg->msg.w.vector_cnt > 0", conn->current_msg->msg.w.vector_cnt > 0); 1717 1718 apiflags = conn->current_msg->msg.w.apiflags; 1719 dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); 1720 1721#if LWIP_SO_SNDTIMEO 1722 if ((conn->send_timeout != 0) && 1723 ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) { 1724 write_finished = 1; 1725 if (conn->current_msg->msg.w.offset == 0) { 1726 /* nothing has been written */ 1727 err = ERR_WOULDBLOCK; 1728 } else { 1729 /* partial write */ 1730 err = ERR_OK; 1731 } 1732 } else 1733#endif /* LWIP_SO_SNDTIMEO */ 1734 { 1735 do { 1736 dataptr = (const u8_t *)conn->current_msg->msg.w.vector->ptr + conn->current_msg->msg.w.vector_off; 1737 diff = conn->current_msg->msg.w.vector->len - conn->current_msg->msg.w.vector_off; 1738 if (diff > 0xffffUL) { /* max_u16_t */ 1739 len = 0xffff; 1740 apiflags |= TCP_WRITE_FLAG_MORE; 1741 } else { 1742 len = (u16_t)diff; 1743 } 1744 available = tcp_sndbuf(conn->pcb.tcp); 1745 if (available < len) { 1746 /* don't try to write more than sendbuf */ 1747 len = available; 1748 if (dontblock) { 1749 if (!len) { 1750 /* set error according to partial write or not */ 1751 err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK; 1752 goto err_mem; 1753 } 1754 } else { 1755 apiflags |= TCP_WRITE_FLAG_MORE; 1756 } 1757 } 1758 LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!", 1759 ((conn->current_msg->msg.w.vector_off + len) <= conn->current_msg->msg.w.vector->len)); 1760 /* we should loop around for more sending in the following cases: 1761 1) We couldn't finish the current vector because of 16-bit size limitations. 1762 tcp_write() and tcp_sndbuf() both are limited to 16-bit sizes 1763 2) We are sending the remainder of the current vector and have more */ 1764 if ((len == 0xffff && diff > 0xffffUL) || 1765 (len == (u16_t)diff && conn->current_msg->msg.w.vector_cnt > 1)) { 1766 write_more = 1; 1767 apiflags |= TCP_WRITE_FLAG_MORE; 1768 } else { 1769 write_more = 0; 1770 } 1771 err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); 1772 if (err == ERR_OK) { 1773 conn->current_msg->msg.w.offset += len; 1774 conn->current_msg->msg.w.vector_off += len; 1775 /* check if current vector is finished */ 1776 if (conn->current_msg->msg.w.vector_off == conn->current_msg->msg.w.vector->len) { 1777 conn->current_msg->msg.w.vector_cnt--; 1778 /* if we have additional vectors, move on to them */ 1779 if (conn->current_msg->msg.w.vector_cnt > 0) { 1780 conn->current_msg->msg.w.vector++; 1781 conn->current_msg->msg.w.vector_off = 0; 1782 } 1783 } 1784 } 1785 } while (write_more && err == ERR_OK); 1786 /* if OK or memory error, check available space */ 1787 if ((err == ERR_OK) || (err == ERR_MEM)) { 1788err_mem: 1789 if (dontblock && (conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len)) { 1790 /* non-blocking write did not write everything: mark the pcb non-writable 1791 and let poll_tcp check writable space to mark the pcb writable again */ 1792 API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0); 1793 conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; 1794 } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || 1795 (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { 1796 /* The queued byte- or pbuf-count exceeds the configured low-water limit, 1797 let select mark this pcb as non-writable. */ 1798 API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0); 1799 } 1800 } 1801 1802 if (err == ERR_OK) { 1803 err_t out_err; 1804 if ((conn->current_msg->msg.w.offset == conn->current_msg->msg.w.len) || dontblock) { 1805 /* return sent length (caller reads length from msg.w.offset) */ 1806 write_finished = 1; 1807 } 1808 out_err = tcp_output(conn->pcb.tcp); 1809 if (out_err == ERR_RTE) { 1810 /* If tcp_output fails because no route is found, 1811 don't try writing any more but return the error 1812 to the application thread. */ 1813 err = out_err; 1814 write_finished = 1; 1815 } 1816 } else if (err == ERR_MEM) { 1817 /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called. 1818 For blocking sockets, we do NOT return to the application 1819 thread, since ERR_MEM is only a temporary error! Non-blocking 1820 will remain non-writable until sent_tcp/poll_tcp is called */ 1821 1822 /* tcp_write returned ERR_MEM, try tcp_output anyway */ 1823 err_t out_err = tcp_output(conn->pcb.tcp); 1824 if (out_err == ERR_RTE) { 1825 /* If tcp_output fails because no route is found, 1826 don't try writing any more but return the error 1827 to the application thread. */ 1828 err = out_err; 1829 write_finished = 1; 1830 } else if (dontblock) { 1831 /* non-blocking write is done on ERR_MEM, set error according 1832 to partial write or not */ 1833 err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK; 1834 write_finished = 1; 1835 } 1836 } else { 1837 /* On errors != ERR_MEM, we don't try writing any more but return 1838 the error to the application thread. */ 1839 write_finished = 1; 1840 } 1841 } 1842 if (write_finished) { 1843 /* everything was written: set back connection state 1844 and back to application task */ 1845 sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 1846 conn->current_msg->err = err; 1847 conn->current_msg = NULL; 1848 conn->state = NETCONN_NONE; 1849#if LWIP_TCPIP_CORE_LOCKING 1850 if (delayed) 1851#endif 1852 { 1853 sys_sem_signal(op_completed_sem); 1854 } 1855 } 1856#if LWIP_TCPIP_CORE_LOCKING 1857 else { 1858 return ERR_MEM; 1859 } 1860#endif 1861 return ERR_OK; 1862} 1863#endif /* LWIP_TCP */ 1864 1865/** 1866 * Send some data on a TCP pcb contained in a netconn 1867 * Called from netconn_write 1868 * 1869 * @param m the api_msg pointing to the connection 1870 */ 1871void 1872lwip_netconn_do_write(void *m) 1873{ 1874 struct api_msg *msg = (struct api_msg *)m; 1875 1876 err_t err = netconn_err(msg->conn); 1877 if (err == ERR_OK) { 1878 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 1879#if LWIP_TCP 1880 if (msg->conn->state != NETCONN_NONE) { 1881 /* netconn is connecting, closing or in blocking write */ 1882 err = ERR_INPROGRESS; 1883 } else if (msg->conn->pcb.tcp != NULL) { 1884 msg->conn->state = NETCONN_WRITE; 1885 /* set all the variables used by lwip_netconn_do_writemore */ 1886 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL); 1887 LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0); 1888 msg->conn->current_msg = msg; 1889#if LWIP_TCPIP_CORE_LOCKING 1890 if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) { 1891 LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); 1892 UNLOCK_TCPIP_CORE(); 1893 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 1894 LOCK_TCPIP_CORE(); 1895 LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE); 1896 } 1897#else /* LWIP_TCPIP_CORE_LOCKING */ 1898 lwip_netconn_do_writemore(msg->conn); 1899#endif /* LWIP_TCPIP_CORE_LOCKING */ 1900 /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG 1901 since lwip_netconn_do_writemore ACKs it! */ 1902 return; 1903 } else { 1904 err = ERR_CONN; 1905 } 1906#else /* LWIP_TCP */ 1907 err = ERR_VAL; 1908#endif /* LWIP_TCP */ 1909#if (LWIP_UDP || LWIP_RAW) 1910 } else { 1911 err = ERR_VAL; 1912#endif /* (LWIP_UDP || LWIP_RAW) */ 1913 } 1914 } 1915 msg->err = err; 1916 TCPIP_APIMSG_ACK(msg); 1917} 1918 1919/** 1920 * Return a connection's local or remote address 1921 * Called from netconn_getaddr 1922 * 1923 * @param m the api_msg pointing to the connection 1924 */ 1925void 1926lwip_netconn_do_getaddr(void *m) 1927{ 1928 struct api_msg *msg = (struct api_msg *)m; 1929 1930 if (msg->conn->pcb.ip != NULL) { 1931 if (msg->msg.ad.local) { 1932 ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), 1933 msg->conn->pcb.ip->local_ip); 1934 } else { 1935 ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), 1936 msg->conn->pcb.ip->remote_ip); 1937 } 1938 1939 msg->err = ERR_OK; 1940 switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1941#if LWIP_RAW 1942 case NETCONN_RAW: 1943 if (msg->msg.ad.local) { 1944 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; 1945 } else { 1946 /* return an error as connecting is only a helper for upper layers */ 1947 msg->err = ERR_CONN; 1948 } 1949 break; 1950#endif /* LWIP_RAW */ 1951#if LWIP_UDP 1952 case NETCONN_UDP: 1953 if (msg->msg.ad.local) { 1954 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; 1955 } else { 1956 if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { 1957 msg->err = ERR_CONN; 1958 } else { 1959 API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; 1960 } 1961 } 1962 break; 1963#endif /* LWIP_UDP */ 1964#if LWIP_TCP 1965 case NETCONN_TCP: 1966 if ((msg->msg.ad.local == 0) && 1967 ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) { 1968 /* pcb is not connected and remote name is requested */ 1969 msg->err = ERR_CONN; 1970 } else { 1971 API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port); 1972 } 1973 break; 1974#endif /* LWIP_TCP */ 1975 default: 1976 LWIP_ASSERT("invalid netconn_type", 0); 1977 break; 1978 } 1979 } else { 1980 msg->err = ERR_CONN; 1981 } 1982 TCPIP_APIMSG_ACK(msg); 1983} 1984 1985/** 1986 * Close or half-shutdown a TCP pcb contained in a netconn 1987 * Called from netconn_close 1988 * In contrast to closing sockets, the netconn is not deallocated. 1989 * 1990 * @param m the api_msg pointing to the connection 1991 */ 1992void 1993lwip_netconn_do_close(void *m) 1994{ 1995 struct api_msg *msg = (struct api_msg *)m; 1996 1997#if LWIP_TCP 1998 enum netconn_state state = msg->conn->state; 1999 /* First check if this is a TCP netconn and if it is in a correct state 2000 (LISTEN doesn't support half shutdown) */ 2001 if ((msg->conn->pcb.tcp != NULL) && 2002 (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) && 2003 ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) { 2004 /* Check if we are in a connected state */ 2005 if (state == NETCONN_CONNECT) { 2006 /* TCP connect in progress: cannot shutdown */ 2007 msg->err = ERR_CONN; 2008 } else if (state == NETCONN_WRITE) { 2009#if LWIP_NETCONN_FULLDUPLEX 2010 if (msg->msg.sd.shut & NETCONN_SHUT_WR) { 2011 /* close requested, abort running write */ 2012 sys_sem_t *write_completed_sem; 2013 LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL); 2014 write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg); 2015 msg->conn->current_msg->err = ERR_CLSD; 2016 msg->conn->current_msg = NULL; 2017 msg->conn->state = NETCONN_NONE; 2018 state = NETCONN_NONE; 2019 sys_sem_signal(write_completed_sem); 2020 } else { 2021 LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD); 2022 /* In this case, let the write continue and do not interfere with 2023 conn->current_msg or conn->state! */ 2024 msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0); 2025 } 2026 } 2027 if (state == NETCONN_NONE) { 2028#else /* LWIP_NETCONN_FULLDUPLEX */ 2029 msg->err = ERR_INPROGRESS; 2030 } else { 2031#endif /* LWIP_NETCONN_FULLDUPLEX */ 2032 if (msg->msg.sd.shut & NETCONN_SHUT_RD) { 2033#if LWIP_NETCONN_FULLDUPLEX 2034 /* Mark mboxes invalid */ 2035 netconn_mark_mbox_invalid(msg->conn); 2036#else /* LWIP_NETCONN_FULLDUPLEX */ 2037 netconn_drain(msg->conn); 2038#endif /* LWIP_NETCONN_FULLDUPLEX */ 2039 } 2040 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL); 2041 msg->conn->state = NETCONN_CLOSE; 2042 msg->conn->current_msg = msg; 2043#if LWIP_TCPIP_CORE_LOCKING 2044 if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) { 2045 LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE); 2046 UNLOCK_TCPIP_CORE(); 2047 sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 2048 LOCK_TCPIP_CORE(); 2049 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); 2050 } 2051#else /* LWIP_TCPIP_CORE_LOCKING */ 2052 lwip_netconn_do_close_internal(msg->conn); 2053#endif /* LWIP_TCPIP_CORE_LOCKING */ 2054 /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */ 2055 return; 2056 } 2057 } else 2058#endif /* LWIP_TCP */ 2059 { 2060 msg->err = ERR_CONN; 2061 } 2062 TCPIP_APIMSG_ACK(msg); 2063} 2064 2065#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) 2066/** 2067 * Join multicast groups for UDP netconns. 2068 * Called from netconn_join_leave_group 2069 * 2070 * @param m the api_msg pointing to the connection 2071 */ 2072void 2073lwip_netconn_do_join_leave_group(void *m) 2074{ 2075 struct api_msg *msg = (struct api_msg *)m; 2076 2077 msg->err = ERR_CONN; 2078 if (msg->conn->pcb.tcp != NULL) { 2079 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 2080#if LWIP_UDP 2081#if LWIP_IPV6 && LWIP_IPV6_MLD 2082 if (NETCONNTYPE_ISIPV6(msg->conn->type)) { 2083 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 2084 msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), 2085 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); 2086 } else { 2087 msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), 2088 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); 2089 } 2090 } else 2091#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ 2092 { 2093#if LWIP_IGMP 2094 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 2095 msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), 2096 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); 2097 } else { 2098 msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), 2099 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); 2100 } 2101#endif /* LWIP_IGMP */ 2102 } 2103#endif /* LWIP_UDP */ 2104#if (LWIP_TCP || LWIP_RAW) 2105 } else { 2106 msg->err = ERR_VAL; 2107#endif /* (LWIP_TCP || LWIP_RAW) */ 2108 } 2109 } 2110 TCPIP_APIMSG_ACK(msg); 2111} 2112/** 2113 * Join multicast groups for UDP netconns. 2114 * Called from netconn_join_leave_group_netif 2115 * 2116 * @param m the api_msg pointing to the connection 2117 */ 2118void 2119lwip_netconn_do_join_leave_group_netif(void *m) 2120{ 2121 struct api_msg *msg = (struct api_msg *)m; 2122 struct netif *netif; 2123#ifdef LOSCFG_NET_CONTAINER 2124 struct net_group *group = get_net_group_from_ippcb(msg->conn->pcb.ip); 2125 2126 if (group != NULL) { 2127 netif = netif_get_by_index(msg->msg.jl.if_idx, group); 2128 } else { 2129 netif = NULL; 2130 } 2131#else 2132 netif = netif_get_by_index(msg->msg.jl.if_idx); 2133#endif 2134 2135 if (netif == NULL) { 2136 msg->err = ERR_IF; 2137 goto done; 2138 } 2139 2140 msg->err = ERR_CONN; 2141 if (msg->conn->pcb.tcp != NULL) { 2142 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 2143#if LWIP_UDP 2144#if LWIP_IPV6 && LWIP_IPV6_MLD 2145 if (NETCONNTYPE_ISIPV6(msg->conn->type)) { 2146 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 2147 msg->err = mld6_joingroup_netif(netif, 2148 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); 2149 } else { 2150 msg->err = mld6_leavegroup_netif(netif, 2151 ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); 2152 } 2153 } else 2154#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ 2155 { 2156#if LWIP_IGMP 2157 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 2158 msg->err = igmp_joingroup_netif(netif, 2159 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); 2160 } else { 2161 msg->err = igmp_leavegroup_netif(netif, 2162 ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); 2163 } 2164#endif /* LWIP_IGMP */ 2165 } 2166#endif /* LWIP_UDP */ 2167#if (LWIP_TCP || LWIP_RAW) 2168 } else { 2169 msg->err = ERR_VAL; 2170#endif /* (LWIP_TCP || LWIP_RAW) */ 2171 } 2172 } 2173 2174done: 2175 TCPIP_APIMSG_ACK(msg); 2176} 2177#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ 2178 2179#if LWIP_DNS 2180/** 2181 * Callback function that is called when DNS name is resolved 2182 * (or on timeout). A waiting application thread is waked up by 2183 * signaling the semaphore. 2184 */ 2185static void 2186lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg) 2187{ 2188 struct dns_api_msg *msg = (struct dns_api_msg *)arg; 2189 2190 /* we trust the internal implementation to be correct :-) */ 2191 LWIP_UNUSED_ARG(name); 2192 2193 if (ipaddr == NULL) { 2194 /* timeout or memory error */ 2195 API_EXPR_DEREF(msg->err) = ERR_VAL; 2196 } else { 2197 /* address was resolved */ 2198 API_EXPR_DEREF(msg->err) = ERR_OK; 2199 API_EXPR_DEREF(msg->addr) = *ipaddr; 2200 } 2201 /* wake up the application task waiting in netconn_gethostbyname */ 2202 sys_sem_signal(API_EXPR_REF_SEM(msg->sem)); 2203} 2204 2205/** 2206 * Execute a DNS query 2207 * Called from netconn_gethostbyname 2208 * 2209 * @param arg the dns_api_msg pointing to the query 2210 */ 2211void 2212lwip_netconn_do_gethostbyname(void *arg) 2213{ 2214 struct dns_api_msg *msg = (struct dns_api_msg *)arg; 2215 u8_t addrtype = 2216#if LWIP_IPV4 && LWIP_IPV6 2217 msg->dns_addrtype; 2218#else 2219 LWIP_DNS_ADDRTYPE_DEFAULT; 2220#endif 2221 2222 API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name, 2223 API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype); 2224#if LWIP_TCPIP_CORE_LOCKING 2225 /* For core locking, only block if we need to wait for answer/timeout */ 2226 if (API_EXPR_DEREF(msg->err) == ERR_INPROGRESS) { 2227 UNLOCK_TCPIP_CORE(); 2228 sys_sem_wait(API_EXPR_REF_SEM(msg->sem)); 2229 LOCK_TCPIP_CORE(); 2230 LWIP_ASSERT("do_gethostbyname still in progress!!", API_EXPR_DEREF(msg->err) != ERR_INPROGRESS); 2231 } 2232#else /* LWIP_TCPIP_CORE_LOCKING */ 2233 if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) { 2234 /* on error or immediate success, wake up the application 2235 * task waiting in netconn_gethostbyname */ 2236 sys_sem_signal(API_EXPR_REF_SEM(msg->sem)); 2237 } 2238#endif /* LWIP_TCPIP_CORE_LOCKING */ 2239} 2240#endif /* LWIP_DNS */ 2241 2242#endif /* LWIP_NETCONN */ 2243