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