1 /** @file
2 VLAN Config Protocol implementation and VLAN packet process routine.
3
4 Copyright (c) 2009 - 2014, 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
MnpCreateVlanChild(IN EFI_HANDLE ImageHandle,IN EFI_HANDLE ControllerHandle,IN UINT16 VlanId,OUT EFI_DEVICE_PATH_PROTOCOL ** Devicepath OPTIONAL)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
MnpRemoveVlanTag(IN OUT MNP_DEVICE_DATA * MnpDeviceData,IN OUT NET_BUF * Nbuf,OUT UINT16 * VlanId)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
MnpInsertVlanTag(IN MNP_SERVICE_DATA * MnpServiceData,IN EFI_MANAGED_NETWORK_TRANSMIT_DATA * TxData,OUT UINT16 * ProtocolType,IN OUT UINT8 ** Packet,IN OUT UINT32 * Length)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 /**
235 Get VLAN configuration variable.
236
237 @param[in] MnpDeviceData Pointer to the MNP device context data.
238 @param[out] NumberOfVlan Pointer to number of VLAN to be returned.
239 @param[out] VlanVariable Pointer to the buffer to return requested
240 array of VLAN_TCI.
241
242 @retval EFI_SUCCESS The array of VLAN_TCI was returned in VlanVariable
243 and number of VLAN was returned in NumberOfVlan.
244 @retval EFI_NOT_FOUND VLAN configuration variable not found.
245 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the configuration.
246
247 **/
248 EFI_STATUS
MnpGetVlanVariable(IN MNP_DEVICE_DATA * MnpDeviceData,OUT UINTN * NumberOfVlan,OUT VLAN_TCI ** VlanVariable)249 MnpGetVlanVariable (
250 IN MNP_DEVICE_DATA *MnpDeviceData,
251 OUT UINTN *NumberOfVlan,
252 OUT VLAN_TCI **VlanVariable
253 )
254 {
255 UINTN BufferSize;
256 EFI_STATUS Status;
257 VLAN_TCI *Buffer;
258
259 //
260 // Get VLAN configuration from EFI Variable
261 //
262 Buffer = NULL;
263 BufferSize = 0;
264 Status = gRT->GetVariable (
265 MnpDeviceData->MacString,
266 &gEfiVlanConfigProtocolGuid,
267 NULL,
268 &BufferSize,
269 NULL
270 );
271 if (Status != EFI_BUFFER_TOO_SMALL) {
272 return EFI_NOT_FOUND;
273 }
274
275 //
276 // Allocate buffer to read the variable
277 //
278 Buffer = AllocateZeroPool (BufferSize);
279 if (Buffer == NULL) {
280 return EFI_OUT_OF_RESOURCES;
281 }
282
283 Status = gRT->GetVariable (
284 MnpDeviceData->MacString,
285 &gEfiVlanConfigProtocolGuid,
286 NULL,
287 &BufferSize,
288 Buffer
289 );
290 if (EFI_ERROR (Status)) {
291 FreePool (Buffer);
292 return Status;
293 }
294
295 *NumberOfVlan = BufferSize / sizeof (VLAN_TCI);
296 *VlanVariable = Buffer;
297
298 return Status;
299 }
300
301
302 /**
303 Set VLAN configuration variable.
304
305 @param[in] MnpDeviceData Pointer to the MNP device context data.
306 @param[in] NumberOfVlan Number of VLAN in array VlanVariable.
307 @param[in] VlanVariable Pointer to array of VLAN_TCI.
308
309 @retval EFI_SUCCESS The VLAN variable is successfully set.
310 @retval EFI_OUT_OF_RESOURCES There is not enough resource to set the configuration.
311
312 **/
313 EFI_STATUS
MnpSetVlanVariable(IN MNP_DEVICE_DATA * MnpDeviceData,IN UINTN NumberOfVlan,IN VLAN_TCI * VlanVariable)314 MnpSetVlanVariable (
315 IN MNP_DEVICE_DATA *MnpDeviceData,
316 IN UINTN NumberOfVlan,
317 IN VLAN_TCI *VlanVariable
318 )
319 {
320 return gRT->SetVariable (
321 MnpDeviceData->MacString,
322 &gEfiVlanConfigProtocolGuid,
323 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
324 NumberOfVlan * sizeof (VLAN_TCI),
325 VlanVariable
326 );
327 }
328
329
330 /**
331 Create a VLAN device or modify the configuration parameter of an
332 already-configured VLAN.
333
334 The Set() function is used to create a new VLAN device or change the VLAN
335 configuration parameters. If the VlanId hasn't been configured in the
336 physical Ethernet device, a new VLAN device will be created. If a VLAN with
337 this VlanId is already configured, then related configuration will be updated
338 as the input parameters.
339
340 If VlanId is zero, the VLAN device will send and receive untagged frames.
341 Otherwise, the VLAN device will send and receive VLAN-tagged frames containing the VlanId.
342 If VlanId is out of scope of (0-4094), EFI_INVALID_PARAMETER is returned.
343 If Priority is out of the scope of (0-7), then EFI_INVALID_PARAMETER is returned.
344 If there is not enough system memory to perform the registration, then
345 EFI_OUT_OF_RESOURCES is returned.
346
347 @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL.
348 @param[in] VlanId A unique identifier (1-4094) of the VLAN which is being created
349 or modified, or zero (0).
350 @param[in] Priority 3 bit priority in VLAN header. Priority 0 is default value. If
351 VlanId is zero (0), Priority is ignored.
352
353 @retval EFI_SUCCESS The VLAN is successfully configured.
354 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:
355 - This is NULL.
356 - VlanId is an invalid VLAN Identifier.
357 - Priority is invalid.
358 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to perform the registration.
359
360 **/
361 EFI_STATUS
362 EFIAPI
VlanConfigSet(IN EFI_VLAN_CONFIG_PROTOCOL * This,IN UINT16 VlanId,IN UINT8 Priority)363 VlanConfigSet (
364 IN EFI_VLAN_CONFIG_PROTOCOL *This,
365 IN UINT16 VlanId,
366 IN UINT8 Priority
367 )
368 {
369 EFI_STATUS Status;
370 MNP_DEVICE_DATA *MnpDeviceData;
371 MNP_SERVICE_DATA *MnpServiceData;
372 VLAN_TCI *OldVariable;
373 VLAN_TCI *NewVariable;
374 UINTN NumberOfVlan;
375 UINTN Index;
376 BOOLEAN IsAdd;
377 LIST_ENTRY *Entry;
378
379 if ((This == NULL) || (VlanId > 4094) || (Priority > 7)) {
380 return EFI_INVALID_PARAMETER;
381 }
382
383 IsAdd = FALSE;
384 MnpDeviceData = MNP_DEVICE_DATA_FROM_THIS (This);
385 if (MnpDeviceData->NumberOfVlan == 0) {
386 //
387 // No existing VLAN, this is the first VLAN to add
388 //
389 IsAdd = TRUE;
390 Entry = GetFirstNode (&MnpDeviceData->ServiceList);
391 MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry);
392
393 if (VlanId != 0) {
394 //
395 // VlanId is not 0, need destroy the default MNP service data
396 //
397 Status = MnpDestroyServiceChild (MnpServiceData);
398 if (EFI_ERROR (Status)) {
399 return Status;
400 }
401
402 Status = MnpDestroyServiceData (MnpServiceData);
403 if (EFI_ERROR (Status)) {
404 return Status;
405 }
406
407 //
408 // Create a new MNP service data for this VLAN
409 //
410 MnpServiceData = MnpCreateServiceData (MnpDeviceData, VlanId, Priority);
411 if (MnpServiceData == NULL) {
412 return EFI_OUT_OF_RESOURCES;
413 }
414 }
415 } else {
416 //
417 // Try to find VlanId in existing VLAN list
418 //
419 MnpServiceData = MnpFindServiceData (MnpDeviceData, VlanId);
420 if (MnpServiceData == NULL) {
421 //
422 // VlanId not found, create a new MNP service data
423 //
424 IsAdd = TRUE;
425 MnpServiceData = MnpCreateServiceData (MnpDeviceData, VlanId, Priority);
426 if (MnpServiceData == NULL) {
427 return EFI_OUT_OF_RESOURCES;
428 }
429 }
430 }
431
432 MnpServiceData->VlanId = VlanId;
433 MnpServiceData->Priority = Priority;
434 if (IsAdd) {
435 MnpDeviceData->NumberOfVlan++;
436 }
437
438 //
439 // Update VLAN configuration variable
440 //
441 OldVariable = NULL;
442 NewVariable = NULL;
443 NumberOfVlan = 0;
444 MnpGetVlanVariable (MnpDeviceData, &NumberOfVlan, &OldVariable);
445
446 if (IsAdd) {
447 //
448 // VLAN not exist - add
449 //
450 NewVariable = AllocateZeroPool ((NumberOfVlan + 1) * sizeof (VLAN_TCI));
451 if (NewVariable == NULL) {
452 Status = EFI_OUT_OF_RESOURCES;
453 goto Exit;
454 }
455
456 if (OldVariable != NULL) {
457 CopyMem (NewVariable, OldVariable, NumberOfVlan * sizeof (VLAN_TCI));
458 }
459
460 Index = NumberOfVlan++;
461 } else {
462 //
463 // VLAN already exist - update
464 //
465 for (Index = 0; Index < NumberOfVlan; Index++) {
466 if (OldVariable[Index].Bits.Vid == VlanId) {
467 break;
468 }
469 }
470 ASSERT (Index < NumberOfVlan);
471
472 NewVariable = OldVariable;
473 OldVariable = NULL;
474 }
475
476 NewVariable[Index].Bits.Vid = VlanId;
477 NewVariable[Index].Bits.Priority = Priority;
478
479 Status = MnpSetVlanVariable (MnpDeviceData, NumberOfVlan, NewVariable);
480 FreePool (NewVariable);
481
482 Exit:
483 if (OldVariable != NULL) {
484 FreePool (OldVariable);
485 }
486
487 return Status;
488 }
489
490
491 /**
492 Find configuration information for specified VLAN or all configured VLANs.
493
494 The Find() function is used to find the configuration information for matching
495 VLAN and allocate a buffer into which those entries are copied.
496
497 @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL.
498 @param[in] VlanId Pointer to VLAN identifier. Set to NULL to find all
499 configured VLANs.
500 @param[out] NumberOfVlan The number of VLANs which is found by the specified criteria.
501 @param[out] Entries The buffer which receive the VLAN configuration.
502
503 @retval EFI_SUCCESS The VLAN is successfully found.
504 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:
505 - This is NULL.
506 - Specified VlanId is invalid.
507 @retval EFI_NOT_FOUND No matching VLAN is found.
508
509 **/
510 EFI_STATUS
511 EFIAPI
VlanConfigFind(IN EFI_VLAN_CONFIG_PROTOCOL * This,IN UINT16 * VlanId OPTIONAL,OUT UINT16 * NumberOfVlan,OUT EFI_VLAN_FIND_DATA ** Entries)512 VlanConfigFind (
513 IN EFI_VLAN_CONFIG_PROTOCOL *This,
514 IN UINT16 *VlanId OPTIONAL,
515 OUT UINT16 *NumberOfVlan,
516 OUT EFI_VLAN_FIND_DATA **Entries
517 )
518 {
519 MNP_DEVICE_DATA *MnpDeviceData;
520 MNP_SERVICE_DATA *MnpServiceData;
521 LIST_ENTRY *Entry;
522 EFI_VLAN_FIND_DATA *VlanData;
523
524 if ((This == NULL) || (VlanId != NULL && *VlanId > 4094) || (NumberOfVlan == NULL) || (Entries == NULL)) {
525 return EFI_INVALID_PARAMETER;
526 }
527
528 *NumberOfVlan = 0;
529 *Entries = NULL;
530
531 MnpDeviceData = MNP_DEVICE_DATA_FROM_THIS (This);
532 if (MnpDeviceData->NumberOfVlan == 0) {
533 return EFI_NOT_FOUND;
534 }
535
536 if (VlanId == NULL) {
537 //
538 // Return all current VLAN configuration
539 //
540 *NumberOfVlan = (UINT16) MnpDeviceData->NumberOfVlan;
541 VlanData = AllocateZeroPool (*NumberOfVlan * sizeof (EFI_VLAN_FIND_DATA));
542 if (VlanData == NULL) {
543 return EFI_OUT_OF_RESOURCES;
544 }
545
546 *Entries = VlanData;
547 NET_LIST_FOR_EACH (Entry, &MnpDeviceData->ServiceList) {
548 MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry);
549
550 VlanData->VlanId = MnpServiceData->VlanId;
551 VlanData->Priority = MnpServiceData->Priority;
552 VlanData++;
553 }
554
555 return EFI_SUCCESS;
556 }
557
558 //
559 // VlanId is specified, try to find it in current VLAN list
560 //
561 MnpServiceData = MnpFindServiceData (MnpDeviceData, *VlanId);
562 if (MnpServiceData == NULL) {
563 return EFI_NOT_FOUND;
564 }
565
566 VlanData = AllocateZeroPool (sizeof (EFI_VLAN_FIND_DATA));
567 if (VlanData == NULL) {
568 return EFI_OUT_OF_RESOURCES;
569 }
570 VlanData->VlanId = MnpServiceData->VlanId;
571 VlanData->Priority = MnpServiceData->Priority;
572
573 *NumberOfVlan = 1;
574 *Entries = VlanData;
575
576 return EFI_SUCCESS;
577 }
578
579
580 /**
581 Remove the configured VLAN device.
582
583 The Remove() function is used to remove the specified VLAN device.
584 If the VlanId is out of the scope of (0-4094), EFI_INVALID_PARAMETER is returned.
585 If specified VLAN hasn't been previously configured, EFI_NOT_FOUND is returned.
586
587 @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL.
588 @param[in] VlanId Identifier (0-4094) of the VLAN to be removed.
589
590 @retval EFI_SUCCESS The VLAN is successfully removed.
591 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:
592 - This is NULL.
593 - VlanId is an invalid parameter.
594 @retval EFI_NOT_FOUND The to-be-removed VLAN does not exist.
595
596 **/
597 EFI_STATUS
598 EFIAPI
VlanConfigRemove(IN EFI_VLAN_CONFIG_PROTOCOL * This,IN UINT16 VlanId)599 VlanConfigRemove (
600 IN EFI_VLAN_CONFIG_PROTOCOL *This,
601 IN UINT16 VlanId
602 )
603 {
604 EFI_STATUS Status;
605 MNP_DEVICE_DATA *MnpDeviceData;
606 MNP_SERVICE_DATA *MnpServiceData;
607 LIST_ENTRY *Entry;
608 VLAN_TCI *VlanVariable;
609 VLAN_TCI *VlanData;
610
611 if ((This == NULL) || (VlanId > 4094)) {
612 return EFI_INVALID_PARAMETER;
613 }
614
615 MnpDeviceData = MNP_DEVICE_DATA_FROM_THIS (This);
616 if (MnpDeviceData->NumberOfVlan == 0) {
617 return EFI_NOT_FOUND;
618 }
619
620 //
621 // Try to find the VlanId
622 //
623 MnpServiceData = MnpFindServiceData (MnpDeviceData, VlanId);
624 if (MnpServiceData == NULL) {
625 return EFI_NOT_FOUND;
626 }
627
628 MnpDeviceData->NumberOfVlan--;
629
630 if ((VlanId != 0) || (MnpDeviceData->NumberOfVlan != 0)) {
631 //
632 // If VlanId is not 0 or VlanId is 0 and it is not the last VLAN to remove,
633 // destroy its MNP service data
634 //
635 Status = MnpDestroyServiceChild (MnpServiceData);
636 if (EFI_ERROR (Status)) {
637 return Status;
638 }
639
640 Status = MnpDestroyServiceData (MnpServiceData);
641 if (EFI_ERROR (Status)) {
642 return Status;
643 }
644 }
645
646 if ((VlanId != 0) && (MnpDeviceData->NumberOfVlan == 0)) {
647 //
648 // This is the last VLAN to be removed, restore the default MNP service data
649 //
650 MnpServiceData = MnpCreateServiceData (MnpDeviceData, 0, 0);
651 if (MnpServiceData == NULL) {
652 return EFI_OUT_OF_RESOURCES;
653 }
654 }
655
656 //
657 // Update VLAN configuration variable
658 //
659 VlanVariable = NULL;
660 if (MnpDeviceData->NumberOfVlan != 0) {
661 VlanVariable = AllocatePool (MnpDeviceData->NumberOfVlan * sizeof (VLAN_TCI));
662 if (VlanVariable == NULL) {
663 return EFI_OUT_OF_RESOURCES;
664 }
665
666 VlanData = VlanVariable;
667 NET_LIST_FOR_EACH (Entry, &MnpDeviceData->ServiceList) {
668 MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry);
669
670 VlanData->Bits.Vid = MnpServiceData->VlanId;
671 VlanData->Bits.Priority = MnpServiceData->Priority;
672 VlanData++;
673 }
674 }
675
676 Status = MnpSetVlanVariable (MnpDeviceData, MnpDeviceData->NumberOfVlan, VlanVariable);
677
678 if (VlanVariable != NULL) {
679 FreePool (VlanVariable);
680 }
681
682 return Status;
683 }
684