1 /** @file 2 VLAN Config Protocol implementation and VLAN packet process routine. 3 4 Copyright (c) 2009 - 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 VLAN_DEVICE_PATH mVlanDevicePathTemplate = { 20 { 21 MESSAGING_DEVICE_PATH, 22 MSG_VLAN_DP, 23 { 24 (UINT8) (sizeof (VLAN_DEVICE_PATH)), 25 (UINT8) ((sizeof (VLAN_DEVICE_PATH)) >> 8) 26 } 27 }, 28 0 29 }; 30 31 EFI_VLAN_CONFIG_PROTOCOL mVlanConfigProtocolTemplate = { 32 VlanConfigSet, 33 VlanConfigFind, 34 VlanConfigRemove 35 }; 36 37 38 /** 39 Create a child handle for the VLAN ID. 40 41 @param[in] ImageHandle The driver image handle. 42 @param[in] ControllerHandle Handle of device to bind driver to. 43 @param[in] VlanId The VLAN ID. 44 @param[out] Devicepath Pointer to returned device path for child handle. 45 46 @return The handle of VLAN child or NULL if failed to create VLAN child. 47 48 **/ 49 EFI_HANDLE 50 MnpCreateVlanChild ( 51 IN EFI_HANDLE ImageHandle, 52 IN EFI_HANDLE ControllerHandle, 53 IN UINT16 VlanId, 54 OUT EFI_DEVICE_PATH_PROTOCOL **Devicepath OPTIONAL 55 ) 56 { 57 EFI_HANDLE ChildHandle; 58 VLAN_DEVICE_PATH VlanNode; 59 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; 60 EFI_DEVICE_PATH_PROTOCOL *VlanDevicePath; 61 EFI_STATUS Status; 62 63 // 64 // Try to get parent device path 65 // 66 Status = gBS->OpenProtocol ( 67 ControllerHandle, 68 &gEfiDevicePathProtocolGuid, 69 (VOID **) &ParentDevicePath, 70 ImageHandle, 71 ControllerHandle, 72 EFI_OPEN_PROTOCOL_GET_PROTOCOL 73 ); 74 if (EFI_ERROR (Status)) { 75 return NULL; 76 } 77 78 // 79 // Construct device path for child handle: MAC + VLAN 80 // 81 CopyMem (&VlanNode, &mVlanDevicePathTemplate, sizeof (VLAN_DEVICE_PATH)); 82 VlanNode.VlanId = VlanId; 83 VlanDevicePath = AppendDevicePathNode ( 84 ParentDevicePath, 85 (EFI_DEVICE_PATH_PROTOCOL *) &VlanNode 86 ); 87 if (VlanDevicePath == NULL) { 88 return NULL; 89 } 90 91 // 92 // Create child VLAN handle by installing DevicePath protocol 93 // 94 ChildHandle = NULL; 95 Status = gBS->InstallMultipleProtocolInterfaces ( 96 &ChildHandle, 97 &gEfiDevicePathProtocolGuid, 98 VlanDevicePath, 99 NULL 100 ); 101 if (EFI_ERROR (Status)) { 102 FreePool (VlanDevicePath); 103 return NULL; 104 } 105 106 if (Devicepath != NULL) { 107 *Devicepath = VlanDevicePath; 108 } 109 110 return ChildHandle; 111 } 112 113 /** 114 Remove VLAN tag from a packet. 115 116 @param[in, out] MnpDeviceData Pointer to the mnp device context data. 117 @param[in, out] Nbuf Pointer to the NET_BUF to remove VLAN tag. 118 @param[out] VlanId Pointer to the returned VLAN ID. 119 120 @retval TRUE VLAN tag is removed from this packet. 121 @retval FALSE There is no VLAN tag in this packet. 122 123 **/ 124 BOOLEAN 125 MnpRemoveVlanTag ( 126 IN OUT MNP_DEVICE_DATA *MnpDeviceData, 127 IN OUT NET_BUF *Nbuf, 128 OUT UINT16 *VlanId 129 ) 130 { 131 UINT8 *Packet; 132 UINTN ProtocolOffset; 133 UINT16 ProtocolType; 134 VLAN_TCI VlanTag; 135 136 ProtocolOffset = MnpDeviceData->Snp->Mode->HwAddressSize * 2; 137 138 // 139 // Get the packet buffer. 140 // 141 Packet = NetbufGetByte (Nbuf, 0, NULL); 142 ASSERT (Packet != NULL); 143 144 // 145 // Check whether this is VLAN tagged frame by Ether Type 146 // 147 *VlanId = 0; 148 ProtocolType = NTOHS (*(UINT16 *) (Packet + ProtocolOffset)); 149 if (ProtocolType != ETHER_TYPE_VLAN) { 150 // 151 // Not a VLAN tagged frame 152 // 153 return FALSE; 154 } 155 156 VlanTag.Uint16 = NTOHS (*(UINT16 *) (Packet + ProtocolOffset + sizeof (ProtocolType))); 157 *VlanId = VlanTag.Bits.Vid; 158 159 // 160 // Move hardware address (DA + SA) 4 bytes right to override VLAN tag 161 // 162 CopyMem (Packet + NET_VLAN_TAG_LEN, Packet, ProtocolOffset); 163 164 // 165 // Remove VLAN tag from the Nbuf 166 // 167 NetbufTrim (Nbuf, NET_VLAN_TAG_LEN, NET_BUF_HEAD); 168 169 return TRUE; 170 } 171 172 173 /** 174 Build the vlan packet to transmit from the TxData passed in. 175 176 @param MnpServiceData Pointer to the mnp service context data. 177 @param TxData Pointer to the transmit data containing the 178 information to build the packet. 179 @param ProtocolType Pointer to the Ethernet protocol type. 180 @param Packet Pointer to record the address of the packet. 181 @param Length Pointer to a UINT32 variable used to record the 182 packet's length. 183 184 **/ 185 VOID 186 MnpInsertVlanTag ( 187 IN MNP_SERVICE_DATA *MnpServiceData, 188 IN EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData, 189 OUT UINT16 *ProtocolType, 190 IN OUT UINT8 **Packet, 191 IN OUT UINT32 *Length 192 ) 193 { 194 VLAN_TCI *VlanTci; 195 UINT16 *Tpid; 196 UINT16 *EtherType; 197 MNP_DEVICE_DATA *MnpDeviceData; 198 EFI_SIMPLE_NETWORK_MODE *SnpMode; 199 200 MnpDeviceData = MnpServiceData->MnpDeviceData; 201 SnpMode = MnpDeviceData->Snp->Mode; 202 203 *ProtocolType = ETHER_TYPE_VLAN; 204 *Length = *Length + NET_VLAN_TAG_LEN; 205 *Packet = *Packet - NET_VLAN_TAG_LEN; 206 207 Tpid = (UINT16 *) (*Packet + SnpMode->MediaHeaderSize - sizeof (*ProtocolType)); 208 VlanTci = (VLAN_TCI *) (UINTN) (Tpid + 1); 209 if (TxData->HeaderLength != 0) { 210 // 211 // Media header is in packet, move DA+SA 4 bytes left 212 // 213 CopyMem ( 214 *Packet, 215 *Packet + NET_VLAN_TAG_LEN, 216 SnpMode->MediaHeaderSize - sizeof (*ProtocolType) 217 ); 218 *Tpid = HTONS (ETHER_TYPE_VLAN); 219 } else { 220 // 221 // Media header not in packet, VLAN TCI and original protocol type becomes payload 222 // 223 EtherType = (UINT16 *) (UINTN) (VlanTci + 1); 224 *EtherType = HTONS (TxData->ProtocolType); 225 } 226 227 VlanTci->Bits.Vid = MnpServiceData->VlanId; 228 VlanTci->Bits.Cfi = VLAN_TCI_CFI_CANONICAL_MAC; 229 VlanTci->Bits.Priority = MnpServiceData->Priority; 230 VlanTci->Uint16 = HTONS (VlanTci->Uint16); 231 } 232 233 /** 234 Check VLAN configuration variable and delete the duplicative content if has identical Vlan ID. 235 236 @param[in] MnpDeviceData Pointer to the MNP device context data. 237 @param[in] Buffer Pointer to the buffer contains the array of VLAN_TCI. 238 @param[in] NumberOfVlan Pointer to number of VLAN. 239 @param[out] NewNumberOfVlan Pointer to number of unique VLAN. 240 241 @retval EFI_SUCCESS The VLAN variable is successfully checked. 242 @retval EFI_OUT_OF_RESOURCES There is not enough resource to set the configuration. 243 244 **/ 245 EFI_STATUS 246 MnpCheckVlanVariable ( 247 IN MNP_DEVICE_DATA *MnpDeviceData, 248 IN VLAN_TCI *Buffer, 249 IN UINTN NumberOfVlan, 250 OUT UINTN *NewNumberOfVlan 251 ) 252 { 253 UINTN Index; 254 UINTN Index2; 255 UINTN Count; 256 BOOLEAN FoundDuplicateItem; 257 EFI_STATUS Status; 258 259 Count = 0; 260 FoundDuplicateItem = FALSE; 261 Status = EFI_SUCCESS; 262 263 for (Index = 0; Index < NumberOfVlan; Index++) { 264 for (Index2 = Index + 1; Index2 < NumberOfVlan; Index2++) { 265 if (Buffer[Index].Bits.Vid == Buffer[Index2].Bits.Vid) { 266 FoundDuplicateItem = TRUE; 267 Count++; 268 break; 269 } 270 } 271 if (FoundDuplicateItem) { 272 for (Index2 = Index +1; Index2 < NumberOfVlan; Index++, Index2++) { 273 CopyMem (Buffer + Index, Buffer + Index2, sizeof (VLAN_TCI)); 274 } 275 } 276 FoundDuplicateItem = FALSE; 277 } 278 279 *NewNumberOfVlan = NumberOfVlan - Count; 280 if (Count != 0) { 281 Status = MnpSetVlanVariable (MnpDeviceData, *NewNumberOfVlan, Buffer); 282 } 283 284 return Status; 285 } 286 287 /** 288 Get VLAN configuration variable. 289 290 @param[in] MnpDeviceData Pointer to the MNP device context data. 291 @param[out] NumberOfVlan Pointer to number of VLAN to be returned. 292 @param[out] VlanVariable Pointer to the buffer to return requested 293 array of VLAN_TCI. 294 295 @retval EFI_SUCCESS The array of VLAN_TCI was returned in VlanVariable 296 and number of VLAN was returned in NumberOfVlan. 297 @retval EFI_NOT_FOUND VLAN configuration variable not found. 298 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the configuration. 299 300 **/ 301 EFI_STATUS 302 MnpGetVlanVariable ( 303 IN MNP_DEVICE_DATA *MnpDeviceData, 304 OUT UINTN *NumberOfVlan, 305 OUT VLAN_TCI **VlanVariable 306 ) 307 { 308 UINTN BufferSize; 309 EFI_STATUS Status; 310 VLAN_TCI *Buffer; 311 UINTN NewNumberOfVlan; 312 313 // 314 // Get VLAN configuration from EFI Variable 315 // 316 Buffer = NULL; 317 BufferSize = 0; 318 Status = gRT->GetVariable ( 319 MnpDeviceData->MacString, 320 &gEfiVlanConfigProtocolGuid, 321 NULL, 322 &BufferSize, 323 NULL 324 ); 325 if (Status != EFI_BUFFER_TOO_SMALL) { 326 return EFI_NOT_FOUND; 327 } 328 329 // 330 // Allocate buffer to read the variable 331 // 332 Buffer = AllocateZeroPool (BufferSize); 333 if (Buffer == NULL) { 334 return EFI_OUT_OF_RESOURCES; 335 } 336 337 Status = gRT->GetVariable ( 338 MnpDeviceData->MacString, 339 &gEfiVlanConfigProtocolGuid, 340 NULL, 341 &BufferSize, 342 Buffer 343 ); 344 if (EFI_ERROR (Status)) { 345 FreePool (Buffer); 346 return Status; 347 } 348 349 Status = MnpCheckVlanVariable (MnpDeviceData, Buffer, BufferSize / sizeof (VLAN_TCI), &NewNumberOfVlan); 350 if (!EFI_ERROR (Status)) { 351 *NumberOfVlan = NewNumberOfVlan; 352 *VlanVariable = Buffer; 353 } 354 355 return Status; 356 } 357 358 /** 359 Set VLAN configuration variable. 360 361 @param[in] MnpDeviceData Pointer to the MNP device context data. 362 @param[in] NumberOfVlan Number of VLAN in array VlanVariable. 363 @param[in] VlanVariable Pointer to array of VLAN_TCI. 364 365 @retval EFI_SUCCESS The VLAN variable is successfully set. 366 @retval EFI_OUT_OF_RESOURCES There is not enough resource to set the configuration. 367 368 **/ 369 EFI_STATUS 370 MnpSetVlanVariable ( 371 IN MNP_DEVICE_DATA *MnpDeviceData, 372 IN UINTN NumberOfVlan, 373 IN VLAN_TCI *VlanVariable 374 ) 375 { 376 return gRT->SetVariable ( 377 MnpDeviceData->MacString, 378 &gEfiVlanConfigProtocolGuid, 379 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, 380 NumberOfVlan * sizeof (VLAN_TCI), 381 VlanVariable 382 ); 383 } 384 385 386 /** 387 Create a VLAN device or modify the configuration parameter of an 388 already-configured VLAN. 389 390 The Set() function is used to create a new VLAN device or change the VLAN 391 configuration parameters. If the VlanId hasn't been configured in the 392 physical Ethernet device, a new VLAN device will be created. If a VLAN with 393 this VlanId is already configured, then related configuration will be updated 394 as the input parameters. 395 396 If VlanId is zero, the VLAN device will send and receive untagged frames. 397 Otherwise, the VLAN device will send and receive VLAN-tagged frames containing the VlanId. 398 If VlanId is out of scope of (0-4094), EFI_INVALID_PARAMETER is returned. 399 If Priority is out of the scope of (0-7), then EFI_INVALID_PARAMETER is returned. 400 If there is not enough system memory to perform the registration, then 401 EFI_OUT_OF_RESOURCES is returned. 402 403 @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL. 404 @param[in] VlanId A unique identifier (1-4094) of the VLAN which is being created 405 or modified, or zero (0). 406 @param[in] Priority 3 bit priority in VLAN header. Priority 0 is default value. If 407 VlanId is zero (0), Priority is ignored. 408 409 @retval EFI_SUCCESS The VLAN is successfully configured. 410 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE: 411 - This is NULL. 412 - VlanId is an invalid VLAN Identifier. 413 - Priority is invalid. 414 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to perform the registration. 415 416 **/ 417 EFI_STATUS 418 EFIAPI 419 VlanConfigSet ( 420 IN EFI_VLAN_CONFIG_PROTOCOL *This, 421 IN UINT16 VlanId, 422 IN UINT8 Priority 423 ) 424 { 425 EFI_STATUS Status; 426 MNP_DEVICE_DATA *MnpDeviceData; 427 MNP_SERVICE_DATA *MnpServiceData; 428 VLAN_TCI *OldVariable; 429 VLAN_TCI *NewVariable; 430 UINTN NumberOfVlan; 431 UINTN Index; 432 BOOLEAN IsAdd; 433 LIST_ENTRY *Entry; 434 435 if ((This == NULL) || (VlanId > 4094) || (Priority > 7)) { 436 return EFI_INVALID_PARAMETER; 437 } 438 439 IsAdd = FALSE; 440 MnpDeviceData = MNP_DEVICE_DATA_FROM_THIS (This); 441 if (MnpDeviceData->NumberOfVlan == 0) { 442 // 443 // No existing VLAN, this is the first VLAN to add 444 // 445 IsAdd = TRUE; 446 Entry = GetFirstNode (&MnpDeviceData->ServiceList); 447 MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry); 448 449 if (VlanId != 0) { 450 // 451 // VlanId is not 0, need destroy the default MNP service data 452 // 453 Status = MnpDestroyServiceChild (MnpServiceData); 454 if (EFI_ERROR (Status)) { 455 return Status; 456 } 457 458 Status = MnpDestroyServiceData (MnpServiceData); 459 if (EFI_ERROR (Status)) { 460 return Status; 461 } 462 463 // 464 // Create a new MNP service data for this VLAN 465 // 466 MnpServiceData = MnpCreateServiceData (MnpDeviceData, VlanId, Priority); 467 if (MnpServiceData == NULL) { 468 return EFI_OUT_OF_RESOURCES; 469 } 470 } 471 } else { 472 // 473 // Try to find VlanId in existing VLAN list 474 // 475 MnpServiceData = MnpFindServiceData (MnpDeviceData, VlanId); 476 if (MnpServiceData == NULL) { 477 // 478 // VlanId not found, create a new MNP service data 479 // 480 IsAdd = TRUE; 481 MnpServiceData = MnpCreateServiceData (MnpDeviceData, VlanId, Priority); 482 if (MnpServiceData == NULL) { 483 return EFI_OUT_OF_RESOURCES; 484 } 485 } 486 } 487 488 MnpServiceData->VlanId = VlanId; 489 MnpServiceData->Priority = Priority; 490 if (IsAdd) { 491 MnpDeviceData->NumberOfVlan++; 492 } 493 494 // 495 // Update VLAN configuration variable 496 // 497 OldVariable = NULL; 498 NewVariable = NULL; 499 NumberOfVlan = 0; 500 MnpGetVlanVariable (MnpDeviceData, &NumberOfVlan, &OldVariable); 501 502 if (IsAdd) { 503 // 504 // VLAN not exist - add 505 // 506 NewVariable = AllocateZeroPool ((NumberOfVlan + 1) * sizeof (VLAN_TCI)); 507 if (NewVariable == NULL) { 508 Status = EFI_OUT_OF_RESOURCES; 509 goto Exit; 510 } 511 512 if (OldVariable != NULL) { 513 CopyMem (NewVariable, OldVariable, NumberOfVlan * sizeof (VLAN_TCI)); 514 } 515 516 Index = NumberOfVlan++; 517 } else { 518 // 519 // VLAN already exist - update 520 // 521 for (Index = 0; Index < NumberOfVlan; Index++) { 522 if (OldVariable[Index].Bits.Vid == VlanId) { 523 break; 524 } 525 } 526 ASSERT (Index < NumberOfVlan); 527 528 NewVariable = OldVariable; 529 OldVariable = NULL; 530 } 531 532 NewVariable[Index].Bits.Vid = VlanId; 533 NewVariable[Index].Bits.Priority = Priority; 534 535 Status = MnpSetVlanVariable (MnpDeviceData, NumberOfVlan, NewVariable); 536 FreePool (NewVariable); 537 538 Exit: 539 if (OldVariable != NULL) { 540 FreePool (OldVariable); 541 } 542 543 return Status; 544 } 545 546 547 /** 548 Find configuration information for specified VLAN or all configured VLANs. 549 550 The Find() function is used to find the configuration information for matching 551 VLAN and allocate a buffer into which those entries are copied. 552 553 @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL. 554 @param[in] VlanId Pointer to VLAN identifier. Set to NULL to find all 555 configured VLANs. 556 @param[out] NumberOfVlan The number of VLANs which is found by the specified criteria. 557 @param[out] Entries The buffer which receive the VLAN configuration. 558 559 @retval EFI_SUCCESS The VLAN is successfully found. 560 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE: 561 - This is NULL. 562 - Specified VlanId is invalid. 563 @retval EFI_NOT_FOUND No matching VLAN is found. 564 565 **/ 566 EFI_STATUS 567 EFIAPI 568 VlanConfigFind ( 569 IN EFI_VLAN_CONFIG_PROTOCOL *This, 570 IN UINT16 *VlanId OPTIONAL, 571 OUT UINT16 *NumberOfVlan, 572 OUT EFI_VLAN_FIND_DATA **Entries 573 ) 574 { 575 MNP_DEVICE_DATA *MnpDeviceData; 576 MNP_SERVICE_DATA *MnpServiceData; 577 LIST_ENTRY *Entry; 578 EFI_VLAN_FIND_DATA *VlanData; 579 580 if ((This == NULL) || (VlanId != NULL && *VlanId > 4094) || (NumberOfVlan == NULL) || (Entries == NULL)) { 581 return EFI_INVALID_PARAMETER; 582 } 583 584 *NumberOfVlan = 0; 585 *Entries = NULL; 586 587 MnpDeviceData = MNP_DEVICE_DATA_FROM_THIS (This); 588 if (MnpDeviceData->NumberOfVlan == 0) { 589 return EFI_NOT_FOUND; 590 } 591 592 if (VlanId == NULL) { 593 // 594 // Return all current VLAN configuration 595 // 596 *NumberOfVlan = (UINT16) MnpDeviceData->NumberOfVlan; 597 VlanData = AllocateZeroPool (*NumberOfVlan * sizeof (EFI_VLAN_FIND_DATA)); 598 if (VlanData == NULL) { 599 return EFI_OUT_OF_RESOURCES; 600 } 601 602 *Entries = VlanData; 603 NET_LIST_FOR_EACH (Entry, &MnpDeviceData->ServiceList) { 604 MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry); 605 606 VlanData->VlanId = MnpServiceData->VlanId; 607 VlanData->Priority = MnpServiceData->Priority; 608 VlanData++; 609 } 610 611 return EFI_SUCCESS; 612 } 613 614 // 615 // VlanId is specified, try to find it in current VLAN list 616 // 617 MnpServiceData = MnpFindServiceData (MnpDeviceData, *VlanId); 618 if (MnpServiceData == NULL) { 619 return EFI_NOT_FOUND; 620 } 621 622 VlanData = AllocateZeroPool (sizeof (EFI_VLAN_FIND_DATA)); 623 if (VlanData == NULL) { 624 return EFI_OUT_OF_RESOURCES; 625 } 626 VlanData->VlanId = MnpServiceData->VlanId; 627 VlanData->Priority = MnpServiceData->Priority; 628 629 *NumberOfVlan = 1; 630 *Entries = VlanData; 631 632 return EFI_SUCCESS; 633 } 634 635 636 /** 637 Remove the configured VLAN device. 638 639 The Remove() function is used to remove the specified VLAN device. 640 If the VlanId is out of the scope of (0-4094), EFI_INVALID_PARAMETER is returned. 641 If specified VLAN hasn't been previously configured, EFI_NOT_FOUND is returned. 642 643 @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL. 644 @param[in] VlanId Identifier (0-4094) of the VLAN to be removed. 645 646 @retval EFI_SUCCESS The VLAN is successfully removed. 647 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE: 648 - This is NULL. 649 - VlanId is an invalid parameter. 650 @retval EFI_NOT_FOUND The to-be-removed VLAN does not exist. 651 652 **/ 653 EFI_STATUS 654 EFIAPI 655 VlanConfigRemove ( 656 IN EFI_VLAN_CONFIG_PROTOCOL *This, 657 IN UINT16 VlanId 658 ) 659 { 660 EFI_STATUS Status; 661 MNP_DEVICE_DATA *MnpDeviceData; 662 MNP_SERVICE_DATA *MnpServiceData; 663 LIST_ENTRY *Entry; 664 VLAN_TCI *VlanVariable; 665 VLAN_TCI *VlanData; 666 667 if ((This == NULL) || (VlanId > 4094)) { 668 return EFI_INVALID_PARAMETER; 669 } 670 671 MnpDeviceData = MNP_DEVICE_DATA_FROM_THIS (This); 672 if (MnpDeviceData->NumberOfVlan == 0) { 673 return EFI_NOT_FOUND; 674 } 675 676 // 677 // Try to find the VlanId 678 // 679 MnpServiceData = MnpFindServiceData (MnpDeviceData, VlanId); 680 if (MnpServiceData == NULL) { 681 return EFI_NOT_FOUND; 682 } 683 684 MnpDeviceData->NumberOfVlan--; 685 686 if ((VlanId != 0) || (MnpDeviceData->NumberOfVlan != 0)) { 687 // 688 // If VlanId is not 0 or VlanId is 0 and it is not the last VLAN to remove, 689 // destroy its MNP service data 690 // 691 Status = MnpDestroyServiceChild (MnpServiceData); 692 if (EFI_ERROR (Status)) { 693 return Status; 694 } 695 696 Status = MnpDestroyServiceData (MnpServiceData); 697 if (EFI_ERROR (Status)) { 698 return Status; 699 } 700 } 701 702 if ((VlanId != 0) && (MnpDeviceData->NumberOfVlan == 0)) { 703 // 704 // This is the last VLAN to be removed, restore the default MNP service data 705 // 706 MnpServiceData = MnpCreateServiceData (MnpDeviceData, 0, 0); 707 if (MnpServiceData == NULL) { 708 return EFI_OUT_OF_RESOURCES; 709 } 710 } 711 712 // 713 // Update VLAN configuration variable 714 // 715 VlanVariable = NULL; 716 if (MnpDeviceData->NumberOfVlan != 0) { 717 VlanVariable = AllocatePool (MnpDeviceData->NumberOfVlan * sizeof (VLAN_TCI)); 718 if (VlanVariable == NULL) { 719 return EFI_OUT_OF_RESOURCES; 720 } 721 722 VlanData = VlanVariable; 723 NET_LIST_FOR_EACH (Entry, &MnpDeviceData->ServiceList) { 724 MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry); 725 726 VlanData->Bits.Vid = MnpServiceData->VlanId; 727 VlanData->Bits.Priority = MnpServiceData->Priority; 728 VlanData++; 729 } 730 } 731 732 Status = MnpSetVlanVariable (MnpDeviceData, MnpDeviceData->NumberOfVlan, VlanVariable); 733 734 if (VlanVariable != NULL) { 735 FreePool (VlanVariable); 736 } 737 738 return Status; 739 } 740