]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Misc.c
Fix a bug about the iSCSI DHCP dependency issue.
[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
501793fa 4Copyright (c) 2005 - 2011, 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
a56b6e03 595 ASSERT (Head != NULL);\r
8a67d61d 596 Nbuf->Tcp = Head;\r
597\r
598 Seg->Seq = NTOHL (Head->Seq);\r
599 Seg->Ack = NTOHL (Head->Ack);\r
600 Seg->End = Seg->Seq + (Nbuf->TotalSize - (Head->HeadLen << 2));\r
601\r
602 Seg->Urg = NTOHS (Head->Urg);\r
603 Seg->Wnd = (NTOHS (Head->Wnd) << Tcb->SndWndScale);\r
604 Seg->Flag = Head->Flag;\r
605\r
606 //\r
607 // SYN and FIN flag occupy one sequence space each.\r
608 //\r
609 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
610 //\r
611 // RFC requires that initial window not be scaled\r
612 //\r
613 Seg->Wnd = NTOHS (Head->Wnd);\r
614 Seg->End++;\r
615 }\r
616\r
617 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
618 Seg->End++;\r
619 }\r
620\r
621 return Seg;\r
622}\r
623\r
624\r
625/**\r
626 Reset the connection related with Tcb.\r
627\r
628 @param Tcb Pointer to the TCP_CB of the connection to be\r
629 reset.\r
630\r
8a67d61d 631**/\r
632VOID\r
633TcpResetConnection (\r
634 IN TCP_CB *Tcb\r
635 )\r
636{\r
637 NET_BUF *Nbuf;\r
638 TCP_HEAD *Nhead;\r
639\r
640 Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
641\r
642 if (Nbuf == NULL) {\r
643 return ;\r
644 }\r
645\r
646 Nhead = (TCP_HEAD *) NetbufAllocSpace (\r
647 Nbuf,\r
648 sizeof (TCP_HEAD),\r
649 NET_BUF_TAIL\r
650 );\r
651\r
652 ASSERT (Nhead != NULL);\r
653\r
654 Nbuf->Tcp = Nhead;\r
655\r
656 Nhead->Flag = TCP_FLG_RST;\r
657 Nhead->Seq = HTONL (Tcb->SndNxt);\r
658 Nhead->Ack = HTONL (Tcb->RcvNxt);\r
659 Nhead->SrcPort = Tcb->LocalEnd.Port;\r
660 Nhead->DstPort = Tcb->RemoteEnd.Port;\r
c9325700 661 Nhead->HeadLen = (UINT8) (sizeof (TCP_HEAD) >> 2);\r
8a67d61d 662 Nhead->Res = 0;\r
663 Nhead->Wnd = HTONS (0xFFFF);\r
664 Nhead->Checksum = 0;\r
665 Nhead->Urg = 0;\r
666 Nhead->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);\r
667\r
668 TcpSendIpPacket (Tcb, Nbuf, Tcb->LocalEnd.Ip, Tcb->RemoteEnd.Ip);\r
669\r
670 NetbufFree (Nbuf);\r
671}\r
672\r
673\r
674/**\r
120db52c 675 Initialize an active connection.\r
8a67d61d 676\r
677 @param Tcb Pointer to the TCP_CB that wants to initiate a\r
678 connection.\r
679\r
8a67d61d 680**/\r
681VOID\r
682TcpOnAppConnect (\r
77f00155 683 IN OUT TCP_CB *Tcb\r
8a67d61d 684 )\r
685{\r
686 TcpInitTcbLocal (Tcb);\r
687 TcpSetState (Tcb, TCP_SYN_SENT);\r
688\r
689 TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
690 TcpToSendData (Tcb, 1);\r
691}\r
692\r
693\r
694/**\r
695 Initiate the connection close procedure, called when\r
696 applications want to close the connection.\r
697\r
698 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
699\r
8a67d61d 700**/\r
701VOID\r
702TcpOnAppClose (\r
77f00155 703 IN OUT TCP_CB *Tcb\r
8a67d61d 704 )\r
705{\r
120db52c 706 ASSERT (Tcb != NULL);\r
8a67d61d 707\r
120db52c 708 if (!IsListEmpty (&Tcb->RcvQue) || GET_RCV_DATASIZE (Tcb->Sk) != 0) {\r
8a67d61d 709\r
e48e37fc 710 DEBUG ((EFI_D_WARN, "TcpOnAppClose: connection reset "\r
0e549d5b 711 "because data is lost for TCB %p\n", Tcb));\r
8a67d61d 712\r
713 TcpResetConnection (Tcb);\r
714 TcpClose (Tcb);\r
715 return;\r
716 }\r
717\r
718 switch (Tcb->State) {\r
719 case TCP_CLOSED:\r
720 case TCP_LISTEN:\r
721 case TCP_SYN_SENT:\r
722 TcpSetState (Tcb, TCP_CLOSED);\r
723 break;\r
724\r
725 case TCP_SYN_RCVD:\r
726 case TCP_ESTABLISHED:\r
727 TcpSetState (Tcb, TCP_FIN_WAIT_1);\r
728 break;\r
729\r
730 case TCP_CLOSE_WAIT:\r
731 TcpSetState (Tcb, TCP_LAST_ACK);\r
732 break;\r
dfa596b8 733 default:\r
dfc1f033 734 break;\r
8a67d61d 735 }\r
736\r
737 TcpToSendData (Tcb, 1);\r
738}\r
739\r
740\r
741/**\r
120db52c 742 Check whether the application's newly delivered data can be sent out.\r
8a67d61d 743\r
744 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
745\r
746 @retval 0 Whether the data is sent out or is buffered for\r
747 further sending.\r
748 @retval -1 The Tcb is not in a state that data is permitted to\r
749 be sent out.\r
750\r
751**/\r
752INTN\r
753TcpOnAppSend (\r
77f00155 754 IN OUT TCP_CB *Tcb\r
8a67d61d 755 )\r
756{\r
757\r
758 switch (Tcb->State) {\r
759 case TCP_CLOSED:\r
760 return -1;\r
8a67d61d 761\r
762 case TCP_LISTEN:\r
763 return -1;\r
8a67d61d 764\r
765 case TCP_SYN_SENT:\r
766 case TCP_SYN_RCVD:\r
767 return 0;\r
8a67d61d 768\r
769 case TCP_ESTABLISHED:\r
770 case TCP_CLOSE_WAIT:\r
771 TcpToSendData (Tcb, 0);\r
772 return 0;\r
8a67d61d 773\r
774 case TCP_FIN_WAIT_1:\r
775 case TCP_FIN_WAIT_2:\r
776 case TCP_CLOSING:\r
777 case TCP_LAST_ACK:\r
778 case TCP_TIME_WAIT:\r
779 return -1;\r
77f00155 780\r
dfa596b8 781 default:\r
dfc1f033 782 break;\r
8a67d61d 783 }\r
784\r
785 return 0;\r
786}\r
787\r
788\r
789/**\r
790 Application has consumed some data, check whether\r
791 to send a window updata ack or a delayed ack.\r
792\r
793 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
794\r
8a67d61d 795**/\r
276dcc1b 796VOID\r
8a67d61d 797TcpOnAppConsume (\r
798 IN TCP_CB *Tcb\r
799 )\r
800{\r
4eb65aff 801 UINT32 TcpOld;\r
8a67d61d 802\r
803 switch (Tcb->State) {\r
804 case TCP_CLOSED:\r
276dcc1b 805 return;\r
8a67d61d 806\r
807 case TCP_LISTEN:\r
276dcc1b 808 return;\r
8a67d61d 809\r
810 case TCP_SYN_SENT:\r
811 case TCP_SYN_RCVD:\r
276dcc1b 812 return;\r
8a67d61d 813\r
814 case TCP_ESTABLISHED:\r
4eb65aff 815 TcpOld = TcpRcvWinOld (Tcb);\r
816 if (TcpRcvWinNow (Tcb) > TcpOld) {\r
8a67d61d 817\r
4eb65aff 818 if (TcpOld < Tcb->RcvMss) {\r
8a67d61d 819\r
e48e37fc 820 DEBUG ((EFI_D_INFO, "TcpOnAppConsume: send a window"\r
dfc1f033 821 " update for a window closed Tcb %p\n", Tcb));\r
8a67d61d 822\r
823 TcpSendAck (Tcb);\r
824 } else if (Tcb->DelayedAck == 0) {\r
825\r
e48e37fc 826 DEBUG ((EFI_D_INFO, "TcpOnAppConsume: scheduled a delayed"\r
dfc1f033 827 " ACK to update window for Tcb %p\n", Tcb));\r
8a67d61d 828\r
829 Tcb->DelayedAck = 1;\r
830 }\r
831 }\r
832\r
833 break;\r
834\r
835 case TCP_CLOSE_WAIT:\r
276dcc1b 836 return;\r
8a67d61d 837\r
838 case TCP_FIN_WAIT_1:\r
839 case TCP_FIN_WAIT_2:\r
840 case TCP_CLOSING:\r
841 case TCP_LAST_ACK:\r
842 case TCP_TIME_WAIT:\r
276dcc1b 843 return;\r
c191cdd1 844\r
845 default:\r
846 break;\r
8a67d61d 847 }\r
8a67d61d 848}\r
849\r
850\r
851/**\r
852 Abort the connection by sending a reset segment, called\r
853 when the application wants to abort the connection.\r
854\r
855 @param Tcb Pointer to the TCP_CB of the TCP instance.\r
856\r
8a67d61d 857**/\r
858VOID\r
859TcpOnAppAbort (\r
860 IN TCP_CB *Tcb\r
861 )\r
862{\r
e48e37fc 863 DEBUG ((EFI_D_WARN, "TcpOnAppAbort: connection reset "\r
0e549d5b 864 "issued by application for TCB %p\n", Tcb));\r
8a67d61d 865\r
866 switch (Tcb->State) {\r
867 case TCP_SYN_RCVD:\r
868 case TCP_ESTABLISHED:\r
869 case TCP_FIN_WAIT_1:\r
870 case TCP_FIN_WAIT_2:\r
871 case TCP_CLOSE_WAIT:\r
872 TcpResetConnection (Tcb);\r
873 break;\r
77f00155 874 default:\r
875 break;\r
8a67d61d 876 }\r
877\r
878 TcpSetState (Tcb, TCP_CLOSED);\r
879}\r
880\r
881\r
882/**\r
883 Set the Tdp4 variable data.\r
884\r
120db52c 885 @param Tcp4Service Pointer to Tcp4 service data.\r
8a67d61d 886\r
887 @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.\r
888 @retval other Set variable failed.\r
889\r
890**/\r
891EFI_STATUS\r
892TcpSetVariableData (\r
893 IN TCP4_SERVICE_DATA *Tcp4Service\r
894 )\r
895{\r
896 UINT32 NumConfiguredInstance;\r
e48e37fc 897 LIST_ENTRY *Entry;\r
8a67d61d 898 TCP_CB *TcpPcb;\r
899 TCP4_PROTO_DATA *TcpProto;\r
900 UINTN VariableDataSize;\r
901 EFI_TCP4_VARIABLE_DATA *Tcp4VariableData;\r
902 EFI_TCP4_SERVICE_POINT *Tcp4ServicePoint;\r
903 CHAR16 *NewMacString;\r
904 EFI_STATUS Status;\r
905\r
906 NumConfiguredInstance = 0;\r
907\r
908 //\r
909 // Go through the running queue to count the instances.\r
910 //\r
911 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
912 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
913\r
914 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
915\r
916 if (TcpProto->TcpService == Tcp4Service) {\r
917 //\r
918 // This tcp instance belongs to the Tcp4Service.\r
919 //\r
920 NumConfiguredInstance++;\r
921 }\r
922 }\r
923\r
924 //\r
925 // Go through the listening queue to count the instances.\r
926 //\r
927 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
928 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
929\r
930 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
931\r
932 if (TcpProto->TcpService == Tcp4Service) {\r
933 //\r
934 // This tcp instance belongs to the Tcp4Service.\r
935 //\r
936 NumConfiguredInstance++;\r
937 }\r
938 }\r
939\r
940 //\r
941 // Calculate the size of the Tcp4VariableData. As there may be no Tcp4 child,\r
942 // we should add extra buffer for the service points only if the number of configured\r
943 // children is more than 1.\r
944 //\r
945 VariableDataSize = sizeof (EFI_TCP4_VARIABLE_DATA);\r
946\r
947 if (NumConfiguredInstance > 1) {\r
948 VariableDataSize += sizeof (EFI_TCP4_SERVICE_POINT) * (NumConfiguredInstance - 1);\r
949 }\r
950\r
e48e37fc 951 Tcp4VariableData = AllocatePool (VariableDataSize);\r
8a67d61d 952 if (Tcp4VariableData == NULL) {\r
953 return EFI_OUT_OF_RESOURCES;\r
954 }\r
955\r
956 Tcp4VariableData->DriverHandle = Tcp4Service->DriverBindingHandle;\r
957 Tcp4VariableData->ServiceCount = NumConfiguredInstance;\r
958\r
959 Tcp4ServicePoint = &Tcp4VariableData->Services[0];\r
960\r
961 //\r
962 // Go through the running queue to fill the service points.\r
963 //\r
964 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
965 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
966\r
967 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
968\r
969 if (TcpProto->TcpService == Tcp4Service) {\r
970 //\r
971 // This tcp instance belongs to the Tcp4Service.\r
972 //\r
973 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
e48e37fc 974 CopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 975 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
e48e37fc 976 CopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 977 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
978\r
979 Tcp4ServicePoint++;\r
980 }\r
981 }\r
982\r
983 //\r
984 // Go through the listening queue to fill the service points.\r
985 //\r
986 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
987 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
988\r
989 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
990\r
991 if (TcpProto->TcpService == Tcp4Service) {\r
992 //\r
993 // This tcp instance belongs to the Tcp4Service.\r
994 //\r
995 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
e48e37fc 996 CopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 997 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
e48e37fc 998 CopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 999 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
1000\r
1001 Tcp4ServicePoint++;\r
1002 }\r
1003 }\r
1004\r
1005 //\r
1006 // Get the mac string.\r
1007 //\r
1008 Status = NetLibGetMacString (\r
1009 Tcp4Service->ControllerHandle,\r
1010 Tcp4Service->DriverBindingHandle,\r
1011 &NewMacString\r
1012 );\r
1013 if (EFI_ERROR (Status)) {\r
1014 goto ON_ERROR;\r
1015 }\r
1016\r
1017 if (Tcp4Service->MacString != NULL) {\r
1018 //\r
1019 // The variable is set already, we're going to update it.\r
1020 //\r
1021 if (StrCmp (Tcp4Service->MacString, NewMacString) != 0) {\r
1022 //\r
1023 // The mac address is changed, delete the previous variable first.\r
1024 //\r
1025 gRT->SetVariable (\r
1026 Tcp4Service->MacString,\r
1027 &gEfiTcp4ServiceBindingProtocolGuid,\r
1028 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1029 0,\r
1030 NULL\r
1031 );\r
1032 }\r
1033\r
766c7483 1034 FreePool (Tcp4Service->MacString);\r
8a67d61d 1035 }\r
1036\r
1037 Tcp4Service->MacString = NewMacString;\r
1038\r
1039 Status = gRT->SetVariable (\r
1040 Tcp4Service->MacString,\r
1041 &gEfiTcp4ServiceBindingProtocolGuid,\r
1042 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1043 VariableDataSize,\r
1044 (VOID *) Tcp4VariableData\r
1045 );\r
1046\r
1047ON_ERROR:\r
1048\r
766c7483 1049 FreePool (Tcp4VariableData);\r
8a67d61d 1050\r
1051 return Status;\r
1052}\r
1053\r
1054\r
1055/**\r
1056 Clear the variable and free the resource.\r
1057\r
120db52c 1058 @param Tcp4Service Pointer to Tcp4 service data.\r
8a67d61d 1059\r
1060**/\r
1061VOID\r
1062TcpClearVariableData (\r
1063 IN TCP4_SERVICE_DATA *Tcp4Service\r
1064 )\r
1065{\r
1066 ASSERT (Tcp4Service->MacString != NULL);\r
1067\r
1068 gRT->SetVariable (\r
1069 Tcp4Service->MacString,\r
1070 &gEfiTcp4ServiceBindingProtocolGuid,\r
1071 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1072 0,\r
1073 NULL\r
1074 );\r
1075\r
766c7483 1076 FreePool (Tcp4Service->MacString);\r
8a67d61d 1077 Tcp4Service->MacString = NULL;\r
1078}\r
1079\r
120db52c 1080/**\r
e5e12de7 1081 Install the device path protocol on the TCP instance.\r
1082\r
120db52c 1083 @param Sock Pointer to the socket representing the TCP instance.\r
e5e12de7 1084\r
120db52c 1085 @retval EFI_SUCCESS The device path protocol is installed.\r
1086 @retval other Failed to install the device path protocol.\r
e5e12de7 1087\r
120db52c 1088**/\r
1089EFI_STATUS\r
1090TcpInstallDevicePath (\r
1091 IN SOCKET *Sock\r
1092 )\r
e5e12de7 1093{\r
1094 TCP4_PROTO_DATA *TcpProto;\r
1095 TCP4_SERVICE_DATA *TcpService;\r
1096 TCP_CB *Tcb;\r
1097 IPv4_DEVICE_PATH Ip4DPathNode;\r
1098 EFI_STATUS Status;\r
1204fe83 1099 TCP_PORTNO LocalPort;\r
1100 TCP_PORTNO RemotePort;\r
e5e12de7 1101\r
1102 TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
1103 TcpService = TcpProto->TcpService;\r
1104 Tcb = TcpProto->TcpPcb;\r
1105\r
1204fe83 1106 LocalPort = NTOHS (Tcb->LocalEnd.Port);\r
1107 RemotePort = NTOHS (Tcb->RemoteEnd.Port);\r
e5e12de7 1108 NetLibCreateIPv4DPathNode (\r
1109 &Ip4DPathNode,\r
1110 TcpService->ControllerHandle,\r
1111 Tcb->LocalEnd.Ip,\r
1204fe83 1112 LocalPort,\r
e5e12de7 1113 Tcb->RemoteEnd.Ip,\r
1204fe83 1114 RemotePort,\r
e5e12de7 1115 EFI_IP_PROTO_TCP,\r
1116 Tcb->UseDefaultAddr\r
1117 );\r
1118\r
501793fa
RN
1119 IP4_COPY_ADDRESS (&Ip4DPathNode.SubnetMask, &Tcb->SubnetMask);\r
1120\r
e5e12de7 1121 Sock->DevicePath = AppendDevicePathNode (\r
120db52c 1122 Sock->ParentDevicePath,\r
1123 (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode\r
1124 );\r
e5e12de7 1125 if (Sock->DevicePath == NULL) {\r
1126 return EFI_OUT_OF_RESOURCES;\r
1127 }\r
1128\r
1129 Status = gBS->InstallProtocolInterface (\r
1130 &Sock->SockHandle,\r
1131 &gEfiDevicePathProtocolGuid,\r
1132 EFI_NATIVE_INTERFACE,\r
1133 Sock->DevicePath\r
1134 );\r
1135 if (EFI_ERROR (Status)) {\r
766c7483 1136 FreePool (Sock->DevicePath);\r
e5e12de7 1137 }\r
1138\r
1139 return Status;\r
1140}\r