• 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 - 2015, 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     Ip6->GetModeData (Ip6, &Ip6Mode, NULL, NULL);
570 
571     return (UINT16) (Ip6Mode.MaxPacketSize - sizeof (TCP_HEAD));
572   }
573 }
574 
575 /**
576   Set the Tcb's state.
577 
578   @param[in]  Tcb                   Pointer to the TCP_CB of this TCP instance.
579   @param[in]  State                 The state to be set.
580 
581 **/
582 VOID
TcpSetState(IN TCP_CB * Tcb,IN UINT8 State)583 TcpSetState (
584   IN TCP_CB *Tcb,
585   IN UINT8  State
586   )
587 {
588   ASSERT (Tcb->State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));
589   ASSERT (State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));
590 
591   DEBUG (
592     (EFI_D_INFO,
593     "Tcb (%p) state %s --> %s\n",
594     Tcb,
595     mTcpStateName[Tcb->State],
596     mTcpStateName[State])
597     );
598 
599   Tcb->State = State;
600 
601   switch (State) {
602   case TCP_ESTABLISHED:
603 
604     SockConnEstablished (Tcb->Sk);
605 
606     if (Tcb->Parent != NULL) {
607       //
608       // A new connection is accepted by a listening socket. Install
609       // the device path.
610       //
611       TcpInstallDevicePath (Tcb->Sk);
612     }
613 
614     break;
615 
616   case TCP_CLOSED:
617 
618     SockConnClosed (Tcb->Sk);
619 
620     break;
621   default:
622     break;
623   }
624 }
625 
626 /**
627   Compute the TCP segment's checksum.
628 
629   @param[in]  Nbuf       Pointer to the buffer that contains the TCP segment.
630   @param[in]  HeadSum    The checksum value of the fixed part of pseudo header.
631 
632   @return The checksum value.
633 
634 **/
635 UINT16
TcpChecksum(IN NET_BUF * Nbuf,IN UINT16 HeadSum)636 TcpChecksum (
637   IN NET_BUF *Nbuf,
638   IN UINT16  HeadSum
639   )
640 {
641   UINT16  Checksum;
642 
643   Checksum  = NetbufChecksum (Nbuf);
644   Checksum  = NetAddChecksum (Checksum, HeadSum);
645 
646   Checksum = NetAddChecksum (
647               Checksum,
648               HTONS ((UINT16) Nbuf->TotalSize)
649               );
650 
651   return (UINT16) (~Checksum);
652 }
653 
654 /**
655   Translate the information from the head of the received TCP
656   segment Nbuf contents and fill it into a TCP_SEG structure.
657 
658   @param[in]       Tcb           Pointer to the TCP_CB of this TCP instance.
659   @param[in, out]  Nbuf          Pointer to the buffer contains the TCP segment.
660 
661   @return Pointer to the TCP_SEG that contains the translated TCP head information.
662 
663 **/
664 TCP_SEG *
TcpFormatNetbuf(IN TCP_CB * Tcb,IN OUT NET_BUF * Nbuf)665 TcpFormatNetbuf (
666   IN     TCP_CB  *Tcb,
667   IN OUT NET_BUF *Nbuf
668   )
669 {
670   TCP_SEG   *Seg;
671   TCP_HEAD  *Head;
672 
673   Seg       = TCPSEG_NETBUF (Nbuf);
674   Head      = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);
675   ASSERT (Head != NULL);
676 
677   Nbuf->Tcp = Head;
678 
679   Seg->Seq  = NTOHL (Head->Seq);
680   Seg->Ack  = NTOHL (Head->Ack);
681   Seg->End  = Seg->Seq + (Nbuf->TotalSize - (Head->HeadLen << 2));
682 
683   Seg->Urg  = NTOHS (Head->Urg);
684   Seg->Wnd  = (NTOHS (Head->Wnd) << Tcb->SndWndScale);
685   Seg->Flag = Head->Flag;
686 
687   //
688   // SYN and FIN flag occupy one sequence space each.
689   //
690   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
691     //
692     // RFC requires that the initial window not be scaled.
693     //
694     Seg->Wnd = NTOHS (Head->Wnd);
695     Seg->End++;
696   }
697 
698   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
699     Seg->End++;
700   }
701 
702   return Seg;
703 }
704 
705 /**
706   Initialize an active connection.
707 
708   @param[in, out]  Tcb          Pointer to the TCP_CB that wants to initiate a
709                                 connection.
710 
711 **/
712 VOID
TcpOnAppConnect(IN OUT TCP_CB * Tcb)713 TcpOnAppConnect (
714   IN OUT TCP_CB  *Tcb
715   )
716 {
717   TcpInitTcbLocal (Tcb);
718   TcpSetState (Tcb, TCP_SYN_SENT);
719 
720   TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);
721   TcpToSendData (Tcb, 1);
722 }
723 
724 /**
725   Initiate the connection close procedure, called when
726   applications want to close the connection.
727 
728   @param[in, out]  Tcb          Pointer to the TCP_CB of this TCP instance.
729 
730 **/
731 VOID
TcpOnAppClose(IN OUT TCP_CB * Tcb)732 TcpOnAppClose (
733   IN OUT TCP_CB *Tcb
734   )
735 {
736   ASSERT (Tcb != NULL);
737 
738   if (!IsListEmpty (&Tcb->RcvQue) || GET_RCV_DATASIZE (Tcb->Sk) != 0) {
739 
740     DEBUG (
741       (EFI_D_WARN,
742       "TcpOnAppClose: connection reset because data is lost for TCB %p\n",
743       Tcb)
744       );
745 
746     TcpResetConnection (Tcb);
747     TcpClose (Tcb);
748     return;
749   }
750 
751   switch (Tcb->State) {
752   case TCP_CLOSED:
753   case TCP_LISTEN:
754   case TCP_SYN_SENT:
755     TcpSetState (Tcb, TCP_CLOSED);
756     break;
757 
758   case TCP_SYN_RCVD:
759   case TCP_ESTABLISHED:
760     TcpSetState (Tcb, TCP_FIN_WAIT_1);
761     break;
762 
763   case TCP_CLOSE_WAIT:
764     TcpSetState (Tcb, TCP_LAST_ACK);
765     break;
766   default:
767     break;
768   }
769 
770   TcpToSendData (Tcb, 1);
771 }
772 
773 /**
774   Check whether the application's newly delivered data can be sent out.
775 
776   @param[in, out]  Tcb          Pointer to the TCP_CB of this TCP instance.
777 
778   @retval 0                     The data has been sent out successfully.
779   @retval -1                    The Tcb is not in a state that data is permitted to
780                                 be sent out.
781 
782 **/
783 INTN
TcpOnAppSend(IN OUT TCP_CB * Tcb)784 TcpOnAppSend (
785   IN OUT TCP_CB *Tcb
786   )
787 {
788 
789   switch (Tcb->State) {
790   case TCP_CLOSED:
791     return -1;
792 
793   case TCP_LISTEN:
794     return -1;
795 
796   case TCP_SYN_SENT:
797   case TCP_SYN_RCVD:
798     return 0;
799 
800   case TCP_ESTABLISHED:
801   case TCP_CLOSE_WAIT:
802     TcpToSendData (Tcb, 0);
803     return 0;
804 
805   case TCP_FIN_WAIT_1:
806   case TCP_FIN_WAIT_2:
807   case TCP_CLOSING:
808   case TCP_LAST_ACK:
809   case TCP_TIME_WAIT:
810     return -1;
811 
812   default:
813     break;
814   }
815 
816   return 0;
817 }
818 
819 /**
820   Application has consumed some data. Check whether
821   to send a window update ack or a delayed ack.
822 
823   @param[in]  Tcb        Pointer to the TCP_CB of this TCP instance.
824 
825 **/
826 VOID
TcpOnAppConsume(IN TCP_CB * Tcb)827 TcpOnAppConsume (
828   IN TCP_CB *Tcb
829   )
830 {
831   UINT32 TcpOld;
832 
833   switch (Tcb->State) {
834   case TCP_ESTABLISHED:
835     TcpOld = TcpRcvWinOld (Tcb);
836     if (TcpRcvWinNow (Tcb) > TcpOld) {
837 
838       if (TcpOld < Tcb->RcvMss) {
839 
840         DEBUG (
841           (EFI_D_INFO,
842           "TcpOnAppConsume: send a window update for a window closed Tcb %p\n",
843           Tcb)
844           );
845 
846         TcpSendAck (Tcb);
847       } else if (Tcb->DelayedAck == 0) {
848 
849         DEBUG (
850           (EFI_D_INFO,
851           "TcpOnAppConsume: scheduled a delayed ACK to update window for Tcb %p\n",
852           Tcb)
853           );
854 
855         Tcb->DelayedAck = 1;
856       }
857     }
858 
859     break;
860 
861   default:
862     break;
863   }
864 }
865 
866 /**
867   Abort the connection by sending a reset segment. Called
868   when the application wants to abort the connection.
869 
870   @param[in]  Tcb                   Pointer to the TCP_CB of the TCP instance.
871 
872 **/
873 VOID
TcpOnAppAbort(IN TCP_CB * Tcb)874 TcpOnAppAbort (
875   IN TCP_CB *Tcb
876   )
877 {
878   DEBUG (
879     (EFI_D_WARN,
880     "TcpOnAppAbort: connection reset issued by application for TCB %p\n",
881     Tcb)
882     );
883 
884   switch (Tcb->State) {
885   case TCP_SYN_RCVD:
886   case TCP_ESTABLISHED:
887   case TCP_FIN_WAIT_1:
888   case TCP_FIN_WAIT_2:
889   case TCP_CLOSE_WAIT:
890     TcpResetConnection (Tcb);
891     break;
892   default:
893     break;
894   }
895 
896   TcpSetState (Tcb, TCP_CLOSED);
897 }
898 
899 /**
900   Reset the connection related with Tcb.
901 
902   @param[in]  Tcb         Pointer to the TCP_CB of the connection to be reset.
903 
904 **/
905 VOID
TcpResetConnection(IN TCP_CB * Tcb)906 TcpResetConnection (
907   IN TCP_CB *Tcb
908   )
909 {
910   NET_BUF   *Nbuf;
911   TCP_HEAD  *Nhead;
912 
913   Nbuf = NetbufAlloc (TCP_MAX_HEAD);
914 
915   if (Nbuf == NULL) {
916     return ;
917   }
918 
919   Nhead = (TCP_HEAD *) NetbufAllocSpace (
920                         Nbuf,
921                         sizeof (TCP_HEAD),
922                         NET_BUF_TAIL
923                         );
924 
925   ASSERT (Nhead != NULL);
926 
927   Nbuf->Tcp       = Nhead;
928 
929   Nhead->Flag     = TCP_FLG_RST;
930   Nhead->Seq      = HTONL (Tcb->SndNxt);
931   Nhead->Ack      = HTONL (Tcb->RcvNxt);
932   Nhead->SrcPort  = Tcb->LocalEnd.Port;
933   Nhead->DstPort  = Tcb->RemoteEnd.Port;
934   Nhead->HeadLen  = (UINT8) (sizeof (TCP_HEAD) >> 2);
935   Nhead->Res      = 0;
936   Nhead->Wnd      = HTONS (0xFFFF);
937   Nhead->Checksum = 0;
938   Nhead->Urg      = 0;
939   Nhead->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);
940 
941   TcpSendIpPacket (Tcb, Nbuf, &Tcb->LocalEnd.Ip, &Tcb->RemoteEnd.Ip, Tcb->Sk->IpVersion);
942 
943   NetbufFree (Nbuf);
944 }
945 
946 /**
947   Install the device path protocol on the TCP instance.
948 
949   @param[in]  Sock          Pointer to the socket representing the TCP instance.
950 
951   @retval EFI_SUCCESS           The device path protocol was installed.
952   @retval other                 Failed to install the device path protocol.
953 
954 **/
955 EFI_STATUS
TcpInstallDevicePath(IN SOCKET * Sock)956 TcpInstallDevicePath (
957   IN SOCKET *Sock
958   )
959 {
960   TCP_PROTO_DATA           *TcpProto;
961   TCP_SERVICE_DATA         *TcpService;
962   TCP_CB                   *Tcb;
963   IPv4_DEVICE_PATH         Ip4DPathNode;
964   IPv6_DEVICE_PATH         Ip6DPathNode;
965   EFI_DEVICE_PATH_PROTOCOL *DevicePath;
966   EFI_STATUS               Status;
967   TCP_PORTNO               LocalPort;
968   TCP_PORTNO               RemotePort;
969 
970   TcpProto   = (TCP_PROTO_DATA *) Sock->ProtoReserved;
971   TcpService = TcpProto->TcpService;
972   Tcb        = TcpProto->TcpPcb;
973 
974   LocalPort = NTOHS (Tcb->LocalEnd.Port);
975   RemotePort = NTOHS (Tcb->RemoteEnd.Port);
976   if (Sock->IpVersion == IP_VERSION_4) {
977     NetLibCreateIPv4DPathNode (
978       &Ip4DPathNode,
979       TcpService->ControllerHandle,
980       Tcb->LocalEnd.Ip.Addr[0],
981       LocalPort,
982       Tcb->RemoteEnd.Ip.Addr[0],
983       RemotePort,
984       EFI_IP_PROTO_TCP,
985       Tcb->UseDefaultAddr
986       );
987 
988     IP4_COPY_ADDRESS (&Ip4DPathNode.SubnetMask, &Tcb->SubnetMask);
989 
990     DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode;
991   } else {
992     NetLibCreateIPv6DPathNode (
993       &Ip6DPathNode,
994       TcpService->ControllerHandle,
995       &Tcb->LocalEnd.Ip.v6,
996       LocalPort,
997       &Tcb->RemoteEnd.Ip.v6,
998       RemotePort,
999       EFI_IP_PROTO_TCP
1000       );
1001 
1002     DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &Ip6DPathNode;
1003   }
1004 
1005   Sock->DevicePath = AppendDevicePathNode (Sock->ParentDevicePath, DevicePath);
1006   if (Sock->DevicePath == NULL) {
1007     return EFI_OUT_OF_RESOURCES;
1008   }
1009 
1010   Status = gBS->InstallProtocolInterface (
1011                   &Sock->SockHandle,
1012                   &gEfiDevicePathProtocolGuid,
1013                   EFI_NATIVE_INTERFACE,
1014                   Sock->DevicePath
1015                   );
1016   if (EFI_ERROR (Status)) {
1017     FreePool (Sock->DevicePath);
1018     Sock->DevicePath = NULL;
1019   }
1020 
1021   return Status;
1022 }
1023 
1024