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