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