Removed some bugs in TCP
authorNikhil Chandru Rao <nikhilcrao@users.sourceforge.net>
Tue, 8 Aug 2006 03:42:30 +0000 (03:42 +0000)
committerNikhil Chandru Rao <nikhilcrao@users.sourceforge.net>
Tue, 8 Aug 2006 03:42:30 +0000 (03:42 +0000)
src/include/gpxe/ip6.h
src/include/gpxe/tcp.h
src/net/ipv4.c
src/net/tcp.c

index 1ddba0a..69cbd81 100644 (file)
@@ -11,7 +11,8 @@
 
 /* IP6 constants */
 
-#define IP6_VER                6
+#define IP6_VERSION    0x6
+#define IP6_HOP_LIMIT  64
 
 /* IP6 header */
 
index ca926a5..b7f0acc 100644 (file)
@@ -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
 
index a963569..bfef358 100644 (file)
@@ -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 ) );
 }
 
 /**
index 2450f45..d63f693 100644 (file)
@@ -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:
+       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 );
-                       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:
+                       stop_timer ( &conn->timer );
+                       DBG ( "Timeout! Connection closed\n" );
                        return;
-               case TCP_TIME_WAIT:
+               }
+               goto send_tcp_nomsg;
+       case TCP_SYN_RCVD:
+               if ( over ) {
                        tcp_trans ( conn, TCP_CLOSED );
-                       return;
+                       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;
                }
-               /* Retransmit the data */
-               tcp_senddata ( conn );
-               conn->retransmits++;
                return;
+       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:
-               tcp_send ( conn, TCP_NOMSG, TCP_NOMSG_LEN );
-               return;
+//     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;
 }