VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/NetworkPkg/TcpDxe/TcpMisc.c@ 106411

最後變更 在這個檔案從106411是 105670,由 vboxsync 提交於 6 月 前

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette