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