tcp: introduce ext_args per pcb

This introduces the concept of ext (external/extended) arguments per
tcp_pcb (also for listening pcbs) to store more data than just one
"void *arg" per pcb. The "arg" is for use to applications, whereas
the ext_args may be used by frameworks and leave "arg" untouched.

In addition to a void pointer, callbacks are added to help frameworks
migrate arguments from listen pcb to connection pcb and to free args
when the pcb is freed.

Signed-off-by: goldsimon <goldsimon@gmx.de>
This commit is contained in:
goldsimon
2018-01-24 22:01:39 +01:00
parent ebe782ba16
commit 0e85582bc0
6 changed files with 238 additions and 2 deletions

View File

@@ -8,7 +8,7 @@
* Transmission Control Protocol for IP\n
* @see @ref api
*
* Common functions for the TCP implementation, such as functinos
* Common functions for the TCP implementation, such as functions
* for manipulating the data structures and the TCP timer functions. TCP functions
* related to input and output is found in tcp_in.c and tcp_out.c respectively.\n
*
@@ -190,6 +190,9 @@ static u8_t tcp_timer_ctr;
static u16_t tcp_new_port(void);
static err_t tcp_close_shutdown_fin(struct tcp_pcb *pcb);
#if LWIP_TCP_PCB_NUM_EXT_ARGS
static void tcp_ext_arg_invoke_callbacks_destroyed(struct tcp_pcb_ext_args *ext_args);
#endif
/**
* Initialize this module.
@@ -207,6 +210,9 @@ void
tcp_free(struct tcp_pcb *pcb)
{
LWIP_ASSERT("tcp_free: LISTEN", pcb->state != LISTEN);
#if LWIP_TCP_PCB_NUM_EXT_ARGS
tcp_ext_arg_invoke_callbacks_destroyed(pcb->ext_args);
#endif
memp_free(MEMP_TCP_PCB, pcb);
}
@@ -215,6 +221,9 @@ static void
tcp_free_listen(struct tcp_pcb *pcb)
{
LWIP_ASSERT("tcp_free_listen: !LISTEN", pcb->state != LISTEN);
#if LWIP_TCP_PCB_NUM_EXT_ARGS
tcp_ext_arg_invoke_callbacks_destroyed(pcb->ext_args);
#endif
memp_free(MEMP_TCP_PCB_LISTEN, pcb);
}
@@ -866,6 +875,10 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err)
if (pcb->local_port != 0) {
TCP_RMV(&tcp_bound_pcbs, pcb);
}
#if LWIP_TCP_PCB_NUM_EXT_ARGS
/* copy over ext_args to listening pcb */
memcpy(&lpcb->ext_args, &pcb->ext_args, sizeof(pcb->ext_args));
#endif
tcp_free(pcb);
#if LWIP_CALLBACK_API
lpcb->accept = tcp_accept_null;
@@ -2460,4 +2473,158 @@ tcp_pcbs_sane(void)
}
#endif /* TCP_DEBUG */
#if LWIP_TCP_PCB_NUM_EXT_ARGS
/**
* @defgroup tcp_raw_extargs ext arguments
* @ingroup tcp_raw
* Additional data storage per tcp pcb\n
* @see @ref tcp_raw
*
* When LWIP_TCP_PCB_NUM_EXT_ARGS is > 0, every tcp pcb (including listen pcb)
* includes a number of additional argument entries in an array.
*
* To support memory management, in addition to a 'void *', callbacks can be
* provided to manage transition from listening pcbs to connections and to
* deallocate memory when a pcb is deallocated (see struct @ref tcp_ext_arg_callbacks).
*
* After allocating this index, use @ref tcp_ext_arg_set and @ref tcp_ext_arg_get
* to store and load arguments from this index for a given pcb.
*/
static u8_t tcp_ext_arg_id;
/**
* @ingroup tcp_raw_extargs
* Allocate an index to store data in ext_args member of struct tcp_pcb.
* Returned value is an index in mentioned array.
* The index is *global* over all pcbs!
*
* When @ref LWIP_TCP_PCB_NUM_EXT_ARGS is > 0, every tcp pcb (including listen pcb)
* includes a number of additional argument entries in an array.
*
* To support memory management, in addition to a 'void *', callbacks can be
* provided to manage transition from listening pcbs to connections and to
* deallocate memory when a pcb is deallocated (see struct @ref tcp_ext_arg_callbacks).
*
* After allocating this index, use @ref tcp_ext_arg_set and @ref tcp_ext_arg_get
* to store and load arguments from this index for a given pcb.
*
* @return a unique index into struct tcp_pcb.ext_args
*/
u8_t
tcp_ext_arg_alloc_id(void)
{
u8_t result = tcp_ext_arg_id;
tcp_ext_arg_id++;
LWIP_ASSERT_CORE_LOCKED();
#if LWIP_TCP_PCB_NUM_EXT_ARGS >= 255
#error LWIP_TCP_PCB_NUM_EXT_ARGS
#endif
LWIP_ASSERT("Increase LWIP_TCP_PCB_NUM_EXT_ARGS in lwipopts.h", result < LWIP_TCP_PCB_NUM_EXT_ARGS);
return result;
}
/**
* @ingroup tcp_raw_extargs
* Set callbacks for a given index of ext_args on the specified pcb.
*
* @param pcb tcp_pcb for which to set the callback
* @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id)
* @param callbacks callback table (const since it is referenced, not copied!)
*/
void
tcp_ext_arg_set_callbacks(struct tcp_pcb *pcb, uint8_t id, const struct tcp_ext_arg_callbacks * const callbacks)
{
LWIP_ASSERT("pcb != NULL", pcb != NULL);
LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS);
LWIP_ASSERT("callbacks != NULL", callbacks != NULL);
LWIP_ASSERT_CORE_LOCKED();
pcb->ext_args[id].callbacks = callbacks;
}
/**
* @ingroup tcp_raw_extargs
* Set data for a given index of ext_args on the specified pcb.
*
* @param pcb tcp_pcb for which to set the data
* @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id)
* @param arg data pointer to set
*/
void tcp_ext_arg_set(struct tcp_pcb *pcb, uint8_t id, void *arg)
{
LWIP_ASSERT("pcb != NULL", pcb != NULL);
LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS);
LWIP_ASSERT_CORE_LOCKED();
pcb->ext_args[id].data = arg;
}
/**
* @ingroup tcp_raw_extargs
* Set data for a given index of ext_args on the specified pcb.
*
* @param pcb tcp_pcb for which to set the data
* @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id)
* @return data pointer at the given index
*/
void *tcp_ext_arg_get(const struct tcp_pcb *pcb, uint8_t id)
{
LWIP_ASSERT("pcb != NULL", pcb != NULL);
LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS);
LWIP_ASSERT_CORE_LOCKED();
return pcb->ext_args[id].data;
}
/** This function calls the "destroy" callback for all ext_args once a pcb is
* freed.
*/
static void
tcp_ext_arg_invoke_callbacks_destroyed(struct tcp_pcb_ext_args *ext_args)
{
int i;
LWIP_ASSERT("ext_args != NULL", ext_args != NULL);
for (i = 0; i < LWIP_TCP_PCB_NUM_EXT_ARGS; i++) {
if (ext_args[i].callbacks != NULL) {
if (ext_args[i].callbacks->destroy != NULL) {
ext_args[i].callbacks->destroy((u8_t)i, ext_args[i].data);
}
}
}
}
/** This function calls the "passive_open" callback for all ext_args if a connection
* is in the process of being accepted. This is called just after the SYN is
* received and before a SYN/ACK is sent, to allow to modify the very first
* segment sent even on passive open. Naturally, the "accepted" callback of the
* pcb has not been called yet!
*/
err_t
tcp_ext_arg_invoke_callbacks_passive_open(struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb)
{
int i;
LWIP_ASSERT("lpcb != NULL", lpcb != NULL);
LWIP_ASSERT("cpcb != NULL", cpcb != NULL);
for (i = 0; i < LWIP_TCP_PCB_NUM_EXT_ARGS; i++) {
if (lpcb->ext_args[i].callbacks != NULL) {
if (lpcb->ext_args[i].callbacks->passive_open != NULL) {
err_t err = lpcb->ext_args[i].callbacks->passive_open((u8_t)i, lpcb, cpcb);
if (err != ERR_OK) {
return err;
}
}
}
}
return ERR_OK;
}
#endif /* LWIP_TCP_PCB_NUM_EXT_ARGS */
#endif /* LWIP_TCP */

View File

@@ -680,6 +680,13 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
MIB2_STATS_INC(mib2.tcppassiveopens);
#if LWIP_TCP_PCB_NUM_EXT_ARGS
if (tcp_ext_arg_invoke_callbacks_passive_open(pcb, npcb) != ERR_OK) {
tcp_abandon(npcb, 0);
return;
}
#endif
/* Send a SYN|ACK together with the MSS option. */
rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK);
if (rc != ERR_OK) {