merge
authorGustavo J. A. M. Carneiro <gjc@inescporto.pt>
Mon, 08 Sep 2008 12:35:08 +0100
changeset 3649 c1a2ee633ab5
parent 3648 f912b24ddf2d (current diff)
parent 3646 2b2f692044d8 (diff)
child 3650 516c4f22d251
merge
examples/tcp-errors.cc
src/simulator/wscript
--- a/CHANGES.html	Mon Sep 08 12:19:46 2008 +0100
+++ b/CHANGES.html	Mon Sep 08 12:35:08 2008 +0100
@@ -217,6 +217,63 @@
 
 <h2>changed behavior:</h2>
 <ul>
+
+<li>07-09-2008; changeset 
+<a href="http://code.nsnam.org/ns-3-dev/rev/5d836ab1523b">5d836ab1523b</a></li>
+<ul>
+<li>
+Implement a finite receive buffer for TCP<br>
+The native TCP model in TcpSocketImpl did not support a finite receive buffer.
+This changeset adds the following functionality in this regard:
+<ul>
+<li>
+Being able to set the receiver buffer size through the attributes system.
+</li>
+<li>
+This receiver buffer size is now correctly exported in the TCP header as the
+advertised window.  Prior to this changeset, the TCP header advertised window
+was set to the maximum size of 2^16 bytes.
+window
+</li>
+<li>
+The aforementioned window size is correctly used for flow control, i.e. the
+sending TCP will not send more data than available space in the receiver's
+buffer.
+</li>
+<li>
+In the case of a receiver window collapse, when a advertised zero-window
+packet is received, the sender enters the persist probing state in which
+it sends probe packets with one payload byte at exponentially backed-off
+intervals up to 60s.  The reciever will continue to send advertised 
+zero-window ACKs of the old data so long as the receiver buffer remains full.
+When the receiver window clears up due to an application read, the TCP
+will finally ACK the probe byte, and update its advertised window appropriately.
+</li>
+</ul>
+ 
+See 
+<a href="http://www.nsnam.org/bugzilla/show_bug.cgi?id=239"> bug 239 </a> for
+more.
+</li>
+</ul>
+</li>
+
+<li>07-09-2008; changeset 
+<a href="http://code.nsnam.org/ns-3-dev/rev/7afa66c2b291">7afa66c2b291</a></li>
+<ul>
+<li>
+Add correct FIN exchange behavior during TCP closedown<br>
+The behavior of the native TcpSocketImpl TCP model was such that the final
+FIN exchange was not correct, i.e. calling Socket::Close didn't send a FIN
+packet, and even if it had, the ACK never came back, and even if it had, the
+ACK would have incorrect sequence number.  All these various problems have been
+addressed by this changeset.  See 
+<a href="http://www.nsnam.org/bugzilla/show_bug.cgi?id=242"> bug 242 </a> for
+more.
+</li>
+</ul>
+</li>
+
 <li> 28-07-2008; changeset 
 <a href="http://code.nsnam.org/ns-3-dev/rev/6f68f1044df1">6f68f1044df1</a>
 <ul>
--- a/examples/tcp-errors.cc	Mon Sep 08 12:19:46 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,150 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-//
-// Network topology
-//
-//           10Mb/s, 10ms       10Mb/s, 10ms
-//       n0-----------------n1-----------------n2
-//
-//
-// - CBR traffic for 1000 seconds
-// - Tracing of queues and packet receptions to file 
-//   "tcp-large-transfer.tr"
-// - pcap traces also generated in the following files
-//   "tcp-large-transfer-$n-$i.pcap" where n and i represent node and interface
-// numbers respectively
-//  Usage (e.g.): ./waf --run tcp-large-transfer
-
-
-#include <ctype.h>
-#include <iostream>
-#include <fstream>
-#include <string>
-#include <cassert>
-
-#include "ns3/core-module.h"
-#include "ns3/common-module.h"
-#include "ns3/helper-module.h"
-#include "ns3/node-module.h"
-#include "ns3/global-route-manager.h"
-#include "ns3/simulator-module.h"
-
-using namespace ns3;
-
-NS_LOG_COMPONENT_DEFINE ("TcpErrors");
-
-int main (int argc, char *argv[])
-{
-
-  // Users may find it convenient to turn on explicit debugging
-  // for selected modules; the below lines suggest how to do this
-  //  LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL);
-  //  LogComponentEnable("TcpSocketImpl", LOG_LEVEL_ALL);
-  //  LogComponentEnable("PacketSink", LOG_LEVEL_ALL);
-  //  LogComponentEnable("TcpErrors", LOG_LEVEL_ALL);
-
-  //
-  // Make the random number generators generate reproducible results.
-  //
-  RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
-
-  // Allow the user to override any of the defaults and the above
-  // Bind()s at run-time, via command-line arguments
-  CommandLine cmd;
-  cmd.Parse (argc, argv);
-
-  // Here, we will explicitly create three nodes.  The first container contains
-  // nodes 0 and 1 from the diagram above, and the second one contains nodes
-  // 1 and 2.  This reflects the channel connectivity, and will be used to
-  // install the network interfaces and connect them with a channel.
-  NodeContainer n0n1;
-  n0n1.Create (2);
-
-  NodeContainer n1n2;
-  n1n2.Add (n0n1.Get (1));
-  n1n2.Create (1);
-
-  // We create the channels first without any IP addressing information
-  // First make and configure the helper, so that it will put the appropriate
-  // parameters on the network interfaces and channels we are about to install.
-  PointToPointHelper p2p;
-  p2p.SetDeviceAttribute ("DataRate", DataRateValue (DataRate(10000000)));
-  p2p.SetChannelAttribute ("Delay", TimeValue (MilliSeconds(10)));
-
-  // And then install devices and channels connecting our topology.
-  NetDeviceContainer d0d1 = p2p.Install (n0n1);
-  NetDeviceContainer d1d2 = p2p.Install (n1n2);
-
-  // Now add ip/tcp stack to all nodes.
-  NodeContainer allNodes = NodeContainer (n0n1, n1n2.Get (1));
-  InternetStackHelper internet;
-  internet.Install (allNodes);
-
-  // Later, we add IP addresses.
-  Ipv4AddressHelper ipv4;
-  ipv4.SetBase ("10.1.3.0", "255.255.255.0");
-  Ipv4InterfaceContainer i0i1 = ipv4.Assign (d0d1);
-  ipv4.SetBase ("10.1.2.0", "255.255.255.0");
-  Ipv4InterfaceContainer i1i2 = ipv4.Assign (d1d2);
-
-  // and setup ip routing tables to get total ip-level connectivity.
-  GlobalRouteManager::PopulateRoutingTables ();
-
-  // Set up the sending CBR application
-  uint16_t servPort = 50000;
-  Address remoteAddress(InetSocketAddress(i1i2.GetAddress (1), servPort));
-  OnOffHelper clientHelper ("ns3::TcpSocketFactory", remoteAddress);
-  clientHelper.SetAttribute 
-      ("OnTime", RandomVariableValue (ConstantVariable (1)));
-  clientHelper.SetAttribute 
-      ("OffTime", RandomVariableValue (ConstantVariable (0)));
-  ApplicationContainer clientApp = clientHelper.Install(n0n1.Get(0));
-  clientApp.Start (Seconds (1.0));
-  clientApp.Stop (Seconds (10.0));
-
-  // Create a packet sink to receive at n2
-  PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory",
-                         InetSocketAddress (Ipv4Address::GetAny (), servPort));
-  ApplicationContainer sinkApp = sinkHelper.Install (n1n2.Get(1));
-  sinkApp.Start (Seconds (1.0));
-  sinkApp.Stop (Seconds (10.0));
-
-  // We're going to model a lossy channel
-  RandomVariableValue u01(UniformVariable (0.0, 1.0));
-  DoubleValue rate(0.001);
-  Ptr<RateErrorModel> em1 = 
-      CreateObject<RateErrorModel> ("RanVar", u01, "ErrorRate", rate);
-  Ptr<RateErrorModel> em2 = 
-      CreateObject<RateErrorModel> ("RanVar", u01, "ErrorRate", rate);
-  //put error models on both netdevices of the router nodes so that there is
-  //loss of both data and acks
-  d0d1.Get(1)->SetAttribute("ReceiveErrorModel", PointerValue (em1));
-  d1d2.Get(0)->SetAttribute("ReceiveErrorModel", PointerValue (em2));
-
-  //Ask for ASCII and pcap traces of network traffic
-  std::ofstream ascii;
-  ascii.open ("tcp-errors.tr");
-  PointToPointHelper::EnableAsciiAll (ascii);
-
-  PointToPointHelper::EnablePcapAll ("tcp-errors");
-
-  // Finally, set up the simulator to run for 1000 seconds.
-  Simulator::Stop (Seconds(1000));
-  Simulator::Run ();
-  Simulator::Destroy ();
-}
--- a/examples/tcp-large-transfer.cc	Mon Sep 08 12:19:46 2008 +0100
+++ b/examples/tcp-large-transfer.cc	Mon Sep 08 12:35:08 2008 +0100
@@ -132,6 +132,7 @@
 
   ApplicationContainer apps = sink.Install (n1n2.Get (1));
   apps.Start (Seconds (0.0));
+  apps.Stop (Seconds (3.0));
 
   // Create a source to send packets from n0.  Instead of a full Application
   // and the helper APIs you might see in other example files, this example
--- a/examples/wscript	Mon Sep 08 12:19:46 2008 +0100
+++ b/examples/wscript	Mon Sep 08 12:35:08 2008 +0100
@@ -60,10 +60,6 @@
         ['point-to-point', 'internet-stack'])
     obj.source = 'tcp-large-transfer.cc'
 
-    obj = bld.create_ns3_program('tcp-errors',
-        ['point-to-point', 'internet-stack'])
-    obj.source = 'tcp-errors.cc'
-
     obj = bld.create_ns3_program('tcp-nsc-lfn',
       ['point-to-point', 'internet-stack'])
     obj.source = 'tcp-nsc-lfn.cc'
--- a/src/internet-stack/pending-data.cc	Mon Sep 08 12:19:46 2008 +0100
+++ b/src/internet-stack/pending-data.cc	Mon Sep 08 12:35:08 2008 +0100
@@ -131,7 +131,7 @@
   uint32_t s1 = std::min (s, SizeFromOffset (o)); // Insure not beyond end of data
   if (s1 == 0)
     {
-      return 0;   // No data requested
+      return Create<Packet> ();   // No data requested
     }
   if (data.size() != 0)
     { // Actual data exists, make copy and return it
--- a/src/internet-stack/tcp-socket-impl.cc	Mon Sep 08 12:19:46 2008 +0100
+++ b/src/internet-stack/tcp-socket-impl.cc	Mon Sep 08 12:35:08 2008 +0100
@@ -76,10 +76,13 @@
     m_highestRxAck (0),
     m_lastRxAck (0),
     m_nextRxSequence (0),
+    m_rxAvailable (0),
+    m_rxBufSize (0),
     m_pendingData (0),
+    m_rxWindowSize (0),
+    m_persistTime (Seconds(6)), //XXX hook this into attributes?
     m_rtt (0),
-    m_lastMeasuredRtt (Seconds(0.0)),
-    m_rxAvailable (0)
+    m_lastMeasuredRtt (Seconds(0.0))
 {
   NS_LOG_FUNCTION (this);
 }
@@ -112,20 +115,21 @@
     m_highestRxAck (sock.m_highestRxAck),
     m_lastRxAck (sock.m_lastRxAck),
     m_nextRxSequence (sock.m_nextRxSequence),
+    m_rxAvailable (0),
+    m_rxBufSize (0),
     m_pendingData (0),
     m_segmentSize (sock.m_segmentSize),
     m_rxWindowSize (sock.m_rxWindowSize),
-    m_advertisedWindowSize (sock.m_advertisedWindowSize),
     m_cWnd (sock.m_cWnd),
     m_ssThresh (sock.m_ssThresh),
     m_initialCWnd (sock.m_initialCWnd),
+    m_persistTime (sock.m_persistTime),
     m_rtt (0),
     m_lastMeasuredRtt (Seconds(0.0)),
     m_cnTimeout (sock.m_cnTimeout),
     m_cnCount (sock.m_cnCount),
-    m_rxAvailable (0),
     m_sndBufSize (sock.m_sndBufSize),
-    m_rcvBufSize(sock.m_rcvBufSize)
+    m_rxBufMaxSize(sock.m_rxBufMaxSize)
 {
   NS_LOG_FUNCTION_NOARGS ();
   NS_LOG_LOGIC("Invoked the copy constructor");
@@ -176,7 +180,6 @@
   m_node = node;
   // Initialize some variables 
   m_cWnd = m_initialCWnd * m_segmentSize;
-  m_rxWindowSize = m_advertisedWindowSize;
 }
 
 void 
@@ -212,6 +215,9 @@
   m_node = 0;
   m_endPoint = 0;
   m_tcp = 0;
+  NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at "
+                << (Simulator::Now () + 
+                Simulator::GetDelayLeft (m_retxEvent)).GetSeconds());
   m_retxEvent.Cancel ();
 }
 int
@@ -492,6 +498,7 @@
           out[i->first]  = i->second;
         }
       m_rxAvailable -= i->second->GetSize ();
+      m_rxBufSize -= i->second->GetSize ();
       m_bufferedData.erase (i);     // Remove from list
     }
   if (out.size() == 0)
@@ -514,6 +521,7 @@
       m_bufferedData[i->first+SequenceNumber(avail)] 
           = i->second->CreateFragment(avail,i->second->GetSize()-avail);
       m_rxAvailable += i->second->GetSize()-avail;
+      m_rxBufSize += i->second->GetSize()-avail;
     }
   }
   return outPacket;
@@ -571,6 +579,13 @@
         }
     }
 
+  if (m_rxWindowSize == 0 && tcpHeader.GetWindowSize () != 0) 
+    { //persist probes end
+      NS_LOG_LOGIC (this<<" Leaving zerowindow persist state");
+      m_persistEvent.Cancel ();
+    }
+  m_rxWindowSize = tcpHeader.GetWindowSize (); //update the flow control window
+
   Events_t event = SimulationSingleton<TcpStateMachine>::Get ()->FlagsEvent (tcpHeader.GetFlags () );
   Actions_t action = ProcessEvent (event); //updates the state
   Address address = InetSocketAddress (ipv4, port);
@@ -632,7 +647,7 @@
 
 void TcpSocketImpl::SendEmptyPacket (uint8_t flags)
 {
-  NS_LOG_FUNCTION (this << flags);
+  NS_LOG_FUNCTION (this << (uint32_t)flags);
   Ptr<Packet> p = Create<Packet> ();
   TcpHeader header;
 
@@ -641,17 +656,21 @@
   header.SetAckNumber (m_nextRxSequence);
   header.SetSourcePort (m_endPoint->GetLocalPort ());
   header.SetDestinationPort (m_remotePort);
-  header.SetWindowSize (m_advertisedWindowSize);
+  header.SetWindowSize (AdvertisedWindowSize());
   m_tcp->SendPacket (p, header, m_endPoint->GetLocalAddress (), 
     m_remoteAddress);
   Time rto = m_rtt->RetransmitTimeout ();
-  if (flags & TcpHeader::SYN)
+  bool hasSyn = flags & TcpHeader::SYN;
+  bool hasFin = flags & TcpHeader::FIN;
+  bool isAck = flags == TcpHeader::ACK;
+  if (hasSyn)
     {
       rto = m_cnTimeout;
       m_cnTimeout = m_cnTimeout + m_cnTimeout;
       m_cnCount--;
     }
-  if (m_retxEvent.IsExpired () ) //no outstanding timer
+  if (m_retxEvent.IsExpired () && (hasSyn || hasFin) && !isAck )
+  //no outstanding timer
   {
     NS_LOG_LOGIC ("Schedule retransmission timeout at time " 
           << Simulator::Now ().GetSeconds () << " to expire at time " 
@@ -745,6 +764,13 @@
   Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
   switch (a)
   {
+    case ACK_TX:
+      if(tcpHeader.GetFlags() & TcpHeader::FIN)
+      {
+        ++m_nextRxSequence; //bump this to account for the FIN
+      }
+      SendEmptyPacket (TcpHeader::ACK);
+      break;
     case SYN_ACK_TX:
       NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action SYN_ACK_TX");
 //      m_remotePort = InetSocketAddress::ConvertFrom (fromAddress).GetPort ();
@@ -767,19 +793,20 @@
                                   p, tcpHeader,fromAddress);
           return true;
         }
-        // This is the cloned endpoint
-        m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
-        if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
-          {
-            m_localAddress = ipv4->GetAddress (localIfIndex);
-            m_endPoint->SetLocalAddress (m_localAddress);
-            // Leave local addr in the portmap to any, as the path from
-            // remote can change and packets can arrive on different interfaces
-            //m_endPoint->SetLocalAddress (Ipv4Address::GetAny());
-          }
-        // TCP SYN consumes one byte
-        m_nextRxSequence = tcpHeader.GetSequenceNumber() + SequenceNumber(1);
-        SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
+      // This is the cloned endpoint
+      NS_ASSERT (m_state == SYN_RCVD);
+      m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
+      if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
+        {
+          m_localAddress = ipv4->GetAddress (localIfIndex);
+          m_endPoint->SetLocalAddress (m_localAddress);
+          // Leave local addr in the portmap to any, as the path from
+          // remote can change and packets can arrive on different interfaces
+          //m_endPoint->SetLocalAddress (Ipv4Address::GetAny());
+        }
+      // TCP SYN consumes one byte
+      m_nextRxSequence = tcpHeader.GetSequenceNumber() + SequenceNumber(1);
+      SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
       break;
     case ACK_TX_1:
       NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action ACK_TX_1");
@@ -790,7 +817,6 @@
       NS_LOG_DEBUG ("TcpSocketImpl " << this << " ACK_TX_1" <<
                     " nextRxSeq " << m_nextRxSequence);
       SendEmptyPacket (TcpHeader::ACK);
-      m_rxWindowSize = tcpHeader.GetWindowSize ();
       if (tcpHeader.GetAckNumber () > m_highestRxAck)
       {
         m_highestRxAck = tcpHeader.GetAckNumber ();
@@ -808,13 +834,17 @@
       {
         break;
       }
-      if (tcpHeader.GetAckNumber () == m_highestRxAck && 
-         tcpHeader.GetAckNumber ()  < m_nextTxSequence)
+      if (tcpHeader.GetAckNumber () == m_highestRxAck)
       {
-        DupAck (tcpHeader, ++m_dupAckCount);
+        if (tcpHeader.GetAckNumber ()  < m_nextTxSequence)
+        {
+          DupAck (tcpHeader, ++m_dupAckCount);
+        }
+        NS_ASSERT(tcpHeader.GetAckNumber ()  <= m_nextTxSequence);
+        //if the ack is precisely equal to the nextTxSequence
         break;
       }
-      if (tcpHeader.GetAckNumber () > m_highestRxAck)  
+      if (tcpHeader.GetAckNumber () > m_highestRxAck)
         {
           m_dupAckCount = 0;
         }
@@ -844,6 +874,7 @@
         {
           NewRx (p, tcpHeader, fromAddress);
         }
+      ++m_nextRxSequence; //bump this to account for the FIN
       States_t saveState = m_state; // Used to see if app responds
       NS_LOG_LOGIC ("TcpSocketImpl " << this 
           << " peer close, state " << m_state);
@@ -878,7 +909,7 @@
       NotifyNewConnectionCreated (this, fromAddress);
       break;
     default:
-      break;
+      return ProcessAction (a);
   }
   return true;
 }
@@ -928,7 +959,7 @@
            << " highestRxAck " << m_highestRxAck 
            << " pd->Size " << m_pendingData->Size ()
            << " pd->SFS " << m_pendingData->SizeFromSeq (m_firstPendingSequence, m_nextTxSequence));
-
+//XXX pd->Size is probably a bug, should be SizeFromSeq(...)
       if (w < m_segmentSize && m_pendingData->Size () > w)
         {
           break; // No more
@@ -961,6 +992,7 @@
       header.SetAckNumber (m_nextRxSequence);
       header.SetSourcePort (m_endPoint->GetLocalPort());
       header.SetDestinationPort (m_remotePort);
+      header.SetWindowSize (AdvertisedWindowSize());
       if (m_shutdownSend)
         {
           m_errno = ERROR_SHUTDOWN;
@@ -971,7 +1003,7 @@
       if (m_retxEvent.IsExpired () ) //go ahead and schedule the retransmit
         {
             Time rto = m_rtt->RetransmitTimeout (); 
-            NS_LOG_LOGIC ("SendPendingData Schedule retransmission timeout at time " << 
+            NS_LOG_LOGIC (this<<" SendPendingData Schedule ReTxTimeout at time " << 
               Simulator::Now ().GetSeconds () << " to expire at time " <<
               (Simulator::Now () + rto).GetSeconds () );
           m_retxEvent = Simulator::Schedule (rto,&TcpSocketImpl::ReTxTimeout,this);
@@ -1024,6 +1056,17 @@
   return (win - unack);       // Amount of window space available
 }
 
+uint32_t TcpSocketImpl::RxBufferFreeSpace()
+{
+  return m_rxBufMaxSize - m_rxBufSize;
+}
+
+uint16_t TcpSocketImpl::AdvertisedWindowSize()
+{
+  uint32_t max = 0xffff;
+  return std::min(RxBufferFreeSpace(), max);
+}
+
 void TcpSocketImpl::NewRx (Ptr<Packet> p,
                         const TcpHeader& tcpHeader, 
                         const Address& fromAddress)
@@ -1039,9 +1082,20 @@
                 " ack " << tcpHeader.GetAckNumber() <<
                 " p.size is " << p->GetSize());
   States_t origState = m_state;
+  if (RxBufferFreeSpace() < p->GetSize()) 
+    { //if not enough room, fragment
+      p = p->CreateFragment(0, RxBufferFreeSpace());
+    }
+  //XXX
+  //fragmenting here MIGHT not be the right thing to do, since possibly we trim
+  //the front and back off the packet below if it isn't all new data, so the 
+  //check against RxBufferFreeSpace and fragmentation should ideally occur
+  //just before insertion into m_bufferedData, but this strategy is more
+  //agressive in rejecting oversized packets and still gives acceptable TCP
   uint32_t s = p->GetSize ();  // Size of associated data
   if (s == 0)
-    {// Nothing to do if no associated data
+    {//if there is no data or no rx buffer space, just ack anyway
+      SendEmptyPacket (TcpHeader::ACK);
       return;
     }
   // Log sequence received if enabled
@@ -1074,14 +1128,12 @@
       //buffer this, it'll be read by call to Recv
       UnAckData_t::iterator i = 
           m_bufferedData.find (tcpHeader.GetSequenceNumber () );
-      if (i != m_bufferedData.end () ) //we found it already in the buffer
-      {
-        i->second = 0; // relase reference to already buffered
-      }
-      // Save for later delivery
-      m_bufferedData[tcpHeader.GetSequenceNumber () ] = p;  
+      NS_ASSERT(i == m_bufferedData.end ()); //no way it should have been found
+      // Save for later delivery if there is room
+      m_bufferedData[tcpHeader.GetSequenceNumber () ] = p;
       m_rxAvailable += p->GetSize ();
       RxBufFinishInsert (tcpHeader.GetSequenceNumber ());
+      m_rxBufSize += p->GetSize ();
       NotifyDataRecv ();
       if (m_closeNotified)
         {
@@ -1181,6 +1233,7 @@
       // Save for later delivery
       m_bufferedData[start] = p;
       m_rxAvailable += p->GetSize ();
+      m_rxBufSize += p->GetSize();
       RxBufFinishInsert(start);
       NotifyDataRecv ();
     }
@@ -1248,13 +1301,31 @@
   //DEBUG(1,(cout << "TCP " << this << "Cancelling retx timer " << endl));
   if (!skipTimer)
     {
-      m_retxEvent.Cancel ();  
+      NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at "
+                    << (Simulator::Now () + 
+                        Simulator::GetDelayLeft (m_retxEvent)).GetSeconds());
+      m_retxEvent.Cancel ();
       //On recieving a "New" ack we restart retransmission timer .. RFC 2988
       Time rto = m_rtt->RetransmitTimeout ();
-      NS_LOG_LOGIC ("Schedule retransmission timeout at time " 
+      NS_LOG_LOGIC (this<<" Schedule ReTxTimeout at time " 
           << Simulator::Now ().GetSeconds () << " to expire at time " 
           << (Simulator::Now () + rto).GetSeconds ());
-    m_retxEvent = Simulator::Schedule (rto, &TcpSocketImpl::ReTxTimeout, this);
+      m_retxEvent = 
+          Simulator::Schedule (rto, &TcpSocketImpl::ReTxTimeout, this);
+    }
+  if (m_rxWindowSize == 0 && m_persistEvent.IsExpired ()) //zerowindow
+    {
+      NS_LOG_LOGIC (this<<"Enter zerowindow persist state");
+      NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at "
+                    << (Simulator::Now () + 
+                        Simulator::GetDelayLeft (m_retxEvent)).GetSeconds());
+      m_retxEvent.Cancel ();
+      NS_LOG_LOGIC ("Schedule persist timeout at time " 
+                    <<Simulator::Now ().GetSeconds () << " to expire at time "
+                    << (Simulator::Now () + m_persistTime).GetSeconds());
+      m_persistEvent = 
+      Simulator::Schedule (m_persistTime, &TcpSocketImpl::PersistTimeout, this);
+      NS_ASSERT (m_persistTime == Simulator::GetDelayLeft (m_persistEvent));
     }
   NS_LOG_LOGIC ("TCP " << this << " NewAck " << ack 
            << " numberAck " << (ack - m_highestRxAck)); // Number bytes ack'ed
@@ -1276,6 +1347,9 @@
           delete m_pendingData;
           m_pendingData = 0;
           // Insure no re-tx timer
+          NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at "
+                    << (Simulator::Now () + 
+                        Simulator::GetDelayLeft (m_retxEvent)).GetSeconds());
           m_retxEvent.Cancel ();
         }
     }
@@ -1341,6 +1415,7 @@
 void TcpSocketImpl::ReTxTimeout ()
 { // Retransmit timeout
   NS_LOG_FUNCTION (this);
+  NS_LOG_LOGIC (this<<" ReTxTimeout Expired at time "<<Simulator::Now ().GetSeconds());
   m_ssThresh = Window () / 2; // Per RFC2581
   m_ssThresh = std::max (m_ssThresh, 2 * m_segmentSize);
   // Set cWnd to segSize on timeout,  per rfc2581
@@ -1365,6 +1440,31 @@
     }
 }
 
+void TcpSocketImpl::PersistTimeout ()
+{
+  NS_LOG_LOGIC ("PersistTimeout expired at "<<Simulator::Now ().GetSeconds ());
+  m_persistTime = Scalar(2)*m_persistTime;
+  m_persistTime = std::min(Seconds(60),m_persistTime); //maxes out at 60
+  //the persist timeout sends exactly one byte probes
+  //this is explicit in stevens, and kind of in rfc793 p42, rfc1122 sec4.2.2.17
+  Ptr<Packet> p =
+    m_pendingData->CopyFromSeq(1,m_firstPendingSequence,m_nextTxSequence);
+  TcpHeader tcpHeader;
+  tcpHeader.SetSequenceNumber (m_nextTxSequence);
+  tcpHeader.SetAckNumber (m_nextRxSequence);
+  tcpHeader.SetSourcePort (m_endPoint->GetLocalPort());
+  tcpHeader.SetDestinationPort (m_remotePort);
+  tcpHeader.SetWindowSize (AdvertisedWindowSize());
+
+  m_tcp->SendPacket (p, tcpHeader, m_endPoint->GetLocalAddress (),
+    m_remoteAddress);
+  NS_LOG_LOGIC ("Schedule persist timeout at time " 
+                    <<Simulator::Now ().GetSeconds () << " to expire at time "
+                    << (Simulator::Now () + m_persistTime).GetSeconds());
+  m_persistEvent = 
+    Simulator::Schedule (m_persistTime, &TcpSocketImpl::PersistTimeout, this);
+}
+
 void TcpSocketImpl::Retransmit ()
 {
   NS_LOG_FUNCTION (this);
@@ -1390,9 +1490,10 @@
         }
       return;
     }
+  NS_ASSERT(m_nextTxSequence == m_highestRxAck);
   Ptr<Packet> p = m_pendingData->CopyFromSeq (m_segmentSize,
                                             m_firstPendingSequence,
-                                            m_highestRxAck);
+                                            m_nextTxSequence);
   // Calculate remaining data for COE check
   uint32_t remainingData = m_pendingData->SizeFromSeq (
       m_firstPendingSequence,
@@ -1406,7 +1507,7 @@
   if (m_retxEvent.IsExpired () )
     {
       Time rto = m_rtt->RetransmitTimeout ();
-      NS_LOG_LOGIC ("Schedule retransmission timeout at time "
+      NS_LOG_LOGIC (this<<" Schedule ReTxTimeout at time "
           << Simulator::Now ().GetSeconds () << " to expire at time "
           << (Simulator::Now () + rto).GetSeconds ());
       m_retxEvent = Simulator::Schedule (rto,&TcpSocketImpl::ReTxTimeout,this);
@@ -1419,7 +1520,7 @@
   tcpHeader.SetSourcePort (m_endPoint->GetLocalPort());
   tcpHeader.SetDestinationPort (m_remotePort);
   tcpHeader.SetFlags (flags);
-  tcpHeader.SetWindowSize (m_advertisedWindowSize);
+  tcpHeader.SetWindowSize (AdvertisedWindowSize());
 
   m_tcp->SendPacket (p, tcpHeader, m_endPoint->GetLocalAddress (),
     m_remoteAddress);
@@ -1440,13 +1541,13 @@
 void
 TcpSocketImpl::SetRcvBufSize (uint32_t size)
 {
-  m_rcvBufSize = size;
+  m_rxBufMaxSize = size;
 }
 
 uint32_t
 TcpSocketImpl::GetRcvBufSize (void) const
 {
-  return m_rcvBufSize;
+  return m_rxBufMaxSize;
 }
 
 void
@@ -1462,18 +1563,6 @@
 }
 
 void
-TcpSocketImpl::SetAdvWin (uint32_t window)
-{
-  m_advertisedWindowSize = window;
-}
-
-uint32_t
-TcpSocketImpl::GetAdvWin (void) const
-{
-  return m_advertisedWindowSize;
-}
-
-void
 TcpSocketImpl::SetSSThresh (uint32_t threshold)
 {
   m_ssThresh = threshold;
@@ -1556,6 +1645,7 @@
 #include "ns3/simple-channel.h"
 #include "ns3/simple-net-device.h"
 #include "ns3/drop-tail-queue.h"
+#include "ns3/config.h"
 #include "internet-stack.h"
 #include <string>
 
@@ -1567,20 +1657,34 @@
   TcpSocketImplTest ();
   virtual bool RunTests (void);
   private:
-  void Test1 (void); //send string "Hello world" server->client
-  void Test2 (uint32_t payloadSize);
-  Ptr<Node> CreateInternetNode ();
-  Ptr<SimpleNetDevice> AddSimpleNetDevice (Ptr<Node>,const char*,const char*);
-  
+  //test 1, which sends string "Hello world" server->client
+  void Test1 (void);
   void Test1_HandleConnectionCreated (Ptr<Socket>, const Address &);
   void Test1_HandleRecv (Ptr<Socket> sock);
 
+  //test 2, which sends a number of bytes server->client
+  void Test2 (uint32_t payloadSize);
   void Test2_HandleConnectionCreated (Ptr<Socket>, const Address &);
   void Test2_HandleRecv (Ptr<Socket> sock);
   uint32_t test2_payloadSize;
 
+  //test 3, which makes sure the rx buffer is finite
+  void Test3 (uint32_t payloadSize);
+  void Test3_HandleConnectionCreated (Ptr<Socket>, const Address &);
+  void Test3_HandleRecv (Ptr<Socket> sock);
+  uint32_t test3_payloadSize;
+
+  //helpers to make topology construction easier
+  Ptr<Node> CreateInternetNode ();
+  Ptr<SimpleNetDevice> AddSimpleNetDevice (Ptr<Node>,const char*,const char*);
+  void SetupDefaultSim ();
+
+  //reset all of the below state for another run
   void Reset ();
-  
+
+  //all of the state this class needs; basically both ends of the connection,
+  //and this test kind of acts as an single application running on both nodes
+  //simultaneously
   Ptr<Node> node0;
   Ptr<Node> node1;
   Ptr<SimpleNetDevice> dev0;
@@ -1591,9 +1695,9 @@
   Ptr<Socket> sock1;
   uint32_t rxBytes0;
   uint32_t rxBytes1;
-  
+
   uint8_t* rxPayload;
-  
+
   bool result;
 };
 
@@ -1610,119 +1714,35 @@
 TcpSocketImplTest::RunTests (void)
 {
   Test1();
+  if (!result) return false;
   Test2(600);
+  if (!result) return false;
+  Test3(20000);
   return result;
 }
 
+//-----------------------------------------------------------------------------
+//test 1-----------------------------------------------------------------------
+//-----------------------------------------------------------------------------
 void
 TcpSocketImplTest::Test1 ()
 {
-  const char* netmask = "255.255.255.0";
-  const char* ipaddr0 = "192.168.1.1";
-  const char* ipaddr1 = "192.168.1.2";
-  node0 = CreateInternetNode ();
-  node1 = CreateInternetNode ();
-  dev0 = AddSimpleNetDevice (node0, ipaddr0, netmask);
-  dev1 = AddSimpleNetDevice (node1, ipaddr1, netmask);
-  
-  channel = CreateObject<SimpleChannel> ();
-  dev0->SetChannel (channel);
-  dev1->SetChannel (channel);
-  
-  Ptr<SocketFactory> sockFactory0 = node0->GetObject<TcpSocketFactory> ();
-  Ptr<SocketFactory> sockFactory1 = node1->GetObject<TcpSocketFactory> ();
-  
-  listeningSock = sockFactory0->CreateSocket();
-  sock1 = sockFactory1->CreateSocket();
-  
-  uint16_t port = 50000;
-  InetSocketAddress serverlocaladdr (Ipv4Address::GetAny(), port);
-  InetSocketAddress serverremoteaddr (Ipv4Address(ipaddr0), port);
-  
-  listeningSock->Bind(serverlocaladdr);
-  listeningSock->Listen (0);
+  SetupDefaultSim ();
   listeningSock->SetAcceptCallback 
-    (MakeNullCallback<bool, Ptr< Socket >, const Address &> (),
-     MakeCallback(&TcpSocketImplTest::Test1_HandleConnectionCreated,this));
-  
-  sock1->Connect(serverremoteaddr);
+      (MakeNullCallback<bool, Ptr< Socket >, const Address &> (),
+       MakeCallback(&TcpSocketImplTest::Test1_HandleConnectionCreated,this));
   sock1->SetRecvCallback (MakeCallback(&TcpSocketImplTest::Test1_HandleRecv, this));
-  
+
   Simulator::Run ();
   Simulator::Destroy ();
-  
+
   result = result && (rxBytes1 == 13);
   result = result && (strcmp((const char*) rxPayload,"Hello World!") == 0);
-  
+
   Reset ();
 }
 
 void
-TcpSocketImplTest::Test2 (uint32_t payloadSize)
-{
-  test2_payloadSize = payloadSize;
-  const char* netmask = "255.255.255.0";
-  const char* ipaddr0 = "192.168.1.1";
-  const char* ipaddr1 = "192.168.1.2";
-  node0 = CreateInternetNode ();
-  node1 = CreateInternetNode ();
-  dev0 = AddSimpleNetDevice (node0, ipaddr0, netmask);
-  dev1 = AddSimpleNetDevice (node1, ipaddr1, netmask);
-  
-  channel = CreateObject<SimpleChannel> ();
-  dev0->SetChannel (channel);
-  dev1->SetChannel (channel);
-  
-  Ptr<SocketFactory> sockFactory0 = node0->GetObject<TcpSocketFactory> ();
-  Ptr<SocketFactory> sockFactory1 = node1->GetObject<TcpSocketFactory> ();
-  
-  listeningSock = sockFactory0->CreateSocket();
-  sock1 = sockFactory1->CreateSocket();
-  
-  uint16_t port = 50000;
-  InetSocketAddress serverlocaladdr (Ipv4Address::GetAny(), port);
-  InetSocketAddress serverremoteaddr (Ipv4Address(ipaddr0), port);
-  
-  listeningSock->Bind(serverlocaladdr);
-  listeningSock->Listen (0);
-  listeningSock->SetAcceptCallback 
-    (MakeNullCallback<bool, Ptr< Socket >, const Address &> (),
-     MakeCallback(&TcpSocketImplTest::Test2_HandleConnectionCreated,this));
-  
-  sock1->Connect(serverremoteaddr);
-  sock1->SetRecvCallback (MakeCallback(&TcpSocketImplTest::Test2_HandleRecv, this));
-  
-  Simulator::Run ();
-  Simulator::Destroy ();
-  
-  result = result && (rxBytes1 == test2_payloadSize);
-  
-  Reset ();
-}
-
-Ptr<Node>
-TcpSocketImplTest::CreateInternetNode ()
-{
-  Ptr<Node> node = CreateObject<Node> ();
-  AddInternetStack (node);
-  return node;
-}
-
-Ptr<SimpleNetDevice>
-TcpSocketImplTest::AddSimpleNetDevice (Ptr<Node> node, const char* ipaddr, const char* netmask)
-{
-  Ptr<SimpleNetDevice> dev = CreateObject<SimpleNetDevice> ();
-  dev->SetAddress (Mac48Address::Allocate ());
-  node->AddDevice (dev);
-  Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
-  uint32_t ndid = ipv4->AddInterface (dev);
-  ipv4->SetAddress (ndid, Ipv4Address (ipaddr));
-  ipv4->SetNetworkMask (ndid, Ipv4Mask (netmask));
-  ipv4->SetUp (ndid);
-  return dev;
-}
-
-void
 TcpSocketImplTest::Test1_HandleConnectionCreated (Ptr<Socket> s, const Address & addr)
 {
   NS_ASSERT(s != listeningSock);
@@ -1753,6 +1773,27 @@
   }
 }
 
+//-----------------------------------------------------------------------------
+//test 2-----------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void
+TcpSocketImplTest::Test2 (uint32_t payloadSize)
+{
+  test2_payloadSize = payloadSize;
+  SetupDefaultSim ();
+  listeningSock->SetAcceptCallback 
+      (MakeNullCallback<bool, Ptr< Socket >, const Address &> (),
+       MakeCallback(&TcpSocketImplTest::Test2_HandleConnectionCreated,this));
+  sock1->SetRecvCallback (MakeCallback(&TcpSocketImplTest::Test2_HandleRecv, this));
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  result = result && (rxBytes1 == test2_payloadSize);
+
+  Reset ();
+}
+
 void
 TcpSocketImplTest::Test2_HandleConnectionCreated (Ptr<Socket> s, const Address & addr)
 {
@@ -1777,10 +1818,108 @@
   }
   else
   {
-    NS_FATAL_ERROR ("Recv from unknown socket "<<sock);
+    NS_FATAL_ERROR ("Not supposed to be back traffic in test 2..."<<sock);
+  }
+}
+
+//-----------------------------------------------------------------------------
+//test 3-----------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void
+TcpSocketImplTest::Test3 (uint32_t payloadSize)
+{
+  Config::SetDefault ("ns3::TcpSocket::RcvBufSize", UintegerValue (10000));
+  test3_payloadSize = payloadSize;
+  SetupDefaultSim ();
+  listeningSock->SetAcceptCallback 
+      (MakeNullCallback<bool, Ptr< Socket >, const Address &> (),
+       MakeCallback(&TcpSocketImplTest::Test3_HandleConnectionCreated,this));
+  sock1->SetRecvCallback (MakeCallback(&TcpSocketImplTest::Test3_HandleRecv, this));
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  result = result && (rxBytes1 == test3_payloadSize);
+
+  Reset();
+}
+void
+TcpSocketImplTest::Test3_HandleConnectionCreated (Ptr<Socket> s, const Address &)
+{
+  NS_ASSERT(s != listeningSock);
+  NS_ASSERT(sock0 == 0);
+  sock0 = s;
+  Ptr<Packet> p = Create<Packet> (test3_payloadSize);
+  sock0->Send(p);
+}
+void
+TcpSocketImplTest::Test3_HandleRecv (Ptr<Socket> sock)
+{
+  NS_ASSERT_MSG (sock == sock1, "Not supposed to be back traffic in test 3... ");
+  if(sock->GetRxAvailable() >= 10000 ) //perform batch reads every 10000 bytes
+  {
+    Ptr<Packet> p = sock->Recv();
+    uint32_t sz = p->GetSize();
+    rxBytes1 += sz;
   }
 }
 
+//-----------------------------------------------------------------------------
+//helpers----------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+Ptr<Node>
+TcpSocketImplTest::CreateInternetNode ()
+{
+  Ptr<Node> node = CreateObject<Node> ();
+  AddInternetStack (node);
+  return node;
+}
+
+Ptr<SimpleNetDevice>
+TcpSocketImplTest::AddSimpleNetDevice (Ptr<Node> node, const char* ipaddr, const char* netmask)
+{
+  Ptr<SimpleNetDevice> dev = CreateObject<SimpleNetDevice> ();
+  dev->SetAddress (Mac48Address::Allocate ());
+  node->AddDevice (dev);
+  Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
+  uint32_t ndid = ipv4->AddInterface (dev);
+  ipv4->SetAddress (ndid, Ipv4Address (ipaddr));
+  ipv4->SetNetworkMask (ndid, Ipv4Mask (netmask));
+  ipv4->SetUp (ndid);
+  return dev;
+}
+
+void 
+TcpSocketImplTest::SetupDefaultSim ()
+{
+  const char* netmask = "255.255.255.0";
+  const char* ipaddr0 = "192.168.1.1";
+  const char* ipaddr1 = "192.168.1.2";
+  node0 = CreateInternetNode ();
+  node1 = CreateInternetNode ();
+  dev0 = AddSimpleNetDevice (node0, ipaddr0, netmask);
+  dev1 = AddSimpleNetDevice (node1, ipaddr1, netmask);
+
+  channel = CreateObject<SimpleChannel> ();
+  dev0->SetChannel (channel);
+  dev1->SetChannel (channel);
+
+  Ptr<SocketFactory> sockFactory0 = node0->GetObject<TcpSocketFactory> ();
+  Ptr<SocketFactory> sockFactory1 = node1->GetObject<TcpSocketFactory> ();
+
+  listeningSock = sockFactory0->CreateSocket();
+  sock1 = sockFactory1->CreateSocket();
+
+  uint16_t port = 50000;
+  InetSocketAddress serverlocaladdr (Ipv4Address::GetAny(), port);
+  InetSocketAddress serverremoteaddr (Ipv4Address(ipaddr0), port);
+
+  listeningSock->Bind(serverlocaladdr);
+  listeningSock->Listen (0);
+
+  sock1->Connect(serverremoteaddr);
+}
+
 void
 TcpSocketImplTest::Reset ()
 {
--- a/src/internet-stack/tcp-socket-impl.h	Mon Sep 08 12:19:46 2008 +0100
+++ b/src/internet-stack/tcp-socket-impl.h	Mon Sep 08 12:35:08 2008 +0100
@@ -121,6 +121,10 @@
   virtual uint32_t  Window();         // Return window size (integer)
   virtual uint32_t  AvailableWindow();// Return unfilled portion of window
 
+  //methods for Rx buffer management
+  uint32_t RxBufferFreeSpace();
+  uint16_t AdvertisedWindowSize();
+
   // Manage data tx/rx
   void NewRx (Ptr<Packet>, const TcpHeader&, const Address&);
   void RxBufFinishInsert (SequenceNumber);
@@ -132,6 +136,7 @@
   void ReTxTimeout ();
   void DelAckTimeout ();
   void LastAckTimeout ();
+  void PersistTimeout ();
   void Retransmit ();
   void CommonNewAck (SequenceNumber seq, bool skipTimer = false);
 
@@ -142,8 +147,6 @@
   virtual uint32_t GetRcvBufSize (void) const;
   virtual void SetSegSize (uint32_t size);
   virtual uint32_t GetSegSize (void) const;
-  virtual void SetAdvWin (uint32_t window);
-  virtual uint32_t GetAdvWin (void) const;
   virtual void SetSSThresh (uint32_t threshold);
   virtual uint32_t GetSSThresh (void) const;
   virtual void SetInitialCwnd (uint32_t cwnd);
@@ -195,23 +198,33 @@
   SequenceNumber m_lastRxAck;
   
   //sequence info, reciever side
-  SequenceNumber m_nextRxSequence;
+  SequenceNumber m_nextRxSequence; //next expected sequence
 
-  //history data
-  //this is the incoming data buffer which sorts out of sequence data
-  UnAckData_t m_bufferedData;
+  //Rx buffer
+  UnAckData_t m_bufferedData; //buffer which sorts out of sequence data
+  //Rx buffer state
+  uint32_t m_rxAvailable; // amount of data available for reading through Recv
+  uint32_t m_rxBufSize; //size in bytes of the data in the rx buf
+  //note that these two are not the same: rxAvailbale is the number of
+  //contiguous sequenced bytes that can be read, rxBufSize is the TOTAL size
+  //including out of sequence data, such that m_rxAvailable <= m_rxBufSize
+
   //this is kind of the tx buffer
   PendingData* m_pendingData;
   SequenceNumber m_firstPendingSequence;
 
   // Window management
   uint32_t                       m_segmentSize;          //SegmentSize
-  uint32_t                       m_rxWindowSize;
-  uint32_t                       m_advertisedWindowSize; //Window to advertise
+  uint32_t                       m_rxWindowSize;         //Flow control window
   TracedValue<uint32_t>          m_cWnd;                 //Congestion window
   uint32_t                       m_ssThresh;             //Slow Start Threshold
   uint32_t                       m_initialCWnd;          //Initial cWnd value
 
+  //persist timer management
+  Time                           m_persistTime;
+  EventId                        m_persistEvent;
+  
+
   // Round trip time estimation
   Ptr<RttEstimator> m_rtt;
   Time m_lastMeasuredRtt;
@@ -220,12 +233,9 @@
   Time              m_cnTimeout; 
   uint32_t          m_cnCount;
 
-  // Temporary queue for delivering data to application
-  uint32_t m_rxAvailable;
-
   // Attributes
   uint32_t m_sndBufSize;   // buffer limit for the outgoing queue
-  uint32_t m_rcvBufSize;   // maximum receive socket buffer size
+  uint32_t m_rxBufMaxSize;   // maximum receive socket buffer size
 };
 
 }//namespace ns3
--- a/src/internet-stack/tcp-typedefs.h	Mon Sep 08 12:19:46 2008 +0100
+++ b/src/internet-stack/tcp-typedefs.h	Mon Sep 08 12:35:08 2008 +0100
@@ -63,21 +63,21 @@
 typedef enum {
   NO_ACT,       // 0
   ACK_TX,       // 1
-  ACK_TX_1,     // ACK response to syn
-  RST_TX,       // 2
-  SYN_TX,       // 3
-  SYN_ACK_TX,   // 4
-  FIN_TX,       // 5
-  FIN_ACK_TX,   // 6
-  NEW_ACK,      // 7
-  NEW_SEQ_RX,   // 8
-  RETX,         // 9
-  TX_DATA,      // 10
-  PEER_CLOSE,   // 11
-  APP_CLOSED,   // 12
-  CANCEL_TM,    // 13
-  APP_NOTIFY,   // 14 - Notify app that connection failed
-  SERV_NOTIFY,  // 15 - Notify server tcp that connection completed
+  ACK_TX_1,     // 2 - ACK response to syn
+  RST_TX,       // 3
+  SYN_TX,       // 4
+  SYN_ACK_TX,   // 5
+  FIN_TX,       // 6
+  FIN_ACK_TX,   // 7
+  NEW_ACK,      // 8
+  NEW_SEQ_RX,   // 9
+  RETX,         // 10
+  TX_DATA,      // 11
+  PEER_CLOSE,   // 12
+  APP_CLOSED,   // 13
+  CANCEL_TM,    // 14
+  APP_NOTIFY,   // 15 - Notify app that connection failed
+  SERV_NOTIFY,  // 16 - Notify server tcp that connection completed
   LAST_ACTION } Actions_t;
 
 class SA  // State/Action pair
--- a/src/node/tcp-socket.cc	Mon Sep 08 12:19:46 2008 +0100
+++ b/src/node/tcp-socket.cc	Mon Sep 08 12:35:08 2008 +0100
@@ -55,12 +55,6 @@
                    MakeUintegerAccessor (&TcpSocket::GetSegSize,
                                          &TcpSocket::SetSegSize),
                    MakeUintegerChecker<uint32_t> ())
-    .AddAttribute ("AdvertisedWindowSize",
-                   "TCP advertised window size (bytes)",
-                   UintegerValue (0xffff),
-                   MakeUintegerAccessor (&TcpSocket::GetAdvWin,
-                                         &TcpSocket::SetAdvWin),
-                   MakeUintegerChecker<uint32_t> ())
     .AddAttribute ("SlowStartThreshold",
                    "TCP slow start threshold (bytes)",
                    UintegerValue (0xffff),
--- a/src/node/tcp-socket.h	Mon Sep 08 12:19:46 2008 +0100
+++ b/src/node/tcp-socket.h	Mon Sep 08 12:35:08 2008 +0100
@@ -59,8 +59,6 @@
   virtual uint32_t GetRcvBufSize (void) const = 0;
   virtual void SetSegSize (uint32_t size) = 0;
   virtual uint32_t GetSegSize (void) const = 0;
-  virtual void SetAdvWin (uint32_t window) = 0;
-  virtual uint32_t GetAdvWin (void) const = 0;
   virtual void SetSSThresh (uint32_t threshold) = 0;
   virtual uint32_t GetSSThresh (void) const = 0;
   virtual void SetInitialCwnd (uint32_t count) = 0;