SHEL22
[efi/shell/.git] / IfConfig / IfConfig.c
1 /*++
2
3 Copyright (c) 2006 - 2009, Intel Corporation                                                         
4 All rights reserved. This program and the accompanying materials                          
5 are licensed and made available under the terms and conditions of the BSD License         
6 which accompanies this distribution. The full text of the license may be found at         
7 http://opensource.org/licenses/bsd-license.php                                            
8                                                                                           
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
11
12 Module Name:
13
14   IfConfig.c
15   
16 Abstract:
17
18   Shell command "IfConfig"
19
20 --*/
21 #include "IfConfig.h"
22
23 #include STRING_DEFINES_FILE
24 extern UINT8 STRING_ARRAY_NAME[];
25
26 #define NET_IFTYPE_ETHERNET    1
27 #define NIC_ITEM_CONFIG_SIZE   sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE
28
29 EFI_HII_HANDLE  HiiHandle;
30
31 EFI_GUID  EfiIfConfigGuid = EFI_IFCONFIG_GUID;
32
33
34 #if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
35 EFI_HII_CONFIG_ROUTING_PROTOCOL  *mHiiConfigRouting = NULL;
36 #endif
37 BOOLEAN                          mIp4ConfigExist    = FALSE;
38
39
40 SHELL_VAR_CHECK_ITEM  IfConfigCheckList[] = {
41   {
42     L"-b",
43     0,
44     0,
45     FlagTypeSingle
46   },
47   {
48     L"-s",
49     0x1,
50     0xe,
51     FlagTypeSingle
52   },
53   {
54     L"-l",
55     0x2,
56     0xd,
57     FlagTypeSingle
58   },
59   {
60     L"-c",
61     0x4,
62     0xb,
63     FlagTypeSingle
64   },
65   {
66     L"-?",
67     0x8,
68     0x7,
69     FlagTypeSingle
70   },
71   {
72     NULL,
73     0,
74     0,
75     0
76   }
77 };
78
79 EFI_LIST_ENTRY                  NicInfoList;
80 BOOLEAN                         ArpResolved;
81 BOOLEAN                         Timeout;
82
83 NIC_INFO*
84 IfconfigFindNicByName (
85   IN UINT16                     *Name
86   )
87 /*++
88
89 Routine Description:
90
91   Find the NIC_INFO by the specified nic name.
92
93 Arguments:
94
95   Name - Pointer to the string containing the NIC name.
96
97 Returns:
98
99   Pointer to the NIC_INFO if there is a NIC_INFO named by Name, otherwise NULL.
100
101 --*/
102 {
103   EFI_LIST_ENTRY                *Entry;
104   NIC_INFO                      *Info;
105
106   EFI_LIST_FOR_EACH (Entry, &NicInfoList) {
107     Info = _CR (Entry, NIC_INFO, Link);
108
109     if (StriCmp (Name, Info->Name) == 0) {
110       return Info;
111     }
112   }
113
114   return NULL;
115 }
116
117 VOID
118 PrintMac (
119   IN CHAR16                     *Prefix,
120   IN EFI_MAC_ADDRESS            *Mac
121   )
122 /*++
123
124 Routine Description:
125
126   Print the specified mac address with the Prefix message.
127
128 Arguments:
129
130   Prefix - Pointer to some prefix message.
131   Mac    - Pointer to the mac address.
132
133 Returns:
134
135   None.
136
137 --*/
138 {
139   if (Prefix != NULL) {
140     Print (Prefix);
141   }
142   
143   PrintToken (
144     STRING_TOKEN (STR_IFCONFIG_SHOW_MAC_ADDR),
145     HiiHandle,
146     (UINTN)Mac->Addr[0], 
147     (UINTN)Mac->Addr[1], 
148     (UINTN)Mac->Addr[2],
149     (UINTN)Mac->Addr[3], 
150     (UINTN)Mac->Addr[4], 
151     (UINTN)Mac->Addr[5]
152     );
153 }
154
155 VOID
156 PrintIp (
157   IN CHAR16                     *Prefix,
158   IN EFI_IPv4_ADDRESS           *Ip4 
159   )
160 /*++
161
162 Routine Description:
163
164   Print the specified IPv4 address with the Prefix message.
165
166 Arguments:
167
168   Prefix - Pointer to some prefix message.
169   Ip4    - Pointer to the IPv4 address.
170
171 Returns:
172
173   None.
174
175 --*/
176 {
177   if (Prefix != NULL) {
178     Print (Prefix);
179   }
180
181   PrintToken (
182     STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR),
183     HiiHandle,
184     (UINTN)Ip4->Addr[0],
185     (UINTN)Ip4->Addr[1],
186     (UINTN)Ip4->Addr[2],
187     (UINTN)Ip4->Addr[3]
188     );
189 }
190
191 EFI_STATUS
192 TestChildHandle (
193   IN CONST EFI_HANDLE       ControllerHandle,
194   IN CONST EFI_HANDLE       ChildHandle,
195   IN CONST EFI_GUID         *ProtocolGuid
196   )
197 /*++
198
199 Routine Description:
200
201   Tests whether a child handle is a child device of the controller.
202
203 Arguments:
204
205   ControllerHandle - A handle for a (parent) controller to test.
206   ChildHandle      - A child handle to test.
207   ProtocolGuid     - Supplies the protocol that the child controller
208                      opens on its parent controller
209 Returns:
210
211   EFI_SUCCESS      - ChildHandle is a child of the ControllerHandle.
212   EFI_UNSUPPORTED  - ChildHandle is not a child of the ControllerHandle.
213
214 --*/
215 {
216   EFI_STATUS                            Status;
217   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY   *OpenInfoBuffer;
218   UINTN                                 EntryCount;
219   UINTN                                 Index;
220
221   ASSERT (ProtocolGuid != NULL);
222
223   //
224   // Retrieve the list of agents that are consuming the specific protocol
225   // on ControllerHandle.
226   //
227   Status = BS->OpenProtocolInformation (
228                  ControllerHandle,
229                  (EFI_GUID *) ProtocolGuid,
230                  &OpenInfoBuffer,
231                  &EntryCount
232                  );
233   if (EFI_ERROR (Status)) {
234     return EFI_UNSUPPORTED;
235   }
236
237   //
238   // Inspect if ChildHandle is one of the agents.
239   //
240   Status = EFI_UNSUPPORTED;
241   for (Index = 0; Index < EntryCount; Index++) {
242     if ((OpenInfoBuffer[Index].ControllerHandle == ChildHandle) &&
243         (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
244       Status = EFI_SUCCESS;
245       break;
246     }
247   }
248
249   FreePool (OpenInfoBuffer);
250   return Status;
251 }
252
253 EFI_STATUS 
254 GetChildHandle (
255   IN EFI_HANDLE         Controller,
256   OUT EFI_HANDLE        *ChildHandle
257   )
258 /*++
259
260 Routine Description:
261   Get the child handle of the NIC handle.
262
263 Arguments:
264   Controller   - Routing information: GUID.
265   ChildHandle  - Returned child handle.
266
267 Returns:
268   EFI_SUCCESS  - Successfully to get child handle.
269   Other        - Failed to get child handle.
270
271 --*/
272 {
273   EFI_STATUS                 Status;
274   EFI_HANDLE                 *Handles;
275   UINTN                      HandleCount;
276   UINTN                      Index;
277   EFI_DEVICE_PATH_PROTOCOL   *ChildDeviceDevicePath;
278   VENDOR_DEVICE_PATH         *VendorDeviceNode;
279
280   //
281   // Locate all EFI Hii Config Access protocols
282   //
283   Status = BS->LocateHandleBuffer (
284                  ByProtocol,
285                  &gEfiHiiConfigAccessProtocolGuid,
286                  NULL,
287                  &HandleCount,
288                  &Handles
289                  );
290   if (EFI_ERROR (Status) || (HandleCount == 0)) {
291     return Status;
292   }
293
294   Status = EFI_NOT_FOUND;
295
296   for (Index = 0; Index < HandleCount; Index++) {
297   
298     Status = TestChildHandle (Controller, Handles[Index], &gEfiManagedNetworkServiceBindingProtocolGuid);
299     if (!EFI_ERROR (Status)) {
300       //
301       // Get device path on the child handle
302       //
303       Status = BS->HandleProtocol (
304                      Handles[Index],
305                      &gEfiDevicePathProtocolGuid,
306                      (VOID **) &ChildDeviceDevicePath
307                      );
308       
309       if (!EFI_ERROR (Status)) {
310         while (!IsDevicePathEnd (ChildDeviceDevicePath)) {
311           ChildDeviceDevicePath = NextDevicePathNode (ChildDeviceDevicePath);
312           //
313           // Parse one instance
314           //
315           if (ChildDeviceDevicePath->Type == HARDWARE_DEVICE_PATH && 
316               ChildDeviceDevicePath->SubType == HW_VENDOR_DP) {
317             VendorDeviceNode = (VENDOR_DEVICE_PATH *) ChildDeviceDevicePath;
318             if (CompareMem (&VendorDeviceNode->Guid, &gEfiNicIp4ConfigVariableGuid, sizeof (EFI_GUID)) == 0) {
319               //
320               // Found item matched gEfiNicIp4ConfigVariableGuid
321               //
322               *ChildHandle = Handles[Index];
323               FreePool (Handles);
324               return EFI_SUCCESS;
325             }
326           }
327         }
328       }      
329     }
330   }
331
332   FreePool (Handles);
333   return Status;  
334 }
335
336 UINTN
337 AppendOffsetWidthValue (
338   IN OUT CHAR16               *String,
339   IN UINTN                    Offset,
340   IN UINTN                    Width,
341   IN UINT8                    *Block
342   )
343 /*++
344
345 Routine Description:
346   Append OFFSET/WIDTH/VALUE items at the beginning of string.
347
348 Arguments:
349   String -         Point to the position should be appended.
350   Offset -         Offset value.
351   Width  -         Width value.
352   Block  -         Point to data buffer.
353
354 Returns:
355   The count of unicode character was appended.
356
357 --*/
358 {
359   CHAR16                      *OriString;
360
361   OriString = String;
362
363   StrCpy (String, L"&OFFSET=");
364   String += StrLen (L"&OFFSET=");
365   String += SPrint (String, 0, L"%x", Offset);
366
367   StrCpy (String,L"&WIDTH=");
368   String += StrLen (L"&WIDTH=");
369   String += SPrint (String, 0, L"%x", Width);
370
371   if (Block != NULL) {
372     StrCpy (String,L"&VALUE=");
373     String += StrLen (L"&VALUE=");
374     while ((Width--) != 0) {
375       String += SPrint (String, 0, L"%x", Block[Width]);
376     }
377   }
378   
379   return String - OriString;
380 }
381
382 CHAR16 *
383 ConstructConfigHdr (
384   IN EFI_GUID                *Guid,
385   IN CHAR16                  *Name,
386   IN EFI_HANDLE              DriverHandle
387   )
388 /*++
389
390 Routine Description:
391   Construct <ConfigHdr> using routing information GUID/NAME/PATH.
392
393 Arguments:
394   Guid          - Routing information: GUID.
395   Name          - Routing information: NAME.
396   DriverHandle  - Driver handle which contains the routing information: PATH.
397
398 Returns:
399   NULL  - Fails.
400   Other - Pointer to configHdr string.
401
402 --*/
403 {
404   EFI_STATUS                 Status;
405   CHAR16                     *ConfigHdr;
406   EFI_DEVICE_PATH_PROTOCOL   *DevicePath;
407   CHAR16                     *String;
408   CHAR16                     *UpperString;
409   UINTN                      Index;
410   UINT8                      *Buffer;
411   UINTN                      DevicePathLength;
412   UINTN                      NameLength;
413
414   //
415   // Get the device path from handle installed EFI HII Config Access protocol
416   //
417   Status = BS->HandleProtocol (
418                  DriverHandle,
419                  &gEfiDevicePathProtocolGuid,
420                  (VOID **) &DevicePath
421                  );
422   if (EFI_ERROR (Status)) {
423     return NULL;
424   }
425
426   DevicePathLength = DevicePathSize (DevicePath);
427   NameLength = StrLen (Name);
428   ConfigHdr = AllocateZeroPool ((5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathLength * 2 + 1) * sizeof (CHAR16));
429   if (ConfigHdr == NULL) {
430     return NULL;
431   } 
432
433   String = ConfigHdr;
434   StrCpy (String, L"GUID=");
435   String += StrLen (L"GUID=");
436
437   //
438   // Append Guid converted to <HexCh>32
439   //
440   UpperString = String;
441   for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) {
442     String += SPrint (String, 0, L"%02x", *Buffer++);
443   }
444   *String = 0;
445   StrLwr (UpperString);
446
447   //
448   // Append L"&NAME="
449   //
450   StrCpy (String, L"&NAME=");
451   String += StrLen (L"&NAME=");
452   UpperString = String;
453   for (Index = 0; Index < NameLength ; Index++) {
454     String += SPrint (String, 0, L"00%x", Name[Index]);
455   }
456   *String = 0;
457   StrLwr (UpperString);
458   
459   //
460   // Append L"&PATH="
461   //
462   StrCpy (String, L"&PATH=");
463   String += StrLen (L"&PATH=");
464   UpperString = String;
465   for (Index = 0, Buffer = (UINT8 *) DevicePath; Index < DevicePathLength; Index++) {
466     String += SPrint (String, 0, L"%02x", *Buffer++);
467   }
468   *String = 0;
469   StrLwr (UpperString);
470
471   return ConfigHdr;
472 }
473
474 EFI_STATUS
475 IfConfigGetNicMacInfo (
476   IN  EFI_HANDLE                    ImageHandle,
477   IN  EFI_HANDLE                    Handle,
478   OUT NIC_ADDR                      *NicAddr
479   )    
480 /*++
481
482 Routine Description:
483   Get network physical device NIC information.
484
485 Arguments:
486   ImageHandle - The image handle of this application.
487   Handle      - The network physical device handle.
488   NicAddr     - NIC information.
489
490 Returns:
491   EFI_SUCCESS - Get NIC information successfully.
492   Other       - Fails to get NIC information.
493
494 --*/                  
495 {
496   EFI_STATUS                    Status;
497   EFI_HANDLE                    MnpHandle;
498   EFI_SIMPLE_NETWORK_MODE       SnpMode;
499   EFI_MANAGED_NETWORK_PROTOCOL  *Mnp;
500
501   MnpHandle = NULL;
502   Mnp       = NULL;
503
504   Status = ShellCreateServiceChild (
505              Handle,
506              ImageHandle, 
507              &gEfiManagedNetworkServiceBindingProtocolGuid,
508              &MnpHandle
509              );
510   if (EFI_ERROR (Status)) {
511     return Status;
512   }
513
514   Status = BS->HandleProtocol (
515                   MnpHandle,
516                   &gEfiManagedNetworkProtocolGuid,
517                   (VOID **) &Mnp
518                   );
519   if (EFI_ERROR (Status)) {
520     goto ON_ERROR;
521   }
522
523   Status = Mnp->GetModeData (Mnp, NULL, &SnpMode);
524   if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {
525     goto ON_ERROR;
526   }
527  
528   NicAddr->Type    = (UINT16) SnpMode.IfType;
529   NicAddr->Len     = (UINT8) SnpMode.HwAddressSize;
530   CopyMem (&NicAddr->MacAddr, &SnpMode.CurrentAddress, NicAddr->Len);
531
532 ON_ERROR:
533
534   ShellDestroyServiceChild (
535     Handle,
536     ImageHandle, 
537     &gEfiManagedNetworkServiceBindingProtocolGuid,
538     MnpHandle
539     );
540
541   return Status;
542
543 }
544
545 #if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
546 EFI_STATUS
547 IfconfigGetAllNicInfoByHii (
548   EFI_HANDLE                  ImageHandle
549   )
550 /*++
551
552 Routine Description:
553
554   Get all Nic's information through HII service.
555
556 Arguments:
557
558   ImageHandle - The image handle of this application.
559
560 Returns:
561
562   EFI_SUCCESS - All the nic information is collected.
563   other       - Some error occurs.
564
565 --*/
566 {
567   EFI_STATUS                    Status;
568   EFI_HANDLE                    *Handles;
569   UINTN                         HandleCount;
570   CHAR16                        *ConfigResp;
571   CHAR16                        *ConfigHdr;
572   UINTN                         Index;
573   CHAR16                        *AccessProgress;
574   CHAR16                        *AccessResults;
575   UINTN                         BufferSize;
576   NIC_INFO                      *NicInfo;
577   NIC_IP4_CONFIG_INFO           *NicConfigRequest;
578   NIC_IP4_CONFIG_INFO           *NicConfig;
579   CHAR16                        *String;
580   UINTN                         Length;
581   UINTN                         Offset;
582   EFI_HANDLE                    ChildHandle;
583
584   AccessResults    = NULL;
585   ConfigHdr        = NULL;
586   ConfigResp       = NULL;
587   NicConfigRequest = NULL;
588   NicInfo          = NULL;
589
590   InitializeListHead (&NicInfoList);
591
592   //
593   // Check if HII Config Routing protocol available.
594   //
595   Status = BS->LocateProtocol (
596                 &gEfiHiiConfigRoutingProtocolGuid,
597                 NULL,
598                 &mHiiConfigRouting
599                 );
600   if (EFI_ERROR (Status)) {
601     return EFI_NOT_FOUND;
602   }
603
604   //
605   // Locate all network device handles
606   //
607   Status = BS->LocateHandleBuffer (
608                  ByProtocol,
609                  &gEfiManagedNetworkServiceBindingProtocolGuid,
610                  NULL,
611                  &HandleCount,
612                  &Handles
613                  );
614   if (EFI_ERROR (Status) || (HandleCount == 0)) {
615     return EFI_NOT_FOUND;
616   }
617
618   for (Index = 0; Index < HandleCount; Index++) {
619     Status = GetChildHandle (Handles[Index], &ChildHandle);
620     if (EFI_ERROR (Status)) {
621       //
622       // If failed to get Child handle, try NIC controller handle for back-compatibility.
623       //
624       ChildHandle = Handles[Index];
625     }
626     //
627     // Construct configuration request string header
628     //
629     ConfigHdr = ConstructConfigHdr (&gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE, ChildHandle);
630     Length = StrLen (ConfigHdr);
631     ConfigResp = AllocateZeroPool ((Length + NIC_ITEM_CONFIG_SIZE * 2 + 100) * sizeof (CHAR16));
632     if (ConfigResp == NULL) {
633       Status = EFI_OUT_OF_RESOURCES;
634       goto ON_ERROR;
635     }
636     StrCpy (ConfigResp, ConfigHdr);
637  
638     //
639     // Append OFFSET/WIDTH pair
640     //
641     String = ConfigResp + Length;
642     Offset = 0;
643     String += AppendOffsetWidthValue (String, Offset, NIC_ITEM_CONFIG_SIZE, NULL);
644
645
646     NicInfo = AllocateZeroPool (sizeof (NIC_INFO));
647     if (NicInfo == NULL) {
648       Status = EFI_OUT_OF_RESOURCES;
649       goto ON_ERROR;
650     }
651     NicInfo->Handle       = Handles[Index];
652     NicInfo->NicIp4Config = NULL;
653
654     //
655     // Get network physical devcie MAC information
656     //
657     IfConfigGetNicMacInfo (ImageHandle, Handles[Index], &NicInfo->NicAddress);
658     if (NicInfo->NicAddress.Type == NET_IFTYPE_ETHERNET) {
659       SPrint (NicInfo->Name, 0, L"eth%d", Index);
660     } else {
661       SPrint (NicInfo->Name, 0, L"unk%d", Index);
662     }
663
664     NicConfigRequest = AllocateZeroPool (NIC_ITEM_CONFIG_SIZE);
665     if (NicConfigRequest == NULL) {
666       Status = EFI_OUT_OF_RESOURCES;
667       goto ON_ERROR;
668     }
669
670     //
671     // Get network parameters by HII service
672     //
673     Status = mHiiConfigRouting->ExtractConfig (
674                                   mHiiConfigRouting,
675                                   ConfigResp,
676                                   &AccessProgress,
677                                   &AccessResults
678                                   );
679     if (!EFI_ERROR (Status)) {
680       BufferSize = NIC_ITEM_CONFIG_SIZE;
681       Status = mHiiConfigRouting->ConfigToBlock (
682                                     mHiiConfigRouting,
683                                     AccessResults,
684                                     (UINT8 *) NicConfigRequest,
685                                     &BufferSize,
686                                     &AccessProgress
687                                     );
688       if (!EFI_ERROR (Status)) {
689         BufferSize = sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * NicConfigRequest->Ip4Info.RouteTableSize;
690         NicConfig = AllocateZeroPool (BufferSize);
691         if (NicConfig == NULL) {
692           Status = EFI_OUT_OF_RESOURCES;
693           goto ON_ERROR;
694         }
695         CopyMem (NicConfig, NicConfigRequest, BufferSize);
696
697         //
698         // If succeeds to get NIC configuration, fix up routetable pointer.
699         //
700         NicConfig->Ip4Info.RouteTable = (EFI_IP4_ROUTE_TABLE *) (&NicConfig->Ip4Info + 1);
701         NicInfo->ConfigInfo   = NicConfig;
702
703       } else {
704         NicInfo->ConfigInfo   = NULL;
705       }
706
707       FreePool (AccessResults);
708
709     } else {
710       NicInfo->ConfigInfo   = NULL;
711     }
712
713     //
714     // Add the Nic's info to the global NicInfoList.
715     //
716     InsertTailList (&NicInfoList, &NicInfo->Link);
717
718     FreePool (NicConfigRequest);
719     FreePool (ConfigResp);
720     FreePool (ConfigHdr);
721   }
722
723   FreePool (Handles);
724
725   return EFI_SUCCESS;
726  
727 ON_ERROR:
728   if (AccessResults != NULL) {
729     FreePool (AccessResults);
730   }
731   if (NicConfigRequest != NULL) {
732     FreePool (NicConfigRequest);
733   }
734   if (NicInfo != NULL) {
735     FreePool (NicInfo);
736   }
737   if (ConfigResp != NULL) {
738     FreePool (ConfigResp);
739   }
740   if (ConfigHdr != NULL) {
741     FreePool (ConfigHdr);
742   }
743
744   FreePool (Handles);
745
746   return Status;
747 }
748
749 EFI_STATUS
750 IfconfigSetNicAddrByHii (
751   IN  NIC_INFO                      *NicInfo,
752   IN  NIC_IP4_CONFIG_INFO           *Config
753   )
754 /*++
755
756 Routine Description:
757
758   Set the address for the specified nic by HII service.
759
760 Arguments:
761
762   NicInfo - Pointer to the NIC_INFO of the Nic to be configured.
763   Config - The command line arguments for the set operation.
764
765 Returns:
766
767   EFI_SUCCESS - The address set operation is done.
768   other       - Some error occurs.
769
770 --*/
771 {
772   EFI_STATUS                    Status;
773   NIC_IP4_CONFIG_INFO           *NicConfig;
774   CHAR16                        *ConfigResp;
775   CHAR16                        *ConfigHdr;
776   CHAR16                        *AccessProgress;
777   CHAR16                        *AccessResults;
778   CHAR16                        *String;
779   UINTN                         Length;
780   UINTN                         Offset;
781   EFI_HANDLE                    ChildHandle;
782
783   AccessResults  = NULL;
784   ConfigHdr      = NULL;
785   ConfigResp     = NULL;
786   NicConfig      = NULL;
787
788   Status = GetChildHandle (NicInfo->Handle, &ChildHandle);
789   if (EFI_ERROR (Status)) {
790     //
791     // If failed to get Child handle, try NIC controller handle for back-compatibility
792     //
793     ChildHandle = NicInfo->Handle;
794   }
795   //
796   // Construct config request string header
797   //
798   ConfigHdr = ConstructConfigHdr (&gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE, ChildHandle);
799
800   Length = StrLen (ConfigHdr);
801   ConfigResp = AllocateZeroPool ((Length + NIC_ITEM_CONFIG_SIZE * 2 + 100) * sizeof (CHAR16));
802   StrCpy (ConfigResp, ConfigHdr);
803
804   NicConfig = AllocateZeroPool (NIC_ITEM_CONFIG_SIZE);
805   if (NicConfig == NULL) {
806     Status = EFI_OUT_OF_RESOURCES;
807     goto ON_EXIT;
808   }
809
810   if (Config != NULL) {
811     CopyMem (NicConfig, Config, sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * Config->Ip4Info.RouteTableSize);
812   }
813
814   //
815   // Append OFFSET/WIDTH pair
816   //
817   String = ConfigResp + Length;
818   Offset = 0;
819   String += AppendOffsetWidthValue (String, Offset, NIC_ITEM_CONFIG_SIZE, NULL);
820
821   //
822   // Call HII helper function to generate configuration string
823   //
824   Status = mHiiConfigRouting->BlockToConfig (
825                                 mHiiConfigRouting,
826                                 ConfigResp,
827                                 (UINT8 *) NicConfig,
828                                 NIC_ITEM_CONFIG_SIZE,
829                                 &AccessResults,
830                                 &AccessProgress
831                                 );
832   if (EFI_ERROR (Status)) {
833     goto ON_EXIT;
834   }
835
836   //
837   // Set IP setting by HII servie
838   //
839   Status = mHiiConfigRouting->RouteConfig (
840                                 mHiiConfigRouting,
841                                 AccessResults,
842                                 &AccessProgress
843                                 );
844
845 ON_EXIT:
846   if (AccessResults != NULL) {
847     FreePool (AccessResults);
848   }
849   if (NicConfig != NULL) {
850     FreePool (NicConfig);
851   }
852   if (ConfigResp != NULL) {
853     FreePool (ConfigResp);
854   }
855   if (ConfigHdr != NULL) {
856     FreePool (ConfigHdr);
857   }
858
859   return Status;
860 }
861 #endif
862
863
864 EFI_STATUS
865 IfconfigGetAllNicInfo (
866   VOID
867   )
868 /*++
869
870 Routine Description:
871
872   Get all Nic's information through Ip4Config protocol.
873
874 Arguments:
875
876   None.
877
878 Returns:
879
880   EFI_SUCCESS - All the nic information is collected.
881   other       - Some error occurs.
882
883 --*/
884 {
885   EFI_NIC_IP4_CONFIG_PROTOCOL   *NicIp4Config;
886   EFI_IP4_CONFIG_PROTOCOL       *Ip4Config;
887   NIC_INFO                      *NicInfo;
888   NIC_IP4_CONFIG_INFO           *NicConfig;
889   EFI_HANDLE                    *Handles;
890   UINTN                         HandleCount;
891   UINT32                        Index;
892   UINTN                         Len;
893   EFI_STATUS                    Status;
894   
895   NicIp4Config = NULL;
896   Ip4Config    = NULL;
897   NicInfo      = NULL;
898   NicConfig    = NULL;
899   Handles      = NULL;
900
901   InitializeListHead (&NicInfoList);
902
903   //
904   // Locate the handles which has Ip4Config installed.
905   //
906   Status = BS->LocateHandleBuffer (
907                 ByProtocol,
908                 &gEfiIp4ConfigProtocolGuid,
909                 NULL,
910                 &HandleCount,
911                 &Handles
912                 );
913   if (EFI_ERROR (Status) || (HandleCount == 0)) {
914     return EFI_NOT_FOUND;
915   }
916   
917   //
918   // Found Ip4Config protocol
919   //
920   mIp4ConfigExist = TRUE;
921
922   for (Index = 0; Index < HandleCount; Index++) {
923     //
924     // Open the NicIp4Config and Ip4Config protocols
925     //
926     Status = BS->HandleProtocol (
927                    Handles[Index],
928                    &gEfiNicIp4ConfigProtocolGuid,
929                    (VOID **) &NicIp4Config
930                    );
931     
932     if (EFI_ERROR (Status)) {
933       goto ON_ERROR;
934     }
935
936     Status = BS->HandleProtocol (
937                    Handles[Index],
938                    &gEfiIp4ConfigProtocolGuid,
939                    (VOID **) &Ip4Config
940                    );
941     
942     if (EFI_ERROR (Status)) {
943       goto ON_ERROR;
944     }
945
946     //
947     // Get the Nic IP4 configure through the NicIp4Config protocol
948     //
949     Len    = 0;
950     Status = NicIp4Config->GetInfo (NicIp4Config, &Len, NULL);
951
952     if (Status == EFI_BUFFER_TOO_SMALL) {
953       NicConfig = AllocatePool (Len);
954   
955       if (NicConfig == NULL) {
956   
957         Status = EFI_OUT_OF_RESOURCES;
958         goto ON_ERROR;
959       }
960
961       Status = NicIp4Config->GetInfo (NicIp4Config, &Len, NicConfig); 
962
963       if (EFI_ERROR (Status)) {
964
965         goto ON_ERROR;
966       }
967     } else if (Status != EFI_NOT_FOUND) {     
968       
969       goto ON_ERROR;
970     }
971
972     //
973     // Add the Nic's info to the global NicInfoList.
974     //
975     NicInfo = AllocatePool (sizeof (NIC_INFO));
976
977     if (NicInfo == NULL) {
978       Status = EFI_OUT_OF_RESOURCES;
979       goto ON_ERROR;
980     }
981     
982     NicInfo->Handle       = Handles[Index];
983     NicInfo->NicIp4Config = NicIp4Config;
984     NicInfo->Ip4Config    = Ip4Config;
985     NicInfo->ConfigInfo   = NicConfig;
986     
987     Status = NicIp4Config->GetName (NicIp4Config, NicInfo->Name, &NicInfo->NicAddress);
988
989     if (EFI_ERROR (Status)) {
990       goto ON_ERROR;
991     }
992
993     InsertTailList (&NicInfoList, &NicInfo->Link);
994     
995     NicInfo   = NULL;
996     NicConfig = NULL;
997   }
998
999   FreePool (Handles);
1000   return EFI_SUCCESS;
1001   
1002 ON_ERROR:
1003   if (NicInfo != NULL) {
1004     FreePool (NicInfo);
1005   }
1006
1007   if (NicConfig != NULL) {
1008     FreePool (NicConfig);
1009   }
1010
1011   FreePool (Handles);
1012
1013   //
1014   // Return EFI_SUCCESS if we get at least some NIC's IP configure.
1015   //
1016   return (Index != 0) ? EFI_SUCCESS: Status;
1017 }
1018
1019 EFI_STATUS
1020 StrToIp (
1021   IN  CHAR16                    *String,
1022   OUT EFI_IPv4_ADDRESS          *Ip
1023   )
1024 /*++
1025
1026 Routine Description:
1027
1028   Convert a string into an IPv4 address.
1029
1030 Arguments:
1031
1032   String - Pointer to the string containing an IPv4 address.
1033   Ip     - Pointer to the storage for the IPv4 address.
1034
1035 Returns:
1036
1037   EFI_SUCCESS           - The string is converted into an IPv4 address.
1038   EFI_INVALID_PARAMETER - The string contains an invalid address.
1039
1040 --*/
1041 {
1042   EFI_IP_ADDRESS              IpAddr;
1043   UINT32                      Index;
1044   UINTN                       Byte;
1045   CHAR16                      Number[8];
1046   CHAR16                      *NumPtr;
1047
1048   IpAddr.Addr[0] = 0;
1049
1050   if (!SHELL_IS_DIGIT (*String)) {
1051     return EFI_INVALID_PARAMETER;
1052   }
1053
1054   for (Index = 0; Index < 4; Index++) {
1055     //
1056     // Copy the number to name buffer
1057     //
1058     NumPtr  = Number;
1059     while (SHELL_IS_DIGIT (*String)) {
1060       *NumPtr = *String;
1061       NumPtr++;
1062       String++;
1063     } 
1064     
1065     *NumPtr = 0;
1066     Byte    = Atoi (Number);
1067     if (Byte > 255) {
1068       return EFI_INVALID_PARAMETER;
1069     }
1070
1071     IpAddr.v4.Addr[Index]  = (UINT8) Byte;
1072
1073     if ((*String != '.') || !SHELL_IS_DIGIT (*(String + 1))) {
1074       break;
1075     }
1076
1077     String++;
1078   }
1079
1080   if (Index != 3) {
1081     return EFI_INVALID_PARAMETER;
1082   }
1083
1084   *Ip = IpAddr.v4;
1085   return EFI_SUCCESS;
1086 }
1087
1088
1089 VOID
1090 EFIAPI
1091 IfconfigOnArpResolved (
1092   IN EFI_EVENT                  Event,
1093   IN VOID                       *Context
1094   )
1095 /*++
1096
1097 Routine Description:
1098
1099   The callback function for the Arp address resolved event.
1100
1101 Arguments:
1102
1103   Event   - The event this function is registered to.
1104   Context - The context registered to the event.
1105
1106 Returns:
1107
1108   None.
1109
1110 --*/
1111 {
1112   ARP_REQUEST                   *Request;
1113   UINT8                         Index;
1114
1115   Request = (ARP_REQUEST *) Context;
1116   ASSERT (Request != NULL);
1117
1118   Request->Duplicate = FALSE;
1119   
1120   if (SHELL_MEM_EQUAL (&Request->LocalMac, &Request->DestMac, Request->MacLen)) {
1121     PrintIp (L"IfConfig: the interface is already configured with", &Request->DestIp.v4);
1122     ArpResolved = TRUE;
1123     return;
1124   }
1125   
1126   for (Index = 0; Index < Request->MacLen; Index++) {
1127     if (Request->DestMac.Addr[Index] != 0) {
1128       Request->Duplicate = TRUE;
1129     }
1130   }
1131
1132   if (Request->Duplicate) {
1133     PrintMac (L"IfConfig: IP address conflict with:", &Request->DestMac);    
1134   }
1135
1136   ArpResolved = TRUE;
1137   return ;
1138 }
1139
1140 BOOLEAN
1141 IfconfigIsIpDuplicate (
1142   IN  NIC_INFO                  *NicInfo,
1143   IN  IP4_ADDR                  IpAddr,
1144   IN  EFI_HANDLE                Image
1145   )
1146 /*++
1147
1148 Routine Description:
1149
1150   Check whether the address to be configured conflicts with other hosts.
1151
1152 Arguments:
1153
1154   NicInfo - Pointer to the NIC_INFO of the Nic to be configured.
1155   IpAddr  - The IPv4 address to be configured to the Nic.
1156   Image   - The image handle.
1157
1158 Returns:
1159
1160   TRUE if some other host already uses the IpAddr, otherwise FALSE.
1161
1162 --*/
1163 {
1164   EFI_ARP_PROTOCOL              *Arp;
1165   EFI_ARP_CONFIG_DATA           ArpCfgData;
1166   EFI_HANDLE                    ArpHandle;
1167   ARP_REQUEST                   Request;
1168   EFI_STATUS                    Status;
1169
1170   Arp           = NULL;
1171   ArpHandle     = NULL;
1172   ZeroMem (&Request, sizeof (ARP_REQUEST));
1173
1174   Status = ShellCreateServiceChild (
1175              NicInfo->Handle,
1176              Image, 
1177              &gEfiArpServiceBindingProtocolGuid,
1178              &ArpHandle
1179              );
1180
1181   if (EFI_ERROR (Status)) {
1182     return FALSE;
1183   }
1184
1185   Status = BS->OpenProtocol (
1186                  ArpHandle,
1187                  &gEfiArpProtocolGuid,
1188                  (VOID**)&Arp,
1189                  Image,
1190                  ArpHandle,
1191                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
1192                  );
1193
1194   if (EFI_ERROR (Status)) {
1195     goto ON_EXIT;
1196   }
1197
1198   //
1199   // Set up the Arp requests
1200   //
1201   EFI_IP4_TO_U32 (Request.DestIp.v4)  = IpAddr;
1202   EFI_IP4_TO_U32 (Request.LocalIp.v4) = 0xffffffff;
1203   Request.LocalMac                    = NicInfo->NicAddress.MacAddr;
1204   Request.MacLen                      = NicInfo->NicAddress.Len;
1205   
1206   Status = BS->CreateEvent (
1207                  EFI_EVENT_NOTIFY_SIGNAL,
1208                  EFI_TPL_CALLBACK,
1209                  IfconfigOnArpResolved,
1210                  (VOID *) &Request,
1211                  &Request.OnResolved
1212                  );
1213   
1214   if (EFI_ERROR (Status)) {
1215     goto ON_EXIT;
1216   }
1217   
1218   ArpCfgData.SwAddressType    = 0x0800;
1219   ArpCfgData.SwAddressLength  = 4;
1220   ArpCfgData.StationAddress   = &Request.LocalIp;
1221   ArpCfgData.EntryTimeOut     = 0;
1222   ArpCfgData.RetryCount       = 3;
1223   ArpCfgData.RetryTimeOut     = 0;
1224   
1225   Status = Arp->Configure (Arp, &ArpCfgData);
1226   
1227   if (EFI_ERROR (Status)) {
1228     goto ON_EXIT;
1229   }
1230
1231   Status = Arp->Request (
1232                   Arp,
1233                   &Request.DestIp,
1234                   Request.OnResolved,
1235                   &Request.DestMac
1236                   );
1237   
1238   if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
1239     goto ON_EXIT;
1240   }
1241
1242   while (!ArpResolved) {
1243     
1244   }
1245
1246
1247 ON_EXIT:
1248   if (Request.OnResolved != NULL) {
1249     BS->CloseEvent (Request.OnResolved);
1250   }
1251
1252   ShellDestroyServiceChild (
1253     NicInfo->Handle, 
1254     Image, 
1255     &gEfiArpServiceBindingProtocolGuid, 
1256     ArpHandle
1257     );
1258
1259   return Request.Duplicate;
1260 }
1261
1262 VOID
1263 EFIAPI
1264 TimeoutToGetMap (
1265   EFI_EVENT      Event,
1266   VOID           *Context
1267   )
1268 /*++
1269
1270 Routine Description:
1271
1272   The callback function for the timer event used to get map.
1273
1274 Arguments:
1275
1276   Event   - The event this function is registered to.
1277   Context - The context registered to the event.
1278
1279 Returns:
1280
1281   None.
1282
1283 --*/
1284 {
1285   Timeout = TRUE;
1286   return ;
1287 }
1288
1289 EFI_STATUS
1290 IfconfigStartIp4(
1291   IN NIC_INFO                   *NicInfo,
1292   IN EFI_HANDLE                 Image
1293   )
1294 /*++
1295
1296 Routine Description:
1297
1298   Create an IP child, use it to start the auto configuration, then destory it.
1299
1300 Arguments:
1301
1302   NicInfo - Pointer to the NIC_INFO of the Nic to be configured.
1303   Image   - The image handle.
1304
1305 Returns:
1306
1307   EFI_SUCCESS - The configuration is done.
1308   other       - Some error occurs.
1309
1310 --*/
1311 {
1312   EFI_IP4_PROTOCOL              *Ip4;
1313   EFI_HANDLE                    Ip4Handle;
1314   EFI_HANDLE                    TimerToGetMap;
1315   EFI_IP4_CONFIG_DATA           Ip4ConfigData;
1316   EFI_IP4_MODE_DATA             Ip4Mode;
1317   EFI_STATUS                    Status;
1318
1319   //
1320   // Get the Ip4ServiceBinding Protocol
1321   //
1322   Ip4Handle    = NULL;
1323   Ip4          = NULL;
1324   TimerToGetMap = NULL;
1325
1326   PrintToken (STRING_TOKEN (STR_IFCONFIG_START_SET_ADDR), HiiHandle);
1327
1328   Status = ShellCreateServiceChild (
1329              NicInfo->Handle,
1330              Image,
1331              &gEfiIp4ServiceBindingProtocolGuid,
1332              &Ip4Handle
1333              );
1334
1335   if (EFI_ERROR (Status)) {
1336     return Status;
1337   }
1338
1339   Status = BS->OpenProtocol (
1340                  Ip4Handle,
1341                  &gEfiIp4ProtocolGuid,
1342                  (VOID **) &Ip4,
1343                  NicInfo->Handle,
1344                  Image,
1345                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
1346                  );
1347
1348   if (EFI_ERROR (Status)) {
1349     goto ON_EXIT;
1350   }
1351
1352   Ip4ConfigData.DefaultProtocol          = EFI_IP_PROTO_ICMP;
1353   Ip4ConfigData.AcceptAnyProtocol        = FALSE;
1354   Ip4ConfigData.AcceptIcmpErrors         = FALSE;
1355   Ip4ConfigData.AcceptBroadcast          = FALSE;
1356   Ip4ConfigData.AcceptPromiscuous        = FALSE;
1357   Ip4ConfigData.UseDefaultAddress        = TRUE;
1358   ZeroMem (&Ip4ConfigData.StationAddress, sizeof (EFI_IPv4_ADDRESS));
1359   ZeroMem (&Ip4ConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1360   Ip4ConfigData.TypeOfService            = 0;
1361   Ip4ConfigData.TimeToLive               = 1;
1362   Ip4ConfigData.DoNotFragment            = FALSE;
1363   Ip4ConfigData.RawData                  = FALSE;
1364   Ip4ConfigData.ReceiveTimeout           = 0;
1365   Ip4ConfigData.TransmitTimeout          = 0;
1366
1367   Status = Ip4->Configure (Ip4, &Ip4ConfigData);
1368
1369   if (Status == EFI_NO_MAPPING) {
1370     Timeout = FALSE;
1371     Status  = BS->CreateEvent (
1372                     EFI_EVENT_NOTIFY_SIGNAL | EFI_EVENT_TIMER,
1373                     EFI_TPL_CALLBACK - 1,
1374                     TimeoutToGetMap,
1375                     NULL,
1376                     &TimerToGetMap
1377                     );
1378     
1379     if (EFI_ERROR (Status)) {
1380       goto ON_EXIT;
1381     }
1382     
1383     Status = BS->SetTimer (
1384                    TimerToGetMap,
1385                    TimerRelative,
1386                    MultU64x32 (SEC_TO_NS, 5)
1387                    );
1388     
1389     if (EFI_ERROR (Status)) {
1390       goto ON_EXIT;
1391     }
1392
1393     PrintToken (STRING_TOKEN (STR_IFCONFIG_WAIT_SET_DONE), HiiHandle);
1394     
1395     while (!Timeout) {
1396       Ip4->Poll (Ip4);
1397   
1398       if (!EFI_ERROR (Ip4->GetModeData (Ip4, &Ip4Mode, NULL, NULL)) && 
1399           Ip4Mode.IsConfigured) {       
1400         break;
1401       }
1402     }    
1403   }
1404
1405   Status = Ip4->GetModeData (Ip4, &Ip4Mode, NULL, NULL);
1406
1407   if ((Status == EFI_SUCCESS) && Ip4Mode.IsConfigured) {
1408     PrintIp (L"The default address is: ", &Ip4Mode.ConfigData.StationAddress);  
1409   }
1410   
1411 ON_EXIT: 
1412
1413   if (EFI_ERROR (Status)) {
1414     PrintToken (STRING_TOKEN (STR_IFCONFIG_GET_DEF_ADDR_FAIL), HiiHandle);
1415   }
1416
1417   if (TimerToGetMap != NULL) {
1418     BS->SetTimer (TimerToGetMap, TimerCancel, 0);
1419     BS->CloseEvent (TimerToGetMap);
1420   }
1421
1422   ShellDestroyServiceChild (
1423     NicInfo->Handle,
1424     Image,
1425     &gEfiIp4ServiceBindingProtocolGuid,
1426     Ip4Handle
1427     );
1428   
1429   return Status;
1430 }
1431
1432 EFI_STATUS 
1433 IfconfigSetNicAddr (
1434   IN UINTN                      Argc,
1435   IN SHELL_ARG_LIST             *VarList,
1436   IN EFI_HANDLE                 Image
1437   )
1438 /*++
1439
1440 Routine Description:
1441
1442   Set the address for the specified nic.
1443
1444 Arguments:
1445
1446   Argc    - Count of the passed in VarList.
1447   VarList - The command line arguments for the set operation.
1448   Image   - The image handle.
1449
1450 Returns:
1451
1452   EFI_SUCCESS - The address set operation is done.
1453   other       - Some error occurs.
1454
1455 --*/
1456 {
1457   NIC_IP4_CONFIG_INFO           *Config;
1458   NIC_IP4_CONFIG_INFO           *OldConfig;
1459   EFI_IP_ADDRESS                Ip;
1460   EFI_IP_ADDRESS                Mask;
1461   EFI_IP_ADDRESS                Gateway;
1462   NIC_INFO                      *Info;
1463   BOOLEAN                       Perment;
1464   EFI_STATUS                    Status;
1465   
1466   Info = IfconfigFindNicByName (VarList->VarStr);
1467
1468   if (Info == NULL) {
1469     PrintToken (STRING_TOKEN (STR_IFCONFIG_INTERFACE_NOT_FOUND), HiiHandle, VarList->VarStr);
1470     return EFI_NOT_FOUND;
1471   }
1472
1473   Config = AllocateZeroPool (sizeof (NIC_IP4_CONFIG_INFO) + 2 * sizeof (EFI_IP4_ROUTE_TABLE));
1474   if (Config == NULL) {
1475     return EFI_OUT_OF_RESOURCES;
1476   }
1477
1478   Config->Ip4Info.RouteTable = (EFI_IP4_ROUTE_TABLE *) (Config + 1);
1479
1480   OldConfig = Info->ConfigInfo;
1481   Perment   = FALSE;
1482   Status    = EFI_INVALID_PARAMETER;
1483
1484   VarList = VarList->Next;
1485   StrUpr (VarList->VarStr);
1486
1487   if (StrCmp (VarList->VarStr, L"DHCP") == 0) {
1488     //
1489     // Validate the parameter for DHCP, two valid forms: eth0 DHCP and eth0 DHCP perment
1490     //
1491     if ((Argc != 2) && (Argc!= 3)) {
1492       PrintToken (STRING_TOKEN (STR_IFCONFIG_PROMPT_HELP), HiiHandle);
1493       goto ON_EXIT;
1494     }
1495
1496     if (Argc == 3) {
1497       VarList = VarList->Next;
1498       StrUpr (VarList->VarStr);
1499       if (StrCmp (VarList->VarStr, L"PERMENT") != 0) {
1500         PrintToken (STRING_TOKEN (STR_IFCONFIG_PROMPT_HELP), HiiHandle);
1501         goto ON_EXIT;
1502       }
1503
1504       Perment = TRUE;
1505     }
1506
1507     if ((OldConfig != NULL) && (OldConfig->Source == IP4_CONFIG_SOURCE_DHCP) &&
1508         (OldConfig->Perment == Perment)) {
1509
1510       PrintToken (STRING_TOKEN (STR_IFCONFIG_INTERFACE_CONFIGURED), HiiHandle, Info->Name);
1511       Status = EFI_ALREADY_STARTED;
1512       goto ON_EXIT;
1513     }
1514
1515     Config->Source = IP4_CONFIG_SOURCE_DHCP;
1516   } else if (StrCmp (VarList->VarStr, L"STATIC") == 0) {
1517     //
1518     // validate the parameter, two forms: eth0 static IP NETMASK GATEWAY and
1519     // eth0 static IP NETMASK GATEWAY perment
1520     //
1521     if ((Argc != 5) && (Argc != 6)) {
1522       PrintToken (STRING_TOKEN (STR_IFCONFIG_PROMPT_HELP), HiiHandle);
1523       goto ON_EXIT;
1524     }
1525
1526     VarList = VarList->Next;
1527     if (EFI_ERROR (StrToIp (VarList->VarStr, &Ip.v4))) {
1528       PrintToken (STRING_TOKEN (STR_IFCONFIG_INVALID_IP_STR), HiiHandle, VarList->VarStr);
1529       goto ON_EXIT;
1530     }
1531
1532     VarList = VarList->Next;
1533     if (EFI_ERROR (StrToIp (VarList->VarStr, &Mask.v4))) {
1534       PrintToken (STRING_TOKEN (STR_IFCONFIG_INVALID_IP_STR), HiiHandle, VarList->VarStr);
1535       goto ON_EXIT;
1536     }
1537
1538     VarList = VarList->Next;
1539     if (EFI_ERROR (StrToIp (VarList->VarStr, &Gateway.v4))) {
1540       PrintToken (STRING_TOKEN (STR_IFCONFIG_INVALID_IP_STR), HiiHandle, VarList->VarStr);
1541       goto ON_EXIT;
1542     }
1543
1544     if (Argc == 6) {
1545       VarList = VarList->Next;
1546       StrUpr (VarList->VarStr);
1547
1548       if (StrCmp (VarList->VarStr, L"PERMENT") != 0) {
1549         PrintToken (STRING_TOKEN (STR_IFCONFIG_PROMPT_HELP), HiiHandle);
1550         goto ON_EXIT;
1551       }
1552
1553       Perment = TRUE;
1554     }
1555
1556     if ((Ip.Addr[0] == 0) || (Mask.Addr[0] == 0) ||
1557         !ShellIp4IsUnicast (NTOHL (Ip.Addr[0]), NTOHL (Mask.Addr[0]))) {
1558
1559       PrintToken (STRING_TOKEN (STR_IFCONFIG_INVALID_ADDR_PAIR), HiiHandle);
1560       goto ON_EXIT;
1561     }
1562
1563     if (!IP4_EQUAL_MASK (Ip.Addr[0], Gateway.Addr[0], Mask.Addr[0]) ||
1564         !ShellIp4IsUnicast (NTOHL (Gateway.Addr[0]), NTOHL (Mask.Addr[0]))) {
1565         
1566       PrintToken (STRING_TOKEN (STR_IFCONFIG_INVALID_GATEWAY), HiiHandle);
1567       goto ON_EXIT;
1568     }
1569
1570     //
1571     // Set the configuration up, two route table entries are added:
1572     // one for the direct connected network, and another for the 
1573     // default gateway. Remember, some structure members are cleared
1574     // by AllocateZeroPool
1575     //
1576     Config->Source = IP4_CONFIG_SOURCE_STATIC;
1577     Config->Ip4Info.RouteTableSize = 2;
1578
1579     CopyMem (&Config->Ip4Info.StationAddress, &Ip.v4, sizeof (EFI_IPv4_ADDRESS));
1580     CopyMem (&Config->Ip4Info.SubnetMask, &Mask.v4, sizeof (EFI_IPv4_ADDRESS));
1581
1582     Ip.Addr[0] = Ip.Addr[0] & Mask.Addr[0];
1583
1584     CopyMem (&Config->Ip4Info.RouteTable[0].SubnetAddress, &Ip.v4, sizeof (EFI_IPv4_ADDRESS));
1585     CopyMem (&Config->Ip4Info.RouteTable[0].SubnetMask, &Mask.v4, sizeof (EFI_IPv4_ADDRESS));
1586     CopyMem (&Config->Ip4Info.RouteTable[1].GatewayAddress, &Gateway.v4, sizeof (EFI_IPv4_ADDRESS));
1587   } else {
1588     PrintToken (STRING_TOKEN (STR_IFCONFIG_PROMPT_HELP), HiiHandle);
1589     goto ON_EXIT;
1590   }
1591
1592   Config->NicAddr = Info->NicAddress;
1593   Config->Perment = Perment;
1594
1595 #if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
1596   if (Info->NicIp4Config == NULL) {
1597     //
1598     // Try to use HII service to set NIC address
1599     //
1600     Status = IfconfigSetNicAddrByHii (Info, Config);
1601     if (EFI_ERROR (Status)) {
1602       PrintToken (STRING_TOKEN (STR_IFCONFIG_SET_FAIL), HiiHandle, Status);
1603       goto ON_EXIT;
1604     } 
1605   } else {
1606     //
1607     // Try to use NicIp4Config protocol to set NIC address
1608     //
1609     Status = Info->NicIp4Config->SetInfo (Info->NicIp4Config, Config, TRUE);
1610
1611     if (EFI_ERROR (Status)) {
1612       PrintToken (STRING_TOKEN (STR_IFCONFIG_SET_FAIL), HiiHandle, Status);
1613       goto ON_EXIT;
1614     } 
1615   }
1616 #else
1617   //
1618   // Try to use NicIp4Config protocol to set NIC address
1619   //
1620   Status = Info->NicIp4Config->SetInfo (Info->NicIp4Config, Config, TRUE);
1621
1622   if (EFI_ERROR (Status)) {
1623     PrintToken (STRING_TOKEN (STR_IFCONFIG_SET_FAIL), HiiHandle, Status);
1624     goto ON_EXIT;
1625   } 
1626 #endif
1627
1628   Status = IfconfigStartIp4 (Info, Image);
1629
1630   if (EFI_ERROR (Status)) {
1631     PrintToken (STRING_TOKEN (STR_IFCONFIG_IP_CHILD_FAIL), HiiHandle, Status);
1632   }
1633   
1634 ON_EXIT:
1635   if (Config != NULL) {
1636     FreePool (Config);
1637   }
1638   
1639   return Status;
1640 }
1641
1642
1643 VOID
1644 IfconfigShowNicInfo (
1645   IN  CHAR16                   *Name
1646   )
1647 /*++
1648
1649 Routine Description:
1650
1651   Show the address information for the nic specified.
1652
1653 Arguments:
1654
1655   Name - Pointer to the string containg the nic's name, if NULL, all nics'
1656          information is shown.
1657
1658 Returns:
1659
1660   None.
1661
1662 --*/
1663 {
1664   EFI_LIST_ENTRY                *Entry;
1665   NIC_INFO                      *NicInfo;
1666   UINT32                        Index;
1667   EFI_IP4_IPCONFIG_DATA         *Ip4Config;
1668   EFI_IPv4_ADDRESS              Gateway;
1669   EFI_IPv4_ADDRESS              ZeroIp;
1670
1671   EFI_LIST_FOR_EACH (Entry, &NicInfoList) {
1672     NicInfo = _CR (Entry, NIC_INFO, Link);
1673
1674     if ((Name != NULL) && (StriCmp (Name, NicInfo->Name) != 0)) {
1675       continue;
1676     }
1677
1678     PrintToken (STRING_TOKEN (STR_IFCONFIG_NIC_NAME), HiiHandle, NicInfo->Name);
1679     PrintMac (L"  MAC        : ", &NicInfo->NicAddress.MacAddr);
1680
1681     if (NicInfo->ConfigInfo == NULL) {
1682       PrintToken (STRING_TOKEN (STR_IFCONFIG_NIC_NOT_CONFIGURED), HiiHandle);
1683       continue;
1684     } 
1685
1686     if (NicInfo->ConfigInfo->Source == IP4_CONFIG_SOURCE_DHCP) {
1687       PrintToken (STRING_TOKEN (STR_IFCONFIG_CONFIG_SOURCE), HiiHandle, L"DHCP");
1688     } else if (NicInfo->ConfigInfo->Source == IP4_CONFIG_SOURCE_STATIC) {
1689       PrintToken (STRING_TOKEN (STR_IFCONFIG_CONFIG_SOURCE), HiiHandle, L"STATIC");
1690     } else {
1691       PrintToken (STRING_TOKEN (STR_IFCONFIG_CONFIG_SOURCE), HiiHandle, L"Unknown");
1692     }
1693
1694     PrintToken (
1695       STRING_TOKEN (STR_IFCONFIG_PERMENT_STATUS),
1696       HiiHandle,
1697       (NicInfo->ConfigInfo->Perment? L"TRUE":L"FALSE")
1698       );
1699
1700     Print (L"\n");
1701     
1702     Ip4Config = &NicInfo->ConfigInfo->Ip4Info;
1703
1704     PrintIp (L"  IP address : ", &Ip4Config->StationAddress);
1705     PrintIp (L"  Mask       : ", &Ip4Config->SubnetMask);
1706
1707     ZeroMem (&Gateway, sizeof (EFI_IPv4_ADDRESS));
1708     ZeroMem (&ZeroIp, sizeof (EFI_IPv4_ADDRESS));
1709     
1710     for (Index = 0; Index < Ip4Config->RouteTableSize; Index++) {
1711       if ((CompareMem (&Ip4Config->RouteTable[Index].SubnetAddress, &ZeroIp, sizeof (EFI_IPv4_ADDRESS)) == 0) &&
1712         (CompareMem (&Ip4Config->RouteTable[Index].SubnetMask, &ZeroIp, sizeof (EFI_IPv4_ADDRESS)) == 0)) {
1713         CopyMem (&Gateway, &Ip4Config->RouteTable[Index].GatewayAddress, sizeof (EFI_IPv4_ADDRESS));
1714       }
1715     }
1716    
1717     PrintIp (L"  Gateway    : ", &Gateway);
1718
1719     Print (L"\n");
1720
1721     PrintToken (STRING_TOKEN (STR_IFCONFIG_ROUTES_SIZE), HiiHandle, Ip4Config->RouteTableSize);
1722
1723     for (Index = 0; Index < Ip4Config->RouteTableSize; Index++) {
1724       PrintToken (STRING_TOKEN (STR_IFCONFIG_ROUTES_ENTRY_INDEX), HiiHandle, Index);
1725       PrintIp (L"      Subnet : ", &Ip4Config->RouteTable[Index].SubnetAddress);
1726       PrintIp (L"      Netmask: ", &Ip4Config->RouteTable[Index].SubnetMask);
1727       PrintIp (L"      Gateway: ", &Ip4Config->RouteTable[Index].GatewayAddress);
1728       Print   (L"\n");
1729     }
1730   }
1731
1732   return ;
1733 }
1734
1735 EFI_STATUS
1736 IfconfigClearNicAddr (
1737   IN CHAR16                     *Name
1738   )
1739 /*++
1740
1741 Routine Description:
1742
1743   Clear address configuration for the nic specified.
1744
1745 Arguments:
1746
1747   Name - Pointer to the string containg the nic's name, if NULL, all nics'
1748          address configurations are cleared.
1749
1750 Returns:
1751
1752   EFI_SUCCESS - The address configuration is cleared.
1753   other       - Some error occurs.
1754
1755 --*/
1756 {
1757   EFI_LIST_ENTRY                *Entry;
1758   NIC_INFO                      *Info;
1759   EFI_STATUS                    Status;
1760   
1761   EFI_LIST_FOR_EACH (Entry, &NicInfoList) {
1762     Info = _CR (Entry, NIC_INFO, Link);
1763
1764     if ((Name != NULL) && (StrCmp (Name, Info->Name) != 0)) {
1765       continue;
1766     }
1767
1768 #if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
1769     if (Info->NicIp4Config == NULL) { 
1770       Status = IfconfigSetNicAddrByHii (Info, NULL);
1771     } else {
1772       Status = Info->NicIp4Config->SetInfo (Info->NicIp4Config, NULL, TRUE);
1773     }
1774 #else 
1775     Status = Info->NicIp4Config->SetInfo (Info->NicIp4Config, NULL, TRUE);
1776 #endif
1777
1778     if (EFI_ERROR (Status)) {
1779       return Status;
1780     }
1781   }
1782
1783   return EFI_SUCCESS;
1784   
1785 }
1786
1787 EFI_STATUS
1788 EFIAPI
1789 IfConfig (
1790   IN  EFI_HANDLE                ImageHandle,
1791   IN  EFI_SYSTEM_TABLE          *SystemTable
1792   )
1793 /*++
1794
1795 Routine Description:
1796
1797   The main procedure.
1798
1799 Arguments:
1800
1801   ImageHandle - The image handle of this application.
1802   SystemTable - Pointer to the EFI system table.
1803
1804 Returns:
1805
1806   EFI_SUCCESS - The command finishes successfully.
1807   other       - Some error occurs.
1808
1809 --*/
1810 {
1811   EFI_STATUS                    Status;
1812   CHAR16                        *Useful;
1813   SHELL_ARG_LIST                *Item;
1814   SHELL_VAR_CHECK_CODE          RetCode;
1815   SHELL_VAR_CHECK_PACKAGE       ChkPck;
1816   EFI_LIST_ENTRY                *Entry;
1817   NIC_INFO                      *Info;
1818
1819   //
1820   // We are now being installed as an internal command driver, initialize
1821   // as an nshell app and run
1822   //
1823   EFI_SHELL_APP_INIT (ImageHandle, SystemTable);
1824
1825   //
1826   // Register our string package to HII database.
1827   //
1828   EFI_SHELL_STR_INIT (HiiHandle, STRING_ARRAY_NAME, EfiIfConfigGuid);
1829
1830   InitializeListHead (&NicInfoList);
1831   ZeroMem (&ChkPck, sizeof (SHELL_VAR_CHECK_PACKAGE));
1832
1833   Status = EFI_INVALID_PARAMETER;
1834   LibFilterNullArgs ();
1835   RetCode = LibCheckVariables (SI, IfConfigCheckList, &ChkPck, &Useful);
1836   if (VarCheckOk != RetCode) {
1837     switch (RetCode) {
1838     case VarCheckConflict:
1839       PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_FLAG_CONFLICT), HiiHandle, L"IfConfig", Useful);
1840       break;
1841
1842     case VarCheckDuplicate:
1843       PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_DUP_FLAG), HiiHandle, L"IfConfig", Useful);
1844       break;
1845
1846     case VarCheckLackValue:
1847       PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_LACK_ARG), HiiHandle, L"IfConfig", Useful);
1848       break;
1849
1850     case VarCheckUnknown:
1851       PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_UNKNOWN_FLAG), HiiHandle, L"IfConfig", Useful);
1852       break;
1853
1854     default:
1855       break;
1856     }
1857
1858     goto Done;
1859   }
1860
1861   if (LibCheckVarGetFlag (&ChkPck, L"-b") != NULL) {
1862     if (ChkPck.FlagCount == 1) {
1863       PrintToken (STRING_TOKEN (STR_IFCONFIG_PROMPT_HELP), HiiHandle);
1864       goto Done;
1865     }
1866
1867     EnablePageBreak (DEFAULT_INIT_ROW, DEFAULT_AUTO_LF);
1868   }
1869
1870   if (LibCheckVarGetFlag (&ChkPck, L"-?") != NULL) {
1871     PrintToken (STRING_TOKEN (STR_IFCONFIG_HELP), HiiHandle);
1872
1873     Status = EFI_SUCCESS;
1874     goto Done;
1875   }
1876
1877   Status = IfconfigGetAllNicInfo ();
1878 #if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
1879   if (EFI_ERROR (Status)) {
1880     Status = IfconfigGetAllNicInfoByHii (ImageHandle);
1881     if (EFI_ERROR (Status)) {
1882       if (mIp4ConfigExist) {
1883         PrintToken (STRING_TOKEN (STR_IFCONFIG_GET_NIC_FAIL), HiiHandle, Status);
1884       } else {
1885         PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_LOC_PROT_ERR_EX), HiiHandle, L"IfConfig", L"Ip4Config Protocol");
1886       }
1887
1888       return EFI_NOT_FOUND;
1889     }
1890   }
1891 #else 
1892   if (EFI_ERROR (Status)) {
1893     if (mIp4ConfigExist) {
1894       PrintToken (STRING_TOKEN (STR_IFCONFIG_GET_NIC_FAIL), HiiHandle, Status);
1895     } else {
1896       PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_LOC_PROT_ERR_EX), HiiHandle, L"IfConfig", L"Ip4Config Protocol");
1897     }
1898
1899     return EFI_NOT_FOUND;
1900   }
1901 #endif
1902
1903   Item = LibCheckVarGetFlag (&ChkPck, L"-l");
1904   if (Item != NULL) {
1905
1906     if (ChkPck.ValueCount > 1) {
1907       PrintToken (STRING_TOKEN (STR_IFCONFIG_PROMPT_HELP), HiiHandle);
1908     }
1909
1910     //
1911     // Show the configuration.
1912     //
1913     IfconfigShowNicInfo ((ChkPck.ValueCount != 0) ? ChkPck.VarList->VarStr : NULL);
1914   }
1915
1916   Item = LibCheckVarGetFlag (&ChkPck, L"-s");
1917   if (Item != NULL) {
1918
1919     //
1920     // The correct command line arguments for setting address are:
1921     // IfConfig -s eth0 DHCP [perment]
1922     // IfConfig -s eth0 static ip netmask gateway [perment]
1923     //
1924     if ((ChkPck.ValueCount < 2) || (ChkPck.ValueCount > 6) || (ChkPck.ValueCount == 4)) {
1925       PrintToken (STRING_TOKEN (STR_IFCONFIG_PROMPT_HELP), HiiHandle);
1926       goto Done;
1927     }
1928
1929     IfconfigSetNicAddr (ChkPck.ValueCount, ChkPck.VarList, ImageHandle);
1930   }
1931
1932   Item = LibCheckVarGetFlag (&ChkPck, L"-c");
1933   if (Item != NULL) {
1934
1935     if (ChkPck.ValueCount > 1) {
1936       PrintToken (STRING_TOKEN (STR_IFCONFIG_PROMPT_HELP), HiiHandle);
1937     }
1938
1939     IfconfigClearNicAddr ((ChkPck.ValueCount != 0) ? ChkPck.VarList->VarStr : NULL);
1940   }
1941
1942 Done:
1943
1944   LibCheckVarFreeVarList (&ChkPck);
1945
1946   while (!IsListEmpty (&NicInfoList)) {
1947     Entry = NicInfoList.Flink;
1948     Info  = _CR (Entry, NIC_INFO, Link);
1949
1950     RemoveEntryList (Entry);
1951
1952     if (Info->ConfigInfo != NULL) {
1953       FreePool (Info->ConfigInfo);
1954     }
1955
1956     FreePool (Info);
1957   }
1958
1959   return Status;
1960 }
1961
1962 EFI_BOOTSHELL_CODE(EFI_APPLICATION_ENTRY_POINT(IfConfig))
1963
1964 EFI_STATUS
1965 EFIAPI
1966 IfConfigGetLineHelp (
1967   OUT CHAR16              **Str
1968   )
1969 /*++
1970
1971 Routine Description:
1972
1973   Get this command's line help
1974
1975 Arguments:
1976
1977   Str - The line help
1978
1979 Returns:
1980
1981   EFI_SUCCESS   - Success
1982
1983 --*/
1984 {
1985   return LibCmdGetStringByToken (STRING_ARRAY_NAME, &EfiIfConfigGuid, STRING_TOKEN (STR_IFCONFIG_LINE_HELP), Str);
1986 }