diff options
Diffstat (limited to 'lib/libtle_l4p/tcp_ctl.h')
-rw-r--r-- | lib/libtle_l4p/tcp_ctl.h | 66 |
1 files changed, 62 insertions, 4 deletions
diff --git a/lib/libtle_l4p/tcp_ctl.h b/lib/libtle_l4p/tcp_ctl.h index 7dde8ff..31cbbb2 100644 --- a/lib/libtle_l4p/tcp_ctl.h +++ b/lib/libtle_l4p/tcp_ctl.h @@ -103,6 +103,10 @@ calc_rx_wnd(const struct tle_tcp_stream *s, uint32_t scale) return _rte_ring_get_mask(s->rx.q) << scale; } +/* + * Helper functions for stream_close() + */ + /* empty stream's send queue */ static inline void empty_tq(struct tle_tcp_stream *s) @@ -152,16 +156,19 @@ tcp_stream_reset(struct tle_ctx *ctx, struct tle_tcp_stream *s) rte_atomic32_set(&s->tx.arm, 0); /* reset TCB */ - uop = s->tcb.uop & ~TCP_OP_CLOSE; + uop = s->tcb.uop & ~TLE_TCP_OP_CLOSE_ABORT; memset(&s->tcb, 0, sizeof(s->tcb)); + /* reset remote events */ + s->err.rev = 0; + /* reset cached destination */ memset(&s->tx.dst, 0, sizeof(s->tx.dst)); - if (uop != TCP_OP_ACCEPT) { + if (uop != TLE_TCP_OP_ACCEPT) { /* free stream's destination port */ stream_clear_ctx(ctx, &s->s); - if (uop == TCP_OP_LISTEN) + if (uop == TLE_TCP_OP_LISTEN) empty_lq(s); } @@ -170,9 +177,11 @@ tcp_stream_reset(struct tle_ctx *ctx, struct tle_tcp_stream *s) stbl_del_stream(&ts->st, s->ste, s, (s->flags & TLE_CTX_FLAG_ST) == 0); s->ste = NULL; - empty_rq(s); } + /* empty RX queue */ + empty_rq(s); + /* empty TX queue */ empty_tq(s); @@ -189,6 +198,55 @@ tcp_stream_reset(struct tle_ctx *ctx, struct tle_tcp_stream *s) } } +/* + * - set new uop (CLOSE, ABORT) atomically + * - mark stream down + * - reset events/callbacks + * - if no further actions are necessary, then reset the stream straightway + * @return + * - negative error code + * - zero if stream was terminated and no further action is required + * - current stream state (TLE_TCP_ST *) otherwise + */ +static inline int +stream_close_prolog(struct tle_ctx *ctx, struct tle_tcp_stream *s, uint16_t nop) +{ + uint16_t uop; + uint32_t state; + static const struct tle_stream_cb zcb; + + /* check was *nop* already invoked */ + uop = s->tcb.uop; + if ((uop & nop) == nop) + return -EDEADLK; + + /* record that *nop* was already invoked */ + if (rte_atomic16_cmpset(&s->tcb.uop, uop, uop | nop) == 0) + return -EDEADLK; + + /* mark stream as unavaialbe for RX/TX. */ + tcp_stream_down(s); + + /* reset events/callbacks */ + s->rx.ev = NULL; + s->tx.ev = NULL; + s->err.ev = NULL; + + s->rx.cb = zcb; + s->tx.cb = zcb; + s->err.cb = zcb; + + state = s->tcb.state; + + /* CLOSED, LISTEN, SYN_SENT - we can close the stream straighway */ + if (state <= TLE_TCP_ST_SYN_SENT) { + tcp_stream_reset(ctx, s); + return 0; + } + + return state; +} + static inline struct tle_tcp_stream * tcp_stream_get(struct tle_ctx *ctx, uint32_t flag) { |