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