diff --git a/src/include/gpxe/ip6.h b/src/include/gpxe/ip6.h index 1ddba0a9..69cbd81b 100644 --- a/src/include/gpxe/ip6.h +++ b/src/include/gpxe/ip6.h @@ -11,7 +11,8 @@ /* IP6 constants */ -#define IP6_VER 6 +#define IP6_VERSION 0x6 +#define IP6_HOP_LIMIT 64 /* IP6 header */ diff --git a/src/include/gpxe/tcp.h b/src/include/gpxe/tcp.h index ca926a5c..b7f0acca 100644 --- a/src/include/gpxe/tcp.h +++ b/src/include/gpxe/tcp.h @@ -159,7 +159,6 @@ struct tcp_connection { struct list_head list; /* List of TCP connections */ struct pk_buff *tx_pkb; /* Transmit packet buffer */ struct retry_timer timer; /* Retransmission timer */ - int retransmits; /* Number of retransmits */ struct tcp_operations *tcp_op; /* Operations table for connection */ }; @@ -198,10 +197,10 @@ struct tcp_header { /** * TCP flags */ -#define TCP_RST 0x20 +#define TCP_URG 0x20 #define TCP_ACK 0x10 #define TCP_PSH 0x08 -#define TCP_URG 0x04 +#define TCP_RST 0x04 #define TCP_SYN 0x02 #define TCP_FIN 0x01 diff --git a/src/net/ipv4.c b/src/net/ipv4.c index a9635693..bfef358d 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -107,6 +107,7 @@ void del_ipv4_address ( struct net_device *netdev ) { */ static void ipv4_dump ( struct iphdr *iphdr __unused ) { +/* DBG ( "IP4 header at %p+%#zx\n", iphdr, sizeof ( *iphdr ) ); DBG ( "\tVersion = %d\n", ( iphdr->verhdrlen & IP_MASK_VER ) / 16 ); DBG ( "\tHeader length = %d\n", iphdr->verhdrlen & IP_MASK_HLEN ); @@ -120,6 +121,11 @@ static void ipv4_dump ( struct iphdr *iphdr __unused ) { ntohs ( iphdr->chksum ) ); DBG ( "\tSource = %s\n", inet_ntoa ( iphdr->src ) ); DBG ( "\tDestination = %s\n", inet_ntoa ( iphdr->dest ) ); +*/ + DBG ( "IP4 %p transmitting %p+%d ident %d protocol %d header-csum %x\n", + &ipv4_protocol, iphdr, ntohs ( iphdr->len ), ntohs ( iphdr->ident ), + iphdr->protocol, ntohs ( iphdr->chksum ) ); + DBG ( "src %s, dest %s\n", inet_ntoa ( iphdr->src ), inet_ntoa ( iphdr->dest ) ); } /** diff --git a/src/net/tcp.c b/src/net/tcp.c index 2450f45a..d63f6939 100644 --- a/src/net/tcp.c +++ b/src/net/tcp.c @@ -258,17 +258,7 @@ static const char *tcp_states[] = { * @v conn TCP connection * @v nxt_state Next TCP state */ -void tcp_trans ( struct tcp_connection *conn, int nxt_state ) { - /* Remember the last state */ - conn->tcp_lstate = conn->tcp_state; - conn->tcp_state = nxt_state; - - /* TODO: Check if this check is required */ - if ( conn->tcp_lstate == conn->tcp_state || - conn->tcp_state == TCP_INVALID ) { - conn->tcp_flags = 0; - return; - } +void tcp_set_flags ( struct tcp_connection *conn ) { /* Set the TCP flags */ switch ( conn->tcp_state ) { @@ -331,12 +321,29 @@ void tcp_trans ( struct tcp_connection *conn, int nxt_state ) { } } +void tcp_trans ( struct tcp_connection *conn, int nxt_state ) { + /* Remember the last state */ + conn->tcp_lstate = conn->tcp_state; + conn->tcp_state = nxt_state; + + printf ( "Transition from %s to %s\n", tcp_states[conn->tcp_lstate], tcp_states[conn->tcp_state] ); + + /* TODO: Check if this check is required */ + if ( conn->tcp_lstate == conn->tcp_state || + conn->tcp_state == TCP_INVALID ) { + conn->tcp_flags = 0; + return; + } + tcp_set_flags ( conn ); +} + /** * Dump TCP header * * @v tcphdr TCP header */ void tcp_dump ( struct tcp_header *tcphdr ) { +/* DBG ( "TCP header at %p+%d\n", tcphdr, sizeof ( *tcphdr ) ); DBG ( "\tSource port = %d, Destination port = %d\n", ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ) ); @@ -347,6 +354,10 @@ void tcp_dump ( struct tcp_header *tcphdr ) { ( tcphdr->flags & TCP_MASK_FLAGS ) ); DBG ( "\tAdvertised window = %ld, Checksum = %x, Urgent Pointer = %d\n", ntohs ( tcphdr->win ), tcphdr->csum, ntohs ( tcphdr->urg ) ); +*/ + DBG ( "TCP %p at %p src:%d dest:%d seq:%lld ack:%lld hlen:%hd flags:%#hx\n", + &tcp_protocol, tcphdr, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ), ntohl ( tcphdr->seq ), + ntohl ( tcphdr->ack ), ( ( tcphdr->hlen & TCP_MASK_HLEN ) / 16 ), ( tcphdr->flags & TCP_MASK_FLAGS ) ); } /** @@ -377,49 +388,64 @@ void tcp_init_conn ( struct tcp_connection *conn ) { */ void tcp_expired ( struct retry_timer *timer, int over ) { struct tcp_connection *conn; - if ( over ) { - conn = ( struct tcp_connection * ) container_of ( timer, - struct tcp_connection, timer ); - switch ( conn->tcp_state ) { - case TCP_SYN_SENT: - if ( conn->retransmits > MAX_RETRANSMITS ) { - tcp_trans ( conn, TCP_CLOSED ); - return; - } - if ( conn->tcp_lstate == TCP_CLOSED || - conn->tcp_lstate == TCP_LISTEN ) { - goto send_tcp_nomsg; - } - return; - case TCP_SYN_RCVD: - tcp_trans ( conn, TCP_CLOSED ); - if ( conn->tcp_lstate == TCP_LISTEN || - conn->tcp_lstate == TCP_SYN_SENT ) { - goto send_tcp_nomsg; - } - return; - case TCP_ESTABLISHED: - break; - case TCP_FIN_WAIT_1: - case TCP_FIN_WAIT_2: - case TCP_CLOSE_WAIT: - goto send_tcp_nomsg; - case TCP_CLOSING: - case TCP_LAST_ACK: - return; - case TCP_TIME_WAIT: + conn = ( struct tcp_connection * ) container_of ( timer, + struct tcp_connection, timer ); + DBG ( "Timer expired in %s\n", tcp_states[conn->tcp_state] ); + switch ( conn->tcp_state ) { + case TCP_SYN_SENT: + if ( over ) { tcp_trans ( conn, TCP_CLOSED ); + stop_timer ( &conn->timer ); + DBG ( "Timeout! Connection closed\n" ); return; } - /* Retransmit the data */ - tcp_senddata ( conn ); - conn->retransmits++; + goto send_tcp_nomsg; + case TCP_SYN_RCVD: + if ( over ) { + tcp_trans ( conn, TCP_CLOSED ); + stop_timer ( &conn->timer ); + goto send_tcp_nomsg; + } + goto send_tcp_nomsg; + case TCP_ESTABLISHED: + if ( conn->tcp_lstate == TCP_SYN_SENT ) { + goto send_tcp_nomsg; + } + break; + case TCP_CLOSE_WAIT: + if ( conn->tcp_lstate == TCP_ESTABLISHED ) { + goto send_tcp_nomsg; + } + break; + case TCP_FIN_WAIT_1: + case TCP_FIN_WAIT_2: + goto send_tcp_nomsg; + case TCP_CLOSING: + case TCP_LAST_ACK: + if ( conn->tcp_lstate == TCP_CLOSE_WAIT ) { + goto send_tcp_nomsg; + } return; - - send_tcp_nomsg: - tcp_send ( conn, TCP_NOMSG, TCP_NOMSG_LEN ); + case TCP_TIME_WAIT: + tcp_trans ( conn, TCP_CLOSED ); + stop_timer ( &conn->timer ); return; } + /* Retransmit the data */ + tcp_set_flags ( conn ); + tcp_senddata ( conn ); + return; + + send_tcp_nomsg: +// free_pkb ( conn->tx_pkb ); + conn->tx_pkb = alloc_pkb ( MIN_PKB_LEN ); + pkb_reserve ( conn->tx_pkb, MAX_HDR_LEN ); + tcp_set_flags ( conn ); + int rc; + if ( ( rc = tcp_send ( conn, TCP_NOMSG, TCP_NOMSG_LEN ) ) != 0 ) { + DBG ( "Error sending TCP message (rc = %d)\n", rc ); + } + return; } /** @@ -634,7 +660,13 @@ int tcp_send ( struct tcp_connection *conn, const void *data, size_t len ) { tcp_dump ( tcphdr ); /* Start the timer */ - start_timer ( &conn->timer ); + if ( ( conn->tcp_state == TCP_ESTABLISHED && conn->tcp_lstate == TCP_SYN_SENT ) || + ( conn->tcp_state == TCP_LISTEN && conn->tcp_lstate == TCP_SYN_RCVD ) || + ( conn->tcp_state == TCP_CLOSED && conn->tcp_lstate == TCP_SYN_RCVD ) ) { + // Don't start the timer + } else { + start_timer ( &conn->timer ); + } /* Transmit packet */ return tcpip_tx ( pkb, &tcp_protocol, peer ); @@ -653,6 +685,7 @@ static int tcp_rx ( struct pk_buff *pkb, struct tcp_header *tcphdr; uint32_t acked, toack; int hlen; + int add = 0; /* Sanity check */ if ( pkb_len ( pkb ) < sizeof ( *tcphdr ) ) { @@ -660,14 +693,21 @@ static int tcp_rx ( struct pk_buff *pkb, return -EINVAL; } + /* Process TCP header */ tcphdr = pkb->data; + tcp_dump ( tcphdr ); /* Verify header length */ hlen = ( ( tcphdr->hlen & TCP_MASK_HLEN ) / 16 ) * 4; if ( hlen != sizeof ( *tcphdr ) ) { - DBG ( "Bad header length (%d bytes)\n", hlen ); - return -EINVAL; + if ( hlen == sizeof ( *tcphdr ) + 4 ) { + DBG ( "TCP options sent\n" ); + add = 4; + } else { + DBG ( "Bad header length (%d bytes)\n", hlen ); + return -EINVAL; + } } /* TODO: Verify checksum */ @@ -685,7 +725,6 @@ static int tcp_rx ( struct pk_buff *pkb, found_conn: /* Stop the timer */ stop_timer ( &conn->timer ); - conn->retransmits = 0; /* Set the advertised window */ conn->snd_win = tcphdr->win; @@ -729,6 +768,7 @@ static int tcp_rx ( struct pk_buff *pkb, */ conn->snd_una = ntohl ( tcphdr->ack ); conn->tcp_op->connected ( conn ); + tcp_senddata ( conn ); } else { tcp_trans ( conn, TCP_SYN_RCVD ); out_flags |= TCP_SYN; @@ -752,6 +792,7 @@ static int tcp_rx ( struct pk_buff *pkb, */ conn->snd_una = tcphdr->ack - 1; conn->tcp_op->connected ( conn ); + tcp_senddata ( conn ); return 0; } /* Unexpected packet */ @@ -799,6 +840,7 @@ static int tcp_rx ( struct pk_buff *pkb, case TCP_CLOSING: if ( tcphdr->flags & TCP_ACK ) { tcp_trans ( conn, TCP_TIME_WAIT ); + start_timer ( &conn->timer ); return 0; } /* Unexpected packet */ @@ -831,7 +873,7 @@ static int tcp_rx ( struct pk_buff *pkb, /* Check if expected sequence number */ if ( conn->rcv_nxt == ntohl ( tcphdr->seq ) ) { conn->rcv_nxt += toack; - conn->tcp_op->newdata ( conn, pkb->data + sizeof ( *tcphdr ), toack ); + conn->tcp_op->newdata ( conn, pkb->data + sizeof ( *tcphdr ) + add, toack ); } /* Acknowledge new data */ @@ -870,8 +912,9 @@ static int tcp_rx ( struct pk_buff *pkb, return 0; unexpected: - DBG ( "Unexpected packet received in %d state with flags = %hd\n", - conn->tcp_state, tcphdr->flags & TCP_MASK_FLAGS ); + DBG ( "Unexpected packet received in %s with flags = %#hx\n", + tcp_states[conn->tcp_state], tcphdr->flags & TCP_MASK_FLAGS ); + tcp_close ( conn ); free_pkb ( conn->tx_pkb ); return -EINVAL; }