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