]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/TcpDxe/TcpMisc.c
SecurityPkg: Add TPM PTP support in TCG2 SMM.
[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 - 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
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
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
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
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 *
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
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 *
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
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 *
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
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
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
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
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 *
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
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
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
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
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
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
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
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