Home | History | Annotate | Download | only in Tcp4Dxe
      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
     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
     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 *
    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
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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