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