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