1/** @file
2  Misc support routines for tcp.
3
4Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php<BR>
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT 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
20LIST_ENTRY      mTcpRunQue = {
21  &mTcpRunQue,
22  &mTcpRunQue
23};
24
25LIST_ENTRY      mTcpListenQue = {
26  &mTcpListenQue,
27  &mTcpListenQue
28};
29
30TCP_SEQNO       mTcpGlobalIss = 0x4d7e980b;
31
32CHAR16   *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**/
53VOID
54TcpInitTcbLocal (
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**/
95VOID
96TcpInitTcbPeer (
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**/
182TCP_CB *
183TcpLocateListenTcb (
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**/
246BOOLEAN
247TcpFindTcbByPeer (
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**/
297TCP_CB *
298TcpLocateTcb (
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**/
353INTN
354TcpInsertTcb (
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**/
407TCP_CB *
408TcpCloneTcb (
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**/
451TCP_SEQNO
452TcpGetIss (
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**/
469UINT16
470TcpGetRcvMss (
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**/
497VOID
498TcpSetState (
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_NET,
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**/
553UINT16
554TcpChecksum (
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**/
582TCP_SEG *
583TcpFormatNetbuf (
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**/
630VOID
631TcpResetConnection (
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**/
679VOID
680TcpOnAppConnect (
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**/
699VOID
700TcpOnAppClose (
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**/
750INTN
751TcpOnAppSend (
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**/
794VOID
795TcpOnAppConsume (
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_NET, "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_NET, "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**/
856VOID
857TcpOnAppAbort (
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**/
888EFI_STATUS
889TcpInstallDevicePath (
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