Make TCP give up immediately when it receives -ENETUNREACH from

tcpip_tx().  This avoids the irritating wait when you accidentally type
"kernel pxelinux.0" before bringing up the network interface.

Add ENETUNREACH to strerror()'s list.
pull/1/head
Michael Brown 2007-01-14 16:47:03 +00:00
parent c953c1a1c3
commit 76aa9ad07d
2 changed files with 65 additions and 46 deletions

View File

@ -55,10 +55,13 @@ const char * strerror ( int errno ) {
} }
/** The most common errors */ /** The most common errors */
struct errortab enoerr __errortab = { 0, "No error" }; struct errortab common_errors[] __errortab = {
struct errortab enoem __errortab = { ENOMEM, "Out of memory" }; { 0, "No error" },
struct errortab einval __errortab = { EINVAL, "Invalid argument" }; { ENOMEM, "Out of memory" },
struct errortab enospc __errortab = { ENOSPC, "No space left on device" }; { EINVAL, "Invalid argument" },
struct errortab eio __errortab = { EIO, "Input/output error" }; { ENOSPC, "No space left on device" },
struct errortab eacces __errortab = { EACCES, "Permission denied" }; { EIO, "Input/output error" },
struct errortab enoent __errortab = { ENOENT, "File not found" }; { EACCES, "Permission denied" },
{ ENOENT, "File not found" },
{ ENETUNREACH, "Network unreachable" },
};

View File

@ -17,6 +17,7 @@
*/ */
static void tcp_expired ( struct retry_timer *timer, int over ); static void tcp_expired ( struct retry_timer *timer, int over );
static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send );
/** /**
* A TCP connection * A TCP connection
@ -211,6 +212,35 @@ static void tcp_disassociate ( struct tcp_connection *conn ) {
} }
} }
/**
* Abort TCP connection
*
* @v conn TCP connection
* @v send_rst Send a RST after closing
* @v rc Reason code
*/
static void tcp_abort ( struct tcp_connection *conn, int send_rst, int rc ) {
struct tcp_application *app = conn->app;
/* Transition to CLOSED */
conn->tcp_state = TCP_CLOSED;
tcp_dump_state ( conn );
/* Send RST if requested to do so */
if ( send_rst )
tcp_senddata_conn ( conn, 1 );
/* Break association between application and connection */
tcp_disassociate ( conn );
/* Free the connection */
free_tcp ( conn );
/* Notify application */
if ( app && app->tcp_op->closed )
app->tcp_op->closed ( app, rc );
}
/** /**
* Transmit any outstanding data * Transmit any outstanding data
* *
@ -234,6 +264,7 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) {
unsigned int flags; unsigned int flags;
size_t len; size_t len;
size_t seq_len; size_t seq_len;
int rc;
/* Allocate space to the TX buffer */ /* Allocate space to the TX buffer */
pkb = alloc_pkb ( MAX_PKB_LEN ); pkb = alloc_pkb ( MAX_PKB_LEN );
@ -318,8 +349,23 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) {
DBGC ( conn, "\n" ); DBGC ( conn, "\n" );
/* Transmit packet */ /* Transmit packet */
return tcpip_tx ( pkb, &tcp_protocol, &conn->peer, rc = tcpip_tx ( pkb, &tcp_protocol, &conn->peer, NULL, &tcphdr->csum );
NULL, &tcphdr->csum );
/* If we got -ENETUNREACH, kill the connection immediately
* because there is no point retrying. This isn't strictly
* necessary (since we will eventually time out anyway), but
* it avoids irritating needless delays. Don't do this for
* RST packets transmitted on connection abort, to avoid a
* potential infinite loop.
*/
if ( ( ! ( conn->tcp_state & TCP_STATE_SENT ( TCP_RST ) ) ) &&
( rc == -ENETUNREACH ) ) {
DBGC ( conn, "TCP %p aborting after TX failed: %s\n",
conn, strerror ( rc ) );
tcp_abort ( conn, 0, rc );
}
return rc;
} }
/** /**
@ -392,7 +438,6 @@ int tcp_send ( struct tcp_application *app, const void *data, size_t len ) {
static void tcp_expired ( struct retry_timer *timer, int over ) { static void tcp_expired ( struct retry_timer *timer, int over ) {
struct tcp_connection *conn = struct tcp_connection *conn =
container_of ( timer, struct tcp_connection, timer ); container_of ( timer, struct tcp_connection, timer );
struct tcp_application *app = conn->app;
int graceful_close = TCP_CLOSED_GRACEFULLY ( conn->tcp_state ); int graceful_close = TCP_CLOSED_GRACEFULLY ( conn->tcp_state );
DBGC ( conn, "TCP %p timer %s in %s\n", conn, DBGC ( conn, "TCP %p timer %s in %s\n", conn,
@ -406,29 +451,12 @@ static void tcp_expired ( struct retry_timer *timer, int over ) {
( conn->tcp_state == TCP_CLOSE_WAIT ) || ( conn->tcp_state == TCP_CLOSE_WAIT ) ||
( conn->tcp_state == TCP_CLOSING_OR_LAST_ACK ) ); ( conn->tcp_state == TCP_CLOSING_OR_LAST_ACK ) );
/* If we have finally timed out and given up, or if this is
* the result of a graceful close, terminate the connection
*/
if ( over || graceful_close ) { if ( over || graceful_close ) {
/* If we have finally timed out and given up, or if
/* Transition to CLOSED */ * this is the result of a graceful close, terminate
conn->tcp_state = TCP_CLOSED; * the connection
tcp_dump_state ( conn ); */
tcp_abort ( conn, 1, -ETIMEDOUT );
/* If we haven't closed gracefully, send a RST */
if ( ! graceful_close )
tcp_senddata_conn ( conn, 1 );
/* Break association between application and connection */
tcp_disassociate ( conn );
/* Free the connection */
free_tcp ( conn );
/* Notify application */
if ( app && app->tcp_op->closed )
app->tcp_op->closed ( app, -ETIMEDOUT );
} else { } else {
/* Otherwise, retransmit the packet */ /* Otherwise, retransmit the packet */
tcp_senddata_conn ( conn, 0 ); tcp_senddata_conn ( conn, 0 );
@ -658,7 +686,6 @@ static int tcp_rx_fin ( struct tcp_connection *conn, uint32_t seq ) {
* @ret rc Return status code * @ret rc Return status code
*/ */
static int tcp_rx_rst ( struct tcp_connection *conn, uint32_t seq ) { static int tcp_rx_rst ( struct tcp_connection *conn, uint32_t seq ) {
struct tcp_application *app = conn->app;
/* Accept RST only if it falls within the window. If we have /* Accept RST only if it falls within the window. If we have
* not yet received a SYN, then we have no window to test * 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 ) {
return 0; return 0;
} }
/* Transition to CLOSED */ /* Abort connection without sending a RST */
conn->tcp_state = TCP_CLOSED; tcp_abort ( conn, 0, -ECONNRESET );
tcp_dump_state ( conn );
/* Break association between application and connection */
tcp_disassociate ( conn );
/* Free the connection */
free_tcp ( conn );
/* Notify application */
if ( app && app->tcp_op->closed )
app->tcp_op->closed ( app, -ECONNRESET );
return -ECONNRESET; return -ECONNRESET;
} }