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