VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/NetworkPkg/TcpDxe/TcpMisc.c@ 80721

Last change on this file since 80721 was 80721, checked in by vboxsync, 5 years ago

Devices/EFI/FirmwareNew: Start upgrade process to edk2-stable201908 (compiles on Windows and works to some extent), bugref:4643

  • Property svn:eol-style set to native
File size: 22.2 KB
Line 
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
13LIST_ENTRY mTcpRunQue = {
14 &mTcpRunQue,
15 &mTcpRunQue
16};
17
18LIST_ENTRY mTcpListenQue = {
19 &mTcpListenQue,
20 &mTcpListenQue
21};
22
23TCP_SEQNO mTcpGlobalIss = TCP_BASE_ISS;
24
25CHAR16 *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**/
46VOID
47TcpInitTcbLocal (
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 intial info.
93 @param[in] Opt Pointer to the options announced by the peer.
94
95**/
96VOID
97TcpInitTcbPeer (
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**/
182BOOLEAN
183TcpIsIpEqual (
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**/
209BOOLEAN
210TcpIsIpZero (
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**/
237TCP_CB *
238TcpLocateListenTcb (
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**/
307BOOLEAN
308TcpFindTcbByPeer (
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**/
363TCP_CB *
364TcpLocateTcb (
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**/
421INTN
422TcpInsertTcb (
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**/
478TCP_CB *
479TcpCloneTcb (
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**/
520TCP_SEQNO
521TcpGetIss (
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**/
537UINT16
538TcpGetRcvMss (
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**/
601VOID
602TcpSetState (
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**/
654UINT16
655TcpChecksum (
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**/
683TCP_SEG *
684TcpFormatNetbuf (
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**/
731VOID
732TcpOnAppConnect (
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**/
750VOID
751TcpOnAppClose (
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**/
802INTN
803TcpOnAppSend (
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**/
845VOID
846TcpOnAppConsume (
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**/
892VOID
893TcpOnAppAbort (
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**/
924VOID
925TcpResetConnection (
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**/
974EFI_STATUS
975TcpInstallDevicePath (
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
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette