1 /** @file
2 Shell application for VLAN configuration.
3
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include <Uefi.h>
11
12 #include <Protocol/VlanConfig.h>
13
14 #include <Library/UefiApplicationEntryPoint.h>
15 #include <Library/UefiLib.h>
16 #include <Library/ShellLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/HiiLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Library/UefiHiiServicesLib.h>
21 #include <Library/NetLib.h>
22
23 //
24 // String token ID of VConfig command help message text.
25 //
26 GLOBAL_REMOVE_IF_UNREFERENCED EFI_STRING_ID mStringVConfigHelpTokenId = STRING_TOKEN (STR_VCONFIG_HELP);
27
28 #define INVALID_NIC_INDEX 0xffff
29 #define INVALID_VLAN_ID 0xffff
30
31 //
32 // This is the generated String package data for all .UNI files.
33 // This data array is ready to be used as input of HiiAddPackages() to
34 // create a packagelist (which contains Form packages, String packages, etc).
35 //
36 extern UINT8 VConfigStrings[];
37
38 EFI_HANDLE mImageHandle = NULL;
39 EFI_HII_HANDLE mHiiHandle = NULL;
40
41 SHELL_PARAM_ITEM mParamList[] = {
42 {
43 L"-l",
44 TypeValue
45 },
46 {
47 L"-a",
48 TypeMaxValue
49 },
50 {
51 L"-d",
52 TypeValue
53 },
54 {
55 NULL,
56 TypeMax
57 }
58 };
59
60 /**
61 Locate the network interface handle buffer.
62
63 @param[out] NumberOfHandles Pointer to the number of handles.
64 @param[out] HandleBuffer Pointer to the buffer to store the returned handles.
65
66 **/
67 VOID
LocateNicHandleBuffer(OUT UINTN * NumberOfHandles,OUT EFI_HANDLE ** HandleBuffer)68 LocateNicHandleBuffer (
69 OUT UINTN *NumberOfHandles,
70 OUT EFI_HANDLE **HandleBuffer
71 )
72 {
73 EFI_STATUS Status;
74
75 *NumberOfHandles = 0;
76 *HandleBuffer = NULL;
77
78 Status = gBS->LocateHandleBuffer (
79 ByProtocol,
80 &gEfiVlanConfigProtocolGuid,
81 NULL,
82 NumberOfHandles,
83 HandleBuffer
84 );
85 if (EFI_ERROR (Status)) {
86 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_LOCATE_FAIL), mHiiHandle, Status);
87 }
88 }
89
90 /**
91 Extract the decimal index from the network interface name.
92
93 @param[in] Name Name of the network interface.
94
95 @retval INVALID_NIC_INDEX Failed to extract the network interface index.
96 @return others The network interface index.
97
98 **/
99 UINTN
NicNameToIndex(IN CHAR16 * Name)100 NicNameToIndex (
101 IN CHAR16 *Name
102 )
103 {
104 CHAR16 *Str;
105
106 Str = Name + 3;
107 if ((StrnCmp (Name, L"eth", 3) != 0) || (*Str == 0)) {
108 return INVALID_NIC_INDEX;
109 }
110
111 while (*Str != 0) {
112 if ((*Str < L'0') || (*Str > L'9')) {
113 return INVALID_NIC_INDEX;
114 }
115
116 Str++;
117 }
118
119 return (UINT16) StrDecimalToUintn (Name + 3);
120 }
121
122 /**
123 Find network interface device handle by its name.
124
125 @param[in] Name Name of the network interface.
126
127 @retval NULL Cannot find the network interface.
128 @return others Handle of the network interface.
129
130 **/
131 EFI_HANDLE
NicNameToHandle(IN CHAR16 * Name)132 NicNameToHandle (
133 IN CHAR16 *Name
134 )
135 {
136 UINTN NumberOfHandles;
137 EFI_HANDLE *HandleBuffer;
138 UINTN Index;
139 EFI_HANDLE Handle;
140
141 //
142 // Find all NIC handles.
143 //
144 LocateNicHandleBuffer (&NumberOfHandles, &HandleBuffer);
145 if (NumberOfHandles == 0) {
146 return NULL;
147 }
148
149 Index = NicNameToIndex (Name);
150 if (Index >= NumberOfHandles) {
151 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_INVALID_IF), mHiiHandle, Name);
152 Handle = NULL;
153 } else {
154 Handle = HandleBuffer[Index];
155 }
156
157 FreePool (HandleBuffer);
158 return Handle;
159 }
160
161 /**
162 Open VlanConfig protocol from a handle.
163
164 @param[in] Handle The handle to open the VlanConfig protocol.
165
166 @return The VlanConfig protocol interface.
167
168 **/
169 EFI_VLAN_CONFIG_PROTOCOL *
OpenVlanConfigProtocol(IN EFI_HANDLE Handle)170 OpenVlanConfigProtocol (
171 IN EFI_HANDLE Handle
172 )
173 {
174 EFI_VLAN_CONFIG_PROTOCOL *VlanConfig;
175
176 VlanConfig = NULL;
177 gBS->OpenProtocol (
178 Handle,
179 &gEfiVlanConfigProtocolGuid,
180 (VOID **) &VlanConfig,
181 mImageHandle,
182 Handle,
183 EFI_OPEN_PROTOCOL_GET_PROTOCOL
184 );
185
186 return VlanConfig;
187 }
188
189 /**
190 Close VlanConfig protocol of a handle.
191
192 @param[in] Handle The handle to close the VlanConfig protocol.
193
194 **/
195 VOID
CloseVlanConfigProtocol(IN EFI_HANDLE Handle)196 CloseVlanConfigProtocol (
197 IN EFI_HANDLE Handle
198 )
199 {
200 gBS->CloseProtocol (
201 Handle,
202 &gEfiVlanConfigProtocolGuid,
203 mImageHandle,
204 Handle
205 );
206 }
207
208 /**
209 Display VLAN configuration of a network interface.
210
211 @param[in] Handle Handle of the network interface.
212 @param[in] NicIndex Index of the network interface.
213
214 **/
215 VOID
ShowNicVlanInfo(IN EFI_HANDLE Handle,IN UINTN NicIndex)216 ShowNicVlanInfo (
217 IN EFI_HANDLE Handle,
218 IN UINTN NicIndex
219 )
220 {
221 CHAR16 *MacStr;
222 EFI_STATUS Status;
223 UINTN Index;
224 EFI_VLAN_CONFIG_PROTOCOL *VlanConfig;
225 UINT16 NumberOfVlan;
226 EFI_VLAN_FIND_DATA *VlanData;
227
228 VlanConfig = OpenVlanConfigProtocol (Handle);
229 if (VlanConfig == NULL) {
230 return ;
231 }
232
233 MacStr = NULL;
234 Status = NetLibGetMacString (Handle, mImageHandle, &MacStr);
235 if (EFI_ERROR (Status)) {
236 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_MAC_FAIL), mHiiHandle, Status);
237 goto Exit;
238 }
239
240 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_ETH_MAC), mHiiHandle, NicIndex, MacStr);
241
242 Status = VlanConfig->Find (VlanConfig, NULL, &NumberOfVlan, &VlanData);
243 if (EFI_ERROR (Status)) {
244 if (Status == EFI_NOT_FOUND) {
245 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NO_VLAN), mHiiHandle);
246 } else {
247 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_FIND_FAIL), mHiiHandle, Status);
248 }
249
250 goto Exit;
251 }
252
253 for (Index = 0; Index < NumberOfVlan; Index++) {
254 ShellPrintHiiEx (
255 -1,
256 -1,
257 NULL,
258 STRING_TOKEN (STR_VCONFIG_VLAN_DISPLAY),
259 mHiiHandle,
260 VlanData[Index].VlanId,
261 VlanData[Index].Priority
262 );
263 }
264
265 FreePool (VlanData);
266
267 Exit:
268 CloseVlanConfigProtocol (Handle);
269
270 if (MacStr != NULL) {
271 FreePool (MacStr);
272 }
273 }
274
275 /**
276 Display the VLAN configuration of all, or a specified network interface.
277
278 @param[in] Name Name of the network interface. If NULL, the VLAN
279 configuration of all network will be displayed.
280
281 **/
282 VOID
DisplayVlan(IN CHAR16 * Name OPTIONAL)283 DisplayVlan (
284 IN CHAR16 *Name OPTIONAL
285 )
286 {
287 UINTN NumberOfHandles;
288 EFI_HANDLE *HandleBuffer;
289 UINTN Index;
290 EFI_HANDLE NicHandle;
291
292 if (Name != NULL) {
293 //
294 // Display specified NIC
295 //
296 NicHandle = NicNameToHandle (Name);
297 if (NicHandle == NULL) {
298 return ;
299 }
300
301 ShowNicVlanInfo (NicHandle, 0);
302 return ;
303 }
304
305 //
306 // Find all NIC handles
307 //
308 LocateNicHandleBuffer (&NumberOfHandles, &HandleBuffer);
309 if (NumberOfHandles == 0) {
310 return ;
311 }
312
313 for (Index = 0; Index < NumberOfHandles; Index++) {
314 ShowNicVlanInfo (HandleBuffer[Index], Index);
315 }
316
317 FreePool (HandleBuffer);
318 }
319
320 /**
321 Convert a NULL-terminated unicode decimal VLAN ID string to VLAN ID.
322
323 @param[in] String Pointer to VLAN ID string from user input.
324
325 @retval Value translated from String, or INVALID_VLAN_ID is string is invalid.
326
327 **/
328 UINT16
StrToVlanId(IN CHAR16 * String)329 StrToVlanId (
330 IN CHAR16 *String
331 )
332 {
333 CHAR16 *Str;
334
335 if (String == NULL) {
336 return INVALID_VLAN_ID;
337 }
338
339 Str = String;
340 while ((*Str >= '0') && (*Str <= '9')) {
341 Str++;
342 }
343
344 if (*Str != 0) {
345 return INVALID_VLAN_ID;
346 }
347
348 return (UINT16) StrDecimalToUintn (String);
349 }
350
351 /**
352 Add a VLAN device.
353
354 @param[in] ParamStr Parameter string from user input.
355
356 **/
357 VOID
AddVlan(IN CHAR16 * ParamStr)358 AddVlan (
359 IN CHAR16 *ParamStr
360 )
361 {
362 CHAR16 *Name;
363 CHAR16 *VlanIdStr;
364 CHAR16 *PriorityStr;
365 CHAR16 *StrPtr;
366 BOOLEAN IsSpace;
367 UINTN VlanId;
368 UINTN Priority;
369 EFI_HANDLE Handle;
370 EFI_HANDLE VlanHandle;
371 EFI_VLAN_CONFIG_PROTOCOL *VlanConfig;
372 EFI_STATUS Status;
373
374 VlanConfig = NULL;
375 Priority = 0;
376
377 if (ParamStr == NULL) {
378 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NO_IF), mHiiHandle);
379 return ;
380 }
381
382 StrPtr = AllocateCopyPool (StrSize (ParamStr), ParamStr);
383 if (StrPtr == NULL) {
384 return ;
385 }
386
387 Name = StrPtr;
388 VlanIdStr = NULL;
389 PriorityStr = NULL;
390 IsSpace = FALSE;
391 while (*StrPtr != 0) {
392 if (*StrPtr == L' ') {
393 *StrPtr = 0;
394 IsSpace = TRUE;
395 } else {
396 if (IsSpace) {
397 //
398 // Start of a parameter.
399 //
400 if (VlanIdStr == NULL) {
401 //
402 // 2nd parameter is VLAN ID.
403 //
404 VlanIdStr = StrPtr;
405 } else if (PriorityStr == NULL) {
406 //
407 // 3rd parameter is Priority.
408 //
409 PriorityStr = StrPtr;
410 } else {
411 //
412 // Ignore else parameters.
413 //
414 break;
415 }
416 }
417
418 IsSpace = FALSE;
419 }
420
421 StrPtr++;
422 }
423
424 Handle = NicNameToHandle (Name);
425 if (Handle == NULL) {
426 goto Exit;
427 }
428
429 VlanConfig = OpenVlanConfigProtocol (Handle);
430 if (VlanConfig == NULL) {
431 goto Exit;
432 }
433
434 //
435 // Check VLAN ID.
436 //
437 if ((VlanIdStr == NULL) || (*VlanIdStr == 0)) {
438 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NO_VID), mHiiHandle);
439 goto Exit;
440 }
441
442 VlanId = StrToVlanId (VlanIdStr);
443 if (VlanId > 4094) {
444 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_INVALID_VID), mHiiHandle, VlanIdStr);
445 goto Exit;
446 }
447
448 //
449 // Check Priority.
450 //
451 if ((PriorityStr != NULL) && (*PriorityStr != 0)) {
452 Priority = StrDecimalToUintn (PriorityStr);
453 if (Priority > 7) {
454 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_INVALID_PRIORITY), mHiiHandle, PriorityStr);
455 goto Exit;
456 }
457 }
458
459 //
460 // Set VLAN
461 //
462 Status = VlanConfig->Set (VlanConfig, (UINT16) VlanId, (UINT8) Priority);
463 if (EFI_ERROR (Status)) {
464 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_SET_FAIL), mHiiHandle, Status);
465 goto Exit;
466 }
467
468 //
469 // Connect the VLAN device.
470 //
471 VlanHandle = NetLibGetVlanHandle (Handle, (UINT16) VlanId);
472 if (VlanHandle != NULL) {
473 gBS->ConnectController (VlanHandle, NULL, NULL, TRUE);
474 }
475
476 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_SET_SUCCESS), mHiiHandle);
477
478 Exit:
479 if (VlanConfig != NULL) {
480 CloseVlanConfigProtocol (Handle);
481 }
482
483 FreePool (Name);
484 }
485
486 /**
487 Remove a VLAN device.
488
489 @param[in] ParamStr Parameter string from user input.
490
491 **/
492 VOID
DeleteVlan(IN CHAR16 * ParamStr)493 DeleteVlan (
494 IN CHAR16 *ParamStr
495 )
496 {
497 CHAR16 *Name;
498 CHAR16 *VlanIdStr;
499 CHAR16 *StrPtr;
500 UINTN VlanId;
501 EFI_HANDLE Handle;
502 EFI_VLAN_CONFIG_PROTOCOL *VlanConfig;
503 EFI_STATUS Status;
504 UINT16 NumberOfVlan;
505 EFI_VLAN_FIND_DATA *VlanData;
506
507 VlanConfig = NULL;
508
509 if (ParamStr == NULL) {
510 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NO_IF), mHiiHandle);
511 return ;
512 }
513
514 StrPtr = AllocateCopyPool (StrSize (ParamStr), ParamStr);
515 if (StrPtr == NULL) {
516 return ;
517 }
518
519 Name = StrPtr;
520 VlanIdStr = NULL;
521 while (*StrPtr != 0) {
522 if (*StrPtr == L'.') {
523 *StrPtr = 0;
524 VlanIdStr = StrPtr + 1;
525 break;
526 }
527
528 StrPtr++;
529 }
530
531 Handle = NicNameToHandle (Name);
532 if (Handle == NULL) {
533 goto Exit;
534 }
535
536 VlanConfig = OpenVlanConfigProtocol (Handle);
537 if (VlanConfig == NULL) {
538 goto Exit;
539 }
540
541 //
542 // Check VLAN ID
543 //
544 if (VlanIdStr == NULL || *VlanIdStr == 0) {
545 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NO_VID), mHiiHandle);
546 goto Exit;
547 }
548
549 VlanId = StrToVlanId (VlanIdStr);
550 if (VlanId > 4094) {
551 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_INVALID_VID), mHiiHandle, VlanIdStr);
552 goto Exit;
553 }
554
555 //
556 // Delete VLAN.
557 //
558 Status = VlanConfig->Remove (VlanConfig, (UINT16) VlanId);
559 if (EFI_ERROR (Status)) {
560 if (Status == EFI_NOT_FOUND) {
561 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NOT_FOUND), mHiiHandle);
562 } else {
563 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_REMOVE_FAIL), mHiiHandle, Status);
564 }
565
566 goto Exit;
567 }
568
569 //
570 // Check whether this is the last VLAN to remove.
571 //
572 Status = VlanConfig->Find (VlanConfig, NULL, &NumberOfVlan, &VlanData);
573 if (EFI_ERROR (Status)) {
574 //
575 // This is the last VLAN to remove, try to connect the controller handle.
576 //
577 gBS->ConnectController (Handle, NULL, NULL, TRUE);
578 } else {
579 FreePool (VlanData);
580 }
581
582 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_REMOVE_SUCCESS), mHiiHandle);
583
584 Exit:
585 if (VlanConfig != NULL) {
586 CloseVlanConfigProtocol (Handle);
587 }
588
589 FreePool (Name);
590 }
591
592 /**
593 The actual entry point for the application.
594
595 @param[in] ImageHandle The firmware allocated handle for the EFI image.
596 @param[in] SystemTable A pointer to the EFI System Table.
597
598 @retval EFI_SUCCESS The entry point executed successfully.
599 @retval other Some error occur when executing this entry point.
600
601 **/
602 EFI_STATUS
603 EFIAPI
VlanConfigMain(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)604 VlanConfigMain (
605 IN EFI_HANDLE ImageHandle,
606 IN EFI_SYSTEM_TABLE *SystemTable
607 )
608 {
609 LIST_ENTRY *List;
610 CONST CHAR16 *Str;
611 EFI_HII_PACKAGE_LIST_HEADER *PackageList;
612 EFI_STATUS Status;
613
614 mImageHandle = ImageHandle;
615
616 //
617 // Retrieve HII package list from ImageHandle
618 //
619 Status = gBS->OpenProtocol (
620 ImageHandle,
621 &gEfiHiiPackageListProtocolGuid,
622 (VOID **) &PackageList,
623 ImageHandle,
624 NULL,
625 EFI_OPEN_PROTOCOL_GET_PROTOCOL
626 );
627 if (EFI_ERROR (Status)) {
628 return Status;
629 }
630
631 //
632 // Publish HII package list to HII Database.
633 //
634 Status = gHiiDatabase->NewPackageList (
635 gHiiDatabase,
636 PackageList,
637 NULL,
638 &mHiiHandle
639 );
640 if (EFI_ERROR (Status)) {
641 return Status;
642 }
643
644 if (mHiiHandle == NULL) {
645 return EFI_SUCCESS;
646 }
647
648 List = NULL;
649 ShellCommandLineParseEx (mParamList, &List, NULL, FALSE, FALSE);
650 if (List == NULL) {
651 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NO_ARG), mHiiHandle);
652 goto Exit;
653 }
654
655 if (ShellCommandLineGetFlag (List, L"-l")) {
656 Str = ShellCommandLineGetValue (List, L"-l");
657 DisplayVlan ((CHAR16 *) Str);
658 goto Exit;
659 }
660
661 if (ShellCommandLineGetFlag (List, L"-a")) {
662 Str = ShellCommandLineGetValue (List, L"-a");
663 AddVlan ((CHAR16 *) Str);
664 goto Exit;
665 }
666
667 if (ShellCommandLineGetFlag (List, L"-d")) {
668 Str = ShellCommandLineGetValue (List, L"-d");
669 DeleteVlan ((CHAR16 *) Str);
670 goto Exit;
671 }
672
673 //
674 // No valid argument till now.
675 //
676 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NO_ARG), mHiiHandle);
677
678 Exit:
679 if (List != NULL) {
680 ShellCommandLineFreeVarList (List);
681 }
682
683 //
684 // Remove our string package from HII database.
685 //
686 HiiRemovePackages (mHiiHandle);
687
688 return EFI_SUCCESS;
689 }
690