diff --git a/sys/include/net/gnrc/tcp.h b/sys/include/net/gnrc/tcp.h index 773a0f48fdebe33aa3feabacf3a0d211b55e2baa..67da62adedbcd20b68985b3eb3e352a2364f23c0 100644 --- a/sys/include/net/gnrc/tcp.h +++ b/sys/include/net/gnrc/tcp.h @@ -174,10 +174,18 @@ ssize_t gnrc_tcp_recv(gnrc_tcp_tcb_t *tcb, void *data, const size_t max_len, * @pre @p tcb must not be NULL. * * @param[in,out] tcb TCB holding the connection information. + */ +void gnrc_tcp_close(gnrc_tcp_tcb_t *tcb); + +/** + * @brief Abort a TCP connection. * - * @returns Zero on success. + * @pre gnrc_tcp_tcb_init() must have been successfully called. + * @pre @p tcb must not be NULL. + * + * @param[in,out] tcb TCB holding the connection information. */ -int gnrc_tcp_close(gnrc_tcp_tcb_t *tcb); +void gnrc_tcp_abort(gnrc_tcp_tcb_t *tcb); /** * @brief Calculate and set checksum in TCP header. diff --git a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp.c b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp.c index e9ac63efc2c1e1fe4fffb08f0d6c3fd1d3ba6d87..eff2585686e27b382dba763a5fd80b874637a9a3 100644 --- a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp.c +++ b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp.c @@ -473,7 +473,7 @@ ssize_t gnrc_tcp_recv(gnrc_tcp_tcb_t *tcb, void *data, const size_t max_len, return ret; } -int gnrc_tcp_close(gnrc_tcp_tcb_t *tcb) +void gnrc_tcp_close(gnrc_tcp_tcb_t *tcb) { assert(tcb != NULL); @@ -521,7 +521,19 @@ int gnrc_tcp_close(gnrc_tcp_tcb_t *tcb) xtimer_remove(&connection_timeout_timer); tcb->owner = KERNEL_PID_UNDEF; mutex_unlock(&(tcb->function_lock)); - return 0; +} + +void gnrc_tcp_abort(gnrc_tcp_tcb_t *tcb) +{ + assert(tcb != NULL); + + /* Lock the TCB for this function call */ + mutex_lock(&(tcb->function_lock)); + if (tcb->state != FSM_STATE_CLOSED) { + /* Call FSM ABORT event */ + _fsm(tcb, FSM_EVENT_CALL_ABORT, NULL, NULL, 0); + } + mutex_unlock(&(tcb->function_lock)); } int gnrc_tcp_calc_csum(const gnrc_pktsnip_t *hdr, const gnrc_pktsnip_t *pseudo_hdr) diff --git a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_fsm.c b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_fsm.c index 67daf7e391b2d95037e074ac57717da4acd0bca0..a89fd3b842881ea97e744b719a50d092ec213294 100644 --- a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_fsm.c +++ b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_fsm.c @@ -215,9 +215,7 @@ static int _transition_to(gnrc_tcp_tcb_t *tcb, fsm_state_t state) */ static int _fsm_call_open(gnrc_tcp_tcb_t *tcb) { - gnrc_pktsnip_t *out_pkt = NULL; /* Outgoing packet */ - uint16_t seq_con = 0; /* Sequence number consumption of outgoing packet */ - int ret = 0; /* Return value */ + int ret = 0; DEBUG("gnrc_tcp_fsm.c : _fsm_call_open()\n"); tcb->rcv_wnd = GNRC_TCP_DEFAULT_WINDOW; @@ -243,6 +241,8 @@ static int _fsm_call_open(gnrc_tcp_tcb_t *tcb) } /* Send SYN */ + gnrc_pktsnip_t *out_pkt = NULL; + uint16_t seq_con = 0; _pkt_build(tcb, &out_pkt, &seq_con, MSK_SYN, tcb->iss, 0, NULL, 0); _pkt_setup_retransmit(tcb, out_pkt, false); _pkt_send(tcb, out_pkt, seq_con, false); @@ -261,10 +261,8 @@ static int _fsm_call_open(gnrc_tcp_tcb_t *tcb) */ static int _fsm_call_send(gnrc_tcp_tcb_t *tcb, void *buf, size_t len) { - gnrc_pktsnip_t *out_pkt = NULL; /* Outgoing packet */ - uint16_t seq_con = 0; /* Sequence number consumption (out_pkt) */ - DEBUG("gnrc_tcp_fsm.c : _fsm_call_send()\n"); + size_t payload = (tcb->snd_una + tcb->snd_wnd) - tcb->snd_nxt; /* Check if window is open and all packets were transmitted */ @@ -275,6 +273,8 @@ static int _fsm_call_send(gnrc_tcp_tcb_t *tcb, void *buf, size_t len) payload = (payload < len) ? payload : len; /* Calculate payload size for this segment */ + gnrc_pktsnip_t *out_pkt = NULL; + uint16_t seq_con = 0; _pkt_build(tcb, &out_pkt, &seq_con, MSK_ACK, tcb->snd_nxt, tcb->rcv_nxt, buf, payload); _pkt_setup_retransmit(tcb, out_pkt, false); _pkt_send(tcb, out_pkt, seq_con, false); @@ -294,10 +294,8 @@ static int _fsm_call_send(gnrc_tcp_tcb_t *tcb, void *buf, size_t len) */ static int _fsm_call_recv(gnrc_tcp_tcb_t *tcb, void *buf, size_t len) { - gnrc_pktsnip_t *out_pkt = NULL; /* Outgoing packet */ - uint16_t seq_con = 0; /* Sequence number consumption of outgoing packet */ - DEBUG("gnrc_tcp_fsm.c : _fsm_call_recv()\n"); + if (ringbuffer_empty(&tcb->rcv_buf)) { return 0; } @@ -310,6 +308,8 @@ static int _fsm_call_recv(gnrc_tcp_tcb_t *tcb, void *buf, size_t len) tcb->rcv_wnd = ringbuffer_get_free(&(tcb->rcv_buf)); /* Send ACK to anounce window update */ + gnrc_pktsnip_t *out_pkt = NULL; + uint16_t seq_con = 0; _pkt_build(tcb, &out_pkt, &seq_con, MSK_ACK, tcb->snd_nxt, tcb->rcv_nxt, NULL, 0); _pkt_send(tcb, out_pkt, seq_con, false); } @@ -325,13 +325,14 @@ static int _fsm_call_recv(gnrc_tcp_tcb_t *tcb, void *buf, size_t len) */ static int _fsm_call_close(gnrc_tcp_tcb_t *tcb) { - gnrc_pktsnip_t *out_pkt = NULL; /* Outgoing packet */ - uint16_t seq_con = 0; /* Sequence number consumption of outgoing packet */ - DEBUG("gnrc_tcp_fsm.c : _fsm_call_close()\n"); + if (tcb->state == FSM_STATE_SYN_RCVD || tcb->state == FSM_STATE_ESTABLISHED || tcb->state == FSM_STATE_CLOSE_WAIT) { + /* Send FIN packet */ + gnrc_pktsnip_t *out_pkt = NULL; + uint16_t seq_con = 0; _pkt_build(tcb, &out_pkt, &seq_con, MSK_FIN_ACK, tcb->snd_nxt, tcb->rcv_nxt, NULL, 0); _pkt_setup_retransmit(tcb, out_pkt, false); _pkt_send(tcb, out_pkt, seq_con, false); @@ -352,13 +353,30 @@ static int _fsm_call_close(gnrc_tcp_tcb_t *tcb) /** * @brief FSM handling function for forcefull connection teardown sequence. * - * @returns -EOPNOTSUPP. Currently not implemented. + * @param[in,out] tcb TCB holding the connection information. + * + * @returns Zero on success. */ -static int _fsm_call_abort(void) +static int _fsm_call_abort(gnrc_tcp_tcb_t *tcb) { DEBUG("gnrc_tcp_fsm.c : _fsm_call_abort()\n"); - DEBUG("gnrc_tcp_fsm.c : _fsm_call_abort() : ABORT not implemented\n"); - return -EOPNOTSUPP; + + /* A reset must be sent in case the TCB state is in one of those cases */ + if (tcb->state == FSM_STATE_SYN_RCVD || tcb->state == FSM_STATE_ESTABLISHED || + tcb->state == FSM_STATE_FIN_WAIT_1 || tcb->state == FSM_STATE_FIN_WAIT_2 || + tcb->state == FSM_STATE_CLOSE_WAIT) { + + /* Send RST packet without retransmit */ + gnrc_pktsnip_t *out_pkt = NULL; + uint16_t seq_con = 0; + _pkt_build(tcb, &out_pkt, &seq_con, MSK_RST, tcb->snd_nxt, tcb->rcv_nxt, NULL, 0); + _pkt_send(tcb, out_pkt, seq_con, false); + } + + /* From here on any state must transition into CLOSED state */ + _transition_to(tcb, FSM_STATE_CLOSED); + + return 0; } /** @@ -827,7 +845,7 @@ static int _fsm_unprotected(gnrc_tcp_tcb_t *tcb, fsm_event_t event, gnrc_pktsnip ret = _fsm_call_close(tcb); break; case FSM_EVENT_CALL_ABORT : - ret = _fsm_call_abort(); + ret = _fsm_call_abort(tcb); break; case FSM_EVENT_RCVD_PKT : ret = _fsm_rcvd_pkt(tcb, in_pkt);