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