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