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