]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Tcp4Dxe/SockImpl.c
Refine the comments in PciSegmentLib
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Tcp4Dxe / SockImpl.c
CommitLineData
8a67d61d 1/** @file\r
2\r
3Copyright (c) 2005 - 2006, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 SockImpl.c\r
15\r
16Abstract:\r
17\r
18\r
19**/\r
20\r
21#include "SockImpl.h"\r
22\r
8a67d61d 23UINT32\r
24SockTcpDataToRcv (\r
25 IN SOCK_BUFFER *SockBuffer,\r
26 OUT BOOLEAN *IsOOB,\r
27 IN UINT32 BufLen\r
28 );\r
29\r
8a67d61d 30VOID\r
31SockProcessSndToken (\r
32 IN SOCKET *Sock\r
33 );\r
34\r
35VOID\r
36SockFreeFoo (\r
37 IN EFI_EVENT Event\r
38 )\r
39{\r
40 return ;\r
41}\r
42\r
43\r
44/**\r
45 Get the length of the data that can be retrieved from the socket\r
46 receive buffer.\r
47\r
48 @param SockBuffer Pointer to the socket receive buffer.\r
49 @param IsUrg Pointer to a BOOLEAN variable. If TRUE the data is\r
50 OOB.\r
51 @param BufLen The maximum length of the data buffer to store the\r
52 received data in socket layer.\r
53\r
54 @return The length of the data can be retreived.\r
55\r
56**/\r
8a67d61d 57UINT32\r
58SockTcpDataToRcv (\r
59 IN SOCK_BUFFER *SockBuffer,\r
60 OUT BOOLEAN *IsUrg,\r
61 IN UINT32 BufLen\r
62 )\r
63{\r
64 NET_BUF *RcvBufEntry;\r
65 UINT32 DataLen;\r
66 TCP_RSV_DATA *TcpRsvData;\r
67 BOOLEAN Urg;\r
68\r
69 ASSERT (SockBuffer && IsUrg && (BufLen > 0));\r
70\r
71 RcvBufEntry = SockBufFirst (SockBuffer);\r
72 ASSERT (RcvBufEntry);\r
73\r
74 TcpRsvData = (TCP_RSV_DATA *) RcvBufEntry->ProtoData;\r
75\r
4eb65aff 76 *IsUrg = (BOOLEAN) ((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);\r
8a67d61d 77\r
78 if (*IsUrg && TcpRsvData->UrgLen < RcvBufEntry->TotalSize) {\r
79\r
36ee91ca 80 DataLen = MIN (TcpRsvData->UrgLen, BufLen);\r
8a67d61d 81\r
82 if (DataLen < TcpRsvData->UrgLen) {\r
83 TcpRsvData->UrgLen = TcpRsvData->UrgLen - DataLen;\r
84 } else {\r
85 TcpRsvData->UrgLen = 0;\r
86 }\r
87\r
88 return DataLen;\r
89\r
90 }\r
91\r
92 DataLen = RcvBufEntry->TotalSize;\r
93\r
94 RcvBufEntry = SockBufNext (SockBuffer, RcvBufEntry);\r
95\r
96 while ((BufLen > DataLen) && (RcvBufEntry != NULL)) {\r
97\r
98 TcpRsvData = (TCP_RSV_DATA *) RcvBufEntry->ProtoData;\r
99\r
4eb65aff 100 Urg = (BOOLEAN) ((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);\r
8a67d61d 101\r
102 if (*IsUrg != Urg) {\r
103 break;\r
104 }\r
105\r
106 if (*IsUrg && TcpRsvData->UrgLen < RcvBufEntry->TotalSize) {\r
107\r
108 if (TcpRsvData->UrgLen + DataLen < BufLen) {\r
109 TcpRsvData->UrgLen = 0;\r
110 } else {\r
111 TcpRsvData->UrgLen = TcpRsvData->UrgLen - (BufLen - DataLen);\r
112 }\r
113\r
36ee91ca 114 return MIN (TcpRsvData->UrgLen + DataLen, BufLen);\r
8a67d61d 115\r
116 }\r
117\r
118 DataLen += RcvBufEntry->TotalSize;\r
119\r
120 RcvBufEntry = SockBufNext (SockBuffer, RcvBufEntry);\r
121 }\r
122\r
36ee91ca 123 DataLen = MIN (BufLen, DataLen);\r
8a67d61d 124 return DataLen;\r
125}\r
126\r
127\r
128/**\r
129 Copy data from socket buffer to application provided receive buffer.\r
130\r
131 @param Sock Pointer to the socket.\r
132 @param TcpRxData Pointer to the application provided receive buffer.\r
133 @param RcvdBytes The maximum length of the data can be copied.\r
134 @param IsOOB If TURE the data is OOB, else the data is normal.\r
135\r
136 @return None.\r
137\r
138**/\r
139VOID\r
140SockSetTcpRxData (\r
141 IN SOCKET *Sock,\r
142 IN VOID *TcpRxData,\r
143 IN UINT32 RcvdBytes,\r
144 IN BOOLEAN IsOOB\r
145 )\r
146{\r
147 UINT32 Index;\r
148 UINT32 CopyBytes;\r
149 UINT32 OffSet;\r
150 EFI_TCP4_RECEIVE_DATA *RxData;\r
151 EFI_TCP4_FRAGMENT_DATA *Fragment;\r
152\r
153 RxData = (EFI_TCP4_RECEIVE_DATA *) TcpRxData;\r
154\r
155 OffSet = 0;\r
156\r
157 ASSERT (RxData->DataLength >= RcvdBytes);\r
158\r
159 RxData->DataLength = RcvdBytes;\r
160 RxData->UrgentFlag = IsOOB;\r
161\r
162 for (Index = 0; (Index < RxData->FragmentCount) && (RcvdBytes > 0); Index++) {\r
163\r
164 Fragment = &RxData->FragmentTable[Index];\r
36ee91ca 165 CopyBytes = MIN ((UINT32) (Fragment->FragmentLength), RcvdBytes);\r
8a67d61d 166\r
167 NetbufQueCopy (\r
168 Sock->RcvBuffer.DataQueue,\r
169 OffSet,\r
170 CopyBytes,\r
171 Fragment->FragmentBuffer\r
172 );\r
173\r
174 Fragment->FragmentLength = CopyBytes;\r
175 RcvdBytes -= CopyBytes;\r
176 OffSet += CopyBytes;\r
177 }\r
178}\r
179\r
180\r
181/**\r
182 Get received data from the socket layer to the receive token.\r
183\r
184 @param Sock Pointer to the socket.\r
185 @param RcvToken Pointer to the application provided receive token.\r
186\r
187 @return The length of data received in this token.\r
188\r
189**/\r
190UINT32\r
191SockProcessRcvToken (\r
192 IN SOCKET *Sock,\r
193 IN SOCK_IO_TOKEN *RcvToken\r
194 )\r
195{\r
196 UINT32 TokenRcvdBytes;\r
197 EFI_TCP4_RECEIVE_DATA *RxData;\r
198 BOOLEAN IsUrg;\r
199\r
200 ASSERT (Sock);\r
201\r
202 ASSERT (SOCK_STREAM == Sock->Type);\r
203\r
204 RxData = RcvToken->Packet.RxData;\r
205\r
206 TokenRcvdBytes = SockTcpDataToRcv (\r
207 &Sock->RcvBuffer,\r
208 &IsUrg,\r
4eb65aff 209 (UINT32) RxData->DataLength\r
8a67d61d 210 );\r
211\r
212 //\r
213 // Copy data from RcvBuffer of socket to user\r
214 // provided RxData and set the fields in TCP RxData\r
215 //\r
216 SockSetTcpRxData (Sock, RxData, TokenRcvdBytes, IsUrg);\r
217\r
218 SOCK_TRIM_RCV_BUFF (Sock, TokenRcvdBytes);\r
219 SIGNAL_TOKEN (&(RcvToken->Token), EFI_SUCCESS);\r
220\r
221 return TokenRcvdBytes;\r
222}\r
223\r
224\r
225/**\r
226 Process the TCP send data, buffer the tcp txdata and append\r
227 the buffer to socket send buffer,then try to send it.\r
228\r
229 @param Sock Pointer to the socket.\r
230 @param TcpTxData Pointer to the tcp txdata.\r
231\r
232 @retval EFI_SUCCESS The operation is completed successfully.\r
233 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.\r
234\r
235**/\r
236EFI_STATUS\r
237SockProcessTcpSndData (\r
238 IN SOCKET *Sock,\r
239 IN VOID *TcpTxData\r
240 )\r
241{\r
242 NET_BUF *SndData;\r
243 EFI_STATUS Status;\r
244 EFI_TCP4_TRANSMIT_DATA *TxData;\r
245\r
246 TxData = (EFI_TCP4_TRANSMIT_DATA *) TcpTxData;\r
247\r
248 //\r
249 // transform this TxData into a NET_BUFFER\r
250 // and insert it into Sock->SndBuffer\r
251 //\r
252 SndData = NetbufFromExt (\r
253 (NET_FRAGMENT *) TxData->FragmentTable,\r
4eb65aff 254 (UINT32) TxData->FragmentCount,\r
8a67d61d 255 0,\r
256 0,\r
257 SockFreeFoo,\r
258 NULL\r
259 );\r
260\r
261 if (NULL == SndData) {\r
e48e37fc 262 DEBUG ((EFI_D_ERROR, "SockKProcessSndData: Failed to"\r
8a67d61d 263 " call NetBufferFromExt\n"));\r
264\r
265 return EFI_OUT_OF_RESOURCES;\r
266 }\r
267\r
268 NetbufQueAppend (Sock->SndBuffer.DataQueue, SndData);\r
269\r
270 //\r
271 // notify the low layer protocol to handle this send token\r
272 //\r
273 if (TxData->Urgent) {\r
274 Status = Sock->ProtoHandler (Sock, SOCK_SNDURG, NULL);\r
275\r
276 if (EFI_ERROR (Status)) {\r
277 return Status;\r
278 }\r
279 }\r
280\r
281 if (TxData->Push) {\r
282 Status = Sock->ProtoHandler (Sock, SOCK_SNDPUSH, NULL);\r
283\r
284 if (EFI_ERROR (Status)) {\r
285 return Status;\r
286 }\r
287 }\r
288\r
289 //\r
290 // low layer protocol should really handle the sending\r
291 // process when catching SOCK_SND request\r
292 //\r
293 Status = Sock->ProtoHandler (Sock, SOCK_SND, NULL);\r
294\r
295 if (EFI_ERROR (Status)) {\r
296 return Status;\r
297 }\r
298\r
299 return EFI_SUCCESS;\r
300}\r
301\r
302\r
303/**\r
304 Flush the tokens in the specific token list.\r
305\r
306 @param Sock Pointer to the socket.\r
307 @param PendingTokenList Pointer to the token list to be flushed.\r
308\r
309 @return None.\r
310\r
311**/\r
8a67d61d 312VOID\r
313SockFlushPendingToken (\r
314 IN SOCKET *Sock,\r
e48e37fc 315 IN LIST_ENTRY *PendingTokenList\r
8a67d61d 316 )\r
317{\r
318 SOCK_TOKEN *SockToken;\r
319 SOCK_COMPLETION_TOKEN *Token;\r
320\r
321 ASSERT (Sock && PendingTokenList);\r
322\r
e48e37fc 323 while (!IsListEmpty (PendingTokenList)) {\r
8a67d61d 324 SockToken = NET_LIST_HEAD (\r
325 PendingTokenList,\r
326 SOCK_TOKEN,\r
327 TokenList\r
328 );\r
329\r
330 Token = SockToken->Token;\r
331 SIGNAL_TOKEN (Token, Sock->SockError);\r
332\r
e48e37fc 333 RemoveEntryList (&(SockToken->TokenList));\r
334 gBS->FreePool (SockToken);\r
8a67d61d 335 }\r
336}\r
337\r
338\r
339/**\r
340 Wake up the connection token while the connection is\r
341 successfully established, then try to process any\r
342 pending send token.\r
343\r
344 @param Sock Pointer to the socket.\r
345\r
346 @return None.\r
347\r
348**/\r
8a67d61d 349VOID\r
350SockWakeConnToken (\r
351 IN SOCKET *Sock\r
352 )\r
353{\r
354 ASSERT (Sock->ConnectionToken != NULL);\r
355\r
356 SIGNAL_TOKEN (Sock->ConnectionToken, EFI_SUCCESS);\r
357 Sock->ConnectionToken = NULL;\r
358\r
359 //\r
360 // check to see if some pending send token existed?\r
361 //\r
362 SockProcessSndToken (Sock);\r
363 return ;\r
364}\r
365\r
366\r
367/**\r
368 Wake up the listen token while the connection is\r
369 established successfully.\r
370\r
371 @param Sock Pointer to the socket.\r
372\r
373 @return None.\r
374\r
375**/\r
8a67d61d 376VOID\r
377SockWakeListenToken (\r
378 IN SOCKET *Sock\r
379 )\r
380{\r
381 SOCKET *Parent;\r
382 SOCK_TOKEN *SockToken;\r
383 EFI_TCP4_LISTEN_TOKEN *ListenToken;\r
384\r
385 Parent = Sock->Parent;\r
386\r
387 ASSERT (Parent && SOCK_IS_LISTENING (Parent) && SOCK_IS_CONNECTED (Sock));\r
388\r
e48e37fc 389 if (!IsListEmpty (&Parent->ListenTokenList)) {\r
8a67d61d 390 SockToken = NET_LIST_HEAD (\r
391 &Parent->ListenTokenList,\r
392 SOCK_TOKEN,\r
393 TokenList\r
394 );\r
395\r
396 ListenToken = (EFI_TCP4_LISTEN_TOKEN *) SockToken->Token;\r
397 ListenToken->NewChildHandle = Sock->SockHandle;\r
398\r
399 SIGNAL_TOKEN (&(ListenToken->CompletionToken), EFI_SUCCESS);\r
400\r
e48e37fc 401 RemoveEntryList (&SockToken->TokenList);\r
402 gBS->FreePool (SockToken);\r
8a67d61d 403\r
e48e37fc 404 RemoveEntryList (&Sock->ConnectionList);\r
8a67d61d 405\r
406 Parent->ConnCnt--;\r
e48e37fc 407 DEBUG ((EFI_D_WARN, "SockWakeListenToken: accept a socket, now conncnt is %d", Parent->ConnCnt));\r
8a67d61d 408\r
409 Sock->Parent = NULL;\r
410 }\r
411}\r
412\r
413\r
414/**\r
415 Wake up the receive token while some data is received.\r
416\r
417 @param Sock Pointer to the socket.\r
418\r
419 @return None.\r
420\r
421**/\r
8a67d61d 422VOID\r
423SockWakeRcvToken (\r
424 IN SOCKET *Sock\r
425 )\r
426{\r
427 UINT32 RcvdBytes;\r
428 UINT32 TokenRcvdBytes;\r
429 SOCK_TOKEN *SockToken;\r
430 SOCK_IO_TOKEN *RcvToken;\r
431\r
432 ASSERT (Sock->RcvBuffer.DataQueue);\r
433\r
434 RcvdBytes = (Sock->RcvBuffer.DataQueue)->BufSize;\r
435\r
436 ASSERT (RcvdBytes > 0);\r
437\r
e48e37fc 438 while (RcvdBytes > 0 && !IsListEmpty (&Sock->RcvTokenList)) {\r
8a67d61d 439\r
440 SockToken = NET_LIST_HEAD (\r
441 &Sock->RcvTokenList,\r
442 SOCK_TOKEN,\r
443 TokenList\r
444 );\r
445\r
446 RcvToken = (SOCK_IO_TOKEN *) SockToken->Token;\r
447 TokenRcvdBytes = SockProcessRcvToken (Sock, RcvToken);\r
448\r
449 if (0 == TokenRcvdBytes) {\r
450 return ;\r
451 }\r
452\r
e48e37fc 453 RemoveEntryList (&(SockToken->TokenList));\r
454 gBS->FreePool (SockToken);\r
8a67d61d 455 RcvdBytes -= TokenRcvdBytes;\r
456 }\r
457}\r
458\r
459\r
460/**\r
461 Process the send token.\r
462\r
463 @param Sock Pointer to the socket.\r
464\r
465 @return None.\r
466\r
467**/\r
8a67d61d 468VOID\r
469SockProcessSndToken (\r
470 IN SOCKET *Sock\r
471 )\r
472{\r
473 UINT32 FreeSpace;\r
474 SOCK_TOKEN *SockToken;\r
475 UINT32 DataLen;\r
476 SOCK_IO_TOKEN *SndToken;\r
477 EFI_TCP4_TRANSMIT_DATA *TxData;\r
478 EFI_STATUS Status;\r
479\r
480 ASSERT (Sock && (SOCK_STREAM == Sock->Type));\r
481\r
482 FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);\r
483\r
484 //\r
485 // to determine if process a send token using\r
486 // socket layer flow control policy\r
487 //\r
488 while ((FreeSpace >= Sock->SndBuffer.LowWater) &&\r
e48e37fc 489 !IsListEmpty (&Sock->SndTokenList)) {\r
8a67d61d 490\r
491 SockToken = NET_LIST_HEAD (\r
492 &(Sock->SndTokenList),\r
493 SOCK_TOKEN,\r
494 TokenList\r
495 );\r
496\r
497 //\r
498 // process this token\r
499 //\r
e48e37fc 500 RemoveEntryList (&(SockToken->TokenList));\r
501 InsertTailList (\r
8a67d61d 502 &(Sock->ProcessingSndTokenList),\r
503 &(SockToken->TokenList)\r
504 );\r
505\r
506 //\r
507 // Proceess it in the light of SockType\r
508 //\r
509 SndToken = (SOCK_IO_TOKEN *) SockToken->Token;\r
510 TxData = SndToken->Packet.TxData;\r
511\r
4eb65aff 512 DataLen = (UINT32) TxData->DataLength;\r
8a67d61d 513 Status = SockProcessTcpSndData (Sock, TxData);\r
514\r
515 if (EFI_ERROR (Status)) {\r
516 goto OnError;\r
517 }\r
518\r
519 if (DataLen >= FreeSpace) {\r
520 FreeSpace = 0;\r
521\r
522 } else {\r
523 FreeSpace -= DataLen;\r
524\r
525 }\r
526 }\r
527\r
528 return ;\r
529\r
530OnError:\r
531\r
e48e37fc 532 RemoveEntryList (&SockToken->TokenList);\r
8a67d61d 533 SIGNAL_TOKEN (SockToken->Token, Status);\r
e48e37fc 534 gBS->FreePool (SockToken);\r
8a67d61d 535}\r
536\r
537\r
538/**\r
539 Create a socket with initial data SockInitData.\r
540\r
541 @param SockInitData Pointer to the initial data of the socket.\r
542\r
543 @return Pointer to the newly created socket.\r
544\r
545**/\r
546SOCKET *\r
547SockCreate (\r
548 IN SOCK_INIT_DATA *SockInitData\r
549 )\r
550{\r
551 SOCKET *Sock;\r
552 SOCKET *Parent;\r
553 EFI_STATUS Status;\r
554\r
555 ASSERT (SockInitData && SockInitData->ProtoHandler);\r
556 ASSERT (SockInitData->Type == SOCK_STREAM);\r
4f6e31e4 557 ASSERT (SockInitData->ProtoData && (SockInitData->DataSize <= PROTO_RESERVED_LEN));\r
8a67d61d 558\r
559 Parent = SockInitData->Parent;\r
560\r
561 if (Parent && (Parent->ConnCnt == Parent->BackLog)) {\r
e48e37fc 562 DEBUG (\r
563 (EFI_D_ERROR,\r
564 "SockCreate: Socket parent has "\r
8a67d61d 565 "reached its connection limit with %d ConnCnt and %d BackLog\n",\r
566 Parent->ConnCnt,\r
567 Parent->BackLog)\r
568 );\r
569\r
570 return NULL;\r
571 }\r
572\r
e48e37fc 573 Sock = AllocateZeroPool (sizeof (SOCKET));\r
8a67d61d 574 if (NULL == Sock) {\r
575\r
e48e37fc 576 DEBUG ((EFI_D_ERROR, "SockCreate: No resource to create a new socket\n"));\r
8a67d61d 577 return NULL;\r
578 }\r
579\r
e48e37fc 580 InitializeListHead (&Sock->Link);\r
581 InitializeListHead (&Sock->ConnectionList);\r
582 InitializeListHead (&Sock->ListenTokenList);\r
583 InitializeListHead (&Sock->RcvTokenList);\r
584 InitializeListHead (&Sock->SndTokenList);\r
585 InitializeListHead (&Sock->ProcessingSndTokenList);\r
8a67d61d 586\r
e48e37fc 587 EfiInitializeLock (&(Sock->Lock), TPL_CALLBACK);\r
8a67d61d 588\r
589 Sock->SndBuffer.DataQueue = NetbufQueAlloc ();\r
590 if (NULL == Sock->SndBuffer.DataQueue) {\r
e48e37fc 591 DEBUG ((EFI_D_ERROR, "SockCreate: No resource to allocate"\r
8a67d61d 592 " SndBuffer for new socket\n"));\r
593\r
594 goto OnError;\r
595 }\r
596\r
597 Sock->RcvBuffer.DataQueue = NetbufQueAlloc ();\r
598 if (NULL == Sock->RcvBuffer.DataQueue) {\r
e48e37fc 599 DEBUG ((EFI_D_ERROR, "SockCreate: No resource to allocate "\r
8a67d61d 600 "RcvBuffer for new socket\n"));\r
601\r
602 goto OnError;\r
603 }\r
604\r
605 Sock->Signature = SOCK_SIGNATURE;\r
606\r
607 Sock->Parent = Parent;\r
608 Sock->BackLog = SockInitData->BackLog;\r
609 Sock->ProtoHandler = SockInitData->ProtoHandler;\r
610 Sock->SndBuffer.HighWater = SockInitData->SndBufferSize;\r
611 Sock->RcvBuffer.HighWater = SockInitData->RcvBufferSize;\r
612 Sock->Type = SockInitData->Type;\r
613 Sock->DriverBinding = SockInitData->DriverBinding;\r
614 Sock->State = SockInitData->State;\r
4f6e31e4 615 Sock->CreateCallback = SockInitData->CreateCallback;\r
616 Sock->DestroyCallback = SockInitData->DestroyCallback;\r
617 Sock->Context = SockInitData->Context;\r
8a67d61d 618\r
619 Sock->SockError = EFI_ABORTED;\r
620 Sock->SndBuffer.LowWater = SOCK_BUFF_LOW_WATER;\r
621 Sock->RcvBuffer.LowWater = SOCK_BUFF_LOW_WATER;\r
622\r
623 //\r
624 // Install protocol on Sock->SockHandle\r
625 //\r
e48e37fc 626 CopyMem (\r
8a67d61d 627 &(Sock->NetProtocol.TcpProtocol),\r
628 SockInitData->Protocol,\r
629 sizeof (EFI_TCP4_PROTOCOL)\r
630 );\r
631\r
4f6e31e4 632 //\r
633 // copy the protodata into socket\r
634 //\r
e48e37fc 635 CopyMem (Sock->ProtoReserved, SockInitData->ProtoData, SockInitData->DataSize);\r
4f6e31e4 636\r
8a67d61d 637 Status = gBS->InstallMultipleProtocolInterfaces (\r
638 &Sock->SockHandle,\r
639 &gEfiTcp4ProtocolGuid,\r
640 &(Sock->NetProtocol.TcpProtocol),\r
641 NULL\r
642 );\r
643\r
644 if (EFI_ERROR (Status)) {\r
e48e37fc 645 DEBUG ((EFI_D_ERROR, "SockCreate: Install TCP protocol in "\r
8a67d61d 646 "socket failed with %r\n", Status));\r
647\r
648 goto OnError;\r
649 }\r
650\r
651 if (Parent != NULL) {\r
652 ASSERT (Parent->BackLog > 0);\r
653 ASSERT (SOCK_IS_LISTENING (Parent));\r
654\r
655 //\r
656 // need to add it into Parent->ConnectionList\r
657 // if the Parent->ConnCnt < Parent->BackLog\r
658 //\r
659 Parent->ConnCnt++;\r
660\r
e48e37fc 661 DEBUG (\r
662 (EFI_D_WARN,\r
663 "SockCreate: Create a new socket and add to parent, now conncnt is %d\n",\r
664 Parent->ConnCnt)\r
665 );\r
8a67d61d 666\r
e48e37fc 667 InsertTailList (&Parent->ConnectionList, &Sock->ConnectionList);\r
8a67d61d 668 }\r
669\r
4f6e31e4 670 if (Sock->CreateCallback != NULL) {\r
671 Status = Sock->CreateCallback (Sock, Sock->Context);\r
672 if (EFI_ERROR (Status)) {\r
673 goto OnError;\r
674 }\r
675 }\r
676\r
8a67d61d 677 return Sock;\r
678\r
679OnError:\r
8a67d61d 680\r
4f6e31e4 681 if (Sock->SockHandle != NULL) {\r
682 gBS->UninstallMultipleProtocolInterfaces (\r
683 Sock->SockHandle,\r
684 &gEfiTcp4ProtocolGuid,\r
685 &(Sock->NetProtocol.TcpProtocol),\r
686 NULL\r
687 );\r
688 }\r
8a67d61d 689\r
4f6e31e4 690 if (NULL != Sock->SndBuffer.DataQueue) {\r
691 NetbufQueFree (Sock->SndBuffer.DataQueue);\r
692 }\r
8a67d61d 693\r
4f6e31e4 694 if (NULL != Sock->RcvBuffer.DataQueue) {\r
695 NetbufQueFree (Sock->RcvBuffer.DataQueue);\r
8a67d61d 696 }\r
697\r
e48e37fc 698 gBS->FreePool (Sock);\r
4f6e31e4 699\r
8a67d61d 700 return NULL;\r
701}\r
702\r
703\r
704/**\r
705 Destroy a socket.\r
706\r
707 @param Sock Pointer to the socket.\r
708\r
709 @return None.\r
710\r
711**/\r
712VOID\r
713SockDestroy (\r
714 IN SOCKET *Sock\r
715 )\r
716{\r
717 VOID *SockProtocol;\r
718 EFI_GUID *ProtocolGuid;\r
719 EFI_STATUS Status;\r
720\r
721 ASSERT (SOCK_STREAM == Sock->Type);\r
722\r
4f6e31e4 723 if (Sock->DestroyCallback != NULL) {\r
724 Sock->DestroyCallback (Sock, Sock->Context);\r
725 }\r
726\r
8a67d61d 727 //\r
728 // Flush the completion token buffered\r
729 // by sock and rcv, snd buffer\r
730 //\r
731 if (!SOCK_IS_UNCONFIGURED (Sock)) {\r
732\r
733 SockConnFlush (Sock);\r
734 SockSetState (Sock, SO_CLOSED);\r
735 Sock->ConfigureState = SO_UNCONFIGURED;\r
736\r
737 }\r
738 //\r
739 // Destory the RcvBuffer Queue and SendBuffer Queue\r
740 //\r
741 NetbufQueFree (Sock->RcvBuffer.DataQueue);\r
742 NetbufQueFree (Sock->SndBuffer.DataQueue);\r
743\r
744 //\r
745 // Remove it from parent connection list if needed\r
746 //\r
747 if (Sock->Parent) {\r
748\r
e48e37fc 749 RemoveEntryList (&(Sock->ConnectionList));\r
8a67d61d 750 (Sock->Parent->ConnCnt)--;\r
751\r
e48e37fc 752 DEBUG (\r
753 (EFI_D_WARN,\r
754 "SockDestory: Delete a unaccepted socket from parent"\r
755 "now conncnt is %d\n",\r
756 Sock->Parent->ConnCnt)\r
757 );\r
8a67d61d 758\r
759 Sock->Parent = NULL;\r
760 }\r
761\r
762 //\r
763 // Set the protocol guid and driver binding handle\r
764 // in the light of Sock->SockType\r
765 //\r
766 ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
767\r
768 //\r
769 // Retrieve the protocol installed on this sock\r
770 //\r
771 Status = gBS->OpenProtocol (\r
772 Sock->SockHandle,\r
773 ProtocolGuid,\r
774 &SockProtocol,\r
775 Sock->DriverBinding,\r
776 Sock->SockHandle,\r
777 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
778 );\r
779\r
780 if (EFI_ERROR (Status)) {\r
781\r
e48e37fc 782 DEBUG ((EFI_D_ERROR, "SockDestroy: Open protocol installed "\r
8a67d61d 783 "on socket failed with %r\n", Status));\r
784\r
785 goto FreeSock;\r
786 }\r
787\r
788 //\r
789 // Uninstall the protocol installed on this sock\r
790 // in the light of Sock->SockType\r
791 //\r
792 gBS->UninstallMultipleProtocolInterfaces (\r
793 Sock->SockHandle,\r
794 ProtocolGuid,\r
795 SockProtocol,\r
796 NULL\r
797 );\r
798\r
799FreeSock:\r
e48e37fc 800 gBS->FreePool (Sock);\r
8a67d61d 801 return ;\r
802}\r
803\r
804\r
805/**\r
806 Flush the socket.\r
807\r
808 @param Sock Pointer to the socket.\r
809\r
810 @return None.\r
811\r
812**/\r
813VOID\r
814SockConnFlush (\r
815 IN SOCKET *Sock\r
816 )\r
817{\r
818 SOCKET *Child;\r
819\r
820 ASSERT (Sock);\r
821\r
822 //\r
823 // Clear the flag in this socket\r
824 //\r
825 Sock->Flag = 0;\r
826\r
827 //\r
828 // Flush the SndBuffer and RcvBuffer of Sock\r
829 //\r
830 NetbufQueFlush (Sock->SndBuffer.DataQueue);\r
831 NetbufQueFlush (Sock->RcvBuffer.DataQueue);\r
832\r
833 //\r
834 // Signal the pending token\r
835 //\r
836 if (Sock->ConnectionToken != NULL) {\r
837 SIGNAL_TOKEN (Sock->ConnectionToken, Sock->SockError);\r
838 Sock->ConnectionToken = NULL;\r
839 }\r
840\r
841 if (Sock->CloseToken != NULL) {\r
842 SIGNAL_TOKEN (Sock->CloseToken, Sock->SockError);\r
843 Sock->CloseToken = NULL;\r
844 }\r
845\r
846 SockFlushPendingToken (Sock, &(Sock->ListenTokenList));\r
847 SockFlushPendingToken (Sock, &(Sock->RcvTokenList));\r
848 SockFlushPendingToken (Sock, &(Sock->SndTokenList));\r
849 SockFlushPendingToken (Sock, &(Sock->ProcessingSndTokenList));\r
850\r
851 //\r
852 // Destroy the pending connection, if it is a listening socket\r
853 //\r
854 if (SOCK_IS_LISTENING (Sock)) {\r
e48e37fc 855 while (!IsListEmpty (&Sock->ConnectionList)) {\r
8a67d61d 856 Child = NET_LIST_HEAD (\r
857 &Sock->ConnectionList,\r
858 SOCKET,\r
859 ConnectionList\r
860 );\r
861\r
862 SockDestroyChild (Child);\r
863 }\r
864\r
865 Sock->ConnCnt = 0;\r
866 }\r
867\r
868 return ;\r
869}\r
870\r
871\r
872/**\r
873 Set the state of the socket.\r
874\r
875 @param Sock Pointer to the socket.\r
876 @param State The new state to be set.\r
877\r
878 @return None.\r
879\r
880**/\r
881VOID\r
882SockSetState (\r
883 IN SOCKET *Sock,\r
884 IN SOCK_STATE State\r
885 )\r
886{\r
887 Sock->State = State;\r
888}\r
889\r
890\r
891/**\r
892 Clone a new socket including its associated protocol control block.\r
893\r
894 @param Sock Pointer to the socket to be cloned.\r
895\r
896 @retval * Pointer to the newly cloned socket. If NULL, error\r
897 condition occurred.\r
898\r
899**/\r
900SOCKET *\r
901SockClone (\r
902 IN SOCKET *Sock\r
903 )\r
904{\r
905 SOCKET *ClonedSock;\r
906 SOCK_INIT_DATA InitData;\r
907\r
908 InitData.BackLog = Sock->BackLog;\r
909 InitData.Parent = Sock;\r
910 InitData.State = Sock->State;\r
911 InitData.ProtoHandler = Sock->ProtoHandler;\r
912 InitData.Type = Sock->Type;\r
913 InitData.RcvBufferSize = Sock->RcvBuffer.HighWater;\r
914 InitData.SndBufferSize = Sock->SndBuffer.HighWater;\r
915 InitData.DriverBinding = Sock->DriverBinding;\r
916 InitData.Protocol = &(Sock->NetProtocol);\r
4f6e31e4 917 InitData.CreateCallback = Sock->CreateCallback;\r
918 InitData.DestroyCallback = Sock->DestroyCallback;\r
919 InitData.Context = Sock->Context;\r
920 InitData.ProtoData = Sock->ProtoReserved;\r
921 InitData.DataSize = sizeof (Sock->ProtoReserved);\r
8a67d61d 922\r
923 ClonedSock = SockCreate (&InitData);\r
924\r
925 if (NULL == ClonedSock) {\r
e48e37fc 926 DEBUG ((EFI_D_ERROR, "SockClone: no resource to create a cloned sock\n"));\r
8a67d61d 927 return NULL;\r
928 }\r
929\r
8a67d61d 930 SockSetState (ClonedSock, SO_CONNECTING);\r
931 ClonedSock->ConfigureState = Sock->ConfigureState;\r
932\r
933 return ClonedSock;\r
934}\r
935\r
936\r
937/**\r
938 Called by the low layer protocol to indicate the socket\r
939 a connection is established. This function just changes\r
940 the socket's state to SO_CONNECTED and signals the token\r
941 used for connection establishment.\r
942\r
943 @param Sock Pointer to the socket associated with the\r
944 established connection.\r
945\r
946 @return None.\r
947\r
948**/\r
949VOID\r
950SockConnEstablished (\r
951 IN SOCKET *Sock\r
952 )\r
953{\r
954\r
955 ASSERT (SO_CONNECTING == Sock->State);\r
956\r
957 SockSetState (Sock, SO_CONNECTED);\r
958\r
959 if (NULL == Sock->Parent) {\r
960 SockWakeConnToken (Sock);\r
961 } else {\r
962 SockWakeListenToken (Sock);\r
963 }\r
964\r
965 return ;\r
966}\r
967\r
968\r
969/**\r
970 Called by the low layer protocol to indicate the connection\r
971 is closed. This function flushes the socket, sets the state\r
972 to SO_CLOSED and signals the close token.\r
973\r
974 @param Sock Pointer to the socket associated with the closed\r
975 connection.\r
976\r
977 @return None.\r
978\r
979**/\r
980VOID\r
981SockConnClosed (\r
982 IN SOCKET *Sock\r
983 )\r
984{\r
985 if (Sock->CloseToken) {\r
986 SIGNAL_TOKEN (Sock->CloseToken, EFI_SUCCESS);\r
987 Sock->CloseToken = NULL;\r
988 }\r
989\r
990 SockConnFlush (Sock);\r
991 SockSetState (Sock, SO_CLOSED);\r
992\r
993 if (Sock->Parent != NULL) {\r
994 SockDestroyChild (Sock);\r
995 }\r
996\r
997}\r
998\r
999\r
1000/**\r
1001 Called by low layer protocol to indicate that some\r
1002 data is sent or processed. This function trims the\r
1003 sent data in the socket send buffer, signals the\r
1004 data token if proper\r
1005\r
1006 @param Sock Pointer to the socket.\r
1007 @param Count The length of the data processed or sent, in bytes.\r
1008\r
1009 @return None.\r
1010\r
1011**/\r
1012VOID\r
1013SockDataSent (\r
1014 IN SOCKET *Sock,\r
1015 IN UINT32 Count\r
1016 )\r
1017{\r
1018 SOCK_TOKEN *SockToken;\r
1019 SOCK_COMPLETION_TOKEN *SndToken;\r
1020\r
e48e37fc 1021 ASSERT (!IsListEmpty (&Sock->ProcessingSndTokenList));\r
8a67d61d 1022 ASSERT (Count <= (Sock->SndBuffer.DataQueue)->BufSize);\r
1023\r
1024 NetbufQueTrim (Sock->SndBuffer.DataQueue, Count);\r
1025\r
1026 //\r
1027 // To check if we can signal some snd token in this socket\r
1028 //\r
1029 while (Count > 0) {\r
1030 SockToken = NET_LIST_HEAD (\r
1031 &(Sock->ProcessingSndTokenList),\r
1032 SOCK_TOKEN,\r
1033 TokenList\r
1034 );\r
1035\r
1036 SndToken = SockToken->Token;\r
1037\r
1038 if (SockToken->RemainDataLen <= Count) {\r
1039\r
e48e37fc 1040 RemoveEntryList (&(SockToken->TokenList));\r
8a67d61d 1041 SIGNAL_TOKEN (SndToken, EFI_SUCCESS);\r
1042 Count -= SockToken->RemainDataLen;\r
e48e37fc 1043 gBS->FreePool (SockToken);\r
8a67d61d 1044 } else {\r
1045\r
1046 SockToken->RemainDataLen -= Count;\r
1047 Count = 0;\r
1048 }\r
1049 }\r
1050\r
1051 //\r
1052 // to judge if we can process some send token in\r
1053 // Sock->SndTokenList, if so process those send token\r
1054 //\r
1055 SockProcessSndToken (Sock);\r
1056 return ;\r
1057}\r
1058\r
1059\r
1060/**\r
1061 Called by the low layer protocol to copy some data in socket send\r
1062 buffer starting from the specific offset to a buffer provided by\r
1063 the caller.\r
1064\r
1065 @param Sock Pointer to the socket.\r
1066 @param Offset The start point of the data to be copied.\r
1067 @param Len The length of the data to be copied.\r
1068 @param Dest Pointer to the destination to copy the data.\r
1069\r
1070 @return The data size copied.\r
1071\r
1072**/\r
1073UINT32\r
1074SockGetDataToSend (\r
1075 IN SOCKET *Sock,\r
1076 IN UINT32 Offset,\r
1077 IN UINT32 Len,\r
1078 IN UINT8 *Dest\r
1079 )\r
1080{\r
1081 ASSERT (Sock && SOCK_STREAM == Sock->Type);\r
1082\r
1083 return NetbufQueCopy (\r
1084 Sock->SndBuffer.DataQueue,\r
1085 Offset,\r
1086 Len,\r
1087 Dest\r
1088 );\r
1089}\r
1090\r
1091\r
1092/**\r
1093 Called by the low layer protocol to deliver received data\r
1094 to socket layer. This function will append the data to the\r
1095 socket receive buffer, set ther urgent data length and then\r
1096 check if any receive token can be signaled.\r
1097\r
1098 @param Sock Pointer to the socket.\r
1099 @param NetBuffer Pointer to the buffer that contains the received\r
1100 data.\r
1101 @param UrgLen The length of the urgent data in the received data.\r
1102\r
1103 @return None.\r
1104\r
1105**/\r
1106VOID\r
1107SockDataRcvd (\r
1108 IN SOCKET *Sock,\r
1109 IN NET_BUF *NetBuffer,\r
1110 IN UINT32 UrgLen\r
1111 )\r
1112{\r
1113 ASSERT (Sock && Sock->RcvBuffer.DataQueue &&\r
1114 UrgLen <= NetBuffer->TotalSize);\r
1115\r
1116 NET_GET_REF (NetBuffer);\r
1117\r
1118 ((TCP_RSV_DATA *) (NetBuffer->ProtoData))->UrgLen = UrgLen;\r
1119\r
1120 NetbufQueAppend (Sock->RcvBuffer.DataQueue, NetBuffer);\r
1121\r
1122 SockWakeRcvToken (Sock);\r
1123 return ;\r
1124}\r
1125\r
1126\r
1127/**\r
1128 Get the length of the free space of the specific socket buffer.\r
1129\r
1130 @param Sock Pointer to the socket.\r
1131 @param Which Flag to indicate which socket buffer to check,\r
1132 either send buffer or receive buffer.\r
1133\r
1134 @return The length of the free space, in bytes.\r
1135\r
1136**/\r
1137UINT32\r
1138SockGetFreeSpace (\r
1139 IN SOCKET *Sock,\r
1140 IN UINT32 Which\r
1141 )\r
1142{\r
1143 UINT32 BufferCC;\r
1144 SOCK_BUFFER *SockBuffer;\r
1145\r
1146 ASSERT (Sock && ((SOCK_SND_BUF == Which) || (SOCK_RCV_BUF == Which)));\r
1147\r
1148 if (SOCK_SND_BUF == Which) {\r
1149 SockBuffer = &(Sock->SndBuffer);\r
1150 } else {\r
1151 SockBuffer = &(Sock->RcvBuffer);\r
1152 }\r
1153\r
1154 BufferCC = (SockBuffer->DataQueue)->BufSize;\r
1155\r
1156 if (BufferCC >= SockBuffer->HighWater) {\r
1157\r
1158 return 0;\r
1159 }\r
1160\r
1161 return SockBuffer->HighWater - BufferCC;\r
1162}\r
1163\r
1164\r
1165/**\r
1166 Signal the receive token with the specific error or\r
1167 set socket error code after error is received.\r
1168\r
1169 @param Sock Pointer to the socket.\r
1170 @param Error The error code received.\r
1171\r
1172 @return None.\r
1173\r
1174**/\r
1175VOID\r
1176SockRcvdErr (\r
1177 IN SOCKET *Sock,\r
1178 IN EFI_STATUS Error\r
1179 )\r
1180{\r
1181 SOCK_TOKEN *SockToken;\r
1182\r
e48e37fc 1183 if (!IsListEmpty (&Sock->RcvTokenList)) {\r
8a67d61d 1184\r
1185 SockToken = NET_LIST_HEAD (\r
1186 &Sock->RcvTokenList,\r
1187 SOCK_TOKEN,\r
1188 TokenList\r
1189 );\r
1190\r
e48e37fc 1191 RemoveEntryList (&SockToken->TokenList);\r
8a67d61d 1192\r
1193 SIGNAL_TOKEN (SockToken->Token, Error);\r
1194\r
e48e37fc 1195 gBS->FreePool (SockToken);\r
8a67d61d 1196 } else {\r
1197\r
1198 SOCK_ERROR (Sock, Error);\r
1199 }\r
1200}\r
1201\r
1202\r
1203/**\r
1204 Called by the low layer protocol to indicate that there\r
1205 will be no more data from the communication peer. This\r
1206 function set the socket's state to SO_NO_MORE_DATA and\r
1207 signal all queued IO tokens with the error status\r
1208 EFI_CONNECTION_FIN.\r
1209\r
1210 @param Sock Pointer to the socket.\r
1211\r
1212 @return None.\r
1213\r
1214**/\r
1215VOID\r
1216SockNoMoreData (\r
1217 IN SOCKET *Sock\r
1218 )\r
1219{\r
1220 EFI_STATUS Err;\r
1221\r
1222 SOCK_NO_MORE_DATA (Sock);\r
1223\r
e48e37fc 1224 if (!IsListEmpty (&Sock->RcvTokenList)) {\r
8a67d61d 1225\r
1226 ASSERT (0 == GET_RCV_DATASIZE (Sock));\r
1227\r
1228 Err = Sock->SockError;\r
1229\r
1230 SOCK_ERROR (Sock, EFI_CONNECTION_FIN);\r
1231\r
1232 SockFlushPendingToken (Sock, &Sock->RcvTokenList);\r
1233\r
1234 SOCK_ERROR (Sock, Err);\r
1235\r
1236 }\r
1237\r
1238}\r
1239\r
1240\r
1241/**\r
1242 Get the first buffer block in the specific socket buffer.\r
1243\r
1244 @param Sockbuf Pointer to the socket buffer.\r
1245\r
1246 @return Pointer to the first buffer in the queue. NULL if the queue is empty.\r
1247\r
1248**/\r
1249NET_BUF *\r
1250SockBufFirst (\r
1251 IN SOCK_BUFFER *Sockbuf\r
1252 )\r
1253{\r
e48e37fc 1254 LIST_ENTRY *NetbufList;\r
8a67d61d 1255\r
1256 NetbufList = &(Sockbuf->DataQueue->BufList);\r
1257\r
e48e37fc 1258 if (IsListEmpty (NetbufList)) {\r
8a67d61d 1259 return NULL;\r
1260 }\r
1261\r
1262 return NET_LIST_HEAD (NetbufList, NET_BUF, List);\r
1263}\r
1264\r
1265\r
1266/**\r
1267 Get the next buffer block in the specific socket buffer.\r
1268\r
1269 @param Sockbuf Pointer to the socket buffer.\r
1270 @param SockEntry Pointer to the buffer block prior to the required\r
1271 one.\r
1272\r
1273 @return Pointer to the buffer block next to SockEntry. NULL if SockEntry is the tail or head entry.\r
1274\r
1275**/\r
1276NET_BUF *\r
1277SockBufNext (\r
1278 IN SOCK_BUFFER *Sockbuf,\r
1279 IN NET_BUF *SockEntry\r
1280 )\r
1281{\r
e48e37fc 1282 LIST_ENTRY *NetbufList;\r
8a67d61d 1283\r
1284 NetbufList = &(Sockbuf->DataQueue->BufList);\r
1285\r
1286 if ((SockEntry->List.ForwardLink == NetbufList) ||\r
1287 (SockEntry->List.BackLink == &SockEntry->List) ||\r
1288 (SockEntry->List.ForwardLink == &SockEntry->List)\r
1289 ) {\r
1290\r
1291 return NULL;\r
1292 }\r
1293\r
1294 return NET_LIST_USER_STRUCT (SockEntry->List.ForwardLink, NET_BUF, List);\r
1295}\r