]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/TcpDxe/SockInterface.c
413d6e1373f31d93810c4d49b3bb2271349cd1e9
[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 (
665 (DEBUG_ERROR,
666 "SockSend: Failed to buffer IO token into socket processing SndToken List\n",
667 Status)
668 );
669
670 Status = EFI_OUT_OF_RESOURCES;
671 goto Exit;
672 }
673
674 Status = SockProcessTcpSndData (Sock, TxData);
675
676 if (EFI_ERROR (Status)) {
677 DEBUG (
678 (DEBUG_ERROR,
679 "SockSend: Failed to process Snd Data\n",
680 Status)
681 );
682
683 RemoveEntryList (&(SockToken->TokenList));
684 FreePool (SockToken);
685 }
686 }
687
688 Exit:
689 EfiReleaseLock (&(Sock->Lock));
690 return Status;
691 }
692
693 /**
694 Issue a token to get data from the socket.
695
696 @param[in] Sock Pointer to the socket to get data from.
697 @param[in] Token The token to store the received data from the
698 socket.
699
700 @retval EFI_SUCCESS The token processed successfully.
701 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the
702 socket is closed, or the socket is not in a
703 synchronized state , or the token is already in one
704 of this socket's lists.
705 @retval EFI_NO_MAPPING The IP address configuration operation is not
706 finished.
707 @retval EFI_NOT_STARTED The socket is not configured.
708 @retval EFI_CONNECTION_FIN The connection is closed and there is no more data.
709 @retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limit.
710
711 **/
712 EFI_STATUS
713 SockRcv (
714 IN SOCKET *Sock,
715 IN VOID *Token
716 )
717 {
718 SOCK_IO_TOKEN *RcvToken;
719 UINT32 RcvdBytes;
720 EFI_STATUS Status;
721 EFI_EVENT Event;
722
723 ASSERT (SockStream == Sock->Type);
724
725 Status = EfiAcquireLockOrFail (&(Sock->Lock));
726 if (EFI_ERROR (Status)) {
727 DEBUG (
728 (DEBUG_ERROR,
729 "SockRcv: Get the access for socket failed with %r",
730 Status)
731 );
732
733 return EFI_ACCESS_DENIED;
734 }
735
736 if (SOCK_IS_NO_MAPPING (Sock)) {
737 Status = EFI_NO_MAPPING;
738 goto Exit;
739 }
740
741 if (SOCK_IS_UNCONFIGURED (Sock)) {
742 Status = EFI_NOT_STARTED;
743 goto Exit;
744 }
745
746 if (!(SOCK_IS_CONNECTED (Sock) || SOCK_IS_CONNECTING (Sock))) {
747 Status = EFI_ACCESS_DENIED;
748 goto Exit;
749 }
750
751 RcvToken = (SOCK_IO_TOKEN *)Token;
752
753 //
754 // check if a token is already in the token buffer of this socket
755 //
756 Event = RcvToken->Token.Event;
757 if (SockTokenExisted (Sock, Event)) {
758 Status = EFI_ACCESS_DENIED;
759 goto Exit;
760 }
761
762 RcvToken = (SOCK_IO_TOKEN *)Token;
763 RcvdBytes = GET_RCV_DATASIZE (Sock);
764
765 //
766 // check whether an error has happened before
767 //
768 if (EFI_ABORTED != Sock->SockError) {
769 SIGNAL_TOKEN (&(RcvToken->Token), Sock->SockError);
770 Sock->SockError = EFI_ABORTED;
771 goto Exit;
772 }
773
774 //
775 // check whether can not receive and there is no any
776 // data buffered in Sock->RcvBuffer
777 //
778 if (SOCK_IS_NO_MORE_DATA (Sock) && (0 == RcvdBytes)) {
779 Status = EFI_CONNECTION_FIN;
780 goto Exit;
781 }
782
783 if (RcvdBytes != 0) {
784 SockProcessRcvToken (Sock, RcvToken);
785
786 Status = Sock->ProtoHandler (Sock, SOCK_CONSUMED, NULL);
787 } else {
788 if (NULL == SockBufferToken (Sock, &Sock->RcvTokenList, RcvToken, 0)) {
789 Status = EFI_OUT_OF_RESOURCES;
790 }
791 }
792
793 Exit:
794 EfiReleaseLock (&(Sock->Lock));
795 return Status;
796 }
797
798 /**
799 Reset the socket and its associated protocol control block.
800
801 @param[in, out] Sock Pointer to the socket to be flushed.
802
803 @retval EFI_SUCCESS The socket is flushed successfully.
804 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.
805
806 **/
807 EFI_STATUS
808 SockFlush (
809 IN OUT SOCKET *Sock
810 )
811 {
812 EFI_STATUS Status;
813
814 ASSERT (SockStream == Sock->Type);
815
816 Status = EfiAcquireLockOrFail (&(Sock->Lock));
817 if (EFI_ERROR (Status)) {
818 DEBUG (
819 (DEBUG_ERROR,
820 "SockFlush: Get the access for socket failed with %r",
821 Status)
822 );
823
824 return EFI_ACCESS_DENIED;
825 }
826
827 if (!SOCK_IS_CONFIGURED (Sock)) {
828 Status = EFI_ACCESS_DENIED;
829 goto Exit;
830 }
831
832 Status = Sock->ProtoHandler (Sock, SOCK_FLUSH, NULL);
833 if (EFI_ERROR (Status)) {
834 DEBUG (
835 (DEBUG_ERROR,
836 "SockFlush: Protocol failed handling SOCK_FLUSH with %r",
837 Status)
838 );
839
840 goto Exit;
841 }
842
843 SOCK_ERROR (Sock, EFI_ABORTED);
844 SockConnFlush (Sock);
845 SockSetState (Sock, SO_CLOSED);
846
847 Sock->ConfigureState = SO_UNCONFIGURED;
848
849 Exit:
850 EfiReleaseLock (&(Sock->Lock));
851 return Status;
852 }
853
854 /**
855 Close or abort the socket associated connection.
856
857 @param[in, out] Sock Pointer to the socket of the connection to close
858 or abort.
859 @param[in] Token The token for a close operation.
860 @param[in] OnAbort TRUE for aborting the connection; FALSE to close it.
861
862 @retval EFI_SUCCESS The close or abort operation initialized
863 successfully.
864 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the
865 socket is closed, or the socket is not in a
866 synchronized state , or the token is already in one
867 of this socket's lists.
868 @retval EFI_NO_MAPPING The IP address configuration operation is not
869 finished.
870 @retval EFI_NOT_STARTED The socket is not configured.
871
872 **/
873 EFI_STATUS
874 SockClose (
875 IN OUT SOCKET *Sock,
876 IN VOID *Token,
877 IN BOOLEAN OnAbort
878 )
879 {
880 EFI_STATUS Status;
881 EFI_EVENT Event;
882
883 ASSERT (SockStream == Sock->Type);
884
885 Status = EfiAcquireLockOrFail (&(Sock->Lock));
886 if (EFI_ERROR (Status)) {
887 DEBUG (
888 (DEBUG_ERROR,
889 "SockClose: Get the access for socket failed with %r",
890 Status)
891 );
892
893 return EFI_ACCESS_DENIED;
894 }
895
896 if (SOCK_IS_NO_MAPPING (Sock)) {
897 Status = EFI_NO_MAPPING;
898 goto Exit;
899 }
900
901 if (SOCK_IS_UNCONFIGURED (Sock)) {
902 Status = EFI_NOT_STARTED;
903 goto Exit;
904 }
905
906 if (SOCK_IS_DISCONNECTING (Sock)) {
907 Status = EFI_ACCESS_DENIED;
908 goto Exit;
909 }
910
911 Event = ((SOCK_COMPLETION_TOKEN *)Token)->Event;
912
913 if (SockTokenExisted (Sock, Event)) {
914 Status = EFI_ACCESS_DENIED;
915 goto Exit;
916 }
917
918 Sock->CloseToken = Token;
919 SockSetState (Sock, SO_DISCONNECTING);
920
921 if (OnAbort) {
922 Status = Sock->ProtoHandler (Sock, SOCK_ABORT, NULL);
923 } else {
924 Status = Sock->ProtoHandler (Sock, SOCK_CLOSE, NULL);
925 }
926
927 Exit:
928 EfiReleaseLock (&(Sock->Lock));
929 return Status;
930 }
931
932 /**
933 Abort the socket associated connection, listen, transmission or receive request.
934
935 @param[in, out] Sock Pointer to the socket to abort.
936 @param[in] Token Pointer to a token that has been issued by
937 Connect(), Accept(), Transmit() or Receive(). If
938 NULL, all pending tokens issued by the four
939 functions listed above will be aborted.
940
941 @retval EFI_UNSUPPORTED The operation is not supported in the current
942 implementation.
943 **/
944 EFI_STATUS
945 SockCancel (
946 IN OUT SOCKET *Sock,
947 IN VOID *Token
948 )
949 {
950 EFI_STATUS Status;
951
952 Status = EFI_SUCCESS;
953
954 ASSERT (SockStream == Sock->Type);
955
956 Status = EfiAcquireLockOrFail (&(Sock->Lock));
957 if (EFI_ERROR (Status)) {
958 DEBUG (
959 (DEBUG_ERROR,
960 "SockCancel: Get the access for socket failed with %r",
961 Status)
962 );
963
964 return EFI_ACCESS_DENIED;
965 }
966
967 if (SOCK_IS_UNCONFIGURED (Sock)) {
968 Status = EFI_NOT_STARTED;
969 goto Exit;
970 }
971
972 //
973 // 1. Check ConnectionToken.
974 //
975 if ((Token == NULL) || ((SOCK_COMPLETION_TOKEN *)Token == Sock->ConnectionToken)) {
976 if (Sock->ConnectionToken != NULL) {
977 SIGNAL_TOKEN (Sock->ConnectionToken, EFI_ABORTED);
978 Sock->ConnectionToken = NULL;
979 }
980
981 if (Token != NULL) {
982 Status = EFI_SUCCESS;
983 goto Exit;
984 }
985 }
986
987 //
988 // 2. Check ListenTokenList.
989 //
990 Status = SockCancelToken (Token, &Sock->ListenTokenList);
991 if ((Token != NULL) && !EFI_ERROR (Status)) {
992 goto Exit;
993 }
994
995 //
996 // 3. Check RcvTokenList.
997 //
998 Status = SockCancelToken (Token, &Sock->RcvTokenList);
999 if ((Token != NULL) && !EFI_ERROR (Status)) {
1000 goto Exit;
1001 }
1002
1003 //
1004 // 4. Check SndTokenList.
1005 //
1006 Status = SockCancelToken (Token, &Sock->SndTokenList);
1007 if ((Token != NULL) && !EFI_ERROR (Status)) {
1008 goto Exit;
1009 }
1010
1011 //
1012 // 5. Check ProcessingSndTokenList.
1013 //
1014 Status = SockCancelToken (Token, &Sock->ProcessingSndTokenList);
1015
1016 Exit:
1017 EfiReleaseLock (&(Sock->Lock));
1018 return Status;
1019 }
1020
1021 /**
1022 Get the mode data of the low layer protocol.
1023
1024 @param[in] Sock Pointer to the socket to get mode data from.
1025 @param[in, out] Mode Pointer to the data to store the low layer mode
1026 information.
1027
1028 @retval EFI_SUCCESS The mode data was obtained successfully.
1029 @retval EFI_NOT_STARTED The socket is not configured.
1030
1031 **/
1032 EFI_STATUS
1033 SockGetMode (
1034 IN SOCKET *Sock,
1035 IN OUT VOID *Mode
1036 )
1037 {
1038 return Sock->ProtoHandler (Sock, SOCK_MODE, Mode);
1039 }
1040
1041 /**
1042 Add or remove route information in IP route table associated
1043 with this socket.
1044
1045 @param[in] Sock Pointer to the socket associated with the IP route
1046 table to operate on.
1047 @param[in] RouteInfo Pointer to the route information to be processed.
1048
1049 @retval EFI_SUCCESS The route table updated successfully.
1050 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.
1051 @retval EFI_NO_MAPPING The IP address configuration operation is not
1052 finished.
1053 @retval EFI_NOT_STARTED The socket is not configured.
1054
1055 **/
1056 EFI_STATUS
1057 SockRoute (
1058 IN SOCKET *Sock,
1059 IN VOID *RouteInfo
1060 )
1061 {
1062 EFI_STATUS Status;
1063
1064 Status = EfiAcquireLockOrFail (&(Sock->Lock));
1065 if (EFI_ERROR (Status)) {
1066 DEBUG (
1067 (DEBUG_ERROR,
1068 "SockRoute: Get the access for socket failed with %r",
1069 Status)
1070 );
1071
1072 return EFI_ACCESS_DENIED;
1073 }
1074
1075 if (SOCK_IS_NO_MAPPING (Sock)) {
1076 Status = EFI_NO_MAPPING;
1077 goto Exit;
1078 }
1079
1080 if (SOCK_IS_UNCONFIGURED (Sock)) {
1081 Status = EFI_NOT_STARTED;
1082 goto Exit;
1083 }
1084
1085 Status = Sock->ProtoHandler (Sock, SOCK_ROUTE, RouteInfo);
1086
1087 Exit:
1088 EfiReleaseLock (&(Sock->Lock));
1089 return Status;
1090 }