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