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