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