[tcp] add support for otTcpForwardProgress callback (#7583)

This commit adds support for the remaining TCP callback, which was not
yet supported.

Originally, the unimplemented callback was otTcpSendReady, which would
indicate to the application when new data added to the TCP send buffer
would be sent out immediately. There was also discussion of adding an
otTcpBytesAcked callback, which, together with the
otTcpSendByExtension() call, would allow a circular buffer to be
implemented efficiently on top of the otLinkedBuffer API.

Ultimately, it seemed best to generalize the otTcpSendReady callback
to include both cases where bytes are acked by the connection peer,
and where the send buffer drains, allowing new data to be sent
immediately. The reasoning behind this decision is that both the
otTcpSendReady and otTcpBytesAcked callbacks are triggered by the same
event --- an ACK received from the connection peer --- and that it may
require the application to have to "coordinate state" across
callbacks. Having a single callback function to indicate both
conditions seemed like it could simplify applications significantly.

The new, combined, callback is otTcpForwardProgress. This commit
implements support and documentation for this callback function.
This commit is contained in:
Sam Kumar
2022-04-22 09:12:12 -07:00
committed by GitHub
parent 4bd7ab4b79
commit d79468bb18
10 changed files with 262 additions and 101 deletions
+7 -6
View File
@@ -1186,6 +1186,7 @@ tcp_do_segment(struct ip6_hdr* ip6, struct tcphdr *th, otMessage* msg,
{
uint32_t poppedbytes = lbuf_pop(&tp->sendbuf, acked, &sig->links_popped);
KASSERT(poppedbytes == acked, ("More bytes were acked than are in the send buffer"));
sig->bytes_acked += poppedbytes;
}
if (SEQ_GT(tp->snd_una, tp->snd_recover) &&
SEQ_LEQ(th->th_ack, tp->snd_recover))
@@ -1329,10 +1330,9 @@ tcp_do_segment(struct ip6_hdr* ip6, struct tcphdr *th, otMessage* msg,
*/
if (!tpiscantrcv(tp)) {
size_t usedbefore = cbuf_used_space(&tp->recvbuf);
cbuf_write(&tp->recvbuf, msg, otMessageGetOffset(msg) + drop_hdrlen, tlen, cbuf_copy_from_message);
if (usedbefore == 0 && tlen > 0) {
sig->recvbuf_notempty = true;
if (tlen > 0) {
sig->recvbuf_added = true;
}
} else {
/*
@@ -2213,10 +2213,12 @@ process_ACK:
tp->snd_wnd -= usedspace;
poppedbytes = lbuf_pop(&tp->sendbuf, usedspace, &sig->links_popped);
KASSERT(poppedbytes == usedspace, ("Could not fully empty send buffer"));
sig->bytes_acked += poppedbytes;
ourfinisacked = 1;
} else {
uint32_t poppedbytes = lbuf_pop(&tp->sendbuf, acked, &sig->links_popped);
KASSERT(poppedbytes == acked, ("Could not remove acked bytes from send buffer"));
sig->bytes_acked += poppedbytes;
tp->snd_wnd -= acked;
ourfinisacked = 0;
}
@@ -2414,10 +2416,9 @@ step6:
* sbappendstream_locked(&so->so_rcv, m, 0);).
*/
if (!tpiscantrcv(tp)) {
size_t usedbefore = cbuf_used_space(&tp->recvbuf);
cbuf_write(&tp->recvbuf, msg, otMessageGetOffset(msg) + drop_hdrlen, tlen, cbuf_copy_from_message);
if (usedbefore == 0 && tlen > 0) {
sig->recvbuf_notempty = true;
if (tlen > 0) {
sig->recvbuf_added = true;
}
} else if (tlen > 0) {
/*
+2 -2
View File
@@ -103,8 +103,8 @@ present:
KASSERT(merged == mergeable, ("Reassembly merge out of bounds: tried to merge %d, but merged %d", (int) mergeable, (int) merged));
if (tpiscantrcv(tp)) {
cbuf_pop(&tp->recvbuf, merged); // So no data really enters the buffer
} else if (usedbefore == 0 && merged > 0) {
sig->recvbuf_notempty = true;
} else if (merged > 0) {
sig->recvbuf_added = true;
}
} else {
/* If there is data in the buffer AND we can't receive more, then that must be because we received a FIN,
+2 -2
View File
@@ -57,7 +57,7 @@ void lbuf_extend(struct lbufhead* buffer, size_t numbytes) {
buffer->tail->mLength += numbytes;
}
size_t lbuf_pop(struct lbufhead* buffer, size_t numbytes, int* ntraversed) {
size_t lbuf_pop(struct lbufhead* buffer, size_t numbytes, uint32_t* ntraversed) {
otLinkedBuffer* curr = buffer->head;
size_t bytesleft = numbytes;
size_t curroffset = buffer->offset;
@@ -109,6 +109,6 @@ int lbuf_getrange(struct lbufhead* buffer, size_t offset, size_t numbytes,
return 0;
}
size_t lbuf_used_space(struct lbufhead* buffer) {
size_t lbuf_used_space(const struct lbufhead* buffer) {
return buffer->length;
}
+2 -2
View File
@@ -65,7 +65,7 @@ void lbuf_extend(struct lbufhead* buffer, size_t numbytes);
NUMBYTES bytes in the buffer to begin with). *NTRAVERSED is incremented once
for each entry in the buffer that is no longer referenced and can be
reclaimed. */
size_t lbuf_pop(struct lbufhead* buffer, size_t numbytes, int* ntraversed);
size_t lbuf_pop(struct lbufhead* buffer, size_t numbytes, uint32_t* ntraversed);
/* Given a range of indices, specified by an OFFSET from the start and a
length NUMBYTES, this function locates the chain of linked buffer entries
@@ -83,6 +83,6 @@ int lbuf_getrange(struct lbufhead* buffer, size_t offset, size_t numbytes,
struct otLinkedBuffer** last, size_t* lastextra);
/* Returns the total number of bytes stored in the buffer. */
size_t lbuf_used_space(struct lbufhead* buffer);
size_t lbuf_used_space(const struct lbufhead* buffer);
#endif
+31 -22
View File
@@ -42,43 +42,52 @@ extern "C" {
#endif
#include <errno.h>
#include <openthread/ip6.h>
#include <openthread/message.h>
#include "bsdtcp/ip6.h"
#include "bsdtcp/tcp.h"
#include "bsdtcp/tcp_fsm.h"
#include "bsdtcp/tcp_timer.h"
#include "bsdtcp/tcp_var.h"
#include <openthread/ip6.h>
#include <openthread/message.h>
#define RELOOKUP_REQUIRED -1
#define CONN_LOST_NORMAL 0
struct tcplp_signals {
int links_popped;
bool conn_established;
bool recvbuf_notempty;
bool rcvd_fin;
struct tcplp_signals
{
uint32_t links_popped;
uint32_t bytes_acked;
bool conn_established;
bool recvbuf_added;
bool rcvd_fin;
};
/*
* Functions that the TCP protocol logic can call to interact with the rest of
* the system.
*/
otMessage* tcplp_sys_new_message(otInstance* instance);
void tcplp_sys_free_message(otInstance* instance, otMessage* pkt);
void tcplp_sys_send_message(otInstance* instance, otMessage* pkt, otMessageInfo* info);
uint32_t tcplp_sys_get_ticks();
uint32_t tcplp_sys_get_millis();
void tcplp_sys_set_timer(struct tcpcb* tcb, uint8_t timer_flag, uint32_t delay);
void tcplp_sys_stop_timer(struct tcpcb* tcb, uint8_t timer_flag);
struct tcpcb* tcplp_sys_accept_ready(struct tcpcb_listen* tpl, struct in6_addr* addr, uint16_t port);
bool tcplp_sys_accepted_connection(struct tcpcb_listen* tpl, struct tcpcb* accepted, struct in6_addr* addr, uint16_t port);
void tcplp_sys_connection_lost(struct tcpcb* tcb, uint8_t errnum);
void tcplp_sys_on_state_change(struct tcpcb* tcb, int newstate);
void tcplp_sys_log(const char* format, ...);
void tcplp_sys_panic(const char* format, ...);
bool tcplp_sys_autobind(otInstance *aInstance, const otSockAddr *aPeer, otSockAddr *aToBind, bool aBindAddress, bool aBindPort);
uint32_t tcplp_sys_generate_isn();
otMessage * tcplp_sys_new_message(otInstance *instance);
void tcplp_sys_free_message(otInstance *instance, otMessage *pkt);
void tcplp_sys_send_message(otInstance *instance, otMessage *pkt, otMessageInfo *info);
uint32_t tcplp_sys_get_ticks();
uint32_t tcplp_sys_get_millis();
void tcplp_sys_set_timer(struct tcpcb *tcb, uint8_t timer_flag, uint32_t delay);
void tcplp_sys_stop_timer(struct tcpcb *tcb, uint8_t timer_flag);
struct tcpcb *tcplp_sys_accept_ready(struct tcpcb_listen *tpl, struct in6_addr *addr, uint16_t port);
bool tcplp_sys_accepted_connection(struct tcpcb_listen *tpl,
struct tcpcb * accepted,
struct in6_addr * addr,
uint16_t port);
void tcplp_sys_connection_lost(struct tcpcb *tcb, uint8_t errnum);
void tcplp_sys_on_state_change(struct tcpcb *tcb, int newstate);
void tcplp_sys_log(const char *format, ...);
void tcplp_sys_panic(const char *format, ...);
bool tcplp_sys_autobind(otInstance * aInstance,
const otSockAddr *aPeer,
otSockAddr * aToBind,
bool aBindAddress,
bool aBindPort);
uint32_t tcplp_sys_generate_isn();
#ifdef __cplusplus
} // extern "C"