tcp4input.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,546 行 · 第 1/3 页
C
1,546 行
TcpClearAllTimer (Tcb);
if (Tcb->TimeWaitTimeout != 0) {
TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);
} else {
TCP4_DEBUG_WARN (("Connection closed immediately "
"because app disables TIME_WAIT timer for %x\n", Tcb));
TcpSendAck (Tcb);
TcpClose (Tcb);
}
break;
case TCP_CLOSE_WAIT:
case TCP_CLOSING:
case TCP_LAST_ACK:
case TCP_TIME_WAIT:
//
// The peer sends to us junk FIN byte. Discard
// the buffer then reset the connection
//
NetbufFree (Nbuf);
return -1;
break;
}
TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
Seg->End--;
}
//
// Don't delay the ack if PUSH flag is on.
//
if (TCP_FLG_ON (Seg->Flag, TCP_FLG_PSH)) {
TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
}
if (Nbuf->TotalSize) {
Urgent = 0;
if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&
TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvUp)) {
if (TCP_SEQ_LEQ (Seg->End, Tcb->RcvUp)) {
Urgent = Nbuf->TotalSize;
} else {
Urgent = TCP_SUB_SEQ (Tcb->RcvUp, Seg->Seq) + 1;
}
}
SockDataRcvd (Tcb->Sk, Nbuf, Urgent);
}
if (TCP_FIN_RCVD (Tcb->State)) {
SockNoMoreData (Tcb->Sk);
}
NetbufFree (Nbuf);
}
return 0;
}
VOID
TcpQueueData (
IN TCP_CB *Tcb,
IN NET_BUF *Nbuf
)
/*++
Routine Description:
Store the data into the reassemble queue.
Arguments:
Tcb - Pointer to the TCP_CB of this TCP instance.
Nbuf - Pointer to the buffer containing the data to be queued.
Returns:
None.
--*/
{
TCP_SEG *Seg;
NET_LIST_ENTRY *Head;
NET_LIST_ENTRY *Prev;
NET_LIST_ENTRY *Cur;
NET_BUF *Node;
ASSERT (Tcb && Nbuf && (Nbuf->Tcp == NULL));
NET_GET_REF (Nbuf);
Seg = TCPSEG_NETBUF (Nbuf);
Head = &Tcb->RcvQue;
//
// Fast path to process normal case. That is,
// no out-of-order segments are received.
//
if (NetListIsEmpty (Head)) {
NetListInsertTail (Head, &Nbuf->List);
return ;
}
//
// Find the point to insert the buffer
//
for (Prev = Head, Cur = Head->ForwardLink;
Cur != Head;
Prev = Cur, Cur = Cur->ForwardLink) {
Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->Seq)) {
break;
}
}
//
// Check whether the current segment overlaps with the
// previous segment.
//
if (Prev != Head) {
Node = NET_LIST_USER_STRUCT (Prev, NET_BUF, List);
if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->End)) {
if (TCP_SEQ_LEQ (Seg->End, TCPSEG_NETBUF (Node)->End)) {
NetbufFree (Nbuf);
return ;
}
TcpTrimSegment (Nbuf, TCPSEG_NETBUF (Node)->End, Seg->End);
}
}
NetListInsertHead (Prev, &Nbuf->List);
TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
//
// Check the segments after the insert point.
//
while (Cur != Head) {
Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->End, Seg->End)) {
Cur = Cur->ForwardLink;
NetListRemoveEntry (&Node->List);
NetbufFree (Node);
continue;
}
if (TCP_SEQ_LT (TCPSEG_NETBUF (Node)->Seq, Seg->End)) {
if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->Seq, Seg->Seq)) {
NetListRemoveEntry (&Nbuf->List);
NetbufFree (Nbuf);
return ;
}
TcpTrimSegment (Nbuf, Seg->Seq, TCPSEG_NETBUF (Node)->Seq);
break;
}
Cur = Cur->ForwardLink;
}
}
VOID
TcpAdjustSndQue (
IN TCP_CB *Tcb,
IN TCP_SEQNO Ack
)
/*++
Routine Description:
Ajust the send queue or the retransmit queue.
Arguments:
Tcb - Pointer to the TCP_CB of this TCP instance.
Ack - The acknowledge seuqence number of the received segment.
Returns:
None.
--*/
{
NET_LIST_ENTRY *Head;
NET_LIST_ENTRY *Cur;
NET_BUF *Node;
TCP_SEG *Seg;
Head = &Tcb->SndQue;
Cur = Head->ForwardLink;
while (Cur != Head) {
Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
Seg = TCPSEG_NETBUF (Node);
if (TCP_SEQ_GEQ (Seg->Seq, Ack)) {
break;
}
//
// Remove completely ACKed segments
//
if (TCP_SEQ_LEQ (Seg->End, Ack)) {
Cur = Cur->ForwardLink;
NetListRemoveEntry (&Node->List);
NetbufFree (Node);
continue;
}
TcpTrimSegment (Node, Ack, Seg->End);
break;
}
}
INTN
TcpInput (
IN NET_BUF *Nbuf,
IN UINT32 Src,
IN UINT32 Dst
)
/*++
Routine Description:
Process the received TCP segments.
Arguments:
Nbuf - Buffer that contains received TCP segment without IP header.
Src - Source address of the segment, or the peer's IP address.
Dst - Destination address of the segment, or the local end's IP address.
Returns:
0 - Segment is processed successfully. It is either accepted or discarded.
But no connection is reset by the segment.
-1 - A connection is reset by the segment.
--*/
{
TCP_CB *Tcb;
TCP_CB *Parent;
TCP_OPTION Option;
TCP_HEAD *Head;
INT32 Len;
TCP_SEG *Seg;
TCP_SEQNO Right;
TCP_SEQNO Urg;
NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
Parent = NULL;
Tcb = NULL;
Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);
Len = Nbuf->TotalSize - (Head->HeadLen << 2);
if ((Head->HeadLen < 5) || (Len < 0) ||
TcpChecksum (Nbuf, NetPseudoHeadChecksum (Src, Dst, 6, 0))) {
TCP4_DEBUG_TRACE (("TcpInput: received an mal-formated packet\n"));
goto DISCARD;
}
if (TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)) {
Len++;
}
if (TCP_FLG_ON (Head->Flag, TCP_FLG_FIN)) {
Len++;
}
Tcb = TcpLocateTcb (
Head->DstPort,
Dst,
Head->SrcPort,
Src,
(BOOLEAN) TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)
);
if ((Tcb == NULL) || (Tcb->State == TCP_CLOSED)) {
TCP4_DEBUG_TRACE (("TcpInput: send reset because no TCB find\n"));
Tcb = NULL;
goto SEND_RESET;
}
Seg = TcpFormatNetbuf (Tcb, Nbuf);
//
// RFC1122 recommended reaction to illegal option
// (in fact, an illegal option length) is reset.
//
if (TcpParseOption (Nbuf->Tcp, &Option) == -1) {
TCP4_DEBUG_ERROR (("TcpInput: reset the peer because"
" of mal-format option for Tcb %x\n", Tcb));
goto SEND_RESET;
}
//
// From now on, the segment is headless
//
NetbufTrim (Nbuf, (Head->HeadLen << 2), NET_BUF_HEAD);
Nbuf->Tcp = NULL;
//
// TODO: add fast path process here
//
//
// Process the segment in LISTEN state.
//
if (Tcb->State == TCP_LISTEN) {
//
// First step: Check RST
//
if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {
TCP4_DEBUG_WARN (("TcpInput: discard a reset segment "
"for TCB %x in listening\n", Tcb));
goto DISCARD;
}
//
// Second step: Check ACK.
// Any ACK sent to TCP in LISTEN is reseted.
//
if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
TCP4_DEBUG_WARN (("TcpInput: send reset because of"
" segment with ACK for TCB %x in listening\n", Tcb));
goto SEND_RESET;
}
//
// Third step: Check SYN
//
if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
//
// create a child TCB to handle the data
//
Parent = Tcb;
Tcb = TcpCloneTcb (Parent);
if (Tcb == NULL) {
TCP4_DEBUG_ERROR (("TcpInput: discard a segment because"
"failed to clone a child for TCB%x\n", Tcb));
goto DISCARD;
}
TCP4_DEBUG_TRACE (("TcpInput: create a child for TCB %x"
" in listening\n", Tcb));
//
// init the TCB structure
//
Tcb->LocalEnd.Ip = Dst;
Tcb->LocalEnd.Port = Head->DstPort;
Tcb->RemoteEnd.Ip = Src;
Tcb->RemoteEnd.Port = Head->SrcPort;
TcpInitTcbLocal (Tcb);
TcpInitTcbPeer (Tcb, Seg, &Option);
TcpSetState (Tcb, TCP_SYN_RCVD);
TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);
TcpTrimInWnd (Tcb, Nbuf);
goto StepSix;
}
goto DISCARD;
} else if (Tcb->State == TCP_SYN_SENT) {
//
// First step: Check ACK bit
//
if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK) && (Seg->Ack != Tcb->Iss + 1)) {
TCP4_DEBUG_WARN (("TcpInput: send reset because of "
"wrong ACK received for TCB %x in SYN_SENT\n", Tcb));
goto SEND_RESET;
}
//
// Second step: Check RST bit
//
if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {
if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
TCP4_DEBUG_WARN (("TcpInput: connection reset by"
" peer for TCB%x in SYN_SENT\n", Tcb));
SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);
goto DROP_CONNECTION;
} else {
TCP4_DEBUG_WARN (("TcpInput: discard a reset segment "
"because of no ACK for TCB%x in SYN_SENT\n", Tcb));
goto DISCARD;
}
}
//
// Third step: Check security and precedence. Skipped
//
//
// Fourth step: Check SYN. Pay attention to sitimulatous open
//
if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
TcpInitTcbPeer (Tcb, Seg, &Option);
if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
Tcb->SndUna = Seg->Ack;
}
TcpClearTimer (Tcb, TCP_TIMER_REXMIT);
if (TCP_SEQ_GT (Tcb->SndUna, Tcb->Iss)) {
TcpSetState (Tcb, TCP_ESTABLISHED);
TcpClearTimer (Tcb, TCP_TIMER_CONNECT);
TcpDeliverData (Tcb);
if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&
TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {
TcpComputeRtt (Tcb, Tcb->RttMeasure);
TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
}
TcpTrimInWnd (Tcb, Nbuf);
TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
TCP4_DEBUG_TRACE (("TcpInput: connection established"
" for TCB %x in SYN_SENT\n", Tcb));
goto StepSix;
} else {
//
// Received a SYN segment without ACK, simultanous open.
//
TcpSetState (Tcb, TCP_SYN_RCVD);
ASSERT (Tcb->SndNxt == Tcb->Iss + 1);
TcpAdjustSndQue (Tcb, Tcb->SndNxt);
TcpTrimInWnd (Tcb, Nbuf);
TCP4_DEBUG_WARN (("TcpInput: simultanous open "
"for TCB %x in SYN_SENT\n", Tcb));
goto StepSix;
}
}
goto DISCARD;
}
//
// Process segment in SYN_RCVD or TCP_CONNECTED states
//
//
// First step: Check whether SEG.SEQ is acceptable
//
if (!TcpSeqAcceptable (Tcb, Seg)) {
TCP4_DEBUG_WARN (("TcpInput: sequence acceptance"
" test failed for segment of TCB %x\n", Tcb));
if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {
TcpSendAck (Tcb);
}
goto DISCARD;
}
if ((TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2)) &&
(Tcb->RcvWl2 == Seg->End) &&
!TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN | TCP_FLG_FIN)) {
TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?