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
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 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
MnpCheckVlanVariable(IN MNP_DEVICE_DATA * MnpDeviceData,IN VLAN_TCI * Buffer,IN UINTN NumberOfVlan,OUT UINTN * NewNumberOfVlan)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
MnpGetVlanVariable(IN MNP_DEVICE_DATA * MnpDeviceData,OUT UINTN * NumberOfVlan,OUT VLAN_TCI ** VlanVariable)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
MnpSetVlanVariable(IN MNP_DEVICE_DATA * MnpDeviceData,IN UINTN NumberOfVlan,IN VLAN_TCI * VlanVariable)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
VlanConfigSet(IN EFI_VLAN_CONFIG_PROTOCOL * This,IN UINT16 VlanId,IN UINT8 Priority)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
VlanConfigFind(IN EFI_VLAN_CONFIG_PROTOCOL * This,IN UINT16 * VlanId OPTIONAL,OUT UINT16 * NumberOfVlan,OUT EFI_VLAN_FIND_DATA ** Entries)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
VlanConfigRemove(IN EFI_VLAN_CONFIG_PROTOCOL * This,IN UINT16 VlanId)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