]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/MnpDxe/MnpVlan.c
MdeModulePkg: Fix IPv4 double free
[mirror_edk2.git] / MdeModulePkg / Universal / Network / MnpDxe / MnpVlan.c
CommitLineData
779ae357 1/** @file\r
2 VLAN Config Protocol implementation and VLAN packet process routine.\r
3\r
0bb073b9 4Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 5This program and the accompanying materials\r
779ae357 6are licensed and made available under the terms and conditions\r
7of the BSD License which accompanies this distribution. The full\r
8text of the license may be found at<BR>\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "MnpImpl.h"\r
17#include "MnpVlan.h"\r
18\r
19VLAN_DEVICE_PATH mVlanDevicePathTemplate = {\r
20 {\r
21 MESSAGING_DEVICE_PATH,\r
22 MSG_VLAN_DP,\r
23 {\r
24 (UINT8) (sizeof (VLAN_DEVICE_PATH)),\r
25 (UINT8) ((sizeof (VLAN_DEVICE_PATH)) >> 8)\r
26 }\r
27 },\r
28 0\r
29};\r
30\r
31EFI_VLAN_CONFIG_PROTOCOL mVlanConfigProtocolTemplate = {\r
32 VlanConfigSet,\r
33 VlanConfigFind,\r
34 VlanConfigRemove\r
35};\r
36\r
37\r
38/**\r
39 Create a child handle for the VLAN ID.\r
40\r
41 @param[in] ImageHandle The driver image handle.\r
42 @param[in] ControllerHandle Handle of device to bind driver to.\r
43 @param[in] VlanId The VLAN ID.\r
44 @param[out] Devicepath Pointer to returned device path for child handle.\r
45\r
46 @return The handle of VLAN child or NULL if failed to create VLAN child.\r
47\r
48**/\r
49EFI_HANDLE\r
50MnpCreateVlanChild (\r
51 IN EFI_HANDLE ImageHandle,\r
52 IN EFI_HANDLE ControllerHandle,\r
53 IN UINT16 VlanId,\r
54 OUT EFI_DEVICE_PATH_PROTOCOL **Devicepath OPTIONAL\r
55 )\r
56{\r
57 EFI_HANDLE ChildHandle;\r
58 VLAN_DEVICE_PATH VlanNode;\r
59 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
60 EFI_DEVICE_PATH_PROTOCOL *VlanDevicePath;\r
61 EFI_STATUS Status;\r
62\r
63 //\r
64 // Try to get parent device path\r
65 //\r
66 Status = gBS->OpenProtocol (\r
67 ControllerHandle,\r
68 &gEfiDevicePathProtocolGuid,\r
69 (VOID **) &ParentDevicePath,\r
70 ImageHandle,\r
71 ControllerHandle,\r
72 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
73 );\r
74 if (EFI_ERROR (Status)) {\r
75 return NULL;\r
76 }\r
77\r
78 //\r
79 // Construct device path for child handle: MAC + VLAN\r
80 //\r
81 CopyMem (&VlanNode, &mVlanDevicePathTemplate, sizeof (VLAN_DEVICE_PATH));\r
82 VlanNode.VlanId = VlanId;\r
83 VlanDevicePath = AppendDevicePathNode (\r
84 ParentDevicePath,\r
85 (EFI_DEVICE_PATH_PROTOCOL *) &VlanNode\r
86 );\r
87 if (VlanDevicePath == NULL) {\r
88 return NULL;\r
89 }\r
90\r
91 //\r
92 // Create child VLAN handle by installing DevicePath protocol\r
93 //\r
94 ChildHandle = NULL;\r
95 Status = gBS->InstallMultipleProtocolInterfaces (\r
96 &ChildHandle,\r
97 &gEfiDevicePathProtocolGuid,\r
98 VlanDevicePath,\r
99 NULL\r
100 );\r
101 if (EFI_ERROR (Status)) {\r
102 FreePool (VlanDevicePath);\r
103 return NULL;\r
104 }\r
105\r
106 if (Devicepath != NULL) {\r
107 *Devicepath = VlanDevicePath;\r
108 }\r
109\r
110 return ChildHandle;\r
111}\r
112\r
113/**\r
114 Remove VLAN tag from a packet.\r
115\r
116 @param[in, out] MnpDeviceData Pointer to the mnp device context data.\r
117 @param[in, out] Nbuf Pointer to the NET_BUF to remove VLAN tag.\r
118 @param[out] VlanId Pointer to the returned VLAN ID.\r
119\r
120 @retval TRUE VLAN tag is removed from this packet.\r
121 @retval FALSE There is no VLAN tag in this packet.\r
122\r
123**/\r
124BOOLEAN\r
125MnpRemoveVlanTag (\r
126 IN OUT MNP_DEVICE_DATA *MnpDeviceData,\r
127 IN OUT NET_BUF *Nbuf,\r
128 OUT UINT16 *VlanId\r
129 )\r
130{\r
131 UINT8 *Packet;\r
132 UINTN ProtocolOffset;\r
133 UINT16 ProtocolType;\r
134 VLAN_TCI VlanTag;\r
135\r
136 ProtocolOffset = MnpDeviceData->Snp->Mode->HwAddressSize * 2;\r
137\r
138 //\r
139 // Get the packet buffer.\r
140 //\r
141 Packet = NetbufGetByte (Nbuf, 0, NULL);\r
142 ASSERT (Packet != NULL);\r
143\r
144 //\r
145 // Check whether this is VLAN tagged frame by Ether Type\r
146 //\r
147 *VlanId = 0;\r
148 ProtocolType = NTOHS (*(UINT16 *) (Packet + ProtocolOffset));\r
149 if (ProtocolType != ETHER_TYPE_VLAN) {\r
150 //\r
151 // Not a VLAN tagged frame\r
152 //\r
153 return FALSE;\r
154 }\r
155\r
156 VlanTag.Uint16 = NTOHS (*(UINT16 *) (Packet + ProtocolOffset + sizeof (ProtocolType)));\r
157 *VlanId = VlanTag.Bits.Vid;\r
158\r
159 //\r
160 // Move hardware address (DA + SA) 4 bytes right to override VLAN tag\r
161 //\r
162 CopyMem (Packet + NET_VLAN_TAG_LEN, Packet, ProtocolOffset);\r
163\r
164 //\r
165 // Remove VLAN tag from the Nbuf\r
166 //\r
167 NetbufTrim (Nbuf, NET_VLAN_TAG_LEN, NET_BUF_HEAD);\r
168\r
169 return TRUE;\r
170}\r
171\r
172\r
173/**\r
bdebd2ce 174 Build the vlan packet to transmit from the TxData passed in.\r
779ae357 175\r
176 @param MnpServiceData Pointer to the mnp service context data.\r
177 @param TxData Pointer to the transmit data containing the\r
178 information to build the packet.\r
179 @param ProtocolType Pointer to the Ethernet protocol type.\r
180 @param Packet Pointer to record the address of the packet.\r
181 @param Length Pointer to a UINT32 variable used to record the\r
182 packet's length.\r
183\r
184**/\r
185VOID\r
186MnpInsertVlanTag (\r
187 IN MNP_SERVICE_DATA *MnpServiceData,\r
188 IN EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData,\r
189 OUT UINT16 *ProtocolType,\r
190 IN OUT UINT8 **Packet,\r
191 IN OUT UINT32 *Length\r
192 )\r
193{\r
194 VLAN_TCI *VlanTci;\r
195 UINT16 *Tpid;\r
196 UINT16 *EtherType;\r
197 MNP_DEVICE_DATA *MnpDeviceData;\r
198 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
199\r
779ae357 200 MnpDeviceData = MnpServiceData->MnpDeviceData;\r
201 SnpMode = MnpDeviceData->Snp->Mode;\r
202\r
203 *ProtocolType = ETHER_TYPE_VLAN;\r
204 *Length = *Length + NET_VLAN_TAG_LEN;\r
205 *Packet = *Packet - NET_VLAN_TAG_LEN;\r
206\r
207 Tpid = (UINT16 *) (*Packet + SnpMode->MediaHeaderSize - sizeof (*ProtocolType));\r
208 VlanTci = (VLAN_TCI *) (UINTN) (Tpid + 1);\r
209 if (TxData->HeaderLength != 0) {\r
210 //\r
211 // Media header is in packet, move DA+SA 4 bytes left\r
212 //\r
213 CopyMem (\r
214 *Packet,\r
215 *Packet + NET_VLAN_TAG_LEN,\r
216 SnpMode->MediaHeaderSize - sizeof (*ProtocolType)\r
217 );\r
218 *Tpid = HTONS (ETHER_TYPE_VLAN);\r
219 } else {\r
220 //\r
221 // Media header not in packet, VLAN TCI and original protocol type becomes payload\r
222 //\r
223 EtherType = (UINT16 *) (UINTN) (VlanTci + 1);\r
224 *EtherType = HTONS (TxData->ProtocolType);\r
225 }\r
226\r
227 VlanTci->Bits.Vid = MnpServiceData->VlanId;\r
228 VlanTci->Bits.Cfi = VLAN_TCI_CFI_CANONICAL_MAC;\r
229 VlanTci->Bits.Priority = MnpServiceData->Priority;\r
230 VlanTci->Uint16 = HTONS (VlanTci->Uint16);\r
231}\r
232\r
0bb073b9
ZL
233/**\r
234 Check VLAN configuration variable and delete the duplicative content if has identical Vlan ID.\r
235\r
236 @param[in] MnpDeviceData Pointer to the MNP device context data.\r
237 @param[in] Buffer Pointer to the buffer contains the array of VLAN_TCI.\r
238 @param[in] NumberOfVlan Pointer to number of VLAN.\r
239 @param[out] NewNumberOfVlan Pointer to number of unique VLAN.\r
240 \r
241 @retval EFI_SUCCESS The VLAN variable is successfully checked.\r
242 @retval EFI_OUT_OF_RESOURCES There is not enough resource to set the configuration.\r
243\r
244**/\r
245EFI_STATUS\r
246MnpCheckVlanVariable (\r
247 IN MNP_DEVICE_DATA *MnpDeviceData,\r
248 IN VLAN_TCI *Buffer,\r
249 IN UINTN NumberOfVlan,\r
250 OUT UINTN *NewNumberOfVlan\r
251 )\r
252{\r
253 UINTN Index;\r
254 UINTN Index2;\r
255 UINTN Count;\r
256 BOOLEAN FoundDuplicateItem;\r
257 EFI_STATUS Status;\r
258\r
259 Count = 0;\r
260 FoundDuplicateItem = FALSE;\r
261 Status = EFI_SUCCESS;\r
262 \r
263 for (Index = 0; Index < NumberOfVlan; Index++) {\r
264 for (Index2 = Index + 1; Index2 < NumberOfVlan; Index2++) {\r
265 if (Buffer[Index].Bits.Vid == Buffer[Index2].Bits.Vid) {\r
266 FoundDuplicateItem = TRUE;\r
267 Count++;\r
268 break;\r
269 }\r
270 }\r
271 if (FoundDuplicateItem) {\r
272 for (Index2 = Index +1; Index2 < NumberOfVlan; Index++, Index2++) {\r
273 CopyMem (Buffer + Index, Buffer + Index2, sizeof (VLAN_TCI));\r
274 }\r
275 }\r
276 FoundDuplicateItem = FALSE;\r
277 }\r
278\r
279 *NewNumberOfVlan = NumberOfVlan - Count;\r
280 if (Count != 0) {\r
281 Status = MnpSetVlanVariable (MnpDeviceData, *NewNumberOfVlan, Buffer);\r
282 }\r
283 \r
284 return Status;\r
285}\r
779ae357 286\r
287/**\r
288 Get VLAN configuration variable.\r
289\r
290 @param[in] MnpDeviceData Pointer to the MNP device context data.\r
291 @param[out] NumberOfVlan Pointer to number of VLAN to be returned.\r
292 @param[out] VlanVariable Pointer to the buffer to return requested\r
293 array of VLAN_TCI.\r
294\r
295 @retval EFI_SUCCESS The array of VLAN_TCI was returned in VlanVariable\r
296 and number of VLAN was returned in NumberOfVlan.\r
297 @retval EFI_NOT_FOUND VLAN configuration variable not found.\r
298 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the configuration.\r
299\r
300**/\r
301EFI_STATUS\r
302MnpGetVlanVariable (\r
303 IN MNP_DEVICE_DATA *MnpDeviceData,\r
304 OUT UINTN *NumberOfVlan,\r
305 OUT VLAN_TCI **VlanVariable\r
306 )\r
307{\r
308 UINTN BufferSize;\r
309 EFI_STATUS Status;\r
310 VLAN_TCI *Buffer;\r
0bb073b9 311 UINTN NewNumberOfVlan;\r
779ae357 312\r
313 //\r
314 // Get VLAN configuration from EFI Variable\r
315 //\r
316 Buffer = NULL;\r
317 BufferSize = 0;\r
318 Status = gRT->GetVariable (\r
319 MnpDeviceData->MacString,\r
320 &gEfiVlanConfigProtocolGuid,\r
321 NULL,\r
322 &BufferSize,\r
323 NULL\r
324 );\r
325 if (Status != EFI_BUFFER_TOO_SMALL) {\r
326 return EFI_NOT_FOUND;\r
327 }\r
328\r
329 //\r
330 // Allocate buffer to read the variable\r
331 //\r
332 Buffer = AllocateZeroPool (BufferSize);\r
333 if (Buffer == NULL) {\r
334 return EFI_OUT_OF_RESOURCES;\r
335 }\r
336\r
337 Status = gRT->GetVariable (\r
338 MnpDeviceData->MacString,\r
339 &gEfiVlanConfigProtocolGuid,\r
340 NULL,\r
341 &BufferSize,\r
342 Buffer\r
343 );\r
344 if (EFI_ERROR (Status)) {\r
345 FreePool (Buffer);\r
346 return Status;\r
347 }\r
348\r
0bb073b9
ZL
349 Status = MnpCheckVlanVariable (MnpDeviceData, Buffer, BufferSize / sizeof (VLAN_TCI), &NewNumberOfVlan);\r
350 if (!EFI_ERROR (Status)) {\r
351 *NumberOfVlan = NewNumberOfVlan;\r
352 *VlanVariable = Buffer;\r
353 }\r
779ae357 354\r
355 return Status;\r
356}\r
357\r
779ae357 358/**\r
359 Set VLAN configuration variable.\r
360\r
361 @param[in] MnpDeviceData Pointer to the MNP device context data.\r
362 @param[in] NumberOfVlan Number of VLAN in array VlanVariable.\r
363 @param[in] VlanVariable Pointer to array of VLAN_TCI.\r
364\r
365 @retval EFI_SUCCESS The VLAN variable is successfully set.\r
366 @retval EFI_OUT_OF_RESOURCES There is not enough resource to set the configuration.\r
367\r
368**/\r
369EFI_STATUS\r
370MnpSetVlanVariable (\r
371 IN MNP_DEVICE_DATA *MnpDeviceData,\r
372 IN UINTN NumberOfVlan,\r
373 IN VLAN_TCI *VlanVariable\r
374 )\r
375{\r
376 return gRT->SetVariable (\r
377 MnpDeviceData->MacString,\r
378 &gEfiVlanConfigProtocolGuid,\r
d120b462 379 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
779ae357 380 NumberOfVlan * sizeof (VLAN_TCI),\r
381 VlanVariable\r
382 );\r
383}\r
384\r
385\r
386/**\r
387 Create a VLAN device or modify the configuration parameter of an\r
388 already-configured VLAN.\r
389\r
390 The Set() function is used to create a new VLAN device or change the VLAN\r
391 configuration parameters. If the VlanId hasn't been configured in the\r
392 physical Ethernet device, a new VLAN device will be created. If a VLAN with\r
393 this VlanId is already configured, then related configuration will be updated\r
394 as the input parameters.\r
395\r
396 If VlanId is zero, the VLAN device will send and receive untagged frames.\r
397 Otherwise, the VLAN device will send and receive VLAN-tagged frames containing the VlanId.\r
398 If VlanId is out of scope of (0-4094), EFI_INVALID_PARAMETER is returned.\r
399 If Priority is out of the scope of (0-7), then EFI_INVALID_PARAMETER is returned.\r
400 If there is not enough system memory to perform the registration, then\r
401 EFI_OUT_OF_RESOURCES is returned.\r
402\r
403 @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL.\r
404 @param[in] VlanId A unique identifier (1-4094) of the VLAN which is being created\r
405 or modified, or zero (0).\r
406 @param[in] Priority 3 bit priority in VLAN header. Priority 0 is default value. If\r
407 VlanId is zero (0), Priority is ignored.\r
408\r
409 @retval EFI_SUCCESS The VLAN is successfully configured.\r
410 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:\r
411 - This is NULL.\r
412 - VlanId is an invalid VLAN Identifier.\r
413 - Priority is invalid.\r
414 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to perform the registration.\r
415\r
416**/\r
417EFI_STATUS\r
418EFIAPI\r
419VlanConfigSet (\r
420 IN EFI_VLAN_CONFIG_PROTOCOL *This,\r
421 IN UINT16 VlanId,\r
422 IN UINT8 Priority\r
423 )\r
424{\r
425 EFI_STATUS Status;\r
426 MNP_DEVICE_DATA *MnpDeviceData;\r
427 MNP_SERVICE_DATA *MnpServiceData;\r
428 VLAN_TCI *OldVariable;\r
429 VLAN_TCI *NewVariable;\r
430 UINTN NumberOfVlan;\r
431 UINTN Index;\r
432 BOOLEAN IsAdd;\r
433 LIST_ENTRY *Entry;\r
434\r
435 if ((This == NULL) || (VlanId > 4094) || (Priority > 7)) {\r
436 return EFI_INVALID_PARAMETER;\r
437 }\r
438\r
439 IsAdd = FALSE;\r
440 MnpDeviceData = MNP_DEVICE_DATA_FROM_THIS (This);\r
441 if (MnpDeviceData->NumberOfVlan == 0) {\r
442 //\r
443 // No existing VLAN, this is the first VLAN to add\r
444 //\r
445 IsAdd = TRUE;\r
446 Entry = GetFirstNode (&MnpDeviceData->ServiceList);\r
447 MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry);\r
448\r
449 if (VlanId != 0) {\r
450 //\r
451 // VlanId is not 0, need destroy the default MNP service data\r
452 //\r
453 Status = MnpDestroyServiceChild (MnpServiceData);\r
454 if (EFI_ERROR (Status)) {\r
455 return Status;\r
456 }\r
457\r
458 Status = MnpDestroyServiceData (MnpServiceData);\r
459 if (EFI_ERROR (Status)) {\r
460 return Status;\r
461 }\r
462\r
463 //\r
464 // Create a new MNP service data for this VLAN\r
465 //\r
466 MnpServiceData = MnpCreateServiceData (MnpDeviceData, VlanId, Priority);\r
467 if (MnpServiceData == NULL) {\r
468 return EFI_OUT_OF_RESOURCES;\r
469 }\r
470 }\r
471 } else {\r
472 //\r
473 // Try to find VlanId in existing VLAN list\r
474 //\r
475 MnpServiceData = MnpFindServiceData (MnpDeviceData, VlanId);\r
476 if (MnpServiceData == NULL) {\r
477 //\r
478 // VlanId not found, create a new MNP service data\r
479 //\r
480 IsAdd = TRUE;\r
481 MnpServiceData = MnpCreateServiceData (MnpDeviceData, VlanId, Priority);\r
482 if (MnpServiceData == NULL) {\r
483 return EFI_OUT_OF_RESOURCES;\r
484 }\r
485 }\r
486 }\r
487\r
488 MnpServiceData->VlanId = VlanId;\r
489 MnpServiceData->Priority = Priority;\r
490 if (IsAdd) {\r
491 MnpDeviceData->NumberOfVlan++;\r
492 }\r
493\r
494 //\r
495 // Update VLAN configuration variable\r
496 //\r
497 OldVariable = NULL;\r
498 NewVariable = NULL;\r
499 NumberOfVlan = 0;\r
500 MnpGetVlanVariable (MnpDeviceData, &NumberOfVlan, &OldVariable);\r
501\r
502 if (IsAdd) {\r
503 //\r
504 // VLAN not exist - add\r
505 //\r
506 NewVariable = AllocateZeroPool ((NumberOfVlan + 1) * sizeof (VLAN_TCI));\r
507 if (NewVariable == NULL) {\r
508 Status = EFI_OUT_OF_RESOURCES;\r
509 goto Exit;\r
510 }\r
511\r
512 if (OldVariable != NULL) {\r
513 CopyMem (NewVariable, OldVariable, NumberOfVlan * sizeof (VLAN_TCI));\r
514 }\r
515\r
516 Index = NumberOfVlan++;\r
517 } else {\r
518 //\r
519 // VLAN already exist - update\r
520 //\r
521 for (Index = 0; Index < NumberOfVlan; Index++) {\r
522 if (OldVariable[Index].Bits.Vid == VlanId) {\r
523 break;\r
524 }\r
525 }\r
526 ASSERT (Index < NumberOfVlan);\r
527\r
528 NewVariable = OldVariable;\r
529 OldVariable = NULL;\r
530 }\r
531\r
532 NewVariable[Index].Bits.Vid = VlanId;\r
533 NewVariable[Index].Bits.Priority = Priority;\r
534\r
535 Status = MnpSetVlanVariable (MnpDeviceData, NumberOfVlan, NewVariable);\r
536 FreePool (NewVariable);\r
537\r
538Exit:\r
539 if (OldVariable != NULL) {\r
540 FreePool (OldVariable);\r
541 }\r
542\r
543 return Status;\r
544}\r
545\r
546\r
547/**\r
548 Find configuration information for specified VLAN or all configured VLANs.\r
549\r
550 The Find() function is used to find the configuration information for matching\r
551 VLAN and allocate a buffer into which those entries are copied.\r
552\r
553 @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL.\r
554 @param[in] VlanId Pointer to VLAN identifier. Set to NULL to find all\r
555 configured VLANs.\r
556 @param[out] NumberOfVlan The number of VLANs which is found by the specified criteria.\r
557 @param[out] Entries The buffer which receive the VLAN configuration.\r
558\r
559 @retval EFI_SUCCESS The VLAN is successfully found.\r
560 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:\r
561 - This is NULL.\r
562 - Specified VlanId is invalid.\r
563 @retval EFI_NOT_FOUND No matching VLAN is found.\r
564\r
565**/\r
566EFI_STATUS\r
567EFIAPI\r
568VlanConfigFind (\r
569 IN EFI_VLAN_CONFIG_PROTOCOL *This,\r
570 IN UINT16 *VlanId OPTIONAL,\r
571 OUT UINT16 *NumberOfVlan,\r
572 OUT EFI_VLAN_FIND_DATA **Entries\r
573 )\r
574{\r
575 MNP_DEVICE_DATA *MnpDeviceData;\r
576 MNP_SERVICE_DATA *MnpServiceData;\r
577 LIST_ENTRY *Entry;\r
578 EFI_VLAN_FIND_DATA *VlanData;\r
579\r
580 if ((This == NULL) || (VlanId != NULL && *VlanId > 4094) || (NumberOfVlan == NULL) || (Entries == NULL)) {\r
581 return EFI_INVALID_PARAMETER;\r
582 }\r
583\r
584 *NumberOfVlan = 0;\r
585 *Entries = NULL;\r
586\r
587 MnpDeviceData = MNP_DEVICE_DATA_FROM_THIS (This);\r
588 if (MnpDeviceData->NumberOfVlan == 0) {\r
589 return EFI_NOT_FOUND;\r
590 }\r
591\r
592 if (VlanId == NULL) {\r
593 //\r
594 // Return all current VLAN configuration\r
595 //\r
596 *NumberOfVlan = (UINT16) MnpDeviceData->NumberOfVlan;\r
597 VlanData = AllocateZeroPool (*NumberOfVlan * sizeof (EFI_VLAN_FIND_DATA));\r
598 if (VlanData == NULL) {\r
599 return EFI_OUT_OF_RESOURCES;\r
600 }\r
601\r
602 *Entries = VlanData;\r
603 NET_LIST_FOR_EACH (Entry, &MnpDeviceData->ServiceList) {\r
604 MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry);\r
605\r
606 VlanData->VlanId = MnpServiceData->VlanId;\r
607 VlanData->Priority = MnpServiceData->Priority;\r
608 VlanData++;\r
609 }\r
610\r
611 return EFI_SUCCESS;\r
612 }\r
613\r
614 //\r
615 // VlanId is specified, try to find it in current VLAN list\r
616 //\r
617 MnpServiceData = MnpFindServiceData (MnpDeviceData, *VlanId);\r
618 if (MnpServiceData == NULL) {\r
619 return EFI_NOT_FOUND;\r
620 }\r
621\r
622 VlanData = AllocateZeroPool (sizeof (EFI_VLAN_FIND_DATA));\r
623 if (VlanData == NULL) {\r
624 return EFI_OUT_OF_RESOURCES;\r
625 }\r
626 VlanData->VlanId = MnpServiceData->VlanId;\r
627 VlanData->Priority = MnpServiceData->Priority;\r
628\r
629 *NumberOfVlan = 1;\r
630 *Entries = VlanData;\r
631\r
632 return EFI_SUCCESS;\r
633}\r
634\r
635\r
636/**\r
637 Remove the configured VLAN device.\r
638\r
639 The Remove() function is used to remove the specified VLAN device.\r
640 If the VlanId is out of the scope of (0-4094), EFI_INVALID_PARAMETER is returned.\r
641 If specified VLAN hasn't been previously configured, EFI_NOT_FOUND is returned.\r
642\r
643 @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL.\r
644 @param[in] VlanId Identifier (0-4094) of the VLAN to be removed.\r
645\r
646 @retval EFI_SUCCESS The VLAN is successfully removed.\r
647 @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE:\r
648 - This is NULL.\r
649 - VlanId is an invalid parameter.\r
650 @retval EFI_NOT_FOUND The to-be-removed VLAN does not exist.\r
651\r
652**/\r
653EFI_STATUS\r
654EFIAPI\r
655VlanConfigRemove (\r
656 IN EFI_VLAN_CONFIG_PROTOCOL *This,\r
657 IN UINT16 VlanId\r
658 )\r
659{\r
660 EFI_STATUS Status;\r
661 MNP_DEVICE_DATA *MnpDeviceData;\r
662 MNP_SERVICE_DATA *MnpServiceData;\r
663 LIST_ENTRY *Entry;\r
664 VLAN_TCI *VlanVariable;\r
665 VLAN_TCI *VlanData;\r
666\r
667 if ((This == NULL) || (VlanId > 4094)) {\r
668 return EFI_INVALID_PARAMETER;\r
669 }\r
670\r
671 MnpDeviceData = MNP_DEVICE_DATA_FROM_THIS (This);\r
672 if (MnpDeviceData->NumberOfVlan == 0) {\r
673 return EFI_NOT_FOUND;\r
674 }\r
675\r
676 //\r
677 // Try to find the VlanId\r
678 //\r
679 MnpServiceData = MnpFindServiceData (MnpDeviceData, VlanId);\r
680 if (MnpServiceData == NULL) {\r
681 return EFI_NOT_FOUND;\r
682 }\r
683\r
684 MnpDeviceData->NumberOfVlan--;\r
685\r
686 if ((VlanId != 0) || (MnpDeviceData->NumberOfVlan != 0)) {\r
687 //\r
688 // If VlanId is not 0 or VlanId is 0 and it is not the last VLAN to remove,\r
689 // destroy its MNP service data\r
690 //\r
691 Status = MnpDestroyServiceChild (MnpServiceData);\r
692 if (EFI_ERROR (Status)) {\r
693 return Status;\r
694 }\r
695\r
696 Status = MnpDestroyServiceData (MnpServiceData);\r
697 if (EFI_ERROR (Status)) {\r
698 return Status;\r
699 }\r
700 }\r
701\r
702 if ((VlanId != 0) && (MnpDeviceData->NumberOfVlan == 0)) {\r
703 //\r
704 // This is the last VLAN to be removed, restore the default MNP service data\r
705 //\r
706 MnpServiceData = MnpCreateServiceData (MnpDeviceData, 0, 0);\r
707 if (MnpServiceData == NULL) {\r
708 return EFI_OUT_OF_RESOURCES;\r
709 }\r
710 }\r
711\r
712 //\r
713 // Update VLAN configuration variable\r
714 //\r
715 VlanVariable = NULL;\r
716 if (MnpDeviceData->NumberOfVlan != 0) {\r
717 VlanVariable = AllocatePool (MnpDeviceData->NumberOfVlan * sizeof (VLAN_TCI));\r
718 if (VlanVariable == NULL) {\r
719 return EFI_OUT_OF_RESOURCES;\r
720 }\r
721\r
722 VlanData = VlanVariable;\r
723 NET_LIST_FOR_EACH (Entry, &MnpDeviceData->ServiceList) {\r
724 MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry);\r
725\r
726 VlanData->Bits.Vid = MnpServiceData->VlanId;\r
727 VlanData->Bits.Priority = MnpServiceData->Priority;\r
728 VlanData++;\r
729 }\r
730 }\r
731\r
732 Status = MnpSetVlanVariable (MnpDeviceData, MnpDeviceData->NumberOfVlan, VlanVariable);\r
733\r
734 if (VlanVariable != NULL) {\r
735 FreePool (VlanVariable);\r
736 }\r
737\r
738 return Status;\r
739}\r