1. Sync the latest network stack. Add NetLibCreateIPv4DPathNode () in netlib library.
[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) NET_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
430 Clone = NetAllocatePool (sizeof (TCP_CB));
431
432 if (Clone == NULL) {
433 return NULL;
434
435 }
436
437 NetCopyMem (Clone, Tcb, sizeof (TCP_CB));
438
439 //
440 // Increate the reference count of the shared IpInfo.
441 //
442 NET_GET_REF (Tcb->IpInfo);
443
444 NetListInit (&Clone->List);
445 NetListInit (&Clone->SndQue);
446 NetListInit (&Clone->RcvQue);
447
448 Clone->Sk = SockClone (Tcb->Sk);
449 if (Clone->Sk == NULL) {
450 TCP4_DEBUG_ERROR (("TcpCloneTcb: failed to clone a sock\n"));
451 NetFreePool (Clone);
452 return NULL;
453 }
454
455 ((TCP4_PROTO_DATA *) (Clone->Sk->ProtoReserved))->TcpPcb = Clone;
456
457 //
458 // Open the device path on the handle where service binding resides on.
459 //
460 TcpService = ((TCP4_PROTO_DATA *) (Clone->Sk->ProtoReserved))->TcpService;
461 gBS->OpenProtocol (
462 TcpService->ControllerHandle,
463 &gEfiDevicePathProtocolGuid,
464 (VOID **) &Clone->Sk->ParentDevicePath,
465 TcpService->DriverBindingHandle,
466 Clone->Sk->SockHandle,
467 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
468 );
469
470 return Clone;
471 }
472
473
474 /**
475 Compute an ISS to be used by a new connection.
476
477 None
478
479 @return The result ISS.
480
481 **/
482 TCP_SEQNO
483 TcpGetIss (
484 VOID
485 )
486 {
487 mTcpGlobalIss += 2048;
488 return mTcpGlobalIss;
489 }
490
491
492 /**
493 Get the local mss.
494
495 None
496
497 @return The mss size.
498
499 **/
500 UINT16
501 TcpGetRcvMss (
502 IN SOCKET *Sock
503 )
504 {
505 EFI_SIMPLE_NETWORK_MODE SnpMode;
506 TCP4_PROTO_DATA *TcpProto;
507 EFI_IP4_PROTOCOL *Ip;
508
509 ASSERT (Sock);
510
511 TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
512 Ip = TcpProto->TcpService->IpIo->Ip;
513 ASSERT (Ip);
514
515 Ip->GetModeData (Ip, NULL, NULL, &SnpMode);
516
517 return (UINT16) (SnpMode.MaxPacketSize - 40);
518 }
519
520
521 /**
522 Set the Tcb's state.
523
524 @param Tcb Pointer to the TCP_CB of this TCP instance.
525 @param State The state to be set.
526
527 @return None
528
529 **/
530 VOID
531 TcpSetState (
532 IN TCP_CB *Tcb,
533 IN UINT8 State
534 )
535 {
536 TCP4_DEBUG_TRACE (
537 ("Tcb (%x) state %s --> %s\n",
538 Tcb,
539 mTcpStateName[Tcb->State],
540 mTcpStateName[State])
541 );
542
543 Tcb->State = State;
544
545 switch (State) {
546 case TCP_ESTABLISHED:
547
548 SockConnEstablished (Tcb->Sk);
549
550 if (Tcb->Parent != NULL) {
551 //
552 // A new connection is accepted by a listening socket, install
553 // the device path.
554 //
555 TcpInstallDevicePath (Tcb->Sk);
556 }
557
558 break;
559
560 case TCP_CLOSED:
561
562 SockConnClosed (Tcb->Sk);
563
564 break;
565 }
566 }
567
568
569 /**
570 Compute the TCP segment's checksum.
571
572 @param Nbuf Pointer to the buffer that contains the TCP
573 segment.
574 @param HeadSum The checksum value of the fixed part of pseudo
575 header.
576
577 @return The checksum value.
578
579 **/
580 UINT16
581 TcpChecksum (
582 IN NET_BUF *Nbuf,
583 IN UINT16 HeadSum
584 )
585 {
586 UINT16 Checksum;
587
588 Checksum = NetbufChecksum (Nbuf);
589 Checksum = NetAddChecksum (Checksum, HeadSum);
590
591 Checksum = NetAddChecksum (
592 Checksum,
593 HTONS ((UINT16) Nbuf->TotalSize)
594 );
595
596 return (UINT16) ~Checksum;
597 }
598
599
600 /**
601 Translate the information from the head of the received TCP
602 segment Nbuf contains and fill it into a TCP_SEG structure.
603
604 @param Tcb Pointer to the TCP_CB of this TCP instance.
605 @param Nbuf Pointer to the buffer contains the TCP segment.
606
607 @return Pointer to the TCP_SEG that contains the translated TCP head information.
608
609 **/
610 TCP_SEG *
611 TcpFormatNetbuf (
612 IN TCP_CB *Tcb,
613 IN NET_BUF *Nbuf
614 )
615 {
616 TCP_SEG *Seg;
617 TCP_HEAD *Head;
618
619 Seg = TCPSEG_NETBUF (Nbuf);
620 Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);
621 Nbuf->Tcp = Head;
622
623 Seg->Seq = NTOHL (Head->Seq);
624 Seg->Ack = NTOHL (Head->Ack);
625 Seg->End = Seg->Seq + (Nbuf->TotalSize - (Head->HeadLen << 2));
626
627 Seg->Urg = NTOHS (Head->Urg);
628 Seg->Wnd = (NTOHS (Head->Wnd) << Tcb->SndWndScale);
629 Seg->Flag = Head->Flag;
630
631 //
632 // SYN and FIN flag occupy one sequence space each.
633 //
634 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
635 //
636 // RFC requires that initial window not be scaled
637 //
638 Seg->Wnd = NTOHS (Head->Wnd);
639 Seg->End++;
640 }
641
642 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
643 Seg->End++;
644 }
645
646 return Seg;
647 }
648
649
650 /**
651 Reset the connection related with Tcb.
652
653 @param Tcb Pointer to the TCP_CB of the connection to be
654 reset.
655
656 @return None
657
658 **/
659 VOID
660 TcpResetConnection (
661 IN TCP_CB *Tcb
662 )
663 {
664 NET_BUF *Nbuf;
665 TCP_HEAD *Nhead;
666
667 Nbuf = NetbufAlloc (TCP_MAX_HEAD);
668
669 if (Nbuf == NULL) {
670 return ;
671 }
672
673 Nhead = (TCP_HEAD *) NetbufAllocSpace (
674 Nbuf,
675 sizeof (TCP_HEAD),
676 NET_BUF_TAIL
677 );
678
679 ASSERT (Nhead != NULL);
680
681 Nbuf->Tcp = Nhead;
682
683 Nhead->Flag = TCP_FLG_RST;
684 Nhead->Seq = HTONL (Tcb->SndNxt);
685 Nhead->Ack = HTONL (Tcb->RcvNxt);
686 Nhead->SrcPort = Tcb->LocalEnd.Port;
687 Nhead->DstPort = Tcb->RemoteEnd.Port;
688 Nhead->HeadLen = (sizeof (TCP_HEAD) >> 2);
689 Nhead->Res = 0;
690 Nhead->Wnd = HTONS (0xFFFF);
691 Nhead->Checksum = 0;
692 Nhead->Urg = 0;
693 Nhead->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);
694
695 TcpSendIpPacket (Tcb, Nbuf, Tcb->LocalEnd.Ip, Tcb->RemoteEnd.Ip);
696
697 NetbufFree (Nbuf);
698 }
699
700
701 /**
702 Initialize an active connection,
703
704 @param Tcb Pointer to the TCP_CB that wants to initiate a
705 connection.
706
707 @return None
708
709 **/
710 VOID
711 TcpOnAppConnect (
712 IN TCP_CB *Tcb
713 )
714 {
715 TcpInitTcbLocal (Tcb);
716 TcpSetState (Tcb, TCP_SYN_SENT);
717
718 TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);
719 TcpToSendData (Tcb, 1);
720 }
721
722
723 /**
724 Initiate the connection close procedure, called when
725 applications want to close the connection.
726
727 @param Tcb Pointer to the TCP_CB of this TCP instance.
728
729 @return None.
730
731 **/
732 VOID
733 TcpOnAppClose (
734 IN TCP_CB *Tcb
735 )
736 {
737 ASSERT (Tcb);
738
739 if (!NetListIsEmpty (&Tcb->RcvQue) || GET_RCV_DATASIZE (Tcb->Sk)) {
740
741 TCP4_DEBUG_WARN (("TcpOnAppClose: connection reset "
742 "because data is lost for TCB %x\n", Tcb));
743
744 TcpResetConnection (Tcb);
745 TcpClose (Tcb);
746 return;
747 }
748
749 switch (Tcb->State) {
750 case TCP_CLOSED:
751 case TCP_LISTEN:
752 case TCP_SYN_SENT:
753 TcpSetState (Tcb, TCP_CLOSED);
754 break;
755
756 case TCP_SYN_RCVD:
757 case TCP_ESTABLISHED:
758 TcpSetState (Tcb, TCP_FIN_WAIT_1);
759 break;
760
761 case TCP_CLOSE_WAIT:
762 TcpSetState (Tcb, TCP_LAST_ACK);
763 break;
764 }
765
766 TcpToSendData (Tcb, 1);
767 }
768
769
770 /**
771 Check whether the application's newly delivered data
772 can be sent out.
773
774 @param Tcb Pointer to the TCP_CB of this TCP instance.
775
776 @retval 0 Whether the data is sent out or is buffered for
777 further sending.
778 @retval -1 The Tcb is not in a state that data is permitted to
779 be sent out.
780
781 **/
782 INTN
783 TcpOnAppSend (
784 IN TCP_CB *Tcb
785 )
786 {
787
788 switch (Tcb->State) {
789 case TCP_CLOSED:
790 return -1;
791 break;
792
793 case TCP_LISTEN:
794 return -1;
795 break;
796
797 case TCP_SYN_SENT:
798 case TCP_SYN_RCVD:
799 return 0;
800 break;
801
802 case TCP_ESTABLISHED:
803 case TCP_CLOSE_WAIT:
804 TcpToSendData (Tcb, 0);
805 return 0;
806 break;
807
808 case TCP_FIN_WAIT_1:
809 case TCP_FIN_WAIT_2:
810 case TCP_CLOSING:
811 case TCP_LAST_ACK:
812 case TCP_TIME_WAIT:
813 return -1;
814 break;
815 }
816
817 return 0;
818 }
819
820
821 /**
822 Application has consumed some data, check whether
823 to send a window updata ack or a delayed ack.
824
825 @param Tcb Pointer to the TCP_CB of this TCP instance.
826
827
828 **/
829 INTN
830 TcpOnAppConsume (
831 IN TCP_CB *Tcb
832 )
833 {
834 UINT32 TcpOld;
835
836 switch (Tcb->State) {
837 case TCP_CLOSED:
838 return -1;
839 break;
840
841 case TCP_LISTEN:
842 return -1;
843 break;
844
845 case TCP_SYN_SENT:
846 case TCP_SYN_RCVD:
847 return 0;
848 break;
849
850 case TCP_ESTABLISHED:
851 TcpOld = TcpRcvWinOld (Tcb);
852 if (TcpRcvWinNow (Tcb) > TcpOld) {
853
854 if (TcpOld < Tcb->RcvMss) {
855
856 TCP4_DEBUG_TRACE (("TcpOnAppConsume: send a window"
857 " update for a window closed Tcb(%x)\n", Tcb));
858
859 TcpSendAck (Tcb);
860 } else if (Tcb->DelayedAck == 0) {
861
862 TCP4_DEBUG_TRACE (("TcpOnAppConsume: scheduled a delayed"
863 " ACK to update window for Tcb(%x)\n", Tcb));
864
865 Tcb->DelayedAck = 1;
866 }
867 }
868
869 break;
870
871 case TCP_CLOSE_WAIT:
872 return 0;
873 break;
874
875 case TCP_FIN_WAIT_1:
876 case TCP_FIN_WAIT_2:
877 case TCP_CLOSING:
878 case TCP_LAST_ACK:
879 case TCP_TIME_WAIT:
880 return -1;
881 break;
882 }
883
884 return -1;
885 }
886
887
888 /**
889 Abort the connection by sending a reset segment, called
890 when the application wants to abort the connection.
891
892 @param Tcb Pointer to the TCP_CB of the TCP instance.
893
894 @return None.
895
896 **/
897 VOID
898 TcpOnAppAbort (
899 IN TCP_CB *Tcb
900 )
901 {
902 TCP4_DEBUG_WARN (("TcpOnAppAbort: connection reset "
903 "issued by application for TCB %x\n", Tcb));
904
905 switch (Tcb->State) {
906 case TCP_SYN_RCVD:
907 case TCP_ESTABLISHED:
908 case TCP_FIN_WAIT_1:
909 case TCP_FIN_WAIT_2:
910 case TCP_CLOSE_WAIT:
911 TcpResetConnection (Tcb);
912 break;
913 }
914
915 TcpSetState (Tcb, TCP_CLOSED);
916 }
917
918
919 /**
920 Set the Tdp4 variable data.
921
922 @param Tcp4Service Tcp4 service data.
923
924 @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.
925 @retval other Set variable failed.
926
927 **/
928 EFI_STATUS
929 TcpSetVariableData (
930 IN TCP4_SERVICE_DATA *Tcp4Service
931 )
932 {
933 UINT32 NumConfiguredInstance;
934 NET_LIST_ENTRY *Entry;
935 TCP_CB *TcpPcb;
936 TCP4_PROTO_DATA *TcpProto;
937 UINTN VariableDataSize;
938 EFI_TCP4_VARIABLE_DATA *Tcp4VariableData;
939 EFI_TCP4_SERVICE_POINT *Tcp4ServicePoint;
940 CHAR16 *NewMacString;
941 EFI_STATUS Status;
942
943 NumConfiguredInstance = 0;
944
945 //
946 // Go through the running queue to count the instances.
947 //
948 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {
949 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
950
951 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;
952
953 if (TcpProto->TcpService == Tcp4Service) {
954 //
955 // This tcp instance belongs to the Tcp4Service.
956 //
957 NumConfiguredInstance++;
958 }
959 }
960
961 //
962 // Go through the listening queue to count the instances.
963 //
964 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {
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 // Calculate the size of the Tcp4VariableData. As there may be no Tcp4 child,
979 // we should add extra buffer for the service points only if the number of configured
980 // children is more than 1.
981 //
982 VariableDataSize = sizeof (EFI_TCP4_VARIABLE_DATA);
983
984 if (NumConfiguredInstance > 1) {
985 VariableDataSize += sizeof (EFI_TCP4_SERVICE_POINT) * (NumConfiguredInstance - 1);
986 }
987
988 Tcp4VariableData = NetAllocatePool (VariableDataSize);
989 if (Tcp4VariableData == NULL) {
990 return EFI_OUT_OF_RESOURCES;
991 }
992
993 Tcp4VariableData->DriverHandle = Tcp4Service->DriverBindingHandle;
994 Tcp4VariableData->ServiceCount = NumConfiguredInstance;
995
996 Tcp4ServicePoint = &Tcp4VariableData->Services[0];
997
998 //
999 // Go through the running queue to fill the service points.
1000 //
1001 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {
1002 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
1003
1004 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;
1005
1006 if (TcpProto->TcpService == Tcp4Service) {
1007 //
1008 // This tcp instance belongs to the Tcp4Service.
1009 //
1010 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;
1011 NetCopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
1012 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);
1013 NetCopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
1014 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);
1015
1016 Tcp4ServicePoint++;
1017 }
1018 }
1019
1020 //
1021 // Go through the listening queue to fill the service points.
1022 //
1023 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {
1024 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
1025
1026 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;
1027
1028 if (TcpProto->TcpService == Tcp4Service) {
1029 //
1030 // This tcp instance belongs to the Tcp4Service.
1031 //
1032 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;
1033 NetCopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
1034 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);
1035 NetCopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
1036 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);
1037
1038 Tcp4ServicePoint++;
1039 }
1040 }
1041
1042 //
1043 // Get the mac string.
1044 //
1045 Status = NetLibGetMacString (
1046 Tcp4Service->ControllerHandle,
1047 Tcp4Service->DriverBindingHandle,
1048 &NewMacString
1049 );
1050 if (EFI_ERROR (Status)) {
1051 goto ON_ERROR;
1052 }
1053
1054 if (Tcp4Service->MacString != NULL) {
1055 //
1056 // The variable is set already, we're going to update it.
1057 //
1058 if (StrCmp (Tcp4Service->MacString, NewMacString) != 0) {
1059 //
1060 // The mac address is changed, delete the previous variable first.
1061 //
1062 gRT->SetVariable (
1063 Tcp4Service->MacString,
1064 &gEfiTcp4ServiceBindingProtocolGuid,
1065 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1066 0,
1067 NULL
1068 );
1069 }
1070
1071 NetFreePool (Tcp4Service->MacString);
1072 }
1073
1074 Tcp4Service->MacString = NewMacString;
1075
1076 Status = gRT->SetVariable (
1077 Tcp4Service->MacString,
1078 &gEfiTcp4ServiceBindingProtocolGuid,
1079 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1080 VariableDataSize,
1081 (VOID *) Tcp4VariableData
1082 );
1083
1084 ON_ERROR:
1085
1086 NetFreePool (Tcp4VariableData);
1087
1088 return Status;
1089 }
1090
1091
1092 /**
1093 Clear the variable and free the resource.
1094
1095 @param Tcp4Service Tcp4 service data.
1096
1097 @return None.
1098
1099 **/
1100 VOID
1101 TcpClearVariableData (
1102 IN TCP4_SERVICE_DATA *Tcp4Service
1103 )
1104 {
1105 ASSERT (Tcp4Service->MacString != NULL);
1106
1107 gRT->SetVariable (
1108 Tcp4Service->MacString,
1109 &gEfiTcp4ServiceBindingProtocolGuid,
1110 EFI_VARIABLE_BOOTSERVICE_ACCESS,
1111 0,
1112 NULL
1113 );
1114
1115 NetFreePool (Tcp4Service->MacString);
1116 Tcp4Service->MacString = NULL;
1117 }
1118
1119 EFI_STATUS
1120 TcpInstallDevicePath (
1121 IN SOCKET *Sock
1122 )
1123 /*++
1124
1125 Routine Description:
1126
1127 Install the device path protocol on the TCP instance.
1128
1129 Arguments:
1130
1131 Sock - Pointer to the socket representing the TCP instance.
1132
1133 Returns:
1134
1135 EFI_SUCCESS - The device path protocol is installed.
1136 other - Failed to install the device path protocol.
1137
1138 --*/
1139 {
1140 TCP4_PROTO_DATA *TcpProto;
1141 TCP4_SERVICE_DATA *TcpService;
1142 TCP_CB *Tcb;
1143 IPv4_DEVICE_PATH Ip4DPathNode;
1144 EFI_STATUS Status;
1145
1146 TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
1147 TcpService = TcpProto->TcpService;
1148 Tcb = TcpProto->TcpPcb;
1149
1150 NetLibCreateIPv4DPathNode (
1151 &Ip4DPathNode,
1152 TcpService->ControllerHandle,
1153 Tcb->LocalEnd.Ip,
1154 NTOHS (Tcb->LocalEnd.Port),
1155 Tcb->RemoteEnd.Ip,
1156 NTOHS (Tcb->RemoteEnd.Port),
1157 EFI_IP_PROTO_TCP,
1158 Tcb->UseDefaultAddr
1159 );
1160
1161 Sock->DevicePath = AppendDevicePathNode (
1162 Sock->ParentDevicePath,
1163 (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode
1164 );
1165 if (Sock->DevicePath == NULL) {
1166 return EFI_OUT_OF_RESOURCES;
1167 }
1168
1169 Status = gBS->InstallProtocolInterface (
1170 &Sock->SockHandle,
1171 &gEfiDevicePathProtocolGuid,
1172 EFI_NATIVE_INTERFACE,
1173 Sock->DevicePath
1174 );
1175 if (EFI_ERROR (Status)) {
1176 NetFreePool (Sock->DevicePath);
1177 }
1178
1179 return Status;
1180 }