git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10418 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1729 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1729 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Implementation of Managed Network Protocol private services.
 | |
| 
 | |
| Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>
 | |
| This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions
 | |
| of the BSD License which accompanies this distribution.  The full
 | |
| text of the license may be found at<BR>
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "MnpImpl.h"
 | |
| #include "MnpVlan.h"
 | |
| 
 | |
| EFI_SERVICE_BINDING_PROTOCOL    mMnpServiceBindingProtocol = {
 | |
|   MnpServiceBindingCreateChild,
 | |
|   MnpServiceBindingDestroyChild
 | |
| };
 | |
| 
 | |
| EFI_MANAGED_NETWORK_PROTOCOL    mMnpProtocolTemplate = {
 | |
|   MnpGetModeData,
 | |
|   MnpConfigure,
 | |
|   MnpMcastIpToMac,
 | |
|   MnpGroups,
 | |
|   MnpTransmit,
 | |
|   MnpReceive,
 | |
|   MnpCancel,
 | |
|   MnpPoll
 | |
| };
 | |
| 
 | |
| EFI_MANAGED_NETWORK_CONFIG_DATA mMnpDefaultConfigData = {
 | |
|   10000000,
 | |
|   10000000,
 | |
|   0,
 | |
|   FALSE,
 | |
|   FALSE,
 | |
|   FALSE,
 | |
|   FALSE,
 | |
|   FALSE,
 | |
|   FALSE,
 | |
|   FALSE
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Add Count of net buffers to MnpDeviceData->FreeNbufQue. The length of the net
 | |
|   buffer is specified by MnpDeviceData->BufferLength.
 | |
| 
 | |
|   @param[in, out]  MnpDeviceData         Pointer to the MNP_DEVICE_DATA.
 | |
|   @param[in]       Count                 Number of NET_BUFFERs to add.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The specified amount of NET_BUFs are allocated
 | |
|                                 and added to MnpDeviceData->FreeNbufQue.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Failed to allocate a NET_BUF structure.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| MnpAddFreeNbuf (
 | |
|   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,
 | |
|   IN     UINTN             Count
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINTN       Index;
 | |
|   NET_BUF     *Nbuf;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
 | |
|   ASSERT ((Count > 0) && (MnpDeviceData->BufferLength > 0));
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
|   for (Index = 0; Index < Count; Index++) {
 | |
|     Nbuf = NetbufAlloc (MnpDeviceData->BufferLength + MnpDeviceData->PaddingSize);
 | |
|     if (Nbuf == NULL) {
 | |
|       DEBUG ((EFI_D_ERROR, "MnpAddFreeNbuf: NetBufAlloc failed.\n"));
 | |
| 
 | |
|       Status = EFI_OUT_OF_RESOURCES;
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if (MnpDeviceData->PaddingSize > 0) {
 | |
|       //
 | |
|       // Pad padding bytes before the media header
 | |
|       //
 | |
|       NetbufAllocSpace (Nbuf, MnpDeviceData->PaddingSize, NET_BUF_TAIL);
 | |
|       NetbufTrim (Nbuf, MnpDeviceData->PaddingSize, NET_BUF_HEAD);
 | |
|     }
 | |
| 
 | |
|     NetbufQueAppend (&MnpDeviceData->FreeNbufQue, Nbuf);
 | |
|   }
 | |
| 
 | |
|   MnpDeviceData->NbufCnt += Index;
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Allocate a free NET_BUF from MnpDeviceData->FreeNbufQue. If there is none
 | |
|   in the queue, first try to allocate some and add them into the queue, then
 | |
|   fetch the NET_BUF from the updated FreeNbufQue.
 | |
| 
 | |
|   @param[in, out]  MnpDeviceData        Pointer to the MNP_DEVICE_DATA.
 | |
| 
 | |
|   @return     Pointer to the allocated free NET_BUF structure, if NULL the
 | |
|               operation is failed.
 | |
| 
 | |
| **/
 | |
| NET_BUF *
 | |
| MnpAllocNbuf (
 | |
|   IN OUT MNP_DEVICE_DATA   *MnpDeviceData
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS    Status;
 | |
|   NET_BUF_QUEUE *FreeNbufQue;
 | |
|   NET_BUF       *Nbuf;
 | |
|   EFI_TPL       OldTpl;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
 | |
| 
 | |
|   FreeNbufQue = &MnpDeviceData->FreeNbufQue;
 | |
|   OldTpl      = gBS->RaiseTPL (TPL_NOTIFY);
 | |
| 
 | |
|   //
 | |
|   // Check whether there are available buffers, or else try to add some.
 | |
|   //
 | |
|   if (FreeNbufQue->BufNum == 0) {
 | |
|     if ((MnpDeviceData->NbufCnt + MNP_NET_BUFFER_INCREASEMENT) > MNP_MAX_NET_BUFFER_NUM) {
 | |
|       DEBUG (
 | |
|         (EFI_D_ERROR,
 | |
|         "MnpAllocNbuf: The maximum NET_BUF size is reached for MNP driver instance %p.\n",
 | |
|         MnpDeviceData)
 | |
|         );
 | |
| 
 | |
|       Nbuf = NULL;
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     Status = MnpAddFreeNbuf (MnpDeviceData, MNP_NET_BUFFER_INCREASEMENT);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG (
 | |
|         (EFI_D_ERROR,
 | |
|         "MnpAllocNbuf: Failed to add NET_BUFs into the FreeNbufQue, %r.\n",
 | |
|         Status)
 | |
|         );
 | |
| 
 | |
|       //
 | |
|       // Don't return NULL, perhaps MnpAddFreeNbuf does add some NET_BUFs but
 | |
|       // the amount is less than MNP_NET_BUFFER_INCREASEMENT.
 | |
|       //
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Nbuf = NetbufQueRemove (FreeNbufQue);
 | |
| 
 | |
|   //
 | |
|   // Increase the RefCnt.
 | |
|   //
 | |
|   if (Nbuf != NULL) {
 | |
|     NET_GET_REF (Nbuf);
 | |
|   }
 | |
| 
 | |
| ON_EXIT:
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
| 
 | |
|   return Nbuf;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Try to reclaim the Nbuf into the buffer pool.
 | |
| 
 | |
|   @param[in, out]  MnpDeviceData         Pointer to the mnp device context data.
 | |
|   @param[in, out]  Nbuf                  Pointer to the NET_BUF to free.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| MnpFreeNbuf (
 | |
|   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,
 | |
|   IN OUT NET_BUF           *Nbuf
 | |
|   )
 | |
| {
 | |
|   EFI_TPL  OldTpl;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
 | |
|   ASSERT (Nbuf->RefCnt > 1);
 | |
| 
 | |
|   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
 | |
| 
 | |
|   NET_PUT_REF (Nbuf);
 | |
| 
 | |
|   if (Nbuf->RefCnt == 1) {
 | |
|     //
 | |
|     // Trim all buffer contained in the Nbuf, then append it to the NbufQue.
 | |
|     //
 | |
|     NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_TAIL);
 | |
| 
 | |
|     if (NetbufAllocSpace (Nbuf, NET_VLAN_TAG_LEN, NET_BUF_HEAD) != NULL) {
 | |
|       //
 | |
|       // There is space reserved for vlan tag in the head, reclaim it
 | |
|       //
 | |
|       NetbufTrim (Nbuf, NET_VLAN_TAG_LEN, NET_BUF_TAIL);
 | |
|     }
 | |
| 
 | |
|     NetbufQueAppend (&MnpDeviceData->FreeNbufQue, Nbuf);
 | |
|   }
 | |
| 
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Initialize the mnp device context data.
 | |
| 
 | |
|   @param[in, out]  MnpDeviceData      Pointer to the mnp device context data.
 | |
|   @param[in]       ImageHandle        The driver image handle.
 | |
|   @param[in]       ControllerHandle   Handle of device to bind driver to.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The mnp service context is initialized.
 | |
|   @retval EFI_UNSUPPORTED       ControllerHandle does not support Simple Network Protocol.
 | |
|   @retval Others                Other errors as indicated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| MnpInitializeDeviceData (
 | |
|   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,
 | |
|   IN     EFI_HANDLE        ImageHandle,
 | |
|   IN     EFI_HANDLE        ControllerHandle
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
 | |
|   EFI_SIMPLE_NETWORK_MODE     *SnpMode;
 | |
| 
 | |
|   MnpDeviceData->Signature        = MNP_DEVICE_DATA_SIGNATURE;
 | |
|   MnpDeviceData->ImageHandle      = ImageHandle;
 | |
|   MnpDeviceData->ControllerHandle = ControllerHandle;
 | |
| 
 | |
|   //
 | |
|   // Copy the MNP Protocol interfaces from the template.
 | |
|   //
 | |
|   CopyMem (&MnpDeviceData->VlanConfig, &mVlanConfigProtocolTemplate, sizeof (EFI_VLAN_CONFIG_PROTOCOL));
 | |
| 
 | |
|   //
 | |
|   // Open the Simple Network protocol.
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   &gEfiSimpleNetworkProtocolGuid,
 | |
|                   (VOID **) &Snp,
 | |
|                   ImageHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get MTU from Snp.
 | |
|   //
 | |
|   SnpMode            = Snp->Mode;
 | |
|   MnpDeviceData->Snp = Snp;
 | |
| 
 | |
|   //
 | |
|   // Initialize the lists.
 | |
|   //
 | |
|   InitializeListHead (&MnpDeviceData->ServiceList);
 | |
|   InitializeListHead (&MnpDeviceData->GroupAddressList);
 | |
| 
 | |
|   //
 | |
|   // Get the buffer length used to allocate NET_BUF to hold data received
 | |
|   // from SNP. Do this before fill the FreeNetBufQue.
 | |
|   //
 | |
|   //
 | |
|   MnpDeviceData->BufferLength = SnpMode->MediaHeaderSize + NET_VLAN_TAG_LEN + SnpMode->MaxPacketSize + NET_ETHER_FCS_SIZE;
 | |
| 
 | |
|   //
 | |
|   // Make sure the protocol headers immediately following the media header
 | |
|   // 4-byte aligned, and also preserve additional space for VLAN tag
 | |
|   //
 | |
|   MnpDeviceData->PaddingSize = ((4 - SnpMode->MediaHeaderSize) & 0x3) + NET_VLAN_TAG_LEN;
 | |
| 
 | |
|   //
 | |
|   // Initialize MAC string which will be used as VLAN configuration variable name
 | |
|   //
 | |
|   Status = NetLibGetMacString (ControllerHandle, ImageHandle, &MnpDeviceData->MacString);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Initialize the FreeNetBufQue and pre-allocate some NET_BUFs.
 | |
|   //
 | |
|   NetbufQueInit (&MnpDeviceData->FreeNbufQue);
 | |
|   Status = MnpAddFreeNbuf (MnpDeviceData, MNP_INIT_NET_BUFFER_NUM);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: MnpAddFreeNbuf failed, %r.\n", Status));
 | |
| 
 | |
|     goto ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get one NET_BUF from the FreeNbufQue for rx cache.
 | |
|   //
 | |
|   MnpDeviceData->RxNbufCache = MnpAllocNbuf (MnpDeviceData);
 | |
|   NetbufAllocSpace (
 | |
|     MnpDeviceData->RxNbufCache,
 | |
|     MnpDeviceData->BufferLength,
 | |
|     NET_BUF_TAIL
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Allocate buffer pool for tx.
 | |
|   //
 | |
|   MnpDeviceData->TxBuf = AllocatePool (MnpDeviceData->BufferLength);
 | |
|   if (MnpDeviceData->TxBuf == NULL) {
 | |
|     DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: AllocatePool failed.\n"));
 | |
| 
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create the system poll timer.
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL | EVT_TIMER,
 | |
|                   TPL_CALLBACK,
 | |
|                   MnpSystemPoll,
 | |
|                   MnpDeviceData,
 | |
|                   &MnpDeviceData->PollTimer
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: CreateEvent for poll timer failed.\n"));
 | |
| 
 | |
|     goto ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create the timer for packet timeout check.
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL | EVT_TIMER,
 | |
|                   TPL_CALLBACK,
 | |
|                   MnpCheckPacketTimeout,
 | |
|                   MnpDeviceData,
 | |
|                   &MnpDeviceData->TimeoutCheckTimer
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: CreateEvent for packet timeout check failed.\n"));
 | |
| 
 | |
|     goto ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create the timer for media detection.
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL | EVT_TIMER,
 | |
|                   TPL_CALLBACK,
 | |
|                   MnpCheckMediaStatus,
 | |
|                   MnpDeviceData,
 | |
|                   &MnpDeviceData->MediaDetectTimer
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: CreateEvent for media detection failed.\n"));
 | |
| 
 | |
|     goto ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create the timer for tx timeout check.
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_TIMER,
 | |
|                   TPL_CALLBACK,
 | |
|                   NULL,
 | |
|                   NULL,
 | |
|                   &MnpDeviceData->TxTimeoutEvent
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: CreateEvent for tx timeout event failed.\n"));
 | |
|   }
 | |
| 
 | |
| ERROR:
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Free the dynamic allocated resources if necessary.
 | |
|     //
 | |
|     if (MnpDeviceData->MacString != NULL) {
 | |
|       FreePool (MnpDeviceData->MacString);
 | |
|     }
 | |
| 
 | |
|     if (MnpDeviceData->TimeoutCheckTimer != NULL) {
 | |
|       gBS->CloseEvent (MnpDeviceData->TimeoutCheckTimer);
 | |
|     }
 | |
| 
 | |
|     if (MnpDeviceData->MediaDetectTimer != NULL) {
 | |
|       gBS->CloseEvent (MnpDeviceData->MediaDetectTimer);
 | |
|     }
 | |
| 
 | |
|     if (MnpDeviceData->PollTimer != NULL) {
 | |
|       gBS->CloseEvent (MnpDeviceData->PollTimer);
 | |
|     }
 | |
| 
 | |
|     if (MnpDeviceData->TxBuf != NULL) {
 | |
|       FreePool (MnpDeviceData->TxBuf);
 | |
|     }
 | |
| 
 | |
|     if (MnpDeviceData->RxNbufCache != NULL) {
 | |
|       MnpFreeNbuf (MnpDeviceData, MnpDeviceData->RxNbufCache);
 | |
|     }
 | |
| 
 | |
|     if (MnpDeviceData->FreeNbufQue.BufNum != 0) {
 | |
|       NetbufQueFlush (&MnpDeviceData->FreeNbufQue);
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Close the Simple Network Protocol.
 | |
|     //
 | |
|     gBS->CloseProtocol (
 | |
|           ControllerHandle,
 | |
|           &gEfiSimpleNetworkProtocolGuid,
 | |
|           ImageHandle,
 | |
|           ControllerHandle
 | |
|           );
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Destroy the MNP device context data.
 | |
| 
 | |
|   @param[in, out]  MnpDeviceData      Pointer to the mnp device context data.
 | |
|   @param[in]       ImageHandle        The driver image handle.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| MnpDestroyDeviceData (
 | |
|   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,
 | |
|   IN     EFI_HANDLE        ImageHandle
 | |
|   )
 | |
| {
 | |
|   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
 | |
| 
 | |
|   //
 | |
|   // Free Vlan Config variable name string
 | |
|   //
 | |
|   if (MnpDeviceData->MacString != NULL) {
 | |
|     FreePool (MnpDeviceData->MacString);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // The GroupAddressList must be empty.
 | |
|   //
 | |
|   ASSERT (IsListEmpty (&MnpDeviceData->GroupAddressList));
 | |
| 
 | |
|   //
 | |
|   // Close the event.
 | |
|   //
 | |
|   gBS->CloseEvent (MnpDeviceData->TxTimeoutEvent);
 | |
|   gBS->CloseEvent (MnpDeviceData->TimeoutCheckTimer);
 | |
|   gBS->CloseEvent (MnpDeviceData->MediaDetectTimer);
 | |
|   gBS->CloseEvent (MnpDeviceData->PollTimer);
 | |
| 
 | |
|   //
 | |
|   // Free the tx buffer.
 | |
|   //
 | |
|   FreePool (MnpDeviceData->TxBuf);
 | |
| 
 | |
|   //
 | |
|   // Free the RxNbufCache.
 | |
|   //
 | |
|   MnpFreeNbuf (MnpDeviceData, MnpDeviceData->RxNbufCache);
 | |
| 
 | |
|   //
 | |
|   // Flush the FreeNbufQue.
 | |
|   //
 | |
|   MnpDeviceData->NbufCnt -= MnpDeviceData->FreeNbufQue.BufNum;
 | |
|   NetbufQueFlush (&MnpDeviceData->FreeNbufQue);
 | |
| 
 | |
|   //
 | |
|   // Close the Simple Network Protocol.
 | |
|   //
 | |
|   gBS->CloseProtocol (
 | |
|          MnpDeviceData->ControllerHandle,
 | |
|          &gEfiSimpleNetworkProtocolGuid,
 | |
|          ImageHandle,
 | |
|          MnpDeviceData->ControllerHandle
 | |
|          );
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Create mnp service context data.
 | |
| 
 | |
|   @param[in]       MnpDeviceData      Pointer to the mnp device context data.
 | |
|   @param[in]       VlanId             The VLAN ID.
 | |
|   @param[in]       Priority           The VLAN priority. If VlanId is 0,
 | |
|                                       Priority is ignored.
 | |
| 
 | |
|   @return A pointer to MNP_SERVICE_DATA or NULL if failed to create MNP service context.
 | |
| 
 | |
| **/
 | |
| MNP_SERVICE_DATA *
 | |
| MnpCreateServiceData (
 | |
|   IN MNP_DEVICE_DATA     *MnpDeviceData,
 | |
|   IN UINT16              VlanId,
 | |
|   IN UINT8                Priority OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_HANDLE                MnpServiceHandle;
 | |
|   MNP_SERVICE_DATA          *MnpServiceData;
 | |
|   EFI_STATUS                Status;
 | |
|   EFI_SIMPLE_NETWORK_MODE   *SnpMode;
 | |
|   EFI_VLAN_CONFIG_PROTOCOL  *VlanConfig;
 | |
| 
 | |
|   //
 | |
|   // Initialize the Mnp Service Data.
 | |
|   //
 | |
|   MnpServiceData = AllocateZeroPool (sizeof (MNP_SERVICE_DATA));
 | |
|   if (MnpServiceData == NULL) {
 | |
|     DEBUG ((EFI_D_ERROR, "MnpCreateServiceData: Faild to allocate memory for the new Mnp Service Data.\n"));
 | |
| 
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Add to MNP service list
 | |
|   //
 | |
|   InsertTailList (&MnpDeviceData->ServiceList, &MnpServiceData->Link);
 | |
| 
 | |
|   MnpServiceData->Signature     = MNP_SERVICE_DATA_SIGNATURE;
 | |
|   MnpServiceData->MnpDeviceData = MnpDeviceData;
 | |
| 
 | |
|   //
 | |
|   // Copy the ServiceBinding structure.
 | |
|   //
 | |
|   CopyMem (&MnpServiceData->ServiceBinding, &mMnpServiceBindingProtocol, sizeof (EFI_SERVICE_BINDING_PROTOCOL));
 | |
| 
 | |
|   //
 | |
|   // Initialize the lists.
 | |
|   //
 | |
|   InitializeListHead (&MnpServiceData->ChildrenList);
 | |
| 
 | |
|   SnpMode = MnpDeviceData->Snp->Mode;
 | |
|   if (VlanId != 0) {
 | |
|     //
 | |
|     // Create VLAN child handle
 | |
|     //
 | |
|     MnpServiceHandle = MnpCreateVlanChild (
 | |
|                          MnpDeviceData->ImageHandle,
 | |
|                          MnpDeviceData->ControllerHandle,
 | |
|                          VlanId,
 | |
|                          &MnpServiceData->DevicePath
 | |
|                          );
 | |
|     if (MnpServiceHandle == NULL) {
 | |
|       DEBUG ((EFI_D_ERROR, "MnpCreateServiceData: Faild to create child handle.\n"));
 | |
| 
 | |
|       return NULL;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Open VLAN Config Protocol by child
 | |
|     //
 | |
|     Status = gBS->OpenProtocol (
 | |
|                     MnpDeviceData->ControllerHandle,
 | |
|                     &gEfiVlanConfigProtocolGuid,
 | |
|                     (VOID **) &VlanConfig,
 | |
|                     MnpDeviceData->ImageHandle,
 | |
|                     MnpServiceHandle,
 | |
|                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Exit;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Reduce MTU for VLAN device
 | |
|     //
 | |
|     MnpServiceData->Mtu = SnpMode->MaxPacketSize - NET_VLAN_TAG_LEN;
 | |
|   } else {
 | |
|     //
 | |
|     // VlanId set to 0 means rx/tx untagged frame
 | |
|     //
 | |
|     MnpServiceHandle    = MnpDeviceData->ControllerHandle;
 | |
|     MnpServiceData->Mtu = SnpMode->MaxPacketSize;
 | |
|   }
 | |
| 
 | |
|   MnpServiceData->ServiceHandle = MnpServiceHandle;
 | |
|   MnpServiceData->VlanId        = VlanId;
 | |
|   MnpServiceData->Priority      = Priority;
 | |
| 
 | |
|   //
 | |
|   // Install the MNP Service Binding Protocol
 | |
|   //
 | |
|   Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                   &MnpServiceHandle,
 | |
|                   &gEfiManagedNetworkServiceBindingProtocolGuid,
 | |
|                   &MnpServiceData->ServiceBinding,
 | |
|                   NULL
 | |
|                   );
 | |
| 
 | |
| Exit:
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     MnpDestroyServiceData (MnpServiceData);
 | |
|     MnpServiceData = NULL;
 | |
|   }
 | |
| 
 | |
|   return MnpServiceData;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Destroy the MNP service context data.
 | |
| 
 | |
|   @param[in, out]  MnpServiceData    Pointer to the mnp service context data.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The mnp service context is destroyed.
 | |
|   @retval Others                Errors as indicated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| MnpDestroyServiceData (
 | |
|   IN OUT MNP_SERVICE_DATA    *MnpServiceData
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   //
 | |
|   // Uninstall the MNP Service Binding Protocol
 | |
|   //
 | |
|   Status = gBS->UninstallMultipleProtocolInterfaces (
 | |
|                   MnpServiceData->ServiceHandle,
 | |
|                   &gEfiManagedNetworkServiceBindingProtocolGuid,
 | |
|                   &MnpServiceData->ServiceBinding,
 | |
|                   NULL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (MnpServiceData->VlanId != 0) {
 | |
|     //
 | |
|     // Close VlanConfig Protocol opened by VLAN child handle
 | |
|     //
 | |
|     Status = gBS->CloseProtocol (
 | |
|                     MnpServiceData->MnpDeviceData->ControllerHandle,
 | |
|                     &gEfiVlanConfigProtocolGuid,
 | |
|                     MnpServiceData->MnpDeviceData->ImageHandle,
 | |
|                     MnpServiceData->ServiceHandle
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Uninstall Device Path Protocol to destroy the VLAN child handle
 | |
|     //
 | |
|     Status = gBS->UninstallMultipleProtocolInterfaces (
 | |
|                     MnpServiceData->ServiceHandle,
 | |
|                     &gEfiDevicePathProtocolGuid,
 | |
|                     MnpServiceData->DevicePath,
 | |
|                     NULL
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     if (MnpServiceData->DevicePath != NULL) {
 | |
|       FreePool (MnpServiceData->DevicePath);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Remove from MnpDeviceData service list
 | |
|   //
 | |
|   RemoveEntryList (&MnpServiceData->Link);
 | |
| 
 | |
|   FreePool (MnpServiceData);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Destroy all child of the MNP service data.
 | |
| 
 | |
|   @param[in, out]  MnpServiceData    Pointer to the mnp service context data.
 | |
| 
 | |
|   @retval EFI_SUCCESS           All child are destroyed.
 | |
|   @retval Others                Failed to destroy all child.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| MnpDestroyServiceChild (
 | |
|   IN OUT MNP_SERVICE_DATA    *MnpServiceData
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   MNP_INSTANCE_DATA             *Instance;
 | |
|   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
 | |
| 
 | |
|   ServiceBinding = &MnpServiceData->ServiceBinding;
 | |
|   while (!IsListEmpty (&MnpServiceData->ChildrenList)) {
 | |
|     //
 | |
|     // Don't use NetListRemoveHead here, the remove opreration will be done
 | |
|     // in ServiceBindingDestroyChild.
 | |
|     //
 | |
|     Instance = NET_LIST_HEAD (
 | |
|                  &MnpServiceData->ChildrenList,
 | |
|                  MNP_INSTANCE_DATA,
 | |
|                  InstEntry
 | |
|                  );
 | |
| 
 | |
|     Status = ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Find the MNP Service Data for given VLAN ID.
 | |
| 
 | |
|   @param[in]  MnpDeviceData      Pointer to the mnp device context data.
 | |
|   @param[in]  VlanId             The VLAN ID.
 | |
| 
 | |
|   @return A pointer to MNP_SERVICE_DATA or NULL if not found.
 | |
| 
 | |
| **/
 | |
| MNP_SERVICE_DATA *
 | |
| MnpFindServiceData (
 | |
|   IN MNP_DEVICE_DATA     *MnpDeviceData,
 | |
|   IN UINT16              VlanId
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY        *Entry;
 | |
|   MNP_SERVICE_DATA  *MnpServiceData;
 | |
| 
 | |
|   NET_LIST_FOR_EACH (Entry, &MnpDeviceData->ServiceList) {
 | |
|     //
 | |
|     // Check VLAN ID of each Mnp Service Data
 | |
|     //
 | |
|     MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry);
 | |
|     if (MnpServiceData->VlanId == VlanId) {
 | |
|       return MnpServiceData;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize the mnp instance context data.
 | |
| 
 | |
|   @param[in]       MnpServiceData   Pointer to the mnp service context data.
 | |
|   @param[in, out]  Instance         Pointer to the mnp instance context data
 | |
|                                     to initialize.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| MnpInitializeInstanceData (
 | |
|   IN     MNP_SERVICE_DATA    *MnpServiceData,
 | |
|   IN OUT MNP_INSTANCE_DATA   *Instance
 | |
|   )
 | |
| {
 | |
|   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
 | |
|   ASSERT (Instance != NULL);
 | |
| 
 | |
|   //
 | |
|   // Set the signature.
 | |
|   //
 | |
|   Instance->Signature = MNP_INSTANCE_DATA_SIGNATURE;
 | |
| 
 | |
|   //
 | |
|   // Copy the MNP Protocol interfaces from the template.
 | |
|   //
 | |
|   CopyMem (&Instance->ManagedNetwork, &mMnpProtocolTemplate, sizeof (Instance->ManagedNetwork));
 | |
| 
 | |
|   //
 | |
|   // Copy the default config data.
 | |
|   //
 | |
|   CopyMem (&Instance->ConfigData, &mMnpDefaultConfigData, sizeof (Instance->ConfigData));
 | |
| 
 | |
|   //
 | |
|   // Initialize the lists.
 | |
|   //
 | |
|   InitializeListHead (&Instance->GroupCtrlBlkList);
 | |
|   InitializeListHead (&Instance->RcvdPacketQueue);
 | |
|   InitializeListHead (&Instance->RxDeliveredPacketQueue);
 | |
| 
 | |
|   //
 | |
|   // Initialize the RxToken Map.
 | |
|   //
 | |
|   NetMapInit (&Instance->RxTokenMap);
 | |
| 
 | |
|   //
 | |
|   // Save the MnpServiceData info.
 | |
|   //
 | |
|   Instance->MnpServiceData = MnpServiceData;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Check whether the token specified by Arg matches the token in Item.
 | |
| 
 | |
|   @param[in]  Map               Pointer to the NET_MAP.
 | |
|   @param[in]  Item              Pointer to the NET_MAP_ITEM.
 | |
|   @param[in]  Arg               Pointer to the Arg, it's a pointer to the token to
 | |
|                                 check.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The token specified by Arg is different from the
 | |
|                                 token in Item.
 | |
|   @retval EFI_ACCESS_DENIED     The token specified by Arg is the same as that in
 | |
|                                 Item.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MnpTokenExist (
 | |
|   IN NET_MAP         *Map,
 | |
|   IN NET_MAP_ITEM    *Item,
 | |
|   IN VOID            *Arg
 | |
|   )
 | |
| {
 | |
|   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token;
 | |
|   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TokenInItem;
 | |
| 
 | |
|   Token       = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Arg;
 | |
|   TokenInItem = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Item->Key;
 | |
| 
 | |
|   if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
 | |
|     //
 | |
|     // The token is the same either the two tokens equals or the Events in
 | |
|     // the two tokens are the same.
 | |
|     //
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Cancel the token specified by Arg if it matches the token in Item.
 | |
| 
 | |
|   @param[in, out]  Map               Pointer to the NET_MAP.
 | |
|   @param[in, out]  Item              Pointer to the NET_MAP_ITEM.
 | |
|   @param[in]       Arg               Pointer to the Arg, it's a pointer to the
 | |
|                                      token to cancel.
 | |
| 
 | |
|   @retval EFI_SUCCESS       The Arg is NULL, and the token in Item is cancelled,
 | |
|                             or the Arg isn't NULL, and the token in Item is
 | |
|                             different from the Arg.
 | |
|   @retval EFI_ABORTED       The Arg isn't NULL, the token in Item mathces the
 | |
|                             Arg, and the token is cancelled.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MnpCancelTokens (
 | |
|   IN OUT NET_MAP         *Map,
 | |
|   IN OUT NET_MAP_ITEM    *Item,
 | |
|   IN     VOID            *Arg
 | |
|   )
 | |
| {
 | |
|   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TokenToCancel;
 | |
| 
 | |
|   if ((Arg != NULL) && (Item->Key != Arg)) {
 | |
|     //
 | |
|     // The token in Item is not the token specified by Arg.
 | |
|     //
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   TokenToCancel = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Item->Key;
 | |
| 
 | |
|   //
 | |
|   // Remove the item from the map.
 | |
|   //
 | |
|   NetMapRemoveItem (Map, Item, NULL);
 | |
| 
 | |
|   //
 | |
|   // Cancel this token with status set to EFI_ABORTED.
 | |
|   //
 | |
|   TokenToCancel->Status = EFI_ABORTED;
 | |
|   gBS->SignalEvent (TokenToCancel->Event);
 | |
| 
 | |
|   if (Arg != NULL) {
 | |
|     //
 | |
|     // Only abort the token specified by Arg if Arg isn't NULL.
 | |
|     //
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Start and initialize the simple network.
 | |
| 
 | |
|   @param[in]  Snp               Pointer to the simple network protocol.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The simple network protocol is started.
 | |
|   @retval Others                Other errors as indicated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| MnpStartSnp (
 | |
|   IN EFI_SIMPLE_NETWORK_PROTOCOL     *Snp
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   ASSERT (Snp != NULL);
 | |
| 
 | |
|   //
 | |
|   // Start the simple network.
 | |
|   //
 | |
|   Status = Snp->Start (Snp);
 | |
| 
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Initialize the simple network.
 | |
|     //
 | |
|     Status = Snp->Initialize (Snp, 0, 0);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Stop the simple network.
 | |
| 
 | |
|   @param[in]  Snp               Pointer to the simple network protocol.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The simple network is stopped.
 | |
|   @retval Others                Other errors as indicated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| MnpStopSnp (
 | |
|   IN EFI_SIMPLE_NETWORK_PROTOCOL     *Snp
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   ASSERT (Snp != NULL);
 | |
| 
 | |
|   //
 | |
|   // Shut down the simple network.
 | |
|   //
 | |
|   Status  = Snp->Shutdown (Snp);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Stop the simple network.
 | |
|     //
 | |
|     Status = Snp->Stop (Snp);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Start the managed network, this function is called when one instance is configured
 | |
|   or reconfigured.
 | |
| 
 | |
|   @param[in, out]  MnpServiceData       Pointer to the mnp service context data.
 | |
|   @param[in]       IsConfigUpdate       The instance is reconfigured or it's the first
 | |
|                                         time the instanced is configured.
 | |
|   @param[in]       EnableSystemPoll     Enable the system polling or not.
 | |
| 
 | |
|   @retval EFI_SUCCESS                   The managed network is started and some
 | |
|                                         configuration is updated.
 | |
|   @retval Others                        Other errors as indicated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| MnpStart (
 | |
|   IN OUT MNP_SERVICE_DATA    *MnpServiceData,
 | |
|   IN     BOOLEAN             IsConfigUpdate,
 | |
|   IN     BOOLEAN             EnableSystemPoll
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS      Status;
 | |
|   EFI_TIMER_DELAY TimerOpType;
 | |
|   MNP_DEVICE_DATA *MnpDeviceData;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
 | |
| 
 | |
|   Status        = EFI_SUCCESS;
 | |
|   MnpDeviceData = MnpServiceData->MnpDeviceData;
 | |
| 
 | |
|   if (!IsConfigUpdate) {
 | |
|     //
 | |
|     // If it's not a configuration update, increase the configured children number.
 | |
|     //
 | |
|     MnpDeviceData->ConfiguredChildrenNumber++;
 | |
| 
 | |
|     if (MnpDeviceData->ConfiguredChildrenNumber == 1) {
 | |
|       //
 | |
|       // It's the first configured child, start the simple network.
 | |
|       //
 | |
|       Status = MnpStartSnp (MnpDeviceData->Snp);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         DEBUG ((EFI_D_ERROR, "MnpStart: MnpStartSnp failed, %r.\n", Status));
 | |
| 
 | |
|         goto ErrorExit;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Start the timeout timer.
 | |
|       //
 | |
|       Status = gBS->SetTimer (
 | |
|                       MnpDeviceData->TimeoutCheckTimer,
 | |
|                       TimerPeriodic,
 | |
|                       MNP_TIMEOUT_CHECK_INTERVAL
 | |
|                       );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         DEBUG (
 | |
|           (EFI_D_ERROR,
 | |
|           "MnpStart, gBS->SetTimer for TimeoutCheckTimer %r.\n",
 | |
|           Status)
 | |
|           );
 | |
| 
 | |
|         goto ErrorExit;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Start the media detection timer.
 | |
|       //
 | |
|       Status = gBS->SetTimer (
 | |
|                       MnpDeviceData->MediaDetectTimer,
 | |
|                       TimerPeriodic,
 | |
|                       MNP_MEDIA_DETECT_INTERVAL
 | |
|                       );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         DEBUG (
 | |
|           (EFI_D_ERROR,
 | |
|           "MnpStart, gBS->SetTimer for MediaDetectTimer %r.\n",
 | |
|           Status)
 | |
|           );
 | |
| 
 | |
|         goto ErrorExit;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (MnpDeviceData->EnableSystemPoll ^ EnableSystemPoll) {
 | |
|     //
 | |
|     // The EnableSystemPoll differs with the current state, disable or enable
 | |
|     // the system poll.
 | |
|     //
 | |
|     TimerOpType = EnableSystemPoll ? TimerPeriodic : TimerCancel;
 | |
| 
 | |
|     Status      = gBS->SetTimer (MnpDeviceData->PollTimer, TimerOpType, MNP_SYS_POLL_INTERVAL);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "MnpStart: gBS->SetTimer for PollTimer failed, %r.\n", Status));
 | |
| 
 | |
|       goto ErrorExit;
 | |
|     }
 | |
| 
 | |
|     MnpDeviceData->EnableSystemPoll = EnableSystemPoll;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Change the receive filters if need.
 | |
|   //
 | |
|   Status = MnpConfigReceiveFilters (MnpDeviceData);
 | |
| 
 | |
| ErrorExit:
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Stop the managed network.
 | |
| 
 | |
|   @param[in, out]  MnpServiceData    Pointer to the mnp service context data.
 | |
| 
 | |
|   @retval EFI_SUCCESS                The managed network is stopped.
 | |
|   @retval Others                     Other errors as indicated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| MnpStop (
 | |
|   IN OUT MNP_SERVICE_DATA    *MnpServiceData
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS      Status;
 | |
|   MNP_DEVICE_DATA *MnpDeviceData;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
 | |
|   MnpDeviceData = MnpServiceData->MnpDeviceData;
 | |
|   ASSERT (MnpDeviceData->ConfiguredChildrenNumber > 0);
 | |
| 
 | |
|   //
 | |
|   // Configure the receive filters.
 | |
|   //
 | |
|   MnpConfigReceiveFilters (MnpDeviceData);
 | |
| 
 | |
|   //
 | |
|   // Decrease the children number.
 | |
|   //
 | |
|   MnpDeviceData->ConfiguredChildrenNumber--;
 | |
| 
 | |
|   if (MnpDeviceData->ConfiguredChildrenNumber > 0) {
 | |
|     //
 | |
|     // If there are other configured chilren, return and keep the timers and
 | |
|     // simple network unchanged.
 | |
|     //
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // No configured children now.
 | |
|   //
 | |
|   if (MnpDeviceData->EnableSystemPoll) {
 | |
|     //
 | |
|     //  The system poll in on, cancel the poll timer.
 | |
|     //
 | |
|     Status  = gBS->SetTimer (MnpDeviceData->PollTimer, TimerCancel, 0);
 | |
|     MnpDeviceData->EnableSystemPoll = FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Cancel the timeout timer.
 | |
|   //
 | |
|   Status = gBS->SetTimer (MnpDeviceData->TimeoutCheckTimer, TimerCancel, 0);
 | |
| 
 | |
|   //
 | |
|   // Cancel the media detect timer.
 | |
|   //
 | |
|   Status = gBS->SetTimer (MnpDeviceData->MediaDetectTimer, TimerCancel, 0);
 | |
| 
 | |
|   //
 | |
|   // Stop the simple network.
 | |
|   //
 | |
|   Status = MnpStopSnp (MnpDeviceData->Snp);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Flush the instance's received data.
 | |
| 
 | |
|   @param[in, out]  Instance              Pointer to the mnp instance context data.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| MnpFlushRcvdDataQueue (
 | |
|   IN OUT MNP_INSTANCE_DATA   *Instance
 | |
|   )
 | |
| {
 | |
|   EFI_TPL         OldTpl;
 | |
|   MNP_RXDATA_WRAP *RxDataWrap;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
 | |
| 
 | |
|   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
 | |
| 
 | |
|   while (!IsListEmpty (&Instance->RcvdPacketQueue)) {
 | |
|     //
 | |
|     // Remove all the Wraps.
 | |
|     //
 | |
|     RxDataWrap = NET_LIST_HEAD (&Instance->RcvdPacketQueue, MNP_RXDATA_WRAP, WrapEntry);
 | |
| 
 | |
|     //
 | |
|     // Recycle the RxDataWrap.
 | |
|     //
 | |
|     MnpRecycleRxData (NULL, (VOID *) RxDataWrap);
 | |
|     Instance->RcvdPacketQueueSize--;
 | |
|   }
 | |
| 
 | |
|   ASSERT (Instance->RcvdPacketQueueSize == 0);
 | |
| 
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Configure the Instance using ConfigData.
 | |
| 
 | |
|   @param[in, out]  Instance     Pointer to the mnp instance context data.
 | |
|   @param[in]       ConfigData   Pointer to the configuration data used to configure
 | |
|                                 the isntance.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The Instance is configured.
 | |
|   @retval EFI_UNSUPPORTED       EnableReceiveTimestamps is on and the
 | |
|                                 implementation doesn't support it.
 | |
|   @retval Others                Other errors as indicated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| MnpConfigureInstance (
 | |
|   IN OUT MNP_INSTANCE_DATA                 *Instance,
 | |
|   IN     EFI_MANAGED_NETWORK_CONFIG_DATA   *ConfigData OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   MNP_SERVICE_DATA                *MnpServiceData;
 | |
|   MNP_DEVICE_DATA                 *MnpDeviceData;
 | |
|   EFI_MANAGED_NETWORK_CONFIG_DATA *OldConfigData;
 | |
|   EFI_MANAGED_NETWORK_CONFIG_DATA *NewConfigData;
 | |
|   BOOLEAN                         IsConfigUpdate;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
 | |
| 
 | |
|   if ((ConfigData != NULL) && ConfigData->EnableReceiveTimestamps) {
 | |
|     //
 | |
|     // Don't support timestamp.
 | |
|     //
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   Status          = EFI_SUCCESS;
 | |
| 
 | |
|   MnpServiceData  = Instance->MnpServiceData;
 | |
|   MnpDeviceData   = MnpServiceData->MnpDeviceData;
 | |
|   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
 | |
| 
 | |
|   IsConfigUpdate  = (BOOLEAN) ((Instance->Configured) && (ConfigData != NULL));
 | |
| 
 | |
|   OldConfigData   = &Instance->ConfigData;
 | |
|   NewConfigData   = ConfigData;
 | |
|   if (NewConfigData == NULL) {
 | |
|     //
 | |
|     // Restore back the default config data if a reset of this instance
 | |
|     // is required.
 | |
|     //
 | |
|     NewConfigData = &mMnpDefaultConfigData;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Reset the instance's receive filter.
 | |
|   //
 | |
|   Instance->ReceiveFilter = 0;
 | |
| 
 | |
|   //
 | |
|   // Clear the receive counters according to the old ConfigData.
 | |
|   //
 | |
|   if (OldConfigData->EnableUnicastReceive) {
 | |
|     MnpDeviceData->UnicastCount--;
 | |
|   }
 | |
| 
 | |
|   if (OldConfigData->EnableMulticastReceive) {
 | |
|     MnpDeviceData->MulticastCount--;
 | |
|   }
 | |
| 
 | |
|   if (OldConfigData->EnableBroadcastReceive) {
 | |
|     MnpDeviceData->BroadcastCount--;
 | |
|   }
 | |
| 
 | |
|   if (OldConfigData->EnablePromiscuousReceive) {
 | |
|     MnpDeviceData->PromiscuousCount--;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set the receive filter counters and the receive filter of the
 | |
|   // instance according to the new ConfigData.
 | |
|   //
 | |
|   if (NewConfigData->EnableUnicastReceive) {
 | |
|     MnpDeviceData->UnicastCount++;
 | |
|     Instance->ReceiveFilter |= MNP_RECEIVE_UNICAST;
 | |
|   }
 | |
| 
 | |
|   if (NewConfigData->EnableMulticastReceive) {
 | |
|     MnpDeviceData->MulticastCount++;
 | |
|   }
 | |
| 
 | |
|   if (NewConfigData->EnableBroadcastReceive) {
 | |
|     MnpDeviceData->BroadcastCount++;
 | |
|     Instance->ReceiveFilter |= MNP_RECEIVE_BROADCAST;
 | |
|   }
 | |
| 
 | |
|   if (NewConfigData->EnablePromiscuousReceive) {
 | |
|     MnpDeviceData->PromiscuousCount++;
 | |
|   }
 | |
| 
 | |
|   if (OldConfigData->FlushQueuesOnReset) {
 | |
|     MnpFlushRcvdDataQueue (Instance);
 | |
|   }
 | |
| 
 | |
|   if (ConfigData == NULL) {
 | |
|     Instance->ManagedNetwork.Cancel (&Instance->ManagedNetwork, NULL);
 | |
|   }
 | |
| 
 | |
|   if (!NewConfigData->EnableMulticastReceive) {
 | |
|     MnpGroupOp (Instance, FALSE, NULL, NULL);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Save the new configuration data.
 | |
|   //
 | |
|   CopyMem (OldConfigData, NewConfigData, sizeof (*OldConfigData));
 | |
| 
 | |
|   Instance->Configured = (BOOLEAN) (ConfigData != NULL);
 | |
|   if (Instance->Configured) {
 | |
|     //
 | |
|     // The instance is configured, start the Mnp.
 | |
|     //
 | |
|     Status = MnpStart (
 | |
|               MnpServiceData,
 | |
|               IsConfigUpdate,
 | |
|               (BOOLEAN) !NewConfigData->DisableBackgroundPolling
 | |
|               );
 | |
|   } else {
 | |
|     //
 | |
|     // The instance is changed to the unconfigured state, stop the Mnp.
 | |
|     //
 | |
|     Status = MnpStop (MnpServiceData);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Configure the Snp receive filters according to the instances' receive filter
 | |
|   settings.
 | |
| 
 | |
|   @param[in]  MnpDeviceData         Pointer to the mnp device context data.
 | |
| 
 | |
|   @retval     EFI_SUCCESS           The receive filters is configured.
 | |
|   @retval     EFI_OUT_OF_RESOURCES  The receive filters can't be configured due
 | |
|                                     to lack of memory resource.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| MnpConfigReceiveFilters (
 | |
|   IN MNP_DEVICE_DATA     *MnpDeviceData
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
 | |
|   EFI_MAC_ADDRESS             *MCastFilter;
 | |
|   UINT32                      MCastFilterCnt;
 | |
|   UINT32                      EnableFilterBits;
 | |
|   UINT32                      DisableFilterBits;
 | |
|   BOOLEAN                     ResetMCastFilters;
 | |
|   LIST_ENTRY                  *Entry;
 | |
|   UINT32                      Index;
 | |
|   MNP_GROUP_ADDRESS           *GroupAddress;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
 | |
| 
 | |
|   Snp = MnpDeviceData->Snp;
 | |
| 
 | |
|   //
 | |
|   // Initialize the enable filter and disable filter.
 | |
|   //
 | |
|   EnableFilterBits  = 0;
 | |
|   DisableFilterBits = Snp->Mode->ReceiveFilterMask;
 | |
| 
 | |
|   if (MnpDeviceData->UnicastCount != 0) {
 | |
|     //
 | |
|     // Enable unicast if any instance wants to receive unicast.
 | |
|     //
 | |
|     EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
 | |
|   }
 | |
| 
 | |
|   if (MnpDeviceData->BroadcastCount != 0) {
 | |
|     //
 | |
|     // Enable broadcast if any instance wants to receive broadcast.
 | |
|     //
 | |
|     EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
 | |
|   }
 | |
| 
 | |
|   MCastFilter       = NULL;
 | |
|   MCastFilterCnt    = 0;
 | |
|   ResetMCastFilters = TRUE;
 | |
| 
 | |
|   if ((MnpDeviceData->MulticastCount != 0) && (MnpDeviceData->GroupAddressCount != 0)) {
 | |
|     //
 | |
|     // There are instances configured to receive multicast and already some group
 | |
|     // addresses are joined.
 | |
|     //
 | |
| 
 | |
|     ResetMCastFilters = FALSE;
 | |
| 
 | |
|     if (MnpDeviceData->GroupAddressCount <= Snp->Mode->MaxMCastFilterCount) {
 | |
|       //
 | |
|       // The joind group address is less than simple network's maximum count.
 | |
|       // Just configure the snp to do the multicast filtering.
 | |
|       //
 | |
| 
 | |
|       EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
 | |
| 
 | |
|       //
 | |
|       // Allocate pool for the mulicast addresses.
 | |
|       //
 | |
|       MCastFilterCnt  = MnpDeviceData->GroupAddressCount;
 | |
|       MCastFilter     = AllocatePool (sizeof (EFI_MAC_ADDRESS) * MCastFilterCnt);
 | |
|       if (MCastFilter == NULL) {
 | |
|         DEBUG ((EFI_D_ERROR, "MnpConfigReceiveFilters: Failed to allocate memory resource for MCastFilter.\n"));
 | |
| 
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Fill the multicast HW address buffer.
 | |
|       //
 | |
|       Index = 0;
 | |
|       NET_LIST_FOR_EACH (Entry, &MnpDeviceData->GroupAddressList) {
 | |
| 
 | |
|         GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);
 | |
|         CopyMem (MCastFilter + Index, &GroupAddress->Address, sizeof (*(MCastFilter + Index)));
 | |
|         Index++;
 | |
| 
 | |
|         ASSERT (Index <= MCastFilterCnt);
 | |
|       }
 | |
|     } else {
 | |
|       //
 | |
|       // The maximum multicast is reached, set the filter to be promiscuous
 | |
|       // multicast.
 | |
|       //
 | |
| 
 | |
|       if ((Snp->Mode->ReceiveFilterMask & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
 | |
|         EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
 | |
|       } else {
 | |
|         //
 | |
|         // Either MULTICAST or PROMISCUOUS_MULTICAST is not supported by Snp,
 | |
|         // set the NIC to be promiscuous although this will tremendously degrade
 | |
|         // the performance.
 | |
|         //
 | |
|         EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (MnpDeviceData->PromiscuousCount != 0) {
 | |
|     //
 | |
|     // Enable promiscuous if any instance wants to receive promiscuous.
 | |
|     //
 | |
|     EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set the disable filter.
 | |
|   //
 | |
|   DisableFilterBits ^= EnableFilterBits;
 | |
| 
 | |
|   //
 | |
|   // Configure the receive filters of SNP.
 | |
|   //
 | |
|   Status = Snp->ReceiveFilters (
 | |
|                   Snp,
 | |
|                   EnableFilterBits,
 | |
|                   DisableFilterBits,
 | |
|                   ResetMCastFilters,
 | |
|                   MCastFilterCnt,
 | |
|                   MCastFilter
 | |
|                   );
 | |
|   DEBUG_CODE (
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG (
 | |
|         (EFI_D_ERROR,
 | |
|         "MnpConfigReceiveFilters: Snp->ReceiveFilters failed, %r.\n",
 | |
|         Status)
 | |
|         );
 | |
|     }
 | |
|   );
 | |
| 
 | |
|   if (MCastFilter != NULL) {
 | |
|     //
 | |
|     // Free the buffer used to hold the group addresses.
 | |
|     //
 | |
|     FreePool (MCastFilter);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Add a group address control block which controls the MacAddress for
 | |
|   this instance.
 | |
| 
 | |
|   @param[in, out]  Instance        Pointer to the mnp instance context data.
 | |
|   @param[in, out]  CtrlBlk         Pointer to the group address control block.
 | |
|   @param[in, out]  GroupAddress    Pointer to the group adress.
 | |
|   @param[in]       MacAddress      Pointer to the mac address.
 | |
|   @param[in]       HwAddressSize   The hardware address size.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The group address control block is added.
 | |
|   @retval EFI_OUT_OF_RESOURCES     Failed due to lack of memory resources.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| MnpGroupOpAddCtrlBlk (
 | |
|   IN OUT MNP_INSTANCE_DATA         *Instance,
 | |
|   IN OUT MNP_GROUP_CONTROL_BLOCK   *CtrlBlk,
 | |
|   IN OUT MNP_GROUP_ADDRESS         *GroupAddress OPTIONAL,
 | |
|   IN     EFI_MAC_ADDRESS           *MacAddress,
 | |
|   IN     UINT32                    HwAddressSize
 | |
|   )
 | |
| {
 | |
|   MNP_DEVICE_DATA  *MnpDeviceData;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
 | |
| 
 | |
|   MnpDeviceData = Instance->MnpServiceData->MnpDeviceData;
 | |
|   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
 | |
| 
 | |
|   if (GroupAddress == NULL) {
 | |
|     ASSERT (MacAddress != NULL);
 | |
| 
 | |
|     //
 | |
|     // Allocate a new GroupAddress to be added into MNP's GroupAddressList.
 | |
|     //
 | |
|     GroupAddress = AllocatePool (sizeof (MNP_GROUP_ADDRESS));
 | |
|     if (GroupAddress == NULL) {
 | |
| 
 | |
|       DEBUG ((EFI_D_ERROR, "MnpGroupOpFormCtrlBlk: Failed to allocate memory resource.\n"));
 | |
| 
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     CopyMem (&GroupAddress->Address, MacAddress, sizeof (GroupAddress->Address));
 | |
|     GroupAddress->RefCnt = 0;
 | |
|     InsertTailList (
 | |
|       &MnpDeviceData->GroupAddressList,
 | |
|       &GroupAddress->AddrEntry
 | |
|       );
 | |
|     MnpDeviceData->GroupAddressCount++;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Increase the RefCnt.
 | |
|   //
 | |
|   GroupAddress->RefCnt++;
 | |
| 
 | |
|   //
 | |
|   // Add the CtrlBlk into the instance's GroupCtrlBlkList.
 | |
|   //
 | |
|   CtrlBlk->GroupAddress = GroupAddress;
 | |
|   InsertTailList (&Instance->GroupCtrlBlkList, &CtrlBlk->CtrlBlkEntry);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Delete a group control block from the instance. If the controlled group address's
 | |
|   reference count reaches zero, the group address is removed too.
 | |
| 
 | |
|   @param[in]  Instance              Pointer to the instance context data.
 | |
|   @param[in]  CtrlBlk               Pointer to the group control block to delete.
 | |
| 
 | |
|   @return The group address controlled by the control block is no longer used or not.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| MnpGroupOpDelCtrlBlk (
 | |
|   IN MNP_INSTANCE_DATA           *Instance,
 | |
|   IN MNP_GROUP_CONTROL_BLOCK     *CtrlBlk
 | |
|   )
 | |
| {
 | |
|   MNP_DEVICE_DATA   *MnpDeviceData;
 | |
|   MNP_GROUP_ADDRESS *GroupAddress;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
 | |
| 
 | |
|   MnpDeviceData = Instance->MnpServiceData->MnpDeviceData;
 | |
|   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
 | |
| 
 | |
|   //
 | |
|   // Remove and free the CtrlBlk.
 | |
|   //
 | |
|   GroupAddress = CtrlBlk->GroupAddress;
 | |
|   RemoveEntryList (&CtrlBlk->CtrlBlkEntry);
 | |
|   FreePool (CtrlBlk);
 | |
| 
 | |
|   ASSERT (GroupAddress->RefCnt > 0);
 | |
| 
 | |
|   //
 | |
|   // Count down the RefCnt.
 | |
|   //
 | |
|   GroupAddress->RefCnt--;
 | |
| 
 | |
|   if (GroupAddress->RefCnt == 0) {
 | |
|     //
 | |
|     // Free this GroupAddress entry if no instance uses it.
 | |
|     //
 | |
|     MnpDeviceData->GroupAddressCount--;
 | |
|     RemoveEntryList (&GroupAddress->AddrEntry);
 | |
|     FreePool (GroupAddress);
 | |
| 
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Do the group operations for this instance.
 | |
| 
 | |
|   @param[in, out]  Instance        Pointer to the instance context data.
 | |
|   @param[in]       JoinFlag        Set to TRUE to join a group. Set to TRUE to
 | |
|                                    leave a group/groups.
 | |
|   @param[in]       MacAddress      Pointer to the group address to join or leave.
 | |
|   @param[in]       CtrlBlk         Pointer to the group control block if JoinFlag
 | |
|                                    is FALSE.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The group operation finished.
 | |
|   @retval EFI_OUT_OF_RESOURCES     Failed due to lack of memory resources.
 | |
|   @retval Others                   Other errors as indicated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| MnpGroupOp (
 | |
|   IN OUT MNP_INSTANCE_DATA         *Instance,
 | |
|   IN     BOOLEAN                   JoinFlag,
 | |
|   IN     EFI_MAC_ADDRESS           *MacAddress OPTIONAL,
 | |
|   IN     MNP_GROUP_CONTROL_BLOCK   *CtrlBlk OPTIONAL
 | |
|   )
 | |
| {
 | |
|   MNP_DEVICE_DATA         *MnpDeviceData;
 | |
|   LIST_ENTRY              *Entry;
 | |
|   LIST_ENTRY              *NextEntry;
 | |
|   MNP_GROUP_ADDRESS       *GroupAddress;
 | |
|   EFI_SIMPLE_NETWORK_MODE *SnpMode;
 | |
|   MNP_GROUP_CONTROL_BLOCK *NewCtrlBlk;
 | |
|   EFI_STATUS              Status;
 | |
|   BOOLEAN                 AddressExist;
 | |
|   BOOLEAN                 NeedUpdate;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
 | |
| 
 | |
|   MnpDeviceData = Instance->MnpServiceData->MnpDeviceData;
 | |
|   SnpMode       = MnpDeviceData->Snp->Mode;
 | |
| 
 | |
|   if (JoinFlag) {
 | |
|     //
 | |
|     // A new gropu address is to be added.
 | |
|     //
 | |
|     GroupAddress  = NULL;
 | |
|     AddressExist  = FALSE;
 | |
| 
 | |
|     //
 | |
|     // Allocate memory for the control block.
 | |
|     //
 | |
|     NewCtrlBlk = AllocatePool (sizeof (MNP_GROUP_CONTROL_BLOCK));
 | |
|     if (NewCtrlBlk == NULL) {
 | |
|       DEBUG ((EFI_D_ERROR, "MnpGroupOp: Failed to allocate memory resource.\n"));
 | |
| 
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     NET_LIST_FOR_EACH (Entry, &MnpDeviceData->GroupAddressList) {
 | |
|       //
 | |
|       // Check whether the MacAddress is already joined by other instances.
 | |
|       //
 | |
|       GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);
 | |
|       if (CompareMem (MacAddress, &GroupAddress->Address, SnpMode->HwAddressSize) == 0) {
 | |
|         AddressExist = TRUE;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (!AddressExist) {
 | |
|       GroupAddress = NULL;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Add the GroupAddress for this instance.
 | |
|     //
 | |
|     Status = MnpGroupOpAddCtrlBlk (
 | |
|               Instance,
 | |
|               NewCtrlBlk,
 | |
|               GroupAddress,
 | |
|               MacAddress,
 | |
|               SnpMode->HwAddressSize
 | |
|               );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     NeedUpdate = TRUE;
 | |
|   } else {
 | |
|     if (MacAddress != NULL) {
 | |
|       ASSERT (CtrlBlk != NULL);
 | |
| 
 | |
|       //
 | |
|       // Leave the specific multicast mac address.
 | |
|       //
 | |
|       NeedUpdate = MnpGroupOpDelCtrlBlk (Instance, CtrlBlk);
 | |
|     } else {
 | |
|       //
 | |
|       // Leave all multicast mac addresses.
 | |
|       //
 | |
|       NeedUpdate = FALSE;
 | |
| 
 | |
|       NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->GroupCtrlBlkList) {
 | |
| 
 | |
|         NewCtrlBlk = NET_LIST_USER_STRUCT (
 | |
|                       Entry,
 | |
|                       MNP_GROUP_CONTROL_BLOCK,
 | |
|                       CtrlBlkEntry
 | |
|                       );
 | |
|         //
 | |
|         // Update is required if the group address left is no longer used
 | |
|         // by other instances.
 | |
|         //
 | |
|         NeedUpdate = MnpGroupOpDelCtrlBlk (Instance, NewCtrlBlk);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   if (NeedUpdate) {
 | |
|     //
 | |
|     // Reconfigure the receive filters if necessary.
 | |
|     //
 | |
|     Status = MnpConfigReceiveFilters (MnpDeviceData);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 |