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