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