]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigNv.c
Update HiiDataBase to fix the SCT hang issues by the invalid device path.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4ConfigDxe / Ip4ConfigNv.c
1 /** @file
2 Helper functions for configuring or getting the parameters relating to Ip4.
3
4 Copyright (c) 2009, Intel Corporation.<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "Ip4ConfigNv.h"
16
17 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 Ip4HexString[] = "0123456789ABCDEFabcdef";
18
19 UINTN mNumberOfIp4Devices = 0;
20
21 IP4_FORM_CALLBACK_INFO *mCallbackInfo = NULL;
22
23 LIST_ENTRY mIp4ConfigFormList = {
24 &mIp4ConfigFormList,
25 &mIp4ConfigFormList
26 };
27
28 HII_VENDOR_DEVICE_PATH mIp4ConifgHiiVendorDevicePath = {
29 {
30 {
31 HARDWARE_DEVICE_PATH,
32 HW_VENDOR_DP,
33 {
34 (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
35 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
36 }
37 },
38 //
39 // {6D3FD906-42B9-4220-9E63-9D8C972D58EE}
40 //
41 { 0x6d3fd906, 0x42b9, 0x4220, { 0x9e, 0x63, 0x9d, 0x8c, 0x97, 0x2d, 0x58, 0xee } }
42 },
43 {
44 END_DEVICE_PATH_TYPE,
45 END_ENTIRE_DEVICE_PATH_SUBTYPE,
46 {
47 (UINT8) (END_DEVICE_PATH_LENGTH),
48 (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
49 }
50 }
51 };
52
53 /**
54 Convert the mac address into a hexadecimal encoded "-" seperated string.
55
56 @param[in] Mac The mac address.
57 @param[in] Len Length in bytes of the mac address.
58 @param[out] Str The storage to return the mac string.
59
60 **/
61 VOID
62 Ip4MacAddrToStr (
63 IN EFI_MAC_ADDRESS *Mac,
64 IN UINT32 Len,
65 OUT CHAR16 *Str
66 )
67 {
68 UINT32 Index;
69
70 for (Index = 0; Index < Len; Index++) {
71 Str[3 * Index] = (CHAR16) Ip4HexString[(Mac->Addr[Index] >> 4) & 0x0F];
72 Str[3 * Index + 1] = (CHAR16) Ip4HexString[Mac->Addr[Index] & 0x0F];
73 Str[3 * Index + 2] = L'-';
74 }
75
76 Str[3 * Index - 1] = L'\0';
77 }
78
79 /**
80 Calculate the prefix length of the IPv4 subnet mask.
81
82 @param[in] SubnetMask The IPv4 subnet mask.
83
84 @return The prefix length of the subnet mask.
85 @retval 0 Other errors as indicated.
86 **/
87 UINT8
88 GetSubnetMaskPrefixLength (
89 IN EFI_IPv4_ADDRESS *SubnetMask
90 )
91 {
92 UINT8 Len;
93 UINT32 ReverseMask;
94
95 //
96 // The SubnetMask is in network byte order.
97 //
98 ReverseMask = (SubnetMask->Addr[0] << 24) | (SubnetMask->Addr[1] << 16) | (SubnetMask->Addr[2] << 8) | (SubnetMask->Addr[3]);
99
100 //
101 // Reverse it.
102 //
103 ReverseMask = ~ReverseMask;
104
105 if ((ReverseMask & (ReverseMask + 1)) != 0) {
106 return 0;
107 }
108
109 Len = 0;
110
111 while (ReverseMask != 0) {
112 ReverseMask = ReverseMask >> 1;
113 Len++;
114 }
115
116 return (UINT8) (32 - Len);
117 }
118
119 /**
120 Convert the decimal dotted IPv4 address into the binary IPv4 address.
121
122 @param[in] Str The UNICODE string.
123 @param[out] Ip The storage to return the ASCII string.
124
125 @retval EFI_SUCCESS The binary IP address is returned in Ip.
126 @retval EFI_INVALID_PARAMETER The IP string is malformatted.
127 **/
128 EFI_STATUS
129 Ip4AsciiStrToIp (
130 IN CHAR8 *Str,
131 OUT EFI_IPv4_ADDRESS *Ip
132 )
133 {
134 UINTN Index;
135 UINTN Number;
136
137 Index = 0;
138
139 while (*Str != 0) {
140
141 if (Index > 3) {
142 return EFI_INVALID_PARAMETER;
143 }
144
145 Number = 0;
146 while (NET_IS_DIGIT (*Str)) {
147 Number = Number * 10 + (*Str - '0');
148 Str++;
149 }
150
151 if (Number > 0xFF) {
152 return EFI_INVALID_PARAMETER;
153 }
154
155 Ip->Addr[Index] = (UINT8) Number;
156
157 if ((*Str != '\0') && (*Str != '.')) {
158 //
159 // The current character should be either the NULL terminator or
160 // the dot delimiter.
161 //
162 return EFI_INVALID_PARAMETER;
163 }
164
165 if (*Str == '.') {
166 //
167 // Skip the delimiter.
168 //
169 Str++;
170 }
171
172 Index++;
173 }
174
175 if (Index != 4) {
176 return EFI_INVALID_PARAMETER;
177 }
178
179 return EFI_SUCCESS;
180 }
181
182 /**
183 Convert the IPv4 address into a dotted string.
184
185 @param[in] Ip The IPv4 address.
186 @param[out] Str The dotted IP string.
187 **/
188 VOID
189 Ip4ConfigIpToStr (
190 IN EFI_IPv4_ADDRESS *Ip,
191 OUT CHAR16 *Str
192 )
193 {
194 UnicodeSPrint (Str, 2 * IP4_STR_MAX_SIZE, L"%d.%d.%d.%d", Ip->Addr[0], Ip->Addr[1], Ip->Addr[2], Ip->Addr[3]);
195 }
196
197
198 /**
199 Convert the network configuration data into the IFR data.
200
201 @param[in] ConfigFormEntry The IP4 configuration form entry.
202 @param[out] IfrNvData The IFR nv data.
203 **/
204 VOID
205 Ip4ConfigConvertDeviceConfigDataToIfrNvData (
206 IN IP4_CONFIG_INSTANCE *Ip4ConfigInstance,
207 OUT IP4_CONFIG_IFR_NVDATA *IfrFormNvData
208 )
209 {
210 EFI_STATUS Status;
211 NIC_IP4_CONFIG_INFO *NicConfig;
212 UINTN ConfigLen;
213
214 IfrFormNvData->DhcpEnable = 1;
215
216 ConfigLen = sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * 2;
217 NicConfig = AllocateZeroPool (ConfigLen);
218 ASSERT (NicConfig != NULL);
219 Status = EfiNicIp4ConfigGetInfo (Ip4ConfigInstance, &ConfigLen, NicConfig);
220 if (!EFI_ERROR (Status)) {
221 if (NicConfig->Source == IP4_CONFIG_SOURCE_DHCP) {
222 IfrFormNvData->DhcpEnable = 1;
223 } else {
224 IfrFormNvData->DhcpEnable = 0;
225 Ip4ConfigIpToStr (&NicConfig->Ip4Info.StationAddress, IfrFormNvData->StationAddress);
226 Ip4ConfigIpToStr (&NicConfig->Ip4Info.SubnetMask, IfrFormNvData->SubnetMask);
227 Ip4ConfigIpToStr (&NicConfig->Ip4Info.RouteTable[1].GatewayAddress, IfrFormNvData->GatewayAddress);
228 }
229 }
230 FreePool (NicConfig);
231 }
232
233 /**
234 Get the IP4 configuration form entry by the index of the goto opcode actived.
235
236 @param[in] Index The 0-based index of the goto opcode actived.
237
238 @return The IP4 configuration form entry found.
239 **/
240 IP4CONFIG_FORM_ENTRY *
241 Ip4GetConfigFormEntryByIndex (
242 IN UINT32 Index
243 )
244 {
245 UINT32 CurrentIndex;
246 LIST_ENTRY *Entry;
247 IP4CONFIG_FORM_ENTRY *ConfigFormEntry;
248
249 CurrentIndex = 0;
250 ConfigFormEntry = NULL;
251
252 NET_LIST_FOR_EACH (Entry, &mIp4ConfigFormList) {
253 if (CurrentIndex == Index) {
254 ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, IP4CONFIG_FORM_ENTRY, Link);
255 break;
256 }
257
258 CurrentIndex++;
259 }
260
261 return ConfigFormEntry;
262 }
263
264 /**
265 This function allows the caller to request the current
266 configuration for one or more named elements. The resulting
267 string is in <ConfigAltResp> format. Any and all alternative
268 configuration strings shall also be appended to the end of the
269 current configuration string. If they are, they must appear
270 after the current configuration. They must contain the same
271 routing (GUID, NAME, PATH) as the current configuration string.
272 They must have an additional description indicating the type of
273 alternative configuration the string represents,
274 "ALTCFG=<StringToken>". That <StringToken> (when
275 converted from Hex UNICODE to binary) is a reference to a
276 string in the associated string pack.
277
278 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
279 @param[in] Request A null-terminated Unicode string in
280 <ConfigRequest> format. Note that this
281 includes the routing information as well as
282 the configurable name / value pairs. It is
283 invalid for this string to be in
284 <MultiConfigRequest> format.
285 @param[out] Progress On return, points to a character in the
286 Request string. Points to the string's null
287 terminator if request was successful. Points
288 to the most recent "&" before the first
289 failing name / value pair (or the beginning
290 of the string if the failure is in the first
291 name / value pair) if the request was not
292 successful.
293 @param[out] Results A null-terminated Unicode string in
294 <ConfigAltResp> format which has all values
295 filled in for the names in the Request string.
296 String to be allocated by the called function.
297
298 @retval EFI_SUCCESS The Results string is filled with the
299 values corresponding to all requested
300 names.
301 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
302 parts of the results that must be
303 stored awaiting possible future
304 protocols.
305 @retval EFI_INVALID_PARAMETER For example, passing in a NULL
306 for the Request parameter
307 would result in this type of
308 error. In this case, the
309 Progress parameter would be
310 set to NULL.
311 @retval EFI_NOT_FOUND Routing data doesn't match any
312 known driver. Progress set to the
313 first character in the routing header.
314 Note: There is no requirement that the
315 driver validate the routing data. It
316 must skip the <ConfigHdr> in order to
317 process the names.
318 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set
319 to most recent & before the
320 error or the beginning of the
321 string.
322 @retval EFI_INVALID_PARAMETER Unknown name. Progress points
323 to the & before the name in
324 question.Currently not implemented.
325 **/
326 EFI_STATUS
327 EFIAPI
328 Ip4DeviceExtractConfig (
329 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
330 IN CONST EFI_STRING Request,
331 OUT EFI_STRING *Progress,
332 OUT EFI_STRING *Results
333 )
334 {
335 EFI_STATUS Status;
336 UINTN ConfigLen;
337 NIC_IP4_CONFIG_INFO *IfrDeviceNvData;
338 IP4_FORM_CALLBACK_INFO *Private;
339 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
340 IP4_CONFIG_INSTANCE *Ip4ConfigInstance;
341
342 if (Request == NULL) {
343 return EFI_INVALID_PARAMETER;
344 }
345
346 *Progress = Request;
347
348 //
349 // Check Request data in <ConfigHdr>.
350 //
351 if (!HiiIsConfigHdrMatch (Request, &gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE)) {
352 return EFI_NOT_FOUND;
353 }
354
355 Private = IP4CONFIG_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);
356 Ip4ConfigInstance = IP4_CONFIG_INSTANCE_FROM_IP4FORM_CALLBACK_INFO (Private);
357
358 IfrDeviceNvData = AllocateZeroPool (NIC_ITEM_CONFIG_SIZE);
359 if (IfrDeviceNvData == NULL) {
360 return EFI_OUT_OF_RESOURCES;
361 }
362
363 Status = EfiNicIp4ConfigGetInfo (Ip4ConfigInstance, &ConfigLen, IfrDeviceNvData);
364 if (EFI_ERROR (Status)) {
365 FreePool (IfrDeviceNvData);
366 return EFI_NOT_FOUND;
367 }
368
369 //
370 // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
371 //
372 HiiConfigRouting = Private->ConfigRouting;
373 Status = HiiConfigRouting->BlockToConfig (
374 HiiConfigRouting,
375 Request,
376 (UINT8 *) IfrDeviceNvData,
377 NIC_ITEM_CONFIG_SIZE,
378 Results,
379 Progress
380 );
381
382 FreePool (IfrDeviceNvData);
383
384 return Status;
385 }
386
387 /**
388 This function applies changes in a driver's configuration.
389 Input is a Configuration, which has the routing data for this
390 driver followed by name / value configuration pairs. The driver
391 must apply those pairs to its configurable storage. If the
392 driver's configuration is stored in a linear block of data
393 and the driver's name / value pairs are in <BlockConfig>
394 format, it may use the ConfigToBlock helper function (above) to
395 simplify the job. Currently not implemented.
396
397 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
398 @param[in] Configuration A null-terminated Unicode string in
399 <ConfigString> format.
400 @param[out] Progress A pointer to a string filled in with the
401 offset of the most recent '&' before the
402 first failing name / value pair (or the
403 beginn ing of the string if the failure
404 is in the first name / value pair) or
405 the terminating NULL if all was
406 successful.
407
408 @retval EFI_SUCCESS The results have been distributed or are
409 awaiting distribution.
410 @retval EFI_OUT_OF_MEMORY Not enough memory to store the
411 parts of the results that must be
412 stored awaiting possible future
413 protocols.
414 @retval EFI_INVALID_PARAMETERS Passing in a NULL for the
415 Results parameter would result
416 in this type of error.
417 @retval EFI_NOT_FOUND Target for the specified routing data
418 was not found.
419 **/
420 EFI_STATUS
421 EFIAPI
422 Ip4DeviceRouteConfig (
423 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
424 IN CONST EFI_STRING Configuration,
425 OUT EFI_STRING *Progress
426 )
427 {
428 EFI_STATUS Status;
429 UINTN BufferSize;
430 NIC_IP4_CONFIG_INFO *IfrDeviceNvData;
431 NIC_IP4_CONFIG_INFO *NicInfo;
432 IP4_FORM_CALLBACK_INFO *Private;
433 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
434 IP4_CONFIG_INSTANCE *Ip4ConfigInstance;
435 EFI_MAC_ADDRESS ZeroMac;
436
437 if (Configuration == NULL) {
438 return EFI_INVALID_PARAMETER;
439 }
440
441 *Progress = Configuration;
442
443 //
444 // Check Routing data in <ConfigHdr>.
445 //
446 if (!HiiIsConfigHdrMatch (Configuration, &gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE)) {
447 return EFI_NOT_FOUND;
448 }
449
450 Private = IP4CONFIG_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);
451 Ip4ConfigInstance = IP4_CONFIG_INSTANCE_FROM_IP4FORM_CALLBACK_INFO (Private);
452
453 IfrDeviceNvData = AllocateZeroPool (NIC_ITEM_CONFIG_SIZE);
454 if (IfrDeviceNvData == NULL) {
455 return EFI_OUT_OF_RESOURCES;
456 }
457
458 //
459 // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
460 //
461 HiiConfigRouting = Private->ConfigRouting;
462 BufferSize = NIC_ITEM_CONFIG_SIZE;
463 Status = HiiConfigRouting->ConfigToBlock (
464 HiiConfigRouting,
465 Configuration,
466 (UINT8 *) IfrDeviceNvData,
467 &BufferSize,
468 Progress
469 );
470 if (!EFI_ERROR (Status)) {
471 ZeroMem (&ZeroMac, sizeof (EFI_MAC_ADDRESS));
472 if (CompareMem (&IfrDeviceNvData->NicAddr.MacAddr, &ZeroMac, IfrDeviceNvData->NicAddr.Len) != 0) {
473 BufferSize = sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * IfrDeviceNvData->Ip4Info.RouteTableSize;
474 NicInfo = AllocateCopyPool (BufferSize, IfrDeviceNvData);
475 Status = EfiNicIp4ConfigSetInfo (Ip4ConfigInstance, NicInfo, TRUE);
476 } else {
477 Status = EfiNicIp4ConfigSetInfo (Ip4ConfigInstance, NULL, TRUE);
478 }
479 }
480
481 FreePool (IfrDeviceNvData);
482 return Status;
483
484 }
485
486 /**
487 This function allows the caller to request the current
488 configuration for one or more named elements. The resulting
489 string is in <ConfigAltResp> format. Any and all alternative
490 configuration strings shall also be appended to the end of the
491 current configuration string. If they are, they must appear
492 after the current configuration. They must contain the same
493 routing (GUID, NAME, PATH) as the current configuration string.
494 They must have an additional description indicating the type of
495 alternative configuration the string represents,
496 "ALTCFG=<StringToken>". That <StringToken> (when
497 converted from Hex UNICODE to binary) is a reference to a
498 string in the associated string pack.
499
500 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
501 @param[in] Request A null-terminated Unicode string in
502 <ConfigRequest> format. Note that this
503 includes the routing information as well as
504 the configurable name / value pairs. It is
505 invalid for this string to be in
506 <MultiConfigRequest> format.
507 @param[out] Progress On return, points to a character in the
508 Request string. Points to the string's null
509 terminator if request was successful. Points
510 to the most recent "&" before the first
511 failing name / value pair (or the beginning
512 of the string if the failure is in the first
513 name / value pair) if the request was not
514 successful.
515 @param[out] Results A null-terminated Unicode string in
516 <ConfigAltResp> format which has all values
517 filled in for the names in the Request string.
518 String to be allocated by the called function.
519
520 @retval EFI_SUCCESS The Results string is filled with the
521 values corresponding to all requested
522 names.
523 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
524 parts of the results that must be
525 stored awaiting possible future
526 protocols.
527 @retval EFI_INVALID_PARAMETER For example, passing in a NULL
528 for the Request parameter
529 would result in this type of
530 error. In this case, the
531 Progress parameter would be
532 set to NULL.
533 @retval EFI_NOT_FOUND Routing data doesn't match any
534 known driver. Progress set to the
535 first character in the routing header.
536 Note: There is no requirement that the
537 driver validate the routing data. It
538 must skip the <ConfigHdr> in order to
539 process the names.
540 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set
541 to most recent & before the
542 error or the beginning of the
543 string.
544 @retval EFI_INVALID_PARAMETER Unknown name. Progress points
545 to the & before the name in
546 question.Currently not implemented.
547 **/
548 EFI_STATUS
549 EFIAPI
550 Ip4FormExtractConfig (
551 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
552 IN CONST EFI_STRING Request,
553 OUT EFI_STRING *Progress,
554 OUT EFI_STRING *Results
555 )
556 {
557 if (Request == NULL || Progress == NULL || Results == NULL) {
558 return EFI_INVALID_PARAMETER;
559 }
560 *Progress = Request;
561 return EFI_NOT_FOUND;
562 }
563
564 /**
565 This function applies changes in a driver's configuration.
566 Input is a Configuration, which has the routing data for this
567 driver followed by name / value configuration pairs. The driver
568 must apply those pairs to its configurable storage. If the
569 driver's configuration is stored in a linear block of data
570 and the driver's name / value pairs are in <BlockConfig>
571 format, it may use the ConfigToBlock helper function (above) to
572 simplify the job. Currently not implemented.
573
574 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
575 @param[in] Configuration A null-terminated Unicode string in
576 <ConfigString> format.
577 @param[out] Progress A pointer to a string filled in with the
578 offset of the most recent '&' before the
579 first failing name / value pair (or the
580 beginn ing of the string if the failure
581 is in the first name / value pair) or
582 the terminating NULL if all was
583 successful.
584
585 @retval EFI_SUCCESS The results have been distributed or are
586 awaiting distribution.
587 @retval EFI_OUT_OF_MEMORY Not enough memory to store the
588 parts of the results that must be
589 stored awaiting possible future
590 protocols.
591 @retval EFI_INVALID_PARAMETERS Passing in a NULL for the
592 Results parameter would result
593 in this type of error.
594 @retval EFI_NOT_FOUND Target for the specified routing data
595 was not found.
596 **/
597 EFI_STATUS
598 EFIAPI
599 Ip4FormRouteConfig (
600 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
601 IN CONST EFI_STRING Configuration,
602 OUT EFI_STRING *Progress
603 )
604 {
605 if (Configuration == NULL || Progress == NULL) {
606 return EFI_INVALID_PARAMETER;
607 }
608
609 *Progress = Configuration;
610 if (!HiiIsConfigHdrMatch (Configuration, &gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE)) {
611 return EFI_NOT_FOUND;
612 }
613
614 *Progress = Configuration + StrLen (Configuration);
615 return EFI_SUCCESS;
616 }
617
618 /**
619 This function is called to provide results data to the driver.
620 This data consists of a unique key that is used to identify
621 which data is either being passed back or being asked for.
622
623 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
624 @param[in] Action Specifies the type of action taken by the browser.
625 @param[in] QuestionId A unique value which is sent to the original
626 exporting driver so that it can identify the type
627 of data to expect. The format of the data tends to
628 vary based on the opcode that enerated the callback.
629 @param[in] Type The type of value for the question.
630 @param[in] Value A pointer to the data being sent to the original
631 exporting driver.
632 @param[out] ActionRequest On return, points to the action requested by the
633 callback function.
634
635 @retval EFI_SUCCESS The callback successfully handled the action.
636 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
637 variable and its data.
638 @retval EFI_DEVICE_ERROR The variable could not be saved.
639 @retval EFI_UNSUPPORTED The specified Action is not supported by the
640 callback.Currently not implemented.
641 @retval EFI_INVALID_PARAMETERS Passing in wrong parameter.
642 @retval Others Other errors as indicated.
643 **/
644 EFI_STATUS
645 EFIAPI
646 Ip4FormCallback (
647 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
648 IN EFI_BROWSER_ACTION Action,
649 IN EFI_QUESTION_ID QuestionId,
650 IN UINT8 Type,
651 IN EFI_IFR_TYPE_VALUE *Value,
652 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
653 )
654 {
655 IP4_CONFIG_INSTANCE *Ip4ConfigInstance;
656 IP4_FORM_CALLBACK_INFO *Private;
657 CHAR8 Ip4String[IP4_STR_MAX_SIZE];
658 CHAR16 PortString[128];
659 EFI_STRING_ID DeviceFormTitleToken;
660 IP4_CONFIG_IFR_NVDATA *IfrFormNvData;
661 IP4CONFIG_FORM_ENTRY *ConfigFormEntry;
662 EFI_IP_ADDRESS HostIp;
663 EFI_IP_ADDRESS SubnetMask;
664 EFI_IP_ADDRESS Gateway;
665 EFI_STATUS Status;
666 EFI_INPUT_KEY Key;
667 NIC_IP4_CONFIG_INFO *NicInfo;
668 EFI_IP_ADDRESS Ip;
669
670 ConfigFormEntry = NULL;
671
672 Private = IP4CONFIG_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);
673
674 IfrFormNvData = AllocateZeroPool (sizeof (IP4_CONFIG_IFR_NVDATA));
675 if (IfrFormNvData == NULL) {
676 return EFI_OUT_OF_RESOURCES;
677 }
678
679 //
680 // Retrive uncommitted data from Browser
681 //
682 if (!HiiGetBrowserData (&gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE, sizeof (IP4_CONFIG_IFR_NVDATA), (UINT8 *) IfrFormNvData)) {
683 FreePool (IfrFormNvData);
684 return EFI_NOT_FOUND;
685 }
686
687 Status = EFI_SUCCESS;
688
689 switch (QuestionId) {
690
691 case KEY_DHCP_ENABLE:
692 if (IfrFormNvData->DhcpEnable == 0) {
693 Private->Current->SessionConfigData.Enabled = FALSE;
694 } else {
695 Private->Current->SessionConfigData.Enabled = TRUE;
696 }
697
698 break;
699
700 case KEY_LOCAL_IP:
701 UnicodeStrToAsciiStr (IfrFormNvData->StationAddress, Ip4String);
702 Status = Ip4AsciiStrToIp (Ip4String, &HostIp.v4);
703 if (EFI_ERROR (Status) || !Ip4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {
704 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);
705 Status = EFI_INVALID_PARAMETER;
706 } else {
707 CopyMem (&Private->Current->SessionConfigData.LocalIp, &HostIp.v4, sizeof (HostIp.v4));
708 }
709
710 break;
711
712 case KEY_SUBNET_MASK:
713 UnicodeStrToAsciiStr (IfrFormNvData->SubnetMask, Ip4String);
714 Status = Ip4AsciiStrToIp (Ip4String, &SubnetMask.v4);
715 if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (GetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
716 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid SubnetMask!", NULL);
717 Status = EFI_INVALID_PARAMETER;
718 } else {
719 CopyMem (&Private->Current->SessionConfigData.SubnetMask, &SubnetMask.v4, sizeof (SubnetMask.v4));
720 }
721
722 break;
723
724 case KEY_GATE_WAY:
725 UnicodeStrToAsciiStr (IfrFormNvData->GatewayAddress, Ip4String);
726 Status = Ip4AsciiStrToIp (Ip4String, &Gateway.v4);
727 if (EFI_ERROR (Status) || ((Gateway.Addr[0] != 0) && !Ip4IsUnicast (NTOHL (Gateway.Addr[0]), 0))) {
728 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Gateway!", NULL);
729 Status = EFI_INVALID_PARAMETER;
730 } else {
731 CopyMem (&Private->Current->SessionConfigData.Gateway, &Gateway.v4, sizeof (Gateway.v4));
732 }
733
734 break;
735
736 case KEY_SAVE_CHANGES:
737 Ip4ConfigInstance = Private->Current->Ip4ConfigInstance;
738 NicInfo = AllocateZeroPool (sizeof (NIC_IP4_CONFIG_INFO) + 2 * sizeof (EFI_IP4_ROUTE_TABLE));
739 NicInfo->Ip4Info.RouteTable = (EFI_IP4_ROUTE_TABLE *) (NicInfo + 1);
740
741 if (!Private->Current->SessionConfigData.Enabled) {
742 CopyMem (&HostIp.v4, &Private->Current->SessionConfigData.LocalIp, sizeof (HostIp.v4));
743 CopyMem (&SubnetMask.v4, &Private->Current->SessionConfigData.SubnetMask, sizeof (SubnetMask.v4));
744 CopyMem (&Gateway.v4, &Private->Current->SessionConfigData.Gateway, sizeof (Gateway.v4));
745
746 if ((Gateway.Addr[0] != 0)) {
747 if (SubnetMask.Addr[0] == 0) {
748 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Gateway address is set but subnet mask is zero.", NULL);
749 Status = EFI_INVALID_PARAMETER;
750 break;
751 } else if (!IP4_NET_EQUAL (HostIp.Addr[0], Gateway.Addr[0], SubnetMask.Addr[0])) {
752 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Local IP and Gateway are not in the same subnet.", NULL);
753 Status = EFI_INVALID_PARAMETER;
754 break;
755 }
756 }
757
758 NicInfo->Source = IP4_CONFIG_SOURCE_STATIC;
759 NicInfo->Ip4Info.RouteTableSize = 2;
760
761 CopyMem (&NicInfo->Ip4Info.StationAddress, &HostIp.v4, sizeof (EFI_IPv4_ADDRESS));
762 CopyMem (&NicInfo->Ip4Info.SubnetMask, &SubnetMask.v4, sizeof (EFI_IPv4_ADDRESS));
763
764 Ip.Addr[0] = HostIp.Addr[0] & SubnetMask.Addr[0];
765
766 CopyMem (&NicInfo->Ip4Info.RouteTable[0].SubnetAddress, &Ip.v4, sizeof (EFI_IPv4_ADDRESS));
767 CopyMem (&NicInfo->Ip4Info.RouteTable[0].SubnetMask, &SubnetMask.v4, sizeof (EFI_IPv4_ADDRESS));
768 CopyMem (&NicInfo->Ip4Info.RouteTable[1].GatewayAddress, &Gateway.v4, sizeof (EFI_IPv4_ADDRESS));
769 } else {
770 NicInfo->Source = IP4_CONFIG_SOURCE_DHCP;
771 }
772
773 NicInfo->Perment = TRUE;
774 CopyMem (&NicInfo->NicAddr, &Ip4ConfigInstance->NicAddr, sizeof (NIC_ADDR));
775
776 EfiNicIp4ConfigSetInfo (Ip4ConfigInstance, NicInfo, TRUE);
777
778 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
779 break;
780
781 default:
782 if ((QuestionId >= KEY_DEVICE_ENTRY_BASE) && (QuestionId < (mNumberOfIp4Devices + KEY_DEVICE_ENTRY_BASE))) {
783 //
784 // In case goto the device configuration form, update the device form title.
785 //
786 ConfigFormEntry = Ip4GetConfigFormEntryByIndex ((UINT32) (QuestionId - KEY_DEVICE_ENTRY_BASE));
787 ASSERT (ConfigFormEntry != NULL);
788
789 Ip4ConfigInstance = ConfigFormEntry->Ip4ConfigInstance;
790
791 UnicodeSPrint (PortString, (UINTN) 128, L"Port %s", ConfigFormEntry->MacString);
792 DeviceFormTitleToken = (EFI_STRING_ID) STR_IP4_DEVICE_FORM_TITLE;
793 HiiSetString (Private->RegisteredHandle, DeviceFormTitleToken, PortString, NULL);
794
795 Ip4ConfigConvertDeviceConfigDataToIfrNvData (Ip4ConfigInstance, IfrFormNvData);
796
797 Private->Current = ConfigFormEntry;
798 }
799
800 break;
801 }
802
803 if (!EFI_ERROR (Status)) {
804
805 //
806 // Pass changed uncommitted data back to Form Browser
807 //
808 HiiSetBrowserData (&gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE, sizeof (IP4_CONFIG_IFR_NVDATA), (UINT8 *) IfrFormNvData, NULL);
809 }
810
811 FreePool (IfrFormNvData);
812 return Status;
813 }
814
815 /**
816 Install HII Config Access protocol for network device and allocate resource.
817
818 @param[in] Instance The IP4 Config instance.
819
820 @retval EFI_SUCCESS The HII Config Access protocol is installed.
821 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
822 @retval Others Other errors as indicated.
823 **/
824 EFI_STATUS
825 Ip4ConfigDeviceInit (
826 IN IP4_CONFIG_INSTANCE *Instance
827 )
828 {
829 EFI_STATUS Status;
830 EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
831 IP4_FORM_CALLBACK_INFO *CallbackInfo;
832
833 Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **)&HiiDatabase);
834 if (EFI_ERROR (Status)) {
835 return Status;
836 }
837
838 CallbackInfo = &Instance->Ip4FormCallbackInfo;
839
840 CallbackInfo->Signature = IP4CONFIG_FORM_CALLBACK_INFO_SIGNATURE;
841 CallbackInfo->HiiDatabase = HiiDatabase;
842
843 CallbackInfo->ConfigAccess.ExtractConfig = Ip4DeviceExtractConfig;
844 CallbackInfo->ConfigAccess.RouteConfig = Ip4DeviceRouteConfig;
845 CallbackInfo->ConfigAccess.Callback = NULL;
846
847 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **)&CallbackInfo->ConfigRouting);
848 if (EFI_ERROR (Status)) {
849 return Status;
850 }
851
852 CallbackInfo->DriverHandle = Instance->Controller;
853 //
854 // Install Device Path Protocol and Config Access protocol to driver handle
855 //
856 Status = gBS->InstallMultipleProtocolInterfaces (
857 &CallbackInfo->DriverHandle,
858 &gEfiHiiConfigAccessProtocolGuid,
859 &CallbackInfo->ConfigAccess,
860 NULL
861 );
862 ASSERT_EFI_ERROR (Status);
863
864 return Status;
865 }
866
867 /**
868 Uninstall HII Config Access protocol for network device and free resource.
869
870 @param[in] Instance The IP4 Config instance.
871
872 @retval EFI_SUCCESS The HII Config Access protocol is uninstalled.
873 @retval Others Other errors as indicated.
874 **/
875 EFI_STATUS
876 Ip4ConfigDeviceUnload (
877 IN IP4_CONFIG_INSTANCE *Instance
878 )
879 {
880 IP4_FORM_CALLBACK_INFO *CallbackInfo;
881
882 CallbackInfo = &Instance->Ip4FormCallbackInfo;
883
884 Ip4ConfigUpdateForm (Instance, FALSE);
885
886 //
887 // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL
888 //
889 gBS->UninstallMultipleProtocolInterfaces (
890 CallbackInfo->DriverHandle,
891 &gEfiHiiConfigAccessProtocolGuid,
892 &CallbackInfo->ConfigAccess,
893 NULL
894 );
895
896 return EFI_SUCCESS;
897 }
898
899 /**
900 Unload the network configuration form, this includes: delete all the network
901 device configuration entries, uninstall the form callback protocol and
902 free the resources used.
903
904 @retval EFI_SUCCESS The network configuration form is unloaded.
905 **/
906 EFI_STATUS
907 Ip4ConfigFormUnload (
908 VOID
909 )
910 {
911 IP4CONFIG_FORM_ENTRY *ConfigFormEntry;
912
913 while (!IsListEmpty (&mIp4ConfigFormList)) {
914 //
915 // Uninstall the device forms as the network driver instance may fail to
916 // control the controller but still install the device configuration form.
917 // In such case, upon driver unloading, the driver instance's driverbinding.
918 // stop () won't be called, so we have to take this chance here to uninstall
919 // the device form.
920 //
921 ConfigFormEntry = NET_LIST_USER_STRUCT (mIp4ConfigFormList.ForwardLink, IP4CONFIG_FORM_ENTRY, Link);
922 Ip4ConfigUpdateForm (ConfigFormEntry->Ip4ConfigInstance, FALSE);
923 }
924
925 //
926 // Remove HII package list
927 //
928 mCallbackInfo->HiiDatabase->RemovePackageList (
929 mCallbackInfo->HiiDatabase,
930 mCallbackInfo->RegisteredHandle
931 );
932
933 //
934 // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL
935 //
936 gBS->UninstallMultipleProtocolInterfaces (
937 mCallbackInfo->DriverHandle,
938 &gEfiDevicePathProtocolGuid,
939 &mIp4ConifgHiiVendorDevicePath,
940 &gEfiHiiConfigAccessProtocolGuid,
941 &mCallbackInfo->ConfigAccess,
942 NULL
943 );
944
945 FreePool (mCallbackInfo);
946
947 return EFI_SUCCESS;
948 }
949
950 /**
951 Updates the network configuration form to add/delete an entry for the network
952 device specified by the Instance.
953
954 @param[in] Instance The IP4 Config instance.
955 @param[in] AddForm Whether to add or delete a form entry.
956
957 @retval EFI_SUCCESS The network configuration form is updated.
958 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
959 @retval Others Other errors as indicated.
960 **/
961 EFI_STATUS
962 Ip4ConfigUpdateForm (
963 IN IP4_CONFIG_INSTANCE *Instance,
964 IN BOOLEAN AddForm
965 )
966 {
967 LIST_ENTRY *Entry;
968 IP4CONFIG_FORM_ENTRY *ConfigFormEntry;
969 BOOLEAN EntryExisted;
970 EFI_STATUS Status;
971 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
972 CHAR16 PortString[128];
973 UINT16 FormIndex;
974 VOID *StartOpCodeHandle;
975 VOID *EndOpCodeHandle;
976 EFI_IFR_GUID_LABEL *StartLabel;
977 EFI_IFR_GUID_LABEL *EndLabel;
978
979 ConfigFormEntry = NULL;
980 EntryExisted = FALSE;
981
982 NET_LIST_FOR_EACH (Entry, &mIp4ConfigFormList) {
983 ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, IP4CONFIG_FORM_ENTRY, Link);
984
985 if (ConfigFormEntry->Controller == Instance->Controller) {
986 EntryExisted = TRUE;
987 break;
988 }
989 }
990
991 if (AddForm) {
992 if (EntryExisted) {
993 return EFI_SUCCESS;
994 } else {
995 //
996 // Add a new form.
997 //
998 ConfigFormEntry = (IP4CONFIG_FORM_ENTRY *) AllocateZeroPool (sizeof (IP4CONFIG_FORM_ENTRY));
999 if (ConfigFormEntry == NULL) {
1000 return EFI_OUT_OF_RESOURCES;
1001 }
1002
1003 ConfigFormEntry->Ip4ConfigInstance = Instance;
1004 InitializeListHead (&ConfigFormEntry->Link);
1005 ConfigFormEntry->Controller = Instance->Controller;
1006
1007 //
1008 // Get the simple network protocol and convert the MAC address into
1009 // the formatted string.
1010 //
1011 Status = gBS->HandleProtocol (
1012 Instance->Controller,
1013 &gEfiSimpleNetworkProtocolGuid,
1014 (VOID **)&Snp
1015 );
1016 ASSERT (Status == EFI_SUCCESS);
1017
1018 Ip4MacAddrToStr (&Snp->Mode->PermanentAddress, Snp->Mode->HwAddressSize, ConfigFormEntry->MacString);
1019
1020 //
1021 // Compose the Port string and create a new EFI_STRING_ID.
1022 //
1023 UnicodeSPrint (PortString, 128, L"%s %s", Instance->NicName, ConfigFormEntry->MacString);
1024 ConfigFormEntry->PortTitleToken = HiiSetString (mCallbackInfo->RegisteredHandle, 0, PortString, NULL);
1025
1026 //
1027 // Compose the help string of this port and create a new EFI_STRING_ID.
1028 //
1029 UnicodeSPrint (PortString, 128, L"Set the network parameters on eth%d %s", 0, ConfigFormEntry->MacString);
1030 ConfigFormEntry->PortTitleHelpToken = HiiSetString (mCallbackInfo->RegisteredHandle, 0, PortString, NULL);
1031
1032 InsertTailList (&mIp4ConfigFormList, &ConfigFormEntry->Link);
1033 mNumberOfIp4Devices++;
1034 }
1035 } else {
1036 ASSERT (EntryExisted);
1037
1038 mNumberOfIp4Devices--;
1039 RemoveEntryList (&ConfigFormEntry->Link);
1040 gBS->FreePool (ConfigFormEntry);
1041 }
1042
1043 //
1044 // Init OpCode Handle
1045 //
1046 StartOpCodeHandle = HiiAllocateOpCodeHandle ();
1047 ASSERT (StartOpCodeHandle != NULL);
1048
1049 EndOpCodeHandle = HiiAllocateOpCodeHandle ();
1050 ASSERT (EndOpCodeHandle != NULL);
1051
1052 //
1053 // Create Hii Extend Label OpCode as the start opcode
1054 //
1055 StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1056 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1057 StartLabel->Number = DEVICE_ENTRY_LABEL;
1058
1059 //
1060 // Create Hii Extend Label OpCode as the end opcode
1061 //
1062 EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1063 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1064 EndLabel->Number = LABEL_END;
1065
1066 FormIndex = 0;
1067
1068 FormIndex = 0;
1069 NET_LIST_FOR_EACH (Entry, &mIp4ConfigFormList) {
1070 ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, IP4CONFIG_FORM_ENTRY, Link);
1071
1072 HiiCreateGotoOpCode (
1073 StartOpCodeHandle, // Container for dynamic created opcodes
1074 FORMID_DEVICE_FORM, // Target Form ID
1075 ConfigFormEntry->PortTitleToken, // Prompt text
1076 ConfigFormEntry->PortTitleHelpToken, // Help text
1077 EFI_IFR_FLAG_CALLBACK, // Question flag
1078 (UINT16)(KEY_DEVICE_ENTRY_BASE + FormIndex) // Question ID
1079 );
1080
1081 FormIndex++;
1082 }
1083
1084 HiiUpdateForm (
1085 mCallbackInfo->RegisteredHandle,
1086 &gEfiNicIp4ConfigVariableGuid,
1087 FORMID_MAIN_FORM,
1088 StartOpCodeHandle, // Label DEVICE_ENTRY_LABEL
1089 EndOpCodeHandle // LABEL_END
1090 );
1091
1092 HiiFreeOpCodeHandle (StartOpCodeHandle);
1093 HiiFreeOpCodeHandle (EndOpCodeHandle);
1094
1095 return EFI_SUCCESS;
1096 }
1097
1098 /**
1099 Initialize the network configuration form, this includes: delete all the network
1100 device configuration entries, install the form callback protocol and
1101 allocate the resources used.
1102
1103 @retval EFI_SUCCESS The network configuration form is unloaded.
1104 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1105 **/
1106 EFI_STATUS
1107 Ip4ConfigFormInit (
1108 VOID
1109 )
1110 {
1111 EFI_STATUS Status;
1112 EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
1113 IP4_FORM_CALLBACK_INFO *CallbackInfo;
1114
1115 Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **)&HiiDatabase);
1116 if (EFI_ERROR (Status)) {
1117 return Status;
1118 }
1119
1120 CallbackInfo = (IP4_FORM_CALLBACK_INFO *) AllocateZeroPool (sizeof (IP4_FORM_CALLBACK_INFO));
1121 if (CallbackInfo == NULL) {
1122 return EFI_OUT_OF_RESOURCES;
1123 }
1124
1125 CallbackInfo->Signature = IP4CONFIG_FORM_CALLBACK_INFO_SIGNATURE;
1126 CallbackInfo->HiiDatabase = HiiDatabase;
1127
1128 CallbackInfo->ConfigAccess.ExtractConfig = Ip4FormExtractConfig;
1129 CallbackInfo->ConfigAccess.RouteConfig = Ip4FormRouteConfig;
1130 CallbackInfo->ConfigAccess.Callback = Ip4FormCallback;
1131
1132 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **)&CallbackInfo->ConfigRouting);
1133 if (EFI_ERROR (Status)) {
1134 return Status;
1135 }
1136
1137 CallbackInfo->DriverHandle = NULL;
1138 //
1139 // Install Device Path Protocol and Config Access protocol to driver handle
1140 //
1141 Status = gBS->InstallMultipleProtocolInterfaces (
1142 &CallbackInfo->DriverHandle,
1143 &gEfiDevicePathProtocolGuid,
1144 &mIp4ConifgHiiVendorDevicePath,
1145 &gEfiHiiConfigAccessProtocolGuid,
1146 &CallbackInfo->ConfigAccess,
1147 NULL
1148 );
1149 ASSERT_EFI_ERROR (Status);
1150
1151 //
1152 // Publish our HII data
1153 //
1154 CallbackInfo->RegisteredHandle = HiiAddPackages (
1155 &gEfiNicIp4ConfigVariableGuid,
1156 CallbackInfo->DriverHandle,
1157 Ip4ConfigDxeStrings,
1158 Ip4ConfigDxeBin,
1159 NULL
1160 );
1161 if (CallbackInfo->RegisteredHandle == NULL) {
1162 return EFI_OUT_OF_RESOURCES;
1163 }
1164
1165 mCallbackInfo = CallbackInfo;
1166
1167 return Status;
1168 }