summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Universal/Network/MnpDxe/MnpVlan.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Universal/Network/MnpDxe/MnpVlan.c')
-rw-r--r--MdeModulePkg/Universal/Network/MnpDxe/MnpVlan.c688
1 files changed, 688 insertions, 0 deletions
diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpVlan.c b/MdeModulePkg/Universal/Network/MnpDxe/MnpVlan.c
new file mode 100644
index 0000000000..1ba309c413
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/MnpDxe/MnpVlan.c
@@ -0,0 +1,688 @@
+/** @file
+ VLAN Config Protocol implementation and VLAN packet process routine.
+
+Copyright (c) 2009, Intel Corporation.<BR>
+All rights reserved. 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"
+
+VLAN_DEVICE_PATH mVlanDevicePathTemplate = {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_VLAN_DP,
+ {
+ (UINT8) (sizeof (VLAN_DEVICE_PATH)),
+ (UINT8) ((sizeof (VLAN_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0
+};
+
+EFI_VLAN_CONFIG_PROTOCOL mVlanConfigProtocolTemplate = {
+ VlanConfigSet,
+ VlanConfigFind,
+ VlanConfigRemove
+};
+
+
+/**
+ Create a child handle for the VLAN ID.
+
+ @param[in] ImageHandle The driver image handle.
+ @param[in] ControllerHandle Handle of device to bind driver to.
+ @param[in] VlanId The VLAN ID.
+ @param[out] Devicepath Pointer to returned device path for child handle.
+
+ @return The handle of VLAN child or NULL if failed to create VLAN child.
+
+**/
+EFI_HANDLE
+MnpCreateVlanChild (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINT16 VlanId,
+ OUT EFI_DEVICE_PATH_PROTOCOL **Devicepath OPTIONAL
+ )
+{
+ EFI_HANDLE ChildHandle;
+ VLAN_DEVICE_PATH VlanNode;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *VlanDevicePath;
+ EFI_STATUS Status;
+
+ //
+ // Try to get parent device path
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ ImageHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ //
+ // Construct device path for child handle: MAC + VLAN
+ //
+ CopyMem (&VlanNode, &mVlanDevicePathTemplate, sizeof (VLAN_DEVICE_PATH));
+ VlanNode.VlanId = VlanId;
+ VlanDevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &VlanNode
+ );
+ if (VlanDevicePath == NULL) {
+ return NULL;
+ }
+
+ //
+ // Create child VLAN handle by installing DevicePath protocol
+ //
+ ChildHandle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ChildHandle,
+ &gEfiDevicePathProtocolGuid,
+ VlanDevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (VlanDevicePath);
+ return NULL;
+ }
+
+ if (Devicepath != NULL) {
+ *Devicepath = VlanDevicePath;
+ }
+
+ return ChildHandle;
+}
+
+/**
+ Remove VLAN tag from a packet.
+
+ @param[in, out] MnpDeviceData Pointer to the mnp device context data.
+ @param[in, out] Nbuf Pointer to the NET_BUF to remove VLAN tag.
+ @param[out] VlanId Pointer to the returned VLAN ID.
+
+ @retval TRUE VLAN tag is removed from this packet.
+ @retval FALSE There is no VLAN tag in this packet.
+
+**/
+BOOLEAN
+MnpRemoveVlanTag (
+ IN OUT MNP_DEVICE_DATA *MnpDeviceData,
+ IN OUT NET_BUF *Nbuf,
+ OUT UINT16 *VlanId
+ )
+{
+ UINT8 *Packet;
+ UINTN ProtocolOffset;
+ UINT16 ProtocolType;
+ VLAN_TCI VlanTag;
+
+ ProtocolOffset = MnpDeviceData->Snp->Mode->HwAddressSize * 2;
+
+ //
+ // Get the packet buffer.
+ //
+ Packet = NetbufGetByte (Nbuf, 0, NULL);
+ ASSERT (Packet != NULL);
+
+ //
+ // Check whether this is VLAN tagged frame by Ether Type
+ //
+ *VlanId = 0;
+ ProtocolType = NTOHS (*(UINT16 *) (Packet + ProtocolOffset));
+ if (ProtocolType != ETHER_TYPE_VLAN) {
+ //
+ // Not a VLAN tagged frame
+ //
+ return FALSE;
+ }
+
+ VlanTag.Uint16 = NTOHS (*(UINT16 *) (Packet + ProtocolOffset + sizeof (ProtocolType)));
+ *VlanId = VlanTag.Bits.Vid;
+
+ //
+ // Move hardware address (DA + SA) 4 bytes right to override VLAN tag
+ //
+ CopyMem (Packet + NET_VLAN_TAG_LEN, Packet, ProtocolOffset);
+
+ //
+ // Remove VLAN tag from the Nbuf
+ //
+ NetbufTrim (Nbuf, NET_VLAN_TAG_LEN, NET_BUF_HEAD);
+
+ return TRUE;
+}
+
+
+/**
+ Build the packet to transmit from the TxData passed in.
+
+ @param MnpServiceData Pointer to the mnp service context data.
+ @param TxData Pointer to the transmit data containing the
+ information to build the packet.
+ @param ProtocolType Pointer to the Ethernet protocol type.
+ @param Packet Pointer to record the address of the packet.
+ @param Length Pointer to a UINT32 variable used to record the
+ packet's length.
+
+**/
+VOID
+MnpInsertVlanTag (
+ IN MNP_SERVICE_DATA *MnpServiceData,
+ IN EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData,
+ OUT UINT16 *ProtocolType,
+ IN OUT UINT8 **Packet,
+ IN OUT UINT32 *Length
+ )
+{
+ VLAN_TCI *VlanTci;
+ UINT16 *Tpid;
+ UINT16 *EtherType;
+ MNP_DEVICE_DATA *MnpDeviceData;
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;
+
+ if (MnpServiceData->VlanId == 0) {
+ *ProtocolType = TxData->ProtocolType;
+ return ;
+ }
+
+ MnpDeviceData = MnpServiceData->MnpDeviceData;
+ SnpMode = MnpDeviceData->Snp->Mode;
+
+ *ProtocolType = ETHER_TYPE_VLAN;
+ *Length = *Length + NET_VLAN_TAG_LEN;
+ *Packet = *Packet - NET_VLAN_TAG_LEN;
+
+ Tpid = (UINT16 *) (*Packet + SnpMode->MediaHeaderSize - sizeof (*ProtocolType));
+ VlanTci = (VLAN_TCI *) (UINTN) (Tpid + 1);
+ if (TxData->HeaderLength != 0) {
+ //
+ // Media header is in packet, move DA+SA 4 bytes left
+ //
+ CopyMem (
+ *Packet,
+ *Packet + NET_VLAN_TAG_LEN,
+ SnpMode->MediaHeaderSize - sizeof (*ProtocolType)
+ );
+ *Tpid = HTONS (ETHER_TYPE_VLAN);
+ } else {
+ //
+ // Media header not in packet, VLAN TCI and original protocol type becomes payload
+ //
+ EtherType = (UINT16 *) (UINTN) (VlanTci + 1);
+ *EtherType = HTONS (TxData->ProtocolType);
+ }
+
+ VlanTci->Bits.Vid = MnpServiceData->VlanId;
+ VlanTci->Bits.Cfi = VLAN_TCI_CFI_CANONICAL_MAC;
+ VlanTci->Bits.Priority = MnpServiceData->Priority;
+ VlanTci->Uint16 = HTONS (VlanTci->Uint16);
+}
+
+
+/**
+ Get VLAN configuration variable.
+
+ @param[in] MnpDeviceData Pointer to the MNP device context data.
+ @param[out] NumberOfVlan Pointer to number of VLAN to be returned.
+ @param[out] VlanVariable Pointer to the buffer to return requested
+ array of VLAN_TCI.
+
+ @retval EFI_SUCCESS The array of VLAN_TCI was returned in VlanVariable
+ and number of VLAN was returned in NumberOfVlan.
+ @retval EFI_NOT_FOUND VLAN configuration variable not found.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the configuration.
+
+**/
+EFI_STATUS
+MnpGetVlanVariable (
+ IN MNP_DEVICE_DATA *MnpDeviceData,
+ OUT UINTN *NumberOfVlan,
+ OUT VLAN_TCI **VlanVariable
+ )
+{
+ UINTN BufferSize;
+ EFI_STATUS Status;
+ VLAN_TCI *Buffer;
+
+ //
+ // Get VLAN configuration from EFI Variable
+ //
+ Buffer = NULL;
+ BufferSize = 0;
+ Status = gRT->GetVariable (
+ MnpDeviceData->MacString,
+ &gEfiVlanConfigProtocolGuid,
+ NULL,
+ &BufferSize,
+ NULL
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Allocate buffer to read the variable
+ //
+ Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable (
+ MnpDeviceData->MacString,
+ &gEfiVlanConfigProtocolGuid,
+ NULL,
+ &BufferSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Buffer);
+ return Status;
+ }
+
+ *NumberOfVlan = BufferSize / sizeof (VLAN_TCI);
+ *VlanVariable = Buffer;
+
+ return Status;
+}
+
+
+/**
+ Set VLAN configuration variable.
+
+ @param[in] MnpDeviceData Pointer to the MNP device context data.
+ @param[in] NumberOfVlan Number of VLAN in array VlanVariable.
+ @param[in] VlanVariable Pointer to array of VLAN_TCI.
+
+ @retval EFI_SUCCESS The VLAN variable is successfully set.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to set the configuration.
+
+**/
+EFI_STATUS
+MnpSetVlanVariable (
+ IN MNP_DEVICE_DATA *MnpDeviceData,
+ IN UINTN NumberOfVlan,
+ IN VLAN_TCI *VlanVariable
+ )
+{
+ return gRT->SetVariable (
+ MnpDeviceData->MacString,
+ &gEfiVlanConfigProtocolGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ NumberOfVlan * sizeof (VLAN_TCI),
+ VlanVariable
+ );
+}
+
+
+/**
+ Create a VLAN device or modify the configuration parameter of an
+ already-configured VLAN.
+
+ The Set() function is used to create a new VLAN device or change the VLAN
+ configuration parameters. If the VlanId hasn't been configured in the
+ physical Ethernet device, a new VLAN device will be created. If a VLAN with
+ this VlanId is already configured, then related configuration will be updated
+ as the input parameters.
+
+ If VlanId is zero, the VLAN device will send and receive untagged frames.
+ Otherwise, the VLAN device will send and receive VLAN-tagged frames containing the VlanId.
+ If VlanId is out of scope of (0-4094), EFI_INVALID_PARAMETER is returned.
+ If Priority is out of the scope of (0-7), then EFI_INVALID_PARAMETER is returned.
+ If there is not enough system memory to perform the registration, then
+ EFI_OUT_OF_RESOURCES is returned.
+
+ @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL.
+ @param[in] VlanId A unique identifier (1-4094) of the VLAN which is being created
+ or modified, or zero (0).
+ @param[in] Priority 3 bit priority in VLAN header. Priority 0 is default value. If
+ VlanId is zero (0), Priority is ignored.
+
+ @retval EFI_SUCCESS The VLAN is successfully configured.
+ @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:
+ - This is NULL.
+ - VlanId is an invalid VLAN Identifier.
+ - Priority is invalid.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to perform the registration.
+
+**/
+EFI_STATUS
+EFIAPI
+VlanConfigSet (
+ IN EFI_VLAN_CONFIG_PROTOCOL *This,
+ IN UINT16 VlanId,
+ IN UINT8 Priority
+ )
+{
+ EFI_STATUS Status;
+ MNP_DEVICE_DATA *MnpDeviceData;
+ MNP_SERVICE_DATA *MnpServiceData;
+ VLAN_TCI *OldVariable;
+ VLAN_TCI *NewVariable;
+ UINTN NumberOfVlan;
+ UINTN Index;
+ BOOLEAN IsAdd;
+ LIST_ENTRY *Entry;
+
+ if ((This == NULL) || (VlanId > 4094) || (Priority > 7)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IsAdd = FALSE;
+ MnpDeviceData = MNP_DEVICE_DATA_FROM_THIS (This);
+ if (MnpDeviceData->NumberOfVlan == 0) {
+ //
+ // No existing VLAN, this is the first VLAN to add
+ //
+ IsAdd = TRUE;
+ Entry = GetFirstNode (&MnpDeviceData->ServiceList);
+ MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry);
+
+ if (VlanId != 0) {
+ //
+ // VlanId is not 0, need destroy the default MNP service data
+ //
+ Status = MnpDestroyServiceChild (MnpServiceData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = MnpDestroyServiceData (MnpServiceData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Create a new MNP service data for this VLAN
+ //
+ MnpServiceData = MnpCreateServiceData (MnpDeviceData, VlanId, Priority);
+ if (MnpServiceData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ } else {
+ //
+ // Try to find VlanId in existing VLAN list
+ //
+ MnpServiceData = MnpFindServiceData (MnpDeviceData, VlanId);
+ if (MnpServiceData == NULL) {
+ //
+ // VlanId not found, create a new MNP service data
+ //
+ IsAdd = TRUE;
+ MnpServiceData = MnpCreateServiceData (MnpDeviceData, VlanId, Priority);
+ if (MnpServiceData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ }
+
+ MnpServiceData->VlanId = VlanId;
+ MnpServiceData->Priority = Priority;
+ if (IsAdd) {
+ MnpDeviceData->NumberOfVlan++;
+ }
+
+ //
+ // Update VLAN configuration variable
+ //
+ OldVariable = NULL;
+ NewVariable = NULL;
+ NumberOfVlan = 0;
+ MnpGetVlanVariable (MnpDeviceData, &NumberOfVlan, &OldVariable);
+
+ if (IsAdd) {
+ //
+ // VLAN not exist - add
+ //
+ NewVariable = AllocateZeroPool ((NumberOfVlan + 1) * sizeof (VLAN_TCI));
+ if (NewVariable == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ if (OldVariable != NULL) {
+ CopyMem (NewVariable, OldVariable, NumberOfVlan * sizeof (VLAN_TCI));
+ }
+
+ Index = NumberOfVlan++;
+ } else {
+ //
+ // VLAN already exist - update
+ //
+ for (Index = 0; Index < NumberOfVlan; Index++) {
+ if (OldVariable[Index].Bits.Vid == VlanId) {
+ break;
+ }
+ }
+ ASSERT (Index < NumberOfVlan);
+
+ NewVariable = OldVariable;
+ OldVariable = NULL;
+ }
+
+ NewVariable[Index].Bits.Vid = VlanId;
+ NewVariable[Index].Bits.Priority = Priority;
+
+ Status = MnpSetVlanVariable (MnpDeviceData, NumberOfVlan, NewVariable);
+ FreePool (NewVariable);
+
+Exit:
+ if (OldVariable != NULL) {
+ FreePool (OldVariable);
+ }
+
+ return Status;
+}
+
+
+/**
+ Find configuration information for specified VLAN or all configured VLANs.
+
+ The Find() function is used to find the configuration information for matching
+ VLAN and allocate a buffer into which those entries are copied.
+
+ @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL.
+ @param[in] VlanId Pointer to VLAN identifier. Set to NULL to find all
+ configured VLANs.
+ @param[out] NumberOfVlan The number of VLANs which is found by the specified criteria.
+ @param[out] Entries The buffer which receive the VLAN configuration.
+
+ @retval EFI_SUCCESS The VLAN is successfully found.
+ @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:
+ - This is NULL.
+ - Specified VlanId is invalid.
+ @retval EFI_NOT_FOUND No matching VLAN is found.
+
+**/
+EFI_STATUS
+EFIAPI
+VlanConfigFind (
+ IN EFI_VLAN_CONFIG_PROTOCOL *This,
+ IN UINT16 *VlanId OPTIONAL,
+ OUT UINT16 *NumberOfVlan,
+ OUT EFI_VLAN_FIND_DATA **Entries
+ )
+{
+ MNP_DEVICE_DATA *MnpDeviceData;
+ MNP_SERVICE_DATA *MnpServiceData;
+ LIST_ENTRY *Entry;
+ EFI_VLAN_FIND_DATA *VlanData;
+
+ if ((This == NULL) || (VlanId != NULL && *VlanId > 4094) || (NumberOfVlan == NULL) || (Entries == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *NumberOfVlan = 0;
+ *Entries = NULL;
+
+ MnpDeviceData = MNP_DEVICE_DATA_FROM_THIS (This);
+ if (MnpDeviceData->NumberOfVlan == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (VlanId == NULL) {
+ //
+ // Return all current VLAN configuration
+ //
+ *NumberOfVlan = (UINT16) MnpDeviceData->NumberOfVlan;
+ VlanData = AllocateZeroPool (*NumberOfVlan * sizeof (EFI_VLAN_FIND_DATA));
+ if (VlanData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *Entries = VlanData;
+ NET_LIST_FOR_EACH (Entry, &MnpDeviceData->ServiceList) {
+ MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry);
+
+ VlanData->VlanId = MnpServiceData->VlanId;
+ VlanData->Priority = MnpServiceData->Priority;
+ VlanData++;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // VlanId is specified, try to find it in current VLAN list
+ //
+ MnpServiceData = MnpFindServiceData (MnpDeviceData, *VlanId);
+ if (MnpServiceData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ VlanData = AllocateZeroPool (sizeof (EFI_VLAN_FIND_DATA));
+ if (VlanData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ VlanData->VlanId = MnpServiceData->VlanId;
+ VlanData->Priority = MnpServiceData->Priority;
+
+ *NumberOfVlan = 1;
+ *Entries = VlanData;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Remove the configured VLAN device.
+
+ The Remove() function is used to remove the specified VLAN device.
+ If the VlanId is out of the scope of (0-4094), EFI_INVALID_PARAMETER is returned.
+ If specified VLAN hasn't been previously configured, EFI_NOT_FOUND is returned.
+
+ @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL.
+ @param[in] VlanId Identifier (0-4094) of the VLAN to be removed.
+
+ @retval EFI_SUCCESS The VLAN is successfully removed.
+ @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:
+ - This is NULL.
+ - VlanId is an invalid parameter.
+ @retval EFI_NOT_FOUND The to-be-removed VLAN does not exist.
+
+**/
+EFI_STATUS
+EFIAPI
+VlanConfigRemove (
+ IN EFI_VLAN_CONFIG_PROTOCOL *This,
+ IN UINT16 VlanId
+ )
+{
+ EFI_STATUS Status;
+ MNP_DEVICE_DATA *MnpDeviceData;
+ MNP_SERVICE_DATA *MnpServiceData;
+ LIST_ENTRY *Entry;
+ VLAN_TCI *VlanVariable;
+ VLAN_TCI *VlanData;
+
+ if ((This == NULL) || (VlanId > 4094)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MnpDeviceData = MNP_DEVICE_DATA_FROM_THIS (This);
+ if (MnpDeviceData->NumberOfVlan == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Try to find the VlanId
+ //
+ MnpServiceData = MnpFindServiceData (MnpDeviceData, VlanId);
+ if (MnpServiceData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ MnpDeviceData->NumberOfVlan--;
+
+ if ((VlanId != 0) || (MnpDeviceData->NumberOfVlan != 0)) {
+ //
+ // If VlanId is not 0 or VlanId is 0 and it is not the last VLAN to remove,
+ // destroy its MNP service data
+ //
+ Status = MnpDestroyServiceChild (MnpServiceData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = MnpDestroyServiceData (MnpServiceData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if ((VlanId != 0) && (MnpDeviceData->NumberOfVlan == 0)) {
+ //
+ // This is the last VLAN to be removed, restore the default MNP service data
+ //
+ MnpServiceData = MnpCreateServiceData (MnpDeviceData, 0, 0);
+ if (MnpServiceData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // Update VLAN configuration variable
+ //
+ VlanVariable = NULL;
+ if (MnpDeviceData->NumberOfVlan != 0) {
+ VlanVariable = AllocatePool (MnpDeviceData->NumberOfVlan * sizeof (VLAN_TCI));
+ if (VlanVariable == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ VlanData = VlanVariable;
+ NET_LIST_FOR_EACH (Entry, &MnpDeviceData->ServiceList) {
+ MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry);
+
+ VlanData->Bits.Vid = MnpServiceData->VlanId;
+ VlanData->Bits.Priority = MnpServiceData->Priority;
+ VlanData++;
+ }
+ }
+
+ Status = MnpSetVlanVariable (MnpDeviceData, MnpDeviceData->NumberOfVlan, VlanVariable);
+
+ if (VlanVariable != NULL) {
+ FreePool (VlanVariable);
+ }
+
+ return Status;
+}