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