1195972f6Sopenharmony_ci/** 2195972f6Sopenharmony_ci * @file 3195972f6Sopenharmony_ci * Application layered TCP connection API (to be used from TCPIP thread)\n 4195972f6Sopenharmony_ci * This interface mimics the tcp callback API to the application while preventing 5195972f6Sopenharmony_ci * direct linking (much like virtual functions). 6195972f6Sopenharmony_ci * This way, an application can make use of other application layer protocols 7195972f6Sopenharmony_ci * on top of TCP without knowing the details (e.g. TLS, proxy connection). 8195972f6Sopenharmony_ci * 9195972f6Sopenharmony_ci * This file contains the base implementation calling into tcp. 10195972f6Sopenharmony_ci */ 11195972f6Sopenharmony_ci 12195972f6Sopenharmony_ci/* 13195972f6Sopenharmony_ci * Copyright (c) 2017 Simon Goldschmidt 14195972f6Sopenharmony_ci * All rights reserved. 15195972f6Sopenharmony_ci * 16195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 17195972f6Sopenharmony_ci * are permitted provided that the following conditions are met: 18195972f6Sopenharmony_ci * 19195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, 20195972f6Sopenharmony_ci * this list of conditions and the following disclaimer. 21195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, 22195972f6Sopenharmony_ci * this list of conditions and the following disclaimer in the documentation 23195972f6Sopenharmony_ci * and/or other materials provided with the distribution. 24195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products 25195972f6Sopenharmony_ci * derived from this software without specific prior written permission. 26195972f6Sopenharmony_ci * 27195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 28195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 29195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 30195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 31195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 32195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 35195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 36195972f6Sopenharmony_ci * OF SUCH DAMAGE. 37195972f6Sopenharmony_ci * 38195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack. 39195972f6Sopenharmony_ci * 40195972f6Sopenharmony_ci * Author: Simon Goldschmidt <goldsimon@gmx.de> 41195972f6Sopenharmony_ci * 42195972f6Sopenharmony_ci */ 43195972f6Sopenharmony_ci 44195972f6Sopenharmony_ci#include "lwip/opt.h" 45195972f6Sopenharmony_ci 46195972f6Sopenharmony_ci#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ 47195972f6Sopenharmony_ci 48195972f6Sopenharmony_ci#include "lwip/altcp.h" 49195972f6Sopenharmony_ci#include "lwip/altcp_tcp.h" 50195972f6Sopenharmony_ci#include "lwip/priv/altcp_priv.h" 51195972f6Sopenharmony_ci#include "lwip/tcp.h" 52195972f6Sopenharmony_ci#include "lwip/priv/tcp_priv.h" 53195972f6Sopenharmony_ci#include "lwip/mem.h" 54195972f6Sopenharmony_ci 55195972f6Sopenharmony_ci#include <string.h> 56195972f6Sopenharmony_ci 57195972f6Sopenharmony_ci#define ALTCP_TCP_ASSERT_CONN(conn) do { \ 58195972f6Sopenharmony_ci LWIP_ASSERT("conn->inner_conn == NULL", (conn)->inner_conn == NULL); \ 59195972f6Sopenharmony_ci LWIP_UNUSED_ARG(conn); /* for LWIP_NOASSERT */ } while(0) 60195972f6Sopenharmony_ci#define ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb) do { \ 61195972f6Sopenharmony_ci LWIP_ASSERT("pcb mismatch", (conn)->state == tpcb); \ 62195972f6Sopenharmony_ci LWIP_UNUSED_ARG(tpcb); /* for LWIP_NOASSERT */ \ 63195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); } while(0) 64195972f6Sopenharmony_ci 65195972f6Sopenharmony_ci 66195972f6Sopenharmony_ci/* Variable prototype, the actual declaration is at the end of this file 67195972f6Sopenharmony_ci since it contains pointers to static functions declared here */ 68195972f6Sopenharmony_ciextern const struct altcp_functions altcp_tcp_functions; 69195972f6Sopenharmony_ci 70195972f6Sopenharmony_cistatic void altcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb); 71195972f6Sopenharmony_ci 72195972f6Sopenharmony_ci/* callback functions for TCP */ 73195972f6Sopenharmony_cistatic err_t 74195972f6Sopenharmony_cialtcp_tcp_accept(void *arg, struct tcp_pcb *new_tpcb, err_t err) 75195972f6Sopenharmony_ci{ 76195972f6Sopenharmony_ci struct altcp_pcb *listen_conn = (struct altcp_pcb *)arg; 77195972f6Sopenharmony_ci if (listen_conn && listen_conn->accept) { 78195972f6Sopenharmony_ci /* create a new altcp_conn to pass to the next 'accept' callback */ 79195972f6Sopenharmony_ci struct altcp_pcb *new_conn = altcp_alloc(); 80195972f6Sopenharmony_ci if (new_conn == NULL) { 81195972f6Sopenharmony_ci return ERR_MEM; 82195972f6Sopenharmony_ci } 83195972f6Sopenharmony_ci altcp_tcp_setup(new_conn, new_tpcb); 84195972f6Sopenharmony_ci return listen_conn->accept(listen_conn->arg, new_conn, err); 85195972f6Sopenharmony_ci } 86195972f6Sopenharmony_ci return ERR_ARG; 87195972f6Sopenharmony_ci} 88195972f6Sopenharmony_ci 89195972f6Sopenharmony_cistatic err_t 90195972f6Sopenharmony_cialtcp_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) 91195972f6Sopenharmony_ci{ 92195972f6Sopenharmony_ci struct altcp_pcb *conn = (struct altcp_pcb *)arg; 93195972f6Sopenharmony_ci if (conn) { 94195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb); 95195972f6Sopenharmony_ci if (conn->connected) { 96195972f6Sopenharmony_ci return conn->connected(conn->arg, conn, err); 97195972f6Sopenharmony_ci } 98195972f6Sopenharmony_ci } 99195972f6Sopenharmony_ci return ERR_OK; 100195972f6Sopenharmony_ci} 101195972f6Sopenharmony_ci 102195972f6Sopenharmony_cistatic err_t 103195972f6Sopenharmony_cialtcp_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) 104195972f6Sopenharmony_ci{ 105195972f6Sopenharmony_ci struct altcp_pcb *conn = (struct altcp_pcb *)arg; 106195972f6Sopenharmony_ci if (conn) { 107195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb); 108195972f6Sopenharmony_ci if (conn->recv) { 109195972f6Sopenharmony_ci return conn->recv(conn->arg, conn, p, err); 110195972f6Sopenharmony_ci } 111195972f6Sopenharmony_ci } 112195972f6Sopenharmony_ci if (p != NULL) { 113195972f6Sopenharmony_ci /* prevent memory leaks */ 114195972f6Sopenharmony_ci pbuf_free(p); 115195972f6Sopenharmony_ci } 116195972f6Sopenharmony_ci return ERR_OK; 117195972f6Sopenharmony_ci} 118195972f6Sopenharmony_ci 119195972f6Sopenharmony_cistatic err_t 120195972f6Sopenharmony_cialtcp_tcp_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) 121195972f6Sopenharmony_ci{ 122195972f6Sopenharmony_ci struct altcp_pcb *conn = (struct altcp_pcb *)arg; 123195972f6Sopenharmony_ci if (conn) { 124195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb); 125195972f6Sopenharmony_ci if (conn->sent) { 126195972f6Sopenharmony_ci return conn->sent(conn->arg, conn, len); 127195972f6Sopenharmony_ci } 128195972f6Sopenharmony_ci } 129195972f6Sopenharmony_ci return ERR_OK; 130195972f6Sopenharmony_ci} 131195972f6Sopenharmony_ci 132195972f6Sopenharmony_cistatic err_t 133195972f6Sopenharmony_cialtcp_tcp_poll(void *arg, struct tcp_pcb *tpcb) 134195972f6Sopenharmony_ci{ 135195972f6Sopenharmony_ci struct altcp_pcb *conn = (struct altcp_pcb *)arg; 136195972f6Sopenharmony_ci if (conn) { 137195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb); 138195972f6Sopenharmony_ci if (conn->poll) { 139195972f6Sopenharmony_ci return conn->poll(conn->arg, conn); 140195972f6Sopenharmony_ci } 141195972f6Sopenharmony_ci } 142195972f6Sopenharmony_ci return ERR_OK; 143195972f6Sopenharmony_ci} 144195972f6Sopenharmony_ci 145195972f6Sopenharmony_cistatic void 146195972f6Sopenharmony_cialtcp_tcp_err(void *arg, err_t err) 147195972f6Sopenharmony_ci{ 148195972f6Sopenharmony_ci struct altcp_pcb *conn = (struct altcp_pcb *)arg; 149195972f6Sopenharmony_ci if (conn) { 150195972f6Sopenharmony_ci conn->state = NULL; /* already freed */ 151195972f6Sopenharmony_ci if (conn->err) { 152195972f6Sopenharmony_ci conn->err(conn->arg, err); 153195972f6Sopenharmony_ci } 154195972f6Sopenharmony_ci altcp_free(conn); 155195972f6Sopenharmony_ci } 156195972f6Sopenharmony_ci} 157195972f6Sopenharmony_ci 158195972f6Sopenharmony_ci/* setup functions */ 159195972f6Sopenharmony_ci 160195972f6Sopenharmony_cistatic void 161195972f6Sopenharmony_cialtcp_tcp_remove_callbacks(struct tcp_pcb *tpcb) 162195972f6Sopenharmony_ci{ 163195972f6Sopenharmony_ci tcp_arg(tpcb, NULL); 164195972f6Sopenharmony_ci if (tpcb->state != LISTEN) { 165195972f6Sopenharmony_ci tcp_recv(tpcb, NULL); 166195972f6Sopenharmony_ci tcp_sent(tpcb, NULL); 167195972f6Sopenharmony_ci tcp_err(tpcb, NULL); 168195972f6Sopenharmony_ci tcp_poll(tpcb, NULL, tpcb->pollinterval); 169195972f6Sopenharmony_ci } 170195972f6Sopenharmony_ci} 171195972f6Sopenharmony_ci 172195972f6Sopenharmony_cistatic void 173195972f6Sopenharmony_cialtcp_tcp_setup_callbacks(struct altcp_pcb *conn, struct tcp_pcb *tpcb) 174195972f6Sopenharmony_ci{ 175195972f6Sopenharmony_ci tcp_arg(tpcb, conn); 176195972f6Sopenharmony_ci /* this might be called for LISTN when close fails... */ 177195972f6Sopenharmony_ci if (tpcb->state != LISTEN) { 178195972f6Sopenharmony_ci tcp_recv(tpcb, altcp_tcp_recv); 179195972f6Sopenharmony_ci tcp_sent(tpcb, altcp_tcp_sent); 180195972f6Sopenharmony_ci tcp_err(tpcb, altcp_tcp_err); 181195972f6Sopenharmony_ci /* tcp_poll is set when interval is set by application */ 182195972f6Sopenharmony_ci } 183195972f6Sopenharmony_ci} 184195972f6Sopenharmony_ci 185195972f6Sopenharmony_cistatic void 186195972f6Sopenharmony_cialtcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb) 187195972f6Sopenharmony_ci{ 188195972f6Sopenharmony_ci altcp_tcp_setup_callbacks(conn, tpcb); 189195972f6Sopenharmony_ci conn->state = tpcb; 190195972f6Sopenharmony_ci conn->fns = &altcp_tcp_functions; 191195972f6Sopenharmony_ci} 192195972f6Sopenharmony_ci 193195972f6Sopenharmony_cistruct altcp_pcb * 194195972f6Sopenharmony_cialtcp_tcp_new_ip_type(u8_t ip_type) 195195972f6Sopenharmony_ci{ 196195972f6Sopenharmony_ci /* Allocate the tcp pcb first to invoke the priority handling code 197195972f6Sopenharmony_ci if we're out of pcbs */ 198195972f6Sopenharmony_ci struct tcp_pcb *tpcb = tcp_new_ip_type(ip_type); 199195972f6Sopenharmony_ci if (tpcb != NULL) { 200195972f6Sopenharmony_ci struct altcp_pcb *ret = altcp_alloc(); 201195972f6Sopenharmony_ci if (ret != NULL) { 202195972f6Sopenharmony_ci altcp_tcp_setup(ret, tpcb); 203195972f6Sopenharmony_ci return ret; 204195972f6Sopenharmony_ci } else { 205195972f6Sopenharmony_ci /* altcp_pcb allocation failed -> free the tcp_pcb too */ 206195972f6Sopenharmony_ci tcp_close(tpcb); 207195972f6Sopenharmony_ci } 208195972f6Sopenharmony_ci } 209195972f6Sopenharmony_ci return NULL; 210195972f6Sopenharmony_ci} 211195972f6Sopenharmony_ci 212195972f6Sopenharmony_ci/** altcp_tcp allocator function fitting to @ref altcp_allocator_t / @ref altcp_new. 213195972f6Sopenharmony_ci* 214195972f6Sopenharmony_ci* arg pointer is not used for TCP. 215195972f6Sopenharmony_ci*/ 216195972f6Sopenharmony_cistruct altcp_pcb * 217195972f6Sopenharmony_cialtcp_tcp_alloc(void *arg, u8_t ip_type) 218195972f6Sopenharmony_ci{ 219195972f6Sopenharmony_ci LWIP_UNUSED_ARG(arg); 220195972f6Sopenharmony_ci return altcp_tcp_new_ip_type(ip_type); 221195972f6Sopenharmony_ci} 222195972f6Sopenharmony_ci 223195972f6Sopenharmony_cistruct altcp_pcb * 224195972f6Sopenharmony_cialtcp_tcp_wrap(struct tcp_pcb *tpcb) 225195972f6Sopenharmony_ci{ 226195972f6Sopenharmony_ci if (tpcb != NULL) { 227195972f6Sopenharmony_ci struct altcp_pcb *ret = altcp_alloc(); 228195972f6Sopenharmony_ci if (ret != NULL) { 229195972f6Sopenharmony_ci altcp_tcp_setup(ret, tpcb); 230195972f6Sopenharmony_ci return ret; 231195972f6Sopenharmony_ci } 232195972f6Sopenharmony_ci } 233195972f6Sopenharmony_ci return NULL; 234195972f6Sopenharmony_ci} 235195972f6Sopenharmony_ci 236195972f6Sopenharmony_ci 237195972f6Sopenharmony_ci/* "virtual" functions calling into tcp */ 238195972f6Sopenharmony_cistatic void 239195972f6Sopenharmony_cialtcp_tcp_set_poll(struct altcp_pcb *conn, u8_t interval) 240195972f6Sopenharmony_ci{ 241195972f6Sopenharmony_ci if (conn != NULL) { 242195972f6Sopenharmony_ci struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; 243195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 244195972f6Sopenharmony_ci tcp_poll(pcb, altcp_tcp_poll, interval); 245195972f6Sopenharmony_ci } 246195972f6Sopenharmony_ci} 247195972f6Sopenharmony_ci 248195972f6Sopenharmony_cistatic void 249195972f6Sopenharmony_cialtcp_tcp_recved(struct altcp_pcb *conn, u16_t len) 250195972f6Sopenharmony_ci{ 251195972f6Sopenharmony_ci if (conn != NULL) { 252195972f6Sopenharmony_ci struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; 253195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 254195972f6Sopenharmony_ci tcp_recved(pcb, len); 255195972f6Sopenharmony_ci } 256195972f6Sopenharmony_ci} 257195972f6Sopenharmony_ci 258195972f6Sopenharmony_cistatic err_t 259195972f6Sopenharmony_cialtcp_tcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port) 260195972f6Sopenharmony_ci{ 261195972f6Sopenharmony_ci struct tcp_pcb *pcb; 262195972f6Sopenharmony_ci if (conn == NULL) { 263195972f6Sopenharmony_ci return ERR_VAL; 264195972f6Sopenharmony_ci } 265195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 266195972f6Sopenharmony_ci pcb = (struct tcp_pcb *)conn->state; 267195972f6Sopenharmony_ci return tcp_bind(pcb, ipaddr, port); 268195972f6Sopenharmony_ci} 269195972f6Sopenharmony_ci 270195972f6Sopenharmony_cistatic err_t 271195972f6Sopenharmony_cialtcp_tcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected) 272195972f6Sopenharmony_ci{ 273195972f6Sopenharmony_ci struct tcp_pcb *pcb; 274195972f6Sopenharmony_ci if (conn == NULL) { 275195972f6Sopenharmony_ci return ERR_VAL; 276195972f6Sopenharmony_ci } 277195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 278195972f6Sopenharmony_ci conn->connected = connected; 279195972f6Sopenharmony_ci pcb = (struct tcp_pcb *)conn->state; 280195972f6Sopenharmony_ci return tcp_connect(pcb, ipaddr, port, altcp_tcp_connected); 281195972f6Sopenharmony_ci} 282195972f6Sopenharmony_ci 283195972f6Sopenharmony_cistatic struct altcp_pcb * 284195972f6Sopenharmony_cialtcp_tcp_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err) 285195972f6Sopenharmony_ci{ 286195972f6Sopenharmony_ci struct tcp_pcb *pcb; 287195972f6Sopenharmony_ci struct tcp_pcb *lpcb; 288195972f6Sopenharmony_ci if (conn == NULL) { 289195972f6Sopenharmony_ci return NULL; 290195972f6Sopenharmony_ci } 291195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 292195972f6Sopenharmony_ci pcb = (struct tcp_pcb *)conn->state; 293195972f6Sopenharmony_ci lpcb = tcp_listen_with_backlog_and_err(pcb, backlog, err); 294195972f6Sopenharmony_ci if (lpcb != NULL) { 295195972f6Sopenharmony_ci conn->state = lpcb; 296195972f6Sopenharmony_ci tcp_accept(lpcb, altcp_tcp_accept); 297195972f6Sopenharmony_ci return conn; 298195972f6Sopenharmony_ci } 299195972f6Sopenharmony_ci return NULL; 300195972f6Sopenharmony_ci} 301195972f6Sopenharmony_ci 302195972f6Sopenharmony_cistatic void 303195972f6Sopenharmony_cialtcp_tcp_abort(struct altcp_pcb *conn) 304195972f6Sopenharmony_ci{ 305195972f6Sopenharmony_ci if (conn != NULL) { 306195972f6Sopenharmony_ci struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; 307195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 308195972f6Sopenharmony_ci if (pcb) { 309195972f6Sopenharmony_ci tcp_abort(pcb); 310195972f6Sopenharmony_ci } 311195972f6Sopenharmony_ci } 312195972f6Sopenharmony_ci} 313195972f6Sopenharmony_ci 314195972f6Sopenharmony_cistatic err_t 315195972f6Sopenharmony_cialtcp_tcp_close(struct altcp_pcb *conn) 316195972f6Sopenharmony_ci{ 317195972f6Sopenharmony_ci struct tcp_pcb *pcb; 318195972f6Sopenharmony_ci if (conn == NULL) { 319195972f6Sopenharmony_ci return ERR_VAL; 320195972f6Sopenharmony_ci } 321195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 322195972f6Sopenharmony_ci pcb = (struct tcp_pcb *)conn->state; 323195972f6Sopenharmony_ci if (pcb) { 324195972f6Sopenharmony_ci err_t err; 325195972f6Sopenharmony_ci tcp_poll_fn oldpoll = pcb->poll; 326195972f6Sopenharmony_ci altcp_tcp_remove_callbacks(pcb); 327195972f6Sopenharmony_ci err = tcp_close(pcb); 328195972f6Sopenharmony_ci if (err != ERR_OK) { 329195972f6Sopenharmony_ci /* not closed, set up all callbacks again */ 330195972f6Sopenharmony_ci altcp_tcp_setup_callbacks(conn, pcb); 331195972f6Sopenharmony_ci /* poll callback is not included in the above */ 332195972f6Sopenharmony_ci tcp_poll(pcb, oldpoll, pcb->pollinterval); 333195972f6Sopenharmony_ci return err; 334195972f6Sopenharmony_ci } 335195972f6Sopenharmony_ci conn->state = NULL; /* unsafe to reference pcb after tcp_close(). */ 336195972f6Sopenharmony_ci } 337195972f6Sopenharmony_ci altcp_free(conn); 338195972f6Sopenharmony_ci return ERR_OK; 339195972f6Sopenharmony_ci} 340195972f6Sopenharmony_ci 341195972f6Sopenharmony_cistatic err_t 342195972f6Sopenharmony_cialtcp_tcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx) 343195972f6Sopenharmony_ci{ 344195972f6Sopenharmony_ci struct tcp_pcb *pcb; 345195972f6Sopenharmony_ci if (conn == NULL) { 346195972f6Sopenharmony_ci return ERR_VAL; 347195972f6Sopenharmony_ci } 348195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 349195972f6Sopenharmony_ci pcb = (struct tcp_pcb *)conn->state; 350195972f6Sopenharmony_ci return tcp_shutdown(pcb, shut_rx, shut_tx); 351195972f6Sopenharmony_ci} 352195972f6Sopenharmony_ci 353195972f6Sopenharmony_cistatic err_t 354195972f6Sopenharmony_cialtcp_tcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags) 355195972f6Sopenharmony_ci{ 356195972f6Sopenharmony_ci struct tcp_pcb *pcb; 357195972f6Sopenharmony_ci if (conn == NULL) { 358195972f6Sopenharmony_ci return ERR_VAL; 359195972f6Sopenharmony_ci } 360195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 361195972f6Sopenharmony_ci pcb = (struct tcp_pcb *)conn->state; 362195972f6Sopenharmony_ci return tcp_write(pcb, dataptr, len, apiflags); 363195972f6Sopenharmony_ci} 364195972f6Sopenharmony_ci 365195972f6Sopenharmony_cistatic err_t 366195972f6Sopenharmony_cialtcp_tcp_output(struct altcp_pcb *conn) 367195972f6Sopenharmony_ci{ 368195972f6Sopenharmony_ci struct tcp_pcb *pcb; 369195972f6Sopenharmony_ci if (conn == NULL) { 370195972f6Sopenharmony_ci return ERR_VAL; 371195972f6Sopenharmony_ci } 372195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 373195972f6Sopenharmony_ci pcb = (struct tcp_pcb *)conn->state; 374195972f6Sopenharmony_ci return tcp_output(pcb); 375195972f6Sopenharmony_ci} 376195972f6Sopenharmony_ci 377195972f6Sopenharmony_cistatic u16_t 378195972f6Sopenharmony_cialtcp_tcp_mss(struct altcp_pcb *conn) 379195972f6Sopenharmony_ci{ 380195972f6Sopenharmony_ci struct tcp_pcb *pcb; 381195972f6Sopenharmony_ci if (conn == NULL) { 382195972f6Sopenharmony_ci return 0; 383195972f6Sopenharmony_ci } 384195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 385195972f6Sopenharmony_ci pcb = (struct tcp_pcb *)conn->state; 386195972f6Sopenharmony_ci return tcp_mss(pcb); 387195972f6Sopenharmony_ci} 388195972f6Sopenharmony_ci 389195972f6Sopenharmony_cistatic u16_t 390195972f6Sopenharmony_cialtcp_tcp_sndbuf(struct altcp_pcb *conn) 391195972f6Sopenharmony_ci{ 392195972f6Sopenharmony_ci struct tcp_pcb *pcb; 393195972f6Sopenharmony_ci if (conn == NULL) { 394195972f6Sopenharmony_ci return 0; 395195972f6Sopenharmony_ci } 396195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 397195972f6Sopenharmony_ci pcb = (struct tcp_pcb *)conn->state; 398195972f6Sopenharmony_ci return tcp_sndbuf(pcb); 399195972f6Sopenharmony_ci} 400195972f6Sopenharmony_ci 401195972f6Sopenharmony_cistatic u16_t 402195972f6Sopenharmony_cialtcp_tcp_sndqueuelen(struct altcp_pcb *conn) 403195972f6Sopenharmony_ci{ 404195972f6Sopenharmony_ci struct tcp_pcb *pcb; 405195972f6Sopenharmony_ci if (conn == NULL) { 406195972f6Sopenharmony_ci return 0; 407195972f6Sopenharmony_ci } 408195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 409195972f6Sopenharmony_ci pcb = (struct tcp_pcb *)conn->state; 410195972f6Sopenharmony_ci return tcp_sndqueuelen(pcb); 411195972f6Sopenharmony_ci} 412195972f6Sopenharmony_ci 413195972f6Sopenharmony_cistatic void 414195972f6Sopenharmony_cialtcp_tcp_nagle_disable(struct altcp_pcb *conn) 415195972f6Sopenharmony_ci{ 416195972f6Sopenharmony_ci if (conn && conn->state) { 417195972f6Sopenharmony_ci struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; 418195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 419195972f6Sopenharmony_ci tcp_nagle_disable(pcb); 420195972f6Sopenharmony_ci } 421195972f6Sopenharmony_ci} 422195972f6Sopenharmony_ci 423195972f6Sopenharmony_cistatic void 424195972f6Sopenharmony_cialtcp_tcp_nagle_enable(struct altcp_pcb *conn) 425195972f6Sopenharmony_ci{ 426195972f6Sopenharmony_ci if (conn && conn->state) { 427195972f6Sopenharmony_ci struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; 428195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 429195972f6Sopenharmony_ci tcp_nagle_enable(pcb); 430195972f6Sopenharmony_ci } 431195972f6Sopenharmony_ci} 432195972f6Sopenharmony_ci 433195972f6Sopenharmony_cistatic int 434195972f6Sopenharmony_cialtcp_tcp_nagle_disabled(struct altcp_pcb *conn) 435195972f6Sopenharmony_ci{ 436195972f6Sopenharmony_ci if (conn && conn->state) { 437195972f6Sopenharmony_ci struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; 438195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 439195972f6Sopenharmony_ci return tcp_nagle_disabled(pcb); 440195972f6Sopenharmony_ci } 441195972f6Sopenharmony_ci return 0; 442195972f6Sopenharmony_ci} 443195972f6Sopenharmony_ci 444195972f6Sopenharmony_cistatic void 445195972f6Sopenharmony_cialtcp_tcp_setprio(struct altcp_pcb *conn, u8_t prio) 446195972f6Sopenharmony_ci{ 447195972f6Sopenharmony_ci if (conn != NULL) { 448195972f6Sopenharmony_ci struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; 449195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 450195972f6Sopenharmony_ci tcp_setprio(pcb, prio); 451195972f6Sopenharmony_ci } 452195972f6Sopenharmony_ci} 453195972f6Sopenharmony_ci 454195972f6Sopenharmony_ci#if LWIP_TCP_KEEPALIVE 455195972f6Sopenharmony_cistatic void 456195972f6Sopenharmony_cialtcp_tcp_keepalive_disable(struct altcp_pcb *conn) 457195972f6Sopenharmony_ci{ 458195972f6Sopenharmony_ci if (conn && conn->state) { 459195972f6Sopenharmony_ci struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; 460195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 461195972f6Sopenharmony_ci ip_reset_option(pcb, SOF_KEEPALIVE); 462195972f6Sopenharmony_ci } 463195972f6Sopenharmony_ci} 464195972f6Sopenharmony_ci 465195972f6Sopenharmony_cistatic void 466195972f6Sopenharmony_cialtcp_tcp_keepalive_enable(struct altcp_pcb *conn, u32_t idle, u32_t intvl, u32_t cnt) 467195972f6Sopenharmony_ci{ 468195972f6Sopenharmony_ci if (conn && conn->state) { 469195972f6Sopenharmony_ci struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; 470195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 471195972f6Sopenharmony_ci ip_set_option(pcb, SOF_KEEPALIVE); 472195972f6Sopenharmony_ci pcb->keep_idle = idle ? idle : TCP_KEEPIDLE_DEFAULT; 473195972f6Sopenharmony_ci pcb->keep_intvl = intvl ? intvl : TCP_KEEPINTVL_DEFAULT; 474195972f6Sopenharmony_ci pcb->keep_cnt = cnt ? cnt : TCP_KEEPCNT_DEFAULT; 475195972f6Sopenharmony_ci } 476195972f6Sopenharmony_ci} 477195972f6Sopenharmony_ci#endif 478195972f6Sopenharmony_ci 479195972f6Sopenharmony_cistatic void 480195972f6Sopenharmony_cialtcp_tcp_dealloc(struct altcp_pcb *conn) 481195972f6Sopenharmony_ci{ 482195972f6Sopenharmony_ci LWIP_UNUSED_ARG(conn); 483195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 484195972f6Sopenharmony_ci /* no private state to clean up */ 485195972f6Sopenharmony_ci} 486195972f6Sopenharmony_ci 487195972f6Sopenharmony_cistatic err_t 488195972f6Sopenharmony_cialtcp_tcp_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port) 489195972f6Sopenharmony_ci{ 490195972f6Sopenharmony_ci if (conn) { 491195972f6Sopenharmony_ci struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; 492195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 493195972f6Sopenharmony_ci return tcp_tcp_get_tcp_addrinfo(pcb, local, addr, port); 494195972f6Sopenharmony_ci } 495195972f6Sopenharmony_ci return ERR_VAL; 496195972f6Sopenharmony_ci} 497195972f6Sopenharmony_ci 498195972f6Sopenharmony_cistatic ip_addr_t * 499195972f6Sopenharmony_cialtcp_tcp_get_ip(struct altcp_pcb *conn, int local) 500195972f6Sopenharmony_ci{ 501195972f6Sopenharmony_ci if (conn) { 502195972f6Sopenharmony_ci struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; 503195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 504195972f6Sopenharmony_ci if (pcb) { 505195972f6Sopenharmony_ci if (local) { 506195972f6Sopenharmony_ci return &pcb->local_ip; 507195972f6Sopenharmony_ci } else { 508195972f6Sopenharmony_ci return &pcb->remote_ip; 509195972f6Sopenharmony_ci } 510195972f6Sopenharmony_ci } 511195972f6Sopenharmony_ci } 512195972f6Sopenharmony_ci return NULL; 513195972f6Sopenharmony_ci} 514195972f6Sopenharmony_ci 515195972f6Sopenharmony_cistatic u16_t 516195972f6Sopenharmony_cialtcp_tcp_get_port(struct altcp_pcb *conn, int local) 517195972f6Sopenharmony_ci{ 518195972f6Sopenharmony_ci if (conn) { 519195972f6Sopenharmony_ci struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; 520195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 521195972f6Sopenharmony_ci if (pcb) { 522195972f6Sopenharmony_ci if (local) { 523195972f6Sopenharmony_ci return pcb->local_port; 524195972f6Sopenharmony_ci } else { 525195972f6Sopenharmony_ci return pcb->remote_port; 526195972f6Sopenharmony_ci } 527195972f6Sopenharmony_ci } 528195972f6Sopenharmony_ci } 529195972f6Sopenharmony_ci return 0; 530195972f6Sopenharmony_ci} 531195972f6Sopenharmony_ci 532195972f6Sopenharmony_ci#ifdef LWIP_DEBUG 533195972f6Sopenharmony_cistatic enum tcp_state 534195972f6Sopenharmony_cialtcp_tcp_dbg_get_tcp_state(struct altcp_pcb *conn) 535195972f6Sopenharmony_ci{ 536195972f6Sopenharmony_ci if (conn) { 537195972f6Sopenharmony_ci struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state; 538195972f6Sopenharmony_ci ALTCP_TCP_ASSERT_CONN(conn); 539195972f6Sopenharmony_ci if (pcb) { 540195972f6Sopenharmony_ci return pcb->state; 541195972f6Sopenharmony_ci } 542195972f6Sopenharmony_ci } 543195972f6Sopenharmony_ci return CLOSED; 544195972f6Sopenharmony_ci} 545195972f6Sopenharmony_ci#endif 546195972f6Sopenharmony_ciconst struct altcp_functions altcp_tcp_functions = { 547195972f6Sopenharmony_ci altcp_tcp_set_poll, 548195972f6Sopenharmony_ci altcp_tcp_recved, 549195972f6Sopenharmony_ci altcp_tcp_bind, 550195972f6Sopenharmony_ci altcp_tcp_connect, 551195972f6Sopenharmony_ci altcp_tcp_listen, 552195972f6Sopenharmony_ci altcp_tcp_abort, 553195972f6Sopenharmony_ci altcp_tcp_close, 554195972f6Sopenharmony_ci altcp_tcp_shutdown, 555195972f6Sopenharmony_ci altcp_tcp_write, 556195972f6Sopenharmony_ci altcp_tcp_output, 557195972f6Sopenharmony_ci altcp_tcp_mss, 558195972f6Sopenharmony_ci altcp_tcp_sndbuf, 559195972f6Sopenharmony_ci altcp_tcp_sndqueuelen, 560195972f6Sopenharmony_ci altcp_tcp_nagle_disable, 561195972f6Sopenharmony_ci altcp_tcp_nagle_enable, 562195972f6Sopenharmony_ci altcp_tcp_nagle_disabled, 563195972f6Sopenharmony_ci altcp_tcp_setprio, 564195972f6Sopenharmony_ci altcp_tcp_dealloc, 565195972f6Sopenharmony_ci altcp_tcp_get_tcp_addrinfo, 566195972f6Sopenharmony_ci altcp_tcp_get_ip, 567195972f6Sopenharmony_ci altcp_tcp_get_port 568195972f6Sopenharmony_ci#if LWIP_TCP_KEEPALIVE 569195972f6Sopenharmony_ci , altcp_tcp_keepalive_disable 570195972f6Sopenharmony_ci , altcp_tcp_keepalive_enable 571195972f6Sopenharmony_ci#endif 572195972f6Sopenharmony_ci#ifdef LWIP_DEBUG 573195972f6Sopenharmony_ci , altcp_tcp_dbg_get_tcp_state 574195972f6Sopenharmony_ci#endif 575195972f6Sopenharmony_ci}; 576195972f6Sopenharmony_ci 577195972f6Sopenharmony_ci#endif /* LWIP_ALTCP */ 578