]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Misc.c
Import ArpDxe, Dhcp4Dxe, Ip4Dxe, Mtftp4Dxe, PxeBcDxe and PxeDhcp4Dxe.
[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
4eb65aff 126 Tcb->SndMss = (UINT16) NET_MAX (64, Opt->Mss);\r
8a67d61d 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
772db4bb 270 if (EFI_IP4_EQUAL (*Addr, Tcb->LocalEnd.Ip) &&\r
8a67d61d 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
772db4bb 280 if (EFI_IP4_EQUAL (*Addr, Tcb->LocalEnd.Ip) &&\r
8a67d61d 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
4eb65aff 571 return (UINT16) ~Checksum;\r
8a67d61d 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
4eb65aff 809 UINT32 TcpOld;\r
8a67d61d 810\r
811 switch (Tcb->State) {\r
812 case TCP_CLOSED:\r
813 return -1;\r
814 break;\r
815\r
816 case TCP_LISTEN:\r
817 return -1;\r
818 break;\r
819\r
820 case TCP_SYN_SENT:\r
821 case TCP_SYN_RCVD:\r
822 return 0;\r
823 break;\r
824\r
825 case TCP_ESTABLISHED:\r
4eb65aff 826 TcpOld = TcpRcvWinOld (Tcb);\r
827 if (TcpRcvWinNow (Tcb) > TcpOld) {\r
8a67d61d 828\r
4eb65aff 829 if (TcpOld < Tcb->RcvMss) {\r
8a67d61d 830\r
831 TCP4_DEBUG_TRACE (("TcpOnAppConsume: send a window"\r
832 " update for a window closed Tcb(%x)\n", Tcb));\r
833\r
834 TcpSendAck (Tcb);\r
835 } else if (Tcb->DelayedAck == 0) {\r
836\r
837 TCP4_DEBUG_TRACE (("TcpOnAppConsume: scheduled a delayed"\r
838 " ACK to update window for Tcb(%x)\n", Tcb));\r
839\r
840 Tcb->DelayedAck = 1;\r
841 }\r
842 }\r
843\r
844 break;\r
845\r
846 case TCP_CLOSE_WAIT:\r
847 return 0;\r
848 break;\r
849\r
850 case TCP_FIN_WAIT_1:\r
851 case TCP_FIN_WAIT_2:\r
852 case TCP_CLOSING:\r
853 case TCP_LAST_ACK:\r
854 case TCP_TIME_WAIT:\r
855 return -1;\r
856 break;\r
857 }\r
858\r
859 return -1;\r
860}\r
861\r
862\r
863/**\r
864 Abort the connection by sending a reset segment, called\r
865 when the application wants to abort the connection.\r
866\r
867 @param Tcb Pointer to the TCP_CB of the TCP instance.\r
868\r
869 @return None.\r
870\r
871**/\r
872VOID\r
873TcpOnAppAbort (\r
874 IN TCP_CB *Tcb\r
875 )\r
876{\r
877 TCP4_DEBUG_WARN (("TcpOnAppAbort: connection reset "\r
878 "issued by application for TCB %x\n", Tcb));\r
879\r
880 switch (Tcb->State) {\r
881 case TCP_SYN_RCVD:\r
882 case TCP_ESTABLISHED:\r
883 case TCP_FIN_WAIT_1:\r
884 case TCP_FIN_WAIT_2:\r
885 case TCP_CLOSE_WAIT:\r
886 TcpResetConnection (Tcb);\r
887 break;\r
888 }\r
889\r
890 TcpSetState (Tcb, TCP_CLOSED);\r
891}\r
892\r
893\r
894/**\r
895 Set the Tdp4 variable data.\r
896\r
897 @param Tcp4Service Tcp4 service data.\r
898\r
899 @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.\r
900 @retval other Set variable failed.\r
901\r
902**/\r
903EFI_STATUS\r
904TcpSetVariableData (\r
905 IN TCP4_SERVICE_DATA *Tcp4Service\r
906 )\r
907{\r
908 UINT32 NumConfiguredInstance;\r
909 NET_LIST_ENTRY *Entry;\r
910 TCP_CB *TcpPcb;\r
911 TCP4_PROTO_DATA *TcpProto;\r
912 UINTN VariableDataSize;\r
913 EFI_TCP4_VARIABLE_DATA *Tcp4VariableData;\r
914 EFI_TCP4_SERVICE_POINT *Tcp4ServicePoint;\r
915 CHAR16 *NewMacString;\r
916 EFI_STATUS Status;\r
917\r
918 NumConfiguredInstance = 0;\r
919\r
920 //\r
921 // Go through the running queue to count the instances.\r
922 //\r
923 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
924 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
925\r
926 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
927\r
928 if (TcpProto->TcpService == Tcp4Service) {\r
929 //\r
930 // This tcp instance belongs to the Tcp4Service.\r
931 //\r
932 NumConfiguredInstance++;\r
933 }\r
934 }\r
935\r
936 //\r
937 // Go through the listening queue to count the instances.\r
938 //\r
939 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
940 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
941\r
942 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
943\r
944 if (TcpProto->TcpService == Tcp4Service) {\r
945 //\r
946 // This tcp instance belongs to the Tcp4Service.\r
947 //\r
948 NumConfiguredInstance++;\r
949 }\r
950 }\r
951\r
952 //\r
953 // Calculate the size of the Tcp4VariableData. As there may be no Tcp4 child,\r
954 // we should add extra buffer for the service points only if the number of configured\r
955 // children is more than 1.\r
956 //\r
957 VariableDataSize = sizeof (EFI_TCP4_VARIABLE_DATA);\r
958\r
959 if (NumConfiguredInstance > 1) {\r
960 VariableDataSize += sizeof (EFI_TCP4_SERVICE_POINT) * (NumConfiguredInstance - 1);\r
961 }\r
962\r
963 Tcp4VariableData = NetAllocatePool (VariableDataSize);\r
964 if (Tcp4VariableData == NULL) {\r
965 return EFI_OUT_OF_RESOURCES;\r
966 }\r
967\r
968 Tcp4VariableData->DriverHandle = Tcp4Service->DriverBindingHandle;\r
969 Tcp4VariableData->ServiceCount = NumConfiguredInstance;\r
970\r
971 Tcp4ServicePoint = &Tcp4VariableData->Services[0];\r
972\r
973 //\r
974 // Go through the running queue to fill the service points.\r
975 //\r
976 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
977 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
978\r
979 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
980\r
981 if (TcpProto->TcpService == Tcp4Service) {\r
982 //\r
983 // This tcp instance belongs to the Tcp4Service.\r
984 //\r
985 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
772db4bb 986 NetCopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 987 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
772db4bb 988 NetCopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 989 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
990\r
991 Tcp4ServicePoint++;\r
992 }\r
993 }\r
994\r
995 //\r
996 // Go through the listening queue to fill the service points.\r
997 //\r
998 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
999 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
1000\r
1001 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
1002\r
1003 if (TcpProto->TcpService == Tcp4Service) {\r
1004 //\r
1005 // This tcp instance belongs to the Tcp4Service.\r
1006 //\r
1007 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
772db4bb 1008 NetCopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 1009 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
772db4bb 1010 NetCopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 1011 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
1012\r
1013 Tcp4ServicePoint++;\r
1014 }\r
1015 }\r
1016\r
1017 //\r
1018 // Get the mac string.\r
1019 //\r
1020 Status = NetLibGetMacString (\r
1021 Tcp4Service->ControllerHandle,\r
1022 Tcp4Service->DriverBindingHandle,\r
1023 &NewMacString\r
1024 );\r
1025 if (EFI_ERROR (Status)) {\r
1026 goto ON_ERROR;\r
1027 }\r
1028\r
1029 if (Tcp4Service->MacString != NULL) {\r
1030 //\r
1031 // The variable is set already, we're going to update it.\r
1032 //\r
1033 if (StrCmp (Tcp4Service->MacString, NewMacString) != 0) {\r
1034 //\r
1035 // The mac address is changed, delete the previous variable first.\r
1036 //\r
1037 gRT->SetVariable (\r
1038 Tcp4Service->MacString,\r
1039 &gEfiTcp4ServiceBindingProtocolGuid,\r
1040 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1041 0,\r
1042 NULL\r
1043 );\r
1044 }\r
1045\r
1046 NetFreePool (Tcp4Service->MacString);\r
1047 }\r
1048\r
1049 Tcp4Service->MacString = NewMacString;\r
1050\r
1051 Status = gRT->SetVariable (\r
1052 Tcp4Service->MacString,\r
1053 &gEfiTcp4ServiceBindingProtocolGuid,\r
1054 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1055 VariableDataSize,\r
1056 (VOID *) Tcp4VariableData\r
1057 );\r
1058\r
1059ON_ERROR:\r
1060\r
1061 NetFreePool (Tcp4VariableData);\r
1062\r
1063 return Status;\r
1064}\r
1065\r
1066\r
1067/**\r
1068 Clear the variable and free the resource.\r
1069\r
1070 @param Tcp4Service Tcp4 service data.\r
1071\r
1072 @return None.\r
1073\r
1074**/\r
1075VOID\r
1076TcpClearVariableData (\r
1077 IN TCP4_SERVICE_DATA *Tcp4Service\r
1078 )\r
1079{\r
1080 ASSERT (Tcp4Service->MacString != NULL);\r
1081\r
1082 gRT->SetVariable (\r
1083 Tcp4Service->MacString,\r
1084 &gEfiTcp4ServiceBindingProtocolGuid,\r
1085 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1086 0,\r
1087 NULL\r
1088 );\r
1089\r
1090 NetFreePool (Tcp4Service->MacString);\r
1091 Tcp4Service->MacString = NULL;\r
1092}\r
1093\r