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
SockTokenExistedInList(IN LIST_ENTRY * List,IN EFI_EVENT Event)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
SockTokenExisted(IN SOCKET * Sock,IN EFI_EVENT Event)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 *
SockBufferToken(IN SOCKET * Sock,IN LIST_ENTRY * List,IN VOID * Token,IN UINT32 DataLen)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
SockDestroyChild(IN OUT SOCKET * Sock)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 intial data SockInitData and protocol specific
259   data ProtoData.
260 
261   @param[in]  SockInitData         Inital data to setting the socket.
262 
263   @return Pointer to the newly created socket. If NULL, an error condition occured.
264 
265 **/
266 SOCKET *
SockCreateChild(IN SOCK_INIT_DATA * SockInitData)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
SockConfigure(IN SOCKET * Sock,IN VOID * ConfigData)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 initate 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
SockConnect(IN SOCKET * Sock,IN VOID * Token)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 accpeted 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
SockAccept(IN SOCKET * Sock,IN VOID * Token)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
SockSend(IN SOCKET * Sock,IN VOID * Token)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
SockRcv(IN SOCKET * Sock,IN VOID * Token)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
SockFlush(IN OUT SOCKET * Sock)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
SockClose(IN OUT SOCKET * Sock,IN VOID * Token,IN BOOLEAN OnAbort)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
SockCancel(IN OUT SOCKET * Sock,IN VOID * Token)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
SockGetMode(IN SOCKET * Sock,IN OUT VOID * Mode)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
SockRoute(IN SOCKET * Sock,IN VOID * RouteInfo)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 
1127