2 VLAN Config Protocol implementation and VLAN packet process routine.
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
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
);
235 Get VLAN configuration variable.
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
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.
250 IN MNP_DEVICE_DATA
*MnpDeviceData
,
251 OUT UINTN
*NumberOfVlan
,
252 OUT VLAN_TCI
**VlanVariable
260 // Get VLAN configuration from EFI Variable
264 Status
= gRT
->GetVariable (
265 MnpDeviceData
->MacString
,
266 &gEfiVlanConfigProtocolGuid
,
271 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
272 return EFI_NOT_FOUND
;
276 // Allocate buffer to read the variable
278 Buffer
= AllocateZeroPool (BufferSize
);
279 if (Buffer
== NULL
) {
280 return EFI_OUT_OF_RESOURCES
;
283 Status
= gRT
->GetVariable (
284 MnpDeviceData
->MacString
,
285 &gEfiVlanConfigProtocolGuid
,
290 if (EFI_ERROR (Status
)) {
295 *NumberOfVlan
= BufferSize
/ sizeof (VLAN_TCI
);
296 *VlanVariable
= Buffer
;
303 Set VLAN configuration variable.
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.
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.
315 IN MNP_DEVICE_DATA
*MnpDeviceData
,
316 IN UINTN NumberOfVlan
,
317 IN VLAN_TCI
*VlanVariable
320 return gRT
->SetVariable (
321 MnpDeviceData
->MacString
,
322 &gEfiVlanConfigProtocolGuid
,
323 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
324 NumberOfVlan
* sizeof (VLAN_TCI
),
331 Create a VLAN device or modify the configuration parameter of an
332 already-configured VLAN.
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.
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.
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.
353 @retval EFI_SUCCESS The VLAN is successfully configured.
354 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:
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.
364 IN EFI_VLAN_CONFIG_PROTOCOL
*This
,
370 MNP_DEVICE_DATA
*MnpDeviceData
;
371 MNP_SERVICE_DATA
*MnpServiceData
;
372 VLAN_TCI
*OldVariable
;
373 VLAN_TCI
*NewVariable
;
379 if ((This
== NULL
) || (VlanId
> 4094) || (Priority
> 7)) {
380 return EFI_INVALID_PARAMETER
;
384 MnpDeviceData
= MNP_DEVICE_DATA_FROM_THIS (This
);
385 if (MnpDeviceData
->NumberOfVlan
== 0) {
387 // No existing VLAN, this is the first VLAN to add
390 Entry
= GetFirstNode (&MnpDeviceData
->ServiceList
);
391 MnpServiceData
= MNP_SERVICE_DATA_FROM_LINK (Entry
);
395 // VlanId is not 0, need destroy the default MNP service data
397 Status
= MnpDestroyServiceChild (MnpServiceData
);
398 if (EFI_ERROR (Status
)) {
402 Status
= MnpDestroyServiceData (MnpServiceData
);
403 if (EFI_ERROR (Status
)) {
408 // Create a new MNP service data for this VLAN
410 MnpServiceData
= MnpCreateServiceData (MnpDeviceData
, VlanId
, Priority
);
411 if (MnpServiceData
== NULL
) {
412 return EFI_OUT_OF_RESOURCES
;
417 // Try to find VlanId in existing VLAN list
419 MnpServiceData
= MnpFindServiceData (MnpDeviceData
, VlanId
);
420 if (MnpServiceData
== NULL
) {
422 // VlanId not found, create a new MNP service data
425 MnpServiceData
= MnpCreateServiceData (MnpDeviceData
, VlanId
, Priority
);
426 if (MnpServiceData
== NULL
) {
427 return EFI_OUT_OF_RESOURCES
;
432 MnpServiceData
->VlanId
= VlanId
;
433 MnpServiceData
->Priority
= Priority
;
435 MnpDeviceData
->NumberOfVlan
++;
439 // Update VLAN configuration variable
444 MnpGetVlanVariable (MnpDeviceData
, &NumberOfVlan
, &OldVariable
);
448 // VLAN not exist - add
450 NewVariable
= AllocateZeroPool ((NumberOfVlan
+ 1) * sizeof (VLAN_TCI
));
451 if (NewVariable
== NULL
) {
452 Status
= EFI_OUT_OF_RESOURCES
;
456 if (OldVariable
!= NULL
) {
457 CopyMem (NewVariable
, OldVariable
, NumberOfVlan
* sizeof (VLAN_TCI
));
460 Index
= NumberOfVlan
++;
463 // VLAN already exist - update
465 for (Index
= 0; Index
< NumberOfVlan
; Index
++) {
466 if (OldVariable
[Index
].Bits
.Vid
== VlanId
) {
470 ASSERT (Index
< NumberOfVlan
);
472 NewVariable
= OldVariable
;
476 NewVariable
[Index
].Bits
.Vid
= VlanId
;
477 NewVariable
[Index
].Bits
.Priority
= Priority
;
479 Status
= MnpSetVlanVariable (MnpDeviceData
, NumberOfVlan
, NewVariable
);
480 FreePool (NewVariable
);
483 if (OldVariable
!= NULL
) {
484 FreePool (OldVariable
);
492 Find configuration information for specified VLAN or all configured VLANs.
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.
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
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.
503 @retval EFI_SUCCESS The VLAN is successfully found.
504 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:
506 - Specified VlanId is invalid.
507 @retval EFI_NOT_FOUND No matching VLAN is found.
513 IN EFI_VLAN_CONFIG_PROTOCOL
*This
,
514 IN UINT16
*VlanId OPTIONAL
,
515 OUT UINT16
*NumberOfVlan
,
516 OUT EFI_VLAN_FIND_DATA
**Entries
519 MNP_DEVICE_DATA
*MnpDeviceData
;
520 MNP_SERVICE_DATA
*MnpServiceData
;
522 EFI_VLAN_FIND_DATA
*VlanData
;
524 if ((This
== NULL
) || (VlanId
!= NULL
&& *VlanId
> 4094) || (NumberOfVlan
== NULL
) || (Entries
== NULL
)) {
525 return EFI_INVALID_PARAMETER
;
531 MnpDeviceData
= MNP_DEVICE_DATA_FROM_THIS (This
);
532 if (MnpDeviceData
->NumberOfVlan
== 0) {
533 return EFI_NOT_FOUND
;
536 if (VlanId
== NULL
) {
538 // Return all current VLAN configuration
540 *NumberOfVlan
= (UINT16
) MnpDeviceData
->NumberOfVlan
;
541 VlanData
= AllocateZeroPool (*NumberOfVlan
* sizeof (EFI_VLAN_FIND_DATA
));
542 if (VlanData
== NULL
) {
543 return EFI_OUT_OF_RESOURCES
;
547 NET_LIST_FOR_EACH (Entry
, &MnpDeviceData
->ServiceList
) {
548 MnpServiceData
= MNP_SERVICE_DATA_FROM_LINK (Entry
);
550 VlanData
->VlanId
= MnpServiceData
->VlanId
;
551 VlanData
->Priority
= MnpServiceData
->Priority
;
559 // VlanId is specified, try to find it in current VLAN list
561 MnpServiceData
= MnpFindServiceData (MnpDeviceData
, *VlanId
);
562 if (MnpServiceData
== NULL
) {
563 return EFI_NOT_FOUND
;
566 VlanData
= AllocateZeroPool (sizeof (EFI_VLAN_FIND_DATA
));
567 if (VlanData
== NULL
) {
568 return EFI_OUT_OF_RESOURCES
;
570 VlanData
->VlanId
= MnpServiceData
->VlanId
;
571 VlanData
->Priority
= MnpServiceData
->Priority
;
581 Remove the configured VLAN device.
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.
587 @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL.
588 @param[in] VlanId Identifier (0-4094) of the VLAN to be removed.
590 @retval EFI_SUCCESS The VLAN is successfully removed.
591 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:
593 - VlanId is an invalid parameter.
594 @retval EFI_NOT_FOUND The to-be-removed VLAN does not exist.
600 IN EFI_VLAN_CONFIG_PROTOCOL
*This
,
605 MNP_DEVICE_DATA
*MnpDeviceData
;
606 MNP_SERVICE_DATA
*MnpServiceData
;
608 VLAN_TCI
*VlanVariable
;
611 if ((This
== NULL
) || (VlanId
> 4094)) {
612 return EFI_INVALID_PARAMETER
;
615 MnpDeviceData
= MNP_DEVICE_DATA_FROM_THIS (This
);
616 if (MnpDeviceData
->NumberOfVlan
== 0) {
617 return EFI_NOT_FOUND
;
621 // Try to find the VlanId
623 MnpServiceData
= MnpFindServiceData (MnpDeviceData
, VlanId
);
624 if (MnpServiceData
== NULL
) {
625 return EFI_NOT_FOUND
;
628 MnpDeviceData
->NumberOfVlan
--;
630 if ((VlanId
!= 0) || (MnpDeviceData
->NumberOfVlan
!= 0)) {
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
635 Status
= MnpDestroyServiceChild (MnpServiceData
);
636 if (EFI_ERROR (Status
)) {
640 Status
= MnpDestroyServiceData (MnpServiceData
);
641 if (EFI_ERROR (Status
)) {
646 if ((VlanId
!= 0) && (MnpDeviceData
->NumberOfVlan
== 0)) {
648 // This is the last VLAN to be removed, restore the default MNP service data
650 MnpServiceData
= MnpCreateServiceData (MnpDeviceData
, 0, 0);
651 if (MnpServiceData
== NULL
) {
652 return EFI_OUT_OF_RESOURCES
;
657 // Update VLAN configuration variable
660 if (MnpDeviceData
->NumberOfVlan
!= 0) {
661 VlanVariable
= AllocatePool (MnpDeviceData
->NumberOfVlan
* sizeof (VLAN_TCI
));
662 if (VlanVariable
== NULL
) {
663 return EFI_OUT_OF_RESOURCES
;
666 VlanData
= VlanVariable
;
667 NET_LIST_FOR_EACH (Entry
, &MnpDeviceData
->ServiceList
) {
668 MnpServiceData
= MNP_SERVICE_DATA_FROM_LINK (Entry
);
670 VlanData
->Bits
.Vid
= MnpServiceData
->VlanId
;
671 VlanData
->Bits
.Priority
= MnpServiceData
->Priority
;
676 Status
= MnpSetVlanVariable (MnpDeviceData
, MnpDeviceData
->NumberOfVlan
, VlanVariable
);
678 if (VlanVariable
!= NULL
) {
679 FreePool (VlanVariable
);