mirror of https://github.com/acidanthera/audk.git
375 lines
8.0 KiB
C
375 lines
8.0 KiB
C
|
/** @file
|
||
|
Routines to process TCP option.
|
||
|
|
||
|
Copyright (c) 2009 - 2010, 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.
|
||
|
|
||
|
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 "TcpMain.h"
|
||
|
|
||
|
/**
|
||
|
Get a UINT16 value from buffer.
|
||
|
|
||
|
@param[in] Buf Pointer to input buffer.
|
||
|
|
||
|
@return The UINT16 value obtained from the buffer.
|
||
|
|
||
|
**/
|
||
|
UINT16
|
||
|
TcpGetUint16 (
|
||
|
IN UINT8 *Buf
|
||
|
)
|
||
|
{
|
||
|
UINT16 Value;
|
||
|
CopyMem (&Value, Buf, sizeof (UINT16));
|
||
|
return NTOHS (Value);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Get a UINT32 value from buffer.
|
||
|
|
||
|
@param[in] Buf Pointer to input buffer.
|
||
|
|
||
|
@return The UINT32 value obtained from the buffer.
|
||
|
|
||
|
**/
|
||
|
UINT32
|
||
|
TcpGetUint32 (
|
||
|
IN UINT8 *Buf
|
||
|
)
|
||
|
{
|
||
|
UINT32 Value;
|
||
|
CopyMem (&Value, Buf, sizeof (UINT32));
|
||
|
return NTOHL (Value);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Put a UINT32 value in buffer.
|
||
|
|
||
|
@param[out] Buf Pointer to the buffer.
|
||
|
@param[in] Data The UINT32 Date to put in the 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[in] 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[in] Tcb Pointer to the TCP_CB of this TCP instance.
|
||
|
@param[in] 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 a timestamp option if not disabled by the 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 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 the 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[in] Tcb Pointer to the TCP_CB of this TCP instance.
|
||
|
@param[in] 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 the 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[in] Tcp Pointer to the TCP_CB of this TCP instance.
|
||
|
@param[in, out] 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 the 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[in] Tcb Pointer to the TCP_CB of this TCP instance.
|
||
|
@param[in] 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;
|
||
|
}
|