git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10418 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. All rights reserved.<BR>
 | |
| 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;
 | |
| }
 |