]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/TcpDxe/SockInterface.c
NetworkPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / NetworkPkg / TcpDxe / SockInterface.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 Interface function of the Socket.\r
3\r
f75a7f56 4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
a3bcde70 5\r
ecf98fbc 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a3bcde70
HT
7\r
8**/\r
9\r
10#include "SockImpl.h"\r
11\r
12/**\r
13 Check whether the Event is in the List.\r
14\r
15 @param[in] List Pointer to the token list to be searched.\r
16 @param[in] Event The event to be checked.\r
17\r
18 @retval TRUE The specific Event exists in the List.\r
19 @retval FALSE The specific Event is not in the List.\r
20\r
21**/\r
22BOOLEAN\r
23SockTokenExistedInList (\r
24 IN LIST_ENTRY *List,\r
25 IN EFI_EVENT Event\r
26 )\r
27{\r
28 LIST_ENTRY *ListEntry;\r
29 SOCK_TOKEN *SockToken;\r
30\r
31 NET_LIST_FOR_EACH (ListEntry, List) {\r
32 SockToken = NET_LIST_USER_STRUCT (\r
33 ListEntry,\r
34 SOCK_TOKEN,\r
35 TokenList\r
36 );\r
37\r
38 if (Event == SockToken->Token->Event) {\r
39 return TRUE;\r
40 }\r
41 }\r
42\r
43 return FALSE;\r
44}\r
45\r
46/**\r
47 Call SockTokenExistedInList() to check whether the Event is\r
48 in the related socket's lists.\r
49\r
50 @param[in] Sock Pointer to the instance's socket.\r
51 @param[in] Event The event to be checked.\r
52\r
53 @retval TRUE The Event exists in related socket's lists.\r
54 @retval FALSE The Event is not in related socket's lists.\r
55\r
56**/\r
57BOOLEAN\r
58SockTokenExisted (\r
59 IN SOCKET *Sock,\r
60 IN EFI_EVENT Event\r
61 )\r
62{\r
63\r
64 if (SockTokenExistedInList (&Sock->SndTokenList, Event) ||\r
65 SockTokenExistedInList (&Sock->ProcessingSndTokenList, Event) ||\r
66 SockTokenExistedInList (&Sock->RcvTokenList, Event) ||\r
67 SockTokenExistedInList (&Sock->ListenTokenList, Event)\r
68 ) {\r
69\r
70 return TRUE;\r
71 }\r
72\r
73 if ((Sock->ConnectionToken != NULL) && (Sock->ConnectionToken->Event == Event)) {\r
74\r
75 return TRUE;\r
76 }\r
77\r
78 if ((Sock->CloseToken != NULL) && (Sock->CloseToken->Event == Event)) {\r
79 return TRUE;\r
80 }\r
81\r
82 return FALSE;\r
83}\r
84\r
85/**\r
86 Buffer a token into the specific list of the socket Sock.\r
87\r
88 @param[in] Sock Pointer to the instance's socket.\r
89 @param[in] List Pointer to the list to store the token.\r
90 @param[in] Token Pointer to the token to be buffered.\r
91 @param[in] DataLen The data length of the buffer contained in Token.\r
92\r
93 @return Pointer to the token that wraps Token. If NULL, an error condition occurred.\r
94\r
95**/\r
96SOCK_TOKEN *\r
97SockBufferToken (\r
98 IN SOCKET *Sock,\r
99 IN LIST_ENTRY *List,\r
100 IN VOID *Token,\r
101 IN UINT32 DataLen\r
102 )\r
103{\r
104 SOCK_TOKEN *SockToken;\r
105\r
106 SockToken = AllocateZeroPool (sizeof (SOCK_TOKEN));\r
107 if (NULL == SockToken) {\r
108\r
109 DEBUG (\r
110 (EFI_D_ERROR,\r
111 "SockBufferIOToken: No Memory to allocate SockToken\n")\r
112 );\r
113\r
114 return NULL;\r
115 }\r
116\r
117 SockToken->Sock = Sock;\r
118 SockToken->Token = (SOCK_COMPLETION_TOKEN *) Token;\r
119 SockToken->RemainDataLen = DataLen;\r
120 InsertTailList (List, &SockToken->TokenList);\r
121\r
122 return SockToken;\r
123}\r
124\r
125/**\r
75dce340 126 Destroy the socket Sock and its associated protocol control block.\r
a3bcde70
HT
127\r
128 @param[in, out] Sock The socket to be destroyed.\r
129\r
130 @retval EFI_SUCCESS The socket Sock was destroyed successfully.\r
131 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r
132\r
133**/\r
134EFI_STATUS\r
135SockDestroyChild (\r
136 IN OUT SOCKET *Sock\r
137 )\r
138{\r
d555699b
ZL
139 EFI_STATUS Status;\r
140 TCP_PROTO_DATA *ProtoData;\r
141 TCP_CB *Tcb;\r
142 EFI_GUID *IpProtocolGuid;\r
143 EFI_GUID *TcpProtocolGuid;\r
144 VOID *SockProtocol;\r
a3bcde70
HT
145\r
146 ASSERT ((Sock != NULL) && (Sock->ProtoHandler != NULL));\r
147\r
216f7970 148 if (Sock->InDestroy) {\r
a3bcde70
HT
149 return EFI_SUCCESS;\r
150 }\r
151\r
216f7970 152 Sock->InDestroy = TRUE;\r
a3bcde70 153\r
d555699b
ZL
154 if (Sock->IpVersion == IP_VERSION_4) {\r
155 IpProtocolGuid = &gEfiIp4ProtocolGuid;\r
156 TcpProtocolGuid = &gEfiTcp4ProtocolGuid;\r
157 } else {\r
158 IpProtocolGuid = &gEfiIp6ProtocolGuid;\r
159 TcpProtocolGuid = &gEfiTcp6ProtocolGuid;\r
160 }\r
161 ProtoData = (TCP_PROTO_DATA *) Sock->ProtoReserved;\r
162 Tcb = ProtoData->TcpPcb;\r
163\r
164 ASSERT (Tcb != NULL);\r
165\r
d555699b
ZL
166 //\r
167 // Close the IP protocol.\r
168 //\r
169 gBS->CloseProtocol (\r
170 Tcb->IpInfo->ChildHandle,\r
171 IpProtocolGuid,\r
172 ProtoData->TcpService->IpIo->Image,\r
173 Sock->SockHandle\r
174 );\r
175\r
176 if (Sock->DestroyCallback != NULL) {\r
177 Sock->DestroyCallback (Sock, Sock->Context);\r
178 }\r
179\r
180 //\r
181 // Retrieve the protocol installed on this sock\r
182 //\r
183 Status = gBS->OpenProtocol (\r
184 Sock->SockHandle,\r
185 TcpProtocolGuid,\r
186 &SockProtocol,\r
187 Sock->DriverBinding,\r
188 Sock->SockHandle,\r
189 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
190 );\r
191\r
192 if (EFI_ERROR (Status)) {\r
193\r
194 DEBUG (\r
195 (EFI_D_ERROR,\r
196 "SockDestroyChild: Open protocol installed on socket failed with %r\n",\r
197 Status)\r
198 );\r
199 }\r
200\r
201 //\r
202 // Uninstall the protocol installed on this sock\r
203 //\r
204 gBS->UninstallMultipleProtocolInterfaces (\r
205 Sock->SockHandle,\r
206 TcpProtocolGuid,\r
207 SockProtocol,\r
208 NULL\r
209 );\r
210\r
597cf8a1
ZL
211\r
212 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
213 if (EFI_ERROR (Status)) {\r
214\r
215 DEBUG (\r
216 (EFI_D_ERROR,\r
217 "SockDestroyChild: Get the lock to access socket failed with %r\n",\r
218 Status)\r
219 );\r
220\r
221 return EFI_ACCESS_DENIED;\r
222 }\r
223\r
a3bcde70
HT
224 //\r
225 // force protocol layer to detach the PCB\r
226 //\r
227 Status = Sock->ProtoHandler (Sock, SOCK_DETACH, NULL);\r
228\r
229 if (EFI_ERROR (Status)) {\r
230\r
231 DEBUG (\r
232 (EFI_D_ERROR,\r
233 "SockDestroyChild: Protocol detach socket failed with %r\n",\r
234 Status)\r
235 );\r
236\r
216f7970 237 Sock->InDestroy = FALSE;\r
a3bcde70
HT
238 } else if (SOCK_IS_CONFIGURED (Sock)) {\r
239\r
240 SockConnFlush (Sock);\r
241 SockSetState (Sock, SO_CLOSED);\r
242\r
243 Sock->ConfigureState = SO_UNCONFIGURED;\r
244 }\r
245\r
246 EfiReleaseLock (&(Sock->Lock));\r
247\r
248 if (EFI_ERROR (Status)) {\r
249 return Status;\r
250 }\r
251\r
252 SockDestroy (Sock);\r
253 return EFI_SUCCESS;\r
254}\r
255\r
256/**\r
257 Create a socket and its associated protocol control block\r
258 with the intial data SockInitData and protocol specific\r
259 data ProtoData.\r
260\r
261 @param[in] SockInitData Inital data to setting the socket.\r
262\r
263 @return Pointer to the newly created socket. If NULL, an error condition occured.\r
264\r
265**/\r
266SOCKET *\r
267SockCreateChild (\r
268 IN SOCK_INIT_DATA *SockInitData\r
269 )\r
270{\r
271 SOCKET *Sock;\r
272 EFI_STATUS Status;\r
d555699b
ZL
273 VOID *SockProtocol;\r
274 EFI_GUID *TcpProtocolGuid;\r
a3bcde70
HT
275\r
276 //\r
277 // create a new socket\r
278 //\r
279 Sock = SockCreate (SockInitData);\r
280 if (NULL == Sock) {\r
281\r
282 DEBUG (\r
283 (EFI_D_ERROR,\r
284 "SockCreateChild: No resource to create a new socket\n")\r
285 );\r
286\r
287 return NULL;\r
288 }\r
289\r
290 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
291 if (EFI_ERROR (Status)) {\r
292\r
293 DEBUG (\r
294 (EFI_D_ERROR,\r
295 "SockCreateChild: Get the lock to access socket failed with %r\n",\r
296 Status)\r
297 );\r
d555699b 298 goto ERROR;\r
a3bcde70
HT
299 }\r
300 //\r
301 // inform the protocol layer to attach the socket\r
302 // with a new protocol control block\r
303 //\r
304 Status = Sock->ProtoHandler (Sock, SOCK_ATTACH, NULL);\r
80ae1cc7 305 EfiReleaseLock (&(Sock->Lock));\r
a3bcde70
HT
306 if (EFI_ERROR (Status)) {\r
307\r
308 DEBUG (\r
309 (EFI_D_ERROR,\r
310 "SockCreateChild: Protocol failed to attach a socket with %r\n",\r
311 Status)\r
312 );\r
d555699b 313 goto ERROR;\r
a3bcde70
HT
314 }\r
315\r
a3bcde70 316 return Sock;\r
d555699b
ZL
317\r
318ERROR:\r
319\r
320 if (Sock->DestroyCallback != NULL) {\r
321 Sock->DestroyCallback (Sock, Sock->Context);\r
322 }\r
323\r
324 if (Sock->IpVersion == IP_VERSION_4) {\r
325 TcpProtocolGuid = &gEfiTcp4ProtocolGuid;\r
326 } else {\r
327 TcpProtocolGuid = &gEfiTcp6ProtocolGuid;\r
328 }\r
329\r
330 gBS->OpenProtocol (\r
331 Sock->SockHandle,\r
332 TcpProtocolGuid,\r
333 &SockProtocol,\r
334 Sock->DriverBinding,\r
335 Sock->SockHandle,\r
336 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
337 );\r
338 //\r
339 // Uninstall the protocol installed on this sock\r
340 //\r
341 gBS->UninstallMultipleProtocolInterfaces (\r
342 Sock->SockHandle,\r
343 TcpProtocolGuid,\r
344 SockProtocol,\r
345 NULL\r
346 );\r
347 SockDestroy (Sock);\r
348 return NULL;\r
a3bcde70
HT
349}\r
350\r
351/**\r
352 Configure the specific socket Sock using configuration data ConfigData.\r
353\r
354 @param[in] Sock Pointer to the socket to be configured.\r
355 @param[in] ConfigData Pointer to the configuration data.\r
356\r
357 @retval EFI_SUCCESS The socket configured successfully.\r
358 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
359 socket is already configured.\r
360\r
361**/\r
362EFI_STATUS\r
363SockConfigure (\r
364 IN SOCKET *Sock,\r
365 IN VOID *ConfigData\r
366 )\r
367{\r
368 EFI_STATUS Status;\r
369\r
370 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
371 if (EFI_ERROR (Status)) {\r
372\r
373 DEBUG (\r
374 (EFI_D_ERROR,\r
375 "SockConfigure: Get the access for socket failed with %r",\r
376 Status)\r
377 );\r
378\r
379 return EFI_ACCESS_DENIED;\r
380 }\r
381\r
382 if (SOCK_IS_CONFIGURED (Sock)) {\r
383 Status = EFI_ACCESS_DENIED;\r
384 goto OnExit;\r
385 }\r
386\r
387 ASSERT (Sock->State == SO_CLOSED);\r
388\r
389 Status = Sock->ProtoHandler (Sock, SOCK_CONFIGURE, ConfigData);\r
390\r
391OnExit:\r
392 EfiReleaseLock (&(Sock->Lock));\r
393\r
394 return Status;\r
395}\r
396\r
397/**\r
398 Initiate a connection establishment process.\r
399\r
400 @param[in] Sock Pointer to the socket to initiate the initate the\r
401 connection.\r
402 @param[in] Token Pointer to the token used for the connection\r
403 operation.\r
404\r
405 @retval EFI_SUCCESS The connection initialized successfully.\r
406 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
407 socket is closed, or the socket is not configured to\r
408 be an active one, or the token is already in one of\r
409 this socket's lists.\r
410 @retval EFI_NO_MAPPING The IP address configuration operation is not\r
411 finished.\r
412 @retval EFI_NOT_STARTED The socket is not configured.\r
413\r
414**/\r
415EFI_STATUS\r
416SockConnect (\r
417 IN SOCKET *Sock,\r
418 IN VOID *Token\r
419 )\r
420{\r
421 EFI_STATUS Status;\r
422 EFI_EVENT Event;\r
423\r
424 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
425 if (EFI_ERROR (Status)) {\r
426\r
427 DEBUG (\r
428 (EFI_D_ERROR,\r
429 "SockConnect: Get the access for socket failed with %r",\r
430 Status)\r
431 );\r
432\r
433 return EFI_ACCESS_DENIED;\r
434 }\r
435\r
436 if (SOCK_IS_NO_MAPPING (Sock)) {\r
437 Status = EFI_NO_MAPPING;\r
438 goto OnExit;\r
439 }\r
440\r
441 if (SOCK_IS_UNCONFIGURED (Sock)) {\r
442\r
443 Status = EFI_NOT_STARTED;\r
444 goto OnExit;\r
445 }\r
446\r
447 if (!SOCK_IS_CLOSED (Sock) || !SOCK_IS_CONFIGURED_ACTIVE (Sock)) {\r
448\r
449 Status = EFI_ACCESS_DENIED;\r
450 goto OnExit;\r
451 }\r
452\r
453 Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r
454\r
455 if (SockTokenExisted (Sock, Event)) {\r
456\r
457 Status = EFI_ACCESS_DENIED;\r
458 goto OnExit;\r
459 }\r
460\r
461 Sock->ConnectionToken = (SOCK_COMPLETION_TOKEN *) Token;\r
462 SockSetState (Sock, SO_CONNECTING);\r
463 Status = Sock->ProtoHandler (Sock, SOCK_CONNECT, NULL);\r
464\r
465OnExit:\r
466 EfiReleaseLock (&(Sock->Lock));\r
467 return Status;\r
468}\r
469\r
470/**\r
471 Issue a listen token to get an existed connected network instance\r
472 or wait for a connection if there is none.\r
473\r
474 @param[in] Sock Pointer to the socket to accept connections.\r
475 @param[in] Token The token to accept a connection.\r
476\r
477 @retval EFI_SUCCESS Either a connection is accpeted or the Token is\r
478 buffered for further acception.\r
479 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
480 socket is closed, or the socket is not configured to\r
481 be a passive one, or the token is already in one of\r
482 this socket's lists.\r
483 @retval EFI_NO_MAPPING The IP address configuration operation is not\r
484 finished.\r
485 @retval EFI_NOT_STARTED The socket is not configured.\r
486 @retval EFI_OUT_OF_RESOURCE Failed to buffer the Token due to memory limits.\r
487\r
488**/\r
489EFI_STATUS\r
490SockAccept (\r
491 IN SOCKET *Sock,\r
492 IN VOID *Token\r
493 )\r
494{\r
495 EFI_TCP4_LISTEN_TOKEN *ListenToken;\r
496 LIST_ENTRY *ListEntry;\r
497 EFI_STATUS Status;\r
498 SOCKET *Socket;\r
499 EFI_EVENT Event;\r
500\r
501 ASSERT (SockStream == Sock->Type);\r
502\r
503 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
504 if (EFI_ERROR (Status)) {\r
505\r
506 DEBUG (\r
507 (EFI_D_ERROR,\r
508 "SockAccept: Get the access for socket failed with %r",\r
509 Status)\r
510 );\r
511\r
512 return EFI_ACCESS_DENIED;\r
513 }\r
514\r
515 if (SOCK_IS_NO_MAPPING (Sock)) {\r
516 Status = EFI_NO_MAPPING;\r
517 goto Exit;\r
518 }\r
519\r
520 if (SOCK_IS_UNCONFIGURED (Sock)) {\r
521\r
522 Status = EFI_NOT_STARTED;\r
523 goto Exit;\r
524 }\r
525\r
526 if (!SOCK_IS_LISTENING (Sock)) {\r
527\r
528 Status = EFI_ACCESS_DENIED;\r
529 goto Exit;\r
530 }\r
531\r
532 Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r
533\r
534 if (SockTokenExisted (Sock, Event)) {\r
535\r
536 Status = EFI_ACCESS_DENIED;\r
537 goto Exit;\r
538 }\r
539\r
540 ListenToken = (EFI_TCP4_LISTEN_TOKEN *) Token;\r
541\r
542 //\r
543 // Check if a connection has already in this Sock->ConnectionList\r
544 //\r
545 NET_LIST_FOR_EACH (ListEntry, &Sock->ConnectionList) {\r
546\r
547 Socket = NET_LIST_USER_STRUCT (ListEntry, SOCKET, ConnectionList);\r
548\r
549 if (SOCK_IS_CONNECTED (Socket)) {\r
550 ListenToken->NewChildHandle = Socket->SockHandle;\r
551 SIGNAL_TOKEN (&(ListenToken->CompletionToken), EFI_SUCCESS);\r
552\r
553 RemoveEntryList (ListEntry);\r
554\r
555 ASSERT (Socket->Parent != NULL);\r
556\r
557 Socket->Parent->ConnCnt--;\r
558\r
559 DEBUG (\r
f3612a8d 560 (EFI_D_NET,\r
a3bcde70
HT
561 "SockAccept: Accept a socket, now conncount is %d",\r
562 Socket->Parent->ConnCnt)\r
563 );\r
564 Socket->Parent = NULL;\r
565\r
566 goto Exit;\r
567 }\r
568 }\r
569\r
570 //\r
571 // Buffer this token for latter incoming connection request\r
572 //\r
573 if (NULL == SockBufferToken (Sock, &(Sock->ListenTokenList), Token, 0)) {\r
574\r
575 Status = EFI_OUT_OF_RESOURCES;\r
576 }\r
577\r
578Exit:\r
579 EfiReleaseLock (&(Sock->Lock));\r
580\r
581 return Status;\r
582}\r
583\r
584/**\r
585 Issue a token with data to the socket to send out.\r
586\r
587 @param[in] Sock Pointer to the socket to process the token with\r
588 data.\r
589 @param[in] Token The token with data that needs to send out.\r
590\r
591 @retval EFI_SUCCESS The token processed successfully.\r
592 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
593 socket is closed, or the socket is not in a\r
594 synchronized state , or the token is already in one\r
595 of this socket's lists.\r
596 @retval EFI_NO_MAPPING The IP address configuration operation is not\r
597 finished.\r
598 @retval EFI_NOT_STARTED The socket is not configured.\r
599 @retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limits.\r
600\r
601**/\r
602EFI_STATUS\r
603SockSend (\r
604 IN SOCKET *Sock,\r
605 IN VOID *Token\r
606 )\r
607{\r
608 SOCK_IO_TOKEN *SndToken;\r
609 EFI_EVENT Event;\r
610 UINT32 FreeSpace;\r
611 EFI_TCP4_TRANSMIT_DATA *TxData;\r
612 EFI_STATUS Status;\r
613 SOCK_TOKEN *SockToken;\r
614 UINT32 DataLen;\r
615\r
616 ASSERT (SockStream == Sock->Type);\r
617\r
618 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
619 if (EFI_ERROR (Status)) {\r
620\r
621 DEBUG (\r
622 (EFI_D_ERROR,\r
623 "SockSend: Get the access for socket failed with %r",\r
624 Status)\r
625 );\r
626\r
627 return EFI_ACCESS_DENIED;\r
628 }\r
629\r
630 if (SOCK_IS_NO_MAPPING (Sock)) {\r
631 Status = EFI_NO_MAPPING;\r
632 goto Exit;\r
633 }\r
634\r
635 SndToken = (SOCK_IO_TOKEN *) Token;\r
636 TxData = (EFI_TCP4_TRANSMIT_DATA *) SndToken->Packet.TxData;\r
637\r
638 if (SOCK_IS_UNCONFIGURED (Sock)) {\r
639 Status = EFI_NOT_STARTED;\r
640 goto Exit;\r
641 }\r
642\r
643 if (!(SOCK_IS_CONNECTING (Sock) || SOCK_IS_CONNECTED (Sock))) {\r
644\r
645 Status = EFI_ACCESS_DENIED;\r
646 goto Exit;\r
647 }\r
648\r
649 //\r
650 // check if a token is already in the token buffer\r
651 //\r
652 Event = SndToken->Token.Event;\r
653\r
654 if (SockTokenExisted (Sock, Event)) {\r
655 Status = EFI_ACCESS_DENIED;\r
656 goto Exit;\r
657 }\r
658\r
659 DataLen = TxData->DataLength;\r
660\r
661 //\r
662 // process this sending token now or buffer it only?\r
663 //\r
664 FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);\r
665\r
666 if ((FreeSpace < Sock->SndBuffer.LowWater) || !SOCK_IS_CONNECTED (Sock)) {\r
667\r
668 SockToken = SockBufferToken (\r
669 Sock,\r
670 &Sock->SndTokenList,\r
671 SndToken,\r
672 DataLen\r
673 );\r
674\r
675 if (NULL == SockToken) {\r
676 Status = EFI_OUT_OF_RESOURCES;\r
677 }\r
678 } else {\r
679\r
680 SockToken = SockBufferToken (\r
681 Sock,\r
682 &Sock->ProcessingSndTokenList,\r
683 SndToken,\r
684 DataLen\r
685 );\r
686\r
687 if (NULL == SockToken) {\r
688 DEBUG (\r
689 (EFI_D_ERROR,\r
690 "SockSend: Failed to buffer IO token into socket processing SndToken List\n",\r
691 Status)\r
692 );\r
693\r
694 Status = EFI_OUT_OF_RESOURCES;\r
695 goto Exit;\r
696 }\r
697\r
698 Status = SockProcessTcpSndData (Sock, TxData);\r
699\r
700 if (EFI_ERROR (Status)) {\r
701 DEBUG (\r
702 (EFI_D_ERROR,\r
703 "SockSend: Failed to process Snd Data\n",\r
704 Status)\r
705 );\r
706\r
707 RemoveEntryList (&(SockToken->TokenList));\r
708 FreePool (SockToken);\r
709 }\r
710 }\r
711\r
712Exit:\r
713 EfiReleaseLock (&(Sock->Lock));\r
714 return Status;\r
715}\r
716\r
717/**\r
718 Issue a token to get data from the socket.\r
719\r
720 @param[in] Sock Pointer to the socket to get data from.\r
721 @param[in] Token The token to store the received data from the\r
722 socket.\r
723\r
724 @retval EFI_SUCCESS The token processed successfully.\r
725 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
726 socket is closed, or the socket is not in a\r
727 synchronized state , or the token is already in one\r
728 of this socket's lists.\r
729 @retval EFI_NO_MAPPING The IP address configuration operation is not\r
730 finished.\r
731 @retval EFI_NOT_STARTED The socket is not configured.\r
732 @retval EFI_CONNECTION_FIN The connection is closed and there is no more data.\r
733 @retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limit.\r
734\r
735**/\r
736EFI_STATUS\r
737SockRcv (\r
738 IN SOCKET *Sock,\r
739 IN VOID *Token\r
740 )\r
741{\r
742 SOCK_IO_TOKEN *RcvToken;\r
743 UINT32 RcvdBytes;\r
744 EFI_STATUS Status;\r
745 EFI_EVENT Event;\r
746\r
747 ASSERT (SockStream == Sock->Type);\r
748\r
749 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
750 if (EFI_ERROR (Status)) {\r
751\r
752 DEBUG (\r
753 (EFI_D_ERROR,\r
754 "SockRcv: Get the access for socket failed with %r",\r
755 Status)\r
756 );\r
757\r
758 return EFI_ACCESS_DENIED;\r
759 }\r
760\r
761 if (SOCK_IS_NO_MAPPING (Sock)) {\r
762\r
763 Status = EFI_NO_MAPPING;\r
764 goto Exit;\r
765 }\r
766\r
767 if (SOCK_IS_UNCONFIGURED (Sock)) {\r
768\r
769 Status = EFI_NOT_STARTED;\r
770 goto Exit;\r
771 }\r
772\r
773 if (!(SOCK_IS_CONNECTED (Sock) || SOCK_IS_CONNECTING (Sock))) {\r
774\r
775 Status = EFI_ACCESS_DENIED;\r
776 goto Exit;\r
777 }\r
778\r
779 RcvToken = (SOCK_IO_TOKEN *) Token;\r
780\r
781 //\r
782 // check if a token is already in the token buffer of this socket\r
783 //\r
784 Event = RcvToken->Token.Event;\r
785 if (SockTokenExisted (Sock, Event)) {\r
786 Status = EFI_ACCESS_DENIED;\r
787 goto Exit;\r
788 }\r
789\r
790 RcvToken = (SOCK_IO_TOKEN *) Token;\r
791 RcvdBytes = GET_RCV_DATASIZE (Sock);\r
792\r
793 //\r
794 // check whether an error has happened before\r
795 //\r
796 if (EFI_ABORTED != Sock->SockError) {\r
797\r
798 SIGNAL_TOKEN (&(RcvToken->Token), Sock->SockError);\r
799 Sock->SockError = EFI_ABORTED;\r
800 goto Exit;\r
801 }\r
802\r
803 //\r
804 // check whether can not receive and there is no any\r
805 // data buffered in Sock->RcvBuffer\r
806 //\r
807 if (SOCK_IS_NO_MORE_DATA (Sock) && (0 == RcvdBytes)) {\r
808\r
809 Status = EFI_CONNECTION_FIN;\r
810 goto Exit;\r
811 }\r
812\r
813 if (RcvdBytes != 0) {\r
72a4f34e 814 SockProcessRcvToken (Sock, RcvToken);\r
a3bcde70
HT
815\r
816 Status = Sock->ProtoHandler (Sock, SOCK_CONSUMED, NULL);\r
817 } else {\r
818\r
819 if (NULL == SockBufferToken (Sock, &Sock->RcvTokenList, RcvToken, 0)) {\r
820 Status = EFI_OUT_OF_RESOURCES;\r
821 }\r
822 }\r
823\r
824Exit:\r
825 EfiReleaseLock (&(Sock->Lock));\r
826 return Status;\r
827}\r
828\r
829/**\r
830 Reset the socket and its associated protocol control block.\r
831\r
832 @param[in, out] Sock Pointer to the socket to be flushed.\r
833\r
834 @retval EFI_SUCCESS The socket is flushed successfully.\r
835 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r
836\r
837**/\r
838EFI_STATUS\r
839SockFlush (\r
840 IN OUT SOCKET *Sock\r
841 )\r
842{\r
843 EFI_STATUS Status;\r
844\r
845 ASSERT (SockStream == Sock->Type);\r
846\r
847 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
848 if (EFI_ERROR (Status)) {\r
849\r
850 DEBUG (\r
851 (EFI_D_ERROR,\r
852 "SockFlush: Get the access for socket failed with %r",\r
853 Status)\r
854 );\r
855\r
856 return EFI_ACCESS_DENIED;\r
857 }\r
858\r
859 if (!SOCK_IS_CONFIGURED (Sock)) {\r
860\r
861 Status = EFI_ACCESS_DENIED;\r
862 goto Exit;\r
863 }\r
864\r
865 Status = Sock->ProtoHandler (Sock, SOCK_FLUSH, NULL);\r
866 if (EFI_ERROR (Status)) {\r
867\r
868 DEBUG (\r
869 (EFI_D_ERROR,\r
870 "SockFlush: Protocol failed handling SOCK_FLUSH with %r",\r
871 Status)\r
872 );\r
873\r
874 goto Exit;\r
875 }\r
876\r
877 SOCK_ERROR (Sock, EFI_ABORTED);\r
878 SockConnFlush (Sock);\r
879 SockSetState (Sock, SO_CLOSED);\r
880\r
881 Sock->ConfigureState = SO_UNCONFIGURED;\r
882\r
883Exit:\r
884 EfiReleaseLock (&(Sock->Lock));\r
885 return Status;\r
886}\r
887\r
888/**\r
889 Close or abort the socket associated connection.\r
890\r
891 @param[in, out] Sock Pointer to the socket of the connection to close\r
892 or abort.\r
893 @param[in] Token The token for a close operation.\r
894 @param[in] OnAbort TRUE for aborting the connection; FALSE to close it.\r
895\r
896 @retval EFI_SUCCESS The close or abort operation initialized\r
897 successfully.\r
898 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
899 socket is closed, or the socket is not in a\r
900 synchronized state , or the token is already in one\r
901 of this socket's lists.\r
902 @retval EFI_NO_MAPPING The IP address configuration operation is not\r
903 finished.\r
904 @retval EFI_NOT_STARTED The socket is not configured.\r
905\r
906**/\r
907EFI_STATUS\r
908SockClose (\r
909 IN OUT SOCKET *Sock,\r
910 IN VOID *Token,\r
911 IN BOOLEAN OnAbort\r
912 )\r
913{\r
914 EFI_STATUS Status;\r
915 EFI_EVENT Event;\r
916\r
917 ASSERT (SockStream == Sock->Type);\r
918\r
919 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
920 if (EFI_ERROR (Status)) {\r
921 DEBUG (\r
922 (EFI_D_ERROR,\r
923 "SockClose: Get the access for socket failed with %r",\r
924 Status)\r
925 );\r
926\r
927 return EFI_ACCESS_DENIED;\r
928 }\r
929\r
930 if (SOCK_IS_NO_MAPPING (Sock)) {\r
931 Status = EFI_NO_MAPPING;\r
932 goto Exit;\r
933 }\r
934\r
935 if (SOCK_IS_UNCONFIGURED (Sock)) {\r
936 Status = EFI_NOT_STARTED;\r
937 goto Exit;\r
938 }\r
939\r
940 if (SOCK_IS_DISCONNECTING (Sock)) {\r
941 Status = EFI_ACCESS_DENIED;\r
942 goto Exit;\r
943 }\r
944\r
945 Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r
946\r
947 if (SockTokenExisted (Sock, Event)) {\r
948 Status = EFI_ACCESS_DENIED;\r
949 goto Exit;\r
950 }\r
951\r
952 Sock->CloseToken = Token;\r
953 SockSetState (Sock, SO_DISCONNECTING);\r
954\r
955 if (OnAbort) {\r
956 Status = Sock->ProtoHandler (Sock, SOCK_ABORT, NULL);\r
957 } else {\r
958 Status = Sock->ProtoHandler (Sock, SOCK_CLOSE, NULL);\r
959 }\r
960\r
961Exit:\r
962 EfiReleaseLock (&(Sock->Lock));\r
963 return Status;\r
964}\r
965\r
5ffe214a
JW
966/**\r
967 Abort the socket associated connection, listen, transmission or receive request.\r
968\r
969 @param[in, out] Sock Pointer to the socket to abort.\r
970 @param[in] Token Pointer to a token that has been issued by\r
971 Connect(), Accept(), Transmit() or Receive(). If\r
972 NULL, all pending tokens issued by the four\r
973 functions listed above will be aborted.\r
974\r
975 @retval EFI_UNSUPPORTED The operation is not supported in the current\r
976 implementation.\r
977**/\r
978EFI_STATUS\r
979SockCancel (\r
980 IN OUT SOCKET *Sock,\r
981 IN VOID *Token\r
f75a7f56 982 )\r
5ffe214a
JW
983{\r
984 EFI_STATUS Status;\r
985\r
986 Status = EFI_SUCCESS;\r
987\r
988 ASSERT (SockStream == Sock->Type);\r
989\r
990 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
991 if (EFI_ERROR (Status)) {\r
992 DEBUG (\r
993 (EFI_D_ERROR,\r
994 "SockCancel: Get the access for socket failed with %r",\r
995 Status)\r
996 );\r
997\r
998 return EFI_ACCESS_DENIED;\r
999 }\r
1000\r
1001 if (SOCK_IS_UNCONFIGURED (Sock)) {\r
1002 Status = EFI_NOT_STARTED;\r
1003 goto Exit;\r
1004 }\r
f75a7f56 1005\r
5ffe214a
JW
1006 //\r
1007 // 1. Check ConnectionToken.\r
1008 //\r
1009 if (Token == NULL || (SOCK_COMPLETION_TOKEN *) Token == Sock->ConnectionToken) {\r
1010 if (Sock->ConnectionToken != NULL) {\r
1011 SIGNAL_TOKEN (Sock->ConnectionToken, EFI_ABORTED);\r
1012 Sock->ConnectionToken = NULL;\r
1013 }\r
1014\r
1015 if (Token != NULL) {\r
1016 Status = EFI_SUCCESS;\r
1017 goto Exit;\r
1018 }\r
1019 }\r
1020\r
1021 //\r
1022 // 2. Check ListenTokenList.\r
1023 //\r
1024 Status = SockCancelToken (Token, &Sock->ListenTokenList);\r
1025 if (Token != NULL && !EFI_ERROR (Status)) {\r
1026 goto Exit;\r
1027 }\r
1028\r
1029 //\r
1030 // 3. Check RcvTokenList.\r
1031 //\r
1032 Status = SockCancelToken (Token, &Sock->RcvTokenList);\r
1033 if (Token != NULL && !EFI_ERROR (Status)) {\r
1034 goto Exit;\r
1035 }\r
f75a7f56 1036\r
5ffe214a
JW
1037 //\r
1038 // 4. Check SndTokenList.\r
1039 //\r
1040 Status = SockCancelToken (Token, &Sock->SndTokenList);\r
1041 if (Token != NULL && !EFI_ERROR (Status)) {\r
1042 goto Exit;\r
1043 }\r
1044\r
1045 //\r
1046 // 5. Check ProcessingSndTokenList.\r
1047 //\r
1048 Status = SockCancelToken (Token, &Sock->ProcessingSndTokenList);\r
f75a7f56 1049\r
5ffe214a
JW
1050Exit:\r
1051 EfiReleaseLock (&(Sock->Lock));\r
1052 return Status;\r
1053}\r
1054\r
1055\r
a3bcde70
HT
1056/**\r
1057 Get the mode data of the low layer protocol.\r
1058\r
1059 @param[in] Sock Pointer to the socket to get mode data from.\r
1060 @param[in, out] Mode Pointer to the data to store the low layer mode\r
1061 information.\r
1062\r
1063 @retval EFI_SUCCESS The mode data was obtained successfully.\r
1064 @retval EFI_NOT_STARTED The socket is not configured.\r
1065\r
1066**/\r
1067EFI_STATUS\r
1068SockGetMode (\r
1069 IN SOCKET *Sock,\r
1070 IN OUT VOID *Mode\r
1071 )\r
1072{\r
1073 return Sock->ProtoHandler (Sock, SOCK_MODE, Mode);\r
1074}\r
1075\r
a3bcde70
HT
1076/**\r
1077 Add or remove route information in IP route table associated\r
1078 with this socket.\r
1079\r
1080 @param[in] Sock Pointer to the socket associated with the IP route\r
1081 table to operate on.\r
1082 @param[in] RouteInfo Pointer to the route information to be processed.\r
1083\r
1084 @retval EFI_SUCCESS The route table updated successfully.\r
1085 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r
1086 @retval EFI_NO_MAPPING The IP address configuration operation is not\r
1087 finished.\r
1088 @retval EFI_NOT_STARTED The socket is not configured.\r
1089\r
1090**/\r
1091EFI_STATUS\r
1092SockRoute (\r
1093 IN SOCKET *Sock,\r
1094 IN VOID *RouteInfo\r
1095 )\r
1096{\r
1097 EFI_STATUS Status;\r
1098\r
1099 Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
1100 if (EFI_ERROR (Status)) {\r
1101 DEBUG (\r
1102 (EFI_D_ERROR,\r
1103 "SockRoute: Get the access for socket failed with %r",\r
1104 Status)\r
1105 );\r
1106\r
1107 return EFI_ACCESS_DENIED;\r
1108 }\r
1109\r
1110 if (SOCK_IS_NO_MAPPING (Sock)) {\r
1111 Status = EFI_NO_MAPPING;\r
1112 goto Exit;\r
1113 }\r
1114\r
1115 if (SOCK_IS_UNCONFIGURED (Sock)) {\r
1116 Status = EFI_NOT_STARTED;\r
1117 goto Exit;\r
1118 }\r
1119\r
1120 Status = Sock->ProtoHandler (Sock, SOCK_ROUTE, RouteInfo);\r
1121\r
1122Exit:\r
1123 EfiReleaseLock (&(Sock->Lock));\r
1124 return Status;\r
1125}\r
1126\r