1 /** @file
2   Interface function of the Socket.
3 
4   Copyright (c) 2009 - 2012, 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_INFO,
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     Status = SockProcessRcvToken (Sock, RcvToken);
728 
729     if (EFI_ERROR (Status)) {
730       goto Exit;
731     }
732 
733     Status = Sock->ProtoHandler (Sock, SOCK_CONSUMED, NULL);
734   } else {
735 
736     if (NULL == SockBufferToken (Sock, &Sock->RcvTokenList, RcvToken, 0)) {
737       Status = EFI_OUT_OF_RESOURCES;
738     }
739   }
740 
741 Exit:
742   EfiReleaseLock (&(Sock->Lock));
743   return Status;
744 }
745 
746 /**
747   Reset the socket and its associated protocol control block.
748 
749   @param[in, out]  Sock        Pointer to the socket to be flushed.
750 
751   @retval EFI_SUCCESS          The socket is flushed successfully.
752   @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket.
753 
754 **/
755 EFI_STATUS
SockFlush(IN OUT SOCKET * Sock)756 SockFlush (
757   IN OUT SOCKET *Sock
758   )
759 {
760   EFI_STATUS  Status;
761 
762   ASSERT (SockStream == Sock->Type);
763 
764   Status = EfiAcquireLockOrFail (&(Sock->Lock));
765   if (EFI_ERROR (Status)) {
766 
767     DEBUG (
768       (EFI_D_ERROR,
769       "SockFlush: Get the access for socket failed with %r",
770       Status)
771       );
772 
773     return EFI_ACCESS_DENIED;
774   }
775 
776   if (!SOCK_IS_CONFIGURED (Sock)) {
777 
778     Status = EFI_ACCESS_DENIED;
779     goto Exit;
780   }
781 
782   Status = Sock->ProtoHandler (Sock, SOCK_FLUSH, NULL);
783   if (EFI_ERROR (Status)) {
784 
785     DEBUG (
786       (EFI_D_ERROR,
787       "SockFlush: Protocol failed handling SOCK_FLUSH with %r",
788       Status)
789       );
790 
791     goto Exit;
792   }
793 
794   SOCK_ERROR (Sock, EFI_ABORTED);
795   SockConnFlush (Sock);
796   SockSetState (Sock, SO_CLOSED);
797 
798   Sock->ConfigureState = SO_UNCONFIGURED;
799 
800 Exit:
801   EfiReleaseLock (&(Sock->Lock));
802   return Status;
803 }
804 
805 /**
806   Close or abort the socket associated connection.
807 
808   @param[in, out]  Sock        Pointer to the socket of the connection to close
809                                or abort.
810   @param[in]  Token            The token for a close operation.
811   @param[in]  OnAbort          TRUE for aborting the connection; FALSE to close it.
812 
813   @retval EFI_SUCCESS          The close or abort operation initialized
814                                successfully.
815   @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket, or the
816                                socket is closed, or the socket is not in a
817                                synchronized state , or the token is already in one
818                                of this socket's lists.
819   @retval EFI_NO_MAPPING       The IP address configuration operation is not
820                                finished.
821   @retval EFI_NOT_STARTED      The socket is not configured.
822 
823 **/
824 EFI_STATUS
SockClose(IN OUT SOCKET * Sock,IN VOID * Token,IN BOOLEAN OnAbort)825 SockClose (
826   IN OUT SOCKET  *Sock,
827   IN     VOID    *Token,
828   IN     BOOLEAN OnAbort
829   )
830 {
831   EFI_STATUS  Status;
832   EFI_EVENT   Event;
833 
834   ASSERT (SockStream == Sock->Type);
835 
836   Status = EfiAcquireLockOrFail (&(Sock->Lock));
837   if (EFI_ERROR (Status)) {
838     DEBUG (
839       (EFI_D_ERROR,
840       "SockClose: Get the access for socket failed with %r",
841       Status)
842       );
843 
844     return EFI_ACCESS_DENIED;
845   }
846 
847   if (SOCK_IS_NO_MAPPING (Sock)) {
848     Status = EFI_NO_MAPPING;
849     goto Exit;
850   }
851 
852   if (SOCK_IS_UNCONFIGURED (Sock)) {
853     Status = EFI_NOT_STARTED;
854     goto Exit;
855   }
856 
857   if (SOCK_IS_DISCONNECTING (Sock)) {
858     Status = EFI_ACCESS_DENIED;
859     goto Exit;
860   }
861 
862   Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;
863 
864   if (SockTokenExisted (Sock, Event)) {
865     Status = EFI_ACCESS_DENIED;
866     goto Exit;
867   }
868 
869   Sock->CloseToken = Token;
870   SockSetState (Sock, SO_DISCONNECTING);
871 
872   if (OnAbort) {
873     Status = Sock->ProtoHandler (Sock, SOCK_ABORT, NULL);
874   } else {
875     Status = Sock->ProtoHandler (Sock, SOCK_CLOSE, NULL);
876   }
877 
878 Exit:
879   EfiReleaseLock (&(Sock->Lock));
880   return Status;
881 }
882 
883 /**
884   Get the mode data of the low layer protocol.
885 
886   @param[in]       Sock        Pointer to the socket to get mode data from.
887   @param[in, out]  Mode        Pointer to the data to store the low layer mode
888                                information.
889 
890   @retval EFI_SUCCESS          The mode data was obtained successfully.
891   @retval EFI_NOT_STARTED      The socket is not configured.
892 
893 **/
894 EFI_STATUS
SockGetMode(IN SOCKET * Sock,IN OUT VOID * Mode)895 SockGetMode (
896   IN     SOCKET *Sock,
897   IN OUT VOID   *Mode
898   )
899 {
900   return Sock->ProtoHandler (Sock, SOCK_MODE, Mode);
901 }
902 
903 /**
904   Configure the low level protocol to join a multicast group for
905   this socket's connection.
906 
907   @param[in]  Sock             Pointer to the socket of the connection to join the
908                                specific multicast group.
909   @param[in]  GroupInfo        Pointer to the multicast group info.
910 
911   @retval EFI_SUCCESS          The configuration completed successfully.
912   @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket.
913   @retval EFI_NOT_STARTED      The socket is not configured.
914 
915 **/
916 EFI_STATUS
SockGroup(IN SOCKET * Sock,IN VOID * GroupInfo)917 SockGroup (
918   IN SOCKET *Sock,
919   IN VOID   *GroupInfo
920   )
921 {
922   EFI_STATUS  Status;
923 
924   Status = EfiAcquireLockOrFail (&(Sock->Lock));
925 
926   if (EFI_ERROR (Status)) {
927 
928     DEBUG (
929       (EFI_D_ERROR,
930       "SockGroup: Get the access for socket failed with %r",
931       Status)
932       );
933 
934     return EFI_ACCESS_DENIED;
935   }
936 
937   if (SOCK_IS_UNCONFIGURED (Sock)) {
938     Status = EFI_NOT_STARTED;
939     goto Exit;
940   }
941 
942   Status = Sock->ProtoHandler (Sock, SOCK_GROUP, GroupInfo);
943 
944 Exit:
945   EfiReleaseLock (&(Sock->Lock));
946   return Status;
947 }
948 
949 /**
950   Add or remove route information in IP route table associated
951   with this socket.
952 
953   @param[in]  Sock             Pointer to the socket associated with the IP route
954                                table to operate on.
955   @param[in]  RouteInfo        Pointer to the route information to be processed.
956 
957   @retval EFI_SUCCESS          The route table updated successfully.
958   @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket.
959   @retval EFI_NO_MAPPING       The IP address configuration operation is  not
960                                finished.
961   @retval EFI_NOT_STARTED      The socket is not configured.
962 
963 **/
964 EFI_STATUS
SockRoute(IN SOCKET * Sock,IN VOID * RouteInfo)965 SockRoute (
966   IN SOCKET    *Sock,
967   IN VOID      *RouteInfo
968   )
969 {
970   EFI_STATUS  Status;
971 
972   Status = EfiAcquireLockOrFail (&(Sock->Lock));
973   if (EFI_ERROR (Status)) {
974     DEBUG (
975       (EFI_D_ERROR,
976       "SockRoute: Get the access for socket failed with %r",
977       Status)
978       );
979 
980     return EFI_ACCESS_DENIED;
981   }
982 
983   if (SOCK_IS_NO_MAPPING (Sock)) {
984     Status = EFI_NO_MAPPING;
985     goto Exit;
986   }
987 
988   if (SOCK_IS_UNCONFIGURED (Sock)) {
989     Status = EFI_NOT_STARTED;
990     goto Exit;
991   }
992 
993   Status = Sock->ProtoHandler (Sock, SOCK_ROUTE, RouteInfo);
994 
995 Exit:
996   EfiReleaseLock (&(Sock->Lock));
997   return Status;
998 }
999 
1000