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