]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Misc.c
MdeModulePkg/Universal/Network/IScsiDxe/IScsiImpl.h:
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Tcp4Dxe / Tcp4Misc.c
1 /** @file
2 Misc support routines for tcp.
3
4 Copyright (c) 2005 - 2006, Intel Corporation<BR>
5 All rights reserved. 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 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 TCP_CB *Tcb,
96 IN TCP_SEG *Seg,
97 IN TCP_OPTION *Opt
98 )
99 {
100 UINT16 RcvMss;
101
102 ASSERT (Tcb && Seg && Opt);
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 gBS->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_SIMPLE_NETWORK_MODE SnpMode;
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 = TcpProto->TcpService->IpIo->Ip;
482 ASSERT (Ip != NULL);
483
484 Ip->GetModeData (Ip, NULL, NULL, &SnpMode);
485
486 return (UINT16) (SnpMode.MaxPacketSize - 40);
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 TCP_CB *Tcb,
500 IN TCP_STATES 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 = (TCP_STATES)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 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 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 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 TCP_CB *Tcb
749 )
750 {
751
752 switch (Tcb->State) {
753 case TCP_CLOSED:
754 return -1;
755 break;
756
757 case TCP_LISTEN:
758 return -1;
759 break;
760
761 case TCP_SYN_SENT:
762 case TCP_SYN_RCVD:
763 return 0;
764 break;
765
766 case TCP_ESTABLISHED:
767 case TCP_CLOSE_WAIT:
768 TcpToSendData (Tcb, 0);
769 return 0;
770 break;
771
772 case TCP_FIN_WAIT_1:
773 case TCP_FIN_WAIT_2:
774 case TCP_CLOSING:
775 case TCP_LAST_ACK:
776 case TCP_TIME_WAIT:
777 return -1;
778 break;
779 default:
780 break;
781 }
782
783 return 0;
784 }
785
786
787 /**
788 Application has consumed some data, check whether
789 to send a window updata ack or a delayed ack.
790
791 @param Tcb Pointer to the TCP_CB of this TCP instance.
792
793 **/
794 INTN
795 TcpOnAppConsume (
796 IN TCP_CB *Tcb
797 )
798 {
799 UINT32 TcpOld;
800
801 switch (Tcb->State) {
802 case TCP_CLOSED:
803 return -1;
804 break;
805
806 case TCP_LISTEN:
807 return -1;
808 break;
809
810 case TCP_SYN_SENT:
811 case TCP_SYN_RCVD:
812 return 0;
813 break;
814
815 case TCP_ESTABLISHED:
816 TcpOld = TcpRcvWinOld (Tcb);
817 if (TcpRcvWinNow (Tcb) > TcpOld) {
818
819 if (TcpOld < Tcb->RcvMss) {
820
821 DEBUG ((EFI_D_INFO, "TcpOnAppConsume: send a window"
822 " update for a window closed Tcb %p\n", Tcb));
823
824 TcpSendAck (Tcb);
825 } else if (Tcb->DelayedAck == 0) {
826
827 DEBUG ((EFI_D_INFO, "TcpOnAppConsume: scheduled a delayed"
828 " ACK to update window for Tcb %p\n", Tcb));
829
830 Tcb->DelayedAck = 1;
831 }
832 }
833
834 break;
835
836 case TCP_CLOSE_WAIT:
837 return 0;
838 break;
839
840 case TCP_FIN_WAIT_1:
841 case TCP_FIN_WAIT_2:
842 case TCP_CLOSING:
843 case TCP_LAST_ACK:
844 case TCP_TIME_WAIT:
845 return -1;
846 break;
847 }
848
849 return -1;
850 }
851
852
853 /**
854 Abort the connection by sending a reset segment, called
855 when the application wants to abort the connection.
856
857 @param Tcb Pointer to the TCP_CB of the TCP instance.
858
859 **/
860 VOID
861 TcpOnAppAbort (
862 IN TCP_CB *Tcb
863 )
864 {
865 DEBUG ((EFI_D_WARN, "TcpOnAppAbort: connection reset "
866 "issued by application for TCB %p\n", Tcb));
867
868 switch (Tcb->State) {
869 case TCP_SYN_RCVD:
870 case TCP_ESTABLISHED:
871 case TCP_FIN_WAIT_1:
872 case TCP_FIN_WAIT_2:
873 case TCP_CLOSE_WAIT:
874 TcpResetConnection (Tcb);
875 break;
876 default:
877 break;
878 }
879
880 TcpSetState (Tcb, TCP_CLOSED);
881 }
882
883
884 /**
885 Set the Tdp4 variable data.
886
887 @param Tcp4Service Pointer to Tcp4 service data.
888
889 @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.
890 @retval other Set variable failed.
891
892 **/
893 EFI_STATUS
894 TcpSetVariableData (
895 IN TCP4_SERVICE_DATA *Tcp4Service
896 )
897 {
898 UINT32 NumConfiguredInstance;
899 LIST_ENTRY *Entry;
900 TCP_CB *TcpPcb;
901 TCP4_PROTO_DATA *TcpProto;
902 UINTN VariableDataSize;
903 EFI_TCP4_VARIABLE_DATA *Tcp4VariableData;
904 EFI_TCP4_SERVICE_POINT *Tcp4ServicePoint;
905 CHAR16 *NewMacString;
906 EFI_STATUS Status;
907
908 NumConfiguredInstance = 0;
909
910 //
911 // Go through the running queue to count the instances.
912 //
913 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {
914 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
915
916 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;
917
918 if (TcpProto->TcpService == Tcp4Service) {
919 //
920 // This tcp instance belongs to the Tcp4Service.
921 //
922 NumConfiguredInstance++;
923 }
924 }
925
926 //
927 // Go through the listening queue to count the instances.
928 //
929 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {
930 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
931
932 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;
933
934 if (TcpProto->TcpService == Tcp4Service) {
935 //
936 // This tcp instance belongs to the Tcp4Service.
937 //
938 NumConfiguredInstance++;
939 }
940 }
941
942 //
943 // Calculate the size of the Tcp4VariableData. As there may be no Tcp4 child,
944 // we should add extra buffer for the service points only if the number of configured
945 // children is more than 1.
946 //
947 VariableDataSize = sizeof (EFI_TCP4_VARIABLE_DATA);
948
949 if (NumConfiguredInstance > 1) {
950 VariableDataSize += sizeof (EFI_TCP4_SERVICE_POINT) * (NumConfiguredInstance - 1);
951 }
952
953 Tcp4VariableData = AllocatePool (VariableDataSize);
954 if (Tcp4VariableData == NULL) {
955 return EFI_OUT_OF_RESOURCES;
956 }
957
958 Tcp4VariableData->DriverHandle = Tcp4Service->DriverBindingHandle;
959 Tcp4VariableData->ServiceCount = NumConfiguredInstance;
960
961 Tcp4ServicePoint = &Tcp4VariableData->Services[0];
962
963 //
964 // Go through the running queue to fill the service points.
965 //
966 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {
967 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
968
969 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;
970
971 if (TcpProto->TcpService == Tcp4Service) {
972 //
973 // This tcp instance belongs to the Tcp4Service.
974 //
975 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;
976 CopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
977 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);
978 CopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
979 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);
980
981 Tcp4ServicePoint++;
982 }
983 }
984
985 //
986 // Go through the listening queue to fill the service points.
987 //
988 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {
989 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
990
991 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;
992
993 if (TcpProto->TcpService == Tcp4Service) {
994 //
995 // This tcp instance belongs to the Tcp4Service.
996 //
997 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;
998 CopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
999 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);
1000 CopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
1001 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);
1002
1003 Tcp4ServicePoint++;
1004 }
1005 }
1006
1007 //
1008 // Get the mac string.
1009 //
1010 Status = NetLibGetMacString (
1011 Tcp4Service->ControllerHandle,
1012 Tcp4Service->DriverBindingHandle,
1013 &NewMacString
1014 );
1015 if (EFI_ERROR (Status)) {
1016 goto ON_ERROR;
1017 }
1018
1019 if (Tcp4Service->MacString != NULL) {
1020 //
1021 // The variable is set already, we're going to update it.
1022 //
1023 if (StrCmp (Tcp4Service->MacString, NewMacString) != 0) {
1024 //
1025 // The mac address is changed, delete the previous variable first.
1026 //
1027 gRT->SetVariable (
1028 Tcp4Service->MacString,
1029 &gEfiTcp4ServiceBindingProtocolGuid,
1030 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1031 0,
1032 NULL
1033 );
1034 }
1035
1036 gBS->FreePool (Tcp4Service->MacString);
1037 }
1038
1039 Tcp4Service->MacString = NewMacString;
1040
1041 Status = gRT->SetVariable (
1042 Tcp4Service->MacString,
1043 &gEfiTcp4ServiceBindingProtocolGuid,
1044 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1045 VariableDataSize,
1046 (VOID *) Tcp4VariableData
1047 );
1048
1049 ON_ERROR:
1050
1051 gBS->FreePool (Tcp4VariableData);
1052
1053 return Status;
1054 }
1055
1056
1057 /**
1058 Clear the variable and free the resource.
1059
1060 @param Tcp4Service Pointer to Tcp4 service data.
1061
1062 **/
1063 VOID
1064 TcpClearVariableData (
1065 IN TCP4_SERVICE_DATA *Tcp4Service
1066 )
1067 {
1068 ASSERT (Tcp4Service->MacString != NULL);
1069
1070 gRT->SetVariable (
1071 Tcp4Service->MacString,
1072 &gEfiTcp4ServiceBindingProtocolGuid,
1073 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1074 0,
1075 NULL
1076 );
1077
1078 gBS->FreePool (Tcp4Service->MacString);
1079 Tcp4Service->MacString = NULL;
1080 }
1081
1082 /**
1083 Install the device path protocol on the TCP instance.
1084
1085 @param Sock Pointer to the socket representing the TCP instance.
1086
1087 @retval EFI_SUCCESS The device path protocol is installed.
1088 @retval other Failed to install the device path protocol.
1089
1090 **/
1091 EFI_STATUS
1092 TcpInstallDevicePath (
1093 IN SOCKET *Sock
1094 )
1095 {
1096 TCP4_PROTO_DATA *TcpProto;
1097 TCP4_SERVICE_DATA *TcpService;
1098 TCP_CB *Tcb;
1099 IPv4_DEVICE_PATH Ip4DPathNode;
1100 EFI_STATUS Status;
1101
1102 TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
1103 TcpService = TcpProto->TcpService;
1104 Tcb = TcpProto->TcpPcb;
1105
1106 NetLibCreateIPv4DPathNode (
1107 &Ip4DPathNode,
1108 TcpService->ControllerHandle,
1109 Tcb->LocalEnd.Ip,
1110 NTOHS (Tcb->LocalEnd.Port),
1111 Tcb->RemoteEnd.Ip,
1112 NTOHS (Tcb->RemoteEnd.Port),
1113 EFI_IP_PROTO_TCP,
1114 Tcb->UseDefaultAddr
1115 );
1116
1117 Sock->DevicePath = AppendDevicePathNode (
1118 Sock->ParentDevicePath,
1119 (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode
1120 );
1121 if (Sock->DevicePath == NULL) {
1122 return EFI_OUT_OF_RESOURCES;
1123 }
1124
1125 Status = gBS->InstallProtocolInterface (
1126 &Sock->SockHandle,
1127 &gEfiDevicePathProtocolGuid,
1128 EFI_NATIVE_INTERFACE,
1129 Sock->DevicePath
1130 );
1131 if (EFI_ERROR (Status)) {
1132 gBS->FreePool (Sock->DevicePath);
1133 }
1134
1135 return Status;
1136 }