summaryrefslogtreecommitdiffstats
path: root/src/net/tcp.c
diff options
context:
space:
mode:
authorMichael Brown2007-01-03 23:21:59 +0100
committerMichael Brown2007-01-03 23:21:59 +0100
commitb0daa99dceafca86911a8986f85d187c5bf27cf7 (patch)
tree97cfdeb855b6d84e3b1fd51e6b26657a65c3d91a /src/net/tcp.c
parentAccept RST on received packets (diff)
downloadipxe-b0daa99dceafca86911a8986f85d187c5bf27cf7.tar.gz
ipxe-b0daa99dceafca86911a8986f85d187c5bf27cf7.tar.xz
ipxe-b0daa99dceafca86911a8986f85d187c5bf27cf7.zip
Send RST packets when we get a non-matching connection, or receive an
out-of-range ACK.
Diffstat (limited to 'src/net/tcp.c')
-rw-r--r--src/net/tcp.c60
1 files changed, 51 insertions, 9 deletions
diff --git a/src/net/tcp.c b/src/net/tcp.c
index 579495c3..cc556284 100644
--- a/src/net/tcp.c
+++ b/src/net/tcp.c
@@ -426,6 +426,49 @@ static void tcp_expired ( struct retry_timer *timer, int over ) {
}
/**
+ * Send RST response to incoming packet
+ *
+ * @v in_tcphdr TCP header of incoming packet
+ * @ret rc Return status code
+ */
+static int tcp_send_reset ( struct tcp_connection *conn,
+ struct tcp_header *in_tcphdr ) {
+ struct pk_buff *pkb;
+ struct tcp_header *tcphdr;
+
+ /* Allocate space for dataless TX buffer */
+ pkb = alloc_pkb ( MAX_HDR_LEN );
+ if ( ! pkb ) {
+ DBGC ( conn, "TCP %p could not allocate data buffer\n", conn );
+ return -ENOMEM;
+ }
+ pkb_reserve ( pkb, MAX_HDR_LEN );
+
+ /* Construct RST response */
+ tcphdr = pkb_push ( pkb, sizeof ( *tcphdr ) );
+ memset ( tcphdr, 0, sizeof ( *tcphdr ) );
+ tcphdr->src = in_tcphdr->dest;
+ tcphdr->dest = in_tcphdr->src;
+ tcphdr->seq = in_tcphdr->ack;
+ tcphdr->ack = in_tcphdr->seq;
+ tcphdr->hlen = ( ( sizeof ( *tcphdr ) / 4 ) << 4 );
+ tcphdr->flags = ( TCP_RST | TCP_ACK );
+ tcphdr->win = htons ( TCP_WINDOW_SIZE );
+ tcphdr->csum = tcpip_chksum ( pkb->data, pkb_len ( pkb ) );
+
+ /* Dump header */
+ DBGC ( conn, "TCP %p TX %d->%d %08lx..%08lx %08lx %4zd",
+ conn, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ),
+ ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) ),
+ ntohl ( tcphdr->ack ), 0 );
+ tcp_dump_flags ( conn, tcphdr->flags );
+ DBGC ( conn, "\n" );
+
+ /* Transmit packet */
+ return tcpip_tx ( pkb, &tcp_protocol, &conn->peer, &tcphdr->csum );
+}
+
+/**
* Identify TCP connection by local port number
*
* @v local_port Local port (in network-endian order)
@@ -700,18 +743,20 @@ static int tcp_rx ( struct pk_buff *pkb,
tcp_dump_flags ( conn, tcphdr->flags );
DBGC ( conn, "\n" );
- /* If no connection was found, create dummy connection for
- * sending RST
- */
-#warning "Handle non-matched connections"
+ /* If no connection was found, send RST */
if ( ! conn ) {
+ tcp_send_reset ( conn, tcphdr );
rc = -ENOTCONN;
goto done;
}
/* Handle ACK, if present */
- if ( flags & TCP_ACK )
- tcp_rx_ack ( conn, ack, win );
+ if ( flags & TCP_ACK ) {
+ if ( ( rc = tcp_rx_ack ( conn, ack, win ) ) != 0 ) {
+ tcp_send_reset ( conn, tcphdr );
+ goto done;
+ }
+ }
/* Handle SYN, if present */
if ( flags & TCP_SYN ) {
@@ -773,9 +818,6 @@ static int tcp_bind ( struct tcp_connection *conn, uint16_t local_port ) {
struct tcp_connection *existing;
static uint16_t try_port = 1024;
-#warning "Fix the port re-use bug"
- try_port = random();
-
/* If no port specified, find the first available port */
if ( ! local_port ) {
for ( ; try_port ; try_port++ ) {