mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 12:54:17 +00:00 
			
		
		
		
	git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@7147 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			381 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			381 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Routines to process TCP option.
 | 
						|
    
 | 
						|
Copyright (c) 2005 - 2006, Intel Corporation<BR>
 | 
						|
All rights reserved. This program and the accompanying materials
 | 
						|
are licensed and made available under the terms and conditions of the BSD License
 | 
						|
which accompanies this distribution.  The full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php<BR>
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "Tcp4Main.h"
 | 
						|
 | 
						|
/**
 | 
						|
    Get a UINT16 value from buffer.
 | 
						|
    
 | 
						|
    @param Buf                  Pointer to input buffer.
 | 
						|
    
 | 
						|
    @return                     The UINT16 value get from buffer.
 | 
						|
 | 
						|
**/
 | 
						|
UINT16
 | 
						|
TcpGetUint16 (
 | 
						|
  IN UINT8 *Buf
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16  Value;
 | 
						|
  CopyMem (&Value, Buf, sizeof (UINT16));
 | 
						|
  return NTOHS (Value);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
    Get a UINT32 value from buffer.
 | 
						|
    
 | 
						|
    @param Buf                  Pointer to input buffer.
 | 
						|
    
 | 
						|
    @return                     The UINT32 value get from buffer.
 | 
						|
 | 
						|
**/
 | 
						|
UINT32
 | 
						|
TcpGetUint32 (
 | 
						|
  IN UINT8 *Buf
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32  Value;
 | 
						|
  CopyMem (&Value, Buf, sizeof (UINT32));
 | 
						|
  return NTOHL (Value);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
    Put a UINT32 value in buffer.
 | 
						|
    
 | 
						|
    @param Buf                  Pointer to the buffer.
 | 
						|
    @param Data                 The UINT32 Date to put in buffer 
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
TcpPutUint32 (
 | 
						|
     OUT UINT8  *Buf,
 | 
						|
  IN     UINT32 Data
 | 
						|
  )
 | 
						|
{
 | 
						|
  Data = HTONL (Data);
 | 
						|
  CopyMem (Buf, &Data, sizeof (UINT32));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Compute the window scale value according to the given buffer size.
 | 
						|
 | 
						|
  @param  Tcb     Pointer to the TCP_CB of this TCP instance.
 | 
						|
 | 
						|
  @return         The scale value.
 | 
						|
 | 
						|
**/
 | 
						|
UINT8
 | 
						|
TcpComputeScale (
 | 
						|
  IN TCP_CB *Tcb
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8   Scale;
 | 
						|
  UINT32  BufSize;
 | 
						|
 | 
						|
  ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));
 | 
						|
 | 
						|
  BufSize = GET_RCV_BUFFSIZE (Tcb->Sk);
 | 
						|
 | 
						|
  Scale   = 0;
 | 
						|
  while ((Scale < TCP_OPTION_MAX_WS) &&
 | 
						|
         ((UINT32) (TCP_OPTION_MAX_WIN << Scale) < BufSize)) {
 | 
						|
 | 
						|
    Scale++;
 | 
						|
  }
 | 
						|
 | 
						|
  return Scale;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Build the TCP option in three-way handshake.
 | 
						|
 | 
						|
  @param  Tcb     Pointer to the TCP_CB of this TCP instance.
 | 
						|
  @param  Nbuf    Pointer to the buffer to store the options.
 | 
						|
 | 
						|
  @return         The total length of the TCP option field.
 | 
						|
 | 
						|
**/
 | 
						|
UINT16
 | 
						|
TcpSynBuildOption (
 | 
						|
  IN TCP_CB  *Tcb,
 | 
						|
  IN NET_BUF *Nbuf
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8   *Data;
 | 
						|
  UINT16  Len;
 | 
						|
 | 
						|
  ASSERT ((Tcb != NULL) && (Nbuf != NULL) && (Nbuf->Tcp == NULL));
 | 
						|
 | 
						|
  Len = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // Add timestamp option if not disabled by application
 | 
						|
  // and it is the first SYN segment or the peer has sent
 | 
						|
  // us its timestamp.
 | 
						|
  //
 | 
						|
  if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS) &&
 | 
						|
      (!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||
 | 
						|
        TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS))) {
 | 
						|
 | 
						|
    Data = NetbufAllocSpace (
 | 
						|
            Nbuf,
 | 
						|
            TCP_OPTION_TS_ALIGNED_LEN,
 | 
						|
            NET_BUF_HEAD
 | 
						|
            );
 | 
						|
 | 
						|
    ASSERT (Data != NULL);
 | 
						|
    Len += TCP_OPTION_TS_ALIGNED_LEN;
 | 
						|
 | 
						|
    TcpPutUint32 (Data, TCP_OPTION_TS_FAST);
 | 
						|
    TcpPutUint32 (Data + 4, mTcpTick);
 | 
						|
    TcpPutUint32 (Data + 8, 0);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Build window scale option, only when are configured
 | 
						|
  // to send WS option, and either we are doing active
 | 
						|
  // open or we have received WS option from peer.
 | 
						|
  //
 | 
						|
  if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS) &&
 | 
						|
      (!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||
 | 
						|
        TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_WS))) {
 | 
						|
 | 
						|
    Data = NetbufAllocSpace (
 | 
						|
            Nbuf,
 | 
						|
            TCP_OPTION_WS_ALIGNED_LEN,
 | 
						|
            NET_BUF_HEAD
 | 
						|
            );
 | 
						|
 | 
						|
    ASSERT (Data != NULL);
 | 
						|
 | 
						|
    Len += TCP_OPTION_WS_ALIGNED_LEN;
 | 
						|
    TcpPutUint32 (Data, TCP_OPTION_WS_FAST | TcpComputeScale (Tcb));
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Build MSS option
 | 
						|
  //
 | 
						|
  Data = NetbufAllocSpace (Nbuf, TCP_OPTION_MSS_LEN, 1);
 | 
						|
  ASSERT (Data != NULL);
 | 
						|
 | 
						|
  Len += TCP_OPTION_MSS_LEN;
 | 
						|
  TcpPutUint32 (Data, TCP_OPTION_MSS_FAST | Tcb->RcvMss);
 | 
						|
 | 
						|
  return Len;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Build the TCP option in synchronized states.
 | 
						|
 | 
						|
  @param  Tcb     Pointer to the TCP_CB of this TCP instance.
 | 
						|
  @param  Nbuf    Pointer to the buffer to store the options.
 | 
						|
 | 
						|
  @return         The total length of the TCP option field.
 | 
						|
 | 
						|
**/
 | 
						|
UINT16
 | 
						|
TcpBuildOption (
 | 
						|
  IN TCP_CB  *Tcb,
 | 
						|
  IN NET_BUF *Nbuf
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8   *Data;
 | 
						|
  UINT16  Len;
 | 
						|
 | 
						|
  ASSERT ((Tcb != NULL) && (Nbuf != NULL) && (Nbuf->Tcp == NULL));
 | 
						|
  Len = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // Build Timestamp option
 | 
						|
  //
 | 
						|
  if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_TS) &&
 | 
						|
      !TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_RST)) {
 | 
						|
 | 
						|
    Data = NetbufAllocSpace (
 | 
						|
            Nbuf,
 | 
						|
            TCP_OPTION_TS_ALIGNED_LEN,
 | 
						|
            NET_BUF_HEAD
 | 
						|
            );
 | 
						|
 | 
						|
    ASSERT (Data != NULL);
 | 
						|
    Len += TCP_OPTION_TS_ALIGNED_LEN;
 | 
						|
 | 
						|
    TcpPutUint32 (Data, TCP_OPTION_TS_FAST);
 | 
						|
    TcpPutUint32 (Data + 4, mTcpTick);
 | 
						|
    TcpPutUint32 (Data + 8, Tcb->TsRecent);
 | 
						|
  }
 | 
						|
 | 
						|
  return Len;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Parse the supported options.
 | 
						|
 | 
						|
  @param  Tcp     Pointer to the TCP_CB of this TCP instance.
 | 
						|
  @param  Option  Pointer to the TCP_OPTION used to store the successfully pasrsed
 | 
						|
                  options.
 | 
						|
 | 
						|
  @retval 0       The options are successfully pasrsed.
 | 
						|
  @retval -1      Ilegal option was found.
 | 
						|
 | 
						|
**/
 | 
						|
INTN
 | 
						|
TcpParseOption (
 | 
						|
  IN     TCP_HEAD   *Tcp,
 | 
						|
  IN OUT TCP_OPTION *Option
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8 *Head;
 | 
						|
  UINT8 TotalLen;
 | 
						|
  UINT8 Cur;
 | 
						|
  UINT8 Type;
 | 
						|
  UINT8 Len;
 | 
						|
 | 
						|
  ASSERT ((Tcp != NULL) && (Option != NULL));
 | 
						|
 | 
						|
  Option->Flag  = 0;
 | 
						|
 | 
						|
  TotalLen      = (UINT8) ((Tcp->HeadLen << 2) - sizeof (TCP_HEAD));
 | 
						|
  if (TotalLen <= 0) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  Head = (UINT8 *) (Tcp + 1);
 | 
						|
 | 
						|
  //
 | 
						|
  // Fast process of timestamp option
 | 
						|
  //
 | 
						|
  if ((TotalLen == TCP_OPTION_TS_ALIGNED_LEN) &&
 | 
						|
      (TcpGetUint32 (Head) == TCP_OPTION_TS_FAST)) {
 | 
						|
 | 
						|
    Option->TSVal = TcpGetUint32 (Head + 4);
 | 
						|
    Option->TSEcr = TcpGetUint32 (Head + 8);
 | 
						|
    Option->Flag  = TCP_OPTION_RCVD_TS;
 | 
						|
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Slow path to process the options.
 | 
						|
  //
 | 
						|
  Cur = 0;
 | 
						|
 | 
						|
  while (Cur < TotalLen) {
 | 
						|
    Type = Head[Cur];
 | 
						|
 | 
						|
    switch (Type) {
 | 
						|
    case TCP_OPTION_MSS:
 | 
						|
      Len = Head[Cur + 1];
 | 
						|
 | 
						|
      if ((Len != TCP_OPTION_MSS_LEN) ||
 | 
						|
          (TotalLen - Cur < TCP_OPTION_MSS_LEN)) {
 | 
						|
 | 
						|
        return -1;
 | 
						|
      }
 | 
						|
 | 
						|
      Option->Mss = TcpGetUint16 (&Head[Cur + 2]);
 | 
						|
      TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_MSS);
 | 
						|
 | 
						|
      Cur += TCP_OPTION_MSS_LEN;
 | 
						|
      break;
 | 
						|
 | 
						|
    case TCP_OPTION_WS:
 | 
						|
      Len = Head[Cur + 1];
 | 
						|
 | 
						|
      if ((Len != TCP_OPTION_WS_LEN) ||
 | 
						|
          (TotalLen - Cur < TCP_OPTION_WS_LEN)) {
 | 
						|
 | 
						|
        return -1;
 | 
						|
      }
 | 
						|
 | 
						|
      Option->WndScale = (UINT8) MIN (14, Head[Cur + 2]);
 | 
						|
      TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_WS);
 | 
						|
 | 
						|
      Cur += TCP_OPTION_WS_LEN;
 | 
						|
      break;
 | 
						|
 | 
						|
    case TCP_OPTION_TS:
 | 
						|
      Len = Head[Cur + 1];
 | 
						|
 | 
						|
      if ((Len != TCP_OPTION_TS_LEN) ||
 | 
						|
          (TotalLen - Cur < TCP_OPTION_TS_LEN)) {
 | 
						|
 | 
						|
        return -1;
 | 
						|
      }
 | 
						|
 | 
						|
      Option->TSVal = TcpGetUint32 (&Head[Cur + 2]);
 | 
						|
      Option->TSEcr = TcpGetUint32 (&Head[Cur + 6]);
 | 
						|
      TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_TS);
 | 
						|
 | 
						|
      Cur += TCP_OPTION_TS_LEN;
 | 
						|
      break;
 | 
						|
 | 
						|
    case TCP_OPTION_NOP:
 | 
						|
      Cur++;
 | 
						|
      break;
 | 
						|
 | 
						|
    case TCP_OPTION_EOP:
 | 
						|
      Cur = TotalLen;
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      Len = Head[Cur + 1];
 | 
						|
 | 
						|
      if ((TotalLen - Cur) < Len || Len < 2) {
 | 
						|
        return -1;
 | 
						|
      }
 | 
						|
 | 
						|
      Cur = (UINT8) (Cur + Len);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Check the segment against PAWS.
 | 
						|
 | 
						|
  @param  Tcb     Pointer to the TCP_CB of this TCP instance.
 | 
						|
  @param  TSVal   The timestamp value.
 | 
						|
 | 
						|
  @retval 1       The segment passed the PAWS check.
 | 
						|
  @retval 0       The segment failed to pass the PAWS check.
 | 
						|
 | 
						|
**/
 | 
						|
UINT32
 | 
						|
TcpPawsOK (
 | 
						|
  IN TCP_CB *Tcb,
 | 
						|
  IN UINT32 TSVal
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // PAWS as defined in RFC1323, buggy...
 | 
						|
  //
 | 
						|
  if (TCP_TIME_LT (TSVal, Tcb->TsRecent) &&
 | 
						|
      TCP_TIME_LT (Tcb->TsRecentAge + TCP_PAWS_24DAY, mTcpTick)) {
 | 
						|
 | 
						|
    return 0;
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  return 1;
 | 
						|
}
 |