2 Interface function of the Socket.
4 Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php<BR>
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 Check whether the Event is in the List.
22 @param List Pointer to the token list to be searched.
23 @param Event The event to be checked.
25 @retval TRUE The specific Event exists in the List.
26 @retval FALSE The specific Event is not in the List.
30 SockTokenExistedInList (
35 LIST_ENTRY
*ListEntry
;
36 SOCK_TOKEN
*SockToken
;
38 NET_LIST_FOR_EACH (ListEntry
, List
) {
39 SockToken
= NET_LIST_USER_STRUCT (
45 if (Event
== SockToken
->Token
->Event
) {
55 Call SockTokenExistedInList() to check whether the Event is
56 in the related socket's lists.
58 @param Sock Pointer to the instance's socket.
59 @param Event The event to be checked.
61 @retval TRUE The Event exists in related socket's lists.
62 @retval FALSE The Event is not in related socket's lists.
72 if (SockTokenExistedInList (&Sock
->SndTokenList
, Event
) ||
73 SockTokenExistedInList (&Sock
->ProcessingSndTokenList
, Event
) ||
74 SockTokenExistedInList (&Sock
->RcvTokenList
, Event
) ||
75 SockTokenExistedInList (&Sock
->ListenTokenList
, Event
)) {
80 if ((Sock
->ConnectionToken
!= NULL
) &&
81 (Sock
->ConnectionToken
->Event
== Event
)) {
86 if ((Sock
->CloseToken
!= NULL
) && (Sock
->CloseToken
->Event
== Event
)) {
95 Buffer a token into the specific list of socket Sock.
97 @param Sock Pointer to the instance's socket.
98 @param List Pointer to the list to store the token.
99 @param Token Pointer to the token to be buffered.
100 @param DataLen The data length of the buffer contained in Token.
102 @return Pointer to the token that wraps Token. If NULL, error condition occurred.
113 SOCK_TOKEN
*SockToken
;
115 SockToken
= AllocatePool (sizeof (SOCK_TOKEN
));
116 if (NULL
== SockToken
) {
118 DEBUG ((EFI_D_ERROR
, "SockBufferIOToken: No Memory "
119 "to allocate SockToken\n"));
124 SockToken
->Sock
= Sock
;
125 SockToken
->Token
= (SOCK_COMPLETION_TOKEN
*) Token
;
126 SockToken
->RemainDataLen
= DataLen
;
127 InsertTailList (List
, &SockToken
->TokenList
);
134 Destroy the socket Sock and its associated protocol control block.
136 @param Sock The socket to be destroyed.
138 @retval EFI_SUCCESS The socket Sock is destroyed successfully.
139 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.
148 TCP4_PROTO_DATA
*ProtoData
;
152 ASSERT ((Sock
!= NULL
) && (Sock
->ProtoHandler
!= NULL
));
154 if (Sock
->InDestroy
) {
158 Sock
->InDestroy
= TRUE
;
160 ProtoData
= (TCP4_PROTO_DATA
*) Sock
->ProtoReserved
;
161 Tcb
= ProtoData
->TcpPcb
;
163 ASSERT (Tcb
!= NULL
);
165 Status
= EfiAcquireLockOrFail (&(Sock
->Lock
));
166 if (EFI_ERROR (Status
)) {
168 DEBUG ((EFI_D_ERROR
, "SockDestroyChild: Get the lock to "
169 "access socket failed with %r\n", Status
));
171 return EFI_ACCESS_DENIED
;
175 // Close the IP protocol.
178 Tcb
->IpInfo
->ChildHandle
,
179 &gEfiIp4ProtocolGuid
,
180 ProtoData
->TcpService
->IpIo
->Image
,
184 if (Sock
->DestroyCallback
!= NULL
) {
185 Sock
->DestroyCallback (Sock
, Sock
->Context
);
189 // Retrieve the protocol installed on this sock
191 Status
= gBS
->OpenProtocol (
193 &gEfiTcp4ProtocolGuid
,
197 EFI_OPEN_PROTOCOL_GET_PROTOCOL
200 if (EFI_ERROR (Status
)) {
202 DEBUG ((EFI_D_ERROR
, "SockDestroyChild: Open protocol installed "
203 "on socket failed with %r\n", Status
));
207 // Uninstall the protocol installed on this sock
208 // in the light of Sock->SockType
210 gBS
->UninstallMultipleProtocolInterfaces (
212 &gEfiTcp4ProtocolGuid
,
218 // force protocol layer to detach the PCB
220 Status
= Sock
->ProtoHandler (Sock
, SOCK_DETACH
, NULL
);
222 if (EFI_ERROR (Status
)) {
224 DEBUG ((EFI_D_ERROR
, "SockDestroyChild: Protocol detach socket"
225 " failed with %r\n", Status
));
227 Sock
->InDestroy
= FALSE
;
228 } else if (SOCK_IS_CONFIGURED (Sock
)) {
230 SockConnFlush (Sock
);
231 SockSetState (Sock
, SO_CLOSED
);
233 Sock
->ConfigureState
= SO_UNCONFIGURED
;
236 EfiReleaseLock (&(Sock
->Lock
));
238 if (EFI_ERROR (Status
)) {
248 Create a socket and its associated protocol control block
249 with the intial data SockInitData and protocol specific
252 @param SockInitData Inital data to setting the socket.
254 @return Pointer to the newly created socket. If NULL, error condition occured.
259 IN SOCK_INIT_DATA
*SockInitData
267 // create a new socket
269 Sock
= SockCreate (SockInitData
);
272 DEBUG ((EFI_D_ERROR
, "SockCreateChild: No resource to "
273 "create a new socket\n"));
278 Status
= EfiAcquireLockOrFail (&(Sock
->Lock
));
279 if (EFI_ERROR (Status
)) {
281 DEBUG ((EFI_D_ERROR
, "SockCreateChild: Get the lock to "
282 "access socket failed with %r\n", Status
));
287 // inform the protocol layer to attach the socket
288 // with a new protocol control block
290 Status
= Sock
->ProtoHandler (Sock
, SOCK_ATTACH
, NULL
);
291 EfiReleaseLock (&(Sock
->Lock
));
292 if (EFI_ERROR (Status
)) {
294 DEBUG ((EFI_D_ERROR
, "SockCreateChild: Protocol failed to"
295 " attach a socket with %r\n", Status
));
304 if (Sock
->DestroyCallback
!= NULL
) {
305 Sock
->DestroyCallback (Sock
, Sock
->Context
);
310 &gEfiTcp4ProtocolGuid
,
314 EFI_OPEN_PROTOCOL_GET_PROTOCOL
317 // Uninstall the protocol installed on this sock
319 gBS
->UninstallMultipleProtocolInterfaces (
321 &gEfiTcp4ProtocolGuid
,
331 Configure the specific socket Sock using configuration data ConfigData.
333 @param Sock Pointer to the socket to be configured.
334 @param ConfigData Pointer to the configuration data.
336 @retval EFI_SUCCESS The socket is configured successfully.
337 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket or the
338 socket is already configured.
349 Status
= EfiAcquireLockOrFail (&(Sock
->Lock
));
350 if (EFI_ERROR (Status
)) {
352 DEBUG ((EFI_D_ERROR
, "SockConfigure: Get the access for "
353 "socket failed with %r", Status
));
355 return EFI_ACCESS_DENIED
;
358 if (SOCK_IS_CONFIGURED (Sock
)) {
359 Status
= EFI_ACCESS_DENIED
;
363 ASSERT (Sock
->State
== SO_CLOSED
);
365 Status
= Sock
->ProtoHandler (Sock
, SOCK_CONFIGURE
, ConfigData
);
368 EfiReleaseLock (&(Sock
->Lock
));
375 Initiate a connection establishment process.
377 @param Sock Pointer to the socket to initiate the initate the
379 @param Token Pointer to the token used for the connection
382 @retval EFI_SUCCESS The connection is initialized successfully.
383 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the
384 socket is closed, or the socket is not configured to
385 be an active one, or the token is already in one of
387 @retval EFI_NO_MAPPING The IP address configuration operation is not
389 @retval EFI_NOT_STARTED The socket is not configured.
401 Status
= EfiAcquireLockOrFail (&(Sock
->Lock
));
402 if (EFI_ERROR (Status
)) {
404 DEBUG ((EFI_D_ERROR
, "SockConnect: Get the access for "
405 "socket failed with %r", Status
));
407 return EFI_ACCESS_DENIED
;
410 if (SOCK_IS_NO_MAPPING (Sock
)) {
411 Status
= EFI_NO_MAPPING
;
415 if (SOCK_IS_UNCONFIGURED (Sock
)) {
417 Status
= EFI_NOT_STARTED
;
421 if (!SOCK_IS_CLOSED (Sock
) || !SOCK_IS_CONFIGURED_ACTIVE (Sock
)) {
423 Status
= EFI_ACCESS_DENIED
;
427 Event
= ((SOCK_COMPLETION_TOKEN
*) Token
)->Event
;
429 if (SockTokenExisted (Sock
, Event
)) {
431 Status
= EFI_ACCESS_DENIED
;
435 Sock
->ConnectionToken
= (SOCK_COMPLETION_TOKEN
*) Token
;
436 SockSetState (Sock
, SO_CONNECTING
);
437 Status
= Sock
->ProtoHandler (Sock
, SOCK_CONNECT
, NULL
);
440 EfiReleaseLock (&(Sock
->Lock
));
446 Issue a listen token to get an existed connected network instance
447 or wait for a connection if there is none.
449 @param Sock Pointer to the socket to accept connections.
450 @param Token The token to accept a connection.
452 @retval EFI_SUCCESS Either a connection is accpeted or the Token is
453 buffered for further acception.
454 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the
455 socket is closed, or the socket is not configured to
456 be a passive one, or the token is already in one of
458 @retval EFI_NO_MAPPING The IP address configuration operation is not
460 @retval EFI_NOT_STARTED The socket is not configured.
461 @retval EFI_OUT_OF_RESOURCE Failed to buffer the Token due to memory limit.
470 EFI_TCP4_LISTEN_TOKEN
*ListenToken
;
471 LIST_ENTRY
*ListEntry
;
476 ASSERT (SockStream
== Sock
->Type
);
478 Status
= EfiAcquireLockOrFail (&(Sock
->Lock
));
479 if (EFI_ERROR (Status
)) {
481 DEBUG ((EFI_D_ERROR
, "SockAccept: Get the access for socket"
482 " failed with %r", Status
));
484 return EFI_ACCESS_DENIED
;
487 if (SOCK_IS_NO_MAPPING (Sock
)) {
488 Status
= EFI_NO_MAPPING
;
492 if (SOCK_IS_UNCONFIGURED (Sock
)) {
494 Status
= EFI_NOT_STARTED
;
498 if (!SOCK_IS_LISTENING (Sock
)) {
500 Status
= EFI_ACCESS_DENIED
;
504 Event
= ((SOCK_COMPLETION_TOKEN
*) Token
)->Event
;
506 if (SockTokenExisted (Sock
, Event
)) {
508 Status
= EFI_ACCESS_DENIED
;
512 ListenToken
= (EFI_TCP4_LISTEN_TOKEN
*) Token
;
515 // Check if a connection has already in this Sock->ConnectionList
517 NET_LIST_FOR_EACH (ListEntry
, &Sock
->ConnectionList
) {
519 Socket
= NET_LIST_USER_STRUCT (ListEntry
, SOCKET
, ConnectionList
);
521 if (SOCK_IS_CONNECTED (Socket
)) {
522 ListenToken
->NewChildHandle
= Socket
->SockHandle
;
523 SIGNAL_TOKEN (&(ListenToken
->CompletionToken
), EFI_SUCCESS
);
525 RemoveEntryList (ListEntry
);
527 ASSERT (Socket
->Parent
!= NULL
);
529 Socket
->Parent
->ConnCnt
--;
533 "SockAccept: Accept a socket, now conncount is %d",
534 Socket
->Parent
->ConnCnt
)
536 Socket
->Parent
= NULL
;
543 // Buffer this token for latter incoming connection request
545 if (NULL
== SockBufferToken (Sock
, &(Sock
->ListenTokenList
), Token
, 0)) {
547 Status
= EFI_OUT_OF_RESOURCES
;
551 EfiReleaseLock (&(Sock
->Lock
));
558 Issue a token with data to the socket to send out.
560 @param Sock Pointer to the socket to process the token with
562 @param Token The token with data that needs to send out.
564 @retval EFI_SUCCESS The token is processed successfully.
565 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the
566 socket is closed, or the socket is not in a
567 synchronized state , or the token is already in one
568 of this socket's lists.
569 @retval EFI_NO_MAPPING The IP address configuration operation is not
571 @retval EFI_NOT_STARTED The socket is not configured.
572 @retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limit.
581 SOCK_IO_TOKEN
*SndToken
;
584 EFI_TCP4_TRANSMIT_DATA
*TxData
;
586 SOCK_TOKEN
*SockToken
;
589 ASSERT (SockStream
== Sock
->Type
);
591 Status
= EfiAcquireLockOrFail (&(Sock
->Lock
));
592 if (EFI_ERROR (Status
)) {
594 DEBUG ((EFI_D_ERROR
, "SockSend: Get the access for socket"
595 " failed with %r", Status
));
597 return EFI_ACCESS_DENIED
;
600 if (SOCK_IS_NO_MAPPING (Sock
)) {
601 Status
= EFI_NO_MAPPING
;
605 SndToken
= (SOCK_IO_TOKEN
*) Token
;
606 TxData
= (EFI_TCP4_TRANSMIT_DATA
*) SndToken
->Packet
.TxData
;
608 if (SOCK_IS_UNCONFIGURED (Sock
)) {
609 Status
= EFI_NOT_STARTED
;
613 if (!(SOCK_IS_CONNECTING (Sock
) || SOCK_IS_CONNECTED (Sock
))) {
615 Status
= EFI_ACCESS_DENIED
;
620 // check if a token is already in the token buffer
622 Event
= SndToken
->Token
.Event
;
624 if (SockTokenExisted (Sock
, Event
)) {
625 Status
= EFI_ACCESS_DENIED
;
629 DataLen
= (UINT32
) TxData
->DataLength
;
632 // process this sending token now or buffer it only?
634 FreeSpace
= SockGetFreeSpace (Sock
, SOCK_SND_BUF
);
636 if ((FreeSpace
< Sock
->SndBuffer
.LowWater
) || !SOCK_IS_CONNECTED (Sock
)) {
638 SockToken
= SockBufferToken (
645 if (NULL
== SockToken
) {
646 Status
= EFI_OUT_OF_RESOURCES
;
650 SockToken
= SockBufferToken (
652 &Sock
->ProcessingSndTokenList
,
657 if (NULL
== SockToken
) {
658 DEBUG ((EFI_D_ERROR
, "SockSend: Failed to buffer IO token into"
659 " socket processing SndToken List\n", Status
));
661 Status
= EFI_OUT_OF_RESOURCES
;
665 Status
= SockProcessTcpSndData (Sock
, TxData
);
667 if (EFI_ERROR (Status
)) {
668 DEBUG ((EFI_D_ERROR
, "SockSend: Failed to process "
669 "Snd Data\n", Status
));
671 RemoveEntryList (&(SockToken
->TokenList
));
672 FreePool (SockToken
);
677 EfiReleaseLock (&(Sock
->Lock
));
683 Issue a token to get data from the socket.
685 @param Sock Pointer to the socket to get data from.
686 @param Token The token to store the received data from the
689 @retval EFI_SUCCESS The token is processed successfully.
690 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the
691 socket is closed, or the socket is not in a
692 synchronized state , or the token is already in one
693 of this socket's lists.
694 @retval EFI_NO_MAPPING The IP address configuration operation is not
696 @retval EFI_NOT_STARTED The socket is not configured.
697 @retval EFI_CONNECTION_FIN The connection is closed and there is no more data.
698 @retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limit.
707 SOCK_IO_TOKEN
*RcvToken
;
712 ASSERT (SockStream
== Sock
->Type
);
714 Status
= EfiAcquireLockOrFail (&(Sock
->Lock
));
715 if (EFI_ERROR (Status
)) {
717 DEBUG ((EFI_D_ERROR
, "SockRcv: Get the access for socket"
718 " failed with %r", Status
));
720 return EFI_ACCESS_DENIED
;
723 if (SOCK_IS_NO_MAPPING (Sock
)) {
725 Status
= EFI_NO_MAPPING
;
729 if (SOCK_IS_UNCONFIGURED (Sock
)) {
731 Status
= EFI_NOT_STARTED
;
735 if (!(SOCK_IS_CONNECTED (Sock
) || SOCK_IS_CONNECTING (Sock
))) {
737 Status
= EFI_ACCESS_DENIED
;
741 RcvToken
= (SOCK_IO_TOKEN
*) Token
;
744 // check if a token is already in the token buffer of this socket
746 Event
= RcvToken
->Token
.Event
;
747 if (SockTokenExisted (Sock
, Event
)) {
748 Status
= EFI_ACCESS_DENIED
;
752 RcvToken
= (SOCK_IO_TOKEN
*) Token
;
753 RcvdBytes
= GET_RCV_DATASIZE (Sock
);
756 // check whether an error has happened before
758 if (EFI_ABORTED
!= Sock
->SockError
) {
760 SIGNAL_TOKEN (&(RcvToken
->Token
), Sock
->SockError
);
761 Sock
->SockError
= EFI_ABORTED
;
766 // check whether can not receive and there is no any
767 // data buffered in Sock->RcvBuffer
769 if (SOCK_IS_NO_MORE_DATA (Sock
) && (0 == RcvdBytes
)) {
771 Status
= EFI_CONNECTION_FIN
;
775 if (RcvdBytes
!= 0) {
776 SockProcessRcvToken (Sock
, RcvToken
);
778 Status
= Sock
->ProtoHandler (Sock
, SOCK_CONSUMED
, NULL
);
781 if (NULL
== SockBufferToken (Sock
, &Sock
->RcvTokenList
, RcvToken
, 0)) {
782 Status
= EFI_OUT_OF_RESOURCES
;
787 EfiReleaseLock (&(Sock
->Lock
));
793 Reset the socket and its associated protocol control block.
795 @param Sock Pointer to the socket to be flushed.
797 @retval EFI_SUCCESS The socket is flushed successfully.
798 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.
808 ASSERT (SockStream
== Sock
->Type
);
810 Status
= EfiAcquireLockOrFail (&(Sock
->Lock
));
811 if (EFI_ERROR (Status
)) {
813 DEBUG ((EFI_D_ERROR
, "SockFlush: Get the access for socket"
814 " failed with %r", Status
));
816 return EFI_ACCESS_DENIED
;
819 if (!SOCK_IS_CONFIGURED (Sock
)) {
823 Status
= Sock
->ProtoHandler (Sock
, SOCK_FLUSH
, NULL
);
824 if (EFI_ERROR (Status
)) {
826 DEBUG ((EFI_D_ERROR
, "SockFlush: Protocol failed handling"
827 " SOCK_FLUSH with %r", Status
));
832 SOCK_ERROR (Sock
, EFI_ABORTED
);
833 SockConnFlush (Sock
);
834 SockSetState (Sock
, SO_CLOSED
);
836 Sock
->ConfigureState
= SO_UNCONFIGURED
;
839 EfiReleaseLock (&(Sock
->Lock
));
845 Close or abort the socket associated connection.
847 @param Sock Pointer to the socket of the connection to close or
849 @param Token The token for close operation.
850 @param OnAbort TRUE for aborting the connection, FALSE to close it.
852 @retval EFI_SUCCESS The close or abort operation is initialized
854 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the
855 socket is closed, or the socket is not in a
856 synchronized state , or the token is already in one
857 of this socket's lists.
858 @retval EFI_NO_MAPPING The IP address configuration operation is not
860 @retval EFI_NOT_STARTED The socket is not configured.
873 ASSERT (SockStream
== Sock
->Type
);
875 Status
= EfiAcquireLockOrFail (&(Sock
->Lock
));
876 if (EFI_ERROR (Status
)) {
877 DEBUG ((EFI_D_ERROR
, "SockClose: Get the access for socket"
878 " failed with %r", Status
));
880 return EFI_ACCESS_DENIED
;
883 if (SOCK_IS_NO_MAPPING (Sock
)) {
884 Status
= EFI_NO_MAPPING
;
888 if (SOCK_IS_UNCONFIGURED (Sock
)) {
889 Status
= EFI_NOT_STARTED
;
893 if (SOCK_IS_DISCONNECTING (Sock
)) {
894 Status
= EFI_ACCESS_DENIED
;
898 Event
= ((SOCK_COMPLETION_TOKEN
*) Token
)->Event
;
900 if (SockTokenExisted (Sock
, Event
)) {
901 Status
= EFI_ACCESS_DENIED
;
905 Sock
->CloseToken
= Token
;
906 SockSetState (Sock
, SO_DISCONNECTING
);
909 Status
= Sock
->ProtoHandler (Sock
, SOCK_ABORT
, NULL
);
911 Status
= Sock
->ProtoHandler (Sock
, SOCK_CLOSE
, NULL
);
915 EfiReleaseLock (&(Sock
->Lock
));
921 Get the mode data of the low layer protocol.
923 @param Sock Pointer to the socket to get mode data from.
924 @param Mode Pointer to the data to store the low layer mode
927 @retval EFI_SUCCESS The mode data is got successfully.
928 @retval EFI_NOT_STARTED The socket is not configured.
937 return Sock
->ProtoHandler (Sock
, SOCK_MODE
, Mode
);
942 Configure the low level protocol to join a multicast group for
943 this socket's connection.
945 @param Sock Pointer to the socket of the connection to join the
946 specific multicast group.
947 @param GroupInfo Pointer to the multicast group info.
949 @retval EFI_SUCCESS The configuration is done successfully.
950 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.
951 @retval EFI_NOT_STARTED The socket is not configured.
962 Status
= EfiAcquireLockOrFail (&(Sock
->Lock
));
964 if (EFI_ERROR (Status
)) {
966 DEBUG ((EFI_D_ERROR
, "SockGroup: Get the access for socket"
967 " failed with %r", Status
));
969 return EFI_ACCESS_DENIED
;
972 if (SOCK_IS_UNCONFIGURED (Sock
)) {
973 Status
= EFI_NOT_STARTED
;
977 Status
= Sock
->ProtoHandler (Sock
, SOCK_GROUP
, GroupInfo
);
980 EfiReleaseLock (&(Sock
->Lock
));
986 Add or remove route information in IP route table associated
989 @param Sock Pointer to the socket associated with the IP route
991 @param RouteInfo Pointer to the route information to be processed.
993 @retval EFI_SUCCESS The route table is updated successfully.
994 @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.
995 @retval EFI_NO_MAPPING The IP address configuration operation is not
997 @retval EFI_NOT_STARTED The socket is not configured.
1008 Status
= EfiAcquireLockOrFail (&(Sock
->Lock
));
1009 if (EFI_ERROR (Status
)) {
1010 DEBUG ((EFI_D_ERROR
, "SockRoute: Get the access for socket"
1011 " failed with %r", Status
));
1013 return EFI_ACCESS_DENIED
;
1016 if (SOCK_IS_NO_MAPPING (Sock
)) {
1017 Status
= EFI_NO_MAPPING
;
1021 if (SOCK_IS_UNCONFIGURED (Sock
)) {
1022 Status
= EFI_NOT_STARTED
;
1026 Status
= Sock
->ProtoHandler (Sock
, SOCK_ROUTE
, RouteInfo
);
1029 EfiReleaseLock (&(Sock
->Lock
));