]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Misc.c
MdeModulePkg:TcpDriver need to use EFI_D_NET for DEBUG maessage.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Tcp4Dxe / Tcp4Misc.c
CommitLineData
8a67d61d 1/** @file\r
dfc1f033 2 Misc support routines for tcp.\r
8a67d61d 3\r
dea6914d 4Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 5This program and the accompanying materials\r
8a67d61d 6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
dfc1f033 8http://opensource.org/licenses/bsd-license.php<BR>\r
8a67d61d 9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
8a67d61d 13**/\r
14\r
15\r
16#include "Tcp4Main.h"\r
17\r
e5e12de7 18#include <Library/DevicePathLib.h>\r
19\r
e48e37fc 20LIST_ENTRY mTcpRunQue = {\r
8a67d61d 21 &mTcpRunQue,\r
22 &mTcpRunQue\r
23};\r
24\r
e48e37fc 25LIST_ENTRY mTcpListenQue = {\r
8a67d61d 26 &mTcpListenQue,\r
27 &mTcpListenQue\r
28};\r
29\r
30TCP_SEQNO mTcpGlobalIss = 0x4d7e980b;\r
31\r
84b5c78e 32CHAR16 *mTcpStateName[] = {\r
8a67d61d 33 L"TCP_CLOSED",\r
34 L"TCP_LISTEN",\r
35 L"TCP_SYN_SENT",\r
36 L"TCP_SYN_RCVD",\r
37 L"TCP_ESTABLISHED",\r
38 L"TCP_FIN_WAIT_1",\r
39 L"TCP_FIN_WAIT_2",\r
40 L"TCP_CLOSING",\r
41 L"TCP_TIME_WAIT",\r
42 L"TCP_CLOSE_WAIT",\r
43 L"TCP_LAST_ACK"\r
44};\r
45\r
46\r
47/**\r
48 Initialize the Tcb local related members.\r
49\r
50 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
51\r
8a67d61d 52**/\r
53VOID\r
54TcpInitTcbLocal (\r
77f00155 55 IN OUT TCP_CB *Tcb\r
8a67d61d 56 )\r
57{\r
58 //\r
59 // Compute the checksum of the fixed parts of pseudo header\r
60 //\r
61 Tcb->HeadSum = NetPseudoHeadChecksum (\r
62 Tcb->LocalEnd.Ip,\r
63 Tcb->RemoteEnd.Ip,\r
64 0x06,\r
65 0\r
66 );\r
67\r
68 Tcb->Iss = TcpGetIss ();\r
69 Tcb->SndUna = Tcb->Iss;\r
70 Tcb->SndNxt = Tcb->Iss;\r
71\r
72 Tcb->SndWl2 = Tcb->Iss;\r
73 Tcb->SndWnd = 536;\r
74\r
75 Tcb->RcvWnd = GET_RCV_BUFFSIZE (Tcb->Sk);\r
76\r
77 //\r
120db52c 78 // First window size is never scaled\r
8a67d61d 79 //\r
ac8cca2a 80 Tcb->RcvWndScale = 0;\r
81\r
82 Tcb->ProbeTimerOn = FALSE;\r
8a67d61d 83}\r
84\r
85\r
86/**\r
87 Initialize the peer related members.\r
88\r
89 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
90 @param Seg Pointer to the segment that contains the peer's\r
91 intial info.\r
92 @param Opt Pointer to the options announced by the peer.\r
93\r
8a67d61d 94**/\r
95VOID\r
96TcpInitTcbPeer (\r
77f00155 97 IN OUT TCP_CB *Tcb,\r
98 IN TCP_SEG *Seg,\r
99 IN TCP_OPTION *Opt\r
8a67d61d 100 )\r
101{\r
102 UINT16 RcvMss;\r
103\r
276dcc1b 104 ASSERT ((Tcb != NULL) && (Seg != NULL) && (Opt != NULL));\r
8a67d61d 105 ASSERT (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN));\r
106\r
107 Tcb->SndWnd = Seg->Wnd;\r
108 Tcb->SndWndMax = Tcb->SndWnd;\r
109 Tcb->SndWl1 = Seg->Seq;\r
110\r
111 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
112 Tcb->SndWl2 = Seg->Ack;\r
113 } else {\r
114 Tcb->SndWl2 = Tcb->Iss + 1;\r
115 }\r
116\r
117 if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_MSS)) {\r
36ee91ca 118 Tcb->SndMss = (UINT16) MAX (64, Opt->Mss);\r
8a67d61d 119\r
120 RcvMss = TcpGetRcvMss (Tcb->Sk);\r
121 if (Tcb->SndMss > RcvMss) {\r
122 Tcb->SndMss = RcvMss;\r
123 }\r
124\r
125 } else {\r
126 //\r
127 // One end doesn't support MSS option, use default.\r
128 //\r
129 Tcb->RcvMss = 536;\r
130 }\r
131\r
132 Tcb->CWnd = Tcb->SndMss;\r
133\r
134 Tcb->Irs = Seg->Seq;\r
135 Tcb->RcvNxt = Tcb->Irs + 1;\r
136\r
137 Tcb->RcvWl2 = Tcb->RcvNxt;\r
138\r
139 if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_WS) &&\r
140 !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS)) {\r
141\r
142 Tcb->SndWndScale = Opt->WndScale;\r
143\r
144 Tcb->RcvWndScale = TcpComputeScale (Tcb);\r
145 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_WS);\r
146\r
147 } else {\r
148 //\r
149 // One end doesn't support window scale option. use zero.\r
150 //\r
151 Tcb->RcvWndScale = 0;\r
152 }\r
153\r
154 if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_TS) &&\r
155 !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS)) {\r
156\r
157 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_TS);\r
158 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS);\r
159\r
185395a4
BZ
160 Tcb->TsRecent = Opt->TSVal;\r
161\r
8a67d61d 162 //\r
163 // Compute the effective SndMss per RFC1122\r
164 // section 4.2.2.6. If timestamp option is\r
165 // enabled, it will always occupy 12 bytes.\r
166 //\r
167 Tcb->SndMss -= TCP_OPTION_TS_ALIGNED_LEN;\r
168 }\r
169}\r
170\r
171\r
172/**\r
173 Locate a listen TCB that matchs the Local and Remote.\r
174\r
175 @param Local Pointer to the local (IP, Port).\r
176 @param Remote Pointer to the remote (IP, Port).\r
177\r
9c4a5f74 178 @return Pointer to the TCP_CB with the least number of wildcard,\r
120db52c 179 if NULL no match is found.\r
8a67d61d 180\r
181**/\r
8a67d61d 182TCP_CB *\r
183TcpLocateListenTcb (\r
184 IN TCP_PEER *Local,\r
185 IN TCP_PEER *Remote\r
186 )\r
187{\r
e48e37fc 188 LIST_ENTRY *Entry;\r
8a67d61d 189 TCP_CB *Node;\r
190 TCP_CB *Match;\r
191 INTN Last;\r
192 INTN Cur;\r
193\r
194 Last = 4;\r
195 Match = NULL;\r
196\r
197 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
198 Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
199\r
200 if ((Local->Port != Node->LocalEnd.Port) ||\r
201 !TCP_PEER_MATCH (Remote, &Node->RemoteEnd) ||\r
120db52c 202 !TCP_PEER_MATCH (Local, &Node->LocalEnd)) {\r
8a67d61d 203\r
204 continue;\r
205 }\r
206\r
207 //\r
208 // Compute the number of wildcard\r
209 //\r
210 Cur = 0;\r
211 if (Node->RemoteEnd.Ip == 0) {\r
212 Cur++;\r
213 }\r
214\r
215 if (Node->RemoteEnd.Port == 0) {\r
216 Cur++;\r
217 }\r
218\r
219 if (Node->LocalEnd.Ip == 0) {\r
220 Cur++;\r
221 }\r
222\r
223 if (Cur < Last) {\r
224 if (Cur == 0) {\r
225 return Node;\r
226 }\r
227\r
228 Last = Cur;\r
229 Match = Node;\r
230 }\r
231 }\r
232\r
233 return Match;\r
234}\r
235\r
236\r
237/**\r
238 Try to find one Tcb whose <Ip, Port> equals to <IN Addr, IN Port>.\r
239\r
240 @param Addr Pointer to the IP address needs to match.\r
241 @param Port The port number needs to match.\r
242\r
120db52c 243 @return The Tcb which matches the <Addr Port> paire exists or not.\r
8a67d61d 244\r
245**/\r
246BOOLEAN\r
247TcpFindTcbByPeer (\r
248 IN EFI_IPv4_ADDRESS *Addr,\r
249 IN TCP_PORTNO Port\r
250 )\r
251{\r
252 TCP_PORTNO LocalPort;\r
e48e37fc 253 LIST_ENTRY *Entry;\r
8a67d61d 254 TCP_CB *Tcb;\r
255\r
256 ASSERT ((Addr != NULL) && (Port != 0));\r
257\r
258 LocalPort = HTONS (Port);\r
259\r
260 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
261 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
262\r
84b5c78e 263 if (EFI_IP4_EQUAL (Addr, &Tcb->LocalEnd.Ip) &&\r
8a67d61d 264 (LocalPort == Tcb->LocalEnd.Port)) {\r
265\r
266 return TRUE;\r
267 }\r
268 }\r
269\r
270 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
271 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
272\r
84b5c78e 273 if (EFI_IP4_EQUAL (Addr, &Tcb->LocalEnd.Ip) &&\r
8a67d61d 274 (LocalPort == Tcb->LocalEnd.Port)) {\r
275\r
276 return TRUE;\r
277 }\r
278 }\r
279\r
280 return FALSE;\r
281}\r
282\r
283\r
284/**\r
285 Locate the TCP_CB related to the socket pair.\r
286\r
287 @param LocalPort The local port number.\r
288 @param LocalIp The local IP address.\r
289 @param RemotePort The remote port number.\r
290 @param RemoteIp The remote IP address.\r
291 @param Syn Whether to search the listen sockets, if TRUE, the\r
292 listen sockets are searched.\r
293\r
120db52c 294 @return Pointer to the related TCP_CB, if NULL no match is found.\r
8a67d61d 295\r
296**/\r
297TCP_CB *\r
298TcpLocateTcb (\r
299 IN TCP_PORTNO LocalPort,\r
300 IN UINT32 LocalIp,\r
301 IN TCP_PORTNO RemotePort,\r
302 IN UINT32 RemoteIp,\r
303 IN BOOLEAN Syn\r
304 )\r
305{\r
306 TCP_PEER Local;\r
307 TCP_PEER Remote;\r
e48e37fc 308 LIST_ENTRY *Entry;\r
8a67d61d 309 TCP_CB *Tcb;\r
310\r
311 Local.Port = LocalPort;\r
312 Local.Ip = LocalIp;\r
313\r
314 Remote.Port = RemotePort;\r
315 Remote.Ip = RemoteIp;\r
316\r
317 //\r
318 // First check for exact match.\r
319 //\r
320 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
321 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
322\r
323 if (TCP_PEER_EQUAL (&Remote, &Tcb->RemoteEnd) &&\r
324 TCP_PEER_EQUAL (&Local, &Tcb->LocalEnd)) {\r
325\r
e48e37fc 326 RemoveEntryList (&Tcb->List);\r
327 InsertHeadList (&mTcpRunQue, &Tcb->List);\r
8a67d61d 328\r
329 return Tcb;\r
330 }\r
331 }\r
332\r
333 //\r
334 // Only check listen queue when SYN flag is on\r
335 //\r
336 if (Syn) {\r
337 return TcpLocateListenTcb (&Local, &Remote);\r
338 }\r
339\r
340 return NULL;\r
341}\r
342\r
343\r
344/**\r
345 Insert a Tcb into the proper queue.\r
346\r
347 @param Tcb Pointer to the TCP_CB to be inserted.\r
348\r
349 @retval 0 The Tcb is inserted successfully.\r
350 @retval -1 Error condition occurred.\r
351\r
352**/\r
353INTN\r
354TcpInsertTcb (\r
355 IN TCP_CB *Tcb\r
356 )\r
357{\r
e48e37fc 358 LIST_ENTRY *Entry;\r
359 LIST_ENTRY *Head;\r
8a67d61d 360 TCP_CB *Node;\r
8a67d61d 361\r
362 ASSERT (\r
120db52c 363 (Tcb != NULL) &&\r
364 ((Tcb->State == TCP_LISTEN) ||\r
365 (Tcb->State == TCP_SYN_SENT) ||\r
366 (Tcb->State == TCP_SYN_RCVD) ||\r
367 (Tcb->State == TCP_CLOSED))\r
8a67d61d 368 );\r
369\r
370 if (Tcb->LocalEnd.Port == 0) {\r
371 return -1;\r
372 }\r
373\r
374 Head = &mTcpRunQue;\r
375\r
376 if (Tcb->State == TCP_LISTEN) {\r
377 Head = &mTcpListenQue;\r
378 }\r
379\r
380 //\r
381 // Check that Tcb isn't already on the list.\r
382 //\r
383 NET_LIST_FOR_EACH (Entry, Head) {\r
384 Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
385\r
386 if (TCP_PEER_EQUAL (&Tcb->LocalEnd, &Node->LocalEnd) &&\r
387 TCP_PEER_EQUAL (&Tcb->RemoteEnd, &Node->RemoteEnd)) {\r
388\r
389 return -1;\r
390 }\r
391 }\r
392\r
e48e37fc 393 InsertHeadList (Head, &Tcb->List);\r
8a67d61d 394\r
8a67d61d 395 return 0;\r
396}\r
397\r
398\r
399/**\r
dfc1f033 400 Clone a TCB_CB from Tcb.\r
8a67d61d 401\r
402 @param Tcb Pointer to the TCP_CB to be cloned.\r
403\r
120db52c 404 @return Pointer to the new cloned TCP_CB, if NULL error condition occurred.\r
8a67d61d 405\r
406**/\r
407TCP_CB *\r
408TcpCloneTcb (\r
409 IN TCP_CB *Tcb\r
410 )\r
411{\r
412 TCP_CB *Clone;\r
413\r
e48e37fc 414 Clone = AllocatePool (sizeof (TCP_CB));\r
8a67d61d 415\r
416 if (Clone == NULL) {\r
417 return NULL;\r
418\r
419 }\r
420\r
e48e37fc 421 CopyMem (Clone, Tcb, sizeof (TCP_CB));\r
8a67d61d 422\r
423 //\r
424 // Increate the reference count of the shared IpInfo.\r
425 //\r
426 NET_GET_REF (Tcb->IpInfo);\r
427\r
e48e37fc 428 InitializeListHead (&Clone->List);\r
429 InitializeListHead (&Clone->SndQue);\r
430 InitializeListHead (&Clone->RcvQue);\r
8a67d61d 431\r
432 Clone->Sk = SockClone (Tcb->Sk);\r
433 if (Clone->Sk == NULL) {\r
e48e37fc 434 DEBUG ((EFI_D_ERROR, "TcpCloneTcb: failed to clone a sock\n"));\r
766c7483 435 FreePool (Clone);\r
8a67d61d 436 return NULL;\r
437 }\r
438\r
439 ((TCP4_PROTO_DATA *) (Clone->Sk->ProtoReserved))->TcpPcb = Clone;\r
440\r
441 return Clone;\r
442}\r
443\r
444\r
445/**\r
446 Compute an ISS to be used by a new connection.\r
447\r
120db52c 448 @return The result ISS.\r
8a67d61d 449\r
450**/\r
451TCP_SEQNO\r
452TcpGetIss (\r
453 VOID\r
454 )\r
455{\r
456 mTcpGlobalIss += 2048;\r
457 return mTcpGlobalIss;\r
458}\r
459\r
460\r
461/**\r
462 Get the local mss.\r
463\r
85511ddf 464 @param Sock Pointer to the socket to get mss\r
8a67d61d 465\r
120db52c 466 @return The mss size.\r
8a67d61d 467\r
468**/\r
469UINT16\r
470TcpGetRcvMss (\r
471 IN SOCKET *Sock\r
472 )\r
473{\r
a1503a32 474 EFI_IP4_MODE_DATA Ip4Mode;\r
8a67d61d 475 TCP4_PROTO_DATA *TcpProto;\r
476 EFI_IP4_PROTOCOL *Ip;\r
477\r
120db52c 478 ASSERT (Sock != NULL);\r
8a67d61d 479\r
480 TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
2a2e33b2 481 Ip = TcpProto->TcpService->IpIo->Ip.Ip4;\r
120db52c 482 ASSERT (Ip != NULL);\r
8a67d61d 483\r
a1503a32 484 Ip->GetModeData (Ip, &Ip4Mode, NULL, NULL);\r
8a67d61d 485\r
a1503a32 486 return (UINT16) (Ip4Mode.MaxPacketSize - sizeof (TCP_HEAD));\r
8a67d61d 487}\r
488\r
489\r
490/**\r
491 Set the Tcb's state.\r
492\r
493 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
494 @param State The state to be set.\r
495\r
8a67d61d 496**/\r
497VOID\r
498TcpSetState (\r
77f00155 499 IN OUT TCP_CB *Tcb,\r
500 IN UINT8 State\r
8a67d61d 501 )\r
502{\r
9c4a5f74 503 ASSERT (Tcb->State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));\r
504 ASSERT (State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));\r
505\r
e48e37fc 506 DEBUG (\r
dea6914d 507 (EFI_D_NET,\r
0e549d5b 508 "Tcb (%p) state %s --> %s\n",\r
8a67d61d 509 Tcb,\r
510 mTcpStateName[Tcb->State],\r
511 mTcpStateName[State])\r
512 );\r
513\r
276dcc1b 514 Tcb->State = State;\r
8a67d61d 515\r
516 switch (State) {\r
517 case TCP_ESTABLISHED:\r
518\r
519 SockConnEstablished (Tcb->Sk);\r
e5e12de7 520\r
521 if (Tcb->Parent != NULL) {\r
522 //\r
523 // A new connection is accepted by a listening socket, install\r
524 // the device path.\r
525 //\r
526 TcpInstallDevicePath (Tcb->Sk);\r
527 }\r
528\r
8a67d61d 529 break;\r
530\r
531 case TCP_CLOSED:\r
532\r
533 SockConnClosed (Tcb->Sk);\r
534\r
dfc1f033 535 break;\r
dfa596b8 536 default:\r
8a67d61d 537 break;\r
538 }\r
539}\r
540\r
541\r
542/**\r
543 Compute the TCP segment's checksum.\r
544\r
545 @param Nbuf Pointer to the buffer that contains the TCP\r
546 segment.\r
547 @param HeadSum The checksum value of the fixed part of pseudo\r
548 header.\r
549\r
120db52c 550 @return The checksum value.\r
8a67d61d 551\r
552**/\r
553UINT16\r
554TcpChecksum (\r
555 IN NET_BUF *Nbuf,\r
556 IN UINT16 HeadSum\r
557 )\r
558{\r
559 UINT16 Checksum;\r
560\r
561 Checksum = NetbufChecksum (Nbuf);\r
562 Checksum = NetAddChecksum (Checksum, HeadSum);\r
563\r
120db52c 564 Checksum = NetAddChecksum (\r
565 Checksum,\r
566 HTONS ((UINT16) Nbuf->TotalSize)\r
567 );\r
8a67d61d 568\r
4eb65aff 569 return (UINT16) ~Checksum;\r
8a67d61d 570}\r
571\r
8a67d61d 572/**\r
573 Translate the information from the head of the received TCP\r
574 segment Nbuf contains and fill it into a TCP_SEG structure.\r
575\r
576 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
577 @param Nbuf Pointer to the buffer contains the TCP segment.\r
578\r
120db52c 579 @return Pointer to the TCP_SEG that contains the translated TCP head information.\r
8a67d61d 580\r
581**/\r
582TCP_SEG *\r
583TcpFormatNetbuf (\r
77f00155 584 IN TCP_CB *Tcb,\r
585 IN OUT NET_BUF *Nbuf\r
8a67d61d 586 )\r
587{\r
588 TCP_SEG *Seg;\r
589 TCP_HEAD *Head;\r
590\r
591 Seg = TCPSEG_NETBUF (Nbuf);\r
592 Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
a56b6e03 593 ASSERT (Head != NULL);\r
8a67d61d 594 Nbuf->Tcp = Head;\r
595\r
596 Seg->Seq = NTOHL (Head->Seq);\r
597 Seg->Ack = NTOHL (Head->Ack);\r
598 Seg->End = Seg->Seq + (Nbuf->TotalSize - (Head->HeadLen << 2));\r
599\r
600 Seg->Urg = NTOHS (Head->Urg);\r
601 Seg->Wnd = (NTOHS (Head->Wnd) << Tcb->SndWndScale);\r
602 Seg->Flag = Head->Flag;\r
603\r
604 //\r
605 // SYN and FIN flag occupy one sequence space each.\r
606 //\r
607 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
608 //\r
609 // RFC requires that initial window not be scaled\r
610 //\r
611 Seg->Wnd = NTOHS (Head->Wnd);\r
612 Seg->End++;\r
613 }\r
614\r
615 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
616 Seg->End++;\r
617 }\r
618\r
619 return Seg;\r
620}\r
621\r
622\r
623/**\r
624 Reset the connection related with Tcb.\r
625\r
626 @param Tcb Pointer to the TCP_CB of the connection to be\r
627 reset.\r
628\r
8a67d61d 629**/\r
630VOID\r
631TcpResetConnection (\r
632 IN TCP_CB *Tcb\r
633 )\r
634{\r
635 NET_BUF *Nbuf;\r
636 TCP_HEAD *Nhead;\r
637\r
638 Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
639\r
640 if (Nbuf == NULL) {\r
641 return ;\r
642 }\r
643\r
644 Nhead = (TCP_HEAD *) NetbufAllocSpace (\r
645 Nbuf,\r
646 sizeof (TCP_HEAD),\r
647 NET_BUF_TAIL\r
648 );\r
649\r
650 ASSERT (Nhead != NULL);\r
651\r
652 Nbuf->Tcp = Nhead;\r
653\r
654 Nhead->Flag = TCP_FLG_RST;\r
655 Nhead->Seq = HTONL (Tcb->SndNxt);\r
656 Nhead->Ack = HTONL (Tcb->RcvNxt);\r
657 Nhead->SrcPort = Tcb->LocalEnd.Port;\r
658 Nhead->DstPort = Tcb->RemoteEnd.Port;\r
c9325700 659 Nhead->HeadLen = (UINT8) (sizeof (TCP_HEAD) >> 2);\r
8a67d61d 660 Nhead->Res = 0;\r
661 Nhead->Wnd = HTONS (0xFFFF);\r
662 Nhead->Checksum = 0;\r
663 Nhead->Urg = 0;\r
664 Nhead->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);\r
665\r
666 TcpSendIpPacket (Tcb, Nbuf, Tcb->LocalEnd.Ip, Tcb->RemoteEnd.Ip);\r
667\r
668 NetbufFree (Nbuf);\r
669}\r
670\r
671\r
672/**\r
120db52c 673 Initialize an active connection.\r
8a67d61d 674\r
675 @param Tcb Pointer to the TCP_CB that wants to initiate a\r
676 connection.\r
677\r
8a67d61d 678**/\r
679VOID\r
680TcpOnAppConnect (\r
77f00155 681 IN OUT TCP_CB *Tcb\r
8a67d61d 682 )\r
683{\r
684 TcpInitTcbLocal (Tcb);\r
685 TcpSetState (Tcb, TCP_SYN_SENT);\r
686\r
687 TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
688 TcpToSendData (Tcb, 1);\r
689}\r
690\r
691\r
692/**\r
693 Initiate the connection close procedure, called when\r
694 applications want to close the connection.\r
695\r
696 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
697\r
8a67d61d 698**/\r
699VOID\r
700TcpOnAppClose (\r
77f00155 701 IN OUT TCP_CB *Tcb\r
8a67d61d 702 )\r
703{\r
120db52c 704 ASSERT (Tcb != NULL);\r
8a67d61d 705\r
120db52c 706 if (!IsListEmpty (&Tcb->RcvQue) || GET_RCV_DATASIZE (Tcb->Sk) != 0) {\r
8a67d61d 707\r
e48e37fc 708 DEBUG ((EFI_D_WARN, "TcpOnAppClose: connection reset "\r
0e549d5b 709 "because data is lost for TCB %p\n", Tcb));\r
8a67d61d 710\r
711 TcpResetConnection (Tcb);\r
712 TcpClose (Tcb);\r
713 return;\r
714 }\r
715\r
716 switch (Tcb->State) {\r
717 case TCP_CLOSED:\r
718 case TCP_LISTEN:\r
719 case TCP_SYN_SENT:\r
720 TcpSetState (Tcb, TCP_CLOSED);\r
721 break;\r
722\r
723 case TCP_SYN_RCVD:\r
724 case TCP_ESTABLISHED:\r
725 TcpSetState (Tcb, TCP_FIN_WAIT_1);\r
726 break;\r
727\r
728 case TCP_CLOSE_WAIT:\r
729 TcpSetState (Tcb, TCP_LAST_ACK);\r
730 break;\r
dfa596b8 731 default:\r
dfc1f033 732 break;\r
8a67d61d 733 }\r
734\r
735 TcpToSendData (Tcb, 1);\r
736}\r
737\r
738\r
739/**\r
120db52c 740 Check whether the application's newly delivered data can be sent out.\r
8a67d61d 741\r
742 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
743\r
744 @retval 0 Whether the data is sent out or is buffered for\r
745 further sending.\r
746 @retval -1 The Tcb is not in a state that data is permitted to\r
747 be sent out.\r
748\r
749**/\r
750INTN\r
751TcpOnAppSend (\r
77f00155 752 IN OUT TCP_CB *Tcb\r
8a67d61d 753 )\r
754{\r
755\r
756 switch (Tcb->State) {\r
757 case TCP_CLOSED:\r
758 return -1;\r
8a67d61d 759\r
760 case TCP_LISTEN:\r
761 return -1;\r
8a67d61d 762\r
763 case TCP_SYN_SENT:\r
764 case TCP_SYN_RCVD:\r
765 return 0;\r
8a67d61d 766\r
767 case TCP_ESTABLISHED:\r
768 case TCP_CLOSE_WAIT:\r
769 TcpToSendData (Tcb, 0);\r
770 return 0;\r
8a67d61d 771\r
772 case TCP_FIN_WAIT_1:\r
773 case TCP_FIN_WAIT_2:\r
774 case TCP_CLOSING:\r
775 case TCP_LAST_ACK:\r
776 case TCP_TIME_WAIT:\r
777 return -1;\r
77f00155 778\r
dfa596b8 779 default:\r
dfc1f033 780 break;\r
8a67d61d 781 }\r
782\r
783 return 0;\r
784}\r
785\r
786\r
787/**\r
788 Application has consumed some data, check whether\r
789 to send a window updata ack or a delayed ack.\r
790\r
791 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
792\r
8a67d61d 793**/\r
276dcc1b 794VOID\r
8a67d61d 795TcpOnAppConsume (\r
796 IN TCP_CB *Tcb\r
797 )\r
798{\r
4eb65aff 799 UINT32 TcpOld;\r
8a67d61d 800\r
801 switch (Tcb->State) {\r
802 case TCP_CLOSED:\r
276dcc1b 803 return;\r
8a67d61d 804\r
805 case TCP_LISTEN:\r
276dcc1b 806 return;\r
8a67d61d 807\r
808 case TCP_SYN_SENT:\r
809 case TCP_SYN_RCVD:\r
276dcc1b 810 return;\r
8a67d61d 811\r
812 case TCP_ESTABLISHED:\r
4eb65aff 813 TcpOld = TcpRcvWinOld (Tcb);\r
814 if (TcpRcvWinNow (Tcb) > TcpOld) {\r
8a67d61d 815\r
4eb65aff 816 if (TcpOld < Tcb->RcvMss) {\r
8a67d61d 817\r
dea6914d 818 DEBUG ((EFI_D_NET, "TcpOnAppConsume: send a window"\r
dfc1f033 819 " update for a window closed Tcb %p\n", Tcb));\r
8a67d61d 820\r
821 TcpSendAck (Tcb);\r
822 } else if (Tcb->DelayedAck == 0) {\r
823\r
dea6914d 824 DEBUG ((EFI_D_NET, "TcpOnAppConsume: scheduled a delayed"\r
dfc1f033 825 " ACK to update window for Tcb %p\n", Tcb));\r
8a67d61d 826\r
827 Tcb->DelayedAck = 1;\r
828 }\r
829 }\r
830\r
831 break;\r
832\r
833 case TCP_CLOSE_WAIT:\r
276dcc1b 834 return;\r
8a67d61d 835\r
836 case TCP_FIN_WAIT_1:\r
837 case TCP_FIN_WAIT_2:\r
838 case TCP_CLOSING:\r
839 case TCP_LAST_ACK:\r
840 case TCP_TIME_WAIT:\r
276dcc1b 841 return;\r
c191cdd1 842\r
843 default:\r
844 break;\r
8a67d61d 845 }\r
8a67d61d 846}\r
847\r
848\r
849/**\r
850 Abort the connection by sending a reset segment, called\r
851 when the application wants to abort the connection.\r
852\r
853 @param Tcb Pointer to the TCP_CB of the TCP instance.\r
854\r
8a67d61d 855**/\r
856VOID\r
857TcpOnAppAbort (\r
858 IN TCP_CB *Tcb\r
859 )\r
860{\r
e48e37fc 861 DEBUG ((EFI_D_WARN, "TcpOnAppAbort: connection reset "\r
0e549d5b 862 "issued by application for TCB %p\n", Tcb));\r
8a67d61d 863\r
864 switch (Tcb->State) {\r
865 case TCP_SYN_RCVD:\r
866 case TCP_ESTABLISHED:\r
867 case TCP_FIN_WAIT_1:\r
868 case TCP_FIN_WAIT_2:\r
869 case TCP_CLOSE_WAIT:\r
870 TcpResetConnection (Tcb);\r
871 break;\r
77f00155 872 default:\r
873 break;\r
8a67d61d 874 }\r
875\r
876 TcpSetState (Tcb, TCP_CLOSED);\r
877}\r
878\r
120db52c 879/**\r
e5e12de7 880 Install the device path protocol on the TCP instance.\r
881\r
120db52c 882 @param Sock Pointer to the socket representing the TCP instance.\r
e5e12de7 883\r
120db52c 884 @retval EFI_SUCCESS The device path protocol is installed.\r
885 @retval other Failed to install the device path protocol.\r
e5e12de7 886\r
120db52c 887**/\r
888EFI_STATUS\r
889TcpInstallDevicePath (\r
890 IN SOCKET *Sock\r
891 )\r
e5e12de7 892{\r
893 TCP4_PROTO_DATA *TcpProto;\r
894 TCP4_SERVICE_DATA *TcpService;\r
895 TCP_CB *Tcb;\r
896 IPv4_DEVICE_PATH Ip4DPathNode;\r
897 EFI_STATUS Status;\r
1204fe83 898 TCP_PORTNO LocalPort;\r
899 TCP_PORTNO RemotePort;\r
e5e12de7 900\r
901 TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
902 TcpService = TcpProto->TcpService;\r
903 Tcb = TcpProto->TcpPcb;\r
904\r
1204fe83 905 LocalPort = NTOHS (Tcb->LocalEnd.Port);\r
906 RemotePort = NTOHS (Tcb->RemoteEnd.Port);\r
e5e12de7 907 NetLibCreateIPv4DPathNode (\r
908 &Ip4DPathNode,\r
909 TcpService->ControllerHandle,\r
910 Tcb->LocalEnd.Ip,\r
1204fe83 911 LocalPort,\r
e5e12de7 912 Tcb->RemoteEnd.Ip,\r
1204fe83 913 RemotePort,\r
e5e12de7 914 EFI_IP_PROTO_TCP,\r
915 Tcb->UseDefaultAddr\r
916 );\r
917\r
501793fa
RN
918 IP4_COPY_ADDRESS (&Ip4DPathNode.SubnetMask, &Tcb->SubnetMask);\r
919\r
e5e12de7 920 Sock->DevicePath = AppendDevicePathNode (\r
120db52c 921 Sock->ParentDevicePath,\r
922 (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode\r
923 );\r
e5e12de7 924 if (Sock->DevicePath == NULL) {\r
925 return EFI_OUT_OF_RESOURCES;\r
926 }\r
927\r
928 Status = gBS->InstallProtocolInterface (\r
929 &Sock->SockHandle,\r
930 &gEfiDevicePathProtocolGuid,\r
931 EFI_NATIVE_INTERFACE,\r
932 Sock->DevicePath\r
933 );\r
934 if (EFI_ERROR (Status)) {\r
766c7483 935 FreePool (Sock->DevicePath);\r
e5e12de7 936 }\r
937\r
938 return Status;\r
939}\r