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