return NULL;
/* check that we have a proper stream. */
- if (s->tcb.state != TCP_ST_LISTEN) {
+ if (s->tcb.state != TLE_TCP_ST_LISTEN) {
tcp_stream_release(s);
s = NULL;
}
if (tcp_stream_acquire(s) < 0)
return NULL;
- else if (s->tcb.state == TCP_ST_CLOSED) {
+ else if (s->tcb.state == TLE_TCP_ST_CLOSED) {
tcp_stream_release(s);
return NULL;
}
if (tcp_stream_acquire(s) < 0)
return NULL;
/* check that we have a proper stream. */
- else if (s->tcb.state == TCP_ST_CLOSED) {
+ else if (s->tcb.state == TLE_TCP_ST_CLOSED) {
tcp_stream_release(s);
s = NULL;
}
{
struct sdr *dr;
- s->tcb.state = TCP_ST_CLOSED;
+ s->tcb.state = TLE_TCP_ST_CLOSED;
rte_smp_wmb();
timer_stop(s);
/* close() was already invoked, schedule final cleanup */
- if ((s->tcb.uop & TCP_OP_CLOSE) != 0) {
+ if ((s->tcb.uop & TLE_TCP_OP_CLOSE) != 0) {
dr = CTX_TCP_SDR(s->s.ctx);
STAILQ_INSERT_TAIL(&dr->be, &s->s, link);
cs->tcb.snd.ssthresh = cs->tcb.snd.wnd;
cs->tcb.snd.rto_tw = ps->tcb.snd.rto_tw;
- cs->tcb.state = TCP_ST_ESTABLISHED;
+ cs->tcb.state = TLE_TCP_ST_ESTABLISHED;
/* add stream to the table */
cs->ste = stbl_add_stream(st, pi, cs);
if (cs->ste == NULL)
return -ENOBUFS;
- cs->tcb.uop |= TCP_OP_ACCEPT;
+ cs->tcb.uop |= TLE_TCP_OP_ACCEPT;
tcp_stream_up(cs);
return 0;
}
stream_timewait(struct tle_tcp_stream *s, uint32_t rto)
{
if (rto != 0) {
- s->tcb.state = TCP_ST_TIME_WAIT;
+ s->tcb.state = TLE_TCP_ST_TIME_WAIT;
s->tcb.snd.rto = rto;
timer_reset(s);
} else
int32_t ackfin;
s->tcb.rcv.nxt += 1;
+ s->err.rev |= TLE_TCP_REV_FIN;
ackfin = (s->tcb.snd.una == s->tcb.snd.fss);
state = s->tcb.state;
- if (state == TCP_ST_ESTABLISHED) {
- s->tcb.state = TCP_ST_CLOSE_WAIT;
+ if (state == TLE_TCP_ST_ESTABLISHED) {
+ s->tcb.state = TLE_TCP_ST_CLOSE_WAIT;
/* raise err.ev & err.cb */
if (s->err.ev != NULL)
tle_event_raise(s->err.ev);
else if (s->err.cb.func != NULL)
s->err.cb.func(s->err.cb.data, &s->s);
- } else if (state == TCP_ST_FIN_WAIT_1 || state == TCP_ST_CLOSING) {
+ } else if (state == TLE_TCP_ST_FIN_WAIT_1 ||
+ state == TLE_TCP_ST_CLOSING) {
rsp->flags |= TCP_FLAG_ACK;
if (ackfin != 0)
stream_timewait(s, s->tcb.snd.rto_tw);
else
- s->tcb.state = TCP_ST_CLOSING;
- } else if (state == TCP_ST_FIN_WAIT_2) {
+ s->tcb.state = TLE_TCP_ST_CLOSING;
+ } else if (state == TLE_TCP_ST_FIN_WAIT_2) {
rsp->flags |= TCP_FLAG_ACK;
stream_timewait(s, s->tcb.snd.rto_tw);
- } else if (state == TCP_ST_LAST_ACK && ackfin != 0) {
+ } else if (state == TLE_TCP_ST_LAST_ACK && ackfin != 0) {
stream_term(s);
}
}
if (ret != 0)
return ret;
- if (state < TCP_ST_ESTABLISHED)
+ if (state < TLE_TCP_ST_ESTABLISHED)
return -EINVAL;
if (plen != 0) {
* In the SYN-SENT state (a RST received in response to an initial SYN),
* the RST is acceptable if the ACK field acknowledges the SYN.
*/
- if (state == TCP_ST_SYN_SENT) {
+ if (state == TLE_TCP_ST_SYN_SENT) {
rc = ((flags & TCP_FLAG_ACK) == 0 ||
si->ack != s->tcb.snd.nxt) ?
-ERANGE : 0;
else
rc = check_seqn(&s->tcb, si->seq, 0);
- if (rc == 0)
+ if (rc == 0) {
+ s->err.rev |= TLE_TCP_REV_RST;
stream_term(s);
+ }
return rc;
}
empty_tq(s);
state = s->tcb.state;
- if (state == TCP_ST_LAST_ACK)
+ if (state == TLE_TCP_ST_LAST_ACK)
stream_term(s);
- else if (state == TCP_ST_FIN_WAIT_1) {
+ else if (state == TLE_TCP_ST_FIN_WAIT_1) {
timer_stop(s);
- s->tcb.state = TCP_ST_FIN_WAIT_2;
- } else if (state == TCP_ST_CLOSING) {
+ s->tcb.state = TLE_TCP_ST_FIN_WAIT_2;
+ } else if (state == TLE_TCP_ST_CLOSING) {
stream_timewait(s, s->tcb.snd.rto_tw);
}
}
struct tle_tcp_syn_opts so;
struct rte_tcp_hdr *th;
- if (state != TCP_ST_SYN_SENT)
+ if (state != TLE_TCP_ST_SYN_SENT)
return -EINVAL;
/*
rsp->flags |= TCP_FLAG_ACK;
timer_stop(s);
- s->tcb.state = TCP_ST_ESTABLISHED;
+ s->tcb.state = TLE_TCP_ST_ESTABLISHED;
rte_smp_wmb();
if (s->tx.ev != NULL)
i += (ret > 0);
/* normal data/ack packets */
- } else if (state >= TCP_ST_ESTABLISHED && state <= TCP_ST_LAST_ACK) {
+ } else if (state >= TLE_TCP_ST_ESTABLISHED &&
+ state <= TLE_TCP_ST_LAST_ACK) {
/* process incoming data packets. */
dack_info_init(&tack, &s->tcb);
k = 0;
state = s->tcb.state;
- if (state == TCP_ST_LISTEN) {
+ if (state == TLE_TCP_ST_LISTEN) {
/* one connection per flow */
cs = NULL;
return -EINVAL;
if (tcp_stream_try_acquire(s) > 0) {
- rc = rte_atomic16_cmpset(&s->tcb.state, TCP_ST_CLOSED,
- TCP_ST_SYN_SENT);
+ rc = rte_atomic16_cmpset(&s->tcb.state, TLE_TCP_ST_CLOSED,
+ TLE_TCP_ST_SYN_SENT);
rc = (rc == 0) ? -EDEADLK : 0;
} else
rc = -EINVAL;
}
/* fill stream, prepare and transmit syn pkt */
- s->tcb.uop |= TCP_OP_CONNECT;
+ s->tcb.uop |= TLE_TCP_OP_CONNECT;
rc = tx_syn(s, addr);
tcp_stream_release(s);
}
do {
- s->tcb.uop |= TCP_OP_ESTABLISH;
+ s->tcb.uop |= TLE_TCP_OP_ESTABLISH;
/* check and use stream addresses and parameters */
rc = tcp_stream_fill_prm(s, prm);
/* fill TCB from user provided data */
tcb_establish(s, ci);
- s->tcb.state = TCP_ST_ESTABLISHED;
+ s->tcb.state = TLE_TCP_ST_ESTABLISHED;
tcp_stream_up(s);
} while (0);
}
state = s->tcb.state;
- if (state != TCP_ST_ESTABLISHED && state != TCP_ST_CLOSE_WAIT) {
+ if (state != TLE_TCP_ST_ESTABLISHED && state != TLE_TCP_ST_CLOSE_WAIT) {
rte_errno = ENOTCONN;
tcp_stream_release(s);
return 0;
}
state = s->tcb.state;
- if (state != TCP_ST_ESTABLISHED && state != TCP_ST_CLOSE_WAIT) {
+ if (state != TLE_TCP_ST_ESTABLISHED && state != TLE_TCP_ST_CLOSE_WAIT) {
rte_errno = ENOTCONN;
tcp_stream_release(s);
return -1;
tx_nxt_data(s, tms);
/* we also have to send a FIN */
- if (state != TCP_ST_ESTABLISHED &&
- state != TCP_ST_CLOSE_WAIT &&
+ if (state != TLE_TCP_ST_ESTABLISHED &&
+ state != TLE_TCP_ST_CLOSE_WAIT &&
tcp_txq_nxt_cnt(s) == 0 &&
s->tcb.snd.fss != s->tcb.snd.nxt) {
s->tcb.snd.fss = ++s->tcb.snd.nxt;
state = s->tcb.state;
- if (state == TCP_ST_SYN_SENT) {
+ if (state == TLE_TCP_ST_SYN_SENT) {
/* send the SYN, start the rto timer */
send_ack(s, tms, TCP_FLAG_SYN);
timer_start(s);
- } else if (state >= TCP_ST_ESTABLISHED && state <= TCP_ST_LAST_ACK) {
+ } else if (state >= TLE_TCP_ST_ESTABLISHED &&
+ state <= TLE_TCP_ST_LAST_ACK) {
tx_data_fin(s, tms, state);
if (s->tcb.snd.nb_retx < s->tcb.snd.nb_retm) {
- if (state >= TCP_ST_ESTABLISHED && state <= TCP_ST_LAST_ACK) {
+ if (state >= TLE_TCP_ST_ESTABLISHED &&
+ state <= TLE_TCP_ST_LAST_ACK) {
/* update SND.CWD and SND.SSTHRESH */
rto_cwnd_update(&s->tcb);
tx_data_fin(s, tms, state);
- } else if (state == TCP_ST_SYN_SENT) {
+ } else if (state == TLE_TCP_ST_SYN_SENT) {
/* resending SYN */
s->tcb.so.ts.val = tms;
send_ack(s, tms, TCP_FLAG_SYN);
- } else if (state == TCP_ST_TIME_WAIT) {
+ } else if (state == TLE_TCP_ST_TIME_WAIT) {
+ s->err.rev |= TLE_TCP_REV_RTO;
stream_term(s);
}
timer_restart(s);
} else {
+ s->err.rev |= TLE_TCP_REV_RTO;
send_rst(s, s->tcb.snd.nxt);
stream_term(s);
}
/* check was close() already invoked */
uop = s->tcb.uop;
- if ((uop & TCP_OP_CLOSE) != 0)
+ if ((uop & TLE_TCP_OP_CLOSE) != 0)
return -EDEADLK;
/* record that close() was already invoked */
- if (rte_atomic16_cmpset(&s->tcb.uop, uop, uop | TCP_OP_CLOSE) == 0)
+ if (rte_atomic16_cmpset(&s->tcb.uop, uop, uop | TLE_TCP_OP_CLOSE) == 0)
return -EDEADLK;
/* mark stream as unavaialbe for RX/TX. */
state = s->tcb.state;
/* CLOSED, LISTEN, SYN_SENT - we can close the stream straighway */
- if (state <= TCP_ST_SYN_SENT) {
+ if (state <= TLE_TCP_ST_SYN_SENT) {
tcp_stream_reset(ctx, s);
return 0;
}
/* generate FIN and proceed with normal connection termination */
- if (state == TCP_ST_ESTABLISHED || state == TCP_ST_CLOSE_WAIT) {
+ if (state == TLE_TCP_ST_ESTABLISHED || state == TLE_TCP_ST_CLOSE_WAIT) {
/* change state */
- s->tcb.state = (state == TCP_ST_ESTABLISHED) ?
- TCP_ST_FIN_WAIT_1 : TCP_ST_LAST_ACK;
+ s->tcb.state = (state == TLE_TCP_ST_ESTABLISHED) ?
+ TLE_TCP_ST_FIN_WAIT_1 : TLE_TCP_ST_LAST_ACK;
/* mark stream as writable/readable again */
tcp_stream_up(s);
/* app may listen for multiple times to change backlog,
* we will just return success for such cases.
*/
- if (s->tcb.state == TCP_ST_LISTEN)
+ if (s->tcb.state == TLE_TCP_ST_LISTEN)
return 0;
/* mark stream as not closable. */
if (tcp_stream_try_acquire(s) > 0) {
- rc = rte_atomic16_cmpset(&s->tcb.state, TCP_ST_CLOSED,
- TCP_ST_LISTEN);
+ rc = rte_atomic16_cmpset(&s->tcb.state, TLE_TCP_ST_CLOSED,
+ TLE_TCP_ST_LISTEN);
if (rc != 0) {
- s->tcb.uop |= TCP_OP_LISTEN;
+ s->tcb.uop |= TLE_TCP_OP_LISTEN;
s->tcb.rcv.wnd = calc_rx_wnd(s, TCP_WSCALE_DEFAULT);
rc = 0;
} else
s = TCP_STREAM(ts);
- if (tcp_stream_try_acquire(s) < 0 || (s->tcb.uop & TCP_OP_CLOSE) != 0) {
+ if (tcp_stream_try_acquire(s) < 0 ||
+ (s->tcb.uop & TLE_TCP_OP_CLOSE) != 0) {
tcp_stream_release(s);
return -EINVAL;
}
else if (s->tx.cb.func != NULL)
s->tx.cb.func(s->tx.cb.data, &s->s);
}
- if (s->tcb.state == TCP_ST_CLOSE_WAIT ||
- s->tcb.state == TCP_ST_CLOSED) {
+ if (s->tcb.state == TLE_TCP_ST_CLOSE_WAIT ||
+ s->tcb.state == TLE_TCP_ST_CLOSED) {
if (s->err.ev != NULL)
tle_event_raise(s->err.ev);
else if (s->err.cb.func != NULL)
{
struct tle_tcp_stream *s;
- if (ts == NULL)
+ s = TCP_STREAM(ts);
+ if (ts == NULL || s->s.type >= TLE_VNUM)
return -EINVAL;
- s = TCP_STREAM(ts);
return s->tcb.snd.mss;
}
+
+int
+tle_tcp_stream_get_state(const struct tle_stream * ts,
+ struct tle_tcp_stream_state *st)
+{
+ struct tle_tcp_stream *s;
+
+ s = TCP_STREAM(ts);
+ if (ts == NULL || s->s.type >= TLE_VNUM)
+ return -EINVAL;
+
+ st->state = s->tcb.state;
+ st->uop = s->tcb.uop;
+ st->rev = s->err.rev;
+
+ return 0;
+}
extern "C" {
#endif
+/**
+ * TCP stream states
+ */
+enum {
+ TLE_TCP_ST_CLOSED,
+ TLE_TCP_ST_LISTEN,
+ TLE_TCP_ST_SYN_SENT,
+ TLE_TCP_ST_SYN_RCVD,
+ TLE_TCP_ST_ESTABLISHED,
+ TLE_TCP_ST_FIN_WAIT_1,
+ TLE_TCP_ST_FIN_WAIT_2,
+ TLE_TCP_ST_CLOSE_WAIT,
+ TLE_TCP_ST_CLOSING,
+ TLE_TCP_ST_LAST_ACK,
+ TLE_TCP_ST_TIME_WAIT,
+ TLE_TCP_ST_NUM
+};
+
+/**
+ * User control operations for TCP stream
+ */
+enum {
+ TLE_TCP_OP_LISTEN = 0x1,
+ TLE_TCP_OP_ACCEPT = 0x2,
+ TLE_TCP_OP_CONNECT = 0x4,
+ TLE_TCP_OP_ESTABLISH = 0x8,
+ TLE_TCP_OP_CLOSE = 0x10,
+};
+
+/**
+ * termination/error events from remote peer
+ */
+enum {
+ TLE_TCP_REV_FIN = 0x1, /** FIN received from peer*/
+ TLE_TCP_REV_RST = 0x2, /** RST received from peer */
+ TLE_TCP_REV_RTO = 0x4, /** receive timed-out */
+};
+
/**
* TCP stream creation parameters.
*/
struct tle_tcp_syn_opts so;
};
+/**
+ * TCP stream state information.
+ */
+struct tle_tcp_stream_state {
+ /** current TCP state (one of TLE_TCP_ST_*) */
+ uint16_t state;
+ /** bitmask of control ops performed by user (TLE_TCP_OP_*) */
+ uint16_t uop;
+ /** bitmask of remote termination events (TLE_TCP_REV_*) */
+ uint16_t rev;
+};
+
/**
* create a new stream within given TCP context.
* @param ctx
*/
int tle_tcp_stream_get_mss(const struct tle_stream *ts);
+/**
+ * Get current TCP stream state
+ * @param ts
+ * Stream to retrieve state information from.
+ * @return
+ * zero on successful completion.
+ * - EINVAL - invalid parameter passed to function
+ */
+int tle_tcp_stream_get_state(const struct tle_stream *ts,
+ struct tle_tcp_stream_state *st);
+
struct tle_stream *
tle_tcp_stream_establish(struct tle_ctx *ctx,
const struct tle_tcp_stream_param *prm,