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