Update HiiConfigAccess.ExtractConfig interface to support NULL request string and...
[efi/edk2/.git] / edk2 / MdeModulePkg / Universal / Network / Ip4ConfigDxe / Ip4ConfigNv.c
1 /** @file\r
2   Helper functions for configuring or getting the parameters relating to Ip4.\r
3 \r
4 Copyright (c) 2009 - 2010, Intel Corporation.<BR>\r
5 All rights reserved. This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution.  The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9 \r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 \r
13 **/\r
14 \r
15 #include "Ip4ConfigNv.h"\r
16 \r
17 EFI_GUID  mNicIp4ConfigNvDataGuid = EFI_NIC_IP4_CONFIG_NVDATA_GUID;\r
18 \r
19 \r
20 /**\r
21   Calculate the prefix length of the IPv4 subnet mask.\r
22 \r
23   @param[in]  SubnetMask The IPv4 subnet mask.\r
24 \r
25   @return The prefix length of the subnet mask.\r
26   @retval 0 Other errors as indicated.\r
27 **/\r
28 UINT8\r
29 GetSubnetMaskPrefixLength (\r
30   IN EFI_IPv4_ADDRESS  *SubnetMask\r
31   )\r
32 {\r
33   UINT8   Len;\r
34   UINT32  ReverseMask;\r
35 \r
36   //\r
37   // The SubnetMask is in network byte order.\r
38   //\r
39   ReverseMask = (SubnetMask->Addr[0] << 24) | (SubnetMask->Addr[1] << 16) | (SubnetMask->Addr[2] << 8) | (SubnetMask->Addr[3]);\r
40 \r
41   //\r
42   // Reverse it.\r
43   //\r
44   ReverseMask = ~ReverseMask;\r
45 \r
46   if ((ReverseMask & (ReverseMask + 1)) != 0) {\r
47     return 0;\r
48   }\r
49 \r
50   Len = 0;\r
51 \r
52   while (ReverseMask != 0) {\r
53     ReverseMask = ReverseMask >> 1;\r
54     Len++;\r
55   }\r
56 \r
57   return (UINT8) (32 - Len);\r
58 }\r
59 \r
60 /**\r
61   Convert the decimal dotted IPv4 address into the binary IPv4 address.\r
62 \r
63   @param[in]   Str             The UNICODE string.\r
64   @param[out]  Ip              The storage to return the ASCII string.\r
65 \r
66   @retval EFI_SUCCESS           The binary IP address is returned in Ip.\r
67   @retval EFI_INVALID_PARAMETER The IP string is malformatted.\r
68 **/\r
69 EFI_STATUS\r
70 Ip4AsciiStrToIp (\r
71   IN  CHAR8             *Str,\r
72   OUT EFI_IPv4_ADDRESS  *Ip\r
73   )\r
74 {\r
75   UINTN Index;\r
76   UINTN Number;\r
77 \r
78   Index = 0;\r
79 \r
80   while (*Str != 0) {\r
81 \r
82     if (Index > 3) {\r
83       return EFI_INVALID_PARAMETER;\r
84     }\r
85 \r
86     Number = 0;\r
87     while (NET_IS_DIGIT (*Str)) {\r
88       Number = Number * 10 + (*Str - '0');\r
89       Str++;\r
90     }\r
91 \r
92     if (Number > 0xFF) {\r
93       return EFI_INVALID_PARAMETER;\r
94     }\r
95 \r
96     Ip->Addr[Index] = (UINT8) Number;\r
97 \r
98     if ((*Str != '\0') && (*Str != '.')) {\r
99       //\r
100       // The current character should be either the NULL terminator or\r
101       // the dot delimiter.\r
102       //\r
103       return EFI_INVALID_PARAMETER;\r
104     }\r
105 \r
106     if (*Str == '.') {\r
107       //\r
108       // Skip the delimiter.\r
109       //\r
110       Str++;\r
111     }\r
112 \r
113     Index++;\r
114   }\r
115 \r
116   if (Index != 4) {\r
117     return EFI_INVALID_PARAMETER;\r
118   }\r
119 \r
120   return EFI_SUCCESS;\r
121 }\r
122 \r
123 /**\r
124   Convert the IPv4 address into a dotted string.\r
125 \r
126   @param[in]   Ip   The IPv4 address.\r
127   @param[out]  Str  The dotted IP string.\r
128 **/\r
129 VOID\r
130 Ip4ConfigIpToStr (\r
131   IN  EFI_IPv4_ADDRESS  *Ip,\r
132   OUT CHAR16            *Str\r
133   )\r
134 {\r
135   UnicodeSPrint (Str, 2 * IP4_STR_MAX_SIZE, L"%d.%d.%d.%d", Ip->Addr[0], Ip->Addr[1], Ip->Addr[2], Ip->Addr[3]);\r
136 }\r
137 \r
138 \r
139 /**\r
140   Convert the network configuration data into the IFR data.\r
141 \r
142   @param[in]   Ip4ConfigInstance The IP4Config instance\r
143   @param[out]  IfrFormNvData     The IFR nv data.\r
144 **/\r
145 VOID\r
146 Ip4ConfigConvertDeviceConfigDataToIfrNvData (\r
147   IN  IP4_CONFIG_INSTANCE       *Ip4ConfigInstance,\r
148   OUT IP4_CONFIG_IFR_NVDATA     *IfrFormNvData\r
149   )\r
150 {\r
151   EFI_STATUS                    Status;\r
152   NIC_IP4_CONFIG_INFO           *NicConfig;\r
153   UINTN                         ConfigLen;\r
154 \r
155   ConfigLen = sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * 2;\r
156   NicConfig = AllocateZeroPool (ConfigLen);\r
157   ASSERT (NicConfig != NULL);\r
158   Status = EfiNicIp4ConfigGetInfo (Ip4ConfigInstance, &ConfigLen, NicConfig);\r
159   if (!EFI_ERROR (Status)) {\r
160     IfrFormNvData->Configure = 1;\r
161     if (NicConfig->Source == IP4_CONFIG_SOURCE_DHCP) {\r
162       IfrFormNvData->DhcpEnable = 1;\r
163     } else {\r
164       IfrFormNvData->DhcpEnable = 0;\r
165       Ip4ConfigIpToStr (&NicConfig->Ip4Info.StationAddress, IfrFormNvData->StationAddress);\r
166       Ip4ConfigIpToStr (&NicConfig->Ip4Info.SubnetMask, IfrFormNvData->SubnetMask);\r
167       Ip4ConfigIpToStr (&NicConfig->Ip4Info.RouteTable[1].GatewayAddress, IfrFormNvData->GatewayAddress);\r
168     }\r
169   } else {\r
170     IfrFormNvData->Configure = 0;\r
171   }\r
172 \r
173   FreePool (NicConfig);\r
174 }\r
175 \r
176 /**\r
177   Convert the IFR data into the network configuration data and set the IP\r
178   configure parameters for the NIC.\r
179 \r
180   @param[in, out]  Ip4ConfigInstance The IP4Config instance.\r
181 \r
182   @retval EFI_SUCCESS            The configure parameter for this NIC was\r
183                                  set successfully.\r
184   @retval EFI_ALREADY_STARTED    There is a pending auto configuration.\r
185   @retval EFI_NOT_FOUND          No auto configure parameter is found.\r
186 \r
187 **/\r
188 EFI_STATUS\r
189 Ip4ConfigConvertIfrNvDataToDeviceConfigData (\r
190   IN OUT IP4_CONFIG_INSTANCE       *Ip4ConfigInstance\r
191   )\r
192 {\r
193   EFI_STATUS                Status;\r
194   EFI_IP_ADDRESS            HostIp;\r
195   EFI_IP_ADDRESS            SubnetMask;\r
196   EFI_IP_ADDRESS            Gateway;\r
197   EFI_INPUT_KEY             Key;\r
198   NIC_IP4_CONFIG_INFO       *NicInfo;\r
199   EFI_IP_ADDRESS            Ip;\r
200 \r
201   if (!Ip4ConfigInstance->Ip4ConfigCallbackInfo.Configured) {\r
202     //\r
203     // Clear the variable\r
204     //\r
205     ZeroMem (&Ip4ConfigInstance->Ip4ConfigCallbackInfo, sizeof (IP4_SETTING_INFO));\r
206 \r
207     Status = EfiNicIp4ConfigSetInfo (Ip4ConfigInstance, NULL, TRUE);\r
208     if (Status == EFI_NOT_FOUND) {\r
209       return EFI_SUCCESS;\r
210     }\r
211 \r
212     return Status;\r
213   }\r
214 \r
215   NicInfo = AllocateZeroPool (sizeof (NIC_IP4_CONFIG_INFO) + 2 * sizeof (EFI_IP4_ROUTE_TABLE));\r
216   ASSERT (NicInfo != NULL);\r
217 \r
218   NicInfo->Ip4Info.RouteTable = (EFI_IP4_ROUTE_TABLE *) (NicInfo + 1);\r
219 \r
220   if (!Ip4ConfigInstance->Ip4ConfigCallbackInfo.DhcpEnabled) {\r
221     CopyMem (&HostIp.v4, &Ip4ConfigInstance->Ip4ConfigCallbackInfo.LocalIp, sizeof (HostIp.v4));\r
222     CopyMem (&SubnetMask.v4, &Ip4ConfigInstance->Ip4ConfigCallbackInfo.SubnetMask, sizeof (SubnetMask.v4));\r
223     CopyMem (&Gateway.v4, &Ip4ConfigInstance->Ip4ConfigCallbackInfo.Gateway, sizeof (Gateway.v4));\r
224 \r
225     if (!NetIp4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {\r
226       CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);\r
227       return EFI_INVALID_PARAMETER;\r
228     }\r
229     if (EFI_IP4_EQUAL (&SubnetMask, &mZeroIp4Addr)) {\r
230       CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Subnet Mask!", NULL);\r
231       return EFI_INVALID_PARAMETER;\r
232     }\r
233 \r
234     if ((Gateway.Addr[0] != 0)) {\r
235       if (SubnetMask.Addr[0] == 0) {\r
236         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Gateway address is set but subnet mask is zero.", NULL);\r
237         return EFI_INVALID_PARAMETER;\r
238 \r
239       } else if (!IP4_NET_EQUAL (HostIp.Addr[0], Gateway.Addr[0], SubnetMask.Addr[0])) {\r
240         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Local IP and Gateway are not in the same subnet.", NULL);\r
241         return EFI_INVALID_PARAMETER;      }\r
242     }\r
243 \r
244     NicInfo->Source = IP4_CONFIG_SOURCE_STATIC;\r
245     NicInfo->Ip4Info.RouteTableSize = 2;\r
246 \r
247     CopyMem (&NicInfo->Ip4Info.StationAddress, &HostIp.v4, sizeof (EFI_IPv4_ADDRESS));\r
248     CopyMem (&NicInfo->Ip4Info.SubnetMask, &SubnetMask.v4, sizeof (EFI_IPv4_ADDRESS));\r
249 \r
250     Ip.Addr[0] = HostIp.Addr[0] & SubnetMask.Addr[0];\r
251 \r
252     CopyMem (&NicInfo->Ip4Info.RouteTable[0].SubnetAddress, &Ip.v4, sizeof (EFI_IPv4_ADDRESS));\r
253     CopyMem (&NicInfo->Ip4Info.RouteTable[0].SubnetMask, &SubnetMask.v4, sizeof (EFI_IPv4_ADDRESS));\r
254     CopyMem (&NicInfo->Ip4Info.RouteTable[1].GatewayAddress, &Gateway.v4, sizeof (EFI_IPv4_ADDRESS));\r
255 \r
256   } else {\r
257     NicInfo->Source = IP4_CONFIG_SOURCE_DHCP;\r
258     ZeroMem (&Ip4ConfigInstance->Ip4ConfigCallbackInfo.LocalIp, sizeof (EFI_IPv4_ADDRESS));\r
259     ZeroMem (&Ip4ConfigInstance->Ip4ConfigCallbackInfo.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
260     ZeroMem (&Ip4ConfigInstance->Ip4ConfigCallbackInfo.Gateway, sizeof (EFI_IPv4_ADDRESS));\r
261   }\r
262 \r
263   NicInfo->Perment = TRUE;\r
264   CopyMem (&NicInfo->NicAddr, &Ip4ConfigInstance->NicAddr, sizeof (NIC_ADDR));\r
265 \r
266   return EfiNicIp4ConfigSetInfo (Ip4ConfigInstance, NicInfo, TRUE);\r
267 }\r
268 \r
269 /**\r
270   This function allows the caller to request the current\r
271   configuration for one or more named elements. The resulting\r
272   string is in <ConfigAltResp> format. Any and all alternative\r
273   configuration strings shall also be appended to the end of the\r
274   current configuration string. If they are, they must appear\r
275   after the current configuration. They must contain the same\r
276   routing (GUID, NAME, PATH) as the current configuration string.\r
277   They must have an additional description indicating the type of\r
278   alternative configuration the string represents,\r
279   "ALTCFG=<StringToken>". That <StringToken> (when\r
280   converted from Hex UNICODE to binary) is a reference to a\r
281   string in the associated string pack.\r
282 \r
283   @param[in] This       Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
284   @param[in] Request    A null-terminated Unicode string in\r
285                         <ConfigRequest> format. Note that this\r
286                         includes the routing information as well as\r
287                         the configurable name / value pairs. It is\r
288                         invalid for this string to be in\r
289                         <MultiConfigRequest> format.\r
290   @param[out] Progress  On return, points to a character in the\r
291                         Request string. Points to the string's null\r
292                         terminator if request was successful. Points\r
293                         to the most recent "&" before the first\r
294                         failing name / value pair (or the beginning\r
295                         of the string if the failure is in the first\r
296                         name / value pair) if the request was not\r
297                         successful.\r
298   @param[out] Results   A null-terminated Unicode string in\r
299                         <ConfigAltResp> format which has all values\r
300                         filled in for the names in the Request string.\r
301                         String to be allocated by the called function.\r
302 \r
303   @retval EFI_SUCCESS             The Results string is filled with the\r
304                                   values corresponding to all requested\r
305                                   names.\r
306   @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the\r
307                                   parts of the results that must be\r
308                                   stored awaiting possible future\r
309                                   protocols.\r
310   @retval EFI_INVALID_PARAMETER   For example, passing in a NULL\r
311                                   for the Request parameter\r
312                                   would result in this type of\r
313                                   error. In this case, the\r
314                                   Progress parameter would be\r
315                                   set to NULL.\r
316   @retval EFI_NOT_FOUND           Routing data doesn't match any\r
317                                   known driver. Progress set to the\r
318                                   first character in the routing header.\r
319                                   Note: There is no requirement that the\r
320                                   driver validate the routing data. It\r
321                                   must skip the <ConfigHdr> in order to\r
322                                   process the names.\r
323   @retval EFI_INVALID_PARAMETER   Illegal syntax. Progress set\r
324                                   to most recent & before the\r
325                                   error or the beginning of the\r
326                                   string.\r
327   @retval EFI_INVALID_PARAMETER   Unknown name. Progress points\r
328                                   to the & before the name in\r
329                                   question.Currently not implemented.\r
330 **/\r
331 EFI_STATUS\r
332 EFIAPI\r
333 Ip4DeviceExtractConfig (\r
334   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
335   IN  CONST EFI_STRING                       Request,\r
336   OUT EFI_STRING                             *Progress,\r
337   OUT EFI_STRING                             *Results\r
338   )\r
339 {\r
340   EFI_STATUS                       Status;\r
341   UINTN                            ConfigLen;\r
342   NIC_IP4_CONFIG_INFO              *IfrDeviceNvData;\r
343   IP4_CONFIG_INSTANCE              *Ip4ConfigInstance;\r
344   IP4_CONFIG_IFR_NVDATA            *IfrFormNvData;\r
345   EFI_STRING                       ConfigRequestHdr;\r
346   EFI_STRING                       ConfigRequest;\r
347   EFI_STRING                       DeviceResult;\r
348   EFI_STRING                       FormResult;\r
349   CHAR16                           *StrPointer;\r
350   BOOLEAN                          AllocatedRequest;\r
351   UINTN                            Size;\r
352   UINTN                            BufferSize;\r
353 \r
354   if (Progress == NULL || Results == NULL) {\r
355     return EFI_INVALID_PARAMETER;\r
356   }\r
357 \r
358   *Progress     = Request;\r
359   Size          = 0;\r
360   DeviceResult  = NULL;\r
361   FormResult    = NULL;\r
362   ConfigRequest = NULL;\r
363   Status        = EFI_SUCCESS;\r
364   AllocatedRequest  = FALSE;\r
365   Ip4ConfigInstance = IP4_CONFIG_INSTANCE_FROM_CONFIG_ACCESS (This);\r
366 \r
367   //\r
368   // Check Request data in <ConfigHdr>.\r
369   //\r
370   if ((Request == NULL) || HiiIsConfigHdrMatch (Request, &gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE)) {\r
371     IfrDeviceNvData = AllocateZeroPool (NIC_ITEM_CONFIG_SIZE);\r
372     if (IfrDeviceNvData == NULL) {\r
373       return EFI_OUT_OF_RESOURCES;\r
374     }\r
375 \r
376     ConfigLen = sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * 2;\r
377     Status = EfiNicIp4ConfigGetInfo (Ip4ConfigInstance, &ConfigLen, IfrDeviceNvData);\r
378     if (EFI_ERROR (Status)) {\r
379       FreePool (IfrDeviceNvData);\r
380       return EFI_NOT_FOUND;\r
381     }\r
382 \r
383     ConfigRequest = Request;\r
384     if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {\r
385       //\r
386       // Request has no request element, construct full request string.\r
387       // Allocate and fill a buffer large enough to hold the <ConfigHdr> template\r
388       // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator\r
389       //\r
390       ConfigRequestHdr = HiiConstructConfigHdr (&gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE, Ip4ConfigInstance->ChildHandle);\r
391       Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);\r
392       ConfigRequest = AllocateZeroPool (Size);\r
393       ASSERT (ConfigRequest != NULL);\r
394       AllocatedRequest = TRUE;\r
395       BufferSize = NIC_ITEM_CONFIG_SIZE;\r
396       UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);\r
397       FreePool (ConfigRequestHdr);\r
398     }\r
399 \r
400     //\r
401     // Convert buffer data to <ConfigResp> by helper function BlockToConfig()\r
402     //\r
403     Status = gHiiConfigRouting->BlockToConfig (\r
404                                   gHiiConfigRouting,\r
405                                   ConfigRequest,\r
406                                   (UINT8 *) IfrDeviceNvData,\r
407                                   NIC_ITEM_CONFIG_SIZE,\r
408                                   &DeviceResult,\r
409                                   Progress\r
410                                   );\r
411 \r
412     FreePool (IfrDeviceNvData);\r
413     //\r
414     // Free the allocated config request string.\r
415     //\r
416     if (AllocatedRequest) {\r
417       FreePool (ConfigRequest);\r
418       ConfigRequest = NULL;\r
419     }\r
420 \r
421     if (EFI_ERROR (Status)) {\r
422       goto Failure;\r
423     }\r
424   } \r
425   \r
426   if ((Request == NULL) || HiiIsConfigHdrMatch (Request, &mNicIp4ConfigNvDataGuid, EFI_NIC_IP4_CONFIG_VARIABLE)) {\r
427 \r
428     IfrFormNvData = AllocateZeroPool (NIC_ITEM_CONFIG_SIZE);\r
429     if (IfrFormNvData == NULL) {\r
430       return EFI_OUT_OF_RESOURCES;\r
431     }\r
432 \r
433     Ip4ConfigConvertDeviceConfigDataToIfrNvData (Ip4ConfigInstance, IfrFormNvData);\r
434 \r
435     ConfigRequest = Request;\r
436     if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {\r
437       //\r
438       // Request has no request element, construct full request string.\r
439       // Allocate and fill a buffer large enough to hold the <ConfigHdr> template\r
440       // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator\r
441       //\r
442       ConfigRequestHdr = HiiConstructConfigHdr (&mNicIp4ConfigNvDataGuid, EFI_NIC_IP4_CONFIG_VARIABLE, Ip4ConfigInstance->ChildHandle);\r
443       Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);\r
444       ConfigRequest = AllocateZeroPool (Size);\r
445       ASSERT (ConfigRequest != NULL);\r
446       AllocatedRequest = TRUE;\r
447       BufferSize = sizeof (IP4_CONFIG_IFR_NVDATA);\r
448       UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);\r
449       FreePool (ConfigRequestHdr);\r
450     }\r
451  \r
452     //\r
453     // Convert buffer data to <ConfigResp> by helper function BlockToConfig()\r
454     //\r
455     Status = gHiiConfigRouting->BlockToConfig (\r
456                                   gHiiConfigRouting,\r
457                                   ConfigRequest,\r
458                                   (UINT8 *) IfrFormNvData,\r
459                                   sizeof (IP4_CONFIG_IFR_NVDATA),\r
460                                   &FormResult,\r
461                                   Progress\r
462                                   );\r
463 \r
464     FreePool (IfrFormNvData);\r
465     //\r
466     // Free the allocated config request string.\r
467     //\r
468     if (AllocatedRequest) {\r
469       FreePool (ConfigRequest);\r
470       ConfigRequest = NULL;\r
471     }\r
472 \r
473     if (EFI_ERROR (Status)) {\r
474       goto Failure;\r
475     }\r
476   }\r
477 \r
478   if (Request == NULL) {\r
479     Size = StrLen (DeviceResult);\r
480     Size = Size + 1;\r
481     Size = Size + StrLen (FormResult) + 1;\r
482     *Results = AllocateZeroPool (Size * sizeof (CHAR16));\r
483     ASSERT (*Results != NULL);\r
484     StrPointer  = *Results;\r
485     StrCpy (StrPointer, DeviceResult);\r
486     StrPointer  = StrPointer + StrLen (StrPointer);\r
487     *StrPointer = L'&';\r
488     StrCpy (StrPointer + 1, FormResult);\r
489     FreePool (DeviceResult);\r
490     FreePool (FormResult);\r
491   } else if (HiiIsConfigHdrMatch (ConfigRequest, &gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE)) {\r
492     *Results = DeviceResult;\r
493   } else if (HiiIsConfigHdrMatch (ConfigRequest, &mNicIp4ConfigNvDataGuid, EFI_NIC_IP4_CONFIG_VARIABLE)) {\r
494     *Results = FormResult;\r
495   } else {\r
496     return EFI_NOT_FOUND;\r
497   }\r
498 \r
499 Failure:\r
500   //\r
501   // Set Progress string to the original request string.\r
502   //\r
503   if (Request == NULL) {\r
504     *Progress = NULL;\r
505   } else if (StrStr (Request, L"OFFSET") == NULL) {\r
506     *Progress = Request + StrLen (Request);\r
507   }\r
508   \r
509   return Status;\r
510 }\r
511 \r
512 /**\r
513   This function applies changes in a driver's configuration.\r
514   Input is a Configuration, which has the routing data for this\r
515   driver followed by name / value configuration pairs. The driver\r
516   must apply those pairs to its configurable storage. If the\r
517   driver's configuration is stored in a linear block of data\r
518   and the driver's name / value pairs are in <BlockConfig>\r
519   format, it may use the ConfigToBlock helper function (above) to\r
520   simplify the job. Currently not implemented.\r
521 \r
522   @param[in]  This           Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
523   @param[in]  Configuration  A null-terminated Unicode string in\r
524                              <ConfigString> format.\r
525   @param[out] Progress       A pointer to a string filled in with the\r
526                              offset of the most recent '&' before the\r
527                              first failing name / value pair (or the\r
528                              beginn ing of the string if the failure\r
529                              is in the first name / value pair) or\r
530                              the terminating NULL if all was\r
531                              successful.\r
532 \r
533   @retval EFI_SUCCESS             The results have been distributed or are\r
534                                   awaiting distribution.\r
535   @retval EFI_OUT_OF_MEMORY       Not enough memory to store the\r
536                                   parts of the results that must be\r
537                                   stored awaiting possible future\r
538                                   protocols.\r
539   @retval EFI_INVALID_PARAMETERS  Passing in a NULL for the\r
540                                   Results parameter would result\r
541                                   in this type of error.\r
542   @retval EFI_NOT_FOUND           Target for the specified routing data\r
543                                   was not found.\r
544 **/\r
545 EFI_STATUS\r
546 EFIAPI\r
547 Ip4DeviceRouteConfig (\r
548   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
549   IN  CONST EFI_STRING                       Configuration,\r
550   OUT EFI_STRING                             *Progress\r
551   )\r
552 {\r
553   EFI_STATUS                       Status;\r
554   UINTN                            BufferSize;\r
555   NIC_IP4_CONFIG_INFO              *IfrDeviceNvData;\r
556   IP4_CONFIG_IFR_NVDATA            *IfrFormNvData;\r
557   NIC_IP4_CONFIG_INFO              *NicInfo;\r
558   IP4_CONFIG_INSTANCE              *Ip4ConfigInstance;\r
559   EFI_MAC_ADDRESS                  ZeroMac;\r
560 \r
561   if (Configuration == NULL || Progress == NULL) {\r
562     return EFI_INVALID_PARAMETER;\r
563   }\r
564 \r
565   *Progress = Configuration;\r
566 \r
567   Ip4ConfigInstance = IP4_CONFIG_INSTANCE_FROM_CONFIG_ACCESS (This);\r
568 \r
569   //\r
570   // Check Routing data in <ConfigHdr>.\r
571   //\r
572   if (HiiIsConfigHdrMatch (Configuration, &mNicIp4ConfigNvDataGuid, EFI_NIC_IP4_CONFIG_VARIABLE)) {\r
573     //\r
574     // Convert buffer data to <ConfigResp> by helper function BlockToConfig()\r
575     //\r
576     IfrFormNvData = AllocateZeroPool (sizeof (IP4_CONFIG_IFR_NVDATA));\r
577     if (IfrFormNvData == NULL) {\r
578       return EFI_OUT_OF_RESOURCES;\r
579     }\r
580 \r
581     BufferSize = NIC_ITEM_CONFIG_SIZE;\r
582     Status = gHiiConfigRouting->ConfigToBlock (\r
583                                   gHiiConfigRouting,\r
584                                   Configuration,\r
585                                   (UINT8 *) IfrFormNvData,\r
586                                   &BufferSize,\r
587                                   Progress\r
588                                   );\r
589     if (!EFI_ERROR (Status)) {\r
590       Status = Ip4ConfigConvertIfrNvDataToDeviceConfigData (Ip4ConfigInstance);\r
591     }\r
592 \r
593     FreePool (IfrFormNvData);\r
594 \r
595   } else if (HiiIsConfigHdrMatch (Configuration, &gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE)) {\r
596 \r
597     IfrDeviceNvData = AllocateZeroPool (NIC_ITEM_CONFIG_SIZE);\r
598     if (IfrDeviceNvData == NULL) {\r
599       return EFI_OUT_OF_RESOURCES;\r
600     }\r
601 \r
602     BufferSize = NIC_ITEM_CONFIG_SIZE;\r
603     Status = gHiiConfigRouting->ConfigToBlock (\r
604                                   gHiiConfigRouting,\r
605                                   Configuration,\r
606                                   (UINT8 *) IfrDeviceNvData,\r
607                                   &BufferSize,\r
608                                   Progress\r
609                                   );\r
610     if (!EFI_ERROR (Status)) {\r
611       ZeroMem (&ZeroMac, sizeof (EFI_MAC_ADDRESS));\r
612       if (CompareMem (&IfrDeviceNvData->NicAddr.MacAddr, &ZeroMac, IfrDeviceNvData->NicAddr.Len) != 0) {\r
613         BufferSize = sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * IfrDeviceNvData->Ip4Info.RouteTableSize;\r
614         NicInfo = AllocateCopyPool (BufferSize, IfrDeviceNvData);\r
615         Status = EfiNicIp4ConfigSetInfo (Ip4ConfigInstance, NicInfo, TRUE);\r
616       } else {\r
617         ZeroMem (&Ip4ConfigInstance->Ip4ConfigCallbackInfo, sizeof (IP4_SETTING_INFO));\r
618         Status = EfiNicIp4ConfigSetInfo (Ip4ConfigInstance, NULL, TRUE);\r
619       }\r
620     }\r
621 \r
622     FreePool (IfrDeviceNvData);\r
623 \r
624   } else {\r
625 \r
626     return EFI_NOT_FOUND;\r
627   }\r
628 \r
629   return Status;\r
630 \r
631 }\r
632 \r
633 /**\r
634   This function is called to provide results data to the driver.\r
635   This data consists of a unique key that is used to identify\r
636   which data is either being passed back or being asked for.\r
637 \r
638   @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
639   @param[in]  Action             Specifies the type of action taken by the browser.\r
640   @param[in]  QuestionId         A unique value which is sent to the original\r
641                                  exporting driver so that it can identify the type\r
642                                  of data to expect. The format of the data tends to\r
643                                  vary based on the opcode that enerated the callback.\r
644   @param[in]  Type               The type of value for the question.\r
645   @param[in]  Value              A pointer to the data being sent to the original\r
646                                  exporting driver.\r
647   @param[out]  ActionRequest     On return, points to the action requested by the\r
648                                  callback function.\r
649 \r
650   @retval EFI_SUCCESS            The callback successfully handled the action.\r
651   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the\r
652                                  variable and its data.\r
653   @retval EFI_DEVICE_ERROR       The variable could not be saved.\r
654   @retval EFI_UNSUPPORTED        The specified Action is not supported by the\r
655                                  callback.Currently not implemented.\r
656   @retval EFI_INVALID_PARAMETERS Passing in wrong parameter.\r
657   @retval Others                 Other errors as indicated.\r
658 **/\r
659 EFI_STATUS\r
660 EFIAPI\r
661 Ip4FormCallback (\r
662   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
663   IN  EFI_BROWSER_ACTION                     Action,\r
664   IN  EFI_QUESTION_ID                        QuestionId,\r
665   IN  UINT8                                  Type,\r
666   IN  EFI_IFR_TYPE_VALUE                     *Value,\r
667   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest\r
668   )\r
669 {\r
670   IP4_CONFIG_INSTANCE       *Ip4ConfigInstance;\r
671   CHAR8                     Ip4String[IP4_STR_MAX_SIZE];\r
672   IP4_CONFIG_IFR_NVDATA     *IfrFormNvData;\r
673   EFI_IP_ADDRESS            HostIp;\r
674   EFI_IP_ADDRESS            SubnetMask;\r
675   EFI_IP_ADDRESS            Gateway;\r
676   EFI_STATUS                Status;\r
677   EFI_INPUT_KEY             Key;\r
678 \r
679   Ip4ConfigInstance = IP4_CONFIG_INSTANCE_FROM_CONFIG_ACCESS (This);\r
680 \r
681   IfrFormNvData = AllocateZeroPool (sizeof (IP4_CONFIG_IFR_NVDATA));\r
682   if (IfrFormNvData == NULL) {\r
683     return EFI_OUT_OF_RESOURCES;\r
684   }\r
685 \r
686   //\r
687   // Retrive uncommitted data from Browser\r
688   //\r
689   if (!HiiGetBrowserData (&mNicIp4ConfigNvDataGuid, EFI_NIC_IP4_CONFIG_VARIABLE, sizeof (IP4_CONFIG_IFR_NVDATA), (UINT8 *) IfrFormNvData)) {\r
690     FreePool (IfrFormNvData);\r
691     return EFI_NOT_FOUND;\r
692   }\r
693 \r
694   Status = EFI_SUCCESS;\r
695 \r
696   switch (QuestionId) {\r
697 \r
698   case KEY_ENABLE:\r
699     if (IfrFormNvData->Configure == 0) {\r
700       Ip4ConfigInstance->Ip4ConfigCallbackInfo.Configured = FALSE;\r
701     } else {\r
702       Ip4ConfigInstance->Ip4ConfigCallbackInfo.Configured = TRUE;\r
703     }\r
704     break;\r
705 \r
706   case KEY_DHCP_ENABLE:\r
707     if (IfrFormNvData->DhcpEnable == 0) {\r
708       Ip4ConfigInstance->Ip4ConfigCallbackInfo.DhcpEnabled = FALSE;\r
709     } else {\r
710       Ip4ConfigInstance->Ip4ConfigCallbackInfo.DhcpEnabled = TRUE;\r
711     }\r
712 \r
713     break;\r
714 \r
715   case KEY_LOCAL_IP:\r
716     UnicodeStrToAsciiStr (IfrFormNvData->StationAddress, Ip4String);\r
717     Status = Ip4AsciiStrToIp (Ip4String, &HostIp.v4);\r
718     if (EFI_ERROR (Status) || !NetIp4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {\r
719       CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);\r
720       Status = EFI_INVALID_PARAMETER;\r
721     } else {\r
722       CopyMem (&Ip4ConfigInstance->Ip4ConfigCallbackInfo.LocalIp, &HostIp.v4, sizeof (HostIp.v4));\r
723     }\r
724 \r
725     break;\r
726 \r
727   case KEY_SUBNET_MASK:\r
728     UnicodeStrToAsciiStr (IfrFormNvData->SubnetMask, Ip4String);\r
729     Status = Ip4AsciiStrToIp (Ip4String, &SubnetMask.v4);\r
730     if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (GetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {\r
731       CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid SubnetMask!", NULL);\r
732       Status = EFI_INVALID_PARAMETER;\r
733     } else {\r
734       CopyMem (&Ip4ConfigInstance->Ip4ConfigCallbackInfo.SubnetMask, &SubnetMask.v4, sizeof (SubnetMask.v4));\r
735     }\r
736 \r
737     break;\r
738 \r
739   case KEY_GATE_WAY:\r
740     UnicodeStrToAsciiStr (IfrFormNvData->GatewayAddress, Ip4String);\r
741     Status = Ip4AsciiStrToIp (Ip4String, &Gateway.v4);\r
742     if (EFI_ERROR (Status) || ((Gateway.Addr[0] != 0) && !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), 0))) {\r
743       CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Gateway!", NULL);\r
744       Status = EFI_INVALID_PARAMETER;\r
745     } else {\r
746       CopyMem (&Ip4ConfigInstance->Ip4ConfigCallbackInfo.Gateway, &Gateway.v4, sizeof (Gateway.v4));\r
747     }\r
748 \r
749     break;\r
750 \r
751   case KEY_SAVE_CHANGES:\r
752 \r
753     Status = Ip4ConfigConvertIfrNvDataToDeviceConfigData (Ip4ConfigInstance);\r
754 \r
755     *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
756 \r
757     break;\r
758 \r
759   default:\r
760 \r
761     break;\r
762   }\r
763 \r
764   if (!EFI_ERROR (Status)) {\r
765     //\r
766     // Pass changed uncommitted data back to Form Browser\r
767     //\r
768     HiiSetBrowserData (&gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE, sizeof (IP4_CONFIG_IFR_NVDATA), (UINT8 *) IfrFormNvData, NULL);\r
769   }\r
770 \r
771   FreePool (IfrFormNvData);\r
772 \r
773   return Status;\r
774 }\r
775 \r
776 /**\r
777   Install HII Config Access protocol for network device and allocate resource.\r
778 \r
779   @param[in]  Instance            The IP4 Config instance.\r
780 \r
781   @retval EFI_SUCCESS              The HII Config Access protocol is installed.\r
782   @retval EFI_OUT_OF_RESOURCES     Failed to allocate memory.\r
783   @retval Others                   Other errors as indicated.\r
784 **/\r
785 EFI_STATUS\r
786 Ip4ConfigDeviceInit (\r
787   IN IP4_CONFIG_INSTANCE         *Instance\r
788   )\r
789 {\r
790   EFI_STATUS                     Status;\r
791   EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
792   VENDOR_DEVICE_PATH             VendorDeviceNode;\r
793   EFI_SERVICE_BINDING_PROTOCOL   *MnpSb;\r
794   CHAR16                         *MacString;\r
795   CHAR16                         MenuString[128];\r
796   CHAR16                         PortString[128];\r
797   CHAR16                         *OldMenuString;\r
798 \r
799   ConfigAccess = &Instance->HiiConfigAccessProtocol;\r
800   ConfigAccess->ExtractConfig = Ip4DeviceExtractConfig;\r
801   ConfigAccess->RouteConfig   = Ip4DeviceRouteConfig;\r
802   ConfigAccess->Callback      = Ip4FormCallback;\r
803 \r
804   //\r
805   // Construct device path node for EFI HII Config Access protocol,\r
806   // which consists of controller physical device path and one hardware\r
807   // vendor guid node.\r
808   //\r
809   ZeroMem (&VendorDeviceNode, sizeof (VENDOR_DEVICE_PATH));\r
810   VendorDeviceNode.Header.Type = HARDWARE_DEVICE_PATH;\r
811   VendorDeviceNode.Header.SubType = HW_VENDOR_DP;\r
812 \r
813   CopyGuid (&VendorDeviceNode.Guid, &gEfiNicIp4ConfigVariableGuid);\r
814 \r
815   SetDevicePathNodeLength (&VendorDeviceNode.Header, sizeof (VENDOR_DEVICE_PATH));\r
816   Instance->HiiVendorDevicePath = AppendDevicePathNode (\r
817                                     Instance->ParentDevicePath,\r
818                                     (EFI_DEVICE_PATH_PROTOCOL *) &VendorDeviceNode\r
819                                     );\r
820 \r
821   Instance->ChildHandle = NULL;\r
822   //\r
823   // Install Device Path Protocol and Config Access protocol on new handle\r
824   //\r
825   Status = gBS->InstallMultipleProtocolInterfaces (\r
826                   &Instance->ChildHandle,\r
827                   &gEfiDevicePathProtocolGuid,\r
828                   Instance->HiiVendorDevicePath,\r
829                   &gEfiHiiConfigAccessProtocolGuid,\r
830                   ConfigAccess,\r
831                   NULL\r
832                   );\r
833   if (!EFI_ERROR (Status)) {\r
834     //\r
835     // Open the Parent Handle for the child\r
836     //\r
837     Status = gBS->OpenProtocol (\r
838                     Instance->Controller,\r
839                     &gEfiManagedNetworkServiceBindingProtocolGuid,\r
840                     (VOID **) &MnpSb,\r
841                     Instance->Image,\r
842                     Instance->ChildHandle,\r
843                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
844                     );\r
845   }\r
846 \r
847   ASSERT_EFI_ERROR (Status);\r
848 \r
849   //\r
850   // Publish our HII data\r
851   //\r
852   Instance->RegisteredHandle = HiiAddPackages (\r
853                                  &mNicIp4ConfigNvDataGuid,\r
854                                  Instance->ChildHandle,\r
855                                  Ip4ConfigDxeStrings,\r
856                                  Ip4ConfigDxeBin,\r
857                                  NULL\r
858                                  );\r
859   if (Instance->RegisteredHandle == NULL) {\r
860     return EFI_OUT_OF_RESOURCES;\r
861   }\r
862 \r
863   //\r
864   // Append MAC string in the menu string and tile string\r
865   //\r
866   Status = NetLibGetMacString (Instance->Controller, Instance->Image, &MacString);\r
867   if (!EFI_ERROR (Status)) {\r
868     OldMenuString = HiiGetString (Instance->RegisteredHandle, STRING_TOKEN (STR_IP4_CONFIG_FORM_TITLE), NULL);\r
869     UnicodeSPrint (MenuString, 128, L"%s (MAC:%s)", OldMenuString, MacString);\r
870     HiiSetString (Instance->RegisteredHandle, STRING_TOKEN (STR_IP4_CONFIG_FORM_TITLE), MenuString, NULL);\r
871 \r
872     UnicodeSPrint (PortString, 128, L"MAC:%s", MacString);\r
873     HiiSetString (Instance->RegisteredHandle, STRING_TOKEN (STR_IP4_DEVICE_FORM_TITLE), PortString, NULL);\r
874     FreePool (MacString);\r
875   }\r
876 \r
877   return Status;\r
878 }\r
879 \r
880 /**\r
881   Uninstall HII Config Access protocol for network device and free resource.\r
882 \r
883   @param[in]  Instance            The IP4 Config instance.\r
884 \r
885   @retval EFI_SUCCESS             The HII Config Access protocol is uninstalled.\r
886   @retval Others                  Other errors as indicated.\r
887 **/\r
888 EFI_STATUS\r
889 Ip4ConfigDeviceUnload (\r
890   IN IP4_CONFIG_INSTANCE              *Instance\r
891   )\r
892 {\r
893   //\r
894   // Remove HII package list\r
895   //\r
896   HiiRemovePackages (Instance->RegisteredHandle);\r
897 \r
898   //\r
899   // Close the child handle\r
900   //\r
901   gBS->CloseProtocol (\r
902          Instance->Controller,\r
903          &gEfiManagedNetworkServiceBindingProtocolGuid,\r
904          Instance->Image,\r
905          Instance->ChildHandle\r
906          );\r
907 \r
908   //\r
909   // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL\r
910   //\r
911   gBS->UninstallMultipleProtocolInterfaces (\r
912          Instance->ChildHandle,\r
913          &gEfiDevicePathProtocolGuid,\r
914          Instance->HiiVendorDevicePath,\r
915          &gEfiHiiConfigAccessProtocolGuid,\r
916          &Instance->HiiConfigAccessProtocol,\r
917          NULL\r
918          );\r
919 \r
920   return EFI_SUCCESS;\r
921 }\r