|
@@ -17,6 +17,7 @@
|
17
|
17
|
*/
|
18
|
18
|
|
19
|
19
|
static void tcp_expired ( struct retry_timer *timer, int over );
|
|
20
|
+static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send );
|
20
|
21
|
|
21
|
22
|
/**
|
22
|
23
|
* A TCP connection
|
|
@@ -211,6 +212,35 @@ static void tcp_disassociate ( struct tcp_connection *conn ) {
|
211
|
212
|
}
|
212
|
213
|
}
|
213
|
214
|
|
|
215
|
+/**
|
|
216
|
+ * Abort TCP connection
|
|
217
|
+ *
|
|
218
|
+ * @v conn TCP connection
|
|
219
|
+ * @v send_rst Send a RST after closing
|
|
220
|
+ * @v rc Reason code
|
|
221
|
+ */
|
|
222
|
+static void tcp_abort ( struct tcp_connection *conn, int send_rst, int rc ) {
|
|
223
|
+ struct tcp_application *app = conn->app;
|
|
224
|
+
|
|
225
|
+ /* Transition to CLOSED */
|
|
226
|
+ conn->tcp_state = TCP_CLOSED;
|
|
227
|
+ tcp_dump_state ( conn );
|
|
228
|
+
|
|
229
|
+ /* Send RST if requested to do so */
|
|
230
|
+ if ( send_rst )
|
|
231
|
+ tcp_senddata_conn ( conn, 1 );
|
|
232
|
+
|
|
233
|
+ /* Break association between application and connection */
|
|
234
|
+ tcp_disassociate ( conn );
|
|
235
|
+
|
|
236
|
+ /* Free the connection */
|
|
237
|
+ free_tcp ( conn );
|
|
238
|
+
|
|
239
|
+ /* Notify application */
|
|
240
|
+ if ( app && app->tcp_op->closed )
|
|
241
|
+ app->tcp_op->closed ( app, rc );
|
|
242
|
+}
|
|
243
|
+
|
214
|
244
|
/**
|
215
|
245
|
* Transmit any outstanding data
|
216
|
246
|
*
|
|
@@ -234,6 +264,7 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) {
|
234
|
264
|
unsigned int flags;
|
235
|
265
|
size_t len;
|
236
|
266
|
size_t seq_len;
|
|
267
|
+ int rc;
|
237
|
268
|
|
238
|
269
|
/* Allocate space to the TX buffer */
|
239
|
270
|
pkb = alloc_pkb ( MAX_PKB_LEN );
|
|
@@ -318,8 +349,23 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) {
|
318
|
349
|
DBGC ( conn, "\n" );
|
319
|
350
|
|
320
|
351
|
/* Transmit packet */
|
321
|
|
- return tcpip_tx ( pkb, &tcp_protocol, &conn->peer,
|
322
|
|
- NULL, &tcphdr->csum );
|
|
352
|
+ rc = tcpip_tx ( pkb, &tcp_protocol, &conn->peer, NULL, &tcphdr->csum );
|
|
353
|
+
|
|
354
|
+ /* If we got -ENETUNREACH, kill the connection immediately
|
|
355
|
+ * because there is no point retrying. This isn't strictly
|
|
356
|
+ * necessary (since we will eventually time out anyway), but
|
|
357
|
+ * it avoids irritating needless delays. Don't do this for
|
|
358
|
+ * RST packets transmitted on connection abort, to avoid a
|
|
359
|
+ * potential infinite loop.
|
|
360
|
+ */
|
|
361
|
+ if ( ( ! ( conn->tcp_state & TCP_STATE_SENT ( TCP_RST ) ) ) &&
|
|
362
|
+ ( rc == -ENETUNREACH ) ) {
|
|
363
|
+ DBGC ( conn, "TCP %p aborting after TX failed: %s\n",
|
|
364
|
+ conn, strerror ( rc ) );
|
|
365
|
+ tcp_abort ( conn, 0, rc );
|
|
366
|
+ }
|
|
367
|
+
|
|
368
|
+ return rc;
|
323
|
369
|
}
|
324
|
370
|
|
325
|
371
|
/**
|
|
@@ -392,7 +438,6 @@ int tcp_send ( struct tcp_application *app, const void *data, size_t len ) {
|
392
|
438
|
static void tcp_expired ( struct retry_timer *timer, int over ) {
|
393
|
439
|
struct tcp_connection *conn =
|
394
|
440
|
container_of ( timer, struct tcp_connection, timer );
|
395
|
|
- struct tcp_application *app = conn->app;
|
396
|
441
|
int graceful_close = TCP_CLOSED_GRACEFULLY ( conn->tcp_state );
|
397
|
442
|
|
398
|
443
|
DBGC ( conn, "TCP %p timer %s in %s\n", conn,
|
|
@@ -406,29 +451,12 @@ static void tcp_expired ( struct retry_timer *timer, int over ) {
|
406
|
451
|
( conn->tcp_state == TCP_CLOSE_WAIT ) ||
|
407
|
452
|
( conn->tcp_state == TCP_CLOSING_OR_LAST_ACK ) );
|
408
|
453
|
|
409
|
|
- /* If we have finally timed out and given up, or if this is
|
410
|
|
- * the result of a graceful close, terminate the connection
|
411
|
|
- */
|
412
|
454
|
if ( over || graceful_close ) {
|
413
|
|
-
|
414
|
|
- /* Transition to CLOSED */
|
415
|
|
- conn->tcp_state = TCP_CLOSED;
|
416
|
|
- tcp_dump_state ( conn );
|
417
|
|
-
|
418
|
|
- /* If we haven't closed gracefully, send a RST */
|
419
|
|
- if ( ! graceful_close )
|
420
|
|
- tcp_senddata_conn ( conn, 1 );
|
421
|
|
-
|
422
|
|
- /* Break association between application and connection */
|
423
|
|
- tcp_disassociate ( conn );
|
424
|
|
-
|
425
|
|
- /* Free the connection */
|
426
|
|
- free_tcp ( conn );
|
427
|
|
-
|
428
|
|
- /* Notify application */
|
429
|
|
- if ( app && app->tcp_op->closed )
|
430
|
|
- app->tcp_op->closed ( app, -ETIMEDOUT );
|
431
|
|
-
|
|
455
|
+ /* If we have finally timed out and given up, or if
|
|
456
|
+ * this is the result of a graceful close, terminate
|
|
457
|
+ * the connection
|
|
458
|
+ */
|
|
459
|
+ tcp_abort ( conn, 1, -ETIMEDOUT );
|
432
|
460
|
} else {
|
433
|
461
|
/* Otherwise, retransmit the packet */
|
434
|
462
|
tcp_senddata_conn ( conn, 0 );
|
|
@@ -658,7 +686,6 @@ static int tcp_rx_fin ( struct tcp_connection *conn, uint32_t seq ) {
|
658
|
686
|
* @ret rc Return status code
|
659
|
687
|
*/
|
660
|
688
|
static int tcp_rx_rst ( struct tcp_connection *conn, uint32_t seq ) {
|
661
|
|
- struct tcp_application *app = conn->app;
|
662
|
689
|
|
663
|
690
|
/* Accept RST only if it falls within the window. If we have
|
664
|
691
|
* not yet received a SYN, then we have no window to test
|
|
@@ -673,19 +700,8 @@ static int tcp_rx_rst ( struct tcp_connection *conn, uint32_t seq ) {
|
673
|
700
|
return 0;
|
674
|
701
|
}
|
675
|
702
|
|
676
|
|
- /* Transition to CLOSED */
|
677
|
|
- conn->tcp_state = TCP_CLOSED;
|
678
|
|
- tcp_dump_state ( conn );
|
679
|
|
-
|
680
|
|
- /* Break association between application and connection */
|
681
|
|
- tcp_disassociate ( conn );
|
682
|
|
-
|
683
|
|
- /* Free the connection */
|
684
|
|
- free_tcp ( conn );
|
685
|
|
-
|
686
|
|
- /* Notify application */
|
687
|
|
- if ( app && app->tcp_op->closed )
|
688
|
|
- app->tcp_op->closed ( app, -ECONNRESET );
|
|
703
|
+ /* Abort connection without sending a RST */
|
|
704
|
+ tcp_abort ( conn, 0, -ECONNRESET );
|
689
|
705
|
|
690
|
706
|
return -ECONNRESET;
|
691
|
707
|
}
|