]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/HttpBootDxe/HttpBootConfig.c
NetworkPkg: Allow user to create a HTTP corporate boot option in setup page.
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootConfig.c
1 /** @file
2 Helper functions for configuring or getting the parameters relating to HTTP Boot.
3
4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5 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 "HttpBootDxe.h"
16
17 CHAR16 mHttpBootConfigStorageName[] = L"HTTP_BOOT_CONFIG_IFR_NVDATA";
18
19 /**
20 Add new boot option for HTTP boot.
21
22 @param[in] Private Pointer to the driver private data.
23 @param[in] UsingIpv6 Set to TRUE if creating boot option for IPv6.
24 @param[in] Description The description text of the boot option.
25 @param[in] Uri The URI string of the boot file.
26
27 @retval EFI_SUCCESS The boot option is created successfully.
28 @retval Others Failed to create new boot option.
29
30 **/
31 EFI_STATUS
32 HttpBootAddBootOption (
33 IN HTTP_BOOT_PRIVATE_DATA *Private,
34 IN BOOLEAN UsingIpv6,
35 IN CHAR16 *Description,
36 IN CHAR16 *Uri
37 )
38 {
39 EFI_DEV_PATH *Node;
40 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
41 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
42 UINTN Length;
43 CHAR8 AsciiUri[URI_STR_MAX_SIZE];
44 CHAR16 *CurrentOrder;
45 EFI_STATUS Status;
46 UINTN OrderCount;
47 UINTN TargetLocation;
48 BOOLEAN Found;
49 UINT8 *TempByteBuffer;
50 UINT8 *TempByteStart;
51 UINTN DescSize;
52 UINTN FilePathSize;
53 CHAR16 OptionStr[10];
54 UINT16 *NewOrder;
55 UINTN Index;
56
57 NewOrder = NULL;
58 TempByteStart = NULL;
59 NewDevicePath = NULL;
60 NewOrder = NULL;
61 Node = NULL;
62 TmpDevicePath = NULL;
63 CurrentOrder = NULL;
64
65 if (StrLen (Description) == 0) {
66 return EFI_INVALID_PARAMETER;
67 }
68
69 //
70 // Convert the scheme to all lower case.
71 //
72 for (Index = 0; Index < StrLen (Uri); Index++) {
73 if (Uri[Index] == L':') {
74 break;
75 }
76 if (Uri[Index] >= L'A' && Uri[Index] <= L'Z') {
77 Uri[Index] -= (CHAR16)(L'A' - L'a');
78 }
79 }
80
81 //
82 // Only accept empty URI, or http and https URI.
83 //
84 if ((StrLen (Uri) != 0) && (StrnCmp (Uri, L"http://", 7) != 0) && (StrnCmp (Uri, L"https://", 8) != 0)) {
85 return EFI_INVALID_PARAMETER;
86 }
87
88 //
89 // Create a new device path by appending the IP node and URI node to
90 // the driver's parent device path
91 //
92 if (!UsingIpv6) {
93 Node = AllocateZeroPool (sizeof (IPv4_DEVICE_PATH));
94 if (Node == NULL) {
95 Status = EFI_OUT_OF_RESOURCES;
96 goto ON_EXIT;
97 }
98 Node->Ipv4.Header.Type = MESSAGING_DEVICE_PATH;
99 Node->Ipv4.Header.SubType = MSG_IPv4_DP;
100 SetDevicePathNodeLength (Node, sizeof (IPv4_DEVICE_PATH));
101 } else {
102 Node = AllocateZeroPool (sizeof (IPv6_DEVICE_PATH));
103 if (Node == NULL) {
104 Status = EFI_OUT_OF_RESOURCES;
105 goto ON_EXIT;
106 }
107 Node->Ipv6.Header.Type = MESSAGING_DEVICE_PATH;
108 Node->Ipv6.Header.SubType = MSG_IPv6_DP;
109 SetDevicePathNodeLength (Node, sizeof (IPv6_DEVICE_PATH));
110 }
111 TmpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
112 FreePool (Node);
113 if (TmpDevicePath == NULL) {
114 return EFI_OUT_OF_RESOURCES;
115 }
116 //
117 // Update the URI node with the input boot file URI.
118 //
119 UnicodeStrToAsciiStr (Uri, AsciiUri);
120 Length = sizeof (EFI_DEVICE_PATH_PROTOCOL) + AsciiStrSize (AsciiUri);
121 Node = AllocatePool (Length);
122 if (Node == NULL) {
123 Status = EFI_OUT_OF_RESOURCES;
124 FreePool (TmpDevicePath);
125 goto ON_EXIT;
126 }
127 Node->DevPath.Type = MESSAGING_DEVICE_PATH;
128 Node->DevPath.SubType = MSG_URI_DP;
129 SetDevicePathNodeLength (Node, Length);
130 CopyMem ((UINT8*) Node + sizeof (EFI_DEVICE_PATH_PROTOCOL), AsciiUri, AsciiStrSize (AsciiUri));
131 NewDevicePath = AppendDevicePathNode (TmpDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
132 FreePool (Node);
133 FreePool (TmpDevicePath);
134 if (NewDevicePath == NULL) {
135 Status = EFI_OUT_OF_RESOURCES;
136 goto ON_EXIT;
137 }
138
139 //
140 // Get current "BootOrder" variable and find a free target.
141 //
142 Length = 0;
143 Status = GetVariable2 (
144 L"BootOrder",
145 &gEfiGlobalVariableGuid,
146 (VOID **)&CurrentOrder,
147 &Length
148 );
149 if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {
150 goto ON_EXIT;
151 }
152 OrderCount = Length / sizeof (UINT16);
153 Found = FALSE;
154 for (TargetLocation=0; TargetLocation < 0xFFFF; TargetLocation++) {
155 Found = TRUE;
156 for (Index = 0; Index < OrderCount; Index++) {
157 if (CurrentOrder[Index] == TargetLocation) {
158 Found = FALSE;
159 break;
160 }
161 }
162 if (Found) {
163 break;
164 }
165 }
166
167 if (TargetLocation == 0xFFFF) {
168 DEBUG ((EFI_D_ERROR, "Could not find unused target index.\n"));
169 Status = EFI_OUT_OF_RESOURCES;
170 goto ON_EXIT;
171 } else {
172 DEBUG ((EFI_D_INFO, "TargetIndex = %04x.\n", TargetLocation));
173 }
174
175 //
176 // Construct and set the "Boot####" variable
177 //
178 DescSize = StrSize(Description);
179 FilePathSize = GetDevicePathSize (NewDevicePath);
180 TempByteBuffer = AllocateZeroPool(sizeof(EFI_LOAD_OPTION) + DescSize + FilePathSize);
181 if (TempByteBuffer == NULL) {
182 Status = EFI_OUT_OF_RESOURCES;
183 goto ON_EXIT;
184 }
185
186 TempByteStart = TempByteBuffer;
187 *((UINT32 *) TempByteBuffer) = LOAD_OPTION_ACTIVE; // Attributes
188 TempByteBuffer += sizeof (UINT32);
189
190 *((UINT16 *) TempByteBuffer) = (UINT16)FilePathSize; // FilePathListLength
191 TempByteBuffer += sizeof (UINT16);
192
193 CopyMem (TempByteBuffer, Description, DescSize);
194 TempByteBuffer += DescSize;
195 CopyMem (TempByteBuffer, NewDevicePath, FilePathSize);
196
197 UnicodeSPrint (OptionStr, sizeof(OptionStr), L"%s%04x", L"Boot", TargetLocation);
198 Status = gRT->SetVariable (
199 OptionStr,
200 &gEfiGlobalVariableGuid,
201 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
202 sizeof(UINT32) + sizeof(UINT16) + DescSize + FilePathSize,
203 TempByteStart
204 );
205 if (EFI_ERROR (Status)) {
206 goto ON_EXIT;
207 }
208
209 //
210 // Insert into the order list and set "BootOrder" variable
211 //
212 NewOrder = AllocateZeroPool ((OrderCount + 1) * sizeof (UINT16));
213 if (NewOrder == NULL) {
214 Status = EFI_OUT_OF_RESOURCES;
215 goto ON_EXIT;
216 }
217 CopyMem(NewOrder, CurrentOrder, OrderCount * sizeof(UINT16));
218 NewOrder[OrderCount] = (UINT16) TargetLocation;
219 Status = gRT->SetVariable (
220 L"BootOrder",
221 &gEfiGlobalVariableGuid,
222 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
223 ((OrderCount + 1) * sizeof (UINT16)),
224 NewOrder
225 );
226
227
228 ON_EXIT:
229
230 if (CurrentOrder != NULL) {
231 FreePool (CurrentOrder);
232 }
233 if (NewOrder != NULL) {
234 FreePool (NewOrder);
235 }
236 if (TempByteStart != NULL) {
237 FreePool (TempByteStart);
238 }
239 if (NewDevicePath != NULL) {
240 FreePool (NewDevicePath);
241 }
242
243 return Status;
244 }
245
246 /**
247
248 This function allows the caller to request the current
249 configuration for one or more named elements. The resulting
250 string is in <ConfigAltResp> format. Also, any and all alternative
251 configuration strings shall be appended to the end of the
252 current configuration string. If they are, they must appear
253 after the current configuration. They must contain the same
254 routing (GUID, NAME, PATH) as the current configuration string.
255 They must have an additional description indicating the type of
256 alternative configuration the string represents,
257 "ALTCFG=<StringToken>". That <StringToken> (when
258 converted from Hex UNICODE to binary) is a reference to a
259 string in the associated string pack.
260
261 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
262
263 @param[in] Request A null-terminated Unicode string in
264 <ConfigRequest> format. Note that this
265 includes the routing information as well as
266 the configurable name / value pairs. It is
267 invalid for this string to be in
268 <MultiConfigRequest> format.
269
270 @param[out] Progress On return, points to a character in the
271 Request string. Points to the string's null
272 terminator if request was successful. Points
273 to the most recent "&" before the first
274 failing name / value pair (or the beginning
275 of the string if the failure is in the first
276 name / value pair) if the request was not successful.
277
278 @param[out] Results A null-terminated Unicode string in
279 <ConfigAltResp> format which has all values
280 filled in for the names in the Request string.
281 String to be allocated by the called function.
282
283 @retval EFI_SUCCESS The Results string is filled with the
284 values corresponding to all requested
285 names.
286
287 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
288 parts of the results that must be
289 stored awaiting possible future
290 protocols.
291
292 @retval EFI_INVALID_PARAMETER For example, passing in a NULL
293 for the Request parameter
294 would result in this type of
295 error. In this case, the
296 Progress parameter would be
297 set to NULL.
298
299 @retval EFI_NOT_FOUND Routing data doesn't match any
300 known driver. Progress set to the
301 first character in the routing header.
302 Note: There is no requirement that the
303 driver validate the routing data. It
304 must skip the <ConfigHdr> in order to
305 process the names.
306
307 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set
308 to most recent "&" before the
309 error or the beginning of the
310 string.
311
312 @retval EFI_INVALID_PARAMETER Unknown name. Progress points
313 to the & before the name in
314 question.
315
316 **/
317 EFI_STATUS
318 EFIAPI
319 HttpBootFormExtractConfig (
320 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
321 IN CONST EFI_STRING Request,
322 OUT EFI_STRING *Progress,
323 OUT EFI_STRING *Results
324 )
325 {
326 EFI_STATUS Status;
327 UINTN BufferSize;
328 HTTP_BOOT_FORM_CALLBACK_INFO *CallbackInfo;
329 EFI_STRING ConfigRequestHdr;
330 EFI_STRING ConfigRequest;
331 BOOLEAN AllocatedRequest;
332 UINTN Size;
333
334 if (Progress == NULL || Results == NULL) {
335 return EFI_INVALID_PARAMETER;
336 }
337
338 *Progress = Request;
339 if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gHttpBootConfigGuid, mHttpBootConfigStorageName)) {
340 return EFI_NOT_FOUND;
341 }
342
343 ConfigRequestHdr = NULL;
344 ConfigRequest = NULL;
345 AllocatedRequest = FALSE;
346 Size = 0;
347
348 CallbackInfo = HTTP_BOOT_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS (This);
349 //
350 // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
351 //
352 BufferSize = sizeof (HTTP_BOOT_CONFIG_IFR_NVDATA);
353 ZeroMem (&CallbackInfo->HttpBootNvData, BufferSize);
354 StrCpyS (CallbackInfo->HttpBootNvData.Description, DESCRIPTION_STR_MAX_SIZE / sizeof (CHAR16), HTTP_BOOT_DEFAULT_DESCRIPTION_STR);
355
356 ConfigRequest = Request;
357 if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
358 //
359 // Request has no request element, construct full request string.
360 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
361 // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
362 //
363 ConfigRequestHdr = HiiConstructConfigHdr (&gHttpBootConfigGuid, mHttpBootConfigStorageName, CallbackInfo->ChildHandle);
364 Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
365 ConfigRequest = AllocateZeroPool (Size);
366 ASSERT (ConfigRequest != NULL);
367 AllocatedRequest = TRUE;
368 UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
369 FreePool (ConfigRequestHdr);
370 }
371
372 Status = gHiiConfigRouting->BlockToConfig (
373 gHiiConfigRouting,
374 ConfigRequest,
375 (UINT8 *) &CallbackInfo->HttpBootNvData,
376 BufferSize,
377 Results,
378 Progress
379 );
380
381 //
382 // Free the allocated config request string.
383 //
384 if (AllocatedRequest) {
385 FreePool (ConfigRequest);
386 ConfigRequest = NULL;
387 }
388 //
389 // Set Progress string to the original request string.
390 //
391 if (Request == NULL) {
392 *Progress = NULL;
393 } else if (StrStr (Request, L"OFFSET") == NULL) {
394 *Progress = Request + StrLen (Request);
395 }
396
397 return Status;
398 }
399
400 /**
401
402 This function applies changes in a driver's configuration.
403 Input is a Configuration, which has the routing data for this
404 driver followed by name / value configuration pairs. The driver
405 must apply those pairs to its configurable storage. If the
406 driver's configuration is stored in a linear block of data
407 and the driver's name / value pairs are in <BlockConfig>
408 format, it may use the ConfigToBlock helper function (above) to
409 simplify the job.
410
411 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
412
413 @param[in] Configuration A null-terminated Unicode string in
414 <ConfigString> format.
415
416 @param[out] Progress A pointer to a string filled in with the
417 offset of the most recent '&' before the
418 first failing name / value pair (or the
419 beginning of the string if the failure
420 is in the first name / value pair) or
421 the terminating NULL if all was
422 successful.
423
424 @retval EFI_SUCCESS The results have been distributed or are
425 awaiting distribution.
426
427 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
428 parts of the results that must be
429 stored awaiting possible future
430 protocols.
431
432 @retval EFI_INVALID_PARAMETERS Passing in a NULL for the
433 Results parameter would result
434 in this type of error.
435
436 @retval EFI_NOT_FOUND Target for the specified routing data
437 was not found.
438
439 **/
440 EFI_STATUS
441 EFIAPI
442 HttpBootFormRouteConfig (
443 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
444 IN CONST EFI_STRING Configuration,
445 OUT EFI_STRING *Progress
446 )
447 {
448 EFI_STATUS Status;
449 UINTN BufferSize;
450 HTTP_BOOT_FORM_CALLBACK_INFO *CallbackInfo;
451 HTTP_BOOT_PRIVATE_DATA *Private;
452
453 if (Progress == NULL) {
454 return EFI_INVALID_PARAMETER;
455 }
456 *Progress = Configuration;
457
458 if (Configuration == NULL) {
459 return EFI_INVALID_PARAMETER;
460 }
461
462 //
463 // Check routing data in <ConfigHdr>.
464 // Note: there is no name for Name/Value storage, only GUID will be checked
465 //
466 if (!HiiIsConfigHdrMatch (Configuration, &gHttpBootConfigGuid, mHttpBootConfigStorageName)) {
467 return EFI_NOT_FOUND;
468 }
469
470 CallbackInfo = HTTP_BOOT_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS (This);
471 Private = HTTP_BOOT_PRIVATE_DATA_FROM_CALLBACK_INFO (CallbackInfo);
472
473 BufferSize = sizeof (HTTP_BOOT_CONFIG_IFR_NVDATA);
474 ZeroMem (&CallbackInfo->HttpBootNvData, BufferSize);
475
476 Status = gHiiConfigRouting->ConfigToBlock (
477 gHiiConfigRouting,
478 Configuration,
479 (UINT8 *) &CallbackInfo->HttpBootNvData,
480 &BufferSize,
481 Progress
482 );
483 if (EFI_ERROR (Status)) {
484 return Status;
485 }
486
487 //
488 // Create a new boot option according to the configuration data.
489 //
490 HttpBootAddBootOption (
491 Private,
492 (CallbackInfo->HttpBootNvData.IpVersion == HTTP_BOOT_IP_VERSION_6) ? TRUE : FALSE,
493 CallbackInfo->HttpBootNvData.Description,
494 CallbackInfo->HttpBootNvData.Uri
495 );
496
497 return EFI_SUCCESS;
498 }
499
500 /**
501
502 This function is called to provide results data to the driver.
503 This data consists of a unique key that is used to identify
504 which data is either being passed back or being asked for.
505
506 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
507 @param[in] Action Specifies the type of action taken by the browser.
508 @param[in] QuestionId A unique value which is sent to the original
509 exporting driver so that it can identify the type
510 of data to expect. The format of the data tends to
511 vary based on the opcode that generated the callback.
512 @param[in] Type The type of value for the question.
513 @param[in, out] Value A pointer to the data being sent to the original
514 exporting driver.
515 @param[out] ActionRequest On return, points to the action requested by the
516 callback function.
517
518 @retval EFI_SUCCESS The callback successfully handled the action.
519 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
520 variable and its data.
521 @retval EFI_DEVICE_ERROR The variable could not be saved.
522 @retval EFI_UNSUPPORTED The specified Action is not supported by the
523 callback.
524 **/
525 EFI_STATUS
526 EFIAPI
527 HttpBootFormCallback (
528 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
529 IN EFI_BROWSER_ACTION Action,
530 IN EFI_QUESTION_ID QuestionId,
531 IN UINT8 Type,
532 IN OUT EFI_IFR_TYPE_VALUE *Value,
533 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
534 )
535 {
536 EFI_INPUT_KEY Key;
537 UINTN Index;
538 CHAR16 *Uri;
539 HTTP_BOOT_FORM_CALLBACK_INFO *CallbackInfo;
540
541 if (This == NULL || Value == NULL) {
542 return EFI_INVALID_PARAMETER;
543 }
544
545 CallbackInfo = HTTP_BOOT_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS (This);
546
547 if (Action != EFI_BROWSER_ACTION_CHANGING) {
548 return EFI_UNSUPPORTED;
549 }
550
551 switch (QuestionId) {
552 case KEY_INITIATOR_URI:
553 //
554 // Get user input URI string
555 //
556 Uri = HiiGetString (CallbackInfo->RegisteredHandle, Value->string, NULL);
557 ASSERT (Uri != NULL);
558 if (Uri == NULL) {
559 return EFI_UNSUPPORTED;
560 }
561
562 //
563 // Convert the scheme to all lower case.
564 //
565 for (Index = 0; Index < StrLen (Uri); Index++) {
566 if (Uri[Index] == L':') {
567 break;
568 }
569 if (Uri[Index] >= L'A' && Uri[Index] <= L'Z') {
570 Uri[Index] -= (CHAR16)(L'A' - L'a');
571 }
572 }
573
574 //
575 // Set the converted URI string back
576 //
577 HiiSetString (CallbackInfo->RegisteredHandle, Value->string, Uri, NULL);
578
579 //
580 // The URI should be either an empty string (for corporate environment) ,or http(s) for home environment.
581 // Pop up a message box for other unsupported URI.
582 //
583 if ((StrLen (Uri) != 0) && (StrnCmp (Uri, L"http://", 7) != 0) && (StrnCmp (Uri, L"https://", 8) != 0)) {
584 CreatePopUp (
585 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
586 &Key,
587 L"ERROR: Unsupported URI!",
588 L"Only supports HTTP and HTTPS",
589 NULL
590 );
591 }
592
593 FreePool (Uri);
594 break;
595
596 default:
597 break;
598 }
599
600 return EFI_SUCCESS;
601 }
602
603 /**
604 Initialize the configuration form.
605
606 @param[in] Private Pointer to the driver private data.
607
608 @retval EFI_SUCCESS The configuration form is initialized.
609 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
610
611 **/
612 EFI_STATUS
613 HttpBootConfigFormInit (
614 IN HTTP_BOOT_PRIVATE_DATA *Private
615 )
616 {
617 EFI_STATUS Status;
618 HTTP_BOOT_FORM_CALLBACK_INFO *CallbackInfo;
619 VENDOR_DEVICE_PATH VendorDeviceNode;
620 CHAR16 *MacString;
621 CHAR16 *OldMenuString;
622 CHAR16 MenuString[128];
623
624 CallbackInfo = &Private->CallbackInfo;
625
626 if (CallbackInfo->Initilized) {
627 return EFI_SUCCESS;
628 }
629
630 CallbackInfo->Signature = HTTP_BOOT_FORM_CALLBACK_INFO_SIGNATURE;
631
632 //
633 // Construct device path node for EFI HII Config Access protocol,
634 // which consists of controller physical device path and one hardware
635 // vendor guid node.
636 //
637 ZeroMem (&VendorDeviceNode, sizeof (VENDOR_DEVICE_PATH));
638 VendorDeviceNode.Header.Type = HARDWARE_DEVICE_PATH;
639 VendorDeviceNode.Header.SubType = HW_VENDOR_DP;
640 CopyGuid (&VendorDeviceNode.Guid, &gEfiCallerIdGuid);
641 SetDevicePathNodeLength (&VendorDeviceNode.Header, sizeof (VENDOR_DEVICE_PATH));
642 CallbackInfo->HiiVendorDevicePath = AppendDevicePathNode (
643 Private->ParentDevicePath,
644 (EFI_DEVICE_PATH_PROTOCOL *) &VendorDeviceNode
645 );
646 if (CallbackInfo->HiiVendorDevicePath == NULL) {
647 Status = EFI_OUT_OF_RESOURCES;
648 goto Error;
649 }
650
651 CallbackInfo->ConfigAccess.ExtractConfig = HttpBootFormExtractConfig;
652 CallbackInfo->ConfigAccess.RouteConfig = HttpBootFormRouteConfig;
653 CallbackInfo->ConfigAccess.Callback = HttpBootFormCallback;
654
655 //
656 // Install Device Path Protocol and Config Access protocol to driver handle.
657 //
658 Status = gBS->InstallMultipleProtocolInterfaces (
659 &CallbackInfo->ChildHandle,
660 &gEfiDevicePathProtocolGuid,
661 CallbackInfo->HiiVendorDevicePath,
662 &gEfiHiiConfigAccessProtocolGuid,
663 &CallbackInfo->ConfigAccess,
664 NULL
665 );
666 if (EFI_ERROR (Status)) {
667 goto Error;
668 }
669
670 //
671 // Publish our HII data.
672 //
673 CallbackInfo->RegisteredHandle = HiiAddPackages (
674 &gHttpBootConfigGuid,
675 CallbackInfo->ChildHandle,
676 HttpBootDxeStrings,
677 HttpBootConfigVfrBin,
678 NULL
679 );
680 if (CallbackInfo->RegisteredHandle == NULL) {
681 Status = EFI_OUT_OF_RESOURCES;
682 goto Error;
683 }
684
685 //
686 // Append MAC string in the menu help string
687 //
688 Status = NetLibGetMacString (Private->Controller, NULL, &MacString);
689 if (!EFI_ERROR (Status)) {
690 OldMenuString = HiiGetString (
691 CallbackInfo->RegisteredHandle,
692 STRING_TOKEN (STR_HTTP_BOOT_CONFIG_FORM_HELP),
693 NULL
694 );
695 UnicodeSPrint (MenuString, 128, L"%s (MAC:%s)", OldMenuString, MacString);
696 HiiSetString (
697 CallbackInfo->RegisteredHandle,
698 STRING_TOKEN (STR_HTTP_BOOT_CONFIG_FORM_HELP),
699 MenuString,
700 NULL
701 );
702
703 FreePool (MacString);
704 FreePool (OldMenuString);
705
706 CallbackInfo->Initilized = TRUE;
707 return EFI_SUCCESS;
708 }
709
710 Error:
711
712 HttpBootConfigFormUnload (Private);
713 return Status;
714 }
715
716 /**
717 Unload the configuration form, this includes: delete all the configuration
718 entries, uninstall the form callback protocol, and free the resources used.
719 The form will only be unload completely when both IP4 and IP6 stack are stopped.
720
721 @param[in] Private Pointer to the driver private data.
722
723 @retval EFI_SUCCESS The configuration form is unloaded.
724 @retval Others Failed to unload the form.
725
726 **/
727 EFI_STATUS
728 HttpBootConfigFormUnload (
729 IN HTTP_BOOT_PRIVATE_DATA *Private
730 )
731 {
732 HTTP_BOOT_FORM_CALLBACK_INFO *CallbackInfo;
733
734 if (Private->Ip4Nic != NULL || Private->Ip6Nic != NULL) {
735 //
736 // Only unload the configuration form when both IP4 and IP6 stack are stopped.
737 //
738 return EFI_SUCCESS;
739 }
740
741 CallbackInfo = &Private->CallbackInfo;
742 if (CallbackInfo->ChildHandle != NULL) {
743 //
744 // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL
745 //
746 gBS->UninstallMultipleProtocolInterfaces (
747 CallbackInfo->ChildHandle,
748 &gEfiDevicePathProtocolGuid,
749 CallbackInfo->HiiVendorDevicePath,
750 &gEfiHiiConfigAccessProtocolGuid,
751 &CallbackInfo->ConfigAccess,
752 NULL
753 );
754 CallbackInfo->ChildHandle = NULL;
755 }
756
757 if (CallbackInfo->HiiVendorDevicePath != NULL) {
758 FreePool (CallbackInfo->HiiVendorDevicePath);
759 CallbackInfo->HiiVendorDevicePath = NULL;
760 }
761
762 if (CallbackInfo->RegisteredHandle != NULL) {
763 //
764 // Remove HII package list
765 //
766 HiiRemovePackages (CallbackInfo->RegisteredHandle);
767 CallbackInfo->RegisteredHandle = NULL;
768 }
769
770 return EFI_SUCCESS;
771 }