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