1195972f6Sopenharmony_ci/** 2195972f6Sopenharmony_ci * @file 3195972f6Sopenharmony_ci * Sequential API Internal module 4195972f6Sopenharmony_ci * 5195972f6Sopenharmony_ci */ 6195972f6Sopenharmony_ci 7195972f6Sopenharmony_ci/* 8195972f6Sopenharmony_ci * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 9195972f6Sopenharmony_ci * All rights reserved. 10195972f6Sopenharmony_ci * 11195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 12195972f6Sopenharmony_ci * are permitted provided that the following conditions are met: 13195972f6Sopenharmony_ci * 14195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, 15195972f6Sopenharmony_ci * this list of conditions and the following disclaimer. 16195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, 17195972f6Sopenharmony_ci * this list of conditions and the following disclaimer in the documentation 18195972f6Sopenharmony_ci * and/or other materials provided with the distribution. 19195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products 20195972f6Sopenharmony_ci * derived from this software without specific prior written permission. 21195972f6Sopenharmony_ci * 22195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 23195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 24195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 25195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 27195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 30195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 31195972f6Sopenharmony_ci * OF SUCH DAMAGE. 32195972f6Sopenharmony_ci * 33195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack. 34195972f6Sopenharmony_ci * 35195972f6Sopenharmony_ci * Author: Adam Dunkels <adam@sics.se> 36195972f6Sopenharmony_ci * 37195972f6Sopenharmony_ci */ 38195972f6Sopenharmony_ci 39195972f6Sopenharmony_ci#include "lwip/opt.h" 40195972f6Sopenharmony_ci 41195972f6Sopenharmony_ci#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ 42195972f6Sopenharmony_ci 43195972f6Sopenharmony_ci#include "lwip/priv/api_msg.h" 44195972f6Sopenharmony_ci 45195972f6Sopenharmony_ci#include "lwip/ip.h" 46195972f6Sopenharmony_ci#include "lwip/ip_addr.h" 47195972f6Sopenharmony_ci#include "lwip/udp.h" 48195972f6Sopenharmony_ci#include "lwip/tcp.h" 49195972f6Sopenharmony_ci#include "lwip/raw.h" 50195972f6Sopenharmony_ci 51195972f6Sopenharmony_ci#include "lwip/memp.h" 52195972f6Sopenharmony_ci#include "lwip/igmp.h" 53195972f6Sopenharmony_ci#include "lwip/dns.h" 54195972f6Sopenharmony_ci#include "lwip/mld6.h" 55195972f6Sopenharmony_ci#include "lwip/priv/tcpip_priv.h" 56195972f6Sopenharmony_ci 57195972f6Sopenharmony_ci#include <string.h> 58195972f6Sopenharmony_ci 59195972f6Sopenharmony_ci/* netconns are polled once per second (e.g. continue write on memory error) */ 60195972f6Sopenharmony_ci#define NETCONN_TCP_POLL_INTERVAL 2 61195972f6Sopenharmony_ci 62195972f6Sopenharmony_ci#define SET_NONBLOCKING_CONNECT(conn, val) do { if (val) { \ 63195972f6Sopenharmony_ci netconn_set_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); \ 64195972f6Sopenharmony_ci} else { \ 65195972f6Sopenharmony_ci netconn_clear_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); }} while(0) 66195972f6Sopenharmony_ci#define IN_NONBLOCKING_CONNECT(conn) netconn_is_flag_set(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT) 67195972f6Sopenharmony_ci 68195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 69195972f6Sopenharmony_ci#define NETCONN_MBOX_VALID(conn, mbox) (sys_mbox_valid(mbox) && ((conn->flags & NETCONN_FLAG_MBOXINVALID) == 0)) 70195972f6Sopenharmony_ci#else 71195972f6Sopenharmony_ci#define NETCONN_MBOX_VALID(conn, mbox) sys_mbox_valid(mbox) 72195972f6Sopenharmony_ci#endif 73195972f6Sopenharmony_ci 74195972f6Sopenharmony_ci/* forward declarations */ 75195972f6Sopenharmony_ci#if LWIP_TCP 76195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 77195972f6Sopenharmony_ci#define WRITE_DELAYED , 1 78195972f6Sopenharmony_ci#define WRITE_DELAYED_PARAM , u8_t delayed 79195972f6Sopenharmony_ci#else /* LWIP_TCPIP_CORE_LOCKING */ 80195972f6Sopenharmony_ci#define WRITE_DELAYED 81195972f6Sopenharmony_ci#define WRITE_DELAYED_PARAM 82195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */ 83195972f6Sopenharmony_cistatic err_t lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM); 84195972f6Sopenharmony_cistatic err_t lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM); 85195972f6Sopenharmony_ci#endif 86195972f6Sopenharmony_ci 87195972f6Sopenharmony_cistatic void netconn_drain(struct netconn *conn); 88195972f6Sopenharmony_ci 89195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 90195972f6Sopenharmony_ci#define TCPIP_APIMSG_ACK(m) 91195972f6Sopenharmony_ci#else /* LWIP_TCPIP_CORE_LOCKING */ 92195972f6Sopenharmony_ci#define TCPIP_APIMSG_ACK(m) do { sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0) 93195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */ 94195972f6Sopenharmony_ci 95195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 96195972f6Sopenharmony_ciconst u8_t netconn_deleted = 0; 97195972f6Sopenharmony_ci 98195972f6Sopenharmony_ciint 99195972f6Sopenharmony_cilwip_netconn_is_deallocated_msg(void *msg) 100195972f6Sopenharmony_ci{ 101195972f6Sopenharmony_ci if (msg == &netconn_deleted) { 102195972f6Sopenharmony_ci return 1; 103195972f6Sopenharmony_ci } 104195972f6Sopenharmony_ci return 0; 105195972f6Sopenharmony_ci} 106195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */ 107195972f6Sopenharmony_ci 108195972f6Sopenharmony_ci#if LWIP_TCP 109195972f6Sopenharmony_ciconst u8_t netconn_aborted = 0; 110195972f6Sopenharmony_ciconst u8_t netconn_reset = 0; 111195972f6Sopenharmony_ciconst u8_t netconn_closed = 0; 112195972f6Sopenharmony_ci 113195972f6Sopenharmony_ci/** Translate an error to a unique void* passed via an mbox */ 114195972f6Sopenharmony_cistatic void * 115195972f6Sopenharmony_cilwip_netconn_err_to_msg(err_t err) 116195972f6Sopenharmony_ci{ 117195972f6Sopenharmony_ci switch (err) { 118195972f6Sopenharmony_ci case ERR_ABRT: 119195972f6Sopenharmony_ci return LWIP_CONST_CAST(void *, &netconn_aborted); 120195972f6Sopenharmony_ci case ERR_RST: 121195972f6Sopenharmony_ci return LWIP_CONST_CAST(void *, &netconn_reset); 122195972f6Sopenharmony_ci case ERR_CLSD: 123195972f6Sopenharmony_ci return LWIP_CONST_CAST(void *, &netconn_closed); 124195972f6Sopenharmony_ci default: 125195972f6Sopenharmony_ci LWIP_ASSERT("unhandled error", err == ERR_OK); 126195972f6Sopenharmony_ci return NULL; 127195972f6Sopenharmony_ci } 128195972f6Sopenharmony_ci} 129195972f6Sopenharmony_ci 130195972f6Sopenharmony_ciint 131195972f6Sopenharmony_cilwip_netconn_is_err_msg(void *msg, err_t *err) 132195972f6Sopenharmony_ci{ 133195972f6Sopenharmony_ci LWIP_ASSERT("err != NULL", err != NULL); 134195972f6Sopenharmony_ci 135195972f6Sopenharmony_ci if (msg == &netconn_aborted) { 136195972f6Sopenharmony_ci *err = ERR_ABRT; 137195972f6Sopenharmony_ci return 1; 138195972f6Sopenharmony_ci } else if (msg == &netconn_reset) { 139195972f6Sopenharmony_ci *err = ERR_RST; 140195972f6Sopenharmony_ci return 1; 141195972f6Sopenharmony_ci } else if (msg == &netconn_closed) { 142195972f6Sopenharmony_ci *err = ERR_CLSD; 143195972f6Sopenharmony_ci return 1; 144195972f6Sopenharmony_ci } 145195972f6Sopenharmony_ci return 0; 146195972f6Sopenharmony_ci} 147195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 148195972f6Sopenharmony_ci 149195972f6Sopenharmony_ci 150195972f6Sopenharmony_ci#if LWIP_RAW 151195972f6Sopenharmony_ci/** 152195972f6Sopenharmony_ci * Receive callback function for RAW netconns. 153195972f6Sopenharmony_ci * Doesn't 'eat' the packet, only copies it and sends it to 154195972f6Sopenharmony_ci * conn->recvmbox 155195972f6Sopenharmony_ci * 156195972f6Sopenharmony_ci * @see raw.h (struct raw_pcb.recv) for parameters and return value 157195972f6Sopenharmony_ci */ 158195972f6Sopenharmony_cistatic u8_t 159195972f6Sopenharmony_cirecv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, 160195972f6Sopenharmony_ci const ip_addr_t *addr) 161195972f6Sopenharmony_ci{ 162195972f6Sopenharmony_ci struct pbuf *q; 163195972f6Sopenharmony_ci struct netbuf *buf; 164195972f6Sopenharmony_ci struct netconn *conn; 165195972f6Sopenharmony_ci 166195972f6Sopenharmony_ci LWIP_UNUSED_ARG(addr); 167195972f6Sopenharmony_ci conn = (struct netconn *)arg; 168195972f6Sopenharmony_ci 169195972f6Sopenharmony_ci if ((conn != NULL) && NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { 170195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF 171195972f6Sopenharmony_ci int recv_avail; 172195972f6Sopenharmony_ci SYS_ARCH_GET(conn->recv_avail, recv_avail); 173195972f6Sopenharmony_ci if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) { 174195972f6Sopenharmony_ci return 0; 175195972f6Sopenharmony_ci } 176195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */ 177195972f6Sopenharmony_ci /* copy the whole packet into new pbufs */ 178195972f6Sopenharmony_ci q = pbuf_clone(PBUF_RAW, PBUF_RAM, p); 179195972f6Sopenharmony_ci if (q != NULL) { 180195972f6Sopenharmony_ci u16_t len; 181195972f6Sopenharmony_ci buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 182195972f6Sopenharmony_ci if (buf == NULL) { 183195972f6Sopenharmony_ci pbuf_free(q); 184195972f6Sopenharmony_ci return 0; 185195972f6Sopenharmony_ci } 186195972f6Sopenharmony_ci 187195972f6Sopenharmony_ci buf->p = q; 188195972f6Sopenharmony_ci buf->ptr = q; 189195972f6Sopenharmony_ci ip_addr_copy(buf->addr, *ip_current_src_addr()); 190195972f6Sopenharmony_ci buf->port = pcb->protocol; 191195972f6Sopenharmony_ci 192195972f6Sopenharmony_ci len = q->tot_len; 193195972f6Sopenharmony_ci if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { 194195972f6Sopenharmony_ci netbuf_delete(buf); 195195972f6Sopenharmony_ci return 0; 196195972f6Sopenharmony_ci } else { 197195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF 198195972f6Sopenharmony_ci SYS_ARCH_INC(conn->recv_avail, len); 199195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */ 200195972f6Sopenharmony_ci /* Register event with callback */ 201195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 202195972f6Sopenharmony_ci } 203195972f6Sopenharmony_ci } 204195972f6Sopenharmony_ci } 205195972f6Sopenharmony_ci 206195972f6Sopenharmony_ci return 0; /* do not eat the packet */ 207195972f6Sopenharmony_ci} 208195972f6Sopenharmony_ci#endif /* LWIP_RAW*/ 209195972f6Sopenharmony_ci 210195972f6Sopenharmony_ci#if LWIP_UDP 211195972f6Sopenharmony_ci/** 212195972f6Sopenharmony_ci * Receive callback function for UDP netconns. 213195972f6Sopenharmony_ci * Posts the packet to conn->recvmbox or deletes it on memory error. 214195972f6Sopenharmony_ci * 215195972f6Sopenharmony_ci * @see udp.h (struct udp_pcb.recv) for parameters 216195972f6Sopenharmony_ci */ 217195972f6Sopenharmony_cistatic void 218195972f6Sopenharmony_cirecv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, 219195972f6Sopenharmony_ci const ip_addr_t *addr, u16_t port) 220195972f6Sopenharmony_ci{ 221195972f6Sopenharmony_ci struct netbuf *buf; 222195972f6Sopenharmony_ci struct netconn *conn; 223195972f6Sopenharmony_ci u16_t len; 224195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF 225195972f6Sopenharmony_ci int recv_avail; 226195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */ 227195972f6Sopenharmony_ci 228195972f6Sopenharmony_ci LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ 229195972f6Sopenharmony_ci LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); 230195972f6Sopenharmony_ci LWIP_ASSERT("recv_udp must have an argument", arg != NULL); 231195972f6Sopenharmony_ci conn = (struct netconn *)arg; 232195972f6Sopenharmony_ci 233195972f6Sopenharmony_ci if (conn == NULL) { 234195972f6Sopenharmony_ci pbuf_free(p); 235195972f6Sopenharmony_ci return; 236195972f6Sopenharmony_ci } 237195972f6Sopenharmony_ci 238195972f6Sopenharmony_ci LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); 239195972f6Sopenharmony_ci 240195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF 241195972f6Sopenharmony_ci SYS_ARCH_GET(conn->recv_avail, recv_avail); 242195972f6Sopenharmony_ci if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox) || 243195972f6Sopenharmony_ci ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { 244195972f6Sopenharmony_ci#else /* LWIP_SO_RCVBUF */ 245195972f6Sopenharmony_ci if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { 246195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */ 247195972f6Sopenharmony_ci pbuf_free(p); 248195972f6Sopenharmony_ci return; 249195972f6Sopenharmony_ci } 250195972f6Sopenharmony_ci 251195972f6Sopenharmony_ci buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); 252195972f6Sopenharmony_ci if (buf == NULL) { 253195972f6Sopenharmony_ci pbuf_free(p); 254195972f6Sopenharmony_ci return; 255195972f6Sopenharmony_ci } else { 256195972f6Sopenharmony_ci buf->p = p; 257195972f6Sopenharmony_ci buf->ptr = p; 258195972f6Sopenharmony_ci ip_addr_set(&buf->addr, addr); 259195972f6Sopenharmony_ci buf->port = port; 260195972f6Sopenharmony_ci#if LWIP_NETBUF_RECVINFO 261195972f6Sopenharmony_ci if (conn->flags & NETCONN_FLAG_PKTINFO) { 262195972f6Sopenharmony_ci /* get the UDP header - always in the first pbuf, ensured by udp_input */ 263195972f6Sopenharmony_ci const struct udp_hdr *udphdr = (const struct udp_hdr *)ip_next_header_ptr(); 264195972f6Sopenharmony_ci buf->flags = NETBUF_FLAG_DESTADDR; 265195972f6Sopenharmony_ci ip_addr_set(&buf->toaddr, ip_current_dest_addr()); 266195972f6Sopenharmony_ci buf->toport_chksum = udphdr->dest; 267195972f6Sopenharmony_ci } 268195972f6Sopenharmony_ci#endif /* LWIP_NETBUF_RECVINFO */ 269195972f6Sopenharmony_ci } 270195972f6Sopenharmony_ci 271195972f6Sopenharmony_ci len = p->tot_len; 272195972f6Sopenharmony_ci if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { 273195972f6Sopenharmony_ci netbuf_delete(buf); 274195972f6Sopenharmony_ci return; 275195972f6Sopenharmony_ci } else { 276195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF 277195972f6Sopenharmony_ci SYS_ARCH_INC(conn->recv_avail, len); 278195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */ 279195972f6Sopenharmony_ci /* Register event with callback */ 280195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 281195972f6Sopenharmony_ci } 282195972f6Sopenharmony_ci} 283195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 284195972f6Sopenharmony_ci 285195972f6Sopenharmony_ci#if LWIP_TCP 286195972f6Sopenharmony_ci/** 287195972f6Sopenharmony_ci * Receive callback function for TCP netconns. 288195972f6Sopenharmony_ci * Posts the packet to conn->recvmbox, but doesn't delete it on errors. 289195972f6Sopenharmony_ci * 290195972f6Sopenharmony_ci * @see tcp.h (struct tcp_pcb.recv) for parameters and return value 291195972f6Sopenharmony_ci */ 292195972f6Sopenharmony_cistatic err_t 293195972f6Sopenharmony_cirecv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) 294195972f6Sopenharmony_ci{ 295195972f6Sopenharmony_ci struct netconn *conn; 296195972f6Sopenharmony_ci u16_t len; 297195972f6Sopenharmony_ci void *msg; 298195972f6Sopenharmony_ci 299195972f6Sopenharmony_ci LWIP_UNUSED_ARG(pcb); 300195972f6Sopenharmony_ci LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); 301195972f6Sopenharmony_ci LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); 302195972f6Sopenharmony_ci LWIP_ASSERT("err != ERR_OK unhandled", err == ERR_OK); 303195972f6Sopenharmony_ci LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */ 304195972f6Sopenharmony_ci conn = (struct netconn *)arg; 305195972f6Sopenharmony_ci 306195972f6Sopenharmony_ci if (conn == NULL) { 307195972f6Sopenharmony_ci return ERR_VAL; 308195972f6Sopenharmony_ci } 309195972f6Sopenharmony_ci LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); 310195972f6Sopenharmony_ci 311195972f6Sopenharmony_ci if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { 312195972f6Sopenharmony_ci /* recvmbox already deleted */ 313195972f6Sopenharmony_ci if (p != NULL) { 314195972f6Sopenharmony_ci tcp_recved(pcb, p->tot_len); 315195972f6Sopenharmony_ci pbuf_free(p); 316195972f6Sopenharmony_ci } 317195972f6Sopenharmony_ci return ERR_OK; 318195972f6Sopenharmony_ci } 319195972f6Sopenharmony_ci /* Unlike for UDP or RAW pcbs, don't check for available space 320195972f6Sopenharmony_ci using recv_avail since that could break the connection 321195972f6Sopenharmony_ci (data is already ACKed) */ 322195972f6Sopenharmony_ci 323195972f6Sopenharmony_ci if (p != NULL) { 324195972f6Sopenharmony_ci msg = p; 325195972f6Sopenharmony_ci len = p->tot_len; 326195972f6Sopenharmony_ci } else { 327195972f6Sopenharmony_ci msg = LWIP_CONST_CAST(void *, &netconn_closed); 328195972f6Sopenharmony_ci len = 0; 329195972f6Sopenharmony_ci } 330195972f6Sopenharmony_ci 331195972f6Sopenharmony_ci if (sys_mbox_trypost(&conn->recvmbox, msg) != ERR_OK) { 332195972f6Sopenharmony_ci /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */ 333195972f6Sopenharmony_ci return ERR_MEM; 334195972f6Sopenharmony_ci } else { 335195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF 336195972f6Sopenharmony_ci SYS_ARCH_INC(conn->recv_avail, len); 337195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */ 338195972f6Sopenharmony_ci /* Register event with callback */ 339195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); 340195972f6Sopenharmony_ci } 341195972f6Sopenharmony_ci 342195972f6Sopenharmony_ci return ERR_OK; 343195972f6Sopenharmony_ci} 344195972f6Sopenharmony_ci 345195972f6Sopenharmony_ci/** 346195972f6Sopenharmony_ci * Poll callback function for TCP netconns. 347195972f6Sopenharmony_ci * Wakes up an application thread that waits for a connection to close 348195972f6Sopenharmony_ci * or data to be sent. The application thread then takes the 349195972f6Sopenharmony_ci * appropriate action to go on. 350195972f6Sopenharmony_ci * 351195972f6Sopenharmony_ci * Signals the conn->sem. 352195972f6Sopenharmony_ci * netconn_close waits for conn->sem if closing failed. 353195972f6Sopenharmony_ci * 354195972f6Sopenharmony_ci * @see tcp.h (struct tcp_pcb.poll) for parameters and return value 355195972f6Sopenharmony_ci */ 356195972f6Sopenharmony_cistatic err_t 357195972f6Sopenharmony_cipoll_tcp(void *arg, struct tcp_pcb *pcb) 358195972f6Sopenharmony_ci{ 359195972f6Sopenharmony_ci struct netconn *conn = (struct netconn *)arg; 360195972f6Sopenharmony_ci 361195972f6Sopenharmony_ci LWIP_UNUSED_ARG(pcb); 362195972f6Sopenharmony_ci LWIP_ASSERT("conn != NULL", (conn != NULL)); 363195972f6Sopenharmony_ci 364195972f6Sopenharmony_ci if (conn->state == NETCONN_WRITE) { 365195972f6Sopenharmony_ci lwip_netconn_do_writemore(conn WRITE_DELAYED); 366195972f6Sopenharmony_ci } else if (conn->state == NETCONN_CLOSE) { 367195972f6Sopenharmony_ci#if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER 368195972f6Sopenharmony_ci if (conn->current_msg && conn->current_msg->msg.sd.polls_left) { 369195972f6Sopenharmony_ci conn->current_msg->msg.sd.polls_left--; 370195972f6Sopenharmony_ci } 371195972f6Sopenharmony_ci#endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */ 372195972f6Sopenharmony_ci lwip_netconn_do_close_internal(conn WRITE_DELAYED); 373195972f6Sopenharmony_ci } 374195972f6Sopenharmony_ci /* @todo: implement connect timeout here? */ 375195972f6Sopenharmony_ci 376195972f6Sopenharmony_ci /* Did a nonblocking write fail before? Then check available write-space. */ 377195972f6Sopenharmony_ci if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) { 378195972f6Sopenharmony_ci /* If the queued byte- or pbuf-count drops below the configured low-water limit, 379195972f6Sopenharmony_ci let select mark this pcb as writable again. */ 380195972f6Sopenharmony_ci if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && 381195972f6Sopenharmony_ci (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { 382195972f6Sopenharmony_ci netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE); 383195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 384195972f6Sopenharmony_ci } 385195972f6Sopenharmony_ci } 386195972f6Sopenharmony_ci 387195972f6Sopenharmony_ci return ERR_OK; 388195972f6Sopenharmony_ci} 389195972f6Sopenharmony_ci 390195972f6Sopenharmony_ci#if LWIP_LOWPOWER 391195972f6Sopenharmony_ci/* check wether need to poll tcp */ 392195972f6Sopenharmony_ciu8_t 393195972f6Sopenharmony_cipoll_tcp_needed(void *arg, struct tcp_pcb *pcb) 394195972f6Sopenharmony_ci{ 395195972f6Sopenharmony_ci struct netconn *conn = (struct netconn *)arg; 396195972f6Sopenharmony_ci u8_t ret = 0; 397195972f6Sopenharmony_ci 398195972f6Sopenharmony_ci LWIP_UNUSED_ARG(pcb); 399195972f6Sopenharmony_ci if (conn == NULL) { 400195972f6Sopenharmony_ci return 0; 401195972f6Sopenharmony_ci } 402195972f6Sopenharmony_ci if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) { 403195972f6Sopenharmony_ci ret = 1; 404195972f6Sopenharmony_ci } 405195972f6Sopenharmony_ci 406195972f6Sopenharmony_ci /* Did a nonblocking write fail before? Then check available write-space. */ 407195972f6Sopenharmony_ci if ((conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) != 0) { 408195972f6Sopenharmony_ci /* If the queued byte- or pbuf-count drops below the configured low-water limit, 409195972f6Sopenharmony_ci let select mark this pcb as writable again. */ 410195972f6Sopenharmony_ci if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && 411195972f6Sopenharmony_ci (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { 412195972f6Sopenharmony_ci ret = 1; 413195972f6Sopenharmony_ci } 414195972f6Sopenharmony_ci } 415195972f6Sopenharmony_ci return ret; 416195972f6Sopenharmony_ci} 417195972f6Sopenharmony_ci#endif /* LWIP_LOWPOWER */ 418195972f6Sopenharmony_ci 419195972f6Sopenharmony_ci/** 420195972f6Sopenharmony_ci * Sent callback function for TCP netconns. 421195972f6Sopenharmony_ci * Signals the conn->sem and calls API_EVENT. 422195972f6Sopenharmony_ci * netconn_write waits for conn->sem if send buffer is low. 423195972f6Sopenharmony_ci * 424195972f6Sopenharmony_ci * @see tcp.h (struct tcp_pcb.sent) for parameters and return value 425195972f6Sopenharmony_ci */ 426195972f6Sopenharmony_cistatic err_t 427195972f6Sopenharmony_cisent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) 428195972f6Sopenharmony_ci{ 429195972f6Sopenharmony_ci struct netconn *conn = (struct netconn *)arg; 430195972f6Sopenharmony_ci 431195972f6Sopenharmony_ci LWIP_UNUSED_ARG(pcb); 432195972f6Sopenharmony_ci LWIP_ASSERT("conn != NULL", (conn != NULL)); 433195972f6Sopenharmony_ci 434195972f6Sopenharmony_ci if (conn) { 435195972f6Sopenharmony_ci if (conn->state == NETCONN_WRITE) { 436195972f6Sopenharmony_ci lwip_netconn_do_writemore(conn WRITE_DELAYED); 437195972f6Sopenharmony_ci } else if (conn->state == NETCONN_CLOSE) { 438195972f6Sopenharmony_ci lwip_netconn_do_close_internal(conn WRITE_DELAYED); 439195972f6Sopenharmony_ci } 440195972f6Sopenharmony_ci 441195972f6Sopenharmony_ci /* If the queued byte- or pbuf-count drops below the configured low-water limit, 442195972f6Sopenharmony_ci let select mark this pcb as writable again. */ 443195972f6Sopenharmony_ci if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && 444195972f6Sopenharmony_ci (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { 445195972f6Sopenharmony_ci netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE); 446195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); 447195972f6Sopenharmony_ci } 448195972f6Sopenharmony_ci } 449195972f6Sopenharmony_ci 450195972f6Sopenharmony_ci return ERR_OK; 451195972f6Sopenharmony_ci} 452195972f6Sopenharmony_ci 453195972f6Sopenharmony_ci/** 454195972f6Sopenharmony_ci * Error callback function for TCP netconns. 455195972f6Sopenharmony_ci * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. 456195972f6Sopenharmony_ci * The application thread has then to decide what to do. 457195972f6Sopenharmony_ci * 458195972f6Sopenharmony_ci * @see tcp.h (struct tcp_pcb.err) for parameters 459195972f6Sopenharmony_ci */ 460195972f6Sopenharmony_cistatic void 461195972f6Sopenharmony_cierr_tcp(void *arg, err_t err) 462195972f6Sopenharmony_ci{ 463195972f6Sopenharmony_ci struct netconn *conn; 464195972f6Sopenharmony_ci enum netconn_state old_state; 465195972f6Sopenharmony_ci void *mbox_msg; 466195972f6Sopenharmony_ci SYS_ARCH_DECL_PROTECT(lev); 467195972f6Sopenharmony_ci 468195972f6Sopenharmony_ci conn = (struct netconn *)arg; 469195972f6Sopenharmony_ci LWIP_ASSERT("conn != NULL", (conn != NULL)); 470195972f6Sopenharmony_ci 471195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 472195972f6Sopenharmony_ci 473195972f6Sopenharmony_ci /* when err is called, the pcb is deallocated, so delete the reference */ 474195972f6Sopenharmony_ci conn->pcb.tcp = NULL; 475195972f6Sopenharmony_ci /* store pending error */ 476195972f6Sopenharmony_ci conn->pending_err = err; 477195972f6Sopenharmony_ci /* prevent application threads from blocking on 'recvmbox'/'acceptmbox' */ 478195972f6Sopenharmony_ci conn->flags |= NETCONN_FLAG_MBOXCLOSED; 479195972f6Sopenharmony_ci 480195972f6Sopenharmony_ci /* reset conn->state now before waking up other threads */ 481195972f6Sopenharmony_ci old_state = conn->state; 482195972f6Sopenharmony_ci conn->state = NETCONN_NONE; 483195972f6Sopenharmony_ci 484195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 485195972f6Sopenharmony_ci 486195972f6Sopenharmony_ci /* Notify the user layer about a connection error. Used to signal select. */ 487195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_ERROR, 0); 488195972f6Sopenharmony_ci /* Try to release selects pending on 'read' or 'write', too. 489195972f6Sopenharmony_ci They will get an error if they actually try to read or write. */ 490195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 491195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 492195972f6Sopenharmony_ci 493195972f6Sopenharmony_ci mbox_msg = lwip_netconn_err_to_msg(err); 494195972f6Sopenharmony_ci /* pass error message to recvmbox to wake up pending recv */ 495195972f6Sopenharmony_ci if (NETCONN_MBOX_VALID(conn, &conn->recvmbox)) { 496195972f6Sopenharmony_ci /* use trypost to prevent deadlock */ 497195972f6Sopenharmony_ci sys_mbox_trypost(&conn->recvmbox, mbox_msg); 498195972f6Sopenharmony_ci } 499195972f6Sopenharmony_ci /* pass error message to acceptmbox to wake up pending accept */ 500195972f6Sopenharmony_ci if (NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) { 501195972f6Sopenharmony_ci /* use trypost to preven deadlock */ 502195972f6Sopenharmony_ci sys_mbox_trypost(&conn->acceptmbox, mbox_msg); 503195972f6Sopenharmony_ci } 504195972f6Sopenharmony_ci 505195972f6Sopenharmony_ci if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || 506195972f6Sopenharmony_ci (old_state == NETCONN_CONNECT)) { 507195972f6Sopenharmony_ci /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary 508195972f6Sopenharmony_ci since the pcb has already been deleted! */ 509195972f6Sopenharmony_ci int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn); 510195972f6Sopenharmony_ci SET_NONBLOCKING_CONNECT(conn, 0); 511195972f6Sopenharmony_ci 512195972f6Sopenharmony_ci if (!was_nonblocking_connect) { 513195972f6Sopenharmony_ci sys_sem_t *op_completed_sem; 514195972f6Sopenharmony_ci /* set error return code */ 515195972f6Sopenharmony_ci LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 516195972f6Sopenharmony_ci if (old_state == NETCONN_CLOSE) { 517195972f6Sopenharmony_ci /* let close succeed: the connection is closed after all... */ 518195972f6Sopenharmony_ci conn->current_msg->err = ERR_OK; 519195972f6Sopenharmony_ci } else { 520195972f6Sopenharmony_ci /* Write and connect fail */ 521195972f6Sopenharmony_ci conn->current_msg->err = err; 522195972f6Sopenharmony_ci } 523195972f6Sopenharmony_ci op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 524195972f6Sopenharmony_ci LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem)); 525195972f6Sopenharmony_ci conn->current_msg = NULL; 526195972f6Sopenharmony_ci /* wake up the waiting task */ 527195972f6Sopenharmony_ci sys_sem_signal(op_completed_sem); 528195972f6Sopenharmony_ci } else { 529195972f6Sopenharmony_ci /* @todo: test what happens for error on nonblocking connect */ 530195972f6Sopenharmony_ci } 531195972f6Sopenharmony_ci } else { 532195972f6Sopenharmony_ci LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL); 533195972f6Sopenharmony_ci } 534195972f6Sopenharmony_ci} 535195972f6Sopenharmony_ci 536195972f6Sopenharmony_ci/** 537195972f6Sopenharmony_ci * Setup a tcp_pcb with the correct callback function pointers 538195972f6Sopenharmony_ci * and their arguments. 539195972f6Sopenharmony_ci * 540195972f6Sopenharmony_ci * @param conn the TCP netconn to setup 541195972f6Sopenharmony_ci */ 542195972f6Sopenharmony_cistatic void 543195972f6Sopenharmony_cisetup_tcp(struct netconn *conn) 544195972f6Sopenharmony_ci{ 545195972f6Sopenharmony_ci struct tcp_pcb *pcb; 546195972f6Sopenharmony_ci 547195972f6Sopenharmony_ci pcb = conn->pcb.tcp; 548195972f6Sopenharmony_ci tcp_arg(pcb, conn); 549195972f6Sopenharmony_ci tcp_recv(pcb, recv_tcp); 550195972f6Sopenharmony_ci tcp_sent(pcb, sent_tcp); 551195972f6Sopenharmony_ci tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL); 552195972f6Sopenharmony_ci tcp_err(pcb, err_tcp); 553195972f6Sopenharmony_ci} 554195972f6Sopenharmony_ci 555195972f6Sopenharmony_ci/** 556195972f6Sopenharmony_ci * Accept callback function for TCP netconns. 557195972f6Sopenharmony_ci * Allocates a new netconn and posts that to conn->acceptmbox. 558195972f6Sopenharmony_ci * 559195972f6Sopenharmony_ci * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value 560195972f6Sopenharmony_ci */ 561195972f6Sopenharmony_cistatic err_t 562195972f6Sopenharmony_ciaccept_function(void *arg, struct tcp_pcb *newpcb, err_t err) 563195972f6Sopenharmony_ci{ 564195972f6Sopenharmony_ci struct netconn *newconn; 565195972f6Sopenharmony_ci struct netconn *conn = (struct netconn *)arg; 566195972f6Sopenharmony_ci 567195972f6Sopenharmony_ci if (conn == NULL) { 568195972f6Sopenharmony_ci return ERR_VAL; 569195972f6Sopenharmony_ci } 570195972f6Sopenharmony_ci if (!NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) { 571195972f6Sopenharmony_ci LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n")); 572195972f6Sopenharmony_ci return ERR_VAL; 573195972f6Sopenharmony_ci } 574195972f6Sopenharmony_ci 575195972f6Sopenharmony_ci if (newpcb == NULL) { 576195972f6Sopenharmony_ci /* out-of-pcbs during connect: pass on this error to the application */ 577195972f6Sopenharmony_ci if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) { 578195972f6Sopenharmony_ci /* Register event with callback */ 579195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 580195972f6Sopenharmony_ci } 581195972f6Sopenharmony_ci return ERR_VAL; 582195972f6Sopenharmony_ci } 583195972f6Sopenharmony_ci LWIP_ASSERT("expect newpcb == NULL or err == ERR_OK", err == ERR_OK); 584195972f6Sopenharmony_ci LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */ 585195972f6Sopenharmony_ci 586195972f6Sopenharmony_ci LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->state: %s\n", tcp_debug_state_str(newpcb->state))); 587195972f6Sopenharmony_ci 588195972f6Sopenharmony_ci /* We have to set the callback here even though 589195972f6Sopenharmony_ci * the new socket is unknown. newconn->socket is marked as -1. */ 590195972f6Sopenharmony_ci newconn = netconn_alloc(conn->type, conn->callback); 591195972f6Sopenharmony_ci if (newconn == NULL) { 592195972f6Sopenharmony_ci /* outof netconns: pass on this error to the application */ 593195972f6Sopenharmony_ci if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) { 594195972f6Sopenharmony_ci /* Register event with callback */ 595195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 596195972f6Sopenharmony_ci } 597195972f6Sopenharmony_ci return ERR_MEM; 598195972f6Sopenharmony_ci } 599195972f6Sopenharmony_ci newconn->pcb.tcp = newpcb; 600195972f6Sopenharmony_ci setup_tcp(newconn); 601195972f6Sopenharmony_ci 602195972f6Sopenharmony_ci /* handle backlog counter */ 603195972f6Sopenharmony_ci tcp_backlog_delayed(newpcb); 604195972f6Sopenharmony_ci 605195972f6Sopenharmony_ci if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) { 606195972f6Sopenharmony_ci /* When returning != ERR_OK, the pcb is aborted in tcp_process(), 607195972f6Sopenharmony_ci so do nothing here! */ 608195972f6Sopenharmony_ci /* remove all references to this netconn from the pcb */ 609195972f6Sopenharmony_ci struct tcp_pcb *pcb = newconn->pcb.tcp; 610195972f6Sopenharmony_ci tcp_arg(pcb, NULL); 611195972f6Sopenharmony_ci tcp_recv(pcb, NULL); 612195972f6Sopenharmony_ci tcp_sent(pcb, NULL); 613195972f6Sopenharmony_ci tcp_poll(pcb, NULL, 0); 614195972f6Sopenharmony_ci tcp_err(pcb, NULL); 615195972f6Sopenharmony_ci /* remove reference from to the pcb from this netconn */ 616195972f6Sopenharmony_ci newconn->pcb.tcp = NULL; 617195972f6Sopenharmony_ci /* no need to drain since we know the recvmbox is empty. */ 618195972f6Sopenharmony_ci sys_mbox_free(&newconn->recvmbox); 619195972f6Sopenharmony_ci sys_mbox_set_invalid(&newconn->recvmbox); 620195972f6Sopenharmony_ci netconn_free(newconn); 621195972f6Sopenharmony_ci return ERR_MEM; 622195972f6Sopenharmony_ci } else { 623195972f6Sopenharmony_ci /* Register event with callback */ 624195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 625195972f6Sopenharmony_ci } 626195972f6Sopenharmony_ci 627195972f6Sopenharmony_ci return ERR_OK; 628195972f6Sopenharmony_ci} 629195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 630195972f6Sopenharmony_ci 631195972f6Sopenharmony_ci/** 632195972f6Sopenharmony_ci * Create a new pcb of a specific type. 633195972f6Sopenharmony_ci * Called from lwip_netconn_do_newconn(). 634195972f6Sopenharmony_ci * 635195972f6Sopenharmony_ci * @param msg the api_msg describing the connection type 636195972f6Sopenharmony_ci */ 637195972f6Sopenharmony_cistatic void 638195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 639195972f6Sopenharmony_cipcb_new(struct api_msg *msg, struct net_group *group) 640195972f6Sopenharmony_ci#else 641195972f6Sopenharmony_cipcb_new(struct api_msg *msg) 642195972f6Sopenharmony_ci#endif 643195972f6Sopenharmony_ci{ 644195972f6Sopenharmony_ci enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4; 645195972f6Sopenharmony_ci 646195972f6Sopenharmony_ci LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); 647195972f6Sopenharmony_ci 648195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_IPV4 649195972f6Sopenharmony_ci /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */ 650195972f6Sopenharmony_ci if (NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) { 651195972f6Sopenharmony_ci iptype = IPADDR_TYPE_ANY; 652195972f6Sopenharmony_ci } 653195972f6Sopenharmony_ci#endif 654195972f6Sopenharmony_ci 655195972f6Sopenharmony_ci /* Allocate a PCB for this connection */ 656195972f6Sopenharmony_ci switch (NETCONNTYPE_GROUP(msg->conn->type)) { 657195972f6Sopenharmony_ci#if LWIP_RAW 658195972f6Sopenharmony_ci case NETCONN_RAW: 659195972f6Sopenharmony_ci msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto); 660195972f6Sopenharmony_ci if (msg->conn->pcb.raw != NULL) { 661195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 662195972f6Sopenharmony_ci set_raw_pcb_net_group(msg->conn->pcb.raw, group); 663195972f6Sopenharmony_ci#endif 664195972f6Sopenharmony_ci#if LWIP_IPV6 665195972f6Sopenharmony_ci /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */ 666195972f6Sopenharmony_ci if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) { 667195972f6Sopenharmony_ci msg->conn->pcb.raw->chksum_reqd = 1; 668195972f6Sopenharmony_ci msg->conn->pcb.raw->chksum_offset = 2; 669195972f6Sopenharmony_ci } 670195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 671195972f6Sopenharmony_ci raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); 672195972f6Sopenharmony_ci } 673195972f6Sopenharmony_ci break; 674195972f6Sopenharmony_ci#endif /* LWIP_RAW */ 675195972f6Sopenharmony_ci#if LWIP_UDP 676195972f6Sopenharmony_ci case NETCONN_UDP: 677195972f6Sopenharmony_ci msg->conn->pcb.udp = udp_new_ip_type(iptype); 678195972f6Sopenharmony_ci if (msg->conn->pcb.udp != NULL) { 679195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 680195972f6Sopenharmony_ci set_udp_pcb_net_group(msg->conn->pcb.udp, group); 681195972f6Sopenharmony_ci#endif 682195972f6Sopenharmony_ci#if LWIP_UDPLITE 683195972f6Sopenharmony_ci if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) { 684195972f6Sopenharmony_ci udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); 685195972f6Sopenharmony_ci } 686195972f6Sopenharmony_ci#endif /* LWIP_UDPLITE */ 687195972f6Sopenharmony_ci if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) { 688195972f6Sopenharmony_ci udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); 689195972f6Sopenharmony_ci } 690195972f6Sopenharmony_ci udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); 691195972f6Sopenharmony_ci } 692195972f6Sopenharmony_ci break; 693195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 694195972f6Sopenharmony_ci#if LWIP_TCP 695195972f6Sopenharmony_ci case NETCONN_TCP: 696195972f6Sopenharmony_ci msg->conn->pcb.tcp = tcp_new_ip_type(iptype); 697195972f6Sopenharmony_ci if (msg->conn->pcb.tcp != NULL) { 698195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 699195972f6Sopenharmony_ci set_tcp_pcb_net_group(msg->conn->pcb.tcp, group); 700195972f6Sopenharmony_ci#endif 701195972f6Sopenharmony_ci setup_tcp(msg->conn); 702195972f6Sopenharmony_ci } 703195972f6Sopenharmony_ci break; 704195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 705195972f6Sopenharmony_ci default: 706195972f6Sopenharmony_ci /* Unsupported netconn type, e.g. protocol disabled */ 707195972f6Sopenharmony_ci msg->err = ERR_VAL; 708195972f6Sopenharmony_ci return; 709195972f6Sopenharmony_ci } 710195972f6Sopenharmony_ci if (msg->conn->pcb.ip == NULL) { 711195972f6Sopenharmony_ci msg->err = ERR_MEM; 712195972f6Sopenharmony_ci } 713195972f6Sopenharmony_ci} 714195972f6Sopenharmony_ci 715195972f6Sopenharmony_ci/** 716195972f6Sopenharmony_ci * Create a new pcb of a specific type inside a netconn. 717195972f6Sopenharmony_ci * Called from netconn_new_with_proto_and_callback. 718195972f6Sopenharmony_ci * 719195972f6Sopenharmony_ci * @param m the api_msg describing the connection type 720195972f6Sopenharmony_ci */ 721195972f6Sopenharmony_civoid 722195972f6Sopenharmony_cilwip_netconn_do_newconn(void *m) 723195972f6Sopenharmony_ci{ 724195972f6Sopenharmony_ci struct api_msg *msg = (struct api_msg *)m; 725195972f6Sopenharmony_ci 726195972f6Sopenharmony_ci msg->err = ERR_OK; 727195972f6Sopenharmony_ci if (msg->conn->pcb.tcp == NULL) { 728195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 729195972f6Sopenharmony_ci pcb_new(msg, get_curr_process_net_group()); 730195972f6Sopenharmony_ci#else 731195972f6Sopenharmony_ci pcb_new(msg); 732195972f6Sopenharmony_ci#endif 733195972f6Sopenharmony_ci } 734195972f6Sopenharmony_ci /* Else? This "new" connection already has a PCB allocated. */ 735195972f6Sopenharmony_ci /* Is this an error condition? Should it be deleted? */ 736195972f6Sopenharmony_ci /* We currently just are happy and return. */ 737195972f6Sopenharmony_ci 738195972f6Sopenharmony_ci TCPIP_APIMSG_ACK(msg); 739195972f6Sopenharmony_ci} 740195972f6Sopenharmony_ci 741195972f6Sopenharmony_ci/** 742195972f6Sopenharmony_ci * Create a new netconn (of a specific type) that has a callback function. 743195972f6Sopenharmony_ci * The corresponding pcb is NOT created! 744195972f6Sopenharmony_ci * 745195972f6Sopenharmony_ci * @param t the type of 'connection' to create (@see enum netconn_type) 746195972f6Sopenharmony_ci * @param callback a function to call on status changes (RX available, TX'ed) 747195972f6Sopenharmony_ci * @return a newly allocated struct netconn or 748195972f6Sopenharmony_ci * NULL on memory error 749195972f6Sopenharmony_ci */ 750195972f6Sopenharmony_cistruct netconn * 751195972f6Sopenharmony_cinetconn_alloc(enum netconn_type t, netconn_callback callback) 752195972f6Sopenharmony_ci{ 753195972f6Sopenharmony_ci struct netconn *conn; 754195972f6Sopenharmony_ci int size; 755195972f6Sopenharmony_ci u8_t init_flags = 0; 756195972f6Sopenharmony_ci 757195972f6Sopenharmony_ci conn = (struct netconn *)memp_malloc(MEMP_NETCONN); 758195972f6Sopenharmony_ci if (conn == NULL) { 759195972f6Sopenharmony_ci return NULL; 760195972f6Sopenharmony_ci } 761195972f6Sopenharmony_ci 762195972f6Sopenharmony_ci conn->pending_err = ERR_OK; 763195972f6Sopenharmony_ci conn->type = t; 764195972f6Sopenharmony_ci conn->pcb.tcp = NULL; 765195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 766195972f6Sopenharmony_ci conn->mbox_threads_waiting = 0; 767195972f6Sopenharmony_ci#endif 768195972f6Sopenharmony_ci 769195972f6Sopenharmony_ci /* If all sizes are the same, every compiler should optimize this switch to nothing */ 770195972f6Sopenharmony_ci switch (NETCONNTYPE_GROUP(t)) { 771195972f6Sopenharmony_ci#if LWIP_RAW 772195972f6Sopenharmony_ci case NETCONN_RAW: 773195972f6Sopenharmony_ci size = DEFAULT_RAW_RECVMBOX_SIZE; 774195972f6Sopenharmony_ci break; 775195972f6Sopenharmony_ci#endif /* LWIP_RAW */ 776195972f6Sopenharmony_ci#if LWIP_UDP 777195972f6Sopenharmony_ci case NETCONN_UDP: 778195972f6Sopenharmony_ci size = DEFAULT_UDP_RECVMBOX_SIZE; 779195972f6Sopenharmony_ci#if LWIP_NETBUF_RECVINFO 780195972f6Sopenharmony_ci init_flags |= NETCONN_FLAG_PKTINFO; 781195972f6Sopenharmony_ci#endif /* LWIP_NETBUF_RECVINFO */ 782195972f6Sopenharmony_ci break; 783195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 784195972f6Sopenharmony_ci#if LWIP_TCP 785195972f6Sopenharmony_ci case NETCONN_TCP: 786195972f6Sopenharmony_ci size = DEFAULT_TCP_RECVMBOX_SIZE; 787195972f6Sopenharmony_ci break; 788195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 789195972f6Sopenharmony_ci default: 790195972f6Sopenharmony_ci LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); 791195972f6Sopenharmony_ci goto free_and_return; 792195972f6Sopenharmony_ci } 793195972f6Sopenharmony_ci 794195972f6Sopenharmony_ci if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { 795195972f6Sopenharmony_ci goto free_and_return; 796195972f6Sopenharmony_ci } 797195972f6Sopenharmony_ci#if !LWIP_NETCONN_SEM_PER_THREAD 798195972f6Sopenharmony_ci if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { 799195972f6Sopenharmony_ci sys_mbox_free(&conn->recvmbox); 800195972f6Sopenharmony_ci goto free_and_return; 801195972f6Sopenharmony_ci } 802195972f6Sopenharmony_ci#endif 803195972f6Sopenharmony_ci 804195972f6Sopenharmony_ci#if LWIP_TCP 805195972f6Sopenharmony_ci sys_mbox_set_invalid(&conn->acceptmbox); 806195972f6Sopenharmony_ci#endif 807195972f6Sopenharmony_ci conn->state = NETCONN_NONE; 808195972f6Sopenharmony_ci#if LWIP_SOCKET 809195972f6Sopenharmony_ci /* initialize socket to -1 since 0 is a valid socket */ 810195972f6Sopenharmony_ci conn->socket = -1; 811195972f6Sopenharmony_ci#endif /* LWIP_SOCKET */ 812195972f6Sopenharmony_ci conn->callback = callback; 813195972f6Sopenharmony_ci#if LWIP_TCP 814195972f6Sopenharmony_ci conn->current_msg = NULL; 815195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 816195972f6Sopenharmony_ci#if LWIP_SO_SNDTIMEO 817195972f6Sopenharmony_ci conn->send_timeout = 0; 818195972f6Sopenharmony_ci#endif /* LWIP_SO_SNDTIMEO */ 819195972f6Sopenharmony_ci#if LWIP_SO_RCVTIMEO 820195972f6Sopenharmony_ci conn->recv_timeout = 0; 821195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVTIMEO */ 822195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF 823195972f6Sopenharmony_ci conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; 824195972f6Sopenharmony_ci conn->recv_avail = 0; 825195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */ 826195972f6Sopenharmony_ci#if LWIP_SO_LINGER 827195972f6Sopenharmony_ci conn->linger = -1; 828195972f6Sopenharmony_ci#endif /* LWIP_SO_LINGER */ 829195972f6Sopenharmony_ci conn->flags = init_flags; 830195972f6Sopenharmony_ci return conn; 831195972f6Sopenharmony_cifree_and_return: 832195972f6Sopenharmony_ci memp_free(MEMP_NETCONN, conn); 833195972f6Sopenharmony_ci return NULL; 834195972f6Sopenharmony_ci} 835195972f6Sopenharmony_ci 836195972f6Sopenharmony_ci/** 837195972f6Sopenharmony_ci * Delete a netconn and all its resources. 838195972f6Sopenharmony_ci * The pcb is NOT freed (since we might not be in the right thread context do this). 839195972f6Sopenharmony_ci * 840195972f6Sopenharmony_ci * @param conn the netconn to free 841195972f6Sopenharmony_ci */ 842195972f6Sopenharmony_civoid 843195972f6Sopenharmony_cinetconn_free(struct netconn *conn) 844195972f6Sopenharmony_ci{ 845195972f6Sopenharmony_ci LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); 846195972f6Sopenharmony_ci 847195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 848195972f6Sopenharmony_ci /* in fullduplex, netconn is drained here */ 849195972f6Sopenharmony_ci netconn_drain(conn); 850195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */ 851195972f6Sopenharmony_ci 852195972f6Sopenharmony_ci LWIP_ASSERT("recvmbox must be deallocated before calling this function", 853195972f6Sopenharmony_ci !sys_mbox_valid(&conn->recvmbox)); 854195972f6Sopenharmony_ci#if LWIP_TCP 855195972f6Sopenharmony_ci LWIP_ASSERT("acceptmbox must be deallocated before calling this function", 856195972f6Sopenharmony_ci !sys_mbox_valid(&conn->acceptmbox)); 857195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 858195972f6Sopenharmony_ci 859195972f6Sopenharmony_ci#if !LWIP_NETCONN_SEM_PER_THREAD 860195972f6Sopenharmony_ci sys_sem_free(&conn->op_completed); 861195972f6Sopenharmony_ci sys_sem_set_invalid(&conn->op_completed); 862195972f6Sopenharmony_ci#endif 863195972f6Sopenharmony_ci 864195972f6Sopenharmony_ci memp_free(MEMP_NETCONN, conn); 865195972f6Sopenharmony_ci} 866195972f6Sopenharmony_ci 867195972f6Sopenharmony_ci/** 868195972f6Sopenharmony_ci * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in 869195972f6Sopenharmony_ci * these mboxes 870195972f6Sopenharmony_ci * 871195972f6Sopenharmony_ci * @param conn the netconn to free 872195972f6Sopenharmony_ci * @bytes_drained bytes drained from recvmbox 873195972f6Sopenharmony_ci * @accepts_drained pending connections drained from acceptmbox 874195972f6Sopenharmony_ci */ 875195972f6Sopenharmony_cistatic void 876195972f6Sopenharmony_cinetconn_drain(struct netconn *conn) 877195972f6Sopenharmony_ci{ 878195972f6Sopenharmony_ci void *mem; 879195972f6Sopenharmony_ci 880195972f6Sopenharmony_ci /* This runs when mbox and netconn are marked as closed, 881195972f6Sopenharmony_ci so we don't need to lock against rx packets */ 882195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 883195972f6Sopenharmony_ci LWIP_ASSERT("netconn marked closed", conn->flags & NETCONN_FLAG_MBOXINVALID); 884195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */ 885195972f6Sopenharmony_ci 886195972f6Sopenharmony_ci /* Delete and drain the recvmbox. */ 887195972f6Sopenharmony_ci if (sys_mbox_valid(&conn->recvmbox)) { 888195972f6Sopenharmony_ci while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { 889195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 890195972f6Sopenharmony_ci if (!lwip_netconn_is_deallocated_msg(mem)) 891195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */ 892195972f6Sopenharmony_ci { 893195972f6Sopenharmony_ci#if LWIP_TCP 894195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) { 895195972f6Sopenharmony_ci err_t err; 896195972f6Sopenharmony_ci if (!lwip_netconn_is_err_msg(mem, &err)) { 897195972f6Sopenharmony_ci pbuf_free((struct pbuf *)mem); 898195972f6Sopenharmony_ci } 899195972f6Sopenharmony_ci } else 900195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 901195972f6Sopenharmony_ci { 902195972f6Sopenharmony_ci netbuf_delete((struct netbuf *)mem); 903195972f6Sopenharmony_ci } 904195972f6Sopenharmony_ci } 905195972f6Sopenharmony_ci } 906195972f6Sopenharmony_ci sys_mbox_free(&conn->recvmbox); 907195972f6Sopenharmony_ci sys_mbox_set_invalid(&conn->recvmbox); 908195972f6Sopenharmony_ci } 909195972f6Sopenharmony_ci 910195972f6Sopenharmony_ci /* Delete and drain the acceptmbox. */ 911195972f6Sopenharmony_ci#if LWIP_TCP 912195972f6Sopenharmony_ci if (sys_mbox_valid(&conn->acceptmbox)) { 913195972f6Sopenharmony_ci while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { 914195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 915195972f6Sopenharmony_ci if (!lwip_netconn_is_deallocated_msg(mem)) 916195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */ 917195972f6Sopenharmony_ci { 918195972f6Sopenharmony_ci err_t err; 919195972f6Sopenharmony_ci if (!lwip_netconn_is_err_msg(mem, &err)) { 920195972f6Sopenharmony_ci struct netconn *newconn = (struct netconn *)mem; 921195972f6Sopenharmony_ci /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ 922195972f6Sopenharmony_ci /* pcb might be set to NULL already by err_tcp() */ 923195972f6Sopenharmony_ci /* drain recvmbox */ 924195972f6Sopenharmony_ci netconn_drain(newconn); 925195972f6Sopenharmony_ci if (newconn->pcb.tcp != NULL) { 926195972f6Sopenharmony_ci tcp_abort(newconn->pcb.tcp); 927195972f6Sopenharmony_ci newconn->pcb.tcp = NULL; 928195972f6Sopenharmony_ci } 929195972f6Sopenharmony_ci netconn_free(newconn); 930195972f6Sopenharmony_ci } 931195972f6Sopenharmony_ci } 932195972f6Sopenharmony_ci } 933195972f6Sopenharmony_ci sys_mbox_free(&conn->acceptmbox); 934195972f6Sopenharmony_ci sys_mbox_set_invalid(&conn->acceptmbox); 935195972f6Sopenharmony_ci } 936195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 937195972f6Sopenharmony_ci} 938195972f6Sopenharmony_ci 939195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 940195972f6Sopenharmony_cistatic void 941195972f6Sopenharmony_cinetconn_mark_mbox_invalid(struct netconn *conn) 942195972f6Sopenharmony_ci{ 943195972f6Sopenharmony_ci int i, num_waiting; 944195972f6Sopenharmony_ci void *msg = LWIP_CONST_CAST(void *, &netconn_deleted); 945195972f6Sopenharmony_ci 946195972f6Sopenharmony_ci /* Prevent new calls/threads from reading from the mbox */ 947195972f6Sopenharmony_ci conn->flags |= NETCONN_FLAG_MBOXINVALID; 948195972f6Sopenharmony_ci 949195972f6Sopenharmony_ci SYS_ARCH_LOCKED(num_waiting = conn->mbox_threads_waiting); 950195972f6Sopenharmony_ci for (i = 0; i < num_waiting; i++) { 951195972f6Sopenharmony_ci if (sys_mbox_valid_val(conn->recvmbox)) { 952195972f6Sopenharmony_ci sys_mbox_trypost(&conn->recvmbox, msg); 953195972f6Sopenharmony_ci } else { 954195972f6Sopenharmony_ci sys_mbox_trypost(&conn->acceptmbox, msg); 955195972f6Sopenharmony_ci } 956195972f6Sopenharmony_ci } 957195972f6Sopenharmony_ci} 958195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */ 959195972f6Sopenharmony_ci 960195972f6Sopenharmony_ci#if LWIP_TCP 961195972f6Sopenharmony_ci/** 962195972f6Sopenharmony_ci * Internal helper function to close a TCP netconn: since this sometimes 963195972f6Sopenharmony_ci * doesn't work at the first attempt, this function is called from multiple 964195972f6Sopenharmony_ci * places. 965195972f6Sopenharmony_ci * 966195972f6Sopenharmony_ci * @param conn the TCP netconn to close 967195972f6Sopenharmony_ci */ 968195972f6Sopenharmony_cistatic err_t 969195972f6Sopenharmony_cilwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM) 970195972f6Sopenharmony_ci{ 971195972f6Sopenharmony_ci err_t err; 972195972f6Sopenharmony_ci u8_t shut, shut_rx, shut_tx, shut_close; 973195972f6Sopenharmony_ci u8_t close_finished = 0; 974195972f6Sopenharmony_ci struct tcp_pcb *tpcb; 975195972f6Sopenharmony_ci#if LWIP_SO_LINGER 976195972f6Sopenharmony_ci u8_t linger_wait_required = 0; 977195972f6Sopenharmony_ci#endif /* LWIP_SO_LINGER */ 978195972f6Sopenharmony_ci 979195972f6Sopenharmony_ci LWIP_ASSERT("invalid conn", (conn != NULL)); 980195972f6Sopenharmony_ci LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)); 981195972f6Sopenharmony_ci LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); 982195972f6Sopenharmony_ci LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); 983195972f6Sopenharmony_ci LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 984195972f6Sopenharmony_ci 985195972f6Sopenharmony_ci tpcb = conn->pcb.tcp; 986195972f6Sopenharmony_ci shut = conn->current_msg->msg.sd.shut; 987195972f6Sopenharmony_ci shut_rx = shut & NETCONN_SHUT_RD; 988195972f6Sopenharmony_ci shut_tx = shut & NETCONN_SHUT_WR; 989195972f6Sopenharmony_ci /* shutting down both ends is the same as closing 990195972f6Sopenharmony_ci (also if RD or WR side was shut down before already) */ 991195972f6Sopenharmony_ci if (shut == NETCONN_SHUT_RDWR) { 992195972f6Sopenharmony_ci shut_close = 1; 993195972f6Sopenharmony_ci } else if (shut_rx && 994195972f6Sopenharmony_ci ((tpcb->state == FIN_WAIT_1) || 995195972f6Sopenharmony_ci (tpcb->state == FIN_WAIT_2) || 996195972f6Sopenharmony_ci (tpcb->state == CLOSING))) { 997195972f6Sopenharmony_ci shut_close = 1; 998195972f6Sopenharmony_ci } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) { 999195972f6Sopenharmony_ci shut_close = 1; 1000195972f6Sopenharmony_ci } else { 1001195972f6Sopenharmony_ci shut_close = 0; 1002195972f6Sopenharmony_ci } 1003195972f6Sopenharmony_ci 1004195972f6Sopenharmony_ci /* Set back some callback pointers */ 1005195972f6Sopenharmony_ci if (shut_close) { 1006195972f6Sopenharmony_ci tcp_arg(tpcb, NULL); 1007195972f6Sopenharmony_ci } 1008195972f6Sopenharmony_ci if (tpcb->state == LISTEN) { 1009195972f6Sopenharmony_ci tcp_accept(tpcb, NULL); 1010195972f6Sopenharmony_ci } else { 1011195972f6Sopenharmony_ci /* some callbacks have to be reset if tcp_close is not successful */ 1012195972f6Sopenharmony_ci if (shut_rx) { 1013195972f6Sopenharmony_ci tcp_recv(tpcb, NULL); 1014195972f6Sopenharmony_ci tcp_accept(tpcb, NULL); 1015195972f6Sopenharmony_ci } 1016195972f6Sopenharmony_ci if (shut_tx) { 1017195972f6Sopenharmony_ci tcp_sent(tpcb, NULL); 1018195972f6Sopenharmony_ci } 1019195972f6Sopenharmony_ci if (shut_close) { 1020195972f6Sopenharmony_ci tcp_poll(tpcb, NULL, 0); 1021195972f6Sopenharmony_ci tcp_err(tpcb, NULL); 1022195972f6Sopenharmony_ci } 1023195972f6Sopenharmony_ci } 1024195972f6Sopenharmony_ci /* Try to close the connection */ 1025195972f6Sopenharmony_ci if (shut_close) { 1026195972f6Sopenharmony_ci#if LWIP_SO_LINGER 1027195972f6Sopenharmony_ci /* check linger possibilites before calling tcp_close */ 1028195972f6Sopenharmony_ci err = ERR_OK; 1029195972f6Sopenharmony_ci /* linger enabled/required at all? (i.e. is there untransmitted data left?) */ 1030195972f6Sopenharmony_ci if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) { 1031195972f6Sopenharmony_ci if ((conn->linger == 0)) { 1032195972f6Sopenharmony_ci /* data left but linger prevents waiting */ 1033195972f6Sopenharmony_ci tcp_abort(tpcb); 1034195972f6Sopenharmony_ci tpcb = NULL; 1035195972f6Sopenharmony_ci } else if (conn->linger > 0) { 1036195972f6Sopenharmony_ci /* data left and linger says we should wait */ 1037195972f6Sopenharmony_ci if (netconn_is_nonblocking(conn)) { 1038195972f6Sopenharmony_ci /* data left on a nonblocking netconn -> cannot linger */ 1039195972f6Sopenharmony_ci err = ERR_WOULDBLOCK; 1040195972f6Sopenharmony_ci } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= 1041195972f6Sopenharmony_ci (conn->linger * 1000)) { 1042195972f6Sopenharmony_ci /* data left but linger timeout has expired (this happens on further 1043195972f6Sopenharmony_ci calls to this function through poll_tcp */ 1044195972f6Sopenharmony_ci tcp_abort(tpcb); 1045195972f6Sopenharmony_ci tpcb = NULL; 1046195972f6Sopenharmony_ci } else { 1047195972f6Sopenharmony_ci /* data left -> need to wait for ACK after successful close */ 1048195972f6Sopenharmony_ci linger_wait_required = 1; 1049195972f6Sopenharmony_ci } 1050195972f6Sopenharmony_ci } 1051195972f6Sopenharmony_ci } 1052195972f6Sopenharmony_ci if ((err == ERR_OK) && (tpcb != NULL)) 1053195972f6Sopenharmony_ci#endif /* LWIP_SO_LINGER */ 1054195972f6Sopenharmony_ci { 1055195972f6Sopenharmony_ci err = tcp_close(tpcb); 1056195972f6Sopenharmony_ci } 1057195972f6Sopenharmony_ci } else { 1058195972f6Sopenharmony_ci err = tcp_shutdown(tpcb, shut_rx, shut_tx); 1059195972f6Sopenharmony_ci } 1060195972f6Sopenharmony_ci if (err == ERR_OK) { 1061195972f6Sopenharmony_ci close_finished = 1; 1062195972f6Sopenharmony_ci#if LWIP_SO_LINGER 1063195972f6Sopenharmony_ci if (linger_wait_required) { 1064195972f6Sopenharmony_ci /* wait for ACK of all unsent/unacked data by just getting called again */ 1065195972f6Sopenharmony_ci close_finished = 0; 1066195972f6Sopenharmony_ci err = ERR_INPROGRESS; 1067195972f6Sopenharmony_ci } 1068195972f6Sopenharmony_ci#endif /* LWIP_SO_LINGER */ 1069195972f6Sopenharmony_ci } else { 1070195972f6Sopenharmony_ci if (err == ERR_MEM) { 1071195972f6Sopenharmony_ci /* Closing failed because of memory shortage, try again later. Even for 1072195972f6Sopenharmony_ci nonblocking netconns, we have to wait since no standard socket application 1073195972f6Sopenharmony_ci is prepared for close failing because of resource shortage. 1074195972f6Sopenharmony_ci Check the timeout: this is kind of an lwip addition to the standard sockets: 1075195972f6Sopenharmony_ci we wait for some time when failing to allocate a segment for the FIN */ 1076195972f6Sopenharmony_ci#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER 1077195972f6Sopenharmony_ci s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT; 1078195972f6Sopenharmony_ci#if LWIP_SO_SNDTIMEO 1079195972f6Sopenharmony_ci if (conn->send_timeout > 0) { 1080195972f6Sopenharmony_ci close_timeout = conn->send_timeout; 1081195972f6Sopenharmony_ci } 1082195972f6Sopenharmony_ci#endif /* LWIP_SO_SNDTIMEO */ 1083195972f6Sopenharmony_ci#if LWIP_SO_LINGER 1084195972f6Sopenharmony_ci if (conn->linger >= 0) { 1085195972f6Sopenharmony_ci /* use linger timeout (seconds) */ 1086195972f6Sopenharmony_ci close_timeout = conn->linger * 1000U; 1087195972f6Sopenharmony_ci } 1088195972f6Sopenharmony_ci#endif 1089195972f6Sopenharmony_ci if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) { 1090195972f6Sopenharmony_ci#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 1091195972f6Sopenharmony_ci if (conn->current_msg->msg.sd.polls_left == 0) { 1092195972f6Sopenharmony_ci#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ 1093195972f6Sopenharmony_ci close_finished = 1; 1094195972f6Sopenharmony_ci if (shut_close) { 1095195972f6Sopenharmony_ci /* in this case, we want to RST the connection */ 1096195972f6Sopenharmony_ci tcp_abort(tpcb); 1097195972f6Sopenharmony_ci err = ERR_OK; 1098195972f6Sopenharmony_ci } 1099195972f6Sopenharmony_ci } 1100195972f6Sopenharmony_ci } else { 1101195972f6Sopenharmony_ci /* Closing failed for a non-memory error: give up */ 1102195972f6Sopenharmony_ci close_finished = 1; 1103195972f6Sopenharmony_ci } 1104195972f6Sopenharmony_ci } 1105195972f6Sopenharmony_ci if (close_finished) { 1106195972f6Sopenharmony_ci /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */ 1107195972f6Sopenharmony_ci sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 1108195972f6Sopenharmony_ci conn->current_msg->err = err; 1109195972f6Sopenharmony_ci conn->current_msg = NULL; 1110195972f6Sopenharmony_ci conn->state = NETCONN_NONE; 1111195972f6Sopenharmony_ci if (err == ERR_OK) { 1112195972f6Sopenharmony_ci if (shut_close) { 1113195972f6Sopenharmony_ci /* Set back some callback pointers as conn is going away */ 1114195972f6Sopenharmony_ci conn->pcb.tcp = NULL; 1115195972f6Sopenharmony_ci /* Trigger select() in socket layer. Make sure everybody notices activity 1116195972f6Sopenharmony_ci on the connection, error first! */ 1117195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_ERROR, 0); 1118195972f6Sopenharmony_ci } 1119195972f6Sopenharmony_ci if (shut_rx) { 1120195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 1121195972f6Sopenharmony_ci } 1122195972f6Sopenharmony_ci if (shut_tx) { 1123195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 1124195972f6Sopenharmony_ci } 1125195972f6Sopenharmony_ci } 1126195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 1127195972f6Sopenharmony_ci if (delayed) 1128195972f6Sopenharmony_ci#endif 1129195972f6Sopenharmony_ci { 1130195972f6Sopenharmony_ci /* wake up the application task */ 1131195972f6Sopenharmony_ci sys_sem_signal(op_completed_sem); 1132195972f6Sopenharmony_ci } 1133195972f6Sopenharmony_ci return ERR_OK; 1134195972f6Sopenharmony_ci } 1135195972f6Sopenharmony_ci if (!close_finished) { 1136195972f6Sopenharmony_ci /* Closing failed and we want to wait: restore some of the callbacks */ 1137195972f6Sopenharmony_ci /* Closing of listen pcb will never fail! */ 1138195972f6Sopenharmony_ci LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN)); 1139195972f6Sopenharmony_ci if (shut_tx) { 1140195972f6Sopenharmony_ci tcp_sent(tpcb, sent_tcp); 1141195972f6Sopenharmony_ci } 1142195972f6Sopenharmony_ci /* when waiting for close, set up poll interval to 500ms */ 1143195972f6Sopenharmony_ci tcp_poll(tpcb, poll_tcp, 1); 1144195972f6Sopenharmony_ci tcp_err(tpcb, err_tcp); 1145195972f6Sopenharmony_ci tcp_arg(tpcb, conn); 1146195972f6Sopenharmony_ci /* don't restore recv callback: we don't want to receive any more data */ 1147195972f6Sopenharmony_ci } 1148195972f6Sopenharmony_ci /* If closing didn't succeed, we get called again either 1149195972f6Sopenharmony_ci from poll_tcp or from sent_tcp */ 1150195972f6Sopenharmony_ci LWIP_ASSERT("err != ERR_OK", err != ERR_OK); 1151195972f6Sopenharmony_ci return err; 1152195972f6Sopenharmony_ci} 1153195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 1154195972f6Sopenharmony_ci 1155195972f6Sopenharmony_ci/** 1156195972f6Sopenharmony_ci * Delete the pcb inside a netconn. 1157195972f6Sopenharmony_ci * Called from netconn_delete. 1158195972f6Sopenharmony_ci * 1159195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection 1160195972f6Sopenharmony_ci */ 1161195972f6Sopenharmony_civoid 1162195972f6Sopenharmony_cilwip_netconn_do_delconn(void *m) 1163195972f6Sopenharmony_ci{ 1164195972f6Sopenharmony_ci struct api_msg *msg = (struct api_msg *)m; 1165195972f6Sopenharmony_ci 1166195972f6Sopenharmony_ci enum netconn_state state = msg->conn->state; 1167195972f6Sopenharmony_ci LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */ 1168195972f6Sopenharmony_ci (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP)); 1169195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 1170195972f6Sopenharmony_ci /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */ 1171195972f6Sopenharmony_ci if (state != NETCONN_NONE) { 1172195972f6Sopenharmony_ci if ((state == NETCONN_WRITE) || 1173195972f6Sopenharmony_ci ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) { 1174195972f6Sopenharmony_ci /* close requested, abort running write/connect */ 1175195972f6Sopenharmony_ci sys_sem_t *op_completed_sem; 1176195972f6Sopenharmony_ci LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL); 1177195972f6Sopenharmony_ci op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg); 1178195972f6Sopenharmony_ci msg->conn->current_msg->err = ERR_CLSD; 1179195972f6Sopenharmony_ci msg->conn->current_msg = NULL; 1180195972f6Sopenharmony_ci msg->conn->state = NETCONN_NONE; 1181195972f6Sopenharmony_ci sys_sem_signal(op_completed_sem); 1182195972f6Sopenharmony_ci } 1183195972f6Sopenharmony_ci } 1184195972f6Sopenharmony_ci#else /* LWIP_NETCONN_FULLDUPLEX */ 1185195972f6Sopenharmony_ci if (((state != NETCONN_NONE) && 1186195972f6Sopenharmony_ci (state != NETCONN_LISTEN) && 1187195972f6Sopenharmony_ci (state != NETCONN_CONNECT)) || 1188195972f6Sopenharmony_ci ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) { 1189195972f6Sopenharmony_ci /* This means either a blocking write or blocking connect is running 1190195972f6Sopenharmony_ci (nonblocking write returns and sets state to NONE) */ 1191195972f6Sopenharmony_ci msg->err = ERR_INPROGRESS; 1192195972f6Sopenharmony_ci } else 1193195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */ 1194195972f6Sopenharmony_ci { 1195195972f6Sopenharmony_ci LWIP_ASSERT("blocking connect in progress", 1196195972f6Sopenharmony_ci (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); 1197195972f6Sopenharmony_ci msg->err = ERR_OK; 1198195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 1199195972f6Sopenharmony_ci /* Mark mboxes invalid */ 1200195972f6Sopenharmony_ci netconn_mark_mbox_invalid(msg->conn); 1201195972f6Sopenharmony_ci#else /* LWIP_NETCONN_FULLDUPLEX */ 1202195972f6Sopenharmony_ci netconn_drain(msg->conn); 1203195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */ 1204195972f6Sopenharmony_ci 1205195972f6Sopenharmony_ci if (msg->conn->pcb.tcp != NULL) { 1206195972f6Sopenharmony_ci 1207195972f6Sopenharmony_ci switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1208195972f6Sopenharmony_ci#if LWIP_RAW 1209195972f6Sopenharmony_ci case NETCONN_RAW: 1210195972f6Sopenharmony_ci raw_remove(msg->conn->pcb.raw); 1211195972f6Sopenharmony_ci break; 1212195972f6Sopenharmony_ci#endif /* LWIP_RAW */ 1213195972f6Sopenharmony_ci#if LWIP_UDP 1214195972f6Sopenharmony_ci case NETCONN_UDP: 1215195972f6Sopenharmony_ci msg->conn->pcb.udp->recv_arg = NULL; 1216195972f6Sopenharmony_ci udp_remove(msg->conn->pcb.udp); 1217195972f6Sopenharmony_ci break; 1218195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 1219195972f6Sopenharmony_ci#if LWIP_TCP 1220195972f6Sopenharmony_ci case NETCONN_TCP: 1221195972f6Sopenharmony_ci LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL); 1222195972f6Sopenharmony_ci msg->conn->state = NETCONN_CLOSE; 1223195972f6Sopenharmony_ci msg->msg.sd.shut = NETCONN_SHUT_RDWR; 1224195972f6Sopenharmony_ci msg->conn->current_msg = msg; 1225195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 1226195972f6Sopenharmony_ci if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) { 1227195972f6Sopenharmony_ci LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE); 1228195972f6Sopenharmony_ci UNLOCK_TCPIP_CORE(); 1229195972f6Sopenharmony_ci sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 1230195972f6Sopenharmony_ci LOCK_TCPIP_CORE(); 1231195972f6Sopenharmony_ci LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); 1232195972f6Sopenharmony_ci } 1233195972f6Sopenharmony_ci#else /* LWIP_TCPIP_CORE_LOCKING */ 1234195972f6Sopenharmony_ci lwip_netconn_do_close_internal(msg->conn); 1235195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */ 1236195972f6Sopenharmony_ci /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing 1237195972f6Sopenharmony_ci the application thread, so we can return at this point! */ 1238195972f6Sopenharmony_ci return; 1239195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 1240195972f6Sopenharmony_ci default: 1241195972f6Sopenharmony_ci break; 1242195972f6Sopenharmony_ci } 1243195972f6Sopenharmony_ci msg->conn->pcb.tcp = NULL; 1244195972f6Sopenharmony_ci } 1245195972f6Sopenharmony_ci /* tcp netconns don't come here! */ 1246195972f6Sopenharmony_ci 1247195972f6Sopenharmony_ci /* @todo: this lets select make the socket readable and writable, 1248195972f6Sopenharmony_ci which is wrong! errfd instead? */ 1249195972f6Sopenharmony_ci API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); 1250195972f6Sopenharmony_ci API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); 1251195972f6Sopenharmony_ci } 1252195972f6Sopenharmony_ci if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) { 1253195972f6Sopenharmony_ci TCPIP_APIMSG_ACK(msg); 1254195972f6Sopenharmony_ci } 1255195972f6Sopenharmony_ci} 1256195972f6Sopenharmony_ci 1257195972f6Sopenharmony_ci/** 1258195972f6Sopenharmony_ci * Bind a pcb contained in a netconn 1259195972f6Sopenharmony_ci * Called from netconn_bind. 1260195972f6Sopenharmony_ci * 1261195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection and containing 1262195972f6Sopenharmony_ci * the IP address and port to bind to 1263195972f6Sopenharmony_ci */ 1264195972f6Sopenharmony_civoid 1265195972f6Sopenharmony_cilwip_netconn_do_bind(void *m) 1266195972f6Sopenharmony_ci{ 1267195972f6Sopenharmony_ci struct api_msg *msg = (struct api_msg *)m; 1268195972f6Sopenharmony_ci err_t err; 1269195972f6Sopenharmony_ci 1270195972f6Sopenharmony_ci if (msg->conn->pcb.tcp != NULL) { 1271195972f6Sopenharmony_ci switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1272195972f6Sopenharmony_ci#if LWIP_RAW 1273195972f6Sopenharmony_ci case NETCONN_RAW: 1274195972f6Sopenharmony_ci err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); 1275195972f6Sopenharmony_ci break; 1276195972f6Sopenharmony_ci#endif /* LWIP_RAW */ 1277195972f6Sopenharmony_ci#if LWIP_UDP 1278195972f6Sopenharmony_ci case NETCONN_UDP: 1279195972f6Sopenharmony_ci err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); 1280195972f6Sopenharmony_ci break; 1281195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 1282195972f6Sopenharmony_ci#if LWIP_TCP 1283195972f6Sopenharmony_ci case NETCONN_TCP: 1284195972f6Sopenharmony_ci err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); 1285195972f6Sopenharmony_ci break; 1286195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 1287195972f6Sopenharmony_ci default: 1288195972f6Sopenharmony_ci err = ERR_VAL; 1289195972f6Sopenharmony_ci break; 1290195972f6Sopenharmony_ci } 1291195972f6Sopenharmony_ci } else { 1292195972f6Sopenharmony_ci err = ERR_VAL; 1293195972f6Sopenharmony_ci } 1294195972f6Sopenharmony_ci msg->err = err; 1295195972f6Sopenharmony_ci TCPIP_APIMSG_ACK(msg); 1296195972f6Sopenharmony_ci} 1297195972f6Sopenharmony_ci 1298195972f6Sopenharmony_ci/** 1299195972f6Sopenharmony_ci * Bind a pcb contained in a netconn to an interface 1300195972f6Sopenharmony_ci * Called from netconn_bind_if. 1301195972f6Sopenharmony_ci * 1302195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection and containing 1303195972f6Sopenharmony_ci * the IP address and port to bind to 1304195972f6Sopenharmony_ci */ 1305195972f6Sopenharmony_civoid 1306195972f6Sopenharmony_cilwip_netconn_do_bind_if(void *m) 1307195972f6Sopenharmony_ci{ 1308195972f6Sopenharmony_ci struct netif *netif; 1309195972f6Sopenharmony_ci struct api_msg *msg = (struct api_msg *)m; 1310195972f6Sopenharmony_ci err_t err; 1311195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 1312195972f6Sopenharmony_ci struct net_group *group = get_net_group_from_ippcb(msg->conn->pcb.ip); 1313195972f6Sopenharmony_ci 1314195972f6Sopenharmony_ci if (group != NULL) { 1315195972f6Sopenharmony_ci netif = netif_get_by_index(msg->msg.bc.if_idx, group); 1316195972f6Sopenharmony_ci } else { 1317195972f6Sopenharmony_ci netif = NULL; 1318195972f6Sopenharmony_ci } 1319195972f6Sopenharmony_ci#else 1320195972f6Sopenharmony_ci netif = netif_get_by_index(msg->msg.bc.if_idx); 1321195972f6Sopenharmony_ci#endif 1322195972f6Sopenharmony_ci 1323195972f6Sopenharmony_ci if ((netif != NULL) && (msg->conn->pcb.tcp != NULL)) { 1324195972f6Sopenharmony_ci err = ERR_OK; 1325195972f6Sopenharmony_ci switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1326195972f6Sopenharmony_ci#if LWIP_RAW 1327195972f6Sopenharmony_ci case NETCONN_RAW: 1328195972f6Sopenharmony_ci raw_bind_netif(msg->conn->pcb.raw, netif); 1329195972f6Sopenharmony_ci break; 1330195972f6Sopenharmony_ci#endif /* LWIP_RAW */ 1331195972f6Sopenharmony_ci#if LWIP_UDP 1332195972f6Sopenharmony_ci case NETCONN_UDP: 1333195972f6Sopenharmony_ci udp_bind_netif(msg->conn->pcb.udp, netif); 1334195972f6Sopenharmony_ci break; 1335195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 1336195972f6Sopenharmony_ci#if LWIP_TCP 1337195972f6Sopenharmony_ci case NETCONN_TCP: 1338195972f6Sopenharmony_ci tcp_bind_netif(msg->conn->pcb.tcp, netif); 1339195972f6Sopenharmony_ci break; 1340195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 1341195972f6Sopenharmony_ci default: 1342195972f6Sopenharmony_ci err = ERR_VAL; 1343195972f6Sopenharmony_ci break; 1344195972f6Sopenharmony_ci } 1345195972f6Sopenharmony_ci } else { 1346195972f6Sopenharmony_ci err = ERR_VAL; 1347195972f6Sopenharmony_ci } 1348195972f6Sopenharmony_ci msg->err = err; 1349195972f6Sopenharmony_ci TCPIP_APIMSG_ACK(msg); 1350195972f6Sopenharmony_ci} 1351195972f6Sopenharmony_ci 1352195972f6Sopenharmony_ci#if LWIP_TCP 1353195972f6Sopenharmony_ci/** 1354195972f6Sopenharmony_ci * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has 1355195972f6Sopenharmony_ci * been established (or reset by the remote host). 1356195972f6Sopenharmony_ci * 1357195972f6Sopenharmony_ci * @see tcp.h (struct tcp_pcb.connected) for parameters and return values 1358195972f6Sopenharmony_ci */ 1359195972f6Sopenharmony_cistatic err_t 1360195972f6Sopenharmony_cilwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) 1361195972f6Sopenharmony_ci{ 1362195972f6Sopenharmony_ci struct netconn *conn; 1363195972f6Sopenharmony_ci int was_blocking; 1364195972f6Sopenharmony_ci sys_sem_t *op_completed_sem = NULL; 1365195972f6Sopenharmony_ci 1366195972f6Sopenharmony_ci LWIP_UNUSED_ARG(pcb); 1367195972f6Sopenharmony_ci 1368195972f6Sopenharmony_ci conn = (struct netconn *)arg; 1369195972f6Sopenharmony_ci 1370195972f6Sopenharmony_ci if (conn == NULL) { 1371195972f6Sopenharmony_ci return ERR_VAL; 1372195972f6Sopenharmony_ci } 1373195972f6Sopenharmony_ci 1374195972f6Sopenharmony_ci LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); 1375195972f6Sopenharmony_ci LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", 1376195972f6Sopenharmony_ci (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); 1377195972f6Sopenharmony_ci 1378195972f6Sopenharmony_ci if (conn->current_msg != NULL) { 1379195972f6Sopenharmony_ci conn->current_msg->err = err; 1380195972f6Sopenharmony_ci op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 1381195972f6Sopenharmony_ci } 1382195972f6Sopenharmony_ci if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) { 1383195972f6Sopenharmony_ci setup_tcp(conn); 1384195972f6Sopenharmony_ci } 1385195972f6Sopenharmony_ci was_blocking = !IN_NONBLOCKING_CONNECT(conn); 1386195972f6Sopenharmony_ci SET_NONBLOCKING_CONNECT(conn, 0); 1387195972f6Sopenharmony_ci LWIP_ASSERT("blocking connect state error", 1388195972f6Sopenharmony_ci (was_blocking && op_completed_sem != NULL) || 1389195972f6Sopenharmony_ci (!was_blocking && op_completed_sem == NULL)); 1390195972f6Sopenharmony_ci conn->current_msg = NULL; 1391195972f6Sopenharmony_ci conn->state = NETCONN_NONE; 1392195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); 1393195972f6Sopenharmony_ci 1394195972f6Sopenharmony_ci if (was_blocking) { 1395195972f6Sopenharmony_ci sys_sem_signal(op_completed_sem); 1396195972f6Sopenharmony_ci } 1397195972f6Sopenharmony_ci return ERR_OK; 1398195972f6Sopenharmony_ci} 1399195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 1400195972f6Sopenharmony_ci 1401195972f6Sopenharmony_ci/** 1402195972f6Sopenharmony_ci * Connect a pcb contained inside a netconn 1403195972f6Sopenharmony_ci * Called from netconn_connect. 1404195972f6Sopenharmony_ci * 1405195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection and containing 1406195972f6Sopenharmony_ci * the IP address and port to connect to 1407195972f6Sopenharmony_ci */ 1408195972f6Sopenharmony_civoid 1409195972f6Sopenharmony_cilwip_netconn_do_connect(void *m) 1410195972f6Sopenharmony_ci{ 1411195972f6Sopenharmony_ci struct api_msg *msg = (struct api_msg *)m; 1412195972f6Sopenharmony_ci err_t err; 1413195972f6Sopenharmony_ci 1414195972f6Sopenharmony_ci if (msg->conn->pcb.tcp == NULL) { 1415195972f6Sopenharmony_ci /* This may happen when calling netconn_connect() a second time */ 1416195972f6Sopenharmony_ci err = ERR_CLSD; 1417195972f6Sopenharmony_ci } else { 1418195972f6Sopenharmony_ci switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1419195972f6Sopenharmony_ci#if LWIP_RAW 1420195972f6Sopenharmony_ci case NETCONN_RAW: 1421195972f6Sopenharmony_ci err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); 1422195972f6Sopenharmony_ci break; 1423195972f6Sopenharmony_ci#endif /* LWIP_RAW */ 1424195972f6Sopenharmony_ci#if LWIP_UDP 1425195972f6Sopenharmony_ci case NETCONN_UDP: 1426195972f6Sopenharmony_ci err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); 1427195972f6Sopenharmony_ci break; 1428195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 1429195972f6Sopenharmony_ci#if LWIP_TCP 1430195972f6Sopenharmony_ci case NETCONN_TCP: 1431195972f6Sopenharmony_ci /* Prevent connect while doing any other action. */ 1432195972f6Sopenharmony_ci if (msg->conn->state == NETCONN_CONNECT) { 1433195972f6Sopenharmony_ci err = ERR_ALREADY; 1434195972f6Sopenharmony_ci } else if (msg->conn->state != NETCONN_NONE) { 1435195972f6Sopenharmony_ci err = ERR_ISCONN; 1436195972f6Sopenharmony_ci } else { 1437195972f6Sopenharmony_ci setup_tcp(msg->conn); 1438195972f6Sopenharmony_ci err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), 1439195972f6Sopenharmony_ci msg->msg.bc.port, lwip_netconn_do_connected); 1440195972f6Sopenharmony_ci if (err == ERR_OK) { 1441195972f6Sopenharmony_ci u8_t non_blocking = netconn_is_nonblocking(msg->conn); 1442195972f6Sopenharmony_ci msg->conn->state = NETCONN_CONNECT; 1443195972f6Sopenharmony_ci SET_NONBLOCKING_CONNECT(msg->conn, non_blocking); 1444195972f6Sopenharmony_ci if (non_blocking) { 1445195972f6Sopenharmony_ci err = ERR_INPROGRESS; 1446195972f6Sopenharmony_ci } else { 1447195972f6Sopenharmony_ci msg->conn->current_msg = msg; 1448195972f6Sopenharmony_ci /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()), 1449195972f6Sopenharmony_ci when the connection is established! */ 1450195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 1451195972f6Sopenharmony_ci LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT); 1452195972f6Sopenharmony_ci UNLOCK_TCPIP_CORE(); 1453195972f6Sopenharmony_ci sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 1454195972f6Sopenharmony_ci LOCK_TCPIP_CORE(); 1455195972f6Sopenharmony_ci LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT); 1456195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */ 1457195972f6Sopenharmony_ci return; 1458195972f6Sopenharmony_ci } 1459195972f6Sopenharmony_ci } 1460195972f6Sopenharmony_ci } 1461195972f6Sopenharmony_ci break; 1462195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 1463195972f6Sopenharmony_ci default: 1464195972f6Sopenharmony_ci LWIP_ERROR("Invalid netconn type", 0, do { 1465195972f6Sopenharmony_ci err = ERR_VAL; 1466195972f6Sopenharmony_ci } while (0)); 1467195972f6Sopenharmony_ci break; 1468195972f6Sopenharmony_ci } 1469195972f6Sopenharmony_ci } 1470195972f6Sopenharmony_ci msg->err = err; 1471195972f6Sopenharmony_ci /* For all other protocols, netconn_connect() calls netconn_apimsg(), 1472195972f6Sopenharmony_ci so use TCPIP_APIMSG_ACK() here. */ 1473195972f6Sopenharmony_ci TCPIP_APIMSG_ACK(msg); 1474195972f6Sopenharmony_ci} 1475195972f6Sopenharmony_ci 1476195972f6Sopenharmony_ci/** 1477195972f6Sopenharmony_ci * Disconnect a pcb contained inside a netconn 1478195972f6Sopenharmony_ci * Only used for UDP netconns. 1479195972f6Sopenharmony_ci * Called from netconn_disconnect. 1480195972f6Sopenharmony_ci * 1481195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection to disconnect 1482195972f6Sopenharmony_ci */ 1483195972f6Sopenharmony_civoid 1484195972f6Sopenharmony_cilwip_netconn_do_disconnect(void *m) 1485195972f6Sopenharmony_ci{ 1486195972f6Sopenharmony_ci struct api_msg *msg = (struct api_msg *)m; 1487195972f6Sopenharmony_ci 1488195972f6Sopenharmony_ci#if LWIP_UDP 1489195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 1490195972f6Sopenharmony_ci udp_disconnect(msg->conn->pcb.udp); 1491195972f6Sopenharmony_ci msg->err = ERR_OK; 1492195972f6Sopenharmony_ci } else 1493195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 1494195972f6Sopenharmony_ci { 1495195972f6Sopenharmony_ci msg->err = ERR_VAL; 1496195972f6Sopenharmony_ci } 1497195972f6Sopenharmony_ci TCPIP_APIMSG_ACK(msg); 1498195972f6Sopenharmony_ci} 1499195972f6Sopenharmony_ci 1500195972f6Sopenharmony_ci#if LWIP_TCP 1501195972f6Sopenharmony_ci/** 1502195972f6Sopenharmony_ci * Set a TCP pcb contained in a netconn into listen mode 1503195972f6Sopenharmony_ci * Called from netconn_listen. 1504195972f6Sopenharmony_ci * 1505195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection 1506195972f6Sopenharmony_ci */ 1507195972f6Sopenharmony_civoid 1508195972f6Sopenharmony_cilwip_netconn_do_listen(void *m) 1509195972f6Sopenharmony_ci{ 1510195972f6Sopenharmony_ci struct api_msg *msg = (struct api_msg *)m; 1511195972f6Sopenharmony_ci err_t err; 1512195972f6Sopenharmony_ci 1513195972f6Sopenharmony_ci if (msg->conn->pcb.tcp != NULL) { 1514195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 1515195972f6Sopenharmony_ci if (msg->conn->state == NETCONN_NONE) { 1516195972f6Sopenharmony_ci struct tcp_pcb *lpcb; 1517195972f6Sopenharmony_ci if (msg->conn->pcb.tcp->state != CLOSED) { 1518195972f6Sopenharmony_ci /* connection is not closed, cannot listen */ 1519195972f6Sopenharmony_ci err = ERR_VAL; 1520195972f6Sopenharmony_ci } else { 1521195972f6Sopenharmony_ci u8_t backlog; 1522195972f6Sopenharmony_ci#if TCP_LISTEN_BACKLOG 1523195972f6Sopenharmony_ci backlog = msg->msg.lb.backlog; 1524195972f6Sopenharmony_ci#else /* TCP_LISTEN_BACKLOG */ 1525195972f6Sopenharmony_ci backlog = TCP_DEFAULT_LISTEN_BACKLOG; 1526195972f6Sopenharmony_ci#endif /* TCP_LISTEN_BACKLOG */ 1527195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 1528195972f6Sopenharmony_ci /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY, 1529195972f6Sopenharmony_ci * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen 1530195972f6Sopenharmony_ci */ 1531195972f6Sopenharmony_ci if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) && 1532195972f6Sopenharmony_ci (netconn_get_ipv6only(msg->conn) == 0)) { 1533195972f6Sopenharmony_ci /* change PCB type to IPADDR_TYPE_ANY */ 1534195972f6Sopenharmony_ci IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip, IPADDR_TYPE_ANY); 1535195972f6Sopenharmony_ci IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY); 1536195972f6Sopenharmony_ci } 1537195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1538195972f6Sopenharmony_ci 1539195972f6Sopenharmony_ci lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err); 1540195972f6Sopenharmony_ci 1541195972f6Sopenharmony_ci if (lpcb == NULL) { 1542195972f6Sopenharmony_ci /* in this case, the old pcb is still allocated */ 1543195972f6Sopenharmony_ci } else { 1544195972f6Sopenharmony_ci /* delete the recvmbox and allocate the acceptmbox */ 1545195972f6Sopenharmony_ci if (sys_mbox_valid(&msg->conn->recvmbox)) { 1546195972f6Sopenharmony_ci /** @todo: should we drain the recvmbox here? */ 1547195972f6Sopenharmony_ci sys_mbox_free(&msg->conn->recvmbox); 1548195972f6Sopenharmony_ci sys_mbox_set_invalid(&msg->conn->recvmbox); 1549195972f6Sopenharmony_ci } 1550195972f6Sopenharmony_ci err = ERR_OK; 1551195972f6Sopenharmony_ci if (!sys_mbox_valid(&msg->conn->acceptmbox)) { 1552195972f6Sopenharmony_ci err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE); 1553195972f6Sopenharmony_ci } 1554195972f6Sopenharmony_ci if (err == ERR_OK) { 1555195972f6Sopenharmony_ci msg->conn->state = NETCONN_LISTEN; 1556195972f6Sopenharmony_ci msg->conn->pcb.tcp = lpcb; 1557195972f6Sopenharmony_ci tcp_arg(msg->conn->pcb.tcp, msg->conn); 1558195972f6Sopenharmony_ci tcp_accept(msg->conn->pcb.tcp, accept_function); 1559195972f6Sopenharmony_ci } else { 1560195972f6Sopenharmony_ci /* since the old pcb is already deallocated, free lpcb now */ 1561195972f6Sopenharmony_ci tcp_close(lpcb); 1562195972f6Sopenharmony_ci msg->conn->pcb.tcp = NULL; 1563195972f6Sopenharmony_ci } 1564195972f6Sopenharmony_ci } 1565195972f6Sopenharmony_ci } 1566195972f6Sopenharmony_ci } else if (msg->conn->state == NETCONN_LISTEN) { 1567195972f6Sopenharmony_ci /* already listening, allow updating of the backlog */ 1568195972f6Sopenharmony_ci err = ERR_OK; 1569195972f6Sopenharmony_ci tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog); 1570195972f6Sopenharmony_ci } else { 1571195972f6Sopenharmony_ci err = ERR_CONN; 1572195972f6Sopenharmony_ci } 1573195972f6Sopenharmony_ci } else { 1574195972f6Sopenharmony_ci err = ERR_ARG; 1575195972f6Sopenharmony_ci } 1576195972f6Sopenharmony_ci } else { 1577195972f6Sopenharmony_ci err = ERR_CONN; 1578195972f6Sopenharmony_ci } 1579195972f6Sopenharmony_ci msg->err = err; 1580195972f6Sopenharmony_ci TCPIP_APIMSG_ACK(msg); 1581195972f6Sopenharmony_ci} 1582195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 1583195972f6Sopenharmony_ci 1584195972f6Sopenharmony_ci/** 1585195972f6Sopenharmony_ci * Send some data on a RAW or UDP pcb contained in a netconn 1586195972f6Sopenharmony_ci * Called from netconn_send 1587195972f6Sopenharmony_ci * 1588195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection 1589195972f6Sopenharmony_ci */ 1590195972f6Sopenharmony_civoid 1591195972f6Sopenharmony_cilwip_netconn_do_send(void *m) 1592195972f6Sopenharmony_ci{ 1593195972f6Sopenharmony_ci struct api_msg *msg = (struct api_msg *)m; 1594195972f6Sopenharmony_ci 1595195972f6Sopenharmony_ci err_t err = netconn_err(msg->conn); 1596195972f6Sopenharmony_ci if (err == ERR_OK) { 1597195972f6Sopenharmony_ci if (msg->conn->pcb.tcp != NULL) { 1598195972f6Sopenharmony_ci switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1599195972f6Sopenharmony_ci#if LWIP_RAW 1600195972f6Sopenharmony_ci case NETCONN_RAW: 1601195972f6Sopenharmony_ci if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { 1602195972f6Sopenharmony_ci err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); 1603195972f6Sopenharmony_ci } else { 1604195972f6Sopenharmony_ci err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); 1605195972f6Sopenharmony_ci } 1606195972f6Sopenharmony_ci break; 1607195972f6Sopenharmony_ci#endif 1608195972f6Sopenharmony_ci#if LWIP_UDP 1609195972f6Sopenharmony_ci case NETCONN_UDP: 1610195972f6Sopenharmony_ci#if LWIP_CHECKSUM_ON_COPY 1611195972f6Sopenharmony_ci if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { 1612195972f6Sopenharmony_ci err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, 1613195972f6Sopenharmony_ci msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); 1614195972f6Sopenharmony_ci } else { 1615195972f6Sopenharmony_ci err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, 1616195972f6Sopenharmony_ci &msg->msg.b->addr, msg->msg.b->port, 1617195972f6Sopenharmony_ci msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); 1618195972f6Sopenharmony_ci } 1619195972f6Sopenharmony_ci#else /* LWIP_CHECKSUM_ON_COPY */ 1620195972f6Sopenharmony_ci if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { 1621195972f6Sopenharmony_ci err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); 1622195972f6Sopenharmony_ci } else { 1623195972f6Sopenharmony_ci err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port); 1624195972f6Sopenharmony_ci } 1625195972f6Sopenharmony_ci#endif /* LWIP_CHECKSUM_ON_COPY */ 1626195972f6Sopenharmony_ci break; 1627195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 1628195972f6Sopenharmony_ci default: 1629195972f6Sopenharmony_ci err = ERR_CONN; 1630195972f6Sopenharmony_ci break; 1631195972f6Sopenharmony_ci } 1632195972f6Sopenharmony_ci } else { 1633195972f6Sopenharmony_ci err = ERR_CONN; 1634195972f6Sopenharmony_ci } 1635195972f6Sopenharmony_ci } 1636195972f6Sopenharmony_ci msg->err = err; 1637195972f6Sopenharmony_ci TCPIP_APIMSG_ACK(msg); 1638195972f6Sopenharmony_ci} 1639195972f6Sopenharmony_ci 1640195972f6Sopenharmony_ci#if LWIP_TCP 1641195972f6Sopenharmony_ci/** 1642195972f6Sopenharmony_ci * Indicate data has been received from a TCP pcb contained in a netconn 1643195972f6Sopenharmony_ci * Called from netconn_recv 1644195972f6Sopenharmony_ci * 1645195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection 1646195972f6Sopenharmony_ci */ 1647195972f6Sopenharmony_civoid 1648195972f6Sopenharmony_cilwip_netconn_do_recv(void *m) 1649195972f6Sopenharmony_ci{ 1650195972f6Sopenharmony_ci struct api_msg *msg = (struct api_msg *)m; 1651195972f6Sopenharmony_ci 1652195972f6Sopenharmony_ci msg->err = ERR_OK; 1653195972f6Sopenharmony_ci if (msg->conn->pcb.tcp != NULL) { 1654195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 1655195972f6Sopenharmony_ci size_t remaining = msg->msg.r.len; 1656195972f6Sopenharmony_ci do { 1657195972f6Sopenharmony_ci u16_t recved = (u16_t)((remaining > 0xffff) ? 0xffff : remaining); 1658195972f6Sopenharmony_ci tcp_recved(msg->conn->pcb.tcp, recved); 1659195972f6Sopenharmony_ci remaining -= recved; 1660195972f6Sopenharmony_ci } while (remaining != 0); 1661195972f6Sopenharmony_ci } 1662195972f6Sopenharmony_ci } 1663195972f6Sopenharmony_ci TCPIP_APIMSG_ACK(msg); 1664195972f6Sopenharmony_ci} 1665195972f6Sopenharmony_ci 1666195972f6Sopenharmony_ci#if TCP_LISTEN_BACKLOG 1667195972f6Sopenharmony_ci/** Indicate that a TCP pcb has been accepted 1668195972f6Sopenharmony_ci * Called from netconn_accept 1669195972f6Sopenharmony_ci * 1670195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection 1671195972f6Sopenharmony_ci */ 1672195972f6Sopenharmony_civoid 1673195972f6Sopenharmony_cilwip_netconn_do_accepted(void *m) 1674195972f6Sopenharmony_ci{ 1675195972f6Sopenharmony_ci struct api_msg *msg = (struct api_msg *)m; 1676195972f6Sopenharmony_ci 1677195972f6Sopenharmony_ci msg->err = ERR_OK; 1678195972f6Sopenharmony_ci if (msg->conn->pcb.tcp != NULL) { 1679195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 1680195972f6Sopenharmony_ci tcp_backlog_accepted(msg->conn->pcb.tcp); 1681195972f6Sopenharmony_ci } 1682195972f6Sopenharmony_ci } 1683195972f6Sopenharmony_ci TCPIP_APIMSG_ACK(msg); 1684195972f6Sopenharmony_ci} 1685195972f6Sopenharmony_ci#endif /* TCP_LISTEN_BACKLOG */ 1686195972f6Sopenharmony_ci 1687195972f6Sopenharmony_ci/** 1688195972f6Sopenharmony_ci * See if more data needs to be written from a previous call to netconn_write. 1689195972f6Sopenharmony_ci * Called initially from lwip_netconn_do_write. If the first call can't send all data 1690195972f6Sopenharmony_ci * (because of low memory or empty send-buffer), this function is called again 1691195972f6Sopenharmony_ci * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the 1692195972f6Sopenharmony_ci * blocking application thread (waiting in netconn_write) is released. 1693195972f6Sopenharmony_ci * 1694195972f6Sopenharmony_ci * @param conn netconn (that is currently in state NETCONN_WRITE) to process 1695195972f6Sopenharmony_ci * @return ERR_OK 1696195972f6Sopenharmony_ci * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished 1697195972f6Sopenharmony_ci */ 1698195972f6Sopenharmony_cistatic err_t 1699195972f6Sopenharmony_cilwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM) 1700195972f6Sopenharmony_ci{ 1701195972f6Sopenharmony_ci err_t err; 1702195972f6Sopenharmony_ci const void *dataptr; 1703195972f6Sopenharmony_ci u16_t len, available; 1704195972f6Sopenharmony_ci u8_t write_finished = 0; 1705195972f6Sopenharmony_ci size_t diff; 1706195972f6Sopenharmony_ci u8_t dontblock; 1707195972f6Sopenharmony_ci u8_t apiflags; 1708195972f6Sopenharmony_ci u8_t write_more; 1709195972f6Sopenharmony_ci 1710195972f6Sopenharmony_ci LWIP_ASSERT("conn != NULL", conn != NULL); 1711195972f6Sopenharmony_ci LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); 1712195972f6Sopenharmony_ci LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); 1713195972f6Sopenharmony_ci LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); 1714195972f6Sopenharmony_ci LWIP_ASSERT("conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len", 1715195972f6Sopenharmony_ci conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len); 1716195972f6Sopenharmony_ci LWIP_ASSERT("conn->current_msg->msg.w.vector_cnt > 0", conn->current_msg->msg.w.vector_cnt > 0); 1717195972f6Sopenharmony_ci 1718195972f6Sopenharmony_ci apiflags = conn->current_msg->msg.w.apiflags; 1719195972f6Sopenharmony_ci dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); 1720195972f6Sopenharmony_ci 1721195972f6Sopenharmony_ci#if LWIP_SO_SNDTIMEO 1722195972f6Sopenharmony_ci if ((conn->send_timeout != 0) && 1723195972f6Sopenharmony_ci ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) { 1724195972f6Sopenharmony_ci write_finished = 1; 1725195972f6Sopenharmony_ci if (conn->current_msg->msg.w.offset == 0) { 1726195972f6Sopenharmony_ci /* nothing has been written */ 1727195972f6Sopenharmony_ci err = ERR_WOULDBLOCK; 1728195972f6Sopenharmony_ci } else { 1729195972f6Sopenharmony_ci /* partial write */ 1730195972f6Sopenharmony_ci err = ERR_OK; 1731195972f6Sopenharmony_ci } 1732195972f6Sopenharmony_ci } else 1733195972f6Sopenharmony_ci#endif /* LWIP_SO_SNDTIMEO */ 1734195972f6Sopenharmony_ci { 1735195972f6Sopenharmony_ci do { 1736195972f6Sopenharmony_ci dataptr = (const u8_t *)conn->current_msg->msg.w.vector->ptr + conn->current_msg->msg.w.vector_off; 1737195972f6Sopenharmony_ci diff = conn->current_msg->msg.w.vector->len - conn->current_msg->msg.w.vector_off; 1738195972f6Sopenharmony_ci if (diff > 0xffffUL) { /* max_u16_t */ 1739195972f6Sopenharmony_ci len = 0xffff; 1740195972f6Sopenharmony_ci apiflags |= TCP_WRITE_FLAG_MORE; 1741195972f6Sopenharmony_ci } else { 1742195972f6Sopenharmony_ci len = (u16_t)diff; 1743195972f6Sopenharmony_ci } 1744195972f6Sopenharmony_ci available = tcp_sndbuf(conn->pcb.tcp); 1745195972f6Sopenharmony_ci if (available < len) { 1746195972f6Sopenharmony_ci /* don't try to write more than sendbuf */ 1747195972f6Sopenharmony_ci len = available; 1748195972f6Sopenharmony_ci if (dontblock) { 1749195972f6Sopenharmony_ci if (!len) { 1750195972f6Sopenharmony_ci /* set error according to partial write or not */ 1751195972f6Sopenharmony_ci err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK; 1752195972f6Sopenharmony_ci goto err_mem; 1753195972f6Sopenharmony_ci } 1754195972f6Sopenharmony_ci } else { 1755195972f6Sopenharmony_ci apiflags |= TCP_WRITE_FLAG_MORE; 1756195972f6Sopenharmony_ci } 1757195972f6Sopenharmony_ci } 1758195972f6Sopenharmony_ci LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!", 1759195972f6Sopenharmony_ci ((conn->current_msg->msg.w.vector_off + len) <= conn->current_msg->msg.w.vector->len)); 1760195972f6Sopenharmony_ci /* we should loop around for more sending in the following cases: 1761195972f6Sopenharmony_ci 1) We couldn't finish the current vector because of 16-bit size limitations. 1762195972f6Sopenharmony_ci tcp_write() and tcp_sndbuf() both are limited to 16-bit sizes 1763195972f6Sopenharmony_ci 2) We are sending the remainder of the current vector and have more */ 1764195972f6Sopenharmony_ci if ((len == 0xffff && diff > 0xffffUL) || 1765195972f6Sopenharmony_ci (len == (u16_t)diff && conn->current_msg->msg.w.vector_cnt > 1)) { 1766195972f6Sopenharmony_ci write_more = 1; 1767195972f6Sopenharmony_ci apiflags |= TCP_WRITE_FLAG_MORE; 1768195972f6Sopenharmony_ci } else { 1769195972f6Sopenharmony_ci write_more = 0; 1770195972f6Sopenharmony_ci } 1771195972f6Sopenharmony_ci err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); 1772195972f6Sopenharmony_ci if (err == ERR_OK) { 1773195972f6Sopenharmony_ci conn->current_msg->msg.w.offset += len; 1774195972f6Sopenharmony_ci conn->current_msg->msg.w.vector_off += len; 1775195972f6Sopenharmony_ci /* check if current vector is finished */ 1776195972f6Sopenharmony_ci if (conn->current_msg->msg.w.vector_off == conn->current_msg->msg.w.vector->len) { 1777195972f6Sopenharmony_ci conn->current_msg->msg.w.vector_cnt--; 1778195972f6Sopenharmony_ci /* if we have additional vectors, move on to them */ 1779195972f6Sopenharmony_ci if (conn->current_msg->msg.w.vector_cnt > 0) { 1780195972f6Sopenharmony_ci conn->current_msg->msg.w.vector++; 1781195972f6Sopenharmony_ci conn->current_msg->msg.w.vector_off = 0; 1782195972f6Sopenharmony_ci } 1783195972f6Sopenharmony_ci } 1784195972f6Sopenharmony_ci } 1785195972f6Sopenharmony_ci } while (write_more && err == ERR_OK); 1786195972f6Sopenharmony_ci /* if OK or memory error, check available space */ 1787195972f6Sopenharmony_ci if ((err == ERR_OK) || (err == ERR_MEM)) { 1788195972f6Sopenharmony_cierr_mem: 1789195972f6Sopenharmony_ci if (dontblock && (conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len)) { 1790195972f6Sopenharmony_ci /* non-blocking write did not write everything: mark the pcb non-writable 1791195972f6Sopenharmony_ci and let poll_tcp check writable space to mark the pcb writable again */ 1792195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0); 1793195972f6Sopenharmony_ci conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; 1794195972f6Sopenharmony_ci } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || 1795195972f6Sopenharmony_ci (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { 1796195972f6Sopenharmony_ci /* The queued byte- or pbuf-count exceeds the configured low-water limit, 1797195972f6Sopenharmony_ci let select mark this pcb as non-writable. */ 1798195972f6Sopenharmony_ci API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0); 1799195972f6Sopenharmony_ci } 1800195972f6Sopenharmony_ci } 1801195972f6Sopenharmony_ci 1802195972f6Sopenharmony_ci if (err == ERR_OK) { 1803195972f6Sopenharmony_ci err_t out_err; 1804195972f6Sopenharmony_ci if ((conn->current_msg->msg.w.offset == conn->current_msg->msg.w.len) || dontblock) { 1805195972f6Sopenharmony_ci /* return sent length (caller reads length from msg.w.offset) */ 1806195972f6Sopenharmony_ci write_finished = 1; 1807195972f6Sopenharmony_ci } 1808195972f6Sopenharmony_ci out_err = tcp_output(conn->pcb.tcp); 1809195972f6Sopenharmony_ci if (out_err == ERR_RTE) { 1810195972f6Sopenharmony_ci /* If tcp_output fails because no route is found, 1811195972f6Sopenharmony_ci don't try writing any more but return the error 1812195972f6Sopenharmony_ci to the application thread. */ 1813195972f6Sopenharmony_ci err = out_err; 1814195972f6Sopenharmony_ci write_finished = 1; 1815195972f6Sopenharmony_ci } 1816195972f6Sopenharmony_ci } else if (err == ERR_MEM) { 1817195972f6Sopenharmony_ci /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called. 1818195972f6Sopenharmony_ci For blocking sockets, we do NOT return to the application 1819195972f6Sopenharmony_ci thread, since ERR_MEM is only a temporary error! Non-blocking 1820195972f6Sopenharmony_ci will remain non-writable until sent_tcp/poll_tcp is called */ 1821195972f6Sopenharmony_ci 1822195972f6Sopenharmony_ci /* tcp_write returned ERR_MEM, try tcp_output anyway */ 1823195972f6Sopenharmony_ci err_t out_err = tcp_output(conn->pcb.tcp); 1824195972f6Sopenharmony_ci if (out_err == ERR_RTE) { 1825195972f6Sopenharmony_ci /* If tcp_output fails because no route is found, 1826195972f6Sopenharmony_ci don't try writing any more but return the error 1827195972f6Sopenharmony_ci to the application thread. */ 1828195972f6Sopenharmony_ci err = out_err; 1829195972f6Sopenharmony_ci write_finished = 1; 1830195972f6Sopenharmony_ci } else if (dontblock) { 1831195972f6Sopenharmony_ci /* non-blocking write is done on ERR_MEM, set error according 1832195972f6Sopenharmony_ci to partial write or not */ 1833195972f6Sopenharmony_ci err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK; 1834195972f6Sopenharmony_ci write_finished = 1; 1835195972f6Sopenharmony_ci } 1836195972f6Sopenharmony_ci } else { 1837195972f6Sopenharmony_ci /* On errors != ERR_MEM, we don't try writing any more but return 1838195972f6Sopenharmony_ci the error to the application thread. */ 1839195972f6Sopenharmony_ci write_finished = 1; 1840195972f6Sopenharmony_ci } 1841195972f6Sopenharmony_ci } 1842195972f6Sopenharmony_ci if (write_finished) { 1843195972f6Sopenharmony_ci /* everything was written: set back connection state 1844195972f6Sopenharmony_ci and back to application task */ 1845195972f6Sopenharmony_ci sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); 1846195972f6Sopenharmony_ci conn->current_msg->err = err; 1847195972f6Sopenharmony_ci conn->current_msg = NULL; 1848195972f6Sopenharmony_ci conn->state = NETCONN_NONE; 1849195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 1850195972f6Sopenharmony_ci if (delayed) 1851195972f6Sopenharmony_ci#endif 1852195972f6Sopenharmony_ci { 1853195972f6Sopenharmony_ci sys_sem_signal(op_completed_sem); 1854195972f6Sopenharmony_ci } 1855195972f6Sopenharmony_ci } 1856195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 1857195972f6Sopenharmony_ci else { 1858195972f6Sopenharmony_ci return ERR_MEM; 1859195972f6Sopenharmony_ci } 1860195972f6Sopenharmony_ci#endif 1861195972f6Sopenharmony_ci return ERR_OK; 1862195972f6Sopenharmony_ci} 1863195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 1864195972f6Sopenharmony_ci 1865195972f6Sopenharmony_ci/** 1866195972f6Sopenharmony_ci * Send some data on a TCP pcb contained in a netconn 1867195972f6Sopenharmony_ci * Called from netconn_write 1868195972f6Sopenharmony_ci * 1869195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection 1870195972f6Sopenharmony_ci */ 1871195972f6Sopenharmony_civoid 1872195972f6Sopenharmony_cilwip_netconn_do_write(void *m) 1873195972f6Sopenharmony_ci{ 1874195972f6Sopenharmony_ci struct api_msg *msg = (struct api_msg *)m; 1875195972f6Sopenharmony_ci 1876195972f6Sopenharmony_ci err_t err = netconn_err(msg->conn); 1877195972f6Sopenharmony_ci if (err == ERR_OK) { 1878195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { 1879195972f6Sopenharmony_ci#if LWIP_TCP 1880195972f6Sopenharmony_ci if (msg->conn->state != NETCONN_NONE) { 1881195972f6Sopenharmony_ci /* netconn is connecting, closing or in blocking write */ 1882195972f6Sopenharmony_ci err = ERR_INPROGRESS; 1883195972f6Sopenharmony_ci } else if (msg->conn->pcb.tcp != NULL) { 1884195972f6Sopenharmony_ci msg->conn->state = NETCONN_WRITE; 1885195972f6Sopenharmony_ci /* set all the variables used by lwip_netconn_do_writemore */ 1886195972f6Sopenharmony_ci LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL); 1887195972f6Sopenharmony_ci LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0); 1888195972f6Sopenharmony_ci msg->conn->current_msg = msg; 1889195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 1890195972f6Sopenharmony_ci if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) { 1891195972f6Sopenharmony_ci LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); 1892195972f6Sopenharmony_ci UNLOCK_TCPIP_CORE(); 1893195972f6Sopenharmony_ci sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 1894195972f6Sopenharmony_ci LOCK_TCPIP_CORE(); 1895195972f6Sopenharmony_ci LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE); 1896195972f6Sopenharmony_ci } 1897195972f6Sopenharmony_ci#else /* LWIP_TCPIP_CORE_LOCKING */ 1898195972f6Sopenharmony_ci lwip_netconn_do_writemore(msg->conn); 1899195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */ 1900195972f6Sopenharmony_ci /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG 1901195972f6Sopenharmony_ci since lwip_netconn_do_writemore ACKs it! */ 1902195972f6Sopenharmony_ci return; 1903195972f6Sopenharmony_ci } else { 1904195972f6Sopenharmony_ci err = ERR_CONN; 1905195972f6Sopenharmony_ci } 1906195972f6Sopenharmony_ci#else /* LWIP_TCP */ 1907195972f6Sopenharmony_ci err = ERR_VAL; 1908195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 1909195972f6Sopenharmony_ci#if (LWIP_UDP || LWIP_RAW) 1910195972f6Sopenharmony_ci } else { 1911195972f6Sopenharmony_ci err = ERR_VAL; 1912195972f6Sopenharmony_ci#endif /* (LWIP_UDP || LWIP_RAW) */ 1913195972f6Sopenharmony_ci } 1914195972f6Sopenharmony_ci } 1915195972f6Sopenharmony_ci msg->err = err; 1916195972f6Sopenharmony_ci TCPIP_APIMSG_ACK(msg); 1917195972f6Sopenharmony_ci} 1918195972f6Sopenharmony_ci 1919195972f6Sopenharmony_ci/** 1920195972f6Sopenharmony_ci * Return a connection's local or remote address 1921195972f6Sopenharmony_ci * Called from netconn_getaddr 1922195972f6Sopenharmony_ci * 1923195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection 1924195972f6Sopenharmony_ci */ 1925195972f6Sopenharmony_civoid 1926195972f6Sopenharmony_cilwip_netconn_do_getaddr(void *m) 1927195972f6Sopenharmony_ci{ 1928195972f6Sopenharmony_ci struct api_msg *msg = (struct api_msg *)m; 1929195972f6Sopenharmony_ci 1930195972f6Sopenharmony_ci if (msg->conn->pcb.ip != NULL) { 1931195972f6Sopenharmony_ci if (msg->msg.ad.local) { 1932195972f6Sopenharmony_ci ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), 1933195972f6Sopenharmony_ci msg->conn->pcb.ip->local_ip); 1934195972f6Sopenharmony_ci } else { 1935195972f6Sopenharmony_ci ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), 1936195972f6Sopenharmony_ci msg->conn->pcb.ip->remote_ip); 1937195972f6Sopenharmony_ci } 1938195972f6Sopenharmony_ci 1939195972f6Sopenharmony_ci msg->err = ERR_OK; 1940195972f6Sopenharmony_ci switch (NETCONNTYPE_GROUP(msg->conn->type)) { 1941195972f6Sopenharmony_ci#if LWIP_RAW 1942195972f6Sopenharmony_ci case NETCONN_RAW: 1943195972f6Sopenharmony_ci if (msg->msg.ad.local) { 1944195972f6Sopenharmony_ci API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; 1945195972f6Sopenharmony_ci } else { 1946195972f6Sopenharmony_ci /* return an error as connecting is only a helper for upper layers */ 1947195972f6Sopenharmony_ci msg->err = ERR_CONN; 1948195972f6Sopenharmony_ci } 1949195972f6Sopenharmony_ci break; 1950195972f6Sopenharmony_ci#endif /* LWIP_RAW */ 1951195972f6Sopenharmony_ci#if LWIP_UDP 1952195972f6Sopenharmony_ci case NETCONN_UDP: 1953195972f6Sopenharmony_ci if (msg->msg.ad.local) { 1954195972f6Sopenharmony_ci API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; 1955195972f6Sopenharmony_ci } else { 1956195972f6Sopenharmony_ci if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { 1957195972f6Sopenharmony_ci msg->err = ERR_CONN; 1958195972f6Sopenharmony_ci } else { 1959195972f6Sopenharmony_ci API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; 1960195972f6Sopenharmony_ci } 1961195972f6Sopenharmony_ci } 1962195972f6Sopenharmony_ci break; 1963195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 1964195972f6Sopenharmony_ci#if LWIP_TCP 1965195972f6Sopenharmony_ci case NETCONN_TCP: 1966195972f6Sopenharmony_ci if ((msg->msg.ad.local == 0) && 1967195972f6Sopenharmony_ci ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) { 1968195972f6Sopenharmony_ci /* pcb is not connected and remote name is requested */ 1969195972f6Sopenharmony_ci msg->err = ERR_CONN; 1970195972f6Sopenharmony_ci } else { 1971195972f6Sopenharmony_ci API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port); 1972195972f6Sopenharmony_ci } 1973195972f6Sopenharmony_ci break; 1974195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 1975195972f6Sopenharmony_ci default: 1976195972f6Sopenharmony_ci LWIP_ASSERT("invalid netconn_type", 0); 1977195972f6Sopenharmony_ci break; 1978195972f6Sopenharmony_ci } 1979195972f6Sopenharmony_ci } else { 1980195972f6Sopenharmony_ci msg->err = ERR_CONN; 1981195972f6Sopenharmony_ci } 1982195972f6Sopenharmony_ci TCPIP_APIMSG_ACK(msg); 1983195972f6Sopenharmony_ci} 1984195972f6Sopenharmony_ci 1985195972f6Sopenharmony_ci/** 1986195972f6Sopenharmony_ci * Close or half-shutdown a TCP pcb contained in a netconn 1987195972f6Sopenharmony_ci * Called from netconn_close 1988195972f6Sopenharmony_ci * In contrast to closing sockets, the netconn is not deallocated. 1989195972f6Sopenharmony_ci * 1990195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection 1991195972f6Sopenharmony_ci */ 1992195972f6Sopenharmony_civoid 1993195972f6Sopenharmony_cilwip_netconn_do_close(void *m) 1994195972f6Sopenharmony_ci{ 1995195972f6Sopenharmony_ci struct api_msg *msg = (struct api_msg *)m; 1996195972f6Sopenharmony_ci 1997195972f6Sopenharmony_ci#if LWIP_TCP 1998195972f6Sopenharmony_ci enum netconn_state state = msg->conn->state; 1999195972f6Sopenharmony_ci /* First check if this is a TCP netconn and if it is in a correct state 2000195972f6Sopenharmony_ci (LISTEN doesn't support half shutdown) */ 2001195972f6Sopenharmony_ci if ((msg->conn->pcb.tcp != NULL) && 2002195972f6Sopenharmony_ci (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) && 2003195972f6Sopenharmony_ci ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) { 2004195972f6Sopenharmony_ci /* Check if we are in a connected state */ 2005195972f6Sopenharmony_ci if (state == NETCONN_CONNECT) { 2006195972f6Sopenharmony_ci /* TCP connect in progress: cannot shutdown */ 2007195972f6Sopenharmony_ci msg->err = ERR_CONN; 2008195972f6Sopenharmony_ci } else if (state == NETCONN_WRITE) { 2009195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 2010195972f6Sopenharmony_ci if (msg->msg.sd.shut & NETCONN_SHUT_WR) { 2011195972f6Sopenharmony_ci /* close requested, abort running write */ 2012195972f6Sopenharmony_ci sys_sem_t *write_completed_sem; 2013195972f6Sopenharmony_ci LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL); 2014195972f6Sopenharmony_ci write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg); 2015195972f6Sopenharmony_ci msg->conn->current_msg->err = ERR_CLSD; 2016195972f6Sopenharmony_ci msg->conn->current_msg = NULL; 2017195972f6Sopenharmony_ci msg->conn->state = NETCONN_NONE; 2018195972f6Sopenharmony_ci state = NETCONN_NONE; 2019195972f6Sopenharmony_ci sys_sem_signal(write_completed_sem); 2020195972f6Sopenharmony_ci } else { 2021195972f6Sopenharmony_ci LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD); 2022195972f6Sopenharmony_ci /* In this case, let the write continue and do not interfere with 2023195972f6Sopenharmony_ci conn->current_msg or conn->state! */ 2024195972f6Sopenharmony_ci msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0); 2025195972f6Sopenharmony_ci } 2026195972f6Sopenharmony_ci } 2027195972f6Sopenharmony_ci if (state == NETCONN_NONE) { 2028195972f6Sopenharmony_ci#else /* LWIP_NETCONN_FULLDUPLEX */ 2029195972f6Sopenharmony_ci msg->err = ERR_INPROGRESS; 2030195972f6Sopenharmony_ci } else { 2031195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */ 2032195972f6Sopenharmony_ci if (msg->msg.sd.shut & NETCONN_SHUT_RD) { 2033195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 2034195972f6Sopenharmony_ci /* Mark mboxes invalid */ 2035195972f6Sopenharmony_ci netconn_mark_mbox_invalid(msg->conn); 2036195972f6Sopenharmony_ci#else /* LWIP_NETCONN_FULLDUPLEX */ 2037195972f6Sopenharmony_ci netconn_drain(msg->conn); 2038195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */ 2039195972f6Sopenharmony_ci } 2040195972f6Sopenharmony_ci LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL); 2041195972f6Sopenharmony_ci msg->conn->state = NETCONN_CLOSE; 2042195972f6Sopenharmony_ci msg->conn->current_msg = msg; 2043195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 2044195972f6Sopenharmony_ci if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) { 2045195972f6Sopenharmony_ci LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE); 2046195972f6Sopenharmony_ci UNLOCK_TCPIP_CORE(); 2047195972f6Sopenharmony_ci sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); 2048195972f6Sopenharmony_ci LOCK_TCPIP_CORE(); 2049195972f6Sopenharmony_ci LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); 2050195972f6Sopenharmony_ci } 2051195972f6Sopenharmony_ci#else /* LWIP_TCPIP_CORE_LOCKING */ 2052195972f6Sopenharmony_ci lwip_netconn_do_close_internal(msg->conn); 2053195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */ 2054195972f6Sopenharmony_ci /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */ 2055195972f6Sopenharmony_ci return; 2056195972f6Sopenharmony_ci } 2057195972f6Sopenharmony_ci } else 2058195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 2059195972f6Sopenharmony_ci { 2060195972f6Sopenharmony_ci msg->err = ERR_CONN; 2061195972f6Sopenharmony_ci } 2062195972f6Sopenharmony_ci TCPIP_APIMSG_ACK(msg); 2063195972f6Sopenharmony_ci} 2064195972f6Sopenharmony_ci 2065195972f6Sopenharmony_ci#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) 2066195972f6Sopenharmony_ci/** 2067195972f6Sopenharmony_ci * Join multicast groups for UDP netconns. 2068195972f6Sopenharmony_ci * Called from netconn_join_leave_group 2069195972f6Sopenharmony_ci * 2070195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection 2071195972f6Sopenharmony_ci */ 2072195972f6Sopenharmony_civoid 2073195972f6Sopenharmony_cilwip_netconn_do_join_leave_group(void *m) 2074195972f6Sopenharmony_ci{ 2075195972f6Sopenharmony_ci struct api_msg *msg = (struct api_msg *)m; 2076195972f6Sopenharmony_ci 2077195972f6Sopenharmony_ci msg->err = ERR_CONN; 2078195972f6Sopenharmony_ci if (msg->conn->pcb.tcp != NULL) { 2079195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 2080195972f6Sopenharmony_ci#if LWIP_UDP 2081195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_IPV6_MLD 2082195972f6Sopenharmony_ci if (NETCONNTYPE_ISIPV6(msg->conn->type)) { 2083195972f6Sopenharmony_ci if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 2084195972f6Sopenharmony_ci msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), 2085195972f6Sopenharmony_ci ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); 2086195972f6Sopenharmony_ci } else { 2087195972f6Sopenharmony_ci msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), 2088195972f6Sopenharmony_ci ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); 2089195972f6Sopenharmony_ci } 2090195972f6Sopenharmony_ci } else 2091195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ 2092195972f6Sopenharmony_ci { 2093195972f6Sopenharmony_ci#if LWIP_IGMP 2094195972f6Sopenharmony_ci if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 2095195972f6Sopenharmony_ci msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), 2096195972f6Sopenharmony_ci ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); 2097195972f6Sopenharmony_ci } else { 2098195972f6Sopenharmony_ci msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), 2099195972f6Sopenharmony_ci ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); 2100195972f6Sopenharmony_ci } 2101195972f6Sopenharmony_ci#endif /* LWIP_IGMP */ 2102195972f6Sopenharmony_ci } 2103195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 2104195972f6Sopenharmony_ci#if (LWIP_TCP || LWIP_RAW) 2105195972f6Sopenharmony_ci } else { 2106195972f6Sopenharmony_ci msg->err = ERR_VAL; 2107195972f6Sopenharmony_ci#endif /* (LWIP_TCP || LWIP_RAW) */ 2108195972f6Sopenharmony_ci } 2109195972f6Sopenharmony_ci } 2110195972f6Sopenharmony_ci TCPIP_APIMSG_ACK(msg); 2111195972f6Sopenharmony_ci} 2112195972f6Sopenharmony_ci/** 2113195972f6Sopenharmony_ci * Join multicast groups for UDP netconns. 2114195972f6Sopenharmony_ci * Called from netconn_join_leave_group_netif 2115195972f6Sopenharmony_ci * 2116195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection 2117195972f6Sopenharmony_ci */ 2118195972f6Sopenharmony_civoid 2119195972f6Sopenharmony_cilwip_netconn_do_join_leave_group_netif(void *m) 2120195972f6Sopenharmony_ci{ 2121195972f6Sopenharmony_ci struct api_msg *msg = (struct api_msg *)m; 2122195972f6Sopenharmony_ci struct netif *netif; 2123195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 2124195972f6Sopenharmony_ci struct net_group *group = get_net_group_from_ippcb(msg->conn->pcb.ip); 2125195972f6Sopenharmony_ci 2126195972f6Sopenharmony_ci if (group != NULL) { 2127195972f6Sopenharmony_ci netif = netif_get_by_index(msg->msg.jl.if_idx, group); 2128195972f6Sopenharmony_ci } else { 2129195972f6Sopenharmony_ci netif = NULL; 2130195972f6Sopenharmony_ci } 2131195972f6Sopenharmony_ci#else 2132195972f6Sopenharmony_ci netif = netif_get_by_index(msg->msg.jl.if_idx); 2133195972f6Sopenharmony_ci#endif 2134195972f6Sopenharmony_ci 2135195972f6Sopenharmony_ci if (netif == NULL) { 2136195972f6Sopenharmony_ci msg->err = ERR_IF; 2137195972f6Sopenharmony_ci goto done; 2138195972f6Sopenharmony_ci } 2139195972f6Sopenharmony_ci 2140195972f6Sopenharmony_ci msg->err = ERR_CONN; 2141195972f6Sopenharmony_ci if (msg->conn->pcb.tcp != NULL) { 2142195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { 2143195972f6Sopenharmony_ci#if LWIP_UDP 2144195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_IPV6_MLD 2145195972f6Sopenharmony_ci if (NETCONNTYPE_ISIPV6(msg->conn->type)) { 2146195972f6Sopenharmony_ci if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 2147195972f6Sopenharmony_ci msg->err = mld6_joingroup_netif(netif, 2148195972f6Sopenharmony_ci ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); 2149195972f6Sopenharmony_ci } else { 2150195972f6Sopenharmony_ci msg->err = mld6_leavegroup_netif(netif, 2151195972f6Sopenharmony_ci ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); 2152195972f6Sopenharmony_ci } 2153195972f6Sopenharmony_ci } else 2154195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ 2155195972f6Sopenharmony_ci { 2156195972f6Sopenharmony_ci#if LWIP_IGMP 2157195972f6Sopenharmony_ci if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { 2158195972f6Sopenharmony_ci msg->err = igmp_joingroup_netif(netif, 2159195972f6Sopenharmony_ci ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); 2160195972f6Sopenharmony_ci } else { 2161195972f6Sopenharmony_ci msg->err = igmp_leavegroup_netif(netif, 2162195972f6Sopenharmony_ci ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); 2163195972f6Sopenharmony_ci } 2164195972f6Sopenharmony_ci#endif /* LWIP_IGMP */ 2165195972f6Sopenharmony_ci } 2166195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 2167195972f6Sopenharmony_ci#if (LWIP_TCP || LWIP_RAW) 2168195972f6Sopenharmony_ci } else { 2169195972f6Sopenharmony_ci msg->err = ERR_VAL; 2170195972f6Sopenharmony_ci#endif /* (LWIP_TCP || LWIP_RAW) */ 2171195972f6Sopenharmony_ci } 2172195972f6Sopenharmony_ci } 2173195972f6Sopenharmony_ci 2174195972f6Sopenharmony_cidone: 2175195972f6Sopenharmony_ci TCPIP_APIMSG_ACK(msg); 2176195972f6Sopenharmony_ci} 2177195972f6Sopenharmony_ci#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ 2178195972f6Sopenharmony_ci 2179195972f6Sopenharmony_ci#if LWIP_DNS 2180195972f6Sopenharmony_ci/** 2181195972f6Sopenharmony_ci * Callback function that is called when DNS name is resolved 2182195972f6Sopenharmony_ci * (or on timeout). A waiting application thread is waked up by 2183195972f6Sopenharmony_ci * signaling the semaphore. 2184195972f6Sopenharmony_ci */ 2185195972f6Sopenharmony_cistatic void 2186195972f6Sopenharmony_cilwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg) 2187195972f6Sopenharmony_ci{ 2188195972f6Sopenharmony_ci struct dns_api_msg *msg = (struct dns_api_msg *)arg; 2189195972f6Sopenharmony_ci 2190195972f6Sopenharmony_ci /* we trust the internal implementation to be correct :-) */ 2191195972f6Sopenharmony_ci LWIP_UNUSED_ARG(name); 2192195972f6Sopenharmony_ci 2193195972f6Sopenharmony_ci if (ipaddr == NULL) { 2194195972f6Sopenharmony_ci /* timeout or memory error */ 2195195972f6Sopenharmony_ci API_EXPR_DEREF(msg->err) = ERR_VAL; 2196195972f6Sopenharmony_ci } else { 2197195972f6Sopenharmony_ci /* address was resolved */ 2198195972f6Sopenharmony_ci API_EXPR_DEREF(msg->err) = ERR_OK; 2199195972f6Sopenharmony_ci API_EXPR_DEREF(msg->addr) = *ipaddr; 2200195972f6Sopenharmony_ci } 2201195972f6Sopenharmony_ci /* wake up the application task waiting in netconn_gethostbyname */ 2202195972f6Sopenharmony_ci sys_sem_signal(API_EXPR_REF_SEM(msg->sem)); 2203195972f6Sopenharmony_ci} 2204195972f6Sopenharmony_ci 2205195972f6Sopenharmony_ci/** 2206195972f6Sopenharmony_ci * Execute a DNS query 2207195972f6Sopenharmony_ci * Called from netconn_gethostbyname 2208195972f6Sopenharmony_ci * 2209195972f6Sopenharmony_ci * @param arg the dns_api_msg pointing to the query 2210195972f6Sopenharmony_ci */ 2211195972f6Sopenharmony_civoid 2212195972f6Sopenharmony_cilwip_netconn_do_gethostbyname(void *arg) 2213195972f6Sopenharmony_ci{ 2214195972f6Sopenharmony_ci struct dns_api_msg *msg = (struct dns_api_msg *)arg; 2215195972f6Sopenharmony_ci u8_t addrtype = 2216195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 2217195972f6Sopenharmony_ci msg->dns_addrtype; 2218195972f6Sopenharmony_ci#else 2219195972f6Sopenharmony_ci LWIP_DNS_ADDRTYPE_DEFAULT; 2220195972f6Sopenharmony_ci#endif 2221195972f6Sopenharmony_ci 2222195972f6Sopenharmony_ci API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name, 2223195972f6Sopenharmony_ci API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype); 2224195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 2225195972f6Sopenharmony_ci /* For core locking, only block if we need to wait for answer/timeout */ 2226195972f6Sopenharmony_ci if (API_EXPR_DEREF(msg->err) == ERR_INPROGRESS) { 2227195972f6Sopenharmony_ci UNLOCK_TCPIP_CORE(); 2228195972f6Sopenharmony_ci sys_sem_wait(API_EXPR_REF_SEM(msg->sem)); 2229195972f6Sopenharmony_ci LOCK_TCPIP_CORE(); 2230195972f6Sopenharmony_ci LWIP_ASSERT("do_gethostbyname still in progress!!", API_EXPR_DEREF(msg->err) != ERR_INPROGRESS); 2231195972f6Sopenharmony_ci } 2232195972f6Sopenharmony_ci#else /* LWIP_TCPIP_CORE_LOCKING */ 2233195972f6Sopenharmony_ci if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) { 2234195972f6Sopenharmony_ci /* on error or immediate success, wake up the application 2235195972f6Sopenharmony_ci * task waiting in netconn_gethostbyname */ 2236195972f6Sopenharmony_ci sys_sem_signal(API_EXPR_REF_SEM(msg->sem)); 2237195972f6Sopenharmony_ci } 2238195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */ 2239195972f6Sopenharmony_ci} 2240195972f6Sopenharmony_ci#endif /* LWIP_DNS */ 2241195972f6Sopenharmony_ci 2242195972f6Sopenharmony_ci#endif /* LWIP_NETCONN */ 2243