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