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