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