|
@@ -113,6 +113,8 @@ struct tcp_connection {
|
113
|
113
|
struct process process;
|
114
|
114
|
/** Retransmission timer */
|
115
|
115
|
struct retry_timer timer;
|
|
116
|
+ /** Keepalive timer */
|
|
117
|
+ struct retry_timer keepalive;
|
116
|
118
|
/** Shutdown (TIME_WAIT) timer */
|
117
|
119
|
struct retry_timer wait;
|
118
|
120
|
|
|
@@ -177,6 +179,7 @@ static struct profiler tcp_xfer_profiler __profiler = { .name = "tcp.xfer" };
|
177
|
179
|
static struct process_descriptor tcp_process_desc;
|
178
|
180
|
static struct interface_descriptor tcp_xfer_desc;
|
179
|
181
|
static void tcp_expired ( struct retry_timer *timer, int over );
|
|
182
|
+static void tcp_keepalive_expired ( struct retry_timer *timer, int over );
|
180
|
183
|
static void tcp_wait_expired ( struct retry_timer *timer, int over );
|
181
|
184
|
static struct tcp_connection * tcp_demux ( unsigned int local_port );
|
182
|
185
|
static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack,
|
|
@@ -284,6 +287,7 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer,
|
284
|
287
|
intf_init ( &tcp->xfer, &tcp_xfer_desc, &tcp->refcnt );
|
285
|
288
|
process_init_stopped ( &tcp->process, &tcp_process_desc, &tcp->refcnt );
|
286
|
289
|
timer_init ( &tcp->timer, tcp_expired, &tcp->refcnt );
|
|
290
|
+ timer_init ( &tcp->keepalive, tcp_keepalive_expired, &tcp->refcnt );
|
287
|
291
|
timer_init ( &tcp->wait, tcp_wait_expired, &tcp->refcnt );
|
288
|
292
|
tcp->prev_tcp_state = TCP_CLOSED;
|
289
|
293
|
tcp->tcp_state = TCP_STATE_SENT ( TCP_SYN );
|
|
@@ -380,6 +384,7 @@ static void tcp_close ( struct tcp_connection *tcp, int rc ) {
|
380
|
384
|
/* Remove from list and drop reference */
|
381
|
385
|
process_del ( &tcp->process );
|
382
|
386
|
stop_timer ( &tcp->timer );
|
|
387
|
+ stop_timer ( &tcp->keepalive );
|
383
|
388
|
stop_timer ( &tcp->wait );
|
384
|
389
|
list_del ( &tcp->list );
|
385
|
390
|
ref_put ( &tcp->refcnt );
|
|
@@ -394,6 +399,9 @@ static void tcp_close ( struct tcp_connection *tcp, int rc ) {
|
394
|
399
|
if ( ! ( tcp->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) )
|
395
|
400
|
tcp_rx_ack ( tcp, ( tcp->snd_seq + 1 ), 0 );
|
396
|
401
|
|
|
402
|
+ /* Stop keepalive timer */
|
|
403
|
+ stop_timer ( &tcp->keepalive );
|
|
404
|
+
|
397
|
405
|
/* If we have no data remaining to send, start sending FIN */
|
398
|
406
|
if ( list_empty ( &tcp->tx_queue ) &&
|
399
|
407
|
! ( tcp->tcp_state & TCP_STATE_SENT ( TCP_FIN ) ) ) {
|
|
@@ -801,6 +809,32 @@ static void tcp_expired ( struct retry_timer *timer, int over ) {
|
801
|
809
|
}
|
802
|
810
|
}
|
803
|
811
|
|
|
812
|
+/**
|
|
813
|
+ * Keepalive timer expired
|
|
814
|
+ *
|
|
815
|
+ * @v timer Keepalive timer
|
|
816
|
+ * @v over Failure indicator
|
|
817
|
+ */
|
|
818
|
+static void tcp_keepalive_expired ( struct retry_timer *timer,
|
|
819
|
+ int over __unused ) {
|
|
820
|
+ struct tcp_connection *tcp =
|
|
821
|
+ container_of ( timer, struct tcp_connection, keepalive );
|
|
822
|
+
|
|
823
|
+ DBGC ( tcp, "TCP %p sending keepalive\n", tcp );
|
|
824
|
+
|
|
825
|
+ /* Reset keepalive timer */
|
|
826
|
+ start_timer_fixed ( &tcp->keepalive, TCP_KEEPALIVE_DELAY );
|
|
827
|
+
|
|
828
|
+ /* Send keepalive. We do this only to preserve or restore
|
|
829
|
+ * state in intermediate devices (e.g. firewall NAT tables);
|
|
830
|
+ * we don't actually care about eliciting a response to verify
|
|
831
|
+ * that the peer is still alive. We therefore send just a
|
|
832
|
+ * pure ACK, to keep our transmit path simple.
|
|
833
|
+ */
|
|
834
|
+ tcp->flags |= TCP_ACK_PENDING;
|
|
835
|
+ tcp_xmit ( tcp );
|
|
836
|
+}
|
|
837
|
+
|
804
|
838
|
/**
|
805
|
839
|
* Shutdown timer expired
|
806
|
840
|
*
|
|
@@ -1105,6 +1139,10 @@ static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack,
|
1105
|
1139
|
/* Update window size */
|
1106
|
1140
|
tcp->snd_win = win;
|
1107
|
1141
|
|
|
1142
|
+ /* Hold off (or start) the keepalive timer, if applicable */
|
|
1143
|
+ if ( ! ( tcp->tcp_state & TCP_STATE_SENT ( TCP_FIN ) ) )
|
|
1144
|
+ start_timer_fixed ( &tcp->keepalive, TCP_KEEPALIVE_DELAY );
|
|
1145
|
+
|
1108
|
1146
|
/* Ignore ACKs that don't actually acknowledge any new data.
|
1109
|
1147
|
* (In particular, do not stop the retransmission timer; this
|
1110
|
1148
|
* avoids creating a sorceror's apprentice syndrome when a
|