1195972f6Sopenharmony_ci/**
2195972f6Sopenharmony_ci * @file
3195972f6Sopenharmony_ci * @defgroup altcp Application layered TCP Functions
4195972f6Sopenharmony_ci * @ingroup altcp_api
5195972f6Sopenharmony_ci *
6195972f6Sopenharmony_ci * This file contains the common functions for altcp to work.
7195972f6Sopenharmony_ci * For more details see @ref altcp_api.
8195972f6Sopenharmony_ci */
9195972f6Sopenharmony_ci
10195972f6Sopenharmony_ci/**
11195972f6Sopenharmony_ci * @defgroup altcp_api Application layered TCP Introduction
12195972f6Sopenharmony_ci * @ingroup callbackstyle_api
13195972f6Sopenharmony_ci *
14195972f6Sopenharmony_ci * Overview
15195972f6Sopenharmony_ci * --------
16195972f6Sopenharmony_ci * altcp (application layered TCP connection API; to be used from TCPIP thread)
17195972f6Sopenharmony_ci * is an abstraction layer that prevents applications linking hard against the
18195972f6Sopenharmony_ci * @ref tcp.h functions while providing the same functionality. It is used to
19195972f6Sopenharmony_ci * e.g. add SSL/TLS (see LWIP_ALTCP_TLS) or proxy-connect support to an application
20195972f6Sopenharmony_ci * written for the tcp callback API without that application knowing the
21195972f6Sopenharmony_ci * protocol details.
22195972f6Sopenharmony_ci *
23195972f6Sopenharmony_ci * * This interface mimics the tcp callback API to the application while preventing
24195972f6Sopenharmony_ci *   direct linking (much like virtual functions).
25195972f6Sopenharmony_ci * * This way, an application can make use of other application layer protocols
26195972f6Sopenharmony_ci *   on top of TCP without knowing the details (e.g. TLS, proxy connection).
27195972f6Sopenharmony_ci * * This is achieved by simply including "lwip/altcp.h" instead of "lwip/tcp.h",
28195972f6Sopenharmony_ci *   replacing "struct tcp_pcb" with "struct altcp_pcb" and prefixing all functions
29195972f6Sopenharmony_ci *   with "altcp_" instead of "tcp_".
30195972f6Sopenharmony_ci *
31195972f6Sopenharmony_ci * With altcp support disabled (LWIP_ALTCP==0), applications written against the
32195972f6Sopenharmony_ci * altcp API can still be compiled but are directly linked against the tcp.h
33195972f6Sopenharmony_ci * callback API and then cannot use layered protocols. To minimize code changes
34195972f6Sopenharmony_ci * in this case, the use of altcp_allocators is strongly suggested.
35195972f6Sopenharmony_ci *
36195972f6Sopenharmony_ci * Usage
37195972f6Sopenharmony_ci * -----
38195972f6Sopenharmony_ci * To make use of this API from an existing tcp raw API application:
39195972f6Sopenharmony_ci * * Include "lwip/altcp.h" instead of "lwip/tcp.h"
40195972f6Sopenharmony_ci * * Replace "struct tcp_pcb" with "struct altcp_pcb"
41195972f6Sopenharmony_ci * * Prefix all called tcp API functions with "altcp_" instead of "tcp_" to link
42195972f6Sopenharmony_ci *   against the altcp functions
43195972f6Sopenharmony_ci * * @ref altcp_new (and @ref altcp_new_ip_type/@ref altcp_new_ip6) take
44195972f6Sopenharmony_ci *   an @ref altcp_allocator_t as an argument, whereas the original tcp API
45195972f6Sopenharmony_ci *   functions take no arguments.
46195972f6Sopenharmony_ci * * An @ref altcp_allocator_t allocator is an object that holds a pointer to an
47195972f6Sopenharmony_ci *   allocator object and a corresponding state (e.g. for TLS, the corresponding
48195972f6Sopenharmony_ci *   state may hold certificates or keys). This way, the application does not
49195972f6Sopenharmony_ci *   even need to know if it uses TLS or pure TCP, this is handled at runtime
50195972f6Sopenharmony_ci *   by passing a specific allocator.
51195972f6Sopenharmony_ci * * An application can alternatively bind hard to the altcp_tls API by calling
52195972f6Sopenharmony_ci *   @ref altcp_tls_new or @ref altcp_tls_wrap.
53195972f6Sopenharmony_ci * * The TLS layer is not directly implemented by lwIP, but a port to mbedTLS is
54195972f6Sopenharmony_ci *   provided.
55195972f6Sopenharmony_ci * * Another altcp layer is proxy-connect to use TLS behind a HTTP proxy (see
56195972f6Sopenharmony_ci *   @ref altcp_proxyconnect.h)
57195972f6Sopenharmony_ci *
58195972f6Sopenharmony_ci * altcp_allocator_t
59195972f6Sopenharmony_ci * -----------------
60195972f6Sopenharmony_ci * An altcp allocator is created by the application by combining an allocator
61195972f6Sopenharmony_ci * callback function and a corresponding state, e.g.:\code{.c}
62195972f6Sopenharmony_ci * static const unsigned char cert[] = {0x2D, ... (see mbedTLS doc for how to create this)};
63195972f6Sopenharmony_ci * struct altcp_tls_config * conf = altcp_tls_create_config_client(cert, sizeof(cert));
64195972f6Sopenharmony_ci * altcp_allocator_t tls_allocator = {
65195972f6Sopenharmony_ci *   altcp_tls_alloc, conf
66195972f6Sopenharmony_ci * };
67195972f6Sopenharmony_ci * \endcode
68195972f6Sopenharmony_ci *
69195972f6Sopenharmony_ci *
70195972f6Sopenharmony_ci * struct altcp_tls_config
71195972f6Sopenharmony_ci * -----------------------
72195972f6Sopenharmony_ci * The struct altcp_tls_config holds state that is needed to create new TLS client
73195972f6Sopenharmony_ci * or server connections (e.g. certificates and private keys).
74195972f6Sopenharmony_ci *
75195972f6Sopenharmony_ci * It is not defined by lwIP itself but by the TLS port (e.g. altcp_tls to mbedTLS
76195972f6Sopenharmony_ci * adaption). However, the parameters used to create it are defined in @ref
77195972f6Sopenharmony_ci * altcp_tls.h (see @ref altcp_tls_create_config_server_privkey_cert for servers
78195972f6Sopenharmony_ci * and @ref altcp_tls_create_config_client/@ref altcp_tls_create_config_client_2wayauth
79195972f6Sopenharmony_ci * for clients).
80195972f6Sopenharmony_ci *
81195972f6Sopenharmony_ci * For mbedTLS, ensure that certificates can be parsed by 'mbedtls_x509_crt_parse()' and
82195972f6Sopenharmony_ci * private keys can be parsed by 'mbedtls_pk_parse_key()'.
83195972f6Sopenharmony_ci */
84195972f6Sopenharmony_ci
85195972f6Sopenharmony_ci/*
86195972f6Sopenharmony_ci * Copyright (c) 2017 Simon Goldschmidt
87195972f6Sopenharmony_ci * All rights reserved.
88195972f6Sopenharmony_ci *
89195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification,
90195972f6Sopenharmony_ci * are permitted provided that the following conditions are met:
91195972f6Sopenharmony_ci *
92195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice,
93195972f6Sopenharmony_ci *    this list of conditions and the following disclaimer.
94195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice,
95195972f6Sopenharmony_ci *    this list of conditions and the following disclaimer in the documentation
96195972f6Sopenharmony_ci *    and/or other materials provided with the distribution.
97195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products
98195972f6Sopenharmony_ci *    derived from this software without specific prior written permission.
99195972f6Sopenharmony_ci *
100195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
101195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
102195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
103195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
104195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
105195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
106195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
107195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
108195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
109195972f6Sopenharmony_ci * OF SUCH DAMAGE.
110195972f6Sopenharmony_ci *
111195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack.
112195972f6Sopenharmony_ci *
113195972f6Sopenharmony_ci * Author: Simon Goldschmidt <goldsimon@gmx.de>
114195972f6Sopenharmony_ci *
115195972f6Sopenharmony_ci */
116195972f6Sopenharmony_ci
117195972f6Sopenharmony_ci#include "lwip/opt.h"
118195972f6Sopenharmony_ci
119195972f6Sopenharmony_ci#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
120195972f6Sopenharmony_ci
121195972f6Sopenharmony_ci#include "lwip/altcp.h"
122195972f6Sopenharmony_ci#include "lwip/priv/altcp_priv.h"
123195972f6Sopenharmony_ci#include "lwip/altcp_tcp.h"
124195972f6Sopenharmony_ci#include "lwip/tcp.h"
125195972f6Sopenharmony_ci#include "lwip/mem.h"
126195972f6Sopenharmony_ci
127195972f6Sopenharmony_ci#include <string.h>
128195972f6Sopenharmony_ci
129195972f6Sopenharmony_ciextern const struct altcp_functions altcp_tcp_functions;
130195972f6Sopenharmony_ci
131195972f6Sopenharmony_ci/**
132195972f6Sopenharmony_ci * For altcp layer implementations only: allocate a new struct altcp_pcb from the pool
133195972f6Sopenharmony_ci * and zero the memory
134195972f6Sopenharmony_ci */
135195972f6Sopenharmony_cistruct altcp_pcb *
136195972f6Sopenharmony_cialtcp_alloc(void)
137195972f6Sopenharmony_ci{
138195972f6Sopenharmony_ci  struct altcp_pcb *ret = (struct altcp_pcb *)memp_malloc(MEMP_ALTCP_PCB);
139195972f6Sopenharmony_ci  if (ret != NULL) {
140195972f6Sopenharmony_ci    memset(ret, 0, sizeof(struct altcp_pcb));
141195972f6Sopenharmony_ci  }
142195972f6Sopenharmony_ci  return ret;
143195972f6Sopenharmony_ci}
144195972f6Sopenharmony_ci
145195972f6Sopenharmony_ci/**
146195972f6Sopenharmony_ci * For altcp layer implementations only: return a struct altcp_pcb to the pool
147195972f6Sopenharmony_ci */
148195972f6Sopenharmony_civoid
149195972f6Sopenharmony_cialtcp_free(struct altcp_pcb *conn)
150195972f6Sopenharmony_ci{
151195972f6Sopenharmony_ci  if (conn) {
152195972f6Sopenharmony_ci    if (conn->fns && conn->fns->dealloc) {
153195972f6Sopenharmony_ci      conn->fns->dealloc(conn);
154195972f6Sopenharmony_ci    }
155195972f6Sopenharmony_ci    memp_free(MEMP_ALTCP_PCB, conn);
156195972f6Sopenharmony_ci  }
157195972f6Sopenharmony_ci}
158195972f6Sopenharmony_ci
159195972f6Sopenharmony_ci/**
160195972f6Sopenharmony_ci * @ingroup altcp
161195972f6Sopenharmony_ci * altcp_new_ip6: @ref altcp_new for IPv6
162195972f6Sopenharmony_ci */
163195972f6Sopenharmony_cistruct altcp_pcb *
164195972f6Sopenharmony_cialtcp_new_ip6(altcp_allocator_t *allocator)
165195972f6Sopenharmony_ci{
166195972f6Sopenharmony_ci  return altcp_new_ip_type(allocator, IPADDR_TYPE_V6);
167195972f6Sopenharmony_ci}
168195972f6Sopenharmony_ci
169195972f6Sopenharmony_ci/**
170195972f6Sopenharmony_ci * @ingroup altcp
171195972f6Sopenharmony_ci * altcp_new: @ref altcp_new for IPv4
172195972f6Sopenharmony_ci */
173195972f6Sopenharmony_cistruct altcp_pcb *
174195972f6Sopenharmony_cialtcp_new(altcp_allocator_t *allocator)
175195972f6Sopenharmony_ci{
176195972f6Sopenharmony_ci  return altcp_new_ip_type(allocator, IPADDR_TYPE_V4);
177195972f6Sopenharmony_ci}
178195972f6Sopenharmony_ci
179195972f6Sopenharmony_ci/**
180195972f6Sopenharmony_ci * @ingroup altcp
181195972f6Sopenharmony_ci * altcp_new_ip_type: called by applications to allocate a new pcb with the help of an
182195972f6Sopenharmony_ci * allocator function.
183195972f6Sopenharmony_ci *
184195972f6Sopenharmony_ci * @param allocator allocator function and argument
185195972f6Sopenharmony_ci * @param ip_type IP version of the pcb (@ref lwip_ip_addr_type)
186195972f6Sopenharmony_ci * @return a new altcp_pcb or NULL on error
187195972f6Sopenharmony_ci */
188195972f6Sopenharmony_cistruct altcp_pcb *
189195972f6Sopenharmony_cialtcp_new_ip_type(altcp_allocator_t *allocator, u8_t ip_type)
190195972f6Sopenharmony_ci{
191195972f6Sopenharmony_ci  struct altcp_pcb *conn;
192195972f6Sopenharmony_ci  if (allocator == NULL) {
193195972f6Sopenharmony_ci    /* no allocator given, create a simple TCP connection */
194195972f6Sopenharmony_ci    return altcp_tcp_new_ip_type(ip_type);
195195972f6Sopenharmony_ci  }
196195972f6Sopenharmony_ci  if (allocator->alloc == NULL) {
197195972f6Sopenharmony_ci    /* illegal allocator */
198195972f6Sopenharmony_ci    return NULL;
199195972f6Sopenharmony_ci  }
200195972f6Sopenharmony_ci  conn = allocator->alloc(allocator->arg, ip_type);
201195972f6Sopenharmony_ci  if (conn == NULL) {
202195972f6Sopenharmony_ci    /* allocation failed */
203195972f6Sopenharmony_ci    return NULL;
204195972f6Sopenharmony_ci  }
205195972f6Sopenharmony_ci  return conn;
206195972f6Sopenharmony_ci}
207195972f6Sopenharmony_ci
208195972f6Sopenharmony_ci/**
209195972f6Sopenharmony_ci * @ingroup altcp
210195972f6Sopenharmony_ci * @see tcp_arg()
211195972f6Sopenharmony_ci */
212195972f6Sopenharmony_civoid
213195972f6Sopenharmony_cialtcp_arg(struct altcp_pcb *conn, void *arg)
214195972f6Sopenharmony_ci{
215195972f6Sopenharmony_ci  if (conn) {
216195972f6Sopenharmony_ci    conn->arg = arg;
217195972f6Sopenharmony_ci  }
218195972f6Sopenharmony_ci}
219195972f6Sopenharmony_ci
220195972f6Sopenharmony_ci/**
221195972f6Sopenharmony_ci * @ingroup altcp
222195972f6Sopenharmony_ci * @see tcp_accept()
223195972f6Sopenharmony_ci */
224195972f6Sopenharmony_civoid
225195972f6Sopenharmony_cialtcp_accept(struct altcp_pcb *conn, altcp_accept_fn accept)
226195972f6Sopenharmony_ci{
227195972f6Sopenharmony_ci  if (conn != NULL) {
228195972f6Sopenharmony_ci    conn->accept = accept;
229195972f6Sopenharmony_ci  }
230195972f6Sopenharmony_ci}
231195972f6Sopenharmony_ci
232195972f6Sopenharmony_ci/**
233195972f6Sopenharmony_ci * @ingroup altcp
234195972f6Sopenharmony_ci * @see tcp_recv()
235195972f6Sopenharmony_ci */
236195972f6Sopenharmony_civoid
237195972f6Sopenharmony_cialtcp_recv(struct altcp_pcb *conn, altcp_recv_fn recv)
238195972f6Sopenharmony_ci{
239195972f6Sopenharmony_ci  if (conn) {
240195972f6Sopenharmony_ci    conn->recv = recv;
241195972f6Sopenharmony_ci  }
242195972f6Sopenharmony_ci}
243195972f6Sopenharmony_ci
244195972f6Sopenharmony_ci/**
245195972f6Sopenharmony_ci * @ingroup altcp
246195972f6Sopenharmony_ci * @see tcp_sent()
247195972f6Sopenharmony_ci */
248195972f6Sopenharmony_civoid
249195972f6Sopenharmony_cialtcp_sent(struct altcp_pcb *conn, altcp_sent_fn sent)
250195972f6Sopenharmony_ci{
251195972f6Sopenharmony_ci  if (conn) {
252195972f6Sopenharmony_ci    conn->sent = sent;
253195972f6Sopenharmony_ci  }
254195972f6Sopenharmony_ci}
255195972f6Sopenharmony_ci
256195972f6Sopenharmony_ci/**
257195972f6Sopenharmony_ci * @ingroup altcp
258195972f6Sopenharmony_ci * @see tcp_poll()
259195972f6Sopenharmony_ci */
260195972f6Sopenharmony_civoid
261195972f6Sopenharmony_cialtcp_poll(struct altcp_pcb *conn, altcp_poll_fn poll, u8_t interval)
262195972f6Sopenharmony_ci{
263195972f6Sopenharmony_ci  if (conn) {
264195972f6Sopenharmony_ci    conn->poll = poll;
265195972f6Sopenharmony_ci    conn->pollinterval = interval;
266195972f6Sopenharmony_ci    if (conn->fns && conn->fns->set_poll) {
267195972f6Sopenharmony_ci      conn->fns->set_poll(conn, interval);
268195972f6Sopenharmony_ci    }
269195972f6Sopenharmony_ci  }
270195972f6Sopenharmony_ci}
271195972f6Sopenharmony_ci
272195972f6Sopenharmony_ci/**
273195972f6Sopenharmony_ci * @ingroup altcp
274195972f6Sopenharmony_ci * @see tcp_err()
275195972f6Sopenharmony_ci */
276195972f6Sopenharmony_civoid
277195972f6Sopenharmony_cialtcp_err(struct altcp_pcb *conn, altcp_err_fn err)
278195972f6Sopenharmony_ci{
279195972f6Sopenharmony_ci  if (conn) {
280195972f6Sopenharmony_ci    conn->err = err;
281195972f6Sopenharmony_ci  }
282195972f6Sopenharmony_ci}
283195972f6Sopenharmony_ci
284195972f6Sopenharmony_ci/* Generic functions calling the "virtual" ones */
285195972f6Sopenharmony_ci
286195972f6Sopenharmony_ci/**
287195972f6Sopenharmony_ci * @ingroup altcp
288195972f6Sopenharmony_ci * @see tcp_recved()
289195972f6Sopenharmony_ci */
290195972f6Sopenharmony_civoid
291195972f6Sopenharmony_cialtcp_recved(struct altcp_pcb *conn, u16_t len)
292195972f6Sopenharmony_ci{
293195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->recved) {
294195972f6Sopenharmony_ci    conn->fns->recved(conn, len);
295195972f6Sopenharmony_ci  }
296195972f6Sopenharmony_ci}
297195972f6Sopenharmony_ci
298195972f6Sopenharmony_ci/**
299195972f6Sopenharmony_ci * @ingroup altcp
300195972f6Sopenharmony_ci * @see tcp_bind()
301195972f6Sopenharmony_ci */
302195972f6Sopenharmony_cierr_t
303195972f6Sopenharmony_cialtcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port)
304195972f6Sopenharmony_ci{
305195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->bind) {
306195972f6Sopenharmony_ci    return conn->fns->bind(conn, ipaddr, port);
307195972f6Sopenharmony_ci  }
308195972f6Sopenharmony_ci  return ERR_VAL;
309195972f6Sopenharmony_ci}
310195972f6Sopenharmony_ci
311195972f6Sopenharmony_ci/**
312195972f6Sopenharmony_ci * @ingroup altcp
313195972f6Sopenharmony_ci * @see tcp_connect()
314195972f6Sopenharmony_ci */
315195972f6Sopenharmony_cierr_t
316195972f6Sopenharmony_cialtcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected)
317195972f6Sopenharmony_ci{
318195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->connect) {
319195972f6Sopenharmony_ci    return conn->fns->connect(conn, ipaddr, port, connected);
320195972f6Sopenharmony_ci  }
321195972f6Sopenharmony_ci  return ERR_VAL;
322195972f6Sopenharmony_ci}
323195972f6Sopenharmony_ci
324195972f6Sopenharmony_ci/**
325195972f6Sopenharmony_ci * @ingroup altcp
326195972f6Sopenharmony_ci * @see tcp_listen_with_backlog_and_err()
327195972f6Sopenharmony_ci */
328195972f6Sopenharmony_cistruct altcp_pcb *
329195972f6Sopenharmony_cialtcp_listen_with_backlog_and_err(struct altcp_pcb *conn, u8_t backlog, err_t *err)
330195972f6Sopenharmony_ci{
331195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->listen) {
332195972f6Sopenharmony_ci    return conn->fns->listen(conn, backlog, err);
333195972f6Sopenharmony_ci  }
334195972f6Sopenharmony_ci  return NULL;
335195972f6Sopenharmony_ci}
336195972f6Sopenharmony_ci
337195972f6Sopenharmony_ci/**
338195972f6Sopenharmony_ci * @ingroup altcp
339195972f6Sopenharmony_ci * @see tcp_abort()
340195972f6Sopenharmony_ci */
341195972f6Sopenharmony_civoid
342195972f6Sopenharmony_cialtcp_abort(struct altcp_pcb *conn)
343195972f6Sopenharmony_ci{
344195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->abort) {
345195972f6Sopenharmony_ci    conn->fns->abort(conn);
346195972f6Sopenharmony_ci  }
347195972f6Sopenharmony_ci}
348195972f6Sopenharmony_ci
349195972f6Sopenharmony_ci/**
350195972f6Sopenharmony_ci * @ingroup altcp
351195972f6Sopenharmony_ci * @see tcp_close()
352195972f6Sopenharmony_ci */
353195972f6Sopenharmony_cierr_t
354195972f6Sopenharmony_cialtcp_close(struct altcp_pcb *conn)
355195972f6Sopenharmony_ci{
356195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->close) {
357195972f6Sopenharmony_ci    return conn->fns->close(conn);
358195972f6Sopenharmony_ci  }
359195972f6Sopenharmony_ci  return ERR_VAL;
360195972f6Sopenharmony_ci}
361195972f6Sopenharmony_ci
362195972f6Sopenharmony_ci/**
363195972f6Sopenharmony_ci * @ingroup altcp
364195972f6Sopenharmony_ci * @see tcp_shutdown()
365195972f6Sopenharmony_ci */
366195972f6Sopenharmony_cierr_t
367195972f6Sopenharmony_cialtcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx)
368195972f6Sopenharmony_ci{
369195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->shutdown) {
370195972f6Sopenharmony_ci    return conn->fns->shutdown(conn, shut_rx, shut_tx);
371195972f6Sopenharmony_ci  }
372195972f6Sopenharmony_ci  return ERR_VAL;
373195972f6Sopenharmony_ci}
374195972f6Sopenharmony_ci
375195972f6Sopenharmony_ci/**
376195972f6Sopenharmony_ci * @ingroup altcp
377195972f6Sopenharmony_ci * @see tcp_write()
378195972f6Sopenharmony_ci */
379195972f6Sopenharmony_cierr_t
380195972f6Sopenharmony_cialtcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
381195972f6Sopenharmony_ci{
382195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->write) {
383195972f6Sopenharmony_ci    return conn->fns->write(conn, dataptr, len, apiflags);
384195972f6Sopenharmony_ci  }
385195972f6Sopenharmony_ci  return ERR_VAL;
386195972f6Sopenharmony_ci}
387195972f6Sopenharmony_ci
388195972f6Sopenharmony_ci/**
389195972f6Sopenharmony_ci * @ingroup altcp
390195972f6Sopenharmony_ci * @see tcp_output()
391195972f6Sopenharmony_ci */
392195972f6Sopenharmony_cierr_t
393195972f6Sopenharmony_cialtcp_output(struct altcp_pcb *conn)
394195972f6Sopenharmony_ci{
395195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->output) {
396195972f6Sopenharmony_ci    return conn->fns->output(conn);
397195972f6Sopenharmony_ci  }
398195972f6Sopenharmony_ci  return ERR_VAL;
399195972f6Sopenharmony_ci}
400195972f6Sopenharmony_ci
401195972f6Sopenharmony_ci/**
402195972f6Sopenharmony_ci * @ingroup altcp
403195972f6Sopenharmony_ci * @see tcp_mss()
404195972f6Sopenharmony_ci */
405195972f6Sopenharmony_ciu16_t
406195972f6Sopenharmony_cialtcp_mss(struct altcp_pcb *conn)
407195972f6Sopenharmony_ci{
408195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->mss) {
409195972f6Sopenharmony_ci    return conn->fns->mss(conn);
410195972f6Sopenharmony_ci  }
411195972f6Sopenharmony_ci  return 0;
412195972f6Sopenharmony_ci}
413195972f6Sopenharmony_ci
414195972f6Sopenharmony_ci/**
415195972f6Sopenharmony_ci * @ingroup altcp
416195972f6Sopenharmony_ci * @see tcp_sndbuf()
417195972f6Sopenharmony_ci */
418195972f6Sopenharmony_ciu16_t
419195972f6Sopenharmony_cialtcp_sndbuf(struct altcp_pcb *conn)
420195972f6Sopenharmony_ci{
421195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->sndbuf) {
422195972f6Sopenharmony_ci    return conn->fns->sndbuf(conn);
423195972f6Sopenharmony_ci  }
424195972f6Sopenharmony_ci  return 0;
425195972f6Sopenharmony_ci}
426195972f6Sopenharmony_ci
427195972f6Sopenharmony_ci/**
428195972f6Sopenharmony_ci * @ingroup altcp
429195972f6Sopenharmony_ci * @see tcp_sndqueuelen()
430195972f6Sopenharmony_ci */
431195972f6Sopenharmony_ciu16_t
432195972f6Sopenharmony_cialtcp_sndqueuelen(struct altcp_pcb *conn)
433195972f6Sopenharmony_ci{
434195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->sndqueuelen) {
435195972f6Sopenharmony_ci    return conn->fns->sndqueuelen(conn);
436195972f6Sopenharmony_ci  }
437195972f6Sopenharmony_ci  return 0;
438195972f6Sopenharmony_ci}
439195972f6Sopenharmony_ci
440195972f6Sopenharmony_civoid
441195972f6Sopenharmony_cialtcp_nagle_disable(struct altcp_pcb *conn)
442195972f6Sopenharmony_ci{
443195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->nagle_disable) {
444195972f6Sopenharmony_ci    conn->fns->nagle_disable(conn);
445195972f6Sopenharmony_ci  }
446195972f6Sopenharmony_ci}
447195972f6Sopenharmony_ci
448195972f6Sopenharmony_civoid
449195972f6Sopenharmony_cialtcp_nagle_enable(struct altcp_pcb *conn)
450195972f6Sopenharmony_ci{
451195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->nagle_enable) {
452195972f6Sopenharmony_ci    conn->fns->nagle_enable(conn);
453195972f6Sopenharmony_ci  }
454195972f6Sopenharmony_ci}
455195972f6Sopenharmony_ci
456195972f6Sopenharmony_ciint
457195972f6Sopenharmony_cialtcp_nagle_disabled(struct altcp_pcb *conn)
458195972f6Sopenharmony_ci{
459195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->nagle_disabled) {
460195972f6Sopenharmony_ci    return conn->fns->nagle_disabled(conn);
461195972f6Sopenharmony_ci  }
462195972f6Sopenharmony_ci  return 0;
463195972f6Sopenharmony_ci}
464195972f6Sopenharmony_ci
465195972f6Sopenharmony_ci/**
466195972f6Sopenharmony_ci * @ingroup altcp
467195972f6Sopenharmony_ci * @see tcp_setprio()
468195972f6Sopenharmony_ci */
469195972f6Sopenharmony_civoid
470195972f6Sopenharmony_cialtcp_setprio(struct altcp_pcb *conn, u8_t prio)
471195972f6Sopenharmony_ci{
472195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->setprio) {
473195972f6Sopenharmony_ci    conn->fns->setprio(conn, prio);
474195972f6Sopenharmony_ci  }
475195972f6Sopenharmony_ci}
476195972f6Sopenharmony_ci
477195972f6Sopenharmony_cierr_t
478195972f6Sopenharmony_cialtcp_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port)
479195972f6Sopenharmony_ci{
480195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->addrinfo) {
481195972f6Sopenharmony_ci    return conn->fns->addrinfo(conn, local, addr, port);
482195972f6Sopenharmony_ci  }
483195972f6Sopenharmony_ci  return ERR_VAL;
484195972f6Sopenharmony_ci}
485195972f6Sopenharmony_ci
486195972f6Sopenharmony_ciip_addr_t *
487195972f6Sopenharmony_cialtcp_get_ip(struct altcp_pcb *conn, int local)
488195972f6Sopenharmony_ci{
489195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->getip) {
490195972f6Sopenharmony_ci    return conn->fns->getip(conn, local);
491195972f6Sopenharmony_ci  }
492195972f6Sopenharmony_ci  return NULL;
493195972f6Sopenharmony_ci}
494195972f6Sopenharmony_ci
495195972f6Sopenharmony_ciu16_t
496195972f6Sopenharmony_cialtcp_get_port(struct altcp_pcb *conn, int local)
497195972f6Sopenharmony_ci{
498195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->getport) {
499195972f6Sopenharmony_ci    return conn->fns->getport(conn, local);
500195972f6Sopenharmony_ci  }
501195972f6Sopenharmony_ci  return 0;
502195972f6Sopenharmony_ci}
503195972f6Sopenharmony_ci
504195972f6Sopenharmony_ci#if LWIP_TCP_KEEPALIVE
505195972f6Sopenharmony_civoid
506195972f6Sopenharmony_cialtcp_keepalive_disable(struct altcp_pcb *conn)
507195972f6Sopenharmony_ci{
508195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->keepalive_disable) {
509195972f6Sopenharmony_ci    conn->fns->keepalive_disable(conn);
510195972f6Sopenharmony_ci  }
511195972f6Sopenharmony_ci}
512195972f6Sopenharmony_ci
513195972f6Sopenharmony_civoid
514195972f6Sopenharmony_cialtcp_keepalive_enable(struct altcp_pcb *conn, u32_t idle, u32_t intvl, u32_t count)
515195972f6Sopenharmony_ci{
516195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->keepalive_enable) {
517195972f6Sopenharmony_ci      conn->fns->keepalive_enable(conn, idle, intvl, count);
518195972f6Sopenharmony_ci  }
519195972f6Sopenharmony_ci}
520195972f6Sopenharmony_ci#endif
521195972f6Sopenharmony_ci
522195972f6Sopenharmony_ci#ifdef LWIP_DEBUG
523195972f6Sopenharmony_cienum tcp_state
524195972f6Sopenharmony_cialtcp_dbg_get_tcp_state(struct altcp_pcb *conn)
525195972f6Sopenharmony_ci{
526195972f6Sopenharmony_ci  if (conn && conn->fns && conn->fns->dbg_get_tcp_state) {
527195972f6Sopenharmony_ci    return conn->fns->dbg_get_tcp_state(conn);
528195972f6Sopenharmony_ci  }
529195972f6Sopenharmony_ci  return CLOSED;
530195972f6Sopenharmony_ci}
531195972f6Sopenharmony_ci#endif
532195972f6Sopenharmony_ci
533195972f6Sopenharmony_ci/* Default implementations for the "virtual" functions */
534195972f6Sopenharmony_ci
535195972f6Sopenharmony_civoid
536195972f6Sopenharmony_cialtcp_default_set_poll(struct altcp_pcb *conn, u8_t interval)
537195972f6Sopenharmony_ci{
538195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
539195972f6Sopenharmony_ci    altcp_poll(conn->inner_conn, conn->poll, interval);
540195972f6Sopenharmony_ci  }
541195972f6Sopenharmony_ci}
542195972f6Sopenharmony_ci
543195972f6Sopenharmony_civoid
544195972f6Sopenharmony_cialtcp_default_recved(struct altcp_pcb *conn, u16_t len)
545195972f6Sopenharmony_ci{
546195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
547195972f6Sopenharmony_ci    altcp_recved(conn->inner_conn, len);
548195972f6Sopenharmony_ci  }
549195972f6Sopenharmony_ci}
550195972f6Sopenharmony_ci
551195972f6Sopenharmony_cierr_t
552195972f6Sopenharmony_cialtcp_default_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port)
553195972f6Sopenharmony_ci{
554195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
555195972f6Sopenharmony_ci    return altcp_bind(conn->inner_conn, ipaddr, port);
556195972f6Sopenharmony_ci  }
557195972f6Sopenharmony_ci  return ERR_VAL;
558195972f6Sopenharmony_ci}
559195972f6Sopenharmony_ci
560195972f6Sopenharmony_cierr_t
561195972f6Sopenharmony_cialtcp_default_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx)
562195972f6Sopenharmony_ci{
563195972f6Sopenharmony_ci  if (conn) {
564195972f6Sopenharmony_ci    if (shut_rx && shut_tx && conn->fns && conn->fns->close) {
565195972f6Sopenharmony_ci      /* default shutdown for both sides is close */
566195972f6Sopenharmony_ci      return conn->fns->close(conn);
567195972f6Sopenharmony_ci    }
568195972f6Sopenharmony_ci    if (conn->inner_conn) {
569195972f6Sopenharmony_ci      return altcp_shutdown(conn->inner_conn, shut_rx, shut_tx);
570195972f6Sopenharmony_ci    }
571195972f6Sopenharmony_ci  }
572195972f6Sopenharmony_ci  return ERR_VAL;
573195972f6Sopenharmony_ci}
574195972f6Sopenharmony_ci
575195972f6Sopenharmony_cierr_t
576195972f6Sopenharmony_cialtcp_default_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
577195972f6Sopenharmony_ci{
578195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
579195972f6Sopenharmony_ci    return altcp_write(conn->inner_conn, dataptr, len, apiflags);
580195972f6Sopenharmony_ci  }
581195972f6Sopenharmony_ci  return ERR_VAL;
582195972f6Sopenharmony_ci}
583195972f6Sopenharmony_ci
584195972f6Sopenharmony_cierr_t
585195972f6Sopenharmony_cialtcp_default_output(struct altcp_pcb *conn)
586195972f6Sopenharmony_ci{
587195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
588195972f6Sopenharmony_ci    return altcp_output(conn->inner_conn);
589195972f6Sopenharmony_ci  }
590195972f6Sopenharmony_ci  return ERR_VAL;
591195972f6Sopenharmony_ci}
592195972f6Sopenharmony_ci
593195972f6Sopenharmony_ciu16_t
594195972f6Sopenharmony_cialtcp_default_mss(struct altcp_pcb *conn)
595195972f6Sopenharmony_ci{
596195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
597195972f6Sopenharmony_ci    return altcp_mss(conn->inner_conn);
598195972f6Sopenharmony_ci  }
599195972f6Sopenharmony_ci  return 0;
600195972f6Sopenharmony_ci}
601195972f6Sopenharmony_ci
602195972f6Sopenharmony_ciu16_t
603195972f6Sopenharmony_cialtcp_default_sndbuf(struct altcp_pcb *conn)
604195972f6Sopenharmony_ci{
605195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
606195972f6Sopenharmony_ci    return altcp_sndbuf(conn->inner_conn);
607195972f6Sopenharmony_ci  }
608195972f6Sopenharmony_ci  return 0;
609195972f6Sopenharmony_ci}
610195972f6Sopenharmony_ci
611195972f6Sopenharmony_ciu16_t
612195972f6Sopenharmony_cialtcp_default_sndqueuelen(struct altcp_pcb *conn)
613195972f6Sopenharmony_ci{
614195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
615195972f6Sopenharmony_ci    return altcp_sndqueuelen(conn->inner_conn);
616195972f6Sopenharmony_ci  }
617195972f6Sopenharmony_ci  return 0;
618195972f6Sopenharmony_ci}
619195972f6Sopenharmony_ci
620195972f6Sopenharmony_civoid
621195972f6Sopenharmony_cialtcp_default_nagle_disable(struct altcp_pcb *conn)
622195972f6Sopenharmony_ci{
623195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
624195972f6Sopenharmony_ci    altcp_nagle_disable(conn->inner_conn);
625195972f6Sopenharmony_ci  }
626195972f6Sopenharmony_ci}
627195972f6Sopenharmony_ci
628195972f6Sopenharmony_civoid
629195972f6Sopenharmony_cialtcp_default_nagle_enable(struct altcp_pcb *conn)
630195972f6Sopenharmony_ci{
631195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
632195972f6Sopenharmony_ci    altcp_nagle_enable(conn->inner_conn);
633195972f6Sopenharmony_ci  }
634195972f6Sopenharmony_ci}
635195972f6Sopenharmony_ci
636195972f6Sopenharmony_ciint
637195972f6Sopenharmony_cialtcp_default_nagle_disabled(struct altcp_pcb *conn)
638195972f6Sopenharmony_ci{
639195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
640195972f6Sopenharmony_ci    return altcp_nagle_disabled(conn->inner_conn);
641195972f6Sopenharmony_ci  }
642195972f6Sopenharmony_ci  return 0;
643195972f6Sopenharmony_ci}
644195972f6Sopenharmony_ci
645195972f6Sopenharmony_civoid
646195972f6Sopenharmony_cialtcp_default_setprio(struct altcp_pcb *conn, u8_t prio)
647195972f6Sopenharmony_ci{
648195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
649195972f6Sopenharmony_ci    altcp_setprio(conn->inner_conn, prio);
650195972f6Sopenharmony_ci  }
651195972f6Sopenharmony_ci}
652195972f6Sopenharmony_ci
653195972f6Sopenharmony_civoid
654195972f6Sopenharmony_cialtcp_default_dealloc(struct altcp_pcb *conn)
655195972f6Sopenharmony_ci{
656195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(conn);
657195972f6Sopenharmony_ci  /* nothing to do */
658195972f6Sopenharmony_ci}
659195972f6Sopenharmony_ci
660195972f6Sopenharmony_cierr_t
661195972f6Sopenharmony_cialtcp_default_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port)
662195972f6Sopenharmony_ci{
663195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
664195972f6Sopenharmony_ci    return altcp_get_tcp_addrinfo(conn->inner_conn, local, addr, port);
665195972f6Sopenharmony_ci  }
666195972f6Sopenharmony_ci  return ERR_VAL;
667195972f6Sopenharmony_ci}
668195972f6Sopenharmony_ci
669195972f6Sopenharmony_ciip_addr_t *
670195972f6Sopenharmony_cialtcp_default_get_ip(struct altcp_pcb *conn, int local)
671195972f6Sopenharmony_ci{
672195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
673195972f6Sopenharmony_ci    return altcp_get_ip(conn->inner_conn, local);
674195972f6Sopenharmony_ci  }
675195972f6Sopenharmony_ci  return NULL;
676195972f6Sopenharmony_ci}
677195972f6Sopenharmony_ci
678195972f6Sopenharmony_ciu16_t
679195972f6Sopenharmony_cialtcp_default_get_port(struct altcp_pcb *conn, int local)
680195972f6Sopenharmony_ci{
681195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
682195972f6Sopenharmony_ci    return altcp_get_port(conn->inner_conn, local);
683195972f6Sopenharmony_ci  }
684195972f6Sopenharmony_ci  return 0;
685195972f6Sopenharmony_ci}
686195972f6Sopenharmony_ci
687195972f6Sopenharmony_ci#if LWIP_TCP_KEEPALIVE
688195972f6Sopenharmony_civoid
689195972f6Sopenharmony_cialtcp_default_keepalive_disable(struct altcp_pcb *conn)
690195972f6Sopenharmony_ci{
691195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
692195972f6Sopenharmony_ci    altcp_keepalive_disable(conn->inner_conn);
693195972f6Sopenharmony_ci  }
694195972f6Sopenharmony_ci}
695195972f6Sopenharmony_ci
696195972f6Sopenharmony_civoid
697195972f6Sopenharmony_cialtcp_default_keepalive_enable(struct altcp_pcb *conn, u32_t idle, u32_t intvl, u32_t count)
698195972f6Sopenharmony_ci{
699195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
700195972f6Sopenharmony_ci      altcp_keepalive_enable(conn->inner_conn, idle, intvl, count);
701195972f6Sopenharmony_ci  }
702195972f6Sopenharmony_ci}
703195972f6Sopenharmony_ci#endif
704195972f6Sopenharmony_ci
705195972f6Sopenharmony_ci#ifdef LWIP_DEBUG
706195972f6Sopenharmony_cienum tcp_state
707195972f6Sopenharmony_cialtcp_default_dbg_get_tcp_state(struct altcp_pcb *conn)
708195972f6Sopenharmony_ci{
709195972f6Sopenharmony_ci  if (conn && conn->inner_conn) {
710195972f6Sopenharmony_ci    return altcp_dbg_get_tcp_state(conn->inner_conn);
711195972f6Sopenharmony_ci  }
712195972f6Sopenharmony_ci  return CLOSED;
713195972f6Sopenharmony_ci}
714195972f6Sopenharmony_ci#endif
715195972f6Sopenharmony_ci
716195972f6Sopenharmony_ci
717195972f6Sopenharmony_ci#endif /* LWIP_ALTCP */
718