Home | History | Annotate | Download | only in Tcp4Dxe
      1 /** @file
      2   Misc support routines for tcp.
      3 
      4 Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php<BR>
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 
     16 #include "Tcp4Main.h"
     17 
     18 #include <Library/DevicePathLib.h>
     19 
     20 LIST_ENTRY      mTcpRunQue = {
     21   &mTcpRunQue,
     22   &mTcpRunQue
     23 };
     24 
     25 LIST_ENTRY      mTcpListenQue = {
     26   &mTcpListenQue,
     27   &mTcpListenQue
     28 };
     29 
     30 TCP_SEQNO       mTcpGlobalIss = 0x4d7e980b;
     31 
     32 CHAR16   *mTcpStateName[] = {
     33   L"TCP_CLOSED",
     34   L"TCP_LISTEN",
     35   L"TCP_SYN_SENT",
     36   L"TCP_SYN_RCVD",
     37   L"TCP_ESTABLISHED",
     38   L"TCP_FIN_WAIT_1",
     39   L"TCP_FIN_WAIT_2",
     40   L"TCP_CLOSING",
     41   L"TCP_TIME_WAIT",
     42   L"TCP_CLOSE_WAIT",
     43   L"TCP_LAST_ACK"
     44 };
     45 
     46 
     47 /**
     48   Initialize the Tcb local related members.
     49 
     50   @param  Tcb                   Pointer to the TCP_CB of this TCP instance.
     51 
     52 **/
     53 VOID
     54 TcpInitTcbLocal (
     55   IN OUT TCP_CB *Tcb
     56   )
     57 {
     58   //
     59   // Compute the checksum of the fixed parts of pseudo header
     60   //
     61   Tcb->HeadSum = NetPseudoHeadChecksum (
     62                   Tcb->LocalEnd.Ip,
     63                   Tcb->RemoteEnd.Ip,
     64                   0x06,
     65                   0
     66                   );
     67 
     68   Tcb->Iss    = TcpGetIss ();
     69   Tcb->SndUna = Tcb->Iss;
     70   Tcb->SndNxt = Tcb->Iss;
     71 
     72   Tcb->SndWl2 = Tcb->Iss;
     73   Tcb->SndWnd = 536;
     74 
     75   Tcb->RcvWnd = GET_RCV_BUFFSIZE (Tcb->Sk);
     76 
     77   //
     78   // First window size is never scaled
     79   //
     80   Tcb->RcvWndScale  = 0;
     81 
     82   Tcb->ProbeTimerOn = FALSE;
     83 }
     84 
     85 
     86 /**
     87   Initialize the peer related members.
     88 
     89   @param  Tcb                   Pointer to the TCP_CB of this TCP instance.
     90   @param  Seg                   Pointer to the segment that contains the peer's
     91                                 intial info.
     92   @param  Opt                   Pointer to the options announced by the peer.
     93 
     94 **/
     95 VOID
     96 TcpInitTcbPeer (
     97   IN OUT TCP_CB     *Tcb,
     98   IN     TCP_SEG    *Seg,
     99   IN     TCP_OPTION *Opt
    100   )
    101 {
    102   UINT16  RcvMss;
    103 
    104   ASSERT ((Tcb != NULL) && (Seg != NULL) && (Opt != NULL));
    105   ASSERT (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN));
    106 
    107   Tcb->SndWnd     = Seg->Wnd;
    108   Tcb->SndWndMax  = Tcb->SndWnd;
    109   Tcb->SndWl1     = Seg->Seq;
    110 
    111   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
    112     Tcb->SndWl2 = Seg->Ack;
    113   } else {
    114     Tcb->SndWl2 = Tcb->Iss + 1;
    115   }
    116 
    117   if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_MSS)) {
    118     Tcb->SndMss = (UINT16) MAX (64, Opt->Mss);
    119 
    120     RcvMss = TcpGetRcvMss (Tcb->Sk);
    121     if (Tcb->SndMss > RcvMss) {
    122       Tcb->SndMss = RcvMss;
    123     }
    124 
    125   } else {
    126     //
    127     // One end doesn't support MSS option, use default.
    128     //
    129     Tcb->RcvMss = 536;
    130   }
    131 
    132   Tcb->CWnd   = Tcb->SndMss;
    133 
    134   Tcb->Irs    = Seg->Seq;
    135   Tcb->RcvNxt = Tcb->Irs + 1;
    136 
    137   Tcb->RcvWl2 = Tcb->RcvNxt;
    138 
    139   if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_WS) &&
    140       !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS)) {
    141 
    142     Tcb->SndWndScale  = Opt->WndScale;
    143 
    144     Tcb->RcvWndScale  = TcpComputeScale (Tcb);
    145     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_WS);
    146 
    147   } else {
    148     //
    149     // One end doesn't support window scale option. use zero.
    150     //
    151     Tcb->RcvWndScale = 0;
    152   }
    153 
    154   if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_TS) &&
    155       !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS)) {
    156 
    157     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_TS);
    158     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS);
    159 
    160     Tcb->TsRecent = Opt->TSVal;
    161 
    162     //
    163     // Compute the effective SndMss per RFC1122
    164     // section 4.2.2.6. If timestamp option is
    165     // enabled, it will always occupy 12 bytes.
    166     //
    167     Tcb->SndMss -= TCP_OPTION_TS_ALIGNED_LEN;
    168   }
    169 }
    170 
    171 
    172 /**
    173   Locate a listen TCB that matchs the Local and Remote.
    174 
    175   @param  Local                 Pointer to the local (IP, Port).
    176   @param  Remote                Pointer to the remote (IP, Port).
    177 
    178   @return  Pointer to the TCP_CB with the least number of wildcard,
    179            if NULL no match is found.
    180 
    181 **/
    182 TCP_CB *
    183 TcpLocateListenTcb (
    184   IN TCP_PEER *Local,
    185   IN TCP_PEER *Remote
    186   )
    187 {
    188   LIST_ENTRY      *Entry;
    189   TCP_CB          *Node;
    190   TCP_CB          *Match;
    191   INTN            Last;
    192   INTN            Cur;
    193 
    194   Last  = 4;
    195   Match = NULL;
    196 
    197   NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {
    198     Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
    199 
    200     if ((Local->Port != Node->LocalEnd.Port) ||
    201         !TCP_PEER_MATCH (Remote, &Node->RemoteEnd) ||
    202         !TCP_PEER_MATCH (Local, &Node->LocalEnd)) {
    203 
    204       continue;
    205     }
    206 
    207     //
    208     // Compute the number of wildcard
    209     //
    210     Cur = 0;
    211     if (Node->RemoteEnd.Ip == 0) {
    212       Cur++;
    213     }
    214 
    215     if (Node->RemoteEnd.Port == 0) {
    216       Cur++;
    217     }
    218 
    219     if (Node->LocalEnd.Ip == 0) {
    220       Cur++;
    221     }
    222 
    223     if (Cur < Last) {
    224       if (Cur == 0) {
    225         return Node;
    226       }
    227 
    228       Last  = Cur;
    229       Match = Node;
    230     }
    231   }
    232 
    233   return Match;
    234 }
    235 
    236 
    237 /**
    238   Try to find one Tcb whose <Ip, Port> equals to <IN Addr, IN Port>.
    239 
    240   @param  Addr                  Pointer to the IP address needs to match.
    241   @param  Port                  The port number needs to match.
    242 
    243   @return  The Tcb which matches the <Addr Port> paire exists or not.
    244 
    245 **/
    246 BOOLEAN
    247 TcpFindTcbByPeer (
    248   IN EFI_IPv4_ADDRESS  *Addr,
    249   IN TCP_PORTNO        Port
    250   )
    251 {
    252   TCP_PORTNO      LocalPort;
    253   LIST_ENTRY      *Entry;
    254   TCP_CB          *Tcb;
    255 
    256   ASSERT ((Addr != NULL) && (Port != 0));
    257 
    258   LocalPort = HTONS (Port);
    259 
    260   NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {
    261     Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
    262 
    263     if (EFI_IP4_EQUAL (Addr, &Tcb->LocalEnd.Ip) &&
    264       (LocalPort == Tcb->LocalEnd.Port)) {
    265 
    266       return TRUE;
    267     }
    268   }
    269 
    270   NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {
    271     Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
    272 
    273     if (EFI_IP4_EQUAL (Addr, &Tcb->LocalEnd.Ip) &&
    274       (LocalPort == Tcb->LocalEnd.Port)) {
    275 
    276       return TRUE;
    277     }
    278   }
    279 
    280   return FALSE;
    281 }
    282 
    283 
    284 /**
    285   Locate the TCP_CB related to the socket pair.
    286 
    287   @param  LocalPort             The local port number.
    288   @param  LocalIp               The local IP address.
    289   @param  RemotePort            The remote port number.
    290   @param  RemoteIp              The remote IP address.
    291   @param  Syn                   Whether to search the listen sockets, if TRUE, the
    292                                 listen sockets are searched.
    293 
    294   @return  Pointer to the related TCP_CB, if NULL no match is found.
    295 
    296 **/
    297 TCP_CB *
    298 TcpLocateTcb (
    299   IN TCP_PORTNO  LocalPort,
    300   IN UINT32      LocalIp,
    301   IN TCP_PORTNO  RemotePort,
    302   IN UINT32      RemoteIp,
    303   IN BOOLEAN     Syn
    304   )
    305 {
    306   TCP_PEER        Local;
    307   TCP_PEER        Remote;
    308   LIST_ENTRY      *Entry;
    309   TCP_CB          *Tcb;
    310 
    311   Local.Port  = LocalPort;
    312   Local.Ip    = LocalIp;
    313 
    314   Remote.Port = RemotePort;
    315   Remote.Ip   = RemoteIp;
    316 
    317   //
    318   // First check for exact match.
    319   //
    320   NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {
    321     Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
    322 
    323     if (TCP_PEER_EQUAL (&Remote, &Tcb->RemoteEnd) &&
    324         TCP_PEER_EQUAL (&Local, &Tcb->LocalEnd)) {
    325 
    326       RemoveEntryList (&Tcb->List);
    327       InsertHeadList (&mTcpRunQue, &Tcb->List);
    328 
    329       return Tcb;
    330     }
    331   }
    332 
    333   //
    334   // Only check listen queue when SYN flag is on
    335   //
    336   if (Syn) {
    337     return TcpLocateListenTcb (&Local, &Remote);
    338   }
    339 
    340   return NULL;
    341 }
    342 
    343 
    344 /**
    345   Insert a Tcb into the proper queue.
    346 
    347   @param  Tcb                   Pointer to the TCP_CB to be inserted.
    348 
    349   @retval 0                     The Tcb is inserted successfully.
    350   @retval -1                    Error condition occurred.
    351 
    352 **/
    353 INTN
    354 TcpInsertTcb (
    355   IN TCP_CB *Tcb
    356   )
    357 {
    358   LIST_ENTRY       *Entry;
    359   LIST_ENTRY       *Head;
    360   TCP_CB           *Node;
    361 
    362   ASSERT (
    363     (Tcb != NULL) &&
    364     ((Tcb->State == TCP_LISTEN) ||
    365      (Tcb->State == TCP_SYN_SENT) ||
    366      (Tcb->State == TCP_SYN_RCVD) ||
    367      (Tcb->State == TCP_CLOSED))
    368     );
    369 
    370   if (Tcb->LocalEnd.Port == 0) {
    371     return -1;
    372   }
    373 
    374   Head = &mTcpRunQue;
    375 
    376   if (Tcb->State == TCP_LISTEN) {
    377     Head = &mTcpListenQue;
    378   }
    379 
    380   //
    381   // Check that Tcb isn't already on the list.
    382   //
    383   NET_LIST_FOR_EACH (Entry, Head) {
    384     Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
    385 
    386     if (TCP_PEER_EQUAL (&Tcb->LocalEnd, &Node->LocalEnd) &&
    387         TCP_PEER_EQUAL (&Tcb->RemoteEnd, &Node->RemoteEnd)) {
    388 
    389       return -1;
    390     }
    391   }
    392 
    393   InsertHeadList (Head, &Tcb->List);
    394 
    395   return 0;
    396 }
    397 
    398 
    399 /**
    400   Clone a TCB_CB from Tcb.
    401 
    402   @param  Tcb                   Pointer to the TCP_CB to be cloned.
    403 
    404   @return  Pointer to the new cloned TCP_CB, if NULL error condition occurred.
    405 
    406 **/
    407 TCP_CB *
    408 TcpCloneTcb (
    409   IN TCP_CB *Tcb
    410   )
    411 {
    412   TCP_CB               *Clone;
    413 
    414   Clone = AllocatePool (sizeof (TCP_CB));
    415 
    416   if (Clone == NULL) {
    417     return NULL;
    418 
    419   }
    420 
    421   CopyMem (Clone, Tcb, sizeof (TCP_CB));
    422 
    423   //
    424   // Increate the reference count of the shared IpInfo.
    425   //
    426   NET_GET_REF (Tcb->IpInfo);
    427 
    428   InitializeListHead (&Clone->List);
    429   InitializeListHead (&Clone->SndQue);
    430   InitializeListHead (&Clone->RcvQue);
    431 
    432   Clone->Sk = SockClone (Tcb->Sk);
    433   if (Clone->Sk == NULL) {
    434     DEBUG ((EFI_D_ERROR, "TcpCloneTcb: failed to clone a sock\n"));
    435     FreePool (Clone);
    436     return NULL;
    437   }
    438 
    439   ((TCP4_PROTO_DATA *) (Clone->Sk->ProtoReserved))->TcpPcb = Clone;
    440 
    441   return Clone;
    442 }
    443 
    444 
    445 /**
    446   Compute an ISS to be used by a new connection.
    447 
    448   @return  The result ISS.
    449 
    450 **/
    451 TCP_SEQNO
    452 TcpGetIss (
    453   VOID
    454   )
    455 {
    456   mTcpGlobalIss += 2048;
    457   return mTcpGlobalIss;
    458 }
    459 
    460 
    461 /**
    462   Get the local mss.
    463 
    464   @param  Sock        Pointer to the socket to get mss
    465 
    466   @return  The mss size.
    467 
    468 **/
    469 UINT16
    470 TcpGetRcvMss (
    471   IN SOCKET  *Sock
    472   )
    473 {
    474   EFI_IP4_MODE_DATA       Ip4Mode;
    475   TCP4_PROTO_DATA         *TcpProto;
    476   EFI_IP4_PROTOCOL        *Ip;
    477 
    478   ASSERT (Sock != NULL);
    479 
    480   TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
    481   Ip       = TcpProto->TcpService->IpIo->Ip.Ip4;
    482   ASSERT (Ip != NULL);
    483 
    484   Ip->GetModeData (Ip, &Ip4Mode, NULL, NULL);
    485 
    486   return (UINT16) (Ip4Mode.MaxPacketSize - sizeof (TCP_HEAD));
    487 }
    488 
    489 
    490 /**
    491   Set the Tcb's state.
    492 
    493   @param  Tcb                   Pointer to the TCP_CB of this TCP instance.
    494   @param  State                 The state to be set.
    495 
    496 **/
    497 VOID
    498 TcpSetState (
    499   IN OUT TCP_CB  *Tcb,
    500   IN     UINT8   State
    501   )
    502 {
    503   ASSERT (Tcb->State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));
    504   ASSERT (State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));
    505 
    506   DEBUG (
    507     (EFI_D_INFO,
    508     "Tcb (%p) state %s --> %s\n",
    509     Tcb,
    510     mTcpStateName[Tcb->State],
    511     mTcpStateName[State])
    512     );
    513 
    514   Tcb->State = State;
    515 
    516   switch (State) {
    517   case TCP_ESTABLISHED:
    518 
    519     SockConnEstablished (Tcb->Sk);
    520 
    521     if (Tcb->Parent != NULL) {
    522       //
    523       // A new connection is accepted by a listening socket, install
    524       // the device path.
    525       //
    526       TcpInstallDevicePath (Tcb->Sk);
    527     }
    528 
    529     break;
    530 
    531   case TCP_CLOSED:
    532 
    533     SockConnClosed (Tcb->Sk);
    534 
    535     break;
    536   default:
    537     break;
    538   }
    539 }
    540 
    541 
    542 /**
    543   Compute the TCP segment's checksum.
    544 
    545   @param  Nbuf                  Pointer to the buffer that contains the TCP
    546                                 segment.
    547   @param  HeadSum               The checksum value of the fixed part of pseudo
    548                                 header.
    549 
    550   @return  The checksum value.
    551 
    552 **/
    553 UINT16
    554 TcpChecksum (
    555   IN NET_BUF *Nbuf,
    556   IN UINT16  HeadSum
    557   )
    558 {
    559   UINT16  Checksum;
    560 
    561   Checksum  = NetbufChecksum (Nbuf);
    562   Checksum  = NetAddChecksum (Checksum, HeadSum);
    563 
    564   Checksum  = NetAddChecksum (
    565                 Checksum,
    566                 HTONS ((UINT16) Nbuf->TotalSize)
    567                 );
    568 
    569   return (UINT16) ~Checksum;
    570 }
    571 
    572 /**
    573   Translate the information from the head of the received TCP
    574   segment Nbuf contains and fill it into a TCP_SEG structure.
    575 
    576   @param  Tcb                   Pointer to the TCP_CB of this TCP instance.
    577   @param  Nbuf                  Pointer to the buffer contains the TCP segment.
    578 
    579   @return  Pointer to the TCP_SEG that contains the translated TCP head information.
    580 
    581 **/
    582 TCP_SEG *
    583 TcpFormatNetbuf (
    584   IN     TCP_CB  *Tcb,
    585   IN OUT NET_BUF *Nbuf
    586   )
    587 {
    588   TCP_SEG   *Seg;
    589   TCP_HEAD  *Head;
    590 
    591   Seg       = TCPSEG_NETBUF (Nbuf);
    592   Head      = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);
    593   ASSERT (Head != NULL);
    594   Nbuf->Tcp = Head;
    595 
    596   Seg->Seq  = NTOHL (Head->Seq);
    597   Seg->Ack  = NTOHL (Head->Ack);
    598   Seg->End  = Seg->Seq + (Nbuf->TotalSize - (Head->HeadLen << 2));
    599 
    600   Seg->Urg  = NTOHS (Head->Urg);
    601   Seg->Wnd  = (NTOHS (Head->Wnd) << Tcb->SndWndScale);
    602   Seg->Flag = Head->Flag;
    603 
    604   //
    605   // SYN and FIN flag occupy one sequence space each.
    606   //
    607   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
    608     //
    609     // RFC requires that initial window not be scaled
    610     //
    611     Seg->Wnd = NTOHS (Head->Wnd);
    612     Seg->End++;
    613   }
    614 
    615   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
    616     Seg->End++;
    617   }
    618 
    619   return Seg;
    620 }
    621 
    622 
    623 /**
    624   Reset the connection related with Tcb.
    625 
    626   @param  Tcb                   Pointer to the TCP_CB of the connection to be
    627                                 reset.
    628 
    629 **/
    630 VOID
    631 TcpResetConnection (
    632   IN TCP_CB *Tcb
    633   )
    634 {
    635   NET_BUF   *Nbuf;
    636   TCP_HEAD  *Nhead;
    637 
    638   Nbuf = NetbufAlloc (TCP_MAX_HEAD);
    639 
    640   if (Nbuf == NULL) {
    641     return ;
    642   }
    643 
    644   Nhead = (TCP_HEAD *) NetbufAllocSpace (
    645                         Nbuf,
    646                         sizeof (TCP_HEAD),
    647                         NET_BUF_TAIL
    648                         );
    649 
    650   ASSERT (Nhead != NULL);
    651 
    652   Nbuf->Tcp       = Nhead;
    653 
    654   Nhead->Flag     = TCP_FLG_RST;
    655   Nhead->Seq      = HTONL (Tcb->SndNxt);
    656   Nhead->Ack      = HTONL (Tcb->RcvNxt);
    657   Nhead->SrcPort  = Tcb->LocalEnd.Port;
    658   Nhead->DstPort  = Tcb->RemoteEnd.Port;
    659   Nhead->HeadLen  = (UINT8) (sizeof (TCP_HEAD) >> 2);
    660   Nhead->Res      = 0;
    661   Nhead->Wnd      = HTONS (0xFFFF);
    662   Nhead->Checksum = 0;
    663   Nhead->Urg      = 0;
    664   Nhead->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);
    665 
    666   TcpSendIpPacket (Tcb, Nbuf, Tcb->LocalEnd.Ip, Tcb->RemoteEnd.Ip);
    667 
    668   NetbufFree (Nbuf);
    669 }
    670 
    671 
    672 /**
    673   Initialize an active connection.
    674 
    675   @param  Tcb                   Pointer to the TCP_CB that wants to initiate a
    676                                 connection.
    677 
    678 **/
    679 VOID
    680 TcpOnAppConnect (
    681   IN OUT TCP_CB  *Tcb
    682   )
    683 {
    684   TcpInitTcbLocal (Tcb);
    685   TcpSetState (Tcb, TCP_SYN_SENT);
    686 
    687   TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);
    688   TcpToSendData (Tcb, 1);
    689 }
    690 
    691 
    692 /**
    693   Initiate the connection close procedure, called when
    694   applications want to close the connection.
    695 
    696   @param  Tcb                   Pointer to the TCP_CB of this TCP instance.
    697 
    698 **/
    699 VOID
    700 TcpOnAppClose (
    701   IN OUT TCP_CB *Tcb
    702   )
    703 {
    704   ASSERT (Tcb != NULL);
    705 
    706   if (!IsListEmpty (&Tcb->RcvQue) || GET_RCV_DATASIZE (Tcb->Sk) != 0) {
    707 
    708     DEBUG ((EFI_D_WARN, "TcpOnAppClose: connection reset "
    709       "because data is lost for TCB %p\n", Tcb));
    710 
    711     TcpResetConnection (Tcb);
    712     TcpClose (Tcb);
    713     return;
    714   }
    715 
    716   switch (Tcb->State) {
    717   case TCP_CLOSED:
    718   case TCP_LISTEN:
    719   case TCP_SYN_SENT:
    720     TcpSetState (Tcb, TCP_CLOSED);
    721     break;
    722 
    723   case TCP_SYN_RCVD:
    724   case TCP_ESTABLISHED:
    725     TcpSetState (Tcb, TCP_FIN_WAIT_1);
    726     break;
    727 
    728   case TCP_CLOSE_WAIT:
    729     TcpSetState (Tcb, TCP_LAST_ACK);
    730     break;
    731   default:
    732     break;
    733   }
    734 
    735   TcpToSendData (Tcb, 1);
    736 }
    737 
    738 
    739 /**
    740   Check whether the application's newly delivered data can be sent out.
    741 
    742   @param  Tcb                   Pointer to the TCP_CB of this TCP instance.
    743 
    744   @retval 0                     Whether the data is sent out or is buffered for
    745                                 further sending.
    746   @retval -1                    The Tcb is not in a state that data is permitted to
    747                                 be sent out.
    748 
    749 **/
    750 INTN
    751 TcpOnAppSend (
    752   IN OUT TCP_CB *Tcb
    753   )
    754 {
    755 
    756   switch (Tcb->State) {
    757   case TCP_CLOSED:
    758     return -1;
    759 
    760   case TCP_LISTEN:
    761     return -1;
    762 
    763   case TCP_SYN_SENT:
    764   case TCP_SYN_RCVD:
    765     return 0;
    766 
    767   case TCP_ESTABLISHED:
    768   case TCP_CLOSE_WAIT:
    769     TcpToSendData (Tcb, 0);
    770     return 0;
    771 
    772   case TCP_FIN_WAIT_1:
    773   case TCP_FIN_WAIT_2:
    774   case TCP_CLOSING:
    775   case TCP_LAST_ACK:
    776   case TCP_TIME_WAIT:
    777     return -1;
    778 
    779   default:
    780     break;
    781   }
    782 
    783   return 0;
    784 }
    785 
    786 
    787 /**
    788   Application has consumed some data, check whether
    789   to send a window updata ack or a delayed ack.
    790 
    791   @param  Tcb                   Pointer to the TCP_CB of this TCP instance.
    792 
    793 **/
    794 VOID
    795 TcpOnAppConsume (
    796   IN TCP_CB *Tcb
    797   )
    798 {
    799   UINT32 TcpOld;
    800 
    801   switch (Tcb->State) {
    802   case TCP_CLOSED:
    803     return;
    804 
    805   case TCP_LISTEN:
    806     return;
    807 
    808   case TCP_SYN_SENT:
    809   case TCP_SYN_RCVD:
    810     return;
    811 
    812   case TCP_ESTABLISHED:
    813     TcpOld = TcpRcvWinOld (Tcb);
    814     if (TcpRcvWinNow (Tcb) > TcpOld) {
    815 
    816       if (TcpOld < Tcb->RcvMss) {
    817 
    818         DEBUG ((EFI_D_INFO, "TcpOnAppConsume: send a window"
    819           " update for a window closed Tcb %p\n", Tcb));
    820 
    821         TcpSendAck (Tcb);
    822       } else if (Tcb->DelayedAck == 0) {
    823 
    824         DEBUG ((EFI_D_INFO, "TcpOnAppConsume: scheduled a delayed"
    825           " ACK to update window for Tcb %p\n", Tcb));
    826 
    827         Tcb->DelayedAck = 1;
    828       }
    829     }
    830 
    831     break;
    832 
    833   case TCP_CLOSE_WAIT:
    834     return;
    835 
    836   case TCP_FIN_WAIT_1:
    837   case TCP_FIN_WAIT_2:
    838   case TCP_CLOSING:
    839   case TCP_LAST_ACK:
    840   case TCP_TIME_WAIT:
    841     return;
    842 
    843   default:
    844     break;
    845   }
    846 }
    847 
    848 
    849 /**
    850   Abort the connection by sending a reset segment, called
    851   when the application wants to abort the connection.
    852 
    853   @param  Tcb                   Pointer to the TCP_CB of the TCP instance.
    854 
    855 **/
    856 VOID
    857 TcpOnAppAbort (
    858   IN TCP_CB *Tcb
    859   )
    860 {
    861   DEBUG ((EFI_D_WARN, "TcpOnAppAbort: connection reset "
    862     "issued by application for TCB %p\n", Tcb));
    863 
    864   switch (Tcb->State) {
    865   case TCP_SYN_RCVD:
    866   case TCP_ESTABLISHED:
    867   case TCP_FIN_WAIT_1:
    868   case TCP_FIN_WAIT_2:
    869   case TCP_CLOSE_WAIT:
    870     TcpResetConnection (Tcb);
    871     break;
    872   default:
    873     break;
    874   }
    875 
    876   TcpSetState (Tcb, TCP_CLOSED);
    877 }
    878 
    879 /**
    880   Install the device path protocol on the TCP instance.
    881 
    882   @param  Sock             Pointer to the socket representing the TCP instance.
    883 
    884   @retval  EFI_SUCCESS     The device path protocol is installed.
    885   @retval  other           Failed to install the device path protocol.
    886 
    887 **/
    888 EFI_STATUS
    889 TcpInstallDevicePath (
    890   IN SOCKET *Sock
    891   )
    892 {
    893   TCP4_PROTO_DATA    *TcpProto;
    894   TCP4_SERVICE_DATA  *TcpService;
    895   TCP_CB             *Tcb;
    896   IPv4_DEVICE_PATH   Ip4DPathNode;
    897   EFI_STATUS         Status;
    898   TCP_PORTNO         LocalPort;
    899   TCP_PORTNO         RemotePort;
    900 
    901   TcpProto   = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
    902   TcpService = TcpProto->TcpService;
    903   Tcb        = TcpProto->TcpPcb;
    904 
    905   LocalPort = NTOHS (Tcb->LocalEnd.Port);
    906   RemotePort = NTOHS (Tcb->RemoteEnd.Port);
    907   NetLibCreateIPv4DPathNode (
    908     &Ip4DPathNode,
    909     TcpService->ControllerHandle,
    910     Tcb->LocalEnd.Ip,
    911     LocalPort,
    912     Tcb->RemoteEnd.Ip,
    913     RemotePort,
    914     EFI_IP_PROTO_TCP,
    915     Tcb->UseDefaultAddr
    916     );
    917 
    918   IP4_COPY_ADDRESS (&Ip4DPathNode.SubnetMask, &Tcb->SubnetMask);
    919 
    920   Sock->DevicePath = AppendDevicePathNode (
    921                        Sock->ParentDevicePath,
    922                        (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode
    923                        );
    924   if (Sock->DevicePath == NULL) {
    925     return EFI_OUT_OF_RESOURCES;
    926   }
    927 
    928   Status = gBS->InstallProtocolInterface (
    929                   &Sock->SockHandle,
    930                   &gEfiDevicePathProtocolGuid,
    931                   EFI_NATIVE_INTERFACE,
    932                   Sock->DevicePath
    933                   );
    934   if (EFI_ERROR (Status)) {
    935     FreePool (Sock->DevicePath);
    936   }
    937 
    938   return Status;
    939 }
    940