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