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