2 VLAN Config Protocol implementation and VLAN packet process routine.
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
12 VLAN_DEVICE_PATH mVlanDevicePathTemplate
= {
14 MESSAGING_DEVICE_PATH
,
17 (UINT8
)(sizeof (VLAN_DEVICE_PATH
)),
18 (UINT8
)((sizeof (VLAN_DEVICE_PATH
)) >> 8)
24 EFI_VLAN_CONFIG_PROTOCOL mVlanConfigProtocolTemplate
= {
31 Create a child handle for the VLAN ID.
33 @param[in] ImageHandle The driver image handle.
34 @param[in] ControllerHandle Handle of device to bind driver to.
35 @param[in] VlanId The VLAN ID.
36 @param[out] Devicepath Pointer to returned device path for child handle.
38 @return The handle of VLAN child or NULL if failed to create VLAN child.
43 IN EFI_HANDLE ImageHandle
,
44 IN EFI_HANDLE ControllerHandle
,
46 OUT EFI_DEVICE_PATH_PROTOCOL
**Devicepath OPTIONAL
49 EFI_HANDLE ChildHandle
;
50 VLAN_DEVICE_PATH VlanNode
;
51 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
52 EFI_DEVICE_PATH_PROTOCOL
*VlanDevicePath
;
56 // Try to get parent device path
58 Status
= gBS
->OpenProtocol (
60 &gEfiDevicePathProtocolGuid
,
61 (VOID
**)&ParentDevicePath
,
64 EFI_OPEN_PROTOCOL_GET_PROTOCOL
66 if (EFI_ERROR (Status
)) {
71 // Construct device path for child handle: MAC + VLAN
73 CopyMem (&VlanNode
, &mVlanDevicePathTemplate
, sizeof (VLAN_DEVICE_PATH
));
74 VlanNode
.VlanId
= VlanId
;
75 VlanDevicePath
= AppendDevicePathNode (
77 (EFI_DEVICE_PATH_PROTOCOL
*)&VlanNode
79 if (VlanDevicePath
== NULL
) {
84 // Create child VLAN handle by installing DevicePath protocol
87 Status
= gBS
->InstallMultipleProtocolInterfaces (
89 &gEfiDevicePathProtocolGuid
,
93 if (EFI_ERROR (Status
)) {
94 FreePool (VlanDevicePath
);
98 if (Devicepath
!= NULL
) {
99 *Devicepath
= VlanDevicePath
;
106 Remove VLAN tag from a packet.
108 @param[in, out] MnpDeviceData Pointer to the mnp device context data.
109 @param[in, out] Nbuf Pointer to the NET_BUF to remove VLAN tag.
110 @param[out] VlanId Pointer to the returned VLAN ID.
112 @retval TRUE VLAN tag is removed from this packet.
113 @retval FALSE There is no VLAN tag in this packet.
118 IN OUT MNP_DEVICE_DATA
*MnpDeviceData
,
119 IN OUT NET_BUF
*Nbuf
,
124 UINTN ProtocolOffset
;
128 ProtocolOffset
= MnpDeviceData
->Snp
->Mode
->HwAddressSize
* 2;
131 // Get the packet buffer.
133 Packet
= NetbufGetByte (Nbuf
, 0, NULL
);
134 ASSERT (Packet
!= NULL
);
137 // Check whether this is VLAN tagged frame by Ether Type
140 ProtocolType
= NTOHS (*(UINT16
*)(Packet
+ ProtocolOffset
));
141 if (ProtocolType
!= ETHER_TYPE_VLAN
) {
143 // Not a VLAN tagged frame
148 VlanTag
.Uint16
= NTOHS (*(UINT16
*)(Packet
+ ProtocolOffset
+ sizeof (ProtocolType
)));
149 *VlanId
= VlanTag
.Bits
.Vid
;
152 // Move hardware address (DA + SA) 4 bytes right to override VLAN tag
154 CopyMem (Packet
+ NET_VLAN_TAG_LEN
, Packet
, ProtocolOffset
);
157 // Remove VLAN tag from the Nbuf
159 NetbufTrim (Nbuf
, NET_VLAN_TAG_LEN
, NET_BUF_HEAD
);
165 Build the vlan packet to transmit from the TxData passed in.
167 @param MnpServiceData Pointer to the mnp service context data.
168 @param TxData Pointer to the transmit data containing the
169 information to build the packet.
170 @param ProtocolType Pointer to the Ethernet protocol type.
171 @param Packet Pointer to record the address of the packet.
172 @param Length Pointer to a UINT32 variable used to record the
178 IN MNP_SERVICE_DATA
*MnpServiceData
,
179 IN EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
,
180 OUT UINT16
*ProtocolType
,
181 IN OUT UINT8
**Packet
,
182 IN OUT UINT32
*Length
188 MNP_DEVICE_DATA
*MnpDeviceData
;
189 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
191 MnpDeviceData
= MnpServiceData
->MnpDeviceData
;
192 SnpMode
= MnpDeviceData
->Snp
->Mode
;
194 *ProtocolType
= ETHER_TYPE_VLAN
;
195 *Length
= *Length
+ NET_VLAN_TAG_LEN
;
196 *Packet
= *Packet
- NET_VLAN_TAG_LEN
;
198 Tpid
= (UINT16
*)(*Packet
+ SnpMode
->MediaHeaderSize
- sizeof (*ProtocolType
));
199 VlanTci
= (VLAN_TCI
*)(UINTN
)(Tpid
+ 1);
200 if (TxData
->HeaderLength
!= 0) {
202 // Media header is in packet, move DA+SA 4 bytes left
206 *Packet
+ NET_VLAN_TAG_LEN
,
207 SnpMode
->MediaHeaderSize
- sizeof (*ProtocolType
)
209 *Tpid
= HTONS (ETHER_TYPE_VLAN
);
212 // Media header not in packet, VLAN TCI and original protocol type becomes payload
214 EtherType
= (UINT16
*)(UINTN
)(VlanTci
+ 1);
215 *EtherType
= HTONS (TxData
->ProtocolType
);
218 VlanTci
->Bits
.Vid
= MnpServiceData
->VlanId
;
219 VlanTci
->Bits
.Cfi
= VLAN_TCI_CFI_CANONICAL_MAC
;
220 VlanTci
->Bits
.Priority
= MnpServiceData
->Priority
;
221 VlanTci
->Uint16
= HTONS (VlanTci
->Uint16
);
225 Check VLAN configuration variable and delete the duplicative content if has identical Vlan ID.
227 @param[in] MnpDeviceData Pointer to the MNP device context data.
228 @param[in] Buffer Pointer to the buffer contains the array of VLAN_TCI.
229 @param[in] NumberOfVlan Pointer to number of VLAN.
230 @param[out] NewNumberOfVlan Pointer to number of unique VLAN.
232 @retval EFI_SUCCESS The VLAN variable is successfully checked.
233 @retval EFI_OUT_OF_RESOURCES There is not enough resource to set the configuration.
237 MnpCheckVlanVariable (
238 IN MNP_DEVICE_DATA
*MnpDeviceData
,
240 IN UINTN NumberOfVlan
,
241 OUT UINTN
*NewNumberOfVlan
247 BOOLEAN FoundDuplicateItem
;
251 FoundDuplicateItem
= FALSE
;
252 Status
= EFI_SUCCESS
;
254 for (Index
= 0; Index
< NumberOfVlan
; Index
++) {
255 for (Index2
= Index
+ 1; Index2
< NumberOfVlan
; Index2
++) {
256 if (Buffer
[Index
].Bits
.Vid
== Buffer
[Index2
].Bits
.Vid
) {
257 FoundDuplicateItem
= TRUE
;
263 if (FoundDuplicateItem
) {
264 for (Index2
= Index
+1; Index2
< NumberOfVlan
; Index
++, Index2
++) {
265 CopyMem (Buffer
+ Index
, Buffer
+ Index2
, sizeof (VLAN_TCI
));
269 FoundDuplicateItem
= FALSE
;
272 *NewNumberOfVlan
= NumberOfVlan
- Count
;
274 Status
= MnpSetVlanVariable (MnpDeviceData
, *NewNumberOfVlan
, Buffer
);
281 Get VLAN configuration variable.
283 @param[in] MnpDeviceData Pointer to the MNP device context data.
284 @param[out] NumberOfVlan Pointer to number of VLAN to be returned.
285 @param[out] VlanVariable Pointer to the buffer to return requested
288 @retval EFI_SUCCESS The array of VLAN_TCI was returned in VlanVariable
289 and number of VLAN was returned in NumberOfVlan.
290 @retval EFI_NOT_FOUND VLAN configuration variable not found.
291 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the configuration.
296 IN MNP_DEVICE_DATA
*MnpDeviceData
,
297 OUT UINTN
*NumberOfVlan
,
298 OUT VLAN_TCI
**VlanVariable
304 UINTN NewNumberOfVlan
;
307 // Get VLAN configuration from EFI Variable
311 Status
= gRT
->GetVariable (
312 MnpDeviceData
->MacString
,
313 &gEfiVlanConfigProtocolGuid
,
318 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
319 return EFI_NOT_FOUND
;
323 // Allocate buffer to read the variable
325 Buffer
= AllocateZeroPool (BufferSize
);
326 if (Buffer
== NULL
) {
327 return EFI_OUT_OF_RESOURCES
;
330 Status
= gRT
->GetVariable (
331 MnpDeviceData
->MacString
,
332 &gEfiVlanConfigProtocolGuid
,
337 if (EFI_ERROR (Status
)) {
342 Status
= MnpCheckVlanVariable (MnpDeviceData
, Buffer
, BufferSize
/ sizeof (VLAN_TCI
), &NewNumberOfVlan
);
343 if (!EFI_ERROR (Status
)) {
344 *NumberOfVlan
= NewNumberOfVlan
;
345 *VlanVariable
= Buffer
;
352 Set VLAN configuration variable.
354 @param[in] MnpDeviceData Pointer to the MNP device context data.
355 @param[in] NumberOfVlan Number of VLAN in array VlanVariable.
356 @param[in] VlanVariable Pointer to array of VLAN_TCI.
358 @retval EFI_SUCCESS The VLAN variable is successfully set.
359 @retval EFI_OUT_OF_RESOURCES There is not enough resource to set the configuration.
364 IN MNP_DEVICE_DATA
*MnpDeviceData
,
365 IN UINTN NumberOfVlan
,
366 IN VLAN_TCI
*VlanVariable
369 return gRT
->SetVariable (
370 MnpDeviceData
->MacString
,
371 &gEfiVlanConfigProtocolGuid
,
372 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
373 NumberOfVlan
* sizeof (VLAN_TCI
),
379 Create a VLAN device or modify the configuration parameter of an
380 already-configured VLAN.
382 The Set() function is used to create a new VLAN device or change the VLAN
383 configuration parameters. If the VlanId hasn't been configured in the
384 physical Ethernet device, a new VLAN device will be created. If a VLAN with
385 this VlanId is already configured, then related configuration will be updated
386 as the input parameters.
388 If VlanId is zero, the VLAN device will send and receive untagged frames.
389 Otherwise, the VLAN device will send and receive VLAN-tagged frames containing the VlanId.
390 If VlanId is out of scope of (0-4094), EFI_INVALID_PARAMETER is returned.
391 If Priority is out of the scope of (0-7), then EFI_INVALID_PARAMETER is returned.
392 If there is not enough system memory to perform the registration, then
393 EFI_OUT_OF_RESOURCES is returned.
395 @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL.
396 @param[in] VlanId A unique identifier (1-4094) of the VLAN which is being created
397 or modified, or zero (0).
398 @param[in] Priority 3 bit priority in VLAN header. Priority 0 is default value. If
399 VlanId is zero (0), Priority is ignored.
401 @retval EFI_SUCCESS The VLAN is successfully configured.
402 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:
404 - VlanId is an invalid VLAN Identifier.
405 - Priority is invalid.
406 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to perform the registration.
412 IN EFI_VLAN_CONFIG_PROTOCOL
*This
,
418 MNP_DEVICE_DATA
*MnpDeviceData
;
419 MNP_SERVICE_DATA
*MnpServiceData
;
420 VLAN_TCI
*OldVariable
;
421 VLAN_TCI
*NewVariable
;
427 if ((This
== NULL
) || (VlanId
> 4094) || (Priority
> 7)) {
428 return EFI_INVALID_PARAMETER
;
432 MnpDeviceData
= MNP_DEVICE_DATA_FROM_THIS (This
);
433 if (MnpDeviceData
->NumberOfVlan
== 0) {
435 // No existing VLAN, this is the first VLAN to add
438 Entry
= GetFirstNode (&MnpDeviceData
->ServiceList
);
439 MnpServiceData
= MNP_SERVICE_DATA_FROM_LINK (Entry
);
443 // VlanId is not 0, need destroy the default MNP service data
445 Status
= MnpDestroyServiceChild (MnpServiceData
);
446 if (EFI_ERROR (Status
)) {
450 Status
= MnpDestroyServiceData (MnpServiceData
);
451 if (EFI_ERROR (Status
)) {
456 // Create a new MNP service data for this VLAN
458 MnpServiceData
= MnpCreateServiceData (MnpDeviceData
, VlanId
, Priority
);
459 if (MnpServiceData
== NULL
) {
460 return EFI_OUT_OF_RESOURCES
;
465 // Try to find VlanId in existing VLAN list
467 MnpServiceData
= MnpFindServiceData (MnpDeviceData
, VlanId
);
468 if (MnpServiceData
== NULL
) {
470 // VlanId not found, create a new MNP service data
473 MnpServiceData
= MnpCreateServiceData (MnpDeviceData
, VlanId
, Priority
);
474 if (MnpServiceData
== NULL
) {
475 return EFI_OUT_OF_RESOURCES
;
480 MnpServiceData
->VlanId
= VlanId
;
481 MnpServiceData
->Priority
= Priority
;
483 MnpDeviceData
->NumberOfVlan
++;
487 // Update VLAN configuration variable
492 MnpGetVlanVariable (MnpDeviceData
, &NumberOfVlan
, &OldVariable
);
496 // VLAN not exist - add
498 NewVariable
= AllocateZeroPool ((NumberOfVlan
+ 1) * sizeof (VLAN_TCI
));
499 if (NewVariable
== NULL
) {
500 Status
= EFI_OUT_OF_RESOURCES
;
504 if (OldVariable
!= NULL
) {
505 CopyMem (NewVariable
, OldVariable
, NumberOfVlan
* sizeof (VLAN_TCI
));
508 Index
= NumberOfVlan
++;
511 // VLAN already exist - update
513 for (Index
= 0; Index
< NumberOfVlan
; Index
++) {
514 if (OldVariable
[Index
].Bits
.Vid
== VlanId
) {
519 ASSERT (Index
< NumberOfVlan
);
521 NewVariable
= OldVariable
;
525 NewVariable
[Index
].Bits
.Vid
= VlanId
;
526 NewVariable
[Index
].Bits
.Priority
= Priority
;
528 Status
= MnpSetVlanVariable (MnpDeviceData
, NumberOfVlan
, NewVariable
);
529 FreePool (NewVariable
);
532 if (OldVariable
!= NULL
) {
533 FreePool (OldVariable
);
540 Find configuration information for specified VLAN or all configured VLANs.
542 The Find() function is used to find the configuration information for matching
543 VLAN and allocate a buffer into which those entries are copied.
545 @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL.
546 @param[in] VlanId Pointer to VLAN identifier. Set to NULL to find all
548 @param[out] NumberOfVlan The number of VLANs which is found by the specified criteria.
549 @param[out] Entries The buffer which receive the VLAN configuration.
551 @retval EFI_SUCCESS The VLAN is successfully found.
552 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:
554 - Specified VlanId is invalid.
555 @retval EFI_NOT_FOUND No matching VLAN is found.
561 IN EFI_VLAN_CONFIG_PROTOCOL
*This
,
562 IN UINT16
*VlanId OPTIONAL
,
563 OUT UINT16
*NumberOfVlan
,
564 OUT EFI_VLAN_FIND_DATA
**Entries
567 MNP_DEVICE_DATA
*MnpDeviceData
;
568 MNP_SERVICE_DATA
*MnpServiceData
;
570 EFI_VLAN_FIND_DATA
*VlanData
;
572 if ((This
== NULL
) || ((VlanId
!= NULL
) && (*VlanId
> 4094)) || (NumberOfVlan
== NULL
) || (Entries
== NULL
)) {
573 return EFI_INVALID_PARAMETER
;
579 MnpDeviceData
= MNP_DEVICE_DATA_FROM_THIS (This
);
580 if (MnpDeviceData
->NumberOfVlan
== 0) {
581 return EFI_NOT_FOUND
;
584 if (VlanId
== NULL
) {
586 // Return all current VLAN configuration
588 *NumberOfVlan
= (UINT16
)MnpDeviceData
->NumberOfVlan
;
589 VlanData
= AllocateZeroPool (*NumberOfVlan
* sizeof (EFI_VLAN_FIND_DATA
));
590 if (VlanData
== NULL
) {
591 return EFI_OUT_OF_RESOURCES
;
595 NET_LIST_FOR_EACH (Entry
, &MnpDeviceData
->ServiceList
) {
596 MnpServiceData
= MNP_SERVICE_DATA_FROM_LINK (Entry
);
598 VlanData
->VlanId
= MnpServiceData
->VlanId
;
599 VlanData
->Priority
= MnpServiceData
->Priority
;
607 // VlanId is specified, try to find it in current VLAN list
609 MnpServiceData
= MnpFindServiceData (MnpDeviceData
, *VlanId
);
610 if (MnpServiceData
== NULL
) {
611 return EFI_NOT_FOUND
;
614 VlanData
= AllocateZeroPool (sizeof (EFI_VLAN_FIND_DATA
));
615 if (VlanData
== NULL
) {
616 return EFI_OUT_OF_RESOURCES
;
619 VlanData
->VlanId
= MnpServiceData
->VlanId
;
620 VlanData
->Priority
= MnpServiceData
->Priority
;
629 Remove the configured VLAN device.
631 The Remove() function is used to remove the specified VLAN device.
632 If the VlanId is out of the scope of (0-4094), EFI_INVALID_PARAMETER is returned.
633 If specified VLAN hasn't been previously configured, EFI_NOT_FOUND is returned.
635 @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL.
636 @param[in] VlanId Identifier (0-4094) of the VLAN to be removed.
638 @retval EFI_SUCCESS The VLAN is successfully removed.
639 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:
641 - VlanId is an invalid parameter.
642 @retval EFI_NOT_FOUND The to-be-removed VLAN does not exist.
648 IN EFI_VLAN_CONFIG_PROTOCOL
*This
,
653 MNP_DEVICE_DATA
*MnpDeviceData
;
654 MNP_SERVICE_DATA
*MnpServiceData
;
656 VLAN_TCI
*VlanVariable
;
659 if ((This
== NULL
) || (VlanId
> 4094)) {
660 return EFI_INVALID_PARAMETER
;
663 MnpDeviceData
= MNP_DEVICE_DATA_FROM_THIS (This
);
664 if (MnpDeviceData
->NumberOfVlan
== 0) {
665 return EFI_NOT_FOUND
;
669 // Try to find the VlanId
671 MnpServiceData
= MnpFindServiceData (MnpDeviceData
, VlanId
);
672 if (MnpServiceData
== NULL
) {
673 return EFI_NOT_FOUND
;
676 MnpDeviceData
->NumberOfVlan
--;
678 if ((VlanId
!= 0) || (MnpDeviceData
->NumberOfVlan
!= 0)) {
680 // If VlanId is not 0 or VlanId is 0 and it is not the last VLAN to remove,
681 // destroy its MNP service data
683 Status
= MnpDestroyServiceChild (MnpServiceData
);
684 if (EFI_ERROR (Status
)) {
688 Status
= MnpDestroyServiceData (MnpServiceData
);
689 if (EFI_ERROR (Status
)) {
694 if ((VlanId
!= 0) && (MnpDeviceData
->NumberOfVlan
== 0)) {
696 // This is the last VLAN to be removed, restore the default MNP service data
698 MnpServiceData
= MnpCreateServiceData (MnpDeviceData
, 0, 0);
699 if (MnpServiceData
== NULL
) {
700 return EFI_OUT_OF_RESOURCES
;
705 // Update VLAN configuration variable
708 if (MnpDeviceData
->NumberOfVlan
!= 0) {
709 VlanVariable
= AllocatePool (MnpDeviceData
->NumberOfVlan
* sizeof (VLAN_TCI
));
710 if (VlanVariable
== NULL
) {
711 return EFI_OUT_OF_RESOURCES
;
714 VlanData
= VlanVariable
;
715 NET_LIST_FOR_EACH (Entry
, &MnpDeviceData
->ServiceList
) {
716 MnpServiceData
= MNP_SERVICE_DATA_FROM_LINK (Entry
);
718 VlanData
->Bits
.Vid
= MnpServiceData
->VlanId
;
719 VlanData
->Bits
.Priority
= MnpServiceData
->Priority
;
724 Status
= MnpSetVlanVariable (MnpDeviceData
, MnpDeviceData
->NumberOfVlan
, VlanVariable
);
726 if (VlanVariable
!= NULL
) {
727 FreePool (VlanVariable
);