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