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