]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Misc.c
The patch acknowledges the TCP zero window probe message, either the format with...
[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
9c4a5f74 4Copyright (c) 2005 - 2010, 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
359 TCP4_PROTO_DATA *TcpProto;\r
360\r
361 ASSERT (\r
120db52c 362 (Tcb != NULL) &&\r
363 ((Tcb->State == TCP_LISTEN) ||\r
364 (Tcb->State == TCP_SYN_SENT) ||\r
365 (Tcb->State == TCP_SYN_RCVD) ||\r
366 (Tcb->State == TCP_CLOSED))\r
8a67d61d 367 );\r
368\r
369 if (Tcb->LocalEnd.Port == 0) {\r
370 return -1;\r
371 }\r
372\r
373 Head = &mTcpRunQue;\r
374\r
375 if (Tcb->State == TCP_LISTEN) {\r
376 Head = &mTcpListenQue;\r
377 }\r
378\r
379 //\r
380 // Check that Tcb isn't already on the list.\r
381 //\r
382 NET_LIST_FOR_EACH (Entry, Head) {\r
383 Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
384\r
385 if (TCP_PEER_EQUAL (&Tcb->LocalEnd, &Node->LocalEnd) &&\r
386 TCP_PEER_EQUAL (&Tcb->RemoteEnd, &Node->RemoteEnd)) {\r
387\r
388 return -1;\r
389 }\r
390 }\r
391\r
e48e37fc 392 InsertHeadList (Head, &Tcb->List);\r
8a67d61d 393\r
394 TcpProto = (TCP4_PROTO_DATA *) Tcb->Sk->ProtoReserved;\r
395 TcpSetVariableData (TcpProto->TcpService);\r
396\r
397 return 0;\r
398}\r
399\r
400\r
401/**\r
dfc1f033 402 Clone a TCB_CB from Tcb.\r
8a67d61d 403\r
404 @param Tcb Pointer to the TCP_CB to be cloned.\r
405\r
120db52c 406 @return Pointer to the new cloned TCP_CB, if NULL error condition occurred.\r
8a67d61d 407\r
408**/\r
409TCP_CB *\r
410TcpCloneTcb (\r
411 IN TCP_CB *Tcb\r
412 )\r
413{\r
414 TCP_CB *Clone;\r
415\r
e48e37fc 416 Clone = AllocatePool (sizeof (TCP_CB));\r
8a67d61d 417\r
418 if (Clone == NULL) {\r
419 return NULL;\r
420\r
421 }\r
422\r
e48e37fc 423 CopyMem (Clone, Tcb, sizeof (TCP_CB));\r
8a67d61d 424\r
425 //\r
426 // Increate the reference count of the shared IpInfo.\r
427 //\r
428 NET_GET_REF (Tcb->IpInfo);\r
429\r
e48e37fc 430 InitializeListHead (&Clone->List);\r
431 InitializeListHead (&Clone->SndQue);\r
432 InitializeListHead (&Clone->RcvQue);\r
8a67d61d 433\r
434 Clone->Sk = SockClone (Tcb->Sk);\r
435 if (Clone->Sk == NULL) {\r
e48e37fc 436 DEBUG ((EFI_D_ERROR, "TcpCloneTcb: failed to clone a sock\n"));\r
766c7483 437 FreePool (Clone);\r
8a67d61d 438 return NULL;\r
439 }\r
440\r
441 ((TCP4_PROTO_DATA *) (Clone->Sk->ProtoReserved))->TcpPcb = Clone;\r
442\r
443 return Clone;\r
444}\r
445\r
446\r
447/**\r
448 Compute an ISS to be used by a new connection.\r
449\r
120db52c 450 @return The result ISS.\r
8a67d61d 451\r
452**/\r
453TCP_SEQNO\r
454TcpGetIss (\r
455 VOID\r
456 )\r
457{\r
458 mTcpGlobalIss += 2048;\r
459 return mTcpGlobalIss;\r
460}\r
461\r
462\r
463/**\r
464 Get the local mss.\r
465\r
85511ddf 466 @param Sock Pointer to the socket to get mss\r
8a67d61d 467\r
120db52c 468 @return The mss size.\r
8a67d61d 469\r
470**/\r
471UINT16\r
472TcpGetRcvMss (\r
473 IN SOCKET *Sock\r
474 )\r
475{\r
a1503a32 476 EFI_IP4_MODE_DATA Ip4Mode;\r
8a67d61d 477 TCP4_PROTO_DATA *TcpProto;\r
478 EFI_IP4_PROTOCOL *Ip;\r
479\r
120db52c 480 ASSERT (Sock != NULL);\r
8a67d61d 481\r
482 TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
2a2e33b2 483 Ip = TcpProto->TcpService->IpIo->Ip.Ip4;\r
120db52c 484 ASSERT (Ip != NULL);\r
8a67d61d 485\r
a1503a32 486 Ip->GetModeData (Ip, &Ip4Mode, NULL, NULL);\r
8a67d61d 487\r
a1503a32 488 return (UINT16) (Ip4Mode.MaxPacketSize - sizeof (TCP_HEAD));\r
8a67d61d 489}\r
490\r
491\r
492/**\r
493 Set the Tcb's state.\r
494\r
495 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
496 @param State The state to be set.\r
497\r
8a67d61d 498**/\r
499VOID\r
500TcpSetState (\r
77f00155 501 IN OUT TCP_CB *Tcb,\r
502 IN UINT8 State\r
8a67d61d 503 )\r
504{\r
9c4a5f74 505 ASSERT (Tcb->State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));\r
506 ASSERT (State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));\r
507\r
e48e37fc 508 DEBUG (\r
509 (EFI_D_INFO,\r
0e549d5b 510 "Tcb (%p) state %s --> %s\n",\r
8a67d61d 511 Tcb,\r
512 mTcpStateName[Tcb->State],\r
513 mTcpStateName[State])\r
514 );\r
515\r
276dcc1b 516 Tcb->State = State;\r
8a67d61d 517\r
518 switch (State) {\r
519 case TCP_ESTABLISHED:\r
520\r
521 SockConnEstablished (Tcb->Sk);\r
e5e12de7 522\r
523 if (Tcb->Parent != NULL) {\r
524 //\r
525 // A new connection is accepted by a listening socket, install\r
526 // the device path.\r
527 //\r
528 TcpInstallDevicePath (Tcb->Sk);\r
529 }\r
530\r
8a67d61d 531 break;\r
532\r
533 case TCP_CLOSED:\r
534\r
535 SockConnClosed (Tcb->Sk);\r
536\r
dfc1f033 537 break;\r
dfa596b8 538 default:\r
8a67d61d 539 break;\r
540 }\r
541}\r
542\r
543\r
544/**\r
545 Compute the TCP segment's checksum.\r
546\r
547 @param Nbuf Pointer to the buffer that contains the TCP\r
548 segment.\r
549 @param HeadSum The checksum value of the fixed part of pseudo\r
550 header.\r
551\r
120db52c 552 @return The checksum value.\r
8a67d61d 553\r
554**/\r
555UINT16\r
556TcpChecksum (\r
557 IN NET_BUF *Nbuf,\r
558 IN UINT16 HeadSum\r
559 )\r
560{\r
561 UINT16 Checksum;\r
562\r
563 Checksum = NetbufChecksum (Nbuf);\r
564 Checksum = NetAddChecksum (Checksum, HeadSum);\r
565\r
120db52c 566 Checksum = NetAddChecksum (\r
567 Checksum,\r
568 HTONS ((UINT16) Nbuf->TotalSize)\r
569 );\r
8a67d61d 570\r
4eb65aff 571 return (UINT16) ~Checksum;\r
8a67d61d 572}\r
573\r
8a67d61d 574/**\r
575 Translate the information from the head of the received TCP\r
576 segment Nbuf contains and fill it into a TCP_SEG structure.\r
577\r
578 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
579 @param Nbuf Pointer to the buffer contains the TCP segment.\r
580\r
120db52c 581 @return Pointer to the TCP_SEG that contains the translated TCP head information.\r
8a67d61d 582\r
583**/\r
584TCP_SEG *\r
585TcpFormatNetbuf (\r
77f00155 586 IN TCP_CB *Tcb,\r
587 IN OUT NET_BUF *Nbuf\r
8a67d61d 588 )\r
589{\r
590 TCP_SEG *Seg;\r
591 TCP_HEAD *Head;\r
592\r
593 Seg = TCPSEG_NETBUF (Nbuf);\r
594 Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
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
660 Nhead->HeadLen = (sizeof (TCP_HEAD) >> 2);\r
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
e48e37fc 819 DEBUG ((EFI_D_INFO, "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
e48e37fc 825 DEBUG ((EFI_D_INFO, "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
880\r
881/**\r
882 Set the Tdp4 variable data.\r
883\r
120db52c 884 @param Tcp4Service Pointer to Tcp4 service data.\r
8a67d61d 885\r
886 @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.\r
887 @retval other Set variable failed.\r
888\r
889**/\r
890EFI_STATUS\r
891TcpSetVariableData (\r
892 IN TCP4_SERVICE_DATA *Tcp4Service\r
893 )\r
894{\r
895 UINT32 NumConfiguredInstance;\r
e48e37fc 896 LIST_ENTRY *Entry;\r
8a67d61d 897 TCP_CB *TcpPcb;\r
898 TCP4_PROTO_DATA *TcpProto;\r
899 UINTN VariableDataSize;\r
900 EFI_TCP4_VARIABLE_DATA *Tcp4VariableData;\r
901 EFI_TCP4_SERVICE_POINT *Tcp4ServicePoint;\r
902 CHAR16 *NewMacString;\r
903 EFI_STATUS Status;\r
904\r
905 NumConfiguredInstance = 0;\r
906\r
907 //\r
908 // Go through the running queue to count the instances.\r
909 //\r
910 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
911 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
912\r
913 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
914\r
915 if (TcpProto->TcpService == Tcp4Service) {\r
916 //\r
917 // This tcp instance belongs to the Tcp4Service.\r
918 //\r
919 NumConfiguredInstance++;\r
920 }\r
921 }\r
922\r
923 //\r
924 // Go through the listening queue to count the instances.\r
925 //\r
926 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
927 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
928\r
929 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
930\r
931 if (TcpProto->TcpService == Tcp4Service) {\r
932 //\r
933 // This tcp instance belongs to the Tcp4Service.\r
934 //\r
935 NumConfiguredInstance++;\r
936 }\r
937 }\r
938\r
939 //\r
940 // Calculate the size of the Tcp4VariableData. As there may be no Tcp4 child,\r
941 // we should add extra buffer for the service points only if the number of configured\r
942 // children is more than 1.\r
943 //\r
944 VariableDataSize = sizeof (EFI_TCP4_VARIABLE_DATA);\r
945\r
946 if (NumConfiguredInstance > 1) {\r
947 VariableDataSize += sizeof (EFI_TCP4_SERVICE_POINT) * (NumConfiguredInstance - 1);\r
948 }\r
949\r
e48e37fc 950 Tcp4VariableData = AllocatePool (VariableDataSize);\r
8a67d61d 951 if (Tcp4VariableData == NULL) {\r
952 return EFI_OUT_OF_RESOURCES;\r
953 }\r
954\r
955 Tcp4VariableData->DriverHandle = Tcp4Service->DriverBindingHandle;\r
956 Tcp4VariableData->ServiceCount = NumConfiguredInstance;\r
957\r
958 Tcp4ServicePoint = &Tcp4VariableData->Services[0];\r
959\r
960 //\r
961 // Go through the running queue to fill the service points.\r
962 //\r
963 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
964 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
965\r
966 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
967\r
968 if (TcpProto->TcpService == Tcp4Service) {\r
969 //\r
970 // This tcp instance belongs to the Tcp4Service.\r
971 //\r
972 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
e48e37fc 973 CopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 974 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
e48e37fc 975 CopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 976 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
977\r
978 Tcp4ServicePoint++;\r
979 }\r
980 }\r
981\r
982 //\r
983 // Go through the listening queue to fill the service points.\r
984 //\r
985 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
986 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
987\r
988 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
989\r
990 if (TcpProto->TcpService == Tcp4Service) {\r
991 //\r
992 // This tcp instance belongs to the Tcp4Service.\r
993 //\r
994 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
e48e37fc 995 CopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 996 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
e48e37fc 997 CopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 998 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
999\r
1000 Tcp4ServicePoint++;\r
1001 }\r
1002 }\r
1003\r
1004 //\r
1005 // Get the mac string.\r
1006 //\r
1007 Status = NetLibGetMacString (\r
1008 Tcp4Service->ControllerHandle,\r
1009 Tcp4Service->DriverBindingHandle,\r
1010 &NewMacString\r
1011 );\r
1012 if (EFI_ERROR (Status)) {\r
1013 goto ON_ERROR;\r
1014 }\r
1015\r
1016 if (Tcp4Service->MacString != NULL) {\r
1017 //\r
1018 // The variable is set already, we're going to update it.\r
1019 //\r
1020 if (StrCmp (Tcp4Service->MacString, NewMacString) != 0) {\r
1021 //\r
1022 // The mac address is changed, delete the previous variable first.\r
1023 //\r
1024 gRT->SetVariable (\r
1025 Tcp4Service->MacString,\r
1026 &gEfiTcp4ServiceBindingProtocolGuid,\r
1027 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1028 0,\r
1029 NULL\r
1030 );\r
1031 }\r
1032\r
766c7483 1033 FreePool (Tcp4Service->MacString);\r
8a67d61d 1034 }\r
1035\r
1036 Tcp4Service->MacString = NewMacString;\r
1037\r
1038 Status = gRT->SetVariable (\r
1039 Tcp4Service->MacString,\r
1040 &gEfiTcp4ServiceBindingProtocolGuid,\r
1041 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1042 VariableDataSize,\r
1043 (VOID *) Tcp4VariableData\r
1044 );\r
1045\r
1046ON_ERROR:\r
1047\r
766c7483 1048 FreePool (Tcp4VariableData);\r
8a67d61d 1049\r
1050 return Status;\r
1051}\r
1052\r
1053\r
1054/**\r
1055 Clear the variable and free the resource.\r
1056\r
120db52c 1057 @param Tcp4Service Pointer to Tcp4 service data.\r
8a67d61d 1058\r
1059**/\r
1060VOID\r
1061TcpClearVariableData (\r
1062 IN TCP4_SERVICE_DATA *Tcp4Service\r
1063 )\r
1064{\r
1065 ASSERT (Tcp4Service->MacString != NULL);\r
1066\r
1067 gRT->SetVariable (\r
1068 Tcp4Service->MacString,\r
1069 &gEfiTcp4ServiceBindingProtocolGuid,\r
1070 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1071 0,\r
1072 NULL\r
1073 );\r
1074\r
766c7483 1075 FreePool (Tcp4Service->MacString);\r
8a67d61d 1076 Tcp4Service->MacString = NULL;\r
1077}\r
1078\r
120db52c 1079/**\r
e5e12de7 1080 Install the device path protocol on the TCP instance.\r
1081\r
120db52c 1082 @param Sock Pointer to the socket representing the TCP instance.\r
e5e12de7 1083\r
120db52c 1084 @retval EFI_SUCCESS The device path protocol is installed.\r
1085 @retval other Failed to install the device path protocol.\r
e5e12de7 1086\r
120db52c 1087**/\r
1088EFI_STATUS\r
1089TcpInstallDevicePath (\r
1090 IN SOCKET *Sock\r
1091 )\r
e5e12de7 1092{\r
1093 TCP4_PROTO_DATA *TcpProto;\r
1094 TCP4_SERVICE_DATA *TcpService;\r
1095 TCP_CB *Tcb;\r
1096 IPv4_DEVICE_PATH Ip4DPathNode;\r
1097 EFI_STATUS Status;\r
1204fe83 1098 TCP_PORTNO LocalPort;\r
1099 TCP_PORTNO RemotePort;\r
e5e12de7 1100\r
1101 TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
1102 TcpService = TcpProto->TcpService;\r
1103 Tcb = TcpProto->TcpPcb;\r
1104\r
1204fe83 1105 LocalPort = NTOHS (Tcb->LocalEnd.Port);\r
1106 RemotePort = NTOHS (Tcb->RemoteEnd.Port);\r
e5e12de7 1107 NetLibCreateIPv4DPathNode (\r
1108 &Ip4DPathNode,\r
1109 TcpService->ControllerHandle,\r
1110 Tcb->LocalEnd.Ip,\r
1204fe83 1111 LocalPort,\r
e5e12de7 1112 Tcb->RemoteEnd.Ip,\r
1204fe83 1113 RemotePort,\r
e5e12de7 1114 EFI_IP_PROTO_TCP,\r
1115 Tcb->UseDefaultAddr\r
1116 );\r
1117\r
1118 Sock->DevicePath = AppendDevicePathNode (\r
120db52c 1119 Sock->ParentDevicePath,\r
1120 (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode\r
1121 );\r
e5e12de7 1122 if (Sock->DevicePath == NULL) {\r
1123 return EFI_OUT_OF_RESOURCES;\r
1124 }\r
1125\r
1126 Status = gBS->InstallProtocolInterface (\r
1127 &Sock->SockHandle,\r
1128 &gEfiDevicePathProtocolGuid,\r
1129 EFI_NATIVE_INTERFACE,\r
1130 Sock->DevicePath\r
1131 );\r
1132 if (EFI_ERROR (Status)) {\r
766c7483 1133 FreePool (Sock->DevicePath);\r
e5e12de7 1134 }\r
1135\r
1136 return Status;\r
1137}\r