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