2 VLAN Config Protocol implementation and VLAN packet process routine.
4 Copyright (c) 2009 - 2018, 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
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.
19 VLAN_DEVICE_PATH mVlanDevicePathTemplate
= {
21 MESSAGING_DEVICE_PATH
,
24 (UINT8
) (sizeof (VLAN_DEVICE_PATH
)),
25 (UINT8
) ((sizeof (VLAN_DEVICE_PATH
)) >> 8)
31 EFI_VLAN_CONFIG_PROTOCOL mVlanConfigProtocolTemplate
= {
39 Create a child handle for the VLAN ID.
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.
46 @return The handle of VLAN child or NULL if failed to create VLAN child.
51 IN EFI_HANDLE ImageHandle
,
52 IN EFI_HANDLE ControllerHandle
,
54 OUT EFI_DEVICE_PATH_PROTOCOL
**Devicepath OPTIONAL
57 EFI_HANDLE ChildHandle
;
58 VLAN_DEVICE_PATH VlanNode
;
59 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
60 EFI_DEVICE_PATH_PROTOCOL
*VlanDevicePath
;
64 // Try to get parent device path
66 Status
= gBS
->OpenProtocol (
68 &gEfiDevicePathProtocolGuid
,
69 (VOID
**) &ParentDevicePath
,
72 EFI_OPEN_PROTOCOL_GET_PROTOCOL
74 if (EFI_ERROR (Status
)) {
79 // Construct device path for child handle: MAC + VLAN
81 CopyMem (&VlanNode
, &mVlanDevicePathTemplate
, sizeof (VLAN_DEVICE_PATH
));
82 VlanNode
.VlanId
= VlanId
;
83 VlanDevicePath
= AppendDevicePathNode (
85 (EFI_DEVICE_PATH_PROTOCOL
*) &VlanNode
87 if (VlanDevicePath
== NULL
) {
92 // Create child VLAN handle by installing DevicePath protocol
95 Status
= gBS
->InstallMultipleProtocolInterfaces (
97 &gEfiDevicePathProtocolGuid
,
101 if (EFI_ERROR (Status
)) {
102 FreePool (VlanDevicePath
);
106 if (Devicepath
!= NULL
) {
107 *Devicepath
= VlanDevicePath
;
114 Remove VLAN tag from a packet.
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.
120 @retval TRUE VLAN tag is removed from this packet.
121 @retval FALSE There is no VLAN tag in this packet.
126 IN OUT MNP_DEVICE_DATA
*MnpDeviceData
,
127 IN OUT NET_BUF
*Nbuf
,
132 UINTN ProtocolOffset
;
136 ProtocolOffset
= MnpDeviceData
->Snp
->Mode
->HwAddressSize
* 2;
139 // Get the packet buffer.
141 Packet
= NetbufGetByte (Nbuf
, 0, NULL
);
142 ASSERT (Packet
!= NULL
);
145 // Check whether this is VLAN tagged frame by Ether Type
148 ProtocolType
= NTOHS (*(UINT16
*) (Packet
+ ProtocolOffset
));
149 if (ProtocolType
!= ETHER_TYPE_VLAN
) {
151 // Not a VLAN tagged frame
156 VlanTag
.Uint16
= NTOHS (*(UINT16
*) (Packet
+ ProtocolOffset
+ sizeof (ProtocolType
)));
157 *VlanId
= VlanTag
.Bits
.Vid
;
160 // Move hardware address (DA + SA) 4 bytes right to override VLAN tag
162 CopyMem (Packet
+ NET_VLAN_TAG_LEN
, Packet
, ProtocolOffset
);
165 // Remove VLAN tag from the Nbuf
167 NetbufTrim (Nbuf
, NET_VLAN_TAG_LEN
, NET_BUF_HEAD
);
174 Build the vlan packet to transmit from the TxData passed in.
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
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
197 MNP_DEVICE_DATA
*MnpDeviceData
;
198 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
200 MnpDeviceData
= MnpServiceData
->MnpDeviceData
;
201 SnpMode
= MnpDeviceData
->Snp
->Mode
;
203 *ProtocolType
= ETHER_TYPE_VLAN
;
204 *Length
= *Length
+ NET_VLAN_TAG_LEN
;
205 *Packet
= *Packet
- NET_VLAN_TAG_LEN
;
207 Tpid
= (UINT16
*) (*Packet
+ SnpMode
->MediaHeaderSize
- sizeof (*ProtocolType
));
208 VlanTci
= (VLAN_TCI
*) (UINTN
) (Tpid
+ 1);
209 if (TxData
->HeaderLength
!= 0) {
211 // Media header is in packet, move DA+SA 4 bytes left
215 *Packet
+ NET_VLAN_TAG_LEN
,
216 SnpMode
->MediaHeaderSize
- sizeof (*ProtocolType
)
218 *Tpid
= HTONS (ETHER_TYPE_VLAN
);
221 // Media header not in packet, VLAN TCI and original protocol type becomes payload
223 EtherType
= (UINT16
*) (UINTN
) (VlanTci
+ 1);
224 *EtherType
= HTONS (TxData
->ProtocolType
);
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
);
234 Check VLAN configuration variable and delete the duplicative content if has identical Vlan ID.
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.
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.
246 MnpCheckVlanVariable (
247 IN MNP_DEVICE_DATA
*MnpDeviceData
,
249 IN UINTN NumberOfVlan
,
250 OUT UINTN
*NewNumberOfVlan
256 BOOLEAN FoundDuplicateItem
;
260 FoundDuplicateItem
= FALSE
;
261 Status
= EFI_SUCCESS
;
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
;
271 if (FoundDuplicateItem
) {
272 for (Index2
= Index
+1; Index2
< NumberOfVlan
; Index
++, Index2
++) {
273 CopyMem (Buffer
+ Index
, Buffer
+ Index2
, sizeof (VLAN_TCI
));
276 FoundDuplicateItem
= FALSE
;
279 *NewNumberOfVlan
= NumberOfVlan
- Count
;
281 Status
= MnpSetVlanVariable (MnpDeviceData
, *NewNumberOfVlan
, Buffer
);
288 Get VLAN configuration variable.
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
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.
303 IN MNP_DEVICE_DATA
*MnpDeviceData
,
304 OUT UINTN
*NumberOfVlan
,
305 OUT VLAN_TCI
**VlanVariable
311 UINTN NewNumberOfVlan
;
314 // Get VLAN configuration from EFI Variable
318 Status
= gRT
->GetVariable (
319 MnpDeviceData
->MacString
,
320 &gEfiVlanConfigProtocolGuid
,
325 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
326 return EFI_NOT_FOUND
;
330 // Allocate buffer to read the variable
332 Buffer
= AllocateZeroPool (BufferSize
);
333 if (Buffer
== NULL
) {
334 return EFI_OUT_OF_RESOURCES
;
337 Status
= gRT
->GetVariable (
338 MnpDeviceData
->MacString
,
339 &gEfiVlanConfigProtocolGuid
,
344 if (EFI_ERROR (Status
)) {
349 Status
= MnpCheckVlanVariable (MnpDeviceData
, Buffer
, BufferSize
/ sizeof (VLAN_TCI
), &NewNumberOfVlan
);
350 if (!EFI_ERROR (Status
)) {
351 *NumberOfVlan
= NewNumberOfVlan
;
352 *VlanVariable
= Buffer
;
359 Set VLAN configuration variable.
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.
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.
371 IN MNP_DEVICE_DATA
*MnpDeviceData
,
372 IN UINTN NumberOfVlan
,
373 IN VLAN_TCI
*VlanVariable
376 return gRT
->SetVariable (
377 MnpDeviceData
->MacString
,
378 &gEfiVlanConfigProtocolGuid
,
379 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
380 NumberOfVlan
* sizeof (VLAN_TCI
),
387 Create a VLAN device or modify the configuration parameter of an
388 already-configured VLAN.
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.
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.
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.
409 @retval EFI_SUCCESS The VLAN is successfully configured.
410 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:
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.
420 IN EFI_VLAN_CONFIG_PROTOCOL
*This
,
426 MNP_DEVICE_DATA
*MnpDeviceData
;
427 MNP_SERVICE_DATA
*MnpServiceData
;
428 VLAN_TCI
*OldVariable
;
429 VLAN_TCI
*NewVariable
;
435 if ((This
== NULL
) || (VlanId
> 4094) || (Priority
> 7)) {
436 return EFI_INVALID_PARAMETER
;
440 MnpDeviceData
= MNP_DEVICE_DATA_FROM_THIS (This
);
441 if (MnpDeviceData
->NumberOfVlan
== 0) {
443 // No existing VLAN, this is the first VLAN to add
446 Entry
= GetFirstNode (&MnpDeviceData
->ServiceList
);
447 MnpServiceData
= MNP_SERVICE_DATA_FROM_LINK (Entry
);
451 // VlanId is not 0, need destroy the default MNP service data
453 Status
= MnpDestroyServiceChild (MnpServiceData
);
454 if (EFI_ERROR (Status
)) {
458 Status
= MnpDestroyServiceData (MnpServiceData
);
459 if (EFI_ERROR (Status
)) {
464 // Create a new MNP service data for this VLAN
466 MnpServiceData
= MnpCreateServiceData (MnpDeviceData
, VlanId
, Priority
);
467 if (MnpServiceData
== NULL
) {
468 return EFI_OUT_OF_RESOURCES
;
473 // Try to find VlanId in existing VLAN list
475 MnpServiceData
= MnpFindServiceData (MnpDeviceData
, VlanId
);
476 if (MnpServiceData
== NULL
) {
478 // VlanId not found, create a new MNP service data
481 MnpServiceData
= MnpCreateServiceData (MnpDeviceData
, VlanId
, Priority
);
482 if (MnpServiceData
== NULL
) {
483 return EFI_OUT_OF_RESOURCES
;
488 MnpServiceData
->VlanId
= VlanId
;
489 MnpServiceData
->Priority
= Priority
;
491 MnpDeviceData
->NumberOfVlan
++;
495 // Update VLAN configuration variable
500 MnpGetVlanVariable (MnpDeviceData
, &NumberOfVlan
, &OldVariable
);
504 // VLAN not exist - add
506 NewVariable
= AllocateZeroPool ((NumberOfVlan
+ 1) * sizeof (VLAN_TCI
));
507 if (NewVariable
== NULL
) {
508 Status
= EFI_OUT_OF_RESOURCES
;
512 if (OldVariable
!= NULL
) {
513 CopyMem (NewVariable
, OldVariable
, NumberOfVlan
* sizeof (VLAN_TCI
));
516 Index
= NumberOfVlan
++;
519 // VLAN already exist - update
521 for (Index
= 0; Index
< NumberOfVlan
; Index
++) {
522 if (OldVariable
[Index
].Bits
.Vid
== VlanId
) {
526 ASSERT (Index
< NumberOfVlan
);
528 NewVariable
= OldVariable
;
532 NewVariable
[Index
].Bits
.Vid
= VlanId
;
533 NewVariable
[Index
].Bits
.Priority
= Priority
;
535 Status
= MnpSetVlanVariable (MnpDeviceData
, NumberOfVlan
, NewVariable
);
536 FreePool (NewVariable
);
539 if (OldVariable
!= NULL
) {
540 FreePool (OldVariable
);
548 Find configuration information for specified VLAN or all configured VLANs.
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.
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
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.
559 @retval EFI_SUCCESS The VLAN is successfully found.
560 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:
562 - Specified VlanId is invalid.
563 @retval EFI_NOT_FOUND No matching VLAN is found.
569 IN EFI_VLAN_CONFIG_PROTOCOL
*This
,
570 IN UINT16
*VlanId OPTIONAL
,
571 OUT UINT16
*NumberOfVlan
,
572 OUT EFI_VLAN_FIND_DATA
**Entries
575 MNP_DEVICE_DATA
*MnpDeviceData
;
576 MNP_SERVICE_DATA
*MnpServiceData
;
578 EFI_VLAN_FIND_DATA
*VlanData
;
580 if ((This
== NULL
) || (VlanId
!= NULL
&& *VlanId
> 4094) || (NumberOfVlan
== NULL
) || (Entries
== NULL
)) {
581 return EFI_INVALID_PARAMETER
;
587 MnpDeviceData
= MNP_DEVICE_DATA_FROM_THIS (This
);
588 if (MnpDeviceData
->NumberOfVlan
== 0) {
589 return EFI_NOT_FOUND
;
592 if (VlanId
== NULL
) {
594 // Return all current VLAN configuration
596 *NumberOfVlan
= (UINT16
) MnpDeviceData
->NumberOfVlan
;
597 VlanData
= AllocateZeroPool (*NumberOfVlan
* sizeof (EFI_VLAN_FIND_DATA
));
598 if (VlanData
== NULL
) {
599 return EFI_OUT_OF_RESOURCES
;
603 NET_LIST_FOR_EACH (Entry
, &MnpDeviceData
->ServiceList
) {
604 MnpServiceData
= MNP_SERVICE_DATA_FROM_LINK (Entry
);
606 VlanData
->VlanId
= MnpServiceData
->VlanId
;
607 VlanData
->Priority
= MnpServiceData
->Priority
;
615 // VlanId is specified, try to find it in current VLAN list
617 MnpServiceData
= MnpFindServiceData (MnpDeviceData
, *VlanId
);
618 if (MnpServiceData
== NULL
) {
619 return EFI_NOT_FOUND
;
622 VlanData
= AllocateZeroPool (sizeof (EFI_VLAN_FIND_DATA
));
623 if (VlanData
== NULL
) {
624 return EFI_OUT_OF_RESOURCES
;
626 VlanData
->VlanId
= MnpServiceData
->VlanId
;
627 VlanData
->Priority
= MnpServiceData
->Priority
;
637 Remove the configured VLAN device.
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.
643 @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL.
644 @param[in] VlanId Identifier (0-4094) of the VLAN to be removed.
646 @retval EFI_SUCCESS The VLAN is successfully removed.
647 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:
649 - VlanId is an invalid parameter.
650 @retval EFI_NOT_FOUND The to-be-removed VLAN does not exist.
656 IN EFI_VLAN_CONFIG_PROTOCOL
*This
,
661 MNP_DEVICE_DATA
*MnpDeviceData
;
662 MNP_SERVICE_DATA
*MnpServiceData
;
664 VLAN_TCI
*VlanVariable
;
667 if ((This
== NULL
) || (VlanId
> 4094)) {
668 return EFI_INVALID_PARAMETER
;
671 MnpDeviceData
= MNP_DEVICE_DATA_FROM_THIS (This
);
672 if (MnpDeviceData
->NumberOfVlan
== 0) {
673 return EFI_NOT_FOUND
;
677 // Try to find the VlanId
679 MnpServiceData
= MnpFindServiceData (MnpDeviceData
, VlanId
);
680 if (MnpServiceData
== NULL
) {
681 return EFI_NOT_FOUND
;
684 MnpDeviceData
->NumberOfVlan
--;
686 if ((VlanId
!= 0) || (MnpDeviceData
->NumberOfVlan
!= 0)) {
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
691 Status
= MnpDestroyServiceChild (MnpServiceData
);
692 if (EFI_ERROR (Status
)) {
696 Status
= MnpDestroyServiceData (MnpServiceData
);
697 if (EFI_ERROR (Status
)) {
702 if ((VlanId
!= 0) && (MnpDeviceData
->NumberOfVlan
== 0)) {
704 // This is the last VLAN to be removed, restore the default MNP service data
706 MnpServiceData
= MnpCreateServiceData (MnpDeviceData
, 0, 0);
707 if (MnpServiceData
== NULL
) {
708 return EFI_OUT_OF_RESOURCES
;
713 // Update VLAN configuration variable
716 if (MnpDeviceData
->NumberOfVlan
!= 0) {
717 VlanVariable
= AllocatePool (MnpDeviceData
->NumberOfVlan
* sizeof (VLAN_TCI
));
718 if (VlanVariable
== NULL
) {
719 return EFI_OUT_OF_RESOURCES
;
722 VlanData
= VlanVariable
;
723 NET_LIST_FOR_EACH (Entry
, &MnpDeviceData
->ServiceList
) {
724 MnpServiceData
= MNP_SERVICE_DATA_FROM_LINK (Entry
);
726 VlanData
->Bits
.Vid
= MnpServiceData
->VlanId
;
727 VlanData
->Bits
.Priority
= MnpServiceData
->Priority
;
732 Status
= MnpSetVlanVariable (MnpDeviceData
, MnpDeviceData
->NumberOfVlan
, VlanVariable
);
734 if (VlanVariable
!= NULL
) {
735 FreePool (VlanVariable
);