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