1 /** @file
2 Misc support routines for tcp.
3
4 Copyright (c) 2005 - 2016, 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
TcpInitTcbLocal(IN OUT TCP_CB * Tcb)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 Tcb->ProbeTimerOn = FALSE;
83 }
84
85
86 /**
87 Initialize the peer related members.
88
89 @param Tcb Pointer to the TCP_CB of this TCP instance.
90 @param Seg Pointer to the segment that contains the peer's
91 intial info.
92 @param Opt Pointer to the options announced by the peer.
93
94 **/
95 VOID
TcpInitTcbPeer(IN OUT TCP_CB * Tcb,IN TCP_SEG * Seg,IN TCP_OPTION * Opt)96 TcpInitTcbPeer (
97 IN OUT TCP_CB *Tcb,
98 IN TCP_SEG *Seg,
99 IN TCP_OPTION *Opt
100 )
101 {
102 UINT16 RcvMss;
103
104 ASSERT ((Tcb != NULL) && (Seg != NULL) && (Opt != NULL));
105 ASSERT (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN));
106
107 Tcb->SndWnd = Seg->Wnd;
108 Tcb->SndWndMax = Tcb->SndWnd;
109 Tcb->SndWl1 = Seg->Seq;
110
111 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
112 Tcb->SndWl2 = Seg->Ack;
113 } else {
114 Tcb->SndWl2 = Tcb->Iss + 1;
115 }
116
117 if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_MSS)) {
118 Tcb->SndMss = (UINT16) MAX (64, Opt->Mss);
119
120 RcvMss = TcpGetRcvMss (Tcb->Sk);
121 if (Tcb->SndMss > RcvMss) {
122 Tcb->SndMss = RcvMss;
123 }
124
125 } else {
126 //
127 // One end doesn't support MSS option, use default.
128 //
129 Tcb->RcvMss = 536;
130 }
131
132 Tcb->CWnd = Tcb->SndMss;
133
134 Tcb->Irs = Seg->Seq;
135 Tcb->RcvNxt = Tcb->Irs + 1;
136
137 Tcb->RcvWl2 = Tcb->RcvNxt;
138
139 if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_WS) &&
140 !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) &&
155 !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS)) {
156
157 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_TS);
158 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS);
159
160 Tcb->TsRecent = Opt->TSVal;
161
162 //
163 // Compute the effective SndMss per RFC1122
164 // section 4.2.2.6. If timestamp option is
165 // enabled, it will always occupy 12 bytes.
166 //
167 Tcb->SndMss -= TCP_OPTION_TS_ALIGNED_LEN;
168 }
169 }
170
171
172 /**
173 Locate a listen TCB that matchs the Local and Remote.
174
175 @param Local Pointer to the local (IP, Port).
176 @param Remote Pointer to the remote (IP, Port).
177
178 @return Pointer to the TCP_CB with the least number of wildcard,
179 if NULL no match is found.
180
181 **/
182 TCP_CB *
TcpLocateListenTcb(IN TCP_PEER * Local,IN TCP_PEER * Remote)183 TcpLocateListenTcb (
184 IN TCP_PEER *Local,
185 IN TCP_PEER *Remote
186 )
187 {
188 LIST_ENTRY *Entry;
189 TCP_CB *Node;
190 TCP_CB *Match;
191 INTN Last;
192 INTN Cur;
193
194 Last = 4;
195 Match = NULL;
196
197 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {
198 Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
199
200 if ((Local->Port != Node->LocalEnd.Port) ||
201 !TCP_PEER_MATCH (Remote, &Node->RemoteEnd) ||
202 !TCP_PEER_MATCH (Local, &Node->LocalEnd)) {
203
204 continue;
205 }
206
207 //
208 // Compute the number of wildcard
209 //
210 Cur = 0;
211 if (Node->RemoteEnd.Ip == 0) {
212 Cur++;
213 }
214
215 if (Node->RemoteEnd.Port == 0) {
216 Cur++;
217 }
218
219 if (Node->LocalEnd.Ip == 0) {
220 Cur++;
221 }
222
223 if (Cur < Last) {
224 if (Cur == 0) {
225 return Node;
226 }
227
228 Last = Cur;
229 Match = Node;
230 }
231 }
232
233 return Match;
234 }
235
236
237 /**
238 Try to find one Tcb whose <Ip, Port> equals to <IN Addr, IN Port>.
239
240 @param Addr Pointer to the IP address needs to match.
241 @param Port The port number needs to match.
242
243 @return The Tcb which matches the <Addr Port> paire exists or not.
244
245 **/
246 BOOLEAN
TcpFindTcbByPeer(IN EFI_IPv4_ADDRESS * Addr,IN TCP_PORTNO Port)247 TcpFindTcbByPeer (
248 IN EFI_IPv4_ADDRESS *Addr,
249 IN TCP_PORTNO Port
250 )
251 {
252 TCP_PORTNO LocalPort;
253 LIST_ENTRY *Entry;
254 TCP_CB *Tcb;
255
256 ASSERT ((Addr != NULL) && (Port != 0));
257
258 LocalPort = HTONS (Port);
259
260 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {
261 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
262
263 if (EFI_IP4_EQUAL (Addr, &Tcb->LocalEnd.Ip) &&
264 (LocalPort == Tcb->LocalEnd.Port)) {
265
266 return TRUE;
267 }
268 }
269
270 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {
271 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
272
273 if (EFI_IP4_EQUAL (Addr, &Tcb->LocalEnd.Ip) &&
274 (LocalPort == Tcb->LocalEnd.Port)) {
275
276 return TRUE;
277 }
278 }
279
280 return FALSE;
281 }
282
283
284 /**
285 Locate the TCP_CB related to the socket pair.
286
287 @param LocalPort The local port number.
288 @param LocalIp The local IP address.
289 @param RemotePort The remote port number.
290 @param RemoteIp The remote IP address.
291 @param Syn Whether to search the listen sockets, if TRUE, the
292 listen sockets are searched.
293
294 @return Pointer to the related TCP_CB, if NULL no match is found.
295
296 **/
297 TCP_CB *
TcpLocateTcb(IN TCP_PORTNO LocalPort,IN UINT32 LocalIp,IN TCP_PORTNO RemotePort,IN UINT32 RemoteIp,IN BOOLEAN Syn)298 TcpLocateTcb (
299 IN TCP_PORTNO LocalPort,
300 IN UINT32 LocalIp,
301 IN TCP_PORTNO RemotePort,
302 IN UINT32 RemoteIp,
303 IN BOOLEAN Syn
304 )
305 {
306 TCP_PEER Local;
307 TCP_PEER Remote;
308 LIST_ENTRY *Entry;
309 TCP_CB *Tcb;
310
311 Local.Port = LocalPort;
312 Local.Ip = LocalIp;
313
314 Remote.Port = RemotePort;
315 Remote.Ip = RemoteIp;
316
317 //
318 // First check for exact match.
319 //
320 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {
321 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
322
323 if (TCP_PEER_EQUAL (&Remote, &Tcb->RemoteEnd) &&
324 TCP_PEER_EQUAL (&Local, &Tcb->LocalEnd)) {
325
326 RemoveEntryList (&Tcb->List);
327 InsertHeadList (&mTcpRunQue, &Tcb->List);
328
329 return Tcb;
330 }
331 }
332
333 //
334 // Only check listen queue when SYN flag is on
335 //
336 if (Syn) {
337 return TcpLocateListenTcb (&Local, &Remote);
338 }
339
340 return NULL;
341 }
342
343
344 /**
345 Insert a Tcb into the proper queue.
346
347 @param Tcb Pointer to the TCP_CB to be inserted.
348
349 @retval 0 The Tcb is inserted successfully.
350 @retval -1 Error condition occurred.
351
352 **/
353 INTN
TcpInsertTcb(IN TCP_CB * Tcb)354 TcpInsertTcb (
355 IN TCP_CB *Tcb
356 )
357 {
358 LIST_ENTRY *Entry;
359 LIST_ENTRY *Head;
360 TCP_CB *Node;
361
362 ASSERT (
363 (Tcb != NULL) &&
364 ((Tcb->State == TCP_LISTEN) ||
365 (Tcb->State == TCP_SYN_SENT) ||
366 (Tcb->State == TCP_SYN_RCVD) ||
367 (Tcb->State == TCP_CLOSED))
368 );
369
370 if (Tcb->LocalEnd.Port == 0) {
371 return -1;
372 }
373
374 Head = &mTcpRunQue;
375
376 if (Tcb->State == TCP_LISTEN) {
377 Head = &mTcpListenQue;
378 }
379
380 //
381 // Check that Tcb isn't already on the list.
382 //
383 NET_LIST_FOR_EACH (Entry, Head) {
384 Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);
385
386 if (TCP_PEER_EQUAL (&Tcb->LocalEnd, &Node->LocalEnd) &&
387 TCP_PEER_EQUAL (&Tcb->RemoteEnd, &Node->RemoteEnd)) {
388
389 return -1;
390 }
391 }
392
393 InsertHeadList (Head, &Tcb->List);
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 *
TcpCloneTcb(IN TCP_CB * Tcb)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
TcpGetIss(VOID)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
TcpGetRcvMss(IN SOCKET * Sock)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
TcpSetState(IN OUT TCP_CB * Tcb,IN UINT8 State)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_NET,
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
TcpChecksum(IN NET_BUF * Nbuf,IN UINT16 HeadSum)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 *
TcpFormatNetbuf(IN TCP_CB * Tcb,IN OUT NET_BUF * Nbuf)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 ASSERT (Head != NULL);
594 Nbuf->Tcp = Head;
595
596 Seg->Seq = NTOHL (Head->Seq);
597 Seg->Ack = NTOHL (Head->Ack);
598 Seg->End = Seg->Seq + (Nbuf->TotalSize - (Head->HeadLen << 2));
599
600 Seg->Urg = NTOHS (Head->Urg);
601 Seg->Wnd = (NTOHS (Head->Wnd) << Tcb->SndWndScale);
602 Seg->Flag = Head->Flag;
603
604 //
605 // SYN and FIN flag occupy one sequence space each.
606 //
607 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
608 //
609 // RFC requires that initial window not be scaled
610 //
611 Seg->Wnd = NTOHS (Head->Wnd);
612 Seg->End++;
613 }
614
615 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
616 Seg->End++;
617 }
618
619 return Seg;
620 }
621
622
623 /**
624 Reset the connection related with Tcb.
625
626 @param Tcb Pointer to the TCP_CB of the connection to be
627 reset.
628
629 **/
630 VOID
TcpResetConnection(IN TCP_CB * Tcb)631 TcpResetConnection (
632 IN TCP_CB *Tcb
633 )
634 {
635 NET_BUF *Nbuf;
636 TCP_HEAD *Nhead;
637
638 Nbuf = NetbufAlloc (TCP_MAX_HEAD);
639
640 if (Nbuf == NULL) {
641 return ;
642 }
643
644 Nhead = (TCP_HEAD *) NetbufAllocSpace (
645 Nbuf,
646 sizeof (TCP_HEAD),
647 NET_BUF_TAIL
648 );
649
650 ASSERT (Nhead != NULL);
651
652 Nbuf->Tcp = Nhead;
653
654 Nhead->Flag = TCP_FLG_RST;
655 Nhead->Seq = HTONL (Tcb->SndNxt);
656 Nhead->Ack = HTONL (Tcb->RcvNxt);
657 Nhead->SrcPort = Tcb->LocalEnd.Port;
658 Nhead->DstPort = Tcb->RemoteEnd.Port;
659 Nhead->HeadLen = (UINT8) (sizeof (TCP_HEAD) >> 2);
660 Nhead->Res = 0;
661 Nhead->Wnd = HTONS (0xFFFF);
662 Nhead->Checksum = 0;
663 Nhead->Urg = 0;
664 Nhead->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);
665
666 TcpSendIpPacket (Tcb, Nbuf, Tcb->LocalEnd.Ip, Tcb->RemoteEnd.Ip);
667
668 NetbufFree (Nbuf);
669 }
670
671
672 /**
673 Initialize an active connection.
674
675 @param Tcb Pointer to the TCP_CB that wants to initiate a
676 connection.
677
678 **/
679 VOID
TcpOnAppConnect(IN OUT TCP_CB * Tcb)680 TcpOnAppConnect (
681 IN OUT TCP_CB *Tcb
682 )
683 {
684 TcpInitTcbLocal (Tcb);
685 TcpSetState (Tcb, TCP_SYN_SENT);
686
687 TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);
688 TcpToSendData (Tcb, 1);
689 }
690
691
692 /**
693 Initiate the connection close procedure, called when
694 applications want to close the connection.
695
696 @param Tcb Pointer to the TCP_CB of this TCP instance.
697
698 **/
699 VOID
TcpOnAppClose(IN OUT TCP_CB * Tcb)700 TcpOnAppClose (
701 IN OUT TCP_CB *Tcb
702 )
703 {
704 ASSERT (Tcb != NULL);
705
706 if (!IsListEmpty (&Tcb->RcvQue) || GET_RCV_DATASIZE (Tcb->Sk) != 0) {
707
708 DEBUG ((EFI_D_WARN, "TcpOnAppClose: connection reset "
709 "because data is lost for TCB %p\n", Tcb));
710
711 TcpResetConnection (Tcb);
712 TcpClose (Tcb);
713 return;
714 }
715
716 switch (Tcb->State) {
717 case TCP_CLOSED:
718 case TCP_LISTEN:
719 case TCP_SYN_SENT:
720 TcpSetState (Tcb, TCP_CLOSED);
721 break;
722
723 case TCP_SYN_RCVD:
724 case TCP_ESTABLISHED:
725 TcpSetState (Tcb, TCP_FIN_WAIT_1);
726 break;
727
728 case TCP_CLOSE_WAIT:
729 TcpSetState (Tcb, TCP_LAST_ACK);
730 break;
731 default:
732 break;
733 }
734
735 TcpToSendData (Tcb, 1);
736 }
737
738
739 /**
740 Check whether the application's newly delivered data can be sent out.
741
742 @param Tcb Pointer to the TCP_CB of this TCP instance.
743
744 @retval 0 Whether the data is sent out or is buffered for
745 further sending.
746 @retval -1 The Tcb is not in a state that data is permitted to
747 be sent out.
748
749 **/
750 INTN
TcpOnAppSend(IN OUT TCP_CB * Tcb)751 TcpOnAppSend (
752 IN OUT TCP_CB *Tcb
753 )
754 {
755
756 switch (Tcb->State) {
757 case TCP_CLOSED:
758 return -1;
759
760 case TCP_LISTEN:
761 return -1;
762
763 case TCP_SYN_SENT:
764 case TCP_SYN_RCVD:
765 return 0;
766
767 case TCP_ESTABLISHED:
768 case TCP_CLOSE_WAIT:
769 TcpToSendData (Tcb, 0);
770 return 0;
771
772 case TCP_FIN_WAIT_1:
773 case TCP_FIN_WAIT_2:
774 case TCP_CLOSING:
775 case TCP_LAST_ACK:
776 case TCP_TIME_WAIT:
777 return -1;
778
779 default:
780 break;
781 }
782
783 return 0;
784 }
785
786
787 /**
788 Application has consumed some data, check whether
789 to send a window updata ack or a delayed ack.
790
791 @param Tcb Pointer to the TCP_CB of this TCP instance.
792
793 **/
794 VOID
TcpOnAppConsume(IN TCP_CB * Tcb)795 TcpOnAppConsume (
796 IN TCP_CB *Tcb
797 )
798 {
799 UINT32 TcpOld;
800
801 switch (Tcb->State) {
802 case TCP_CLOSED:
803 return;
804
805 case TCP_LISTEN:
806 return;
807
808 case TCP_SYN_SENT:
809 case TCP_SYN_RCVD:
810 return;
811
812 case TCP_ESTABLISHED:
813 TcpOld = TcpRcvWinOld (Tcb);
814 if (TcpRcvWinNow (Tcb) > TcpOld) {
815
816 if (TcpOld < Tcb->RcvMss) {
817
818 DEBUG ((EFI_D_NET, "TcpOnAppConsume: send a window"
819 " update for a window closed Tcb %p\n", Tcb));
820
821 TcpSendAck (Tcb);
822 } else if (Tcb->DelayedAck == 0) {
823
824 DEBUG ((EFI_D_NET, "TcpOnAppConsume: scheduled a delayed"
825 " ACK to update window for Tcb %p\n", Tcb));
826
827 Tcb->DelayedAck = 1;
828 }
829 }
830
831 break;
832
833 case TCP_CLOSE_WAIT:
834 return;
835
836 case TCP_FIN_WAIT_1:
837 case TCP_FIN_WAIT_2:
838 case TCP_CLOSING:
839 case TCP_LAST_ACK:
840 case TCP_TIME_WAIT:
841 return;
842
843 default:
844 break;
845 }
846 }
847
848
849 /**
850 Abort the connection by sending a reset segment, called
851 when the application wants to abort the connection.
852
853 @param Tcb Pointer to the TCP_CB of the TCP instance.
854
855 **/
856 VOID
TcpOnAppAbort(IN TCP_CB * Tcb)857 TcpOnAppAbort (
858 IN TCP_CB *Tcb
859 )
860 {
861 DEBUG ((EFI_D_WARN, "TcpOnAppAbort: connection reset "
862 "issued by application for TCB %p\n", Tcb));
863
864 switch (Tcb->State) {
865 case TCP_SYN_RCVD:
866 case TCP_ESTABLISHED:
867 case TCP_FIN_WAIT_1:
868 case TCP_FIN_WAIT_2:
869 case TCP_CLOSE_WAIT:
870 TcpResetConnection (Tcb);
871 break;
872 default:
873 break;
874 }
875
876 TcpSetState (Tcb, TCP_CLOSED);
877 }
878
879 /**
880 Install the device path protocol on the TCP instance.
881
882 @param Sock Pointer to the socket representing the TCP instance.
883
884 @retval EFI_SUCCESS The device path protocol is installed.
885 @retval other Failed to install the device path protocol.
886
887 **/
888 EFI_STATUS
TcpInstallDevicePath(IN SOCKET * Sock)889 TcpInstallDevicePath (
890 IN SOCKET *Sock
891 )
892 {
893 TCP4_PROTO_DATA *TcpProto;
894 TCP4_SERVICE_DATA *TcpService;
895 TCP_CB *Tcb;
896 IPv4_DEVICE_PATH Ip4DPathNode;
897 EFI_STATUS Status;
898 TCP_PORTNO LocalPort;
899 TCP_PORTNO RemotePort;
900
901 TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
902 TcpService = TcpProto->TcpService;
903 Tcb = TcpProto->TcpPcb;
904
905 LocalPort = NTOHS (Tcb->LocalEnd.Port);
906 RemotePort = NTOHS (Tcb->RemoteEnd.Port);
907 NetLibCreateIPv4DPathNode (
908 &Ip4DPathNode,
909 TcpService->ControllerHandle,
910 Tcb->LocalEnd.Ip,
911 LocalPort,
912 Tcb->RemoteEnd.Ip,
913 RemotePort,
914 EFI_IP_PROTO_TCP,
915 Tcb->UseDefaultAddr
916 );
917
918 IP4_COPY_ADDRESS (&Ip4DPathNode.SubnetMask, &Tcb->SubnetMask);
919
920 Sock->DevicePath = AppendDevicePathNode (
921 Sock->ParentDevicePath,
922 (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode
923 );
924 if (Sock->DevicePath == NULL) {
925 return EFI_OUT_OF_RESOURCES;
926 }
927
928 Status = gBS->InstallProtocolInterface (
929 &Sock->SockHandle,
930 &gEfiDevicePathProtocolGuid,
931 EFI_NATIVE_INTERFACE,
932 Sock->DevicePath
933 );
934 if (EFI_ERROR (Status)) {
935 FreePool (Sock->DevicePath);
936 }
937
938 return Status;
939 }
940