Home | History | Annotate | Download | only in MnpDxe
      1 /** @file
      2   Implementation of Managed Network Protocol private services.
      3 
      4 Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions
      7 of the BSD License which accompanies this distribution.  The full
      8 text of the license may be found at<BR>
      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 "MnpImpl.h"
     17 #include "MnpVlan.h"
     18 
     19 EFI_SERVICE_BINDING_PROTOCOL    mMnpServiceBindingProtocol = {
     20   MnpServiceBindingCreateChild,
     21   MnpServiceBindingDestroyChild
     22 };
     23 
     24 EFI_MANAGED_NETWORK_PROTOCOL    mMnpProtocolTemplate = {
     25   MnpGetModeData,
     26   MnpConfigure,
     27   MnpMcastIpToMac,
     28   MnpGroups,
     29   MnpTransmit,
     30   MnpReceive,
     31   MnpCancel,
     32   MnpPoll
     33 };
     34 
     35 EFI_MANAGED_NETWORK_CONFIG_DATA mMnpDefaultConfigData = {
     36   10000000,
     37   10000000,
     38   0,
     39   FALSE,
     40   FALSE,
     41   FALSE,
     42   FALSE,
     43   FALSE,
     44   FALSE,
     45   FALSE
     46 };
     47 
     48 /**
     49   Add Count of net buffers to MnpDeviceData->FreeNbufQue. The length of the net
     50   buffer is specified by MnpDeviceData->BufferLength.
     51 
     52   @param[in, out]  MnpDeviceData         Pointer to the MNP_DEVICE_DATA.
     53   @param[in]       Count                 Number of NET_BUFFERs to add.
     54 
     55   @retval EFI_SUCCESS           The specified amount of NET_BUFs are allocated
     56                                 and added to MnpDeviceData->FreeNbufQue.
     57   @retval EFI_OUT_OF_RESOURCES  Failed to allocate a NET_BUF structure.
     58 
     59 **/
     60 EFI_STATUS
     61 MnpAddFreeNbuf (
     62   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,
     63   IN     UINTN             Count
     64   )
     65 {
     66   EFI_STATUS  Status;
     67   UINTN       Index;
     68   NET_BUF     *Nbuf;
     69 
     70   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
     71   ASSERT ((Count > 0) && (MnpDeviceData->BufferLength > 0));
     72 
     73   Status = EFI_SUCCESS;
     74   for (Index = 0; Index < Count; Index++) {
     75     Nbuf = NetbufAlloc (MnpDeviceData->BufferLength + MnpDeviceData->PaddingSize);
     76     if (Nbuf == NULL) {
     77       DEBUG ((EFI_D_ERROR, "MnpAddFreeNbuf: NetBufAlloc failed.\n"));
     78 
     79       Status = EFI_OUT_OF_RESOURCES;
     80       break;
     81     }
     82 
     83     if (MnpDeviceData->PaddingSize > 0) {
     84       //
     85       // Pad padding bytes before the media header
     86       //
     87       NetbufAllocSpace (Nbuf, MnpDeviceData->PaddingSize, NET_BUF_TAIL);
     88       NetbufTrim (Nbuf, MnpDeviceData->PaddingSize, NET_BUF_HEAD);
     89     }
     90 
     91     NetbufQueAppend (&MnpDeviceData->FreeNbufQue, Nbuf);
     92   }
     93 
     94   MnpDeviceData->NbufCnt += Index;
     95   return Status;
     96 }
     97 
     98 
     99 /**
    100   Allocate a free NET_BUF from MnpDeviceData->FreeNbufQue. If there is none
    101   in the queue, first try to allocate some and add them into the queue, then
    102   fetch the NET_BUF from the updated FreeNbufQue.
    103 
    104   @param[in, out]  MnpDeviceData        Pointer to the MNP_DEVICE_DATA.
    105 
    106   @return     Pointer to the allocated free NET_BUF structure, if NULL the
    107               operation is failed.
    108 
    109 **/
    110 NET_BUF *
    111 MnpAllocNbuf (
    112   IN OUT MNP_DEVICE_DATA   *MnpDeviceData
    113   )
    114 {
    115   EFI_STATUS    Status;
    116   NET_BUF_QUEUE *FreeNbufQue;
    117   NET_BUF       *Nbuf;
    118   EFI_TPL       OldTpl;
    119 
    120   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
    121 
    122   FreeNbufQue = &MnpDeviceData->FreeNbufQue;
    123   OldTpl      = gBS->RaiseTPL (TPL_NOTIFY);
    124 
    125   //
    126   // Check whether there are available buffers, or else try to add some.
    127   //
    128   if (FreeNbufQue->BufNum == 0) {
    129     if ((MnpDeviceData->NbufCnt + MNP_NET_BUFFER_INCREASEMENT) > MNP_MAX_NET_BUFFER_NUM) {
    130       DEBUG (
    131         (EFI_D_ERROR,
    132         "MnpAllocNbuf: The maximum NET_BUF size is reached for MNP driver instance %p.\n",
    133         MnpDeviceData)
    134         );
    135 
    136       Nbuf = NULL;
    137       goto ON_EXIT;
    138     }
    139 
    140     Status = MnpAddFreeNbuf (MnpDeviceData, MNP_NET_BUFFER_INCREASEMENT);
    141     if (EFI_ERROR (Status)) {
    142       DEBUG (
    143         (EFI_D_ERROR,
    144         "MnpAllocNbuf: Failed to add NET_BUFs into the FreeNbufQue, %r.\n",
    145         Status)
    146         );
    147 
    148       //
    149       // Don't return NULL, perhaps MnpAddFreeNbuf does add some NET_BUFs but
    150       // the amount is less than MNP_NET_BUFFER_INCREASEMENT.
    151       //
    152     }
    153   }
    154 
    155   Nbuf = NetbufQueRemove (FreeNbufQue);
    156 
    157   //
    158   // Increase the RefCnt.
    159   //
    160   if (Nbuf != NULL) {
    161     NET_GET_REF (Nbuf);
    162   }
    163 
    164 ON_EXIT:
    165   gBS->RestoreTPL (OldTpl);
    166 
    167   return Nbuf;
    168 }
    169 
    170 
    171 /**
    172   Try to reclaim the Nbuf into the buffer pool.
    173 
    174   @param[in, out]  MnpDeviceData         Pointer to the mnp device context data.
    175   @param[in, out]  Nbuf                  Pointer to the NET_BUF to free.
    176 
    177 **/
    178 VOID
    179 MnpFreeNbuf (
    180   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,
    181   IN OUT NET_BUF           *Nbuf
    182   )
    183 {
    184   EFI_TPL  OldTpl;
    185 
    186   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
    187   ASSERT (Nbuf->RefCnt > 1);
    188 
    189   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    190 
    191   NET_PUT_REF (Nbuf);
    192 
    193   if (Nbuf->RefCnt == 1) {
    194     //
    195     // Trim all buffer contained in the Nbuf, then append it to the NbufQue.
    196     //
    197     NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_TAIL);
    198 
    199     if (NetbufAllocSpace (Nbuf, NET_VLAN_TAG_LEN, NET_BUF_HEAD) != NULL) {
    200       //
    201       // There is space reserved for vlan tag in the head, reclaim it
    202       //
    203       NetbufTrim (Nbuf, NET_VLAN_TAG_LEN, NET_BUF_TAIL);
    204     }
    205 
    206     NetbufQueAppend (&MnpDeviceData->FreeNbufQue, Nbuf);
    207   }
    208 
    209   gBS->RestoreTPL (OldTpl);
    210 }
    211 
    212 /**
    213   Add Count of TX buffers to MnpDeviceData->AllTxBufList and MnpDeviceData->FreeTxBufList.
    214   The length of the buffer is specified by MnpDeviceData->BufferLength.
    215 
    216   @param[in, out]  MnpDeviceData         Pointer to the MNP_DEVICE_DATA.
    217   @param[in]       Count                 Number of TX buffers to add.
    218 
    219   @retval EFI_SUCCESS           The specified amount of TX buffers are allocated.
    220   @retval EFI_OUT_OF_RESOURCES  Failed to allocate a TX buffer.
    221 
    222 **/
    223 EFI_STATUS
    224 MnpAddFreeTxBuf (
    225   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,
    226   IN     UINTN             Count
    227   )
    228 {
    229   EFI_STATUS        Status;
    230   UINT32            Index;
    231   MNP_TX_BUF_WRAP   *TxBufWrap;
    232 
    233   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
    234   ASSERT ((Count > 0) && (MnpDeviceData->BufferLength > 0));
    235 
    236   Status = EFI_SUCCESS;
    237   for (Index = 0; Index < Count; Index++) {
    238     TxBufWrap = (MNP_TX_BUF_WRAP*) AllocatePool (sizeof (MNP_TX_BUF_WRAP) + MnpDeviceData->BufferLength - 1);
    239     if (TxBufWrap == NULL) {
    240       DEBUG ((EFI_D_ERROR, "MnpAddFreeTxBuf: TxBuf Alloc failed.\n"));
    241 
    242       Status = EFI_OUT_OF_RESOURCES;
    243       break;
    244     }
    245     DEBUG ((EFI_D_INFO, "MnpAddFreeTxBuf: Add TxBufWrap %p, TxBuf %p\n", TxBufWrap, TxBufWrap->TxBuf));
    246     TxBufWrap->Signature = MNP_TX_BUF_WRAP_SIGNATURE;
    247     TxBufWrap->InUse     = FALSE;
    248     InsertTailList (&MnpDeviceData->FreeTxBufList, &TxBufWrap->WrapEntry);
    249     InsertTailList (&MnpDeviceData->AllTxBufList, &TxBufWrap->AllEntry);
    250   }
    251 
    252   MnpDeviceData->TxBufCount += Index;
    253   return Status;
    254 }
    255 
    256 /**
    257   Allocate a free TX buffer from MnpDeviceData->FreeTxBufList. If there is none
    258   in the queue, first try to recycle some from SNP, then try to allocate some and add
    259   them into the queue, then fetch the NET_BUF from the updated FreeTxBufList.
    260 
    261   @param[in, out]  MnpDeviceData        Pointer to the MNP_DEVICE_DATA.
    262 
    263   @return     Pointer to the allocated free NET_BUF structure, if NULL the
    264               operation is failed.
    265 
    266 **/
    267 UINT8 *
    268 MnpAllocTxBuf (
    269   IN OUT MNP_DEVICE_DATA   *MnpDeviceData
    270   )
    271 {
    272   EFI_TPL           OldTpl;
    273   UINT8             *TxBuf;
    274   EFI_STATUS        Status;
    275   LIST_ENTRY        *Entry;
    276   MNP_TX_BUF_WRAP   *TxBufWrap;
    277 
    278   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
    279 
    280   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    281 
    282   if (IsListEmpty (&MnpDeviceData->FreeTxBufList)) {
    283     //
    284     // First try to recycle some TX buffer from SNP
    285     //
    286     Status = MnpRecycleTxBuf (MnpDeviceData);
    287     if (EFI_ERROR (Status)) {
    288       TxBuf = NULL;
    289       goto ON_EXIT;
    290     }
    291 
    292     //
    293     // If still no free TX buffer, allocate more.
    294     //
    295     if (IsListEmpty (&MnpDeviceData->FreeTxBufList)) {
    296       if ((MnpDeviceData->TxBufCount + MNP_TX_BUFFER_INCREASEMENT) > MNP_MAX_TX_BUFFER_NUM) {
    297         DEBUG (
    298           (EFI_D_ERROR,
    299           "MnpAllocTxBuf: The maximum TxBuf size is reached for MNP driver instance %p.\n",
    300           MnpDeviceData)
    301           );
    302 
    303         TxBuf = NULL;
    304         goto ON_EXIT;
    305       }
    306 
    307       Status = MnpAddFreeTxBuf (MnpDeviceData, MNP_TX_BUFFER_INCREASEMENT);
    308       if (IsListEmpty (&MnpDeviceData->FreeTxBufList)) {
    309         DEBUG (
    310           (EFI_D_ERROR,
    311           "MnpAllocNbuf: Failed to add TxBuf into the FreeTxBufList, %r.\n",
    312           Status)
    313           );
    314 
    315         TxBuf = NULL;
    316         goto ON_EXIT;
    317       }
    318     }
    319   }
    320 
    321   ASSERT (!IsListEmpty (&MnpDeviceData->FreeTxBufList));
    322   Entry = MnpDeviceData->FreeTxBufList.ForwardLink;
    323   RemoveEntryList (MnpDeviceData->FreeTxBufList.ForwardLink);
    324   TxBufWrap = NET_LIST_USER_STRUCT_S (Entry, MNP_TX_BUF_WRAP, WrapEntry, MNP_TX_BUF_WRAP_SIGNATURE);
    325   TxBufWrap->InUse = TRUE;
    326   TxBuf = TxBufWrap->TxBuf;
    327 
    328 ON_EXIT:
    329   gBS->RestoreTPL (OldTpl);
    330 
    331   return TxBuf;
    332 }
    333 
    334 /**
    335   Try to reclaim the TX buffer into the buffer pool.
    336 
    337   @param[in, out]  MnpDeviceData         Pointer to the mnp device context data.
    338   @param[in, out]  TxBuf                 Pointer to the TX buffer to free.
    339 
    340 **/
    341 VOID
    342 MnpFreeTxBuf (
    343   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,
    344   IN OUT UINT8             *TxBuf
    345   )
    346 {
    347   MNP_TX_BUF_WRAP   *TxBufWrap;
    348   EFI_TPL           OldTpl;
    349 
    350   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
    351 
    352   if (TxBuf == NULL) {
    353     return;
    354   }
    355 
    356   TxBufWrap = NET_LIST_USER_STRUCT (TxBuf, MNP_TX_BUF_WRAP, TxBuf);
    357   if (TxBufWrap->Signature != MNP_TX_BUF_WRAP_SIGNATURE) {
    358     DEBUG (
    359       (EFI_D_ERROR,
    360       "MnpFreeTxBuf: Signature check failed in MnpFreeTxBuf.\n")
    361       );
    362     return;
    363   }
    364 
    365   if (!TxBufWrap->InUse) {
    366     DEBUG (
    367       (EFI_D_WARN,
    368       "MnpFreeTxBuf: Duplicated recycle report from SNP.\n")
    369       );
    370     return;
    371   }
    372 
    373   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    374   InsertTailList (&MnpDeviceData->FreeTxBufList, &TxBufWrap->WrapEntry);
    375   TxBufWrap->InUse = FALSE;
    376   gBS->RestoreTPL (OldTpl);
    377 }
    378 
    379 /**
    380   Try to recycle all the transmitted buffer address from SNP.
    381 
    382   @param[in, out]  MnpDeviceData     Pointer to the mnp device context data.
    383 
    384   @retval EFI_SUCCESS             Successed to recyclethe transmitted buffer address.
    385   @retval Others                  Failed to recyclethe transmitted buffer address.
    386 
    387 **/
    388 EFI_STATUS
    389 MnpRecycleTxBuf (
    390   IN OUT MNP_DEVICE_DATA   *MnpDeviceData
    391   )
    392 {
    393   UINT8                         *TxBuf;
    394   EFI_SIMPLE_NETWORK_PROTOCOL   *Snp;
    395   EFI_STATUS                    Status;
    396 
    397   Snp = MnpDeviceData->Snp;
    398   ASSERT (Snp != NULL);
    399 
    400   do {
    401     TxBuf = NULL;
    402     Status = Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf);
    403     if (EFI_ERROR (Status)) {
    404       return Status;
    405     }
    406 
    407     if (TxBuf != NULL) {
    408       MnpFreeTxBuf (MnpDeviceData, TxBuf);
    409     }
    410   } while (TxBuf != NULL);
    411 
    412   return EFI_SUCCESS;
    413 }
    414 
    415 /**
    416   Initialize the mnp device context data.
    417 
    418   @param[in, out]  MnpDeviceData      Pointer to the mnp device context data.
    419   @param[in]       ImageHandle        The driver image handle.
    420   @param[in]       ControllerHandle   Handle of device to bind driver to.
    421 
    422   @retval EFI_SUCCESS           The mnp service context is initialized.
    423   @retval EFI_UNSUPPORTED       ControllerHandle does not support Simple Network Protocol.
    424   @retval Others                Other errors as indicated.
    425 
    426 **/
    427 EFI_STATUS
    428 MnpInitializeDeviceData (
    429   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,
    430   IN     EFI_HANDLE        ImageHandle,
    431   IN     EFI_HANDLE        ControllerHandle
    432   )
    433 {
    434   EFI_STATUS                  Status;
    435   EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
    436   EFI_SIMPLE_NETWORK_MODE     *SnpMode;
    437 
    438   MnpDeviceData->Signature        = MNP_DEVICE_DATA_SIGNATURE;
    439   MnpDeviceData->ImageHandle      = ImageHandle;
    440   MnpDeviceData->ControllerHandle = ControllerHandle;
    441 
    442   //
    443   // Copy the MNP Protocol interfaces from the template.
    444   //
    445   CopyMem (&MnpDeviceData->VlanConfig, &mVlanConfigProtocolTemplate, sizeof (EFI_VLAN_CONFIG_PROTOCOL));
    446 
    447   //
    448   // Open the Simple Network protocol.
    449   //
    450   Status = gBS->OpenProtocol (
    451                   ControllerHandle,
    452                   &gEfiSimpleNetworkProtocolGuid,
    453                   (VOID **) &Snp,
    454                   ImageHandle,
    455                   ControllerHandle,
    456                   EFI_OPEN_PROTOCOL_BY_DRIVER
    457                   );
    458   if (EFI_ERROR (Status)) {
    459     return EFI_UNSUPPORTED;
    460   }
    461 
    462   //
    463   // Get MTU from Snp.
    464   //
    465   SnpMode            = Snp->Mode;
    466   MnpDeviceData->Snp = Snp;
    467 
    468   //
    469   // Initialize the lists.
    470   //
    471   InitializeListHead (&MnpDeviceData->ServiceList);
    472   InitializeListHead (&MnpDeviceData->GroupAddressList);
    473 
    474   //
    475   // Get the buffer length used to allocate NET_BUF to hold data received
    476   // from SNP. Do this before fill the FreeNetBufQue.
    477   //
    478   //
    479   MnpDeviceData->BufferLength = SnpMode->MediaHeaderSize + NET_VLAN_TAG_LEN + SnpMode->MaxPacketSize + NET_ETHER_FCS_SIZE;
    480 
    481   //
    482   // Make sure the protocol headers immediately following the media header
    483   // 4-byte aligned, and also preserve additional space for VLAN tag
    484   //
    485   MnpDeviceData->PaddingSize = ((4 - SnpMode->MediaHeaderSize) & 0x3) + NET_VLAN_TAG_LEN;
    486 
    487   //
    488   // Initialize MAC string which will be used as VLAN configuration variable name
    489   //
    490   Status = NetLibGetMacString (ControllerHandle, ImageHandle, &MnpDeviceData->MacString);
    491   if (EFI_ERROR (Status)) {
    492     goto ERROR;
    493   }
    494 
    495   //
    496   // Initialize the FreeNetBufQue and pre-allocate some NET_BUFs.
    497   //
    498   NetbufQueInit (&MnpDeviceData->FreeNbufQue);
    499   Status = MnpAddFreeNbuf (MnpDeviceData, MNP_INIT_NET_BUFFER_NUM);
    500   if (EFI_ERROR (Status)) {
    501     DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: MnpAddFreeNbuf failed, %r.\n", Status));
    502 
    503     goto ERROR;
    504   }
    505 
    506   //
    507   // Get one NET_BUF from the FreeNbufQue for rx cache.
    508   //
    509   MnpDeviceData->RxNbufCache = MnpAllocNbuf (MnpDeviceData);
    510   NetbufAllocSpace (
    511     MnpDeviceData->RxNbufCache,
    512     MnpDeviceData->BufferLength,
    513     NET_BUF_TAIL
    514     );
    515 
    516   //
    517   // Allocate buffer pool for tx.
    518   //
    519   InitializeListHead (&MnpDeviceData->FreeTxBufList);
    520   InitializeListHead (&MnpDeviceData->AllTxBufList);
    521   MnpDeviceData->TxBufCount = 0;
    522 
    523   //
    524   // Create the system poll timer.
    525   //
    526   Status = gBS->CreateEvent (
    527                   EVT_NOTIFY_SIGNAL | EVT_TIMER,
    528                   TPL_CALLBACK,
    529                   MnpSystemPoll,
    530                   MnpDeviceData,
    531                   &MnpDeviceData->PollTimer
    532                   );
    533   if (EFI_ERROR (Status)) {
    534     DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: CreateEvent for poll timer failed.\n"));
    535 
    536     goto ERROR;
    537   }
    538 
    539   //
    540   // Create the timer for packet timeout check.
    541   //
    542   Status = gBS->CreateEvent (
    543                   EVT_NOTIFY_SIGNAL | EVT_TIMER,
    544                   TPL_CALLBACK,
    545                   MnpCheckPacketTimeout,
    546                   MnpDeviceData,
    547                   &MnpDeviceData->TimeoutCheckTimer
    548                   );
    549   if (EFI_ERROR (Status)) {
    550     DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: CreateEvent for packet timeout check failed.\n"));
    551 
    552     goto ERROR;
    553   }
    554 
    555   //
    556   // Create the timer for media detection.
    557   //
    558   Status = gBS->CreateEvent (
    559                   EVT_NOTIFY_SIGNAL | EVT_TIMER,
    560                   TPL_CALLBACK,
    561                   MnpCheckMediaStatus,
    562                   MnpDeviceData,
    563                   &MnpDeviceData->MediaDetectTimer
    564                   );
    565   if (EFI_ERROR (Status)) {
    566     DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: CreateEvent for media detection failed.\n"));
    567 
    568     goto ERROR;
    569   }
    570 
    571 ERROR:
    572   if (EFI_ERROR (Status)) {
    573     //
    574     // Free the dynamic allocated resources if necessary.
    575     //
    576     if (MnpDeviceData->MacString != NULL) {
    577       FreePool (MnpDeviceData->MacString);
    578     }
    579 
    580     if (MnpDeviceData->TimeoutCheckTimer != NULL) {
    581       gBS->CloseEvent (MnpDeviceData->TimeoutCheckTimer);
    582     }
    583 
    584     if (MnpDeviceData->MediaDetectTimer != NULL) {
    585       gBS->CloseEvent (MnpDeviceData->MediaDetectTimer);
    586     }
    587 
    588     if (MnpDeviceData->PollTimer != NULL) {
    589       gBS->CloseEvent (MnpDeviceData->PollTimer);
    590     }
    591 
    592     if (MnpDeviceData->RxNbufCache != NULL) {
    593       MnpFreeNbuf (MnpDeviceData, MnpDeviceData->RxNbufCache);
    594     }
    595 
    596     if (MnpDeviceData->FreeNbufQue.BufNum != 0) {
    597       NetbufQueFlush (&MnpDeviceData->FreeNbufQue);
    598     }
    599 
    600     //
    601     // Close the Simple Network Protocol.
    602     //
    603     gBS->CloseProtocol (
    604           ControllerHandle,
    605           &gEfiSimpleNetworkProtocolGuid,
    606           ImageHandle,
    607           ControllerHandle
    608           );
    609   }
    610 
    611   return Status;
    612 }
    613 
    614 
    615 /**
    616   Destroy the MNP device context data.
    617 
    618   @param[in, out]  MnpDeviceData      Pointer to the mnp device context data.
    619   @param[in]       ImageHandle        The driver image handle.
    620 
    621 **/
    622 VOID
    623 MnpDestroyDeviceData (
    624   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,
    625   IN     EFI_HANDLE        ImageHandle
    626   )
    627 {
    628   LIST_ENTRY         *Entry;
    629   LIST_ENTRY         *NextEntry;
    630   MNP_TX_BUF_WRAP    *TxBufWrap;
    631 
    632   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
    633 
    634   //
    635   // Free Vlan Config variable name string
    636   //
    637   if (MnpDeviceData->MacString != NULL) {
    638     FreePool (MnpDeviceData->MacString);
    639   }
    640 
    641   //
    642   // The GroupAddressList must be empty.
    643   //
    644   ASSERT (IsListEmpty (&MnpDeviceData->GroupAddressList));
    645 
    646   //
    647   // Close the event.
    648   //
    649   gBS->CloseEvent (MnpDeviceData->TimeoutCheckTimer);
    650   gBS->CloseEvent (MnpDeviceData->MediaDetectTimer);
    651   gBS->CloseEvent (MnpDeviceData->PollTimer);
    652 
    653   //
    654   // Free the Tx buffer pool.
    655   //
    656   NET_LIST_FOR_EACH_SAFE(Entry, NextEntry, &MnpDeviceData->AllTxBufList) {
    657     TxBufWrap = NET_LIST_USER_STRUCT (Entry, MNP_TX_BUF_WRAP, AllEntry);
    658     RemoveEntryList (Entry);
    659     FreePool (TxBufWrap);
    660     MnpDeviceData->TxBufCount--;
    661   }
    662   ASSERT (IsListEmpty (&MnpDeviceData->AllTxBufList));
    663   ASSERT (MnpDeviceData->TxBufCount == 0);
    664 
    665   //
    666   // Free the RxNbufCache.
    667   //
    668   MnpFreeNbuf (MnpDeviceData, MnpDeviceData->RxNbufCache);
    669 
    670   //
    671   // Flush the FreeNbufQue.
    672   //
    673   MnpDeviceData->NbufCnt -= MnpDeviceData->FreeNbufQue.BufNum;
    674   NetbufQueFlush (&MnpDeviceData->FreeNbufQue);
    675 
    676   //
    677   // Close the Simple Network Protocol.
    678   //
    679   gBS->CloseProtocol (
    680          MnpDeviceData->ControllerHandle,
    681          &gEfiSimpleNetworkProtocolGuid,
    682          ImageHandle,
    683          MnpDeviceData->ControllerHandle
    684          );
    685 }
    686 
    687 
    688 /**
    689   Create mnp service context data.
    690 
    691   @param[in]       MnpDeviceData      Pointer to the mnp device context data.
    692   @param[in]       VlanId             The VLAN ID.
    693   @param[in]       Priority           The VLAN priority. If VlanId is 0,
    694                                       Priority is ignored.
    695 
    696   @return A pointer to MNP_SERVICE_DATA or NULL if failed to create MNP service context.
    697 
    698 **/
    699 MNP_SERVICE_DATA *
    700 MnpCreateServiceData (
    701   IN MNP_DEVICE_DATA     *MnpDeviceData,
    702   IN UINT16              VlanId,
    703   IN UINT8                Priority OPTIONAL
    704   )
    705 {
    706   EFI_HANDLE                MnpServiceHandle;
    707   MNP_SERVICE_DATA          *MnpServiceData;
    708   EFI_STATUS                Status;
    709   EFI_SIMPLE_NETWORK_MODE   *SnpMode;
    710   EFI_VLAN_CONFIG_PROTOCOL  *VlanConfig;
    711 
    712   //
    713   // Initialize the Mnp Service Data.
    714   //
    715   MnpServiceData = AllocateZeroPool (sizeof (MNP_SERVICE_DATA));
    716   if (MnpServiceData == NULL) {
    717     DEBUG ((EFI_D_ERROR, "MnpCreateServiceData: Faild to allocate memory for the new Mnp Service Data.\n"));
    718 
    719     return NULL;
    720   }
    721 
    722   //
    723   // Add to MNP service list
    724   //
    725   InsertTailList (&MnpDeviceData->ServiceList, &MnpServiceData->Link);
    726 
    727   MnpServiceData->Signature     = MNP_SERVICE_DATA_SIGNATURE;
    728   MnpServiceData->MnpDeviceData = MnpDeviceData;
    729 
    730   //
    731   // Copy the ServiceBinding structure.
    732   //
    733   CopyMem (&MnpServiceData->ServiceBinding, &mMnpServiceBindingProtocol, sizeof (EFI_SERVICE_BINDING_PROTOCOL));
    734 
    735   //
    736   // Initialize the lists.
    737   //
    738   InitializeListHead (&MnpServiceData->ChildrenList);
    739 
    740   SnpMode = MnpDeviceData->Snp->Mode;
    741   if (VlanId != 0) {
    742     //
    743     // Create VLAN child handle
    744     //
    745     MnpServiceHandle = MnpCreateVlanChild (
    746                          MnpDeviceData->ImageHandle,
    747                          MnpDeviceData->ControllerHandle,
    748                          VlanId,
    749                          &MnpServiceData->DevicePath
    750                          );
    751     if (MnpServiceHandle == NULL) {
    752       DEBUG ((EFI_D_ERROR, "MnpCreateServiceData: Faild to create child handle.\n"));
    753 
    754       return NULL;
    755     }
    756 
    757     //
    758     // Open VLAN Config Protocol by child
    759     //
    760     Status = gBS->OpenProtocol (
    761                     MnpDeviceData->ControllerHandle,
    762                     &gEfiVlanConfigProtocolGuid,
    763                     (VOID **) &VlanConfig,
    764                     MnpDeviceData->ImageHandle,
    765                     MnpServiceHandle,
    766                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    767                     );
    768     if (EFI_ERROR (Status)) {
    769       goto Exit;
    770     }
    771 
    772     //
    773     // Reduce MTU for VLAN device
    774     //
    775     MnpServiceData->Mtu = SnpMode->MaxPacketSize - NET_VLAN_TAG_LEN;
    776   } else {
    777     //
    778     // VlanId set to 0 means rx/tx untagged frame
    779     //
    780     MnpServiceHandle    = MnpDeviceData->ControllerHandle;
    781     MnpServiceData->Mtu = SnpMode->MaxPacketSize;
    782   }
    783 
    784   MnpServiceData->ServiceHandle = MnpServiceHandle;
    785   MnpServiceData->VlanId        = VlanId;
    786   MnpServiceData->Priority      = Priority;
    787 
    788   //
    789   // Install the MNP Service Binding Protocol
    790   //
    791   Status = gBS->InstallMultipleProtocolInterfaces (
    792                   &MnpServiceHandle,
    793                   &gEfiManagedNetworkServiceBindingProtocolGuid,
    794                   &MnpServiceData->ServiceBinding,
    795                   NULL
    796                   );
    797 
    798 Exit:
    799   if (EFI_ERROR (Status)) {
    800     MnpDestroyServiceData (MnpServiceData);
    801     MnpServiceData = NULL;
    802   }
    803 
    804   return MnpServiceData;
    805 }
    806 
    807 /**
    808   Destroy the MNP service context data.
    809 
    810   @param[in, out]  MnpServiceData    Pointer to the mnp service context data.
    811 
    812   @retval EFI_SUCCESS           The mnp service context is destroyed.
    813   @retval Others                Errors as indicated.
    814 
    815 **/
    816 EFI_STATUS
    817 MnpDestroyServiceData (
    818   IN OUT MNP_SERVICE_DATA    *MnpServiceData
    819   )
    820 {
    821   EFI_STATUS  Status;
    822 
    823   //
    824   // Uninstall the MNP Service Binding Protocol
    825   //
    826   Status = gBS->UninstallMultipleProtocolInterfaces (
    827                   MnpServiceData->ServiceHandle,
    828                   &gEfiManagedNetworkServiceBindingProtocolGuid,
    829                   &MnpServiceData->ServiceBinding,
    830                   NULL
    831                   );
    832   if (EFI_ERROR (Status)) {
    833     return Status;
    834   }
    835 
    836   if (MnpServiceData->VlanId != 0) {
    837     //
    838     // Close VlanConfig Protocol opened by VLAN child handle
    839     //
    840     Status = gBS->CloseProtocol (
    841                     MnpServiceData->MnpDeviceData->ControllerHandle,
    842                     &gEfiVlanConfigProtocolGuid,
    843                     MnpServiceData->MnpDeviceData->ImageHandle,
    844                     MnpServiceData->ServiceHandle
    845                     );
    846     if (EFI_ERROR (Status)) {
    847       return Status;
    848     }
    849 
    850     //
    851     // Uninstall Device Path Protocol to destroy the VLAN child handle
    852     //
    853     Status = gBS->UninstallMultipleProtocolInterfaces (
    854                     MnpServiceData->ServiceHandle,
    855                     &gEfiDevicePathProtocolGuid,
    856                     MnpServiceData->DevicePath,
    857                     NULL
    858                     );
    859     if (EFI_ERROR (Status)) {
    860       return Status;
    861     }
    862 
    863     if (MnpServiceData->DevicePath != NULL) {
    864       FreePool (MnpServiceData->DevicePath);
    865     }
    866   }
    867 
    868   //
    869   // Remove from MnpDeviceData service list
    870   //
    871   RemoveEntryList (&MnpServiceData->Link);
    872 
    873   FreePool (MnpServiceData);
    874 
    875   return Status;
    876 }
    877 
    878 /**
    879   Callback function which provided by user to remove one node in NetDestroyLinkList process.
    880 
    881   @param[in]    Entry           The entry to be removed.
    882   @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
    883 
    884   @retval EFI_SUCCESS           The entry has been removed successfully.
    885   @retval Others                Fail to remove the entry.
    886 
    887 **/
    888 EFI_STATUS
    889 EFIAPI
    890 MnpDestoryChildEntry (
    891   IN LIST_ENTRY         *Entry,
    892   IN VOID               *Context
    893   )
    894 {
    895   MNP_INSTANCE_DATA             *Instance;
    896   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
    897 
    898   ServiceBinding = (EFI_SERVICE_BINDING_PROTOCOL *) Context;
    899   Instance = CR (Entry, MNP_INSTANCE_DATA, InstEntry, MNP_INSTANCE_DATA_SIGNATURE);
    900   return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
    901 }
    902 
    903 /**
    904   Destroy all child of the MNP service data.
    905 
    906   @param[in, out]  MnpServiceData    Pointer to the mnp service context data.
    907 
    908   @retval EFI_SUCCESS           All child are destroyed.
    909   @retval Others                Failed to destroy all child.
    910 
    911 **/
    912 EFI_STATUS
    913 MnpDestroyServiceChild (
    914   IN OUT MNP_SERVICE_DATA    *MnpServiceData
    915   )
    916 {
    917   LIST_ENTRY                         *List;
    918   EFI_STATUS                         Status;
    919   UINTN                              ListLength;
    920 
    921   List = &MnpServiceData->ChildrenList;
    922 
    923   Status = NetDestroyLinkList (
    924              List,
    925              MnpDestoryChildEntry,
    926              &MnpServiceData->ServiceBinding,
    927              &ListLength
    928              );
    929   if (EFI_ERROR (Status) || ListLength != 0) {
    930     return EFI_DEVICE_ERROR;
    931   }
    932 
    933   return EFI_SUCCESS;
    934 }
    935 
    936 /**
    937   Find the MNP Service Data for given VLAN ID.
    938 
    939   @param[in]  MnpDeviceData      Pointer to the mnp device context data.
    940   @param[in]  VlanId             The VLAN ID.
    941 
    942   @return A pointer to MNP_SERVICE_DATA or NULL if not found.
    943 
    944 **/
    945 MNP_SERVICE_DATA *
    946 MnpFindServiceData (
    947   IN MNP_DEVICE_DATA     *MnpDeviceData,
    948   IN UINT16              VlanId
    949   )
    950 {
    951   LIST_ENTRY        *Entry;
    952   MNP_SERVICE_DATA  *MnpServiceData;
    953 
    954   NET_LIST_FOR_EACH (Entry, &MnpDeviceData->ServiceList) {
    955     //
    956     // Check VLAN ID of each Mnp Service Data
    957     //
    958     MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry);
    959     if (MnpServiceData->VlanId == VlanId) {
    960       return MnpServiceData;
    961     }
    962   }
    963 
    964   return NULL;
    965 }
    966 
    967 /**
    968   Initialize the mnp instance context data.
    969 
    970   @param[in]       MnpServiceData   Pointer to the mnp service context data.
    971   @param[in, out]  Instance         Pointer to the mnp instance context data
    972                                     to initialize.
    973 
    974 **/
    975 VOID
    976 MnpInitializeInstanceData (
    977   IN     MNP_SERVICE_DATA    *MnpServiceData,
    978   IN OUT MNP_INSTANCE_DATA   *Instance
    979   )
    980 {
    981   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
    982   ASSERT (Instance != NULL);
    983 
    984   //
    985   // Set the signature.
    986   //
    987   Instance->Signature = MNP_INSTANCE_DATA_SIGNATURE;
    988 
    989   //
    990   // Copy the MNP Protocol interfaces from the template.
    991   //
    992   CopyMem (&Instance->ManagedNetwork, &mMnpProtocolTemplate, sizeof (Instance->ManagedNetwork));
    993 
    994   //
    995   // Copy the default config data.
    996   //
    997   CopyMem (&Instance->ConfigData, &mMnpDefaultConfigData, sizeof (Instance->ConfigData));
    998 
    999   //
   1000   // Initialize the lists.
   1001   //
   1002   InitializeListHead (&Instance->GroupCtrlBlkList);
   1003   InitializeListHead (&Instance->RcvdPacketQueue);
   1004   InitializeListHead (&Instance->RxDeliveredPacketQueue);
   1005 
   1006   //
   1007   // Initialize the RxToken Map.
   1008   //
   1009   NetMapInit (&Instance->RxTokenMap);
   1010 
   1011   //
   1012   // Save the MnpServiceData info.
   1013   //
   1014   Instance->MnpServiceData = MnpServiceData;
   1015 }
   1016 
   1017 
   1018 /**
   1019   Check whether the token specified by Arg matches the token in Item.
   1020 
   1021   @param[in]  Map               Pointer to the NET_MAP.
   1022   @param[in]  Item              Pointer to the NET_MAP_ITEM.
   1023   @param[in]  Arg               Pointer to the Arg, it's a pointer to the token to
   1024                                 check.
   1025 
   1026   @retval EFI_SUCCESS           The token specified by Arg is different from the
   1027                                 token in Item.
   1028   @retval EFI_ACCESS_DENIED     The token specified by Arg is the same as that in
   1029                                 Item.
   1030 
   1031 **/
   1032 EFI_STATUS
   1033 EFIAPI
   1034 MnpTokenExist (
   1035   IN NET_MAP         *Map,
   1036   IN NET_MAP_ITEM    *Item,
   1037   IN VOID            *Arg
   1038   )
   1039 {
   1040   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token;
   1041   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TokenInItem;
   1042 
   1043   Token       = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Arg;
   1044   TokenInItem = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Item->Key;
   1045 
   1046   if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
   1047     //
   1048     // The token is the same either the two tokens equals or the Events in
   1049     // the two tokens are the same.
   1050     //
   1051     return EFI_ACCESS_DENIED;
   1052   }
   1053 
   1054   return EFI_SUCCESS;
   1055 }
   1056 
   1057 /**
   1058   Cancel the token specified by Arg if it matches the token in Item.
   1059 
   1060   @param[in, out]  Map               Pointer to the NET_MAP.
   1061   @param[in, out]  Item              Pointer to the NET_MAP_ITEM.
   1062   @param[in]       Arg               Pointer to the Arg, it's a pointer to the
   1063                                      token to cancel.
   1064 
   1065   @retval EFI_SUCCESS       The Arg is NULL, and the token in Item is cancelled,
   1066                             or the Arg isn't NULL, and the token in Item is
   1067                             different from the Arg.
   1068   @retval EFI_ABORTED       The Arg isn't NULL, the token in Item mathces the
   1069                             Arg, and the token is cancelled.
   1070 
   1071 **/
   1072 EFI_STATUS
   1073 EFIAPI
   1074 MnpCancelTokens (
   1075   IN OUT NET_MAP         *Map,
   1076   IN OUT NET_MAP_ITEM    *Item,
   1077   IN     VOID            *Arg
   1078   )
   1079 {
   1080   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TokenToCancel;
   1081 
   1082   if ((Arg != NULL) && (Item->Key != Arg)) {
   1083     //
   1084     // The token in Item is not the token specified by Arg.
   1085     //
   1086     return EFI_SUCCESS;
   1087   }
   1088 
   1089   TokenToCancel = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Item->Key;
   1090 
   1091   //
   1092   // Remove the item from the map.
   1093   //
   1094   NetMapRemoveItem (Map, Item, NULL);
   1095 
   1096   //
   1097   // Cancel this token with status set to EFI_ABORTED.
   1098   //
   1099   TokenToCancel->Status = EFI_ABORTED;
   1100   gBS->SignalEvent (TokenToCancel->Event);
   1101 
   1102   if (Arg != NULL) {
   1103     //
   1104     // Only abort the token specified by Arg if Arg isn't NULL.
   1105     //
   1106     return EFI_ABORTED;
   1107   }
   1108 
   1109   return EFI_SUCCESS;
   1110 }
   1111 
   1112 
   1113 /**
   1114   Start and initialize the simple network.
   1115 
   1116   @param[in]  Snp               Pointer to the simple network protocol.
   1117 
   1118   @retval EFI_SUCCESS           The simple network protocol is started.
   1119   @retval Others                Other errors as indicated.
   1120 
   1121 **/
   1122 EFI_STATUS
   1123 MnpStartSnp (
   1124   IN EFI_SIMPLE_NETWORK_PROTOCOL     *Snp
   1125   )
   1126 {
   1127   EFI_STATUS  Status;
   1128 
   1129   ASSERT (Snp != NULL);
   1130 
   1131   //
   1132   // Start the simple network.
   1133   //
   1134   Status = Snp->Start (Snp);
   1135 
   1136   if (!EFI_ERROR (Status)) {
   1137     //
   1138     // Initialize the simple network.
   1139     //
   1140     Status = Snp->Initialize (Snp, 0, 0);
   1141   }
   1142 
   1143   return Status;
   1144 }
   1145 
   1146 
   1147 /**
   1148   Stop the simple network.
   1149 
   1150   @param[in]  MnpDeviceData     Pointer to the MNP_DEVICE_DATA.
   1151 
   1152   @retval EFI_SUCCESS           The simple network is stopped.
   1153   @retval Others                Other errors as indicated.
   1154 
   1155 **/
   1156 EFI_STATUS
   1157 MnpStopSnp (
   1158   IN  MNP_DEVICE_DATA   *MnpDeviceData
   1159   )
   1160 {
   1161   EFI_STATUS  Status;
   1162   EFI_SIMPLE_NETWORK_PROTOCOL     *Snp;
   1163 
   1164   Snp = MnpDeviceData->Snp;
   1165   ASSERT (Snp != NULL);
   1166 
   1167   //
   1168   // Recycle all the transmit buffer from SNP.
   1169   //
   1170   Status = MnpRecycleTxBuf (MnpDeviceData);
   1171   if (EFI_ERROR (Status)) {
   1172     return Status;
   1173   }
   1174 
   1175   //
   1176   // Shut down the simple network.
   1177   //
   1178   Status  = Snp->Shutdown (Snp);
   1179   if (!EFI_ERROR (Status)) {
   1180     //
   1181     // Stop the simple network.
   1182     //
   1183     Status = Snp->Stop (Snp);
   1184   }
   1185 
   1186   return Status;
   1187 }
   1188 
   1189 
   1190 /**
   1191   Start the managed network, this function is called when one instance is configured
   1192   or reconfigured.
   1193 
   1194   @param[in, out]  MnpServiceData       Pointer to the mnp service context data.
   1195   @param[in]       IsConfigUpdate       The instance is reconfigured or it's the first
   1196                                         time the instanced is configured.
   1197   @param[in]       EnableSystemPoll     Enable the system polling or not.
   1198 
   1199   @retval EFI_SUCCESS                   The managed network is started and some
   1200                                         configuration is updated.
   1201   @retval Others                        Other errors as indicated.
   1202 
   1203 **/
   1204 EFI_STATUS
   1205 MnpStart (
   1206   IN OUT MNP_SERVICE_DATA    *MnpServiceData,
   1207   IN     BOOLEAN             IsConfigUpdate,
   1208   IN     BOOLEAN             EnableSystemPoll
   1209   )
   1210 {
   1211   EFI_STATUS      Status;
   1212   EFI_TIMER_DELAY TimerOpType;
   1213   MNP_DEVICE_DATA *MnpDeviceData;
   1214 
   1215   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
   1216 
   1217   Status        = EFI_SUCCESS;
   1218   MnpDeviceData = MnpServiceData->MnpDeviceData;
   1219 
   1220   if (!IsConfigUpdate) {
   1221     //
   1222     // If it's not a configuration update, increase the configured children number.
   1223     //
   1224     MnpDeviceData->ConfiguredChildrenNumber++;
   1225 
   1226     if (MnpDeviceData->ConfiguredChildrenNumber == 1) {
   1227       //
   1228       // It's the first configured child, start the simple network.
   1229       //
   1230       Status = MnpStartSnp (MnpDeviceData->Snp);
   1231       if (EFI_ERROR (Status)) {
   1232         DEBUG ((EFI_D_ERROR, "MnpStart: MnpStartSnp failed, %r.\n", Status));
   1233 
   1234         goto ErrorExit;
   1235       }
   1236 
   1237       //
   1238       // Start the timeout timer.
   1239       //
   1240       Status = gBS->SetTimer (
   1241                       MnpDeviceData->TimeoutCheckTimer,
   1242                       TimerPeriodic,
   1243                       MNP_TIMEOUT_CHECK_INTERVAL
   1244                       );
   1245       if (EFI_ERROR (Status)) {
   1246         DEBUG (
   1247           (EFI_D_ERROR,
   1248           "MnpStart, gBS->SetTimer for TimeoutCheckTimer %r.\n",
   1249           Status)
   1250           );
   1251 
   1252         goto ErrorExit;
   1253       }
   1254 
   1255       //
   1256       // Start the media detection timer.
   1257       //
   1258       Status = gBS->SetTimer (
   1259                       MnpDeviceData->MediaDetectTimer,
   1260                       TimerPeriodic,
   1261                       MNP_MEDIA_DETECT_INTERVAL
   1262                       );
   1263       if (EFI_ERROR (Status)) {
   1264         DEBUG (
   1265           (EFI_D_ERROR,
   1266           "MnpStart, gBS->SetTimer for MediaDetectTimer %r.\n",
   1267           Status)
   1268           );
   1269 
   1270         goto ErrorExit;
   1271       }
   1272     }
   1273   }
   1274 
   1275   if (MnpDeviceData->EnableSystemPoll ^ EnableSystemPoll) {
   1276     //
   1277     // The EnableSystemPoll differs with the current state, disable or enable
   1278     // the system poll.
   1279     //
   1280     TimerOpType = EnableSystemPoll ? TimerPeriodic : TimerCancel;
   1281 
   1282     Status      = gBS->SetTimer (MnpDeviceData->PollTimer, TimerOpType, MNP_SYS_POLL_INTERVAL);
   1283     if (EFI_ERROR (Status)) {
   1284       DEBUG ((EFI_D_ERROR, "MnpStart: gBS->SetTimer for PollTimer failed, %r.\n", Status));
   1285 
   1286       goto ErrorExit;
   1287     }
   1288 
   1289     MnpDeviceData->EnableSystemPoll = EnableSystemPoll;
   1290   }
   1291 
   1292   //
   1293   // Change the receive filters if need.
   1294   //
   1295   Status = MnpConfigReceiveFilters (MnpDeviceData);
   1296 
   1297 ErrorExit:
   1298   return Status;
   1299 }
   1300 
   1301 
   1302 /**
   1303   Stop the managed network.
   1304 
   1305   @param[in, out]  MnpServiceData    Pointer to the mnp service context data.
   1306 
   1307   @retval EFI_SUCCESS                The managed network is stopped.
   1308   @retval Others                     Other errors as indicated.
   1309 
   1310 **/
   1311 EFI_STATUS
   1312 MnpStop (
   1313   IN OUT MNP_SERVICE_DATA    *MnpServiceData
   1314   )
   1315 {
   1316   EFI_STATUS      Status;
   1317   MNP_DEVICE_DATA *MnpDeviceData;
   1318 
   1319   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
   1320   MnpDeviceData = MnpServiceData->MnpDeviceData;
   1321   ASSERT (MnpDeviceData->ConfiguredChildrenNumber > 0);
   1322 
   1323   //
   1324   // Configure the receive filters.
   1325   //
   1326   MnpConfigReceiveFilters (MnpDeviceData);
   1327 
   1328   //
   1329   // Decrease the children number.
   1330   //
   1331   MnpDeviceData->ConfiguredChildrenNumber--;
   1332 
   1333   if (MnpDeviceData->ConfiguredChildrenNumber > 0) {
   1334     //
   1335     // If there are other configured chilren, return and keep the timers and
   1336     // simple network unchanged.
   1337     //
   1338     return EFI_SUCCESS;
   1339   }
   1340 
   1341   //
   1342   // No configured children now.
   1343   //
   1344   if (MnpDeviceData->EnableSystemPoll) {
   1345     //
   1346     //  The system poll in on, cancel the poll timer.
   1347     //
   1348     Status  = gBS->SetTimer (MnpDeviceData->PollTimer, TimerCancel, 0);
   1349     MnpDeviceData->EnableSystemPoll = FALSE;
   1350   }
   1351 
   1352   //
   1353   // Cancel the timeout timer.
   1354   //
   1355   Status = gBS->SetTimer (MnpDeviceData->TimeoutCheckTimer, TimerCancel, 0);
   1356 
   1357   //
   1358   // Cancel the media detect timer.
   1359   //
   1360   Status = gBS->SetTimer (MnpDeviceData->MediaDetectTimer, TimerCancel, 0);
   1361 
   1362   //
   1363   // Stop the simple network.
   1364   //
   1365   Status = MnpStopSnp (MnpDeviceData);
   1366   return Status;
   1367 }
   1368 
   1369 
   1370 /**
   1371   Flush the instance's received data.
   1372 
   1373   @param[in, out]  Instance              Pointer to the mnp instance context data.
   1374 
   1375 **/
   1376 VOID
   1377 MnpFlushRcvdDataQueue (
   1378   IN OUT MNP_INSTANCE_DATA   *Instance
   1379   )
   1380 {
   1381   EFI_TPL         OldTpl;
   1382   MNP_RXDATA_WRAP *RxDataWrap;
   1383 
   1384   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
   1385 
   1386   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   1387 
   1388   while (!IsListEmpty (&Instance->RcvdPacketQueue)) {
   1389     //
   1390     // Remove all the Wraps.
   1391     //
   1392     RxDataWrap = NET_LIST_HEAD (&Instance->RcvdPacketQueue, MNP_RXDATA_WRAP, WrapEntry);
   1393 
   1394     //
   1395     // Recycle the RxDataWrap.
   1396     //
   1397     MnpRecycleRxData (NULL, (VOID *) RxDataWrap);
   1398     Instance->RcvdPacketQueueSize--;
   1399   }
   1400 
   1401   ASSERT (Instance->RcvdPacketQueueSize == 0);
   1402 
   1403   gBS->RestoreTPL (OldTpl);
   1404 }
   1405 
   1406 
   1407 /**
   1408   Configure the Instance using ConfigData.
   1409 
   1410   @param[in, out]  Instance     Pointer to the mnp instance context data.
   1411   @param[in]       ConfigData   Pointer to the configuration data used to configure
   1412                                 the isntance.
   1413 
   1414   @retval EFI_SUCCESS           The Instance is configured.
   1415   @retval EFI_UNSUPPORTED       EnableReceiveTimestamps is on and the
   1416                                 implementation doesn't support it.
   1417   @retval Others                Other errors as indicated.
   1418 
   1419 **/
   1420 EFI_STATUS
   1421 MnpConfigureInstance (
   1422   IN OUT MNP_INSTANCE_DATA                 *Instance,
   1423   IN     EFI_MANAGED_NETWORK_CONFIG_DATA   *ConfigData OPTIONAL
   1424   )
   1425 {
   1426   EFI_STATUS                      Status;
   1427   MNP_SERVICE_DATA                *MnpServiceData;
   1428   MNP_DEVICE_DATA                 *MnpDeviceData;
   1429   EFI_MANAGED_NETWORK_CONFIG_DATA *OldConfigData;
   1430   EFI_MANAGED_NETWORK_CONFIG_DATA *NewConfigData;
   1431   BOOLEAN                         IsConfigUpdate;
   1432 
   1433   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
   1434 
   1435   if ((ConfigData != NULL) && ConfigData->EnableReceiveTimestamps) {
   1436     //
   1437     // Don't support timestamp.
   1438     //
   1439     return EFI_UNSUPPORTED;
   1440   }
   1441 
   1442   Status          = EFI_SUCCESS;
   1443 
   1444   MnpServiceData  = Instance->MnpServiceData;
   1445   MnpDeviceData   = MnpServiceData->MnpDeviceData;
   1446   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
   1447 
   1448   IsConfigUpdate  = (BOOLEAN) ((Instance->Configured) && (ConfigData != NULL));
   1449 
   1450   OldConfigData   = &Instance->ConfigData;
   1451   NewConfigData   = ConfigData;
   1452   if (NewConfigData == NULL) {
   1453     //
   1454     // Restore back the default config data if a reset of this instance
   1455     // is required.
   1456     //
   1457     NewConfigData = &mMnpDefaultConfigData;
   1458   }
   1459 
   1460   //
   1461   // Reset the instance's receive filter.
   1462   //
   1463   Instance->ReceiveFilter = 0;
   1464 
   1465   //
   1466   // Clear the receive counters according to the old ConfigData.
   1467   //
   1468   if (OldConfigData->EnableUnicastReceive) {
   1469     MnpDeviceData->UnicastCount--;
   1470   }
   1471 
   1472   if (OldConfigData->EnableMulticastReceive) {
   1473     MnpDeviceData->MulticastCount--;
   1474   }
   1475 
   1476   if (OldConfigData->EnableBroadcastReceive) {
   1477     MnpDeviceData->BroadcastCount--;
   1478   }
   1479 
   1480   if (OldConfigData->EnablePromiscuousReceive) {
   1481     MnpDeviceData->PromiscuousCount--;
   1482   }
   1483 
   1484   //
   1485   // Set the receive filter counters and the receive filter of the
   1486   // instance according to the new ConfigData.
   1487   //
   1488   if (NewConfigData->EnableUnicastReceive) {
   1489     MnpDeviceData->UnicastCount++;
   1490     Instance->ReceiveFilter |= MNP_RECEIVE_UNICAST;
   1491   }
   1492 
   1493   if (NewConfigData->EnableMulticastReceive) {
   1494     MnpDeviceData->MulticastCount++;
   1495   }
   1496 
   1497   if (NewConfigData->EnableBroadcastReceive) {
   1498     MnpDeviceData->BroadcastCount++;
   1499     Instance->ReceiveFilter |= MNP_RECEIVE_BROADCAST;
   1500   }
   1501 
   1502   if (NewConfigData->EnablePromiscuousReceive) {
   1503     MnpDeviceData->PromiscuousCount++;
   1504   }
   1505 
   1506   if (OldConfigData->FlushQueuesOnReset) {
   1507     MnpFlushRcvdDataQueue (Instance);
   1508   }
   1509 
   1510   if (ConfigData == NULL) {
   1511     Instance->ManagedNetwork.Cancel (&Instance->ManagedNetwork, NULL);
   1512   }
   1513 
   1514   if (!NewConfigData->EnableMulticastReceive) {
   1515     MnpGroupOp (Instance, FALSE, NULL, NULL);
   1516   }
   1517 
   1518   //
   1519   // Save the new configuration data.
   1520   //
   1521   CopyMem (OldConfigData, NewConfigData, sizeof (*OldConfigData));
   1522 
   1523   Instance->Configured = (BOOLEAN) (ConfigData != NULL);
   1524   if (Instance->Configured) {
   1525     //
   1526     // The instance is configured, start the Mnp.
   1527     //
   1528     Status = MnpStart (
   1529               MnpServiceData,
   1530               IsConfigUpdate,
   1531               (BOOLEAN) !NewConfigData->DisableBackgroundPolling
   1532               );
   1533   } else {
   1534     //
   1535     // The instance is changed to the unconfigured state, stop the Mnp.
   1536     //
   1537     Status = MnpStop (MnpServiceData);
   1538   }
   1539 
   1540   return Status;
   1541 }
   1542 
   1543 /**
   1544   Configure the Snp receive filters according to the instances' receive filter
   1545   settings.
   1546 
   1547   @param[in]  MnpDeviceData         Pointer to the mnp device context data.
   1548 
   1549   @retval     EFI_SUCCESS           The receive filters is configured.
   1550   @retval     EFI_OUT_OF_RESOURCES  The receive filters can't be configured due
   1551                                     to lack of memory resource.
   1552 
   1553 **/
   1554 EFI_STATUS
   1555 MnpConfigReceiveFilters (
   1556   IN MNP_DEVICE_DATA     *MnpDeviceData
   1557   )
   1558 {
   1559   EFI_STATUS                  Status;
   1560   EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
   1561   EFI_MAC_ADDRESS             *MCastFilter;
   1562   UINT32                      MCastFilterCnt;
   1563   UINT32                      EnableFilterBits;
   1564   UINT32                      DisableFilterBits;
   1565   BOOLEAN                     ResetMCastFilters;
   1566   LIST_ENTRY                  *Entry;
   1567   UINT32                      Index;
   1568   MNP_GROUP_ADDRESS           *GroupAddress;
   1569 
   1570   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
   1571 
   1572   Snp = MnpDeviceData->Snp;
   1573 
   1574   //
   1575   // Initialize the enable filter and disable filter.
   1576   //
   1577   EnableFilterBits  = 0;
   1578   DisableFilterBits = Snp->Mode->ReceiveFilterMask;
   1579 
   1580   if (MnpDeviceData->UnicastCount != 0) {
   1581     //
   1582     // Enable unicast if any instance wants to receive unicast.
   1583     //
   1584     EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
   1585   }
   1586 
   1587   if (MnpDeviceData->BroadcastCount != 0) {
   1588     //
   1589     // Enable broadcast if any instance wants to receive broadcast.
   1590     //
   1591     EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
   1592   }
   1593 
   1594   MCastFilter       = NULL;
   1595   MCastFilterCnt    = 0;
   1596   ResetMCastFilters = TRUE;
   1597 
   1598   if ((MnpDeviceData->MulticastCount != 0) && (MnpDeviceData->GroupAddressCount != 0)) {
   1599     //
   1600     // There are instances configured to receive multicast and already some group
   1601     // addresses are joined.
   1602     //
   1603 
   1604     ResetMCastFilters = FALSE;
   1605 
   1606     if (MnpDeviceData->GroupAddressCount <= Snp->Mode->MaxMCastFilterCount) {
   1607       //
   1608       // The joind group address is less than simple network's maximum count.
   1609       // Just configure the snp to do the multicast filtering.
   1610       //
   1611 
   1612       EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
   1613 
   1614       //
   1615       // Allocate pool for the mulicast addresses.
   1616       //
   1617       MCastFilterCnt  = MnpDeviceData->GroupAddressCount;
   1618       MCastFilter     = AllocatePool (sizeof (EFI_MAC_ADDRESS) * MCastFilterCnt);
   1619       if (MCastFilter == NULL) {
   1620         DEBUG ((EFI_D_ERROR, "MnpConfigReceiveFilters: Failed to allocate memory resource for MCastFilter.\n"));
   1621 
   1622         return EFI_OUT_OF_RESOURCES;
   1623       }
   1624 
   1625       //
   1626       // Fill the multicast HW address buffer.
   1627       //
   1628       Index = 0;
   1629       NET_LIST_FOR_EACH (Entry, &MnpDeviceData->GroupAddressList) {
   1630 
   1631         GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);
   1632         CopyMem (MCastFilter + Index, &GroupAddress->Address, sizeof (*(MCastFilter + Index)));
   1633         Index++;
   1634 
   1635         ASSERT (Index <= MCastFilterCnt);
   1636       }
   1637     } else {
   1638       //
   1639       // The maximum multicast is reached, set the filter to be promiscuous
   1640       // multicast.
   1641       //
   1642 
   1643       if ((Snp->Mode->ReceiveFilterMask & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
   1644         EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
   1645       } else {
   1646         //
   1647         // Either MULTICAST or PROMISCUOUS_MULTICAST is not supported by Snp,
   1648         // set the NIC to be promiscuous although this will tremendously degrade
   1649         // the performance.
   1650         //
   1651         EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
   1652       }
   1653     }
   1654   }
   1655 
   1656   if (MnpDeviceData->PromiscuousCount != 0) {
   1657     //
   1658     // Enable promiscuous if any instance wants to receive promiscuous.
   1659     //
   1660     EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
   1661   }
   1662 
   1663   //
   1664   // Set the disable filter.
   1665   //
   1666   DisableFilterBits ^= EnableFilterBits;
   1667 
   1668   //
   1669   // Configure the receive filters of SNP.
   1670   //
   1671   Status = Snp->ReceiveFilters (
   1672                   Snp,
   1673                   EnableFilterBits,
   1674                   DisableFilterBits,
   1675                   ResetMCastFilters,
   1676                   MCastFilterCnt,
   1677                   MCastFilter
   1678                   );
   1679   DEBUG_CODE (
   1680     if (EFI_ERROR (Status)) {
   1681       DEBUG (
   1682         (EFI_D_ERROR,
   1683         "MnpConfigReceiveFilters: Snp->ReceiveFilters failed, %r.\n",
   1684         Status)
   1685         );
   1686     }
   1687   );
   1688 
   1689   if (MCastFilter != NULL) {
   1690     //
   1691     // Free the buffer used to hold the group addresses.
   1692     //
   1693     FreePool (MCastFilter);
   1694   }
   1695 
   1696   return Status;
   1697 }
   1698 
   1699 
   1700 /**
   1701   Add a group address control block which controls the MacAddress for
   1702   this instance.
   1703 
   1704   @param[in, out]  Instance        Pointer to the mnp instance context data.
   1705   @param[in, out]  CtrlBlk         Pointer to the group address control block.
   1706   @param[in, out]  GroupAddress    Pointer to the group adress.
   1707   @param[in]       MacAddress      Pointer to the mac address.
   1708   @param[in]       HwAddressSize   The hardware address size.
   1709 
   1710   @retval EFI_SUCCESS              The group address control block is added.
   1711   @retval EFI_OUT_OF_RESOURCES     Failed due to lack of memory resources.
   1712 
   1713 **/
   1714 EFI_STATUS
   1715 MnpGroupOpAddCtrlBlk (
   1716   IN OUT MNP_INSTANCE_DATA         *Instance,
   1717   IN OUT MNP_GROUP_CONTROL_BLOCK   *CtrlBlk,
   1718   IN OUT MNP_GROUP_ADDRESS         *GroupAddress OPTIONAL,
   1719   IN     EFI_MAC_ADDRESS           *MacAddress,
   1720   IN     UINT32                    HwAddressSize
   1721   )
   1722 {
   1723   MNP_DEVICE_DATA  *MnpDeviceData;
   1724 
   1725   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
   1726 
   1727   MnpDeviceData = Instance->MnpServiceData->MnpDeviceData;
   1728   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
   1729 
   1730   if (GroupAddress == NULL) {
   1731     ASSERT (MacAddress != NULL);
   1732 
   1733     //
   1734     // Allocate a new GroupAddress to be added into MNP's GroupAddressList.
   1735     //
   1736     GroupAddress = AllocatePool (sizeof (MNP_GROUP_ADDRESS));
   1737     if (GroupAddress == NULL) {
   1738 
   1739       DEBUG ((EFI_D_ERROR, "MnpGroupOpFormCtrlBlk: Failed to allocate memory resource.\n"));
   1740 
   1741       return EFI_OUT_OF_RESOURCES;
   1742     }
   1743 
   1744     CopyMem (&GroupAddress->Address, MacAddress, sizeof (GroupAddress->Address));
   1745     GroupAddress->RefCnt = 0;
   1746     InsertTailList (
   1747       &MnpDeviceData->GroupAddressList,
   1748       &GroupAddress->AddrEntry
   1749       );
   1750     MnpDeviceData->GroupAddressCount++;
   1751   }
   1752 
   1753   //
   1754   // Increase the RefCnt.
   1755   //
   1756   GroupAddress->RefCnt++;
   1757 
   1758   //
   1759   // Add the CtrlBlk into the instance's GroupCtrlBlkList.
   1760   //
   1761   CtrlBlk->GroupAddress = GroupAddress;
   1762   InsertTailList (&Instance->GroupCtrlBlkList, &CtrlBlk->CtrlBlkEntry);
   1763 
   1764   return EFI_SUCCESS;
   1765 }
   1766 
   1767 
   1768 /**
   1769   Delete a group control block from the instance. If the controlled group address's
   1770   reference count reaches zero, the group address is removed too.
   1771 
   1772   @param[in]  Instance              Pointer to the instance context data.
   1773   @param[in]  CtrlBlk               Pointer to the group control block to delete.
   1774 
   1775   @return The group address controlled by the control block is no longer used or not.
   1776 
   1777 **/
   1778 BOOLEAN
   1779 MnpGroupOpDelCtrlBlk (
   1780   IN MNP_INSTANCE_DATA           *Instance,
   1781   IN MNP_GROUP_CONTROL_BLOCK     *CtrlBlk
   1782   )
   1783 {
   1784   MNP_DEVICE_DATA   *MnpDeviceData;
   1785   MNP_GROUP_ADDRESS *GroupAddress;
   1786 
   1787   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
   1788 
   1789   MnpDeviceData = Instance->MnpServiceData->MnpDeviceData;
   1790   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
   1791 
   1792   //
   1793   // Remove and free the CtrlBlk.
   1794   //
   1795   GroupAddress = CtrlBlk->GroupAddress;
   1796   RemoveEntryList (&CtrlBlk->CtrlBlkEntry);
   1797   FreePool (CtrlBlk);
   1798 
   1799   ASSERT (GroupAddress->RefCnt > 0);
   1800 
   1801   //
   1802   // Count down the RefCnt.
   1803   //
   1804   GroupAddress->RefCnt--;
   1805 
   1806   if (GroupAddress->RefCnt == 0) {
   1807     //
   1808     // Free this GroupAddress entry if no instance uses it.
   1809     //
   1810     MnpDeviceData->GroupAddressCount--;
   1811     RemoveEntryList (&GroupAddress->AddrEntry);
   1812     FreePool (GroupAddress);
   1813 
   1814     return TRUE;
   1815   }
   1816 
   1817   return FALSE;
   1818 }
   1819 
   1820 
   1821 /**
   1822   Do the group operations for this instance.
   1823 
   1824   @param[in, out]  Instance        Pointer to the instance context data.
   1825   @param[in]       JoinFlag        Set to TRUE to join a group. Set to TRUE to
   1826                                    leave a group/groups.
   1827   @param[in]       MacAddress      Pointer to the group address to join or leave.
   1828   @param[in]       CtrlBlk         Pointer to the group control block if JoinFlag
   1829                                    is FALSE.
   1830 
   1831   @retval EFI_SUCCESS              The group operation finished.
   1832   @retval EFI_OUT_OF_RESOURCES     Failed due to lack of memory resources.
   1833   @retval Others                   Other errors as indicated.
   1834 
   1835 **/
   1836 EFI_STATUS
   1837 MnpGroupOp (
   1838   IN OUT MNP_INSTANCE_DATA         *Instance,
   1839   IN     BOOLEAN                   JoinFlag,
   1840   IN     EFI_MAC_ADDRESS           *MacAddress OPTIONAL,
   1841   IN     MNP_GROUP_CONTROL_BLOCK   *CtrlBlk OPTIONAL
   1842   )
   1843 {
   1844   MNP_DEVICE_DATA         *MnpDeviceData;
   1845   LIST_ENTRY              *Entry;
   1846   LIST_ENTRY              *NextEntry;
   1847   MNP_GROUP_ADDRESS       *GroupAddress;
   1848   EFI_SIMPLE_NETWORK_MODE *SnpMode;
   1849   MNP_GROUP_CONTROL_BLOCK *NewCtrlBlk;
   1850   EFI_STATUS              Status;
   1851   BOOLEAN                 AddressExist;
   1852   BOOLEAN                 NeedUpdate;
   1853 
   1854   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
   1855 
   1856   MnpDeviceData = Instance->MnpServiceData->MnpDeviceData;
   1857   SnpMode       = MnpDeviceData->Snp->Mode;
   1858 
   1859   if (JoinFlag) {
   1860     //
   1861     // A new gropu address is to be added.
   1862     //
   1863     GroupAddress  = NULL;
   1864     AddressExist  = FALSE;
   1865 
   1866     //
   1867     // Allocate memory for the control block.
   1868     //
   1869     NewCtrlBlk = AllocatePool (sizeof (MNP_GROUP_CONTROL_BLOCK));
   1870     if (NewCtrlBlk == NULL) {
   1871       DEBUG ((EFI_D_ERROR, "MnpGroupOp: Failed to allocate memory resource.\n"));
   1872 
   1873       return EFI_OUT_OF_RESOURCES;
   1874     }
   1875 
   1876     NET_LIST_FOR_EACH (Entry, &MnpDeviceData->GroupAddressList) {
   1877       //
   1878       // Check whether the MacAddress is already joined by other instances.
   1879       //
   1880       GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);
   1881       if (CompareMem (MacAddress, &GroupAddress->Address, SnpMode->HwAddressSize) == 0) {
   1882         AddressExist = TRUE;
   1883         break;
   1884       }
   1885     }
   1886 
   1887     if (!AddressExist) {
   1888       GroupAddress = NULL;
   1889     }
   1890 
   1891     //
   1892     // Add the GroupAddress for this instance.
   1893     //
   1894     Status = MnpGroupOpAddCtrlBlk (
   1895               Instance,
   1896               NewCtrlBlk,
   1897               GroupAddress,
   1898               MacAddress,
   1899               SnpMode->HwAddressSize
   1900               );
   1901     if (EFI_ERROR (Status)) {
   1902       return Status;
   1903     }
   1904 
   1905     NeedUpdate = TRUE;
   1906   } else {
   1907     if (MacAddress != NULL) {
   1908       ASSERT (CtrlBlk != NULL);
   1909 
   1910       //
   1911       // Leave the specific multicast mac address.
   1912       //
   1913       NeedUpdate = MnpGroupOpDelCtrlBlk (Instance, CtrlBlk);
   1914     } else {
   1915       //
   1916       // Leave all multicast mac addresses.
   1917       //
   1918       NeedUpdate = FALSE;
   1919 
   1920       NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->GroupCtrlBlkList) {
   1921 
   1922         NewCtrlBlk = NET_LIST_USER_STRUCT (
   1923                       Entry,
   1924                       MNP_GROUP_CONTROL_BLOCK,
   1925                       CtrlBlkEntry
   1926                       );
   1927         //
   1928         // Update is required if the group address left is no longer used
   1929         // by other instances.
   1930         //
   1931         NeedUpdate = MnpGroupOpDelCtrlBlk (Instance, NewCtrlBlk);
   1932       }
   1933     }
   1934   }
   1935 
   1936   Status = EFI_SUCCESS;
   1937 
   1938   if (NeedUpdate) {
   1939     //
   1940     // Reconfigure the receive filters if necessary.
   1941     //
   1942     Status = MnpConfigReceiveFilters (MnpDeviceData);
   1943   }
   1944 
   1945   return Status;
   1946 }
   1947