View | Details | Raw Unified | Return to bug 2068
Collapse All | Expand All

(-)a/src/internet/model/tcp-socket-base.cc (-40 / +94 lines)
 Lines 91-97   TcpSocketBase::GetTypeId (void) Link Here 
91
                   MakeCallbackChecker ())
91
                   MakeCallbackChecker ())
92
    .AddAttribute ("WindowScaling", "Enable or disable Window Scaling option",
92
    .AddAttribute ("WindowScaling", "Enable or disable Window Scaling option",
93
                   BooleanValue (true),
93
                   BooleanValue (true),
94
                   MakeBooleanAccessor (&TcpSocketBase::m_winScalingEnabled),
94
                   MakeBooleanAccessor (&TcpSocketBase::EnableWSOption,
95
                                        &TcpSocketBase::GetWSOptionEnabled),
95
                   MakeBooleanChecker ())
96
                   MakeBooleanChecker ())
96
    .AddAttribute ("Timestamp", "Enable or disable Timestamp option",
97
    .AddAttribute ("Timestamp", "Enable or disable Timestamp option",
97
                   BooleanValue (true),
98
                   BooleanValue (true),
 Lines 284-290   TcpSocketBase::TcpSocketBase (void) Link Here 
284
  m_highRxMark (0),
285
  m_highRxMark (0),
285
  m_highRxAckMark (0),
286
  m_highRxAckMark (0),
286
  m_bytesAckedNotProcessed (0),
287
  m_bytesAckedNotProcessed (0),
287
  m_winScalingEnabled (false),
288
  m_winScalingEnabled (0),
288
  m_rcvWindShift (0),
289
  m_rcvWindShift (0),
289
  m_sndWindShift (0),
290
  m_sndWindShift (0),
290
  m_timestampEnabled (true),
291
  m_timestampEnabled (true),
 Lines 1164-1171   TcpSocketBase::DoForwardUp (Ptr<Packet> packet, const Address &fromAddress, Link Here 
1164
1165
1165
  m_rxTrace (packet, tcpHeader, this);
1166
  m_rxTrace (packet, tcpHeader, this);
1166
1167
1167
  ReadOptions (tcpHeader);
1168
1169
  if (tcpHeader.GetFlags () & TcpHeader::SYN)
1168
  if (tcpHeader.GetFlags () & TcpHeader::SYN)
1170
    {
1169
    {
1171
      /* The window field in a segment where the SYN bit is set (i.e., a <SYN>
1170
      /* The window field in a segment where the SYN bit is set (i.e., a <SYN>
 Lines 1174-1194   TcpSocketBase::DoForwardUp (Ptr<Packet> packet, const Address &fromAddress, Link Here 
1174
       */
1173
       */
1175
      m_rWnd = tcpHeader.GetWindowSize ();
1174
      m_rWnd = tcpHeader.GetWindowSize ();
1176
1175
1177
      if (m_tcb->m_initialSsThresh == UINT32_MAX)
1176
      /* RFC 7323, Section 2.2
1177
       *
1178
       * "If a Window Scale option was received in the initial <SYN> segment,
1179
       * then this option MAY be sent in the <SYN,ACK> segment."
1180
       *
1181
       * RFC 7323, Section 2.3
1182
       *
1183
       * "If a TCP receives a <SYN> segment containing a Window Scale
1184
       * option, it SHOULD send its own Window Scale option in the
1185
       * <SYN,ACK> segment."
1186
       *
1187
       * RFC is incostistent in case a <SYN> contains WS option, but the
1188
       * user disabled it through Attributes.
1189
       * As choice, we use the latter approach, enabling WS but advertising
1190
       * 1 as shift, regardless of the buffer size (and doing so we pratically
1191
       * disable the window scale, keeping the send of the option)
1192
       */
1193
      if (tcpHeader.HasOption (TcpOption::WINSCALE))
1178
        {
1194
        {
1179
          m_tcb->m_initialSsThresh = m_rWnd << m_sndWindShift;
1195
          ProcessOptionWScale (tcpHeader.GetOption (TcpOption::WINSCALE));
1196
1197
          if (tcpHeader.GetFlags () == TcpHeader::SYN && m_winScalingEnabled == 0)
1198
            {
1199
              // This is a plain <SYN> with WS enabled, but users choice is
1200
              // to disable our WS side. <SYN-ACK> will have WS option with shift = 1
1201
              m_winScalingEnabled = 2;
1202
            }
1203
1204
          if (m_tcb->m_initialSsThresh == UINT32_MAX)
1205
            {
1206
              m_tcb->m_initialSsThresh = m_rWnd << m_sndWindShift;
1207
            }
1208
        }
1209
      else
1210
        {
1211
          // Disable window scaling at all; our peer does not support it.
1212
          m_winScalingEnabled = 0;
1213
        }
1214
1215
      // When receiving a <SYN> or <SYN-ACK> we should adapt TS to the other end
1216
      if (tcpHeader.HasOption (TcpOption::TS) && m_timestampEnabled)
1217
        {
1218
          ProcessOptionTimestamp (tcpHeader.GetOption (TcpOption::TS));
1219
        }
1220
      else
1221
        {
1222
          m_timestampEnabled = false;
1180
        }
1223
        }
1181
1224
1225
      // Initialize cWnd and ssThresh
1182
      m_tcb->m_cWnd = GetInitialCwnd () * GetSegSize ();
1226
      m_tcb->m_cWnd = GetInitialCwnd () * GetSegSize ();
1183
      m_tcb->m_ssThresh = GetInitialSSThresh ();
1227
      m_tcb->m_ssThresh = GetInitialSSThresh ();
1184
    }
1228
    }
1185
  else if (tcpHeader.GetFlags () & TcpHeader::ACK)
1229
  else if (tcpHeader.GetFlags () & TcpHeader::ACK)
1186
    {
1230
    {
1231
      if (m_timestampEnabled)
1232
        {
1233
          if (tcpHeader.HasOption (TcpOption::TS))
1234
            {
1235
              ProcessOptionTimestamp (tcpHeader.GetOption (TcpOption::TS));
1236
            }
1237
          else
1238
            {
1239
              NS_LOG_LOGIC ("At state " << TcpStateName[m_state] <<
1240
                            " received packet of seq [" << seq <<
1241
                            ":" << seq + packet->GetSize () <<
1242
                            ") without TS option. Silently discard it");
1243
              return;
1244
            }
1245
        }
1246
1187
      EstimateRtt (tcpHeader);
1247
      EstimateRtt (tcpHeader);
1188
      UpdateWindowSize (tcpHeader);
1248
      UpdateWindowSize (tcpHeader);
1189
    }
1249
    }
1190
1250
1191
1192
  if (m_rWnd.Get () == 0 && m_persistEvent.IsExpired ())
1251
  if (m_rWnd.Get () == 0 && m_persistEvent.IsExpired ())
1193
    { // Zero window: Enter persist state to send 1 byte to probe
1252
    { // Zero window: Enter persist state to send 1 byte to probe
1194
      NS_LOG_LOGIC (this << " Enter zerowindow persist state");
1253
      NS_LOG_LOGIC (this << " Enter zerowindow persist state");
 Lines 3079-3119   TcpSocketBase::GetAllowBroadcast (void) const Link Here 
3079
}
3138
}
3080
3139
3081
void
3140
void
3082
TcpSocketBase::ReadOptions (const TcpHeader& header)
3083
{
3084
  NS_LOG_FUNCTION (this << header);
3085
3086
  if ((header.GetFlags () & TcpHeader::SYN))
3087
    {
3088
      if (m_winScalingEnabled)
3089
        {
3090
          m_winScalingEnabled = false;
3091
3092
          if (header.HasOption (TcpOption::WINSCALE))
3093
            {
3094
              m_winScalingEnabled = true;
3095
              ProcessOptionWScale (header.GetOption (TcpOption::WINSCALE));
3096
            }
3097
        }
3098
    }
3099
3100
  bool timestampAttribute = m_timestampEnabled;
3101
  m_timestampEnabled = false;
3102
3103
  if (header.HasOption (TcpOption::TS) && timestampAttribute)
3104
    {
3105
      m_timestampEnabled = true;
3106
      ProcessOptionTimestamp (header.GetOption (TcpOption::TS));
3107
    }
3108
}
3109
3110
void
3111
TcpSocketBase::AddOptions (TcpHeader& header)
3141
TcpSocketBase::AddOptions (TcpHeader& header)
3112
{
3142
{
3113
  NS_LOG_FUNCTION (this << header);
3143
  NS_LOG_FUNCTION (this << header);
3114
3144
3115
  // The window scaling option is set only on SYN packets
3145
  // The window scaling option is set only on SYN packets
3116
  if (m_winScalingEnabled && (header.GetFlags () & TcpHeader::SYN))
3146
  if ((header.GetFlags () & TcpHeader::SYN) && m_winScalingEnabled > 0)
3117
    {
3147
    {
3118
      AddOptionWScale (header);
3148
      AddOptionWScale (header);
3119
    }
3149
    }
 Lines 3170-3175   TcpSocketBase::CalculateWScale () const Link Here 
3170
}
3200
}
3171
3201
3172
void
3202
void
3203
TcpSocketBase::EnableWSOption (bool enable)
3204
{
3205
  if (enable)
3206
    {
3207
      m_winScalingEnabled = 1;
3208
    }
3209
  else
3210
    {
3211
      m_winScalingEnabled = 0;
3212
    }
3213
}
3214
3215
bool
3216
TcpSocketBase::GetWSOptionEnabled (void) const
3217
{
3218
  return m_winScalingEnabled == 1;
3219
}
3220
3221
void
3173
TcpSocketBase::AddOptionWScale (TcpHeader &header)
3222
TcpSocketBase::AddOptionWScale (TcpHeader &header)
3174
{
3223
{
3175
  NS_LOG_FUNCTION (this << header);
3224
  NS_LOG_FUNCTION (this << header);
 Lines 3177-3186   TcpSocketBase::AddOptionWScale (TcpHeader &header) Link Here 
3177
3226
3178
  Ptr<TcpOptionWinScale> option = CreateObject<TcpOptionWinScale> ();
3227
  Ptr<TcpOptionWinScale> option = CreateObject<TcpOptionWinScale> ();
3179
3228
3180
  // In naming, we do the contrary of RFC 1323. The sended scaling factor
3229
  if (m_winScalingEnabled == 2)
3181
  // is Snd.Wind.Scale (and not Rcv.Wind.Scale)
3230
    {
3231
      m_rcvWindShift = 1;
3232
    }
3233
  else
3234
    {
3235
      m_rcvWindShift = CalculateWScale ();
3236
    }
3182
3237
3183
  m_rcvWindShift = CalculateWScale ();
3184
  option->SetScale (m_rcvWindShift);
3238
  option->SetScale (m_rcvWindShift);
3185
3239
3186
  header.AppendOption (option);
3240
  header.AppendOption (option);
(-)a/src/internet/model/tcp-socket-base.h (-15 / +22 lines)
 Lines 824-843   protected: Link Here 
824
   */
824
   */
825
  virtual void DoRetransmit (void);
825
  virtual void DoRetransmit (void);
826
826
827
  /**
828
   * \brief Read TCP options from incoming packets
829
   *
830
   * This method sequentially checks each kind of option, and if it
831
   * is present in the header, starts its processing.
832
   *
833
   * To deal with hosts which don't have the option enabled (or
834
   * implemented) we disable all options, and then re-enable them
835
   * if in the packet there is the option itself.
836
   *
837
   * \param tcpHeader the packet's TCP header
838
   */
839
  virtual void ReadOptions (const TcpHeader& tcpHeader);
840
841
  /** \brief Add options to TcpHeader
827
  /** \brief Add options to TcpHeader
842
   *
828
   *
843
   * Test each option, and if it is enabled on our side, add it
829
   * Test each option, and if it is enabled on our side, add it
 Lines 875-880   protected: Link Here 
875
   */
861
   */
876
  uint8_t CalculateWScale () const;
862
  uint8_t CalculateWScale () const;
877
863
864
  /**
865
   * \brief Enable the window scale option
866
   *
867
   * \param enable true to enable ws option
868
   */
869
  void EnableWSOption (bool enable);
870
871
  /**
872
   * \brief Return true if the window scale option is enabled
873
   *
874
   * \return true if the window scale option is enabled
875
   */
876
  bool GetWSOptionEnabled (void) const;
877
878
  /** \brief Process the timestamp option from other side
878
  /** \brief Process the timestamp option from other side
879
   *
879
   *
880
   * Get the timestamp and the echo, then save timestamp (which will
880
   * Get the timestamp and the echo, then save timestamp (which will
 Lines 953-959   protected: Link Here 
953
  uint32_t                      m_bytesAckedNotProcessed;  //!< Bytes acked, but not processed
953
  uint32_t                      m_bytesAckedNotProcessed;  //!< Bytes acked, but not processed
954
954
955
  // Options
955
  // Options
956
  bool    m_winScalingEnabled; //!< Window Scale option enabled (RFC 7323)
956
  uint8_t m_winScalingEnabled; /**!< Window Scale option enabled (RFC 7323).
957
                                 *   0 = disabled
958
                                 *   1 = enabled
959
                                 *   2 = partially enabled (enabled but forcing shift = 1)
960
                                 *
961
                                 * \see DoForwardUp
962
                                 */
963
957
  uint8_t m_rcvWindShift;      //!< Window shift to apply to outgoing segments
964
  uint8_t m_rcvWindShift;      //!< Window shift to apply to outgoing segments
958
  uint8_t m_sndWindShift;      //!< Window shift to apply to incoming segments
965
  uint8_t m_sndWindShift;      //!< Window shift to apply to incoming segments
959
966
(-)a/src/internet/test/tcp-wscaling-test.cc (-2 / +2 lines)
 Lines 162-169   WScalingTestCase::Tx (const Ptr<const Packet> p, const TcpHeader &h, SocketWho w Link Here 
162
            }
162
            }
163
          else if (m_configuration == ENABLED_SENDER)
163
          else if (m_configuration == ENABLED_SENDER)
164
            {
164
            {
165
              NS_TEST_ASSERT_MSG_EQ (h.HasOption (TcpOption::WINSCALE), false,
165
              NS_TEST_ASSERT_MSG_EQ (h.HasOption (TcpOption::WINSCALE), true,
166
                                     "receiver has not ws enabled but sent anyway");
166
                                     "receiver should have ws enabled with shift = 1");
167
            }
167
            }
168
        }
168
        }
169
    }
169
    }

Return to bug 2068