mirror of https://github.com/acidanthera/audk.git
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;
|
|
}
|