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