]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Misc.c
Code clean up in NetLib:
[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
fb115c61 4Copyright (c) 2005 - 2009, 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
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
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
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
fb115c61 481 Ip = (EFI_IP4_PROTOCOL *) (TcpProto->TcpService->IpIo->Ip);\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
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
276dcc1b 511 Tcb->State = 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
77f00155 581 IN TCP_CB *Tcb,\r
582 IN OUT NET_BUF *Nbuf\r
8a67d61d 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
77f00155 677 IN OUT TCP_CB *Tcb\r
8a67d61d 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
77f00155 697 IN OUT TCP_CB *Tcb\r
8a67d61d 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
77f00155 748 IN OUT TCP_CB *Tcb\r
8a67d61d 749 )\r
750{\r
751\r
752 switch (Tcb->State) {\r
753 case TCP_CLOSED:\r
754 return -1;\r
8a67d61d 755\r
756 case TCP_LISTEN:\r
757 return -1;\r
8a67d61d 758\r
759 case TCP_SYN_SENT:\r
760 case TCP_SYN_RCVD:\r
761 return 0;\r
8a67d61d 762\r
763 case TCP_ESTABLISHED:\r
764 case TCP_CLOSE_WAIT:\r
765 TcpToSendData (Tcb, 0);\r
766 return 0;\r
8a67d61d 767\r
768 case TCP_FIN_WAIT_1:\r
769 case TCP_FIN_WAIT_2:\r
770 case TCP_CLOSING:\r
771 case TCP_LAST_ACK:\r
772 case TCP_TIME_WAIT:\r
773 return -1;\r
77f00155 774\r
dfa596b8 775 default:\r
dfc1f033 776 break;\r
8a67d61d 777 }\r
778\r
779 return 0;\r
780}\r
781\r
782\r
783/**\r
784 Application has consumed some data, check whether\r
785 to send a window updata ack or a delayed ack.\r
786\r
787 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
788\r
8a67d61d 789**/\r
276dcc1b 790VOID\r
8a67d61d 791TcpOnAppConsume (\r
792 IN TCP_CB *Tcb\r
793 )\r
794{\r
4eb65aff 795 UINT32 TcpOld;\r
8a67d61d 796\r
797 switch (Tcb->State) {\r
798 case TCP_CLOSED:\r
276dcc1b 799 return;\r
8a67d61d 800\r
801 case TCP_LISTEN:\r
276dcc1b 802 return;\r
8a67d61d 803\r
804 case TCP_SYN_SENT:\r
805 case TCP_SYN_RCVD:\r
276dcc1b 806 return;\r
8a67d61d 807\r
808 case TCP_ESTABLISHED:\r
4eb65aff 809 TcpOld = TcpRcvWinOld (Tcb);\r
810 if (TcpRcvWinNow (Tcb) > TcpOld) {\r
8a67d61d 811\r
4eb65aff 812 if (TcpOld < Tcb->RcvMss) {\r
8a67d61d 813\r
e48e37fc 814 DEBUG ((EFI_D_INFO, "TcpOnAppConsume: send a window"\r
dfc1f033 815 " update for a window closed Tcb %p\n", Tcb));\r
8a67d61d 816\r
817 TcpSendAck (Tcb);\r
818 } else if (Tcb->DelayedAck == 0) {\r
819\r
e48e37fc 820 DEBUG ((EFI_D_INFO, "TcpOnAppConsume: scheduled a delayed"\r
dfc1f033 821 " ACK to update window for Tcb %p\n", Tcb));\r
8a67d61d 822\r
823 Tcb->DelayedAck = 1;\r
824 }\r
825 }\r
826\r
827 break;\r
828\r
829 case TCP_CLOSE_WAIT:\r
276dcc1b 830 return;\r
8a67d61d 831\r
832 case TCP_FIN_WAIT_1:\r
833 case TCP_FIN_WAIT_2:\r
834 case TCP_CLOSING:\r
835 case TCP_LAST_ACK:\r
836 case TCP_TIME_WAIT:\r
276dcc1b 837 return;\r
c191cdd1 838\r
839 default:\r
840 break;\r
8a67d61d 841 }\r
8a67d61d 842}\r
843\r
844\r
845/**\r
846 Abort the connection by sending a reset segment, called\r
847 when the application wants to abort the connection.\r
848\r
849 @param Tcb Pointer to the TCP_CB of the TCP instance.\r
850\r
8a67d61d 851**/\r
852VOID\r
853TcpOnAppAbort (\r
854 IN TCP_CB *Tcb\r
855 )\r
856{\r
e48e37fc 857 DEBUG ((EFI_D_WARN, "TcpOnAppAbort: connection reset "\r
0e549d5b 858 "issued by application for TCB %p\n", Tcb));\r
8a67d61d 859\r
860 switch (Tcb->State) {\r
861 case TCP_SYN_RCVD:\r
862 case TCP_ESTABLISHED:\r
863 case TCP_FIN_WAIT_1:\r
864 case TCP_FIN_WAIT_2:\r
865 case TCP_CLOSE_WAIT:\r
866 TcpResetConnection (Tcb);\r
867 break;\r
77f00155 868 default:\r
869 break;\r
8a67d61d 870 }\r
871\r
872 TcpSetState (Tcb, TCP_CLOSED);\r
873}\r
874\r
875\r
876/**\r
877 Set the Tdp4 variable data.\r
878\r
120db52c 879 @param Tcp4Service Pointer to Tcp4 service data.\r
8a67d61d 880\r
881 @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.\r
882 @retval other Set variable failed.\r
883\r
884**/\r
885EFI_STATUS\r
886TcpSetVariableData (\r
887 IN TCP4_SERVICE_DATA *Tcp4Service\r
888 )\r
889{\r
890 UINT32 NumConfiguredInstance;\r
e48e37fc 891 LIST_ENTRY *Entry;\r
8a67d61d 892 TCP_CB *TcpPcb;\r
893 TCP4_PROTO_DATA *TcpProto;\r
894 UINTN VariableDataSize;\r
895 EFI_TCP4_VARIABLE_DATA *Tcp4VariableData;\r
896 EFI_TCP4_SERVICE_POINT *Tcp4ServicePoint;\r
897 CHAR16 *NewMacString;\r
898 EFI_STATUS Status;\r
899\r
900 NumConfiguredInstance = 0;\r
901\r
902 //\r
903 // Go through the running queue to count the instances.\r
904 //\r
905 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
906 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
907\r
908 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
909\r
910 if (TcpProto->TcpService == Tcp4Service) {\r
911 //\r
912 // This tcp instance belongs to the Tcp4Service.\r
913 //\r
914 NumConfiguredInstance++;\r
915 }\r
916 }\r
917\r
918 //\r
919 // Go through the listening queue to count the instances.\r
920 //\r
921 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
922 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
923\r
924 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
925\r
926 if (TcpProto->TcpService == Tcp4Service) {\r
927 //\r
928 // This tcp instance belongs to the Tcp4Service.\r
929 //\r
930 NumConfiguredInstance++;\r
931 }\r
932 }\r
933\r
934 //\r
935 // Calculate the size of the Tcp4VariableData. As there may be no Tcp4 child,\r
936 // we should add extra buffer for the service points only if the number of configured\r
937 // children is more than 1.\r
938 //\r
939 VariableDataSize = sizeof (EFI_TCP4_VARIABLE_DATA);\r
940\r
941 if (NumConfiguredInstance > 1) {\r
942 VariableDataSize += sizeof (EFI_TCP4_SERVICE_POINT) * (NumConfiguredInstance - 1);\r
943 }\r
944\r
e48e37fc 945 Tcp4VariableData = AllocatePool (VariableDataSize);\r
8a67d61d 946 if (Tcp4VariableData == NULL) {\r
947 return EFI_OUT_OF_RESOURCES;\r
948 }\r
949\r
950 Tcp4VariableData->DriverHandle = Tcp4Service->DriverBindingHandle;\r
951 Tcp4VariableData->ServiceCount = NumConfiguredInstance;\r
952\r
953 Tcp4ServicePoint = &Tcp4VariableData->Services[0];\r
954\r
955 //\r
956 // Go through the running queue to fill the service points.\r
957 //\r
958 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
959 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
960\r
961 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
962\r
963 if (TcpProto->TcpService == Tcp4Service) {\r
964 //\r
965 // This tcp instance belongs to the Tcp4Service.\r
966 //\r
967 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
e48e37fc 968 CopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 969 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
e48e37fc 970 CopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 971 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
972\r
973 Tcp4ServicePoint++;\r
974 }\r
975 }\r
976\r
977 //\r
978 // Go through the listening queue to fill the service points.\r
979 //\r
980 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
981 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
982\r
983 TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
984\r
985 if (TcpProto->TcpService == Tcp4Service) {\r
986 //\r
987 // This tcp instance belongs to the Tcp4Service.\r
988 //\r
989 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
e48e37fc 990 CopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 991 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
e48e37fc 992 CopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
8a67d61d 993 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
994\r
995 Tcp4ServicePoint++;\r
996 }\r
997 }\r
998\r
999 //\r
1000 // Get the mac string.\r
1001 //\r
1002 Status = NetLibGetMacString (\r
1003 Tcp4Service->ControllerHandle,\r
1004 Tcp4Service->DriverBindingHandle,\r
1005 &NewMacString\r
1006 );\r
1007 if (EFI_ERROR (Status)) {\r
1008 goto ON_ERROR;\r
1009 }\r
1010\r
1011 if (Tcp4Service->MacString != NULL) {\r
1012 //\r
1013 // The variable is set already, we're going to update it.\r
1014 //\r
1015 if (StrCmp (Tcp4Service->MacString, NewMacString) != 0) {\r
1016 //\r
1017 // The mac address is changed, delete the previous variable first.\r
1018 //\r
1019 gRT->SetVariable (\r
1020 Tcp4Service->MacString,\r
1021 &gEfiTcp4ServiceBindingProtocolGuid,\r
1022 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1023 0,\r
1024 NULL\r
1025 );\r
1026 }\r
1027\r
766c7483 1028 FreePool (Tcp4Service->MacString);\r
8a67d61d 1029 }\r
1030\r
1031 Tcp4Service->MacString = NewMacString;\r
1032\r
1033 Status = gRT->SetVariable (\r
1034 Tcp4Service->MacString,\r
1035 &gEfiTcp4ServiceBindingProtocolGuid,\r
1036 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1037 VariableDataSize,\r
1038 (VOID *) Tcp4VariableData\r
1039 );\r
1040\r
1041ON_ERROR:\r
1042\r
766c7483 1043 FreePool (Tcp4VariableData);\r
8a67d61d 1044\r
1045 return Status;\r
1046}\r
1047\r
1048\r
1049/**\r
1050 Clear the variable and free the resource.\r
1051\r
120db52c 1052 @param Tcp4Service Pointer to Tcp4 service data.\r
8a67d61d 1053\r
1054**/\r
1055VOID\r
1056TcpClearVariableData (\r
1057 IN TCP4_SERVICE_DATA *Tcp4Service\r
1058 )\r
1059{\r
1060 ASSERT (Tcp4Service->MacString != NULL);\r
1061\r
1062 gRT->SetVariable (\r
1063 Tcp4Service->MacString,\r
1064 &gEfiTcp4ServiceBindingProtocolGuid,\r
1065 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1066 0,\r
1067 NULL\r
1068 );\r
1069\r
766c7483 1070 FreePool (Tcp4Service->MacString);\r
8a67d61d 1071 Tcp4Service->MacString = NULL;\r
1072}\r
1073\r
120db52c 1074/**\r
e5e12de7 1075 Install the device path protocol on the TCP instance.\r
1076\r
120db52c 1077 @param Sock Pointer to the socket representing the TCP instance.\r
e5e12de7 1078\r
120db52c 1079 @retval EFI_SUCCESS The device path protocol is installed.\r
1080 @retval other Failed to install the device path protocol.\r
e5e12de7 1081\r
120db52c 1082**/\r
1083EFI_STATUS\r
1084TcpInstallDevicePath (\r
1085 IN SOCKET *Sock\r
1086 )\r
e5e12de7 1087{\r
1088 TCP4_PROTO_DATA *TcpProto;\r
1089 TCP4_SERVICE_DATA *TcpService;\r
1090 TCP_CB *Tcb;\r
1091 IPv4_DEVICE_PATH Ip4DPathNode;\r
1092 EFI_STATUS Status;\r
1204fe83 1093 TCP_PORTNO LocalPort;\r
1094 TCP_PORTNO RemotePort;\r
e5e12de7 1095\r
1096 TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
1097 TcpService = TcpProto->TcpService;\r
1098 Tcb = TcpProto->TcpPcb;\r
1099\r
1204fe83 1100 LocalPort = NTOHS (Tcb->LocalEnd.Port);\r
1101 RemotePort = NTOHS (Tcb->RemoteEnd.Port);\r
e5e12de7 1102 NetLibCreateIPv4DPathNode (\r
1103 &Ip4DPathNode,\r
1104 TcpService->ControllerHandle,\r
1105 Tcb->LocalEnd.Ip,\r
1204fe83 1106 LocalPort,\r
e5e12de7 1107 Tcb->RemoteEnd.Ip,\r
1204fe83 1108 RemotePort,\r
e5e12de7 1109 EFI_IP_PROTO_TCP,\r
1110 Tcb->UseDefaultAddr\r
1111 );\r
1112\r
1113 Sock->DevicePath = AppendDevicePathNode (\r
120db52c 1114 Sock->ParentDevicePath,\r
1115 (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode\r
1116 );\r
e5e12de7 1117 if (Sock->DevicePath == NULL) {\r
1118 return EFI_OUT_OF_RESOURCES;\r
1119 }\r
1120\r
1121 Status = gBS->InstallProtocolInterface (\r
1122 &Sock->SockHandle,\r
1123 &gEfiDevicePathProtocolGuid,\r
1124 EFI_NATIVE_INTERFACE,\r
1125 Sock->DevicePath\r
1126 );\r
1127 if (EFI_ERROR (Status)) {\r
766c7483 1128 FreePool (Sock->DevicePath);\r
e5e12de7 1129 }\r
1130\r
1131 return Status;\r
1132}\r