1 /** 2 * @file 3 * TCP API (to be used from TCPIP thread)\n 4 * See also @ref tcp_raw 5 */ 6 7 /* 8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without modification, 12 * are permitted provided that the following conditions are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright notice, 15 * this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright notice, 17 * this list of conditions and the following disclaimer in the documentation 18 * and/or other materials provided with the distribution. 19 * 3. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 31 * OF SUCH DAMAGE. 32 * 33 * This file is part of the lwIP TCP/IP stack. 34 * 35 * Author: Adam Dunkels <adam@sics.se> 36 * 37 */ 38 #ifndef LWIP_HDR_TCP_H 39 #define LWIP_HDR_TCP_H 40 41 #include "lwip/opt.h" 42 43 #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ 44 45 #include "lwip/tcpbase.h" 46 #include "lwip/mem.h" 47 #include "lwip/pbuf.h" 48 #include "lwip/ip.h" 49 #include "lwip/icmp.h" 50 #include "lwip/err.h" 51 #include "lwip/ip6.h" 52 #include "lwip/ip6_addr.h" 53 54 #ifdef __cplusplus 55 extern "C" { 56 #endif 57 58 struct tcp_pcb; 59 struct tcp_pcb_listen; 60 61 /** Function prototype for tcp accept callback functions. Called when a new 62 * connection can be accepted on a listening pcb. 63 * 64 * @param arg Additional argument to pass to the callback function (@see tcp_arg()) 65 * @param newpcb The new connection pcb 66 * @param err An error code if there has been an error accepting. 67 * Only return ERR_ABRT if you have called tcp_abort from within the 68 * callback function! 69 */ 70 typedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err); 71 72 /** Function prototype for tcp receive callback functions. Called when data has 73 * been received. 74 * 75 * @param arg Additional argument to pass to the callback function (@see tcp_arg()) 76 * @param tpcb The connection pcb which received data 77 * @param p The received data (or NULL when the connection has been closed!) 78 * @param err An error code if there has been an error receiving 79 * Only return ERR_ABRT if you have called tcp_abort from within the 80 * callback function! 81 */ 82 typedef err_t (*tcp_recv_fn)(void *arg, struct tcp_pcb *tpcb, 83 struct pbuf *p, err_t err); 84 85 /** Function prototype for tcp sent callback functions. Called when sent data has 86 * been acknowledged by the remote side. Use it to free corresponding resources. 87 * This also means that the pcb has now space available to send new data. 88 * 89 * @param arg Additional argument to pass to the callback function (@see tcp_arg()) 90 * @param tpcb The connection pcb for which data has been acknowledged 91 * @param len The amount of bytes acknowledged 92 * @return ERR_OK: try to send some data by calling tcp_output 93 * Only return ERR_ABRT if you have called tcp_abort from within the 94 * callback function! 95 */ 96 typedef err_t (*tcp_sent_fn)(void *arg, struct tcp_pcb *tpcb, 97 u16_t len); 98 99 /** Function prototype for tcp poll callback functions. Called periodically as 100 * specified by @see tcp_poll. 101 * 102 * @param arg Additional argument to pass to the callback function (@see tcp_arg()) 103 * @param tpcb tcp pcb 104 * @return ERR_OK: try to send some data by calling tcp_output 105 * Only return ERR_ABRT if you have called tcp_abort from within the 106 * callback function! 107 */ 108 typedef err_t (*tcp_poll_fn)(void *arg, struct tcp_pcb *tpcb); 109 110 /** Function prototype for tcp error callback functions. Called when the pcb 111 * receives a RST or is unexpectedly closed for any other reason. 112 * 113 * @note The corresponding pcb is already freed when this callback is called! 114 * 115 * @param arg Additional argument to pass to the callback function (@see tcp_arg()) 116 * @param err Error code to indicate why the pcb has been closed 117 * ERR_ABRT: aborted through tcp_abort or by a TCP timer 118 * ERR_RST: the connection was reset by the remote host 119 */ 120 typedef void (*tcp_err_fn)(void *arg, err_t err); 121 122 /** Function prototype for tcp connected callback functions. Called when a pcb 123 * is connected to the remote side after initiating a connection attempt by 124 * calling tcp_connect(). 125 * 126 * @param arg Additional argument to pass to the callback function (@see tcp_arg()) 127 * @param tpcb The connection pcb which is connected 128 * @param err An unused error code, always ERR_OK currently ;-) @todo! 129 * Only return ERR_ABRT if you have called tcp_abort from within the 130 * callback function! 131 * 132 * @note When a connection attempt fails, the error callback is currently called! 133 */ 134 typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err); 135 136 #if LWIP_WND_SCALE 137 #define RCV_WND_SCALE(pcb, wnd) (((wnd) >> (pcb)->rcv_scale)) 138 #define SND_WND_SCALE(pcb, wnd) (((wnd) << (pcb)->snd_scale)) 139 #define TCPWND16(x) ((u16_t)LWIP_MIN((x), 0xFFFF)) 140 #define TCP_WND_MAX(pcb) ((tcpwnd_size_t)(((pcb)->flags & TF_WND_SCALE) ? TCP_WND : TCPWND16(TCP_WND))) 141 #else 142 #define RCV_WND_SCALE(pcb, wnd) (wnd) 143 #define SND_WND_SCALE(pcb, wnd) (wnd) 144 #define TCPWND16(x) (x) 145 #define TCP_WND_MAX(pcb) TCP_WND 146 #endif 147 /* Increments a tcpwnd_size_t and holds at max value rather than rollover */ 148 #define TCP_WND_INC(wnd, inc) do { \ 149 if ((tcpwnd_size_t)(wnd + inc) >= wnd) { \ 150 wnd = (tcpwnd_size_t)(wnd + inc); \ 151 } else { \ 152 wnd = (tcpwnd_size_t)-1; \ 153 } \ 154 } while(0) 155 156 #if LWIP_TCP_SACK_OUT 157 /** SACK ranges to include in ACK packets. 158 * SACK entry is invalid if left==right. */ 159 struct tcp_sack_range { 160 /** Left edge of the SACK: the first acknowledged sequence number. */ 161 u32_t left; 162 /** Right edge of the SACK: the last acknowledged sequence number +1 (so first NOT acknowledged). */ 163 u32_t right; 164 }; 165 #endif /* LWIP_TCP_SACK_OUT */ 166 167 /** Function prototype for deallocation of arguments. Called *just before* the 168 * pcb is freed, so don't expect to be able to do anything with this pcb! 169 * 170 * @param id ext arg id (allocated via @ref tcp_ext_arg_alloc_id) 171 * @param data pointer to the data (set via @ref tcp_ext_arg_set before) 172 */ 173 typedef void (*tcp_extarg_callback_pcb_destroyed_fn)(u8_t id, void *data); 174 175 /** Function prototype to transition arguments from a listening pcb to an accepted pcb 176 * 177 * @param id ext arg id (allocated via @ref tcp_ext_arg_alloc_id) 178 * @param lpcb the listening pcb accepting a connection 179 * @param cpcb the newly allocated connection pcb 180 * @return ERR_OK if OK, any error if connection should be dropped 181 */ 182 typedef err_t (*tcp_extarg_callback_passive_open_fn)(u8_t id, struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb); 183 184 /** A table of callback functions that is invoked for ext arguments */ 185 struct tcp_ext_arg_callbacks { 186 /** @ref tcp_extarg_callback_pcb_destroyed_fn */ 187 tcp_extarg_callback_pcb_destroyed_fn destroy; 188 /** @ref tcp_extarg_callback_passive_open_fn */ 189 tcp_extarg_callback_passive_open_fn passive_open; 190 }; 191 192 #define LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID 0xFF 193 194 #if LWIP_TCP_PCB_NUM_EXT_ARGS 195 /* This is the structure for ext args in tcp pcbs (used as array) */ 196 struct tcp_pcb_ext_args { 197 const struct tcp_ext_arg_callbacks *callbacks; 198 void *data; 199 }; 200 /* This is a helper define to prevent zero size arrays if disabled */ 201 #define TCP_PCB_EXTARGS struct tcp_pcb_ext_args ext_args[LWIP_TCP_PCB_NUM_EXT_ARGS]; 202 #else 203 #define TCP_PCB_EXTARGS 204 #endif 205 206 typedef u16_t tcpflags_t; 207 #define TCP_ALLFLAGS 0xffffU 208 209 /** 210 * members common to struct tcp_pcb and struct tcp_listen_pcb 211 */ 212 #define TCP_PCB_COMMON(type) \ 213 type *next; /* for the linked list */ \ 214 void *callback_arg; \ 215 TCP_PCB_EXTARGS \ 216 enum tcp_state state; /* TCP state */ \ 217 u8_t prio; \ 218 /* ports are in host byte order */ \ 219 u16_t local_port 220 221 222 /** the TCP protocol control block for listening pcbs */ 223 struct tcp_pcb_listen { 224 /** Common members of all PCB types */ 225 IP_PCB; 226 /** Protocol specific PCB members */ 227 TCP_PCB_COMMON(struct tcp_pcb_listen); 228 229 #if LWIP_CALLBACK_API 230 /* Function to call when a listener has been connected. */ 231 tcp_accept_fn accept; 232 #endif /* LWIP_CALLBACK_API */ 233 234 #if TCP_LISTEN_BACKLOG 235 u8_t backlog; 236 u8_t accepts_pending; 237 #endif /* TCP_LISTEN_BACKLOG */ 238 }; 239 240 241 /** the TCP protocol control block */ 242 struct tcp_pcb { 243 /** common PCB members */ 244 IP_PCB; 245 /** protocol specific PCB members */ 246 TCP_PCB_COMMON(struct tcp_pcb); 247 248 /* ports are in host byte order */ 249 u16_t remote_port; 250 251 tcpflags_t flags; 252 #define TF_ACK_DELAY 0x01U /* Delayed ACK. */ 253 #define TF_ACK_NOW 0x02U /* Immediate ACK. */ 254 #define TF_INFR 0x04U /* In fast recovery. */ 255 #define TF_CLOSEPEND 0x08U /* If this is set, tcp_close failed to enqueue the FIN (retried in tcp_tmr) */ 256 #define TF_RXCLOSED 0x10U /* rx closed by tcp_shutdown */ 257 #define TF_FIN 0x20U /* Connection was closed locally (FIN segment enqueued). */ 258 #define TF_NODELAY 0x40U /* Disable Nagle algorithm */ 259 #define TF_NAGLEMEMERR 0x80U /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ 260 #if LWIP_WND_SCALE 261 #define TF_WND_SCALE 0x0100U /* Window Scale option enabled */ 262 #endif 263 #if TCP_LISTEN_BACKLOG 264 #define TF_BACKLOGPEND 0x0200U /* If this is set, a connection pcb has increased the backlog on its listener */ 265 #endif 266 #if LWIP_TCP_TIMESTAMPS 267 #define TF_TIMESTAMP 0x0400U /* Timestamp option enabled */ 268 #endif 269 #define TF_RTO 0x0800U /* RTO timer has fired, in-flight data moved to unsent and being retransmitted */ 270 #if LWIP_TCP_SACK_OUT 271 #define TF_SACK 0x1000U /* Selective ACKs enabled */ 272 #endif 273 274 /* the rest of the fields are in host byte order 275 as we have to do some math with them */ 276 277 /* Timers */ 278 u8_t polltmr, pollinterval; 279 u8_t last_timer; 280 u32_t tmr; 281 282 /* receiver variables */ 283 u32_t rcv_nxt; /* next seqno expected */ 284 tcpwnd_size_t rcv_wnd; /* receiver window available */ 285 tcpwnd_size_t rcv_ann_wnd; /* receiver window to announce */ 286 u32_t rcv_ann_right_edge; /* announced right edge of window */ 287 288 #if LWIP_TCP_SACK_OUT 289 /* SACK ranges to include in ACK packets (entry is invalid if left==right) */ 290 struct tcp_sack_range rcv_sacks[LWIP_TCP_MAX_SACK_NUM]; 291 #define LWIP_TCP_SACK_VALID(pcb, idx) ((pcb)->rcv_sacks[idx].left != (pcb)->rcv_sacks[idx].right) 292 #endif /* LWIP_TCP_SACK_OUT */ 293 294 /* Retransmission timer. */ 295 s16_t rtime; 296 297 u16_t mss; /* maximum segment size */ 298 299 /* RTT (round trip time) estimation variables */ 300 u32_t rttest; /* RTT estimate in 500ms ticks */ 301 u32_t rtseq; /* sequence number being timed */ 302 s16_t sa, sv; /* @see "Congestion Avoidance and Control" by Van Jacobson and Karels */ 303 304 s16_t rto; /* retransmission time-out (in ticks of TCP_SLOW_INTERVAL) */ 305 u8_t nrtx; /* number of retransmissions */ 306 307 /* fast retransmit/recovery */ 308 u8_t dupacks; 309 u32_t lastack; /* Highest acknowledged seqno. */ 310 311 /* congestion avoidance/control variables */ 312 tcpwnd_size_t cwnd; 313 tcpwnd_size_t ssthresh; 314 315 /* first byte following last rto byte */ 316 u32_t rto_end; 317 318 /* sender variables */ 319 u32_t snd_nxt; /* next new seqno to be sent */ 320 u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last 321 window update. */ 322 u32_t snd_lbb; /* Sequence number of next byte to be buffered. */ 323 tcpwnd_size_t snd_wnd; /* sender window */ 324 tcpwnd_size_t snd_wnd_max; /* the maximum sender window announced by the remote host */ 325 326 tcpwnd_size_t snd_buf; /* Available buffer space for sending (in bytes). */ 327 #define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3) 328 u16_t snd_queuelen; /* Number of pbufs currently in the send buffer. */ 329 330 #if TCP_OVERSIZE 331 /* Extra bytes available at the end of the last pbuf in unsent. */ 332 u16_t unsent_oversize; 333 #endif /* TCP_OVERSIZE */ 334 335 tcpwnd_size_t bytes_acked; 336 337 /* These are ordered by sequence number: */ 338 struct tcp_seg *unsent; /* Unsent (queued) segments. */ 339 struct tcp_seg *unacked; /* Sent but unacknowledged segments. */ 340 #if TCP_QUEUE_OOSEQ 341 struct tcp_seg *ooseq; /* Received out of sequence segments. */ 342 #endif /* TCP_QUEUE_OOSEQ */ 343 344 struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */ 345 346 #if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG 347 struct tcp_pcb_listen* listener; 348 #endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ 349 350 #if LWIP_CALLBACK_API 351 /* Function to be called when more send buffer space is available. */ 352 tcp_sent_fn sent; 353 /* Function to be called when (in-sequence) data has arrived. */ 354 tcp_recv_fn recv; 355 /* Function to be called when a connection has been set up. */ 356 tcp_connected_fn connected; 357 /* Function which is called periodically. */ 358 tcp_poll_fn poll; 359 /* Function to be called whenever a fatal error occurs. */ 360 tcp_err_fn errf; 361 #endif /* LWIP_CALLBACK_API */ 362 363 #if LWIP_TCP_TIMESTAMPS 364 u32_t ts_lastacksent; 365 u32_t ts_recent; 366 #endif /* LWIP_TCP_TIMESTAMPS */ 367 368 /* idle time before KEEPALIVE is sent */ 369 u32_t keep_idle; 370 #if LWIP_TCP_KEEPALIVE 371 u32_t keep_intvl; 372 u32_t keep_cnt; 373 #endif /* LWIP_TCP_KEEPALIVE */ 374 375 /* Persist timer counter */ 376 u8_t persist_cnt; 377 /* Persist timer back-off */ 378 u8_t persist_backoff; 379 /* Number of persist probes */ 380 u8_t persist_probe; 381 382 /* KEEPALIVE counter */ 383 u8_t keep_cnt_sent; 384 385 #if LWIP_WND_SCALE 386 u8_t snd_scale; 387 u8_t rcv_scale; 388 #endif 389 }; 390 391 #if LWIP_EVENT_API 392 393 enum lwip_event { 394 LWIP_EVENT_ACCEPT, 395 LWIP_EVENT_SENT, 396 LWIP_EVENT_RECV, 397 LWIP_EVENT_CONNECTED, 398 LWIP_EVENT_POLL, 399 LWIP_EVENT_ERR 400 }; 401 402 err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, 403 enum lwip_event, 404 struct pbuf *p, 405 u16_t size, 406 err_t err); 407 408 #endif /* LWIP_EVENT_API */ 409 410 /* Application program's interface: */ 411 #ifdef LOSCFG_NET_CONTAINER 412 void set_tcp_pcb_net_group(struct tcp_pcb *pcb, struct net_group *group); 413 struct net_group *get_net_group_from_tcp_pcb(const struct tcp_pcb *pcb); 414 #endif 415 struct tcp_pcb * tcp_new (void); 416 struct tcp_pcb * tcp_new_ip_type (u8_t type); 417 418 void tcp_arg (struct tcp_pcb *pcb, void *arg); 419 #if LWIP_CALLBACK_API 420 void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv); 421 void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent); 422 void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err); 423 void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept); 424 #endif /* LWIP_CALLBACK_API */ 425 void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval); 426 427 #if LWIP_LOWPOWER 428 u32_t tcp_fast_tmr_tick(void); 429 u32_t tcp_slow_tmr_tick(void); 430 #endif 431 432 #define tcp_set_flags(pcb, set_flags) do { (pcb)->flags = (tcpflags_t)((pcb)->flags | (set_flags)); } while(0) 433 #define tcp_clear_flags(pcb, clr_flags) do { (pcb)->flags = (tcpflags_t)((pcb)->flags & (tcpflags_t)(~(clr_flags) & TCP_ALLFLAGS)); } while(0) 434 #define tcp_is_flag_set(pcb, flag) (((pcb)->flags & (flag)) != 0) 435 436 #if LWIP_TCP_TIMESTAMPS 437 #define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss) 438 #else /* LWIP_TCP_TIMESTAMPS */ 439 /** @ingroup tcp_raw */ 440 #define tcp_mss(pcb) ((pcb)->mss) 441 #endif /* LWIP_TCP_TIMESTAMPS */ 442 /** @ingroup tcp_raw */ 443 #define tcp_sndbuf(pcb) (TCPWND16((pcb)->snd_buf)) 444 /** @ingroup tcp_raw */ 445 #define tcp_sndqueuelen(pcb) ((pcb)->snd_queuelen) 446 /** @ingroup tcp_raw */ 447 #define tcp_nagle_disable(pcb) tcp_set_flags(pcb, TF_NODELAY) 448 /** @ingroup tcp_raw */ 449 #define tcp_nagle_enable(pcb) tcp_clear_flags(pcb, TF_NODELAY) 450 /** @ingroup tcp_raw */ 451 #define tcp_nagle_disabled(pcb) tcp_is_flag_set(pcb, TF_NODELAY) 452 453 #if TCP_LISTEN_BACKLOG 454 #define tcp_backlog_set(pcb, new_backlog) do { \ 455 LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", (pcb)->state == LISTEN); \ 456 ((struct tcp_pcb_listen *)(pcb))->backlog = ((new_backlog) ? (new_backlog) : 1); } while(0) 457 void tcp_backlog_delayed(struct tcp_pcb* pcb); 458 void tcp_backlog_accepted(struct tcp_pcb* pcb); 459 #else /* TCP_LISTEN_BACKLOG */ 460 #define tcp_backlog_set(pcb, new_backlog) 461 #define tcp_backlog_delayed(pcb) 462 #define tcp_backlog_accepted(pcb) 463 #endif /* TCP_LISTEN_BACKLOG */ 464 #define tcp_accepted(pcb) do { LWIP_UNUSED_ARG(pcb); } while(0) /* compatibility define, not needed any more */ 465 466 void tcp_recved (struct tcp_pcb *pcb, u16_t len); 467 err_t tcp_bind (struct tcp_pcb *pcb, const ip_addr_t *ipaddr, 468 u16_t port); 469 void tcp_bind_netif(struct tcp_pcb *pcb, const struct netif *netif); 470 err_t tcp_connect (struct tcp_pcb *pcb, const ip_addr_t *ipaddr, 471 u16_t port, tcp_connected_fn connected); 472 473 struct tcp_pcb * tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err); 474 struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); 475 /** @ingroup tcp_raw */ 476 #define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) 477 478 void tcp_abort (struct tcp_pcb *pcb); 479 err_t tcp_close (struct tcp_pcb *pcb); 480 err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx); 481 482 err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len, 483 u8_t apiflags); 484 485 void tcp_setprio (struct tcp_pcb *pcb, u8_t prio); 486 487 err_t tcp_output (struct tcp_pcb *pcb); 488 489 err_t tcp_tcp_get_tcp_addrinfo(struct tcp_pcb *pcb, int local, ip_addr_t *addr, u16_t *port); 490 491 #define tcp_dbg_get_tcp_state(pcb) ((pcb)->state) 492 493 /* for compatibility with older implementation */ 494 #define tcp_new_ip6() tcp_new_ip_type(IPADDR_TYPE_V6) 495 496 #if LWIP_TCP_PCB_NUM_EXT_ARGS 497 u8_t tcp_ext_arg_alloc_id(void); 498 void tcp_ext_arg_set_callbacks(struct tcp_pcb *pcb, uint8_t id, const struct tcp_ext_arg_callbacks * const callbacks); 499 void tcp_ext_arg_set(struct tcp_pcb *pcb, uint8_t id, void *arg); 500 void *tcp_ext_arg_get(const struct tcp_pcb *pcb, uint8_t id); 501 #endif 502 503 #ifdef __cplusplus 504 } 505 #endif 506 507 #endif /* LWIP_TCP */ 508 509 #endif /* LWIP_HDR_TCP_H */ 510