]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Misc.c
Sync the latest version from R8.
[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
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
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
c4a62a12 429 EFI_IP4_PROTOCOL *Ip4;\r
8a67d61d 430\r
431 Clone = NetAllocatePool (sizeof (TCP_CB));\r
432\r
433 if (Clone == NULL) {\r
434 return NULL;\r
435\r
436 }\r
437\r
438 NetCopyMem (Clone, Tcb, sizeof (TCP_CB));\r
439\r
440 //\r
441 // Increate the reference count of the shared IpInfo.\r
442 //\r
443 NET_GET_REF (Tcb->IpInfo);\r
444\r
445 NetListInit (&Clone->List);\r
446 NetListInit (&Clone->SndQue);\r
447 NetListInit (&Clone->RcvQue);\r
448\r
449 Clone->Sk = SockClone (Tcb->Sk);\r
450 if (Clone->Sk == NULL) {\r
451 TCP4_DEBUG_ERROR (("TcpCloneTcb: failed to clone a sock\n"));\r
452 NetFreePool (Clone);\r
453 return NULL;\r
454 }\r
455\r
456 ((TCP4_PROTO_DATA *) (Clone->Sk->ProtoReserved))->TcpPcb = Clone;\r
457\r
c4a62a12 458 TcpService = ((TCP4_PROTO_DATA *) (Clone->Sk->ProtoReserved))->TcpService;\r
459\r
460 NetListInsertTail (&TcpService->SocketList, &Clone->Sk->Link);\r
461\r
e5e12de7 462 //\r
463 // Open the device path on the handle where service binding resides on.\r
464 //\r
e5e12de7 465 gBS->OpenProtocol (\r
466 TcpService->ControllerHandle,\r
467 &gEfiDevicePathProtocolGuid,\r
468 (VOID **) &Clone->Sk->ParentDevicePath,\r
469 TcpService->DriverBindingHandle,\r
470 Clone->Sk->SockHandle,\r
471 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
472 );\r
473\r
c4a62a12 474 //\r
475 // Open the ip protocol by child controller.\r
476 //\r
477 gBS->OpenProtocol (\r
478 TcpService->IpIo->ChildHandle,\r
479 &gEfiIp4ProtocolGuid,\r
480 (VOID **) &Ip4,\r
481 TcpService->DriverBindingHandle,\r
482 Clone->Sk->SockHandle,\r
483 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
484 );\r
485\r
8a67d61d 486 return Clone;\r
487}\r
488\r
489\r
490/**\r
491 Compute an ISS to be used by a new connection.\r
492\r
493 None\r
494\r
495 @return The result ISS.\r
496\r
497**/\r
498TCP_SEQNO\r
499TcpGetIss (\r
500 VOID\r
501 )\r
502{\r
503 mTcpGlobalIss += 2048;\r
504 return mTcpGlobalIss;\r
505}\r
506\r
507\r
508/**\r
509 Get the local mss.\r
510\r
511 None\r
512\r
513 @return The mss size.\r
514\r
515**/\r
516UINT16\r
517TcpGetRcvMss (\r
518 IN SOCKET *Sock\r
519 )\r
520{\r
521 EFI_SIMPLE_NETWORK_MODE SnpMode;\r
522 TCP4_PROTO_DATA *TcpProto;\r
523 EFI_IP4_PROTOCOL *Ip;\r
524\r
525 ASSERT (Sock);\r
526\r
527 TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
528 Ip = TcpProto->TcpService->IpIo->Ip;\r
529 ASSERT (Ip);\r
530\r
531 Ip->GetModeData (Ip, NULL, NULL, &SnpMode);\r
532\r
533 return (UINT16) (SnpMode.MaxPacketSize - 40);\r
534}\r
535\r
536\r
537/**\r
538 Set the Tcb's state.\r
539\r
540 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
541 @param State The state to be set.\r
542\r
543 @return None\r
544\r
545**/\r
546VOID\r
547TcpSetState (\r
548 IN TCP_CB *Tcb,\r
549 IN UINT8 State\r
550 )\r
551{\r
552 TCP4_DEBUG_TRACE (\r
553 ("Tcb (%x) state %s --> %s\n",\r
554 Tcb,\r
555 mTcpStateName[Tcb->State],\r
556 mTcpStateName[State])\r
557 );\r
558\r
559 Tcb->State = State;\r
560\r
561 switch (State) {\r
562 case TCP_ESTABLISHED:\r
563\r
564 SockConnEstablished (Tcb->Sk);\r
e5e12de7 565\r
566 if (Tcb->Parent != NULL) {\r
567 //\r
568 // A new connection is accepted by a listening socket, install\r
569 // the device path.\r
570 //\r
571 TcpInstallDevicePath (Tcb->Sk);\r
572 }\r
573\r
8a67d61d 574 break;\r
575\r
576 case TCP_CLOSED:\r
577\r
578 SockConnClosed (Tcb->Sk);\r
579\r
580 break;\r
581 }\r
582}\r
583\r
584\r
585/**\r
586 Compute the TCP segment's checksum.\r
587\r
588 @param Nbuf Pointer to the buffer that contains the TCP\r
589 segment.\r
590 @param HeadSum The checksum value of the fixed part of pseudo\r
591 header.\r
592\r
593 @return The checksum value.\r
594\r
595**/\r
596UINT16\r
597TcpChecksum (\r
598 IN NET_BUF *Nbuf,\r
599 IN UINT16 HeadSum\r
600 )\r
601{\r
602 UINT16 Checksum;\r
603\r
604 Checksum = NetbufChecksum (Nbuf);\r
605 Checksum = NetAddChecksum (Checksum, HeadSum);\r
606\r
607 Checksum = NetAddChecksum (\r
608 Checksum,\r
609 HTONS ((UINT16) Nbuf->TotalSize)\r
610 );\r
611\r
4eb65aff 612 return (UINT16) ~Checksum;\r
8a67d61d 613}\r
614\r
615\r
616/**\r
617 Translate the information from the head of the received TCP\r
618 segment Nbuf contains and fill it into a TCP_SEG structure.\r
619\r
620 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
621 @param Nbuf Pointer to the buffer contains the TCP segment.\r
622\r
623 @return Pointer to the TCP_SEG that contains the translated TCP head information.\r
624\r
625**/\r
626TCP_SEG *\r
627TcpFormatNetbuf (\r
628 IN TCP_CB *Tcb,\r
629 IN NET_BUF *Nbuf\r
630 )\r
631{\r
632 TCP_SEG *Seg;\r
633 TCP_HEAD *Head;\r
634\r
635 Seg = TCPSEG_NETBUF (Nbuf);\r
636 Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
637 Nbuf->Tcp = Head;\r
638\r
639 Seg->Seq = NTOHL (Head->Seq);\r
640 Seg->Ack = NTOHL (Head->Ack);\r
641 Seg->End = Seg->Seq + (Nbuf->TotalSize - (Head->HeadLen << 2));\r
642\r
643 Seg->Urg = NTOHS (Head->Urg);\r
644 Seg->Wnd = (NTOHS (Head->Wnd) << Tcb->SndWndScale);\r
645 Seg->Flag = Head->Flag;\r
646\r
647 //\r
648 // SYN and FIN flag occupy one sequence space each.\r
649 //\r
650 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
651 //\r
652 // RFC requires that initial window not be scaled\r
653 //\r
654 Seg->Wnd = NTOHS (Head->Wnd);\r
655 Seg->End++;\r
656 }\r
657\r
658 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
659 Seg->End++;\r
660 }\r
661\r
662 return Seg;\r
663}\r
664\r
665\r
666/**\r
667 Reset the connection related with Tcb.\r
668\r
669 @param Tcb Pointer to the TCP_CB of the connection to be\r
670 reset.\r
671\r
672 @return None\r
673\r
674**/\r
675VOID\r
676TcpResetConnection (\r
677 IN TCP_CB *Tcb\r
678 )\r
679{\r
680 NET_BUF *Nbuf;\r
681 TCP_HEAD *Nhead;\r
682\r
683 Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
684\r
685 if (Nbuf == NULL) {\r
686 return ;\r
687 }\r
688\r
689 Nhead = (TCP_HEAD *) NetbufAllocSpace (\r
690 Nbuf,\r
691 sizeof (TCP_HEAD),\r
692 NET_BUF_TAIL\r
693 );\r
694\r
695 ASSERT (Nhead != NULL);\r
696\r
697 Nbuf->Tcp = Nhead;\r
698\r
699 Nhead->Flag = TCP_FLG_RST;\r
700 Nhead->Seq = HTONL (Tcb->SndNxt);\r
701 Nhead->Ack = HTONL (Tcb->RcvNxt);\r
702 Nhead->SrcPort = Tcb->LocalEnd.Port;\r
703 Nhead->DstPort = Tcb->RemoteEnd.Port;\r
704 Nhead->HeadLen = (sizeof (TCP_HEAD) >> 2);\r
705 Nhead->Res = 0;\r
706 Nhead->Wnd = HTONS (0xFFFF);\r
707 Nhead->Checksum = 0;\r
708 Nhead->Urg = 0;\r
709 Nhead->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);\r
710\r
711 TcpSendIpPacket (Tcb, Nbuf, Tcb->LocalEnd.Ip, Tcb->RemoteEnd.Ip);\r
712\r
713 NetbufFree (Nbuf);\r
714}\r
715\r
716\r
717/**\r
718 Initialize an active connection,\r
719\r
720 @param Tcb Pointer to the TCP_CB that wants to initiate a\r
721 connection.\r
722\r
723 @return None\r
724\r
725**/\r
726VOID\r
727TcpOnAppConnect (\r
728 IN TCP_CB *Tcb\r
729 )\r
730{\r
731 TcpInitTcbLocal (Tcb);\r
732 TcpSetState (Tcb, TCP_SYN_SENT);\r
733\r
734 TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
735 TcpToSendData (Tcb, 1);\r
736}\r
737\r
738\r
739/**\r
740 Initiate the connection close procedure, called when\r
741 applications want to close the connection.\r
742\r
743 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
744\r
745 @return None.\r
746\r
747**/\r
748VOID\r
749TcpOnAppClose (\r
750 IN TCP_CB *Tcb\r
751 )\r
752{\r
753 ASSERT (Tcb);\r
754\r
755 if (!NetListIsEmpty (&Tcb->RcvQue) || GET_RCV_DATASIZE (Tcb->Sk)) {\r
756\r
757 TCP4_DEBUG_WARN (("TcpOnAppClose: connection reset "\r
758 "because data is lost for TCB %x\n", Tcb));\r
759\r
760 TcpResetConnection (Tcb);\r
761 TcpClose (Tcb);\r
762 return;\r
763 }\r
764\r
765 switch (Tcb->State) {\r
766 case TCP_CLOSED:\r
767 case TCP_LISTEN:\r
768 case TCP_SYN_SENT:\r
769 TcpSetState (Tcb, TCP_CLOSED);\r
770 break;\r
771\r
772 case TCP_SYN_RCVD:\r
773 case TCP_ESTABLISHED:\r
774 TcpSetState (Tcb, TCP_FIN_WAIT_1);\r
775 break;\r
776\r
777 case TCP_CLOSE_WAIT:\r
778 TcpSetState (Tcb, TCP_LAST_ACK);\r
779 break;\r
780 }\r
781\r
782 TcpToSendData (Tcb, 1);\r
783}\r
784\r
785\r
786/**\r
787 Check whether the application's newly delivered data\r
788 can be sent out.\r
789\r
790 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
791\r
792 @retval 0 Whether the data is sent out or is buffered for\r
793 further sending.\r
794 @retval -1 The Tcb is not in a state that data is permitted to\r
795 be sent out.\r
796\r
797**/\r
798INTN\r
799TcpOnAppSend (\r
800 IN TCP_CB *Tcb\r
801 )\r
802{\r
803\r
804 switch (Tcb->State) {\r
805 case TCP_CLOSED:\r
806 return -1;\r
807 break;\r
808\r
809 case TCP_LISTEN:\r
810 return -1;\r
811 break;\r
812\r
813 case TCP_SYN_SENT:\r
814 case TCP_SYN_RCVD:\r
815 return 0;\r
816 break;\r
817\r
818 case TCP_ESTABLISHED:\r
819 case TCP_CLOSE_WAIT:\r
820 TcpToSendData (Tcb, 0);\r
821 return 0;\r
822 break;\r
823\r
824 case TCP_FIN_WAIT_1:\r
825 case TCP_FIN_WAIT_2:\r
826 case TCP_CLOSING:\r
827 case TCP_LAST_ACK:\r
828 case TCP_TIME_WAIT:\r
829 return -1;\r
830 break;\r
831 }\r
832\r
833 return 0;\r
834}\r
835\r
836\r
837/**\r
838 Application has consumed some data, check whether\r
839 to send a window updata ack or a delayed ack.\r
840\r
841 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
842\r
843\r
844**/\r
845INTN\r
846TcpOnAppConsume (\r
847 IN TCP_CB *Tcb\r
848 )\r
849{\r
4eb65aff 850 UINT32 TcpOld;\r
8a67d61d 851\r
852 switch (Tcb->State) {\r
853 case TCP_CLOSED:\r
854 return -1;\r
855 break;\r
856\r
857 case TCP_LISTEN:\r
858 return -1;\r
859 break;\r
860\r
861 case TCP_SYN_SENT:\r
862 case TCP_SYN_RCVD:\r
863 return 0;\r
864 break;\r
865\r
866 case TCP_ESTABLISHED:\r
4eb65aff 867 TcpOld = TcpRcvWinOld (Tcb);\r
868 if (TcpRcvWinNow (Tcb) > TcpOld) {\r
8a67d61d 869\r
4eb65aff 870 if (TcpOld < Tcb->RcvMss) {\r
8a67d61d 871\r
872 TCP4_DEBUG_TRACE (("TcpOnAppConsume: send a window"\r
873 " update for a window closed Tcb(%x)\n", Tcb));\r
874\r
875 TcpSendAck (Tcb);\r
876 } else if (Tcb->DelayedAck == 0) {\r
877\r
878 TCP4_DEBUG_TRACE (("TcpOnAppConsume: scheduled a delayed"\r
879 " ACK to update window for Tcb(%x)\n", Tcb));\r
880\r
881 Tcb->DelayedAck = 1;\r
882 }\r
883 }\r
884\r
885 break;\r
886\r
887 case TCP_CLOSE_WAIT:\r
888 return 0;\r
889 break;\r
890\r
891 case TCP_FIN_WAIT_1:\r
892 case TCP_FIN_WAIT_2:\r
893 case TCP_CLOSING:\r
894 case TCP_LAST_ACK:\r
895 case TCP_TIME_WAIT:\r
896 return -1;\r
897 break;\r
898 }\r
899\r
900 return -1;\r
901}\r
902\r
903\r
904/**\r
905 Abort the connection by sending a reset segment, called\r
906 when the application wants to abort the connection.\r
907\r
908 @param Tcb Pointer to the TCP_CB of the TCP instance.\r
909\r
910 @return None.\r
911\r
912**/\r
913VOID\r
914TcpOnAppAbort (\r
915 IN TCP_CB *Tcb\r
916 )\r
917{\r
918 TCP4_DEBUG_WARN (("TcpOnAppAbort: connection reset "\r
919 "issued by application for TCB %x\n", Tcb));\r
920\r
921 switch (Tcb->State) {\r
922 case TCP_SYN_RCVD:\r
923 case TCP_ESTABLISHED:\r
924 case TCP_FIN_WAIT_1:\r
925 case TCP_FIN_WAIT_2:\r
926 case TCP_CLOSE_WAIT:\r
927 TcpResetConnection (Tcb);\r
928 break;\r
929 }\r
930\r
931 TcpSetState (Tcb, TCP_CLOSED);\r
932}\r
933\r
934\r
935/**\r
936 Set the Tdp4 variable data.\r
937\r
938 @param Tcp4Service Tcp4 service data.\r
939\r
940 @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.\r
941 @retval other Set variable failed.\r
942\r
943**/\r
944EFI_STATUS\r
945TcpSetVariableData (\r
946 IN TCP4_SERVICE_DATA *Tcp4Service\r
947 )\r
948{\r
949 UINT32 NumConfiguredInstance;\r
950 NET_LIST_ENTRY *Entry;\r
951 TCP_CB *TcpPcb;\r
952 TCP4_PROTO_DATA *TcpProto;\r
953 UINTN VariableDataSize;\r
954 EFI_TCP4_VARIABLE_DATA *Tcp4VariableData;\r
955 EFI_TCP4_SERVICE_POINT *Tcp4ServicePoint;\r
956 CHAR16 *NewMacString;\r
957 EFI_STATUS Status;\r
958\r
959 NumConfiguredInstance = 0;\r
960\r
961 //\r
962 // Go through the running queue to count the instances.\r
963 //\r
964 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\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 // Go through the listening queue to count the instances.\r
979 //\r
980 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
981 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
982\r
983 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
984\r
985 if (TcpProto->TcpService == Tcp4Service) {\r
986 //\r
987 // This tcp instance belongs to the Tcp4Service.\r
988 //\r
989 NumConfiguredInstance++;\r
990 }\r
991 }\r
992\r
993 //\r
994 // Calculate the size of the Tcp4VariableData. As there may be no Tcp4 child,\r
995 // we should add extra buffer for the service points only if the number of configured\r
996 // children is more than 1.\r
997 //\r
998 VariableDataSize = sizeof (EFI_TCP4_VARIABLE_DATA);\r
999\r
1000 if (NumConfiguredInstance > 1) {\r
1001 VariableDataSize += sizeof (EFI_TCP4_SERVICE_POINT) * (NumConfiguredInstance - 1);\r
1002 }\r
1003\r
1004 Tcp4VariableData = NetAllocatePool (VariableDataSize);\r
1005 if (Tcp4VariableData == NULL) {\r
1006 return EFI_OUT_OF_RESOURCES;\r
1007 }\r
1008\r
1009 Tcp4VariableData->DriverHandle = Tcp4Service->DriverBindingHandle;\r
1010 Tcp4VariableData->ServiceCount = NumConfiguredInstance;\r
1011\r
1012 Tcp4ServicePoint = &Tcp4VariableData->Services[0];\r
1013\r
1014 //\r
1015 // Go through the running queue to fill the service points.\r
1016 //\r
1017 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
1018 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
1019\r
1020 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
1021\r
1022 if (TcpProto->TcpService == Tcp4Service) {\r
1023 //\r
1024 // This tcp instance belongs to the Tcp4Service.\r
1025 //\r
1026 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
772db4bb 1027 NetCopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 1028 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
772db4bb 1029 NetCopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 1030 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
1031\r
1032 Tcp4ServicePoint++;\r
1033 }\r
1034 }\r
1035\r
1036 //\r
1037 // Go through the listening queue to fill the service points.\r
1038 //\r
1039 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
1040 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
1041\r
1042 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
1043\r
1044 if (TcpProto->TcpService == Tcp4Service) {\r
1045 //\r
1046 // This tcp instance belongs to the Tcp4Service.\r
1047 //\r
1048 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
772db4bb 1049 NetCopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 1050 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
772db4bb 1051 NetCopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 1052 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
1053\r
1054 Tcp4ServicePoint++;\r
1055 }\r
1056 }\r
1057\r
1058 //\r
1059 // Get the mac string.\r
1060 //\r
1061 Status = NetLibGetMacString (\r
1062 Tcp4Service->ControllerHandle,\r
1063 Tcp4Service->DriverBindingHandle,\r
1064 &NewMacString\r
1065 );\r
1066 if (EFI_ERROR (Status)) {\r
1067 goto ON_ERROR;\r
1068 }\r
1069\r
1070 if (Tcp4Service->MacString != NULL) {\r
1071 //\r
1072 // The variable is set already, we're going to update it.\r
1073 //\r
1074 if (StrCmp (Tcp4Service->MacString, NewMacString) != 0) {\r
1075 //\r
1076 // The mac address is changed, delete the previous variable first.\r
1077 //\r
1078 gRT->SetVariable (\r
1079 Tcp4Service->MacString,\r
1080 &gEfiTcp4ServiceBindingProtocolGuid,\r
1081 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1082 0,\r
1083 NULL\r
1084 );\r
1085 }\r
1086\r
1087 NetFreePool (Tcp4Service->MacString);\r
1088 }\r
1089\r
1090 Tcp4Service->MacString = NewMacString;\r
1091\r
1092 Status = gRT->SetVariable (\r
1093 Tcp4Service->MacString,\r
1094 &gEfiTcp4ServiceBindingProtocolGuid,\r
1095 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1096 VariableDataSize,\r
1097 (VOID *) Tcp4VariableData\r
1098 );\r
1099\r
1100ON_ERROR:\r
1101\r
1102 NetFreePool (Tcp4VariableData);\r
1103\r
1104 return Status;\r
1105}\r
1106\r
1107\r
1108/**\r
1109 Clear the variable and free the resource.\r
1110\r
1111 @param Tcp4Service Tcp4 service data.\r
1112\r
1113 @return None.\r
1114\r
1115**/\r
1116VOID\r
1117TcpClearVariableData (\r
1118 IN TCP4_SERVICE_DATA *Tcp4Service\r
1119 )\r
1120{\r
1121 ASSERT (Tcp4Service->MacString != NULL);\r
1122\r
1123 gRT->SetVariable (\r
1124 Tcp4Service->MacString,\r
1125 &gEfiTcp4ServiceBindingProtocolGuid,\r
1126 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1127 0,\r
1128 NULL\r
1129 );\r
1130\r
1131 NetFreePool (Tcp4Service->MacString);\r
1132 Tcp4Service->MacString = NULL;\r
1133}\r
1134\r
e5e12de7 1135EFI_STATUS\r
1136TcpInstallDevicePath (\r
1137 IN SOCKET *Sock\r
1138 )\r
1139/*++\r
1140\r
1141Routine Description:\r
1142\r
1143 Install the device path protocol on the TCP instance.\r
1144\r
1145Arguments:\r
1146\r
1147 Sock - Pointer to the socket representing the TCP instance.\r
1148\r
1149Returns:\r
1150\r
1151 EFI_SUCCESS - The device path protocol is installed.\r
1152 other - Failed to install the device path protocol.\r
1153\r
1154--*/\r
1155{\r
1156 TCP4_PROTO_DATA *TcpProto;\r
1157 TCP4_SERVICE_DATA *TcpService;\r
1158 TCP_CB *Tcb;\r
1159 IPv4_DEVICE_PATH Ip4DPathNode;\r
1160 EFI_STATUS Status;\r
1161\r
1162 TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
1163 TcpService = TcpProto->TcpService;\r
1164 Tcb = TcpProto->TcpPcb;\r
1165\r
1166 NetLibCreateIPv4DPathNode (\r
1167 &Ip4DPathNode,\r
1168 TcpService->ControllerHandle,\r
1169 Tcb->LocalEnd.Ip,\r
1170 NTOHS (Tcb->LocalEnd.Port),\r
1171 Tcb->RemoteEnd.Ip,\r
1172 NTOHS (Tcb->RemoteEnd.Port),\r
1173 EFI_IP_PROTO_TCP,\r
1174 Tcb->UseDefaultAddr\r
1175 );\r
1176\r
1177 Sock->DevicePath = AppendDevicePathNode (\r
1178 Sock->ParentDevicePath,\r
1179 (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode\r
1180 );\r
1181 if (Sock->DevicePath == NULL) {\r
1182 return EFI_OUT_OF_RESOURCES;\r
1183 }\r
1184\r
1185 Status = gBS->InstallProtocolInterface (\r
1186 &Sock->SockHandle,\r
1187 &gEfiDevicePathProtocolGuid,\r
1188 EFI_NATIVE_INTERFACE,\r
1189 Sock->DevicePath\r
1190 );\r
1191 if (EFI_ERROR (Status)) {\r
1192 NetFreePool (Sock->DevicePath);\r
1193 }\r
1194\r
1195 return Status;\r
1196}\r