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