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