VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/RedfishPkg/RedfishHttpDxe/RedfishHttpDxe.c@ 108794

Last change on this file since 108794 was 108794, checked in by vboxsync, 2 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 42.6 KB
Line 
1/** @file
2 RedfishHttpDxe produces EdkIIRedfishHttpProtocol
3 for EDK2 Redfish Feature driver to do HTTP operations.
4
5 Copyright (c) 2023-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9**/
10
11#include "RedfishHttpDxe.h"
12#include "RedfishHttpData.h"
13#include "RedfishHttpOperation.h"
14
15REDFISH_HTTP_CACHE_PRIVATE *mRedfishHttpCachePrivate = NULL;
16
17/**
18 Debug output the cache list.
19
20 @param[in] Msg Debug message string.
21 @param[in] ErrorLevel Output error level.
22 @param[in] CacheList Target list to dump.
23
24 @retval EFI_SUCCESS Debug dump finished.
25 @retval EFI_INVALID_PARAMETER HttpCacheList is NULL.
26
27**/
28EFI_STATUS
29DebugPrintHttpCacheList (
30 IN CONST CHAR8 *Msg,
31 IN UINTN ErrorLevel,
32 IN REDFISH_HTTP_CACHE_LIST *CacheList
33 )
34{
35 LIST_ENTRY *List;
36 REDFISH_HTTP_CACHE_DATA *Data;
37 UINTN Index;
38
39 if (CacheList == NULL) {
40 return EFI_INVALID_PARAMETER;
41 }
42
43 if (!IS_EMPTY_STRING (Msg)) {
44 DEBUG ((ErrorLevel, "%a\n", Msg));
45 }
46
47 if (IsListEmpty (&CacheList->Head)) {
48 DEBUG ((ErrorLevel, "list is empty\n"));
49 return EFI_NOT_FOUND;
50 }
51
52 DEBUG ((ErrorLevel, "list count: %d capacity: %d\n", CacheList->Count, CacheList->Capacity));
53 Data = NULL;
54 Index = 0;
55 List = GetFirstNode (&CacheList->Head);
56 while (!IsNull (&CacheList->Head, List)) {
57 Data = REDFISH_HTTP_CACHE_FROM_LIST (List);
58
59 DEBUG ((ErrorLevel, "%d) Uri: %s Hit: %d\n", ++Index, Data->Uri, Data->HitCount));
60
61 List = GetNextNode (&CacheList->Head, List);
62 }
63
64 return EFI_SUCCESS;
65}
66
67/**
68
69 Check HTTP status code to see if we like to retry HTTP request or not.
70
71 @param[in] StatusCode HTTP status code.
72
73 @retval BOOLEAN Return true when we like to retry request.
74 Return false when we don't want to retry request.
75
76**/
77BOOLEAN
78RedfishRetryRequired (
79 IN EFI_HTTP_STATUS_CODE *StatusCode
80 )
81{
82 if (StatusCode == NULL) {
83 return TRUE;
84 }
85
86 if ((*StatusCode == HTTP_STATUS_500_INTERNAL_SERVER_ERROR) ||
87 (*StatusCode == HTTP_STATUS_UNSUPPORTED_STATUS))
88 {
89 return TRUE;
90 }
91
92 return FALSE;
93}
94
95/**
96
97 This function follows below sections in Redfish specification to
98 check HTTP status code and see if this is success response or not.
99
100 7.5.2 Modification success responses
101 7.11 POST (action)
102
103 @param[in] Method HTTP method of this status code.
104 @param[in] StatusCode HTTP status code.
105
106 @retval BOOLEAN Return true when this is success response.
107 Return false when this is not success response.
108
109**/
110BOOLEAN
111RedfishSuccessResponse (
112 IN EFI_HTTP_METHOD Method,
113 IN EFI_HTTP_STATUS_CODE *StatusCode
114 )
115{
116 BOOLEAN SuccessResponse;
117
118 if (StatusCode == NULL) {
119 return TRUE;
120 }
121
122 SuccessResponse = FALSE;
123 switch (Method) {
124 case HttpMethodPost:
125 if ((*StatusCode == HTTP_STATUS_200_OK) ||
126 (*StatusCode == HTTP_STATUS_201_CREATED) ||
127 (*StatusCode == HTTP_STATUS_202_ACCEPTED) ||
128 (*StatusCode == HTTP_STATUS_204_NO_CONTENT))
129 {
130 SuccessResponse = TRUE;
131 }
132
133 break;
134 case HttpMethodPatch:
135 case HttpMethodPut:
136 case HttpMethodDelete:
137 if ((*StatusCode == HTTP_STATUS_200_OK) ||
138 (*StatusCode == HTTP_STATUS_202_ACCEPTED) ||
139 (*StatusCode == HTTP_STATUS_204_NO_CONTENT))
140 {
141 SuccessResponse = TRUE;
142 }
143
144 break;
145 default:
146 //
147 // Return true for unsupported method to prevent false alarm.
148 //
149 SuccessResponse = TRUE;
150 break;
151 }
152
153 return SuccessResponse;
154}
155
156/**
157
158 Convert Unicode string to ASCII string. It's call responsibility to release returned buffer.
159
160 @param[in] UnicodeStr Unicode string to convert.
161
162 @retval CHAR8 * ASCII string returned.
163 @retval NULL Errors occur.
164
165**/
166CHAR8 *
167StringUnicodeToAscii (
168 IN EFI_STRING UnicodeStr
169 )
170{
171 CHAR8 *AsciiStr;
172 UINTN AsciiStrSize;
173 EFI_STATUS Status;
174
175 if (IS_EMPTY_STRING (UnicodeStr)) {
176 return NULL;
177 }
178
179 AsciiStrSize = StrLen (UnicodeStr) + 1;
180 AsciiStr = AllocateZeroPool (AsciiStrSize);
181 if (AsciiStr == NULL) {
182 return NULL;
183 }
184
185 Status = UnicodeStrToAsciiStrS (UnicodeStr, AsciiStr, AsciiStrSize);
186 if (EFI_ERROR (Status)) {
187 DEBUG ((DEBUG_ERROR, "UnicodeStrToAsciiStrS failed: %r\n", Status));
188 FreePool (AsciiStr);
189 return NULL;
190 }
191
192 return AsciiStr;
193}
194
195/**
196 Return HTTP method in ASCII string. Caller does not need
197 to free returned string buffer.
198
199 @param[in] Method HTTP method.
200
201 @retval CHAR8 * Method in string.
202**/
203CHAR8 *
204HttpMethodToString (
205 IN EFI_HTTP_METHOD Method
206 )
207{
208 switch (Method) {
209 case HttpMethodGet:
210 return HTTP_METHOD_GET;
211 break;
212 case HttpMethodPost:
213 return HTTP_METHOD_POST;
214 break;
215 case HttpMethodPatch:
216 return HTTP_METHOD_PATCH;
217 break;
218 case HttpMethodPut:
219 return HTTP_METHOD_PUT;
220 break;
221 case HttpMethodDelete:
222 return HTTP_METHOD_DELETE;
223 break;
224 default:
225 break;
226 }
227
228 return "Unknown";
229}
230
231/**
232 Report HTTP communication error via report status code.
233
234 @param[in] Method HTTP method.
235 @param[in] Uri The URI which has failure.
236 @param[in] HttpStatusCode HTTP status code.
237
238**/
239VOID
240ReportHttpError (
241 IN EFI_HTTP_METHOD Method,
242 IN EFI_STRING Uri,
243 IN EFI_HTTP_STATUS_CODE *HttpStatusCode OPTIONAL
244 )
245{
246 CHAR8 ErrorMsg[REDFISH_ERROR_MSG_MAX];
247
248 if (IS_EMPTY_STRING (Uri)) {
249 DEBUG ((DEBUG_ERROR, "%a: no URI to report error status\n", __func__));
250 return;
251 }
252
253 //
254 // Report failure of URI and HTTP status code.
255 //
256 AsciiSPrint (ErrorMsg, sizeof (ErrorMsg), REDFISH_HTTP_ERROR_REPORT, HttpMethodToString (Method), (HttpStatusCode == NULL ? HTTP_STATUS_UNSUPPORTED_STATUS : *HttpStatusCode), Uri);
257 DEBUG ((DEBUG_ERROR, "%a\n", ErrorMsg));
258
259 //
260 // Report this failure via status code and BMC has chance to capture the error.
261 //
262 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
263 EFI_ERROR_CODE | EFI_ERROR_MAJOR,
264 EFI_COMPUTING_UNIT_MANAGEABILITY | EFI_MANAGEABILITY_EC_REDFISH_COMMUNICATION_ERROR,
265 ErrorMsg,
266 AsciiStrSize (ErrorMsg)
267 );
268}
269
270/**
271 This function create Redfish service. It's caller's responsibility to free returned
272 Redfish service by calling FreeService ().
273
274 @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
275 @param[in] RedfishConfigServiceInfo Redfish config service information.
276
277 @retval REDFISH_SERVICE Redfish service is created.
278 @retval NULL Errors occur.
279
280**/
281REDFISH_SERVICE
282EFIAPI
283RedfishCreateRedfishService (
284 IN EDKII_REDFISH_HTTP_PROTOCOL *This,
285 IN REDFISH_CONFIG_SERVICE_INFORMATION *RedfishConfigServiceInfo
286 )
287{
288 EFI_STATUS Status;
289 REDFISH_HTTP_CACHE_PRIVATE *Private;
290 REDFISH_SERVICE_PRIVATE *NewService;
291 CHAR8 *AsciiLocation;
292 CHAR8 *Host;
293 CHAR8 *BasicAuthString;
294 UINTN BasicAuthStrSize;
295 CHAR8 *EncodedAuthString;
296 UINTN EncodedAuthStrSize;
297 EDKII_REDFISH_AUTH_METHOD AuthMethod;
298 CHAR8 *Username;
299 CHAR8 *Password;
300 UINTN UsernameSize;
301 UINTN PasswordSize;
302 EFI_REST_EX_PROTOCOL *RestEx;
303
304 if ((This == NULL) || (RedfishConfigServiceInfo == NULL)) {
305 return NULL;
306 }
307
308 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: service location: %s\n", __func__, RedfishConfigServiceInfo->RedfishServiceLocation));
309
310 Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
311 BasicAuthString = NULL;
312 EncodedAuthString = NULL;
313 Username = NULL;
314 Password = NULL;
315 NewService = NULL;
316 AsciiLocation = NULL;
317 Host = NULL;
318 BasicAuthStrSize = 0;
319 EncodedAuthStrSize = 0;
320 UsernameSize = 0;
321 PasswordSize = 0;
322
323 //
324 // Build host and host name from service location
325 //
326 if (!IS_EMPTY_STRING (RedfishConfigServiceInfo->RedfishServiceLocation)) {
327 AsciiLocation = StringUnicodeToAscii (RedfishConfigServiceInfo->RedfishServiceLocation);
328 if (AsciiLocation == NULL) {
329 goto ON_RELEASE;
330 }
331
332 Host = AllocateZeroPool (REDFISH_HOST_NAME_MAX);
333 if (AsciiLocation == NULL) {
334 goto ON_RELEASE;
335 }
336
337 if (RedfishConfigServiceInfo->RedfishServiceUseHttps) {
338 AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "https://%a", AsciiLocation);
339 } else {
340 AsciiSPrint (Host, REDFISH_HOST_NAME_MAX, "http://%a", AsciiLocation);
341 }
342
343 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Host: %a\n", __func__, Host));
344 }
345
346 //
347 // Find Rest Ex protocol
348 //
349 if (RedfishConfigServiceInfo->RedfishServiceRestExHandle != NULL) {
350 Status = gBS->HandleProtocol (
351 RedfishConfigServiceInfo->RedfishServiceRestExHandle,
352 &gEfiRestExProtocolGuid,
353 (VOID **)&RestEx
354 );
355 } else {
356 DEBUG ((DEBUG_ERROR, "%a: Rest Ex protocol is not available\n", __func__));
357 goto ON_RELEASE;
358 }
359
360 //
361 // Get credential
362 //
363 if (Private->CredentialProtocol == NULL) {
364 //
365 // No credential available on this system.
366 //
367 DEBUG ((DEBUG_WARN, "%a: no credential protocol available\n", __func__));
368 } else {
369 Status = Private->CredentialProtocol->GetAuthInfo (
370 Private->CredentialProtocol,
371 &AuthMethod,
372 &Username,
373 &Password
374 );
375 if (EFI_ERROR (Status) || ((AuthMethod != AuthMethodNone) && (IS_EMPTY_STRING (Username) || IS_EMPTY_STRING (Password)))) {
376 DEBUG ((DEBUG_ERROR, "%a: cannot get authentication information: %r\n", __func__, Status));
377 goto ON_RELEASE;
378 } else if (AuthMethod != AuthMethodNone) {
379 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Auth method: 0x%x username: %a password: %a\n", __func__, AuthMethod, Username, Password));
380
381 //
382 // Perform base64 encoding (RFC 7617)
383 //
384 UsernameSize = AsciiStrSize (Username);
385 PasswordSize = AsciiStrSize (Password);
386 BasicAuthStrSize = UsernameSize + PasswordSize; // one byte taken from null-terminator for ':'
387 BasicAuthString = AllocateZeroPool (BasicAuthStrSize);
388 if (BasicAuthString == NULL) {
389 goto ON_RELEASE;
390 }
391
392 AsciiSPrint (
393 BasicAuthString,
394 BasicAuthStrSize,
395 "%a:%a",
396 Username,
397 Password
398 );
399
400 Status = Base64Encode (
401 (CONST UINT8 *)BasicAuthString,
402 BasicAuthStrSize,
403 EncodedAuthString,
404 &EncodedAuthStrSize
405 );
406 if ((Status == EFI_BUFFER_TOO_SMALL) && (EncodedAuthStrSize > 0)) {
407 EncodedAuthString = AllocateZeroPool (EncodedAuthStrSize);
408 if (EncodedAuthString == NULL) {
409 goto ON_RELEASE;
410 }
411
412 Status = Base64Encode (
413 (CONST UINT8 *)BasicAuthString,
414 BasicAuthStrSize,
415 EncodedAuthString,
416 &EncodedAuthStrSize
417 );
418 if (EFI_ERROR (Status)) {
419 DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __func__, Status));
420 }
421
422 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Basic authorization: %a\n", __func__, EncodedAuthString));
423 } else {
424 DEBUG ((DEBUG_ERROR, "%a: Base64Encode failure: %r\n", __func__, Status));
425 goto ON_RELEASE;
426 }
427 }
428 }
429
430 NewService = CreateRedfishService (Host, AsciiLocation, EncodedAuthString, NULL, RestEx);
431 if (NewService == NULL) {
432 DEBUG ((DEBUG_ERROR, "%a: CreateRedfishService\n", __func__));
433 goto ON_RELEASE;
434 }
435
436 if (Private->CredentialProtocol != NULL) {
437 Status = Private->CredentialProtocol->RegisterRedfishService (Private->CredentialProtocol, NewService);
438 if (EFI_ERROR (Status)) {
439 DEBUG ((DEBUG_ERROR, "%a: Failed to register Redfish service - %r\n", __func__, Status));
440 }
441 }
442
443ON_RELEASE:
444
445 if (BasicAuthString != NULL) {
446 ZeroMem (BasicAuthString, BasicAuthStrSize);
447 FreePool (BasicAuthString);
448 }
449
450 if (EncodedAuthString != NULL) {
451 ZeroMem (BasicAuthString, EncodedAuthStrSize);
452 FreePool (EncodedAuthString);
453 }
454
455 if (Username != NULL) {
456 ZeroMem (Username, UsernameSize);
457 FreePool (Username);
458 }
459
460 if (Password != NULL) {
461 ZeroMem (Password, PasswordSize);
462 FreePool (Password);
463 }
464
465 if (AsciiLocation != NULL) {
466 FreePool (AsciiLocation);
467 }
468
469 if (Host != NULL) {
470 FreePool (Host);
471 }
472
473 return NewService;
474}
475
476/**
477 This function free resources in Redfish service. RedfishService is no longer available
478 after this function returns successfully.
479
480 @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
481 @param[in] RedfishService Pointer to Redfish service to be released.
482
483 @retval EFI_SUCCESS Resource is released successfully.
484 @retval Others Errors occur.
485
486**/
487EFI_STATUS
488EFIAPI
489RedfishFreeRedfishService (
490 IN EDKII_REDFISH_HTTP_PROTOCOL *This,
491 IN REDFISH_SERVICE RedfishService
492 )
493{
494 EFI_STATUS Status;
495 REDFISH_SERVICE_PRIVATE *Service;
496 REDFISH_HTTP_CACHE_PRIVATE *Private;
497
498 if ((This == NULL) || (RedfishService == NULL)) {
499 return EFI_INVALID_PARAMETER;
500 }
501
502 Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
503
504 Service = (REDFISH_SERVICE_PRIVATE *)RedfishService;
505 if (Service->Signature != REDFISH_HTTP_SERVICE_SIGNATURE) {
506 DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
507 }
508
509 if (Private->CredentialProtocol != NULL) {
510 Status = Private->CredentialProtocol->UnregisterRedfishService (Private->CredentialProtocol, RedfishService);
511 if (EFI_ERROR (Status)) {
512 DEBUG ((DEBUG_ERROR, "%a: Failed to unregister Redfish service - %r\n", __func__, Status));
513 } else {
514 if (Service->RestEx != NULL) {
515 Status = Service->RestEx->Configure (Service->RestEx, NULL);
516 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: release RestEx instance: %r\n", __func__, Status));
517 }
518 }
519 }
520
521 return ReleaseRedfishService (Service);
522}
523
524/**
525 This function returns JSON value in given RedfishPayload. Returned JSON value
526 is a reference to the JSON value in RedfishPayload. Any modification to returned
527 JSON value will change JSON value in RedfishPayload.
528
529 @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
530 @param[in] RedfishPayload Pointer to Redfish payload.
531
532 @retval EDKII_JSON_VALUE JSON value is returned.
533 @retval NULL Errors occur.
534
535**/
536EDKII_JSON_VALUE
537EFIAPI
538RedfishJsonInRedfishPayload (
539 IN EDKII_REDFISH_HTTP_PROTOCOL *This,
540 IN REDFISH_PAYLOAD RedfishPayload
541 )
542{
543 REDFISH_PAYLOAD_PRIVATE *Payload;
544
545 if ((This == NULL) || (RedfishPayload == NULL)) {
546 return NULL;
547 }
548
549 Payload = (REDFISH_PAYLOAD_PRIVATE *)RedfishPayload;
550 if (Payload->Signature != REDFISH_HTTP_PAYLOAD_SIGNATURE) {
551 DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
552 }
553
554 return Payload->JsonValue;
555}
556
557/**
558 Perform HTTP GET to Get redfish resource from given resource URI with
559 cache mechanism supported. It's caller's responsibility to free Response
560 by calling FreeResponse ().
561
562 @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
563 @param[in] Service Redfish service instance to perform HTTP GET.
564 @param[in] Uri Target resource URI.
565 @param[in] Request Additional request context. This is optional.
566 @param[out] Response HTTP response from redfish service.
567 @param[in] UseCache If it is TRUE, this function will search for
568 cache first. If it is FALSE, this function
569 will query Redfish URI directly.
570
571 @retval EFI_SUCCESS Resource is returned successfully.
572 @retval Others Errors occur.
573
574**/
575EFI_STATUS
576EFIAPI
577RedfishGetResource (
578 IN EDKII_REDFISH_HTTP_PROTOCOL *This,
579 IN REDFISH_SERVICE Service,
580 IN EFI_STRING Uri,
581 IN REDFISH_REQUEST *Request OPTIONAL,
582 OUT REDFISH_RESPONSE *Response,
583 IN BOOLEAN UseCache
584 )
585{
586 EFI_STATUS Status;
587 REDFISH_HTTP_CACHE_DATA *CacheData;
588 UINTN RetryCount;
589 REDFISH_HTTP_CACHE_PRIVATE *Private;
590
591 if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri)) {
592 return EFI_INVALID_PARAMETER;
593 }
594
595 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Get URI: %s cache: %a\n", __func__, Uri, (UseCache ? "true" : "false")));
596
597 Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
598 CacheData = NULL;
599 RetryCount = 0;
600 ZeroMem (Response, sizeof (REDFISH_RESPONSE));
601
602 if (Private->CacheDisabled) {
603 UseCache = FALSE;
604 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: cache is disabled by PCD!\n", __func__));
605 }
606
607 //
608 // Search for cache list.
609 //
610 if (UseCache) {
611 CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
612 if (CacheData != NULL) {
613 DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: cache hit! %s\n", __func__, Uri));
614
615 //
616 // Copy cached response to caller's buffer.
617 //
618 Status = CopyRedfishResponse (CacheData->Response, Response);
619 CacheData->HitCount += 1;
620 return Status;
621 }
622 }
623
624 //
625 // Get resource from redfish service.
626 //
627 do {
628 RetryCount += 1;
629 Status = HttpSendReceive (
630 Service,
631 Uri,
632 HttpMethodGet,
633 Request,
634 Response
635 );
636 DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
637 if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryGet)) {
638 break;
639 }
640
641 //
642 // Retry when BMC is not ready.
643 //
644 if ((Response->StatusCode != NULL)) {
645 DEBUG_CODE (
646 DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
647 );
648
649 if (!RedfishRetryRequired (Response->StatusCode)) {
650 break;
651 }
652
653 //
654 // Release response for next round of request.
655 //
656 This->FreeResponse (This, Response);
657 }
658
659 DEBUG ((DEBUG_WARN, "%a: RedfishGetByUriEx failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryGet));
660 if (Private->RetrySetting.RetryWait > 0) {
661 gBS->Stall (Private->RetrySetting.RetryWait);
662 }
663 } while (TRUE);
664
665 if (EFI_ERROR (Status)) {
666 DEBUG_CODE (
667 DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
668 );
669 //
670 // Report status code for Redfish failure
671 //
672 ReportHttpError (HttpMethodGet, Uri, Response->StatusCode);
673 DEBUG ((DEBUG_ERROR, "%a: get %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryGet, Status));
674 goto ON_RELEASE;
675 }
676
677 if (!Private->CacheDisabled) {
678 //
679 // Keep response in cache list
680 //
681 Status = AddHttpCacheData (&Private->CacheList, Uri, Response);
682 if (EFI_ERROR (Status)) {
683 DEBUG ((DEBUG_ERROR, "%a: failed to cache %s: %r\n", __func__, Uri, Status));
684 goto ON_RELEASE;
685 }
686
687 DEBUG_CODE (
688 DebugPrintHttpCacheList (__func__, REDFISH_HTTP_CACHE_DEBUG_DUMP, &Private->CacheList);
689 );
690 }
691
692ON_RELEASE:
693
694 return Status;
695}
696
697/**
698 This function free resources in Request. Request is no longer available
699 after this function returns successfully.
700
701 @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
702 @param[in] Request HTTP request to be released.
703
704 @retval EFI_SUCCESS Resource is released successfully.
705 @retval Others Errors occur.
706
707**/
708EFI_STATUS
709EFIAPI
710RedfishFreeRequest (
711 IN EDKII_REDFISH_HTTP_PROTOCOL *This,
712 IN REDFISH_REQUEST *Request
713 )
714{
715 if ((This == NULL) || (Request == NULL)) {
716 return EFI_INVALID_PARAMETER;
717 }
718
719 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
720
721 return ReleaseRedfishRequest (Request);
722}
723
724/**
725 This function free resources in given Response.
726
727 @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
728 @param[in] Response HTTP response to be released.
729
730 @retval EFI_SUCCESS Resource is released successfully.
731 @retval Others Errors occur.
732
733**/
734EFI_STATUS
735EFIAPI
736RedfishFreeResponse (
737 IN EDKII_REDFISH_HTTP_PROTOCOL *This,
738 IN REDFISH_RESPONSE *Response
739 )
740{
741 if ((This == NULL) || (Response == NULL)) {
742 return EFI_INVALID_PARAMETER;
743 }
744
745 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: entry\n", __func__));
746
747 return ReleaseRedfishResponse (Response);
748}
749
750/**
751 This function expire the cached response of given URI.
752
753 @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
754 @param[in] Uri Target response of URI.
755
756 @retval EFI_SUCCESS Target response is expired successfully.
757 @retval Others Errors occur.
758
759**/
760EFI_STATUS
761EFIAPI
762RedfishExpireResponse (
763 IN EDKII_REDFISH_HTTP_PROTOCOL *This,
764 IN EFI_STRING Uri
765 )
766{
767 REDFISH_HTTP_CACHE_PRIVATE *Private;
768 REDFISH_HTTP_CACHE_DATA *CacheData;
769
770 if ((This == NULL) || IS_EMPTY_STRING (Uri)) {
771 return EFI_INVALID_PARAMETER;
772 }
773
774 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: expire URI: %s\n", __func__, Uri));
775
776 Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
777
778 CacheData = FindHttpCacheData (&Private->CacheList.Head, Uri);
779 if (CacheData == NULL) {
780 return EFI_NOT_FOUND;
781 }
782
783 return DeleteHttpCacheData (&Private->CacheList, CacheData);
784}
785
786/**
787 Perform HTTP PATCH to send redfish resource to given resource URI.
788 It's caller's responsibility to free Response by calling FreeResponse ().
789
790 @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
791 @param[in] Service Redfish service instance to perform HTTP PATCH.
792 @param[in] Uri Target resource URI.
793 @param[in] Content Data to patch.
794 @param[in] ContentSize Size of the Content to be send to Redfish service.
795 This is optional. When ContentSize is 0, ContentSize
796 is the size of Content.
797 @param[in] ContentType Type of the Content to be send to Redfish service.
798 This is optional. When ContentType is NULL, content
799 type HTTP_CONTENT_TYPE_APP_JSON will be used.
800 @param[out] Response HTTP response from redfish service.
801
802 @retval EFI_SUCCESS Resource is returned successfully.
803 @retval Others Errors occur.
804
805**/
806EFI_STATUS
807EFIAPI
808RedfishPatchResource (
809 IN EDKII_REDFISH_HTTP_PROTOCOL *This,
810 IN REDFISH_SERVICE Service,
811 IN EFI_STRING Uri,
812 IN CHAR8 *Content,
813 IN UINTN ContentSize OPTIONAL,
814 IN CHAR8 *ContentType OPTIONAL,
815 OUT REDFISH_RESPONSE *Response
816 )
817{
818 EFI_STATUS Status;
819 UINTN RetryCount;
820 REDFISH_REQUEST Request;
821 REDFISH_HTTP_CACHE_PRIVATE *Private;
822
823 if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
824 return EFI_INVALID_PARAMETER;
825 }
826
827 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Patch URI: %s\n", __func__, Uri));
828
829 Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
830 RetryCount = 0;
831 ZeroMem (Response, sizeof (REDFISH_RESPONSE));
832 ZeroMem (&Request, sizeof (REDFISH_REQUEST));
833
834 Request.Content = Content;
835 Request.ContentLength = ContentSize;
836 Request.ContentType = ContentType;
837
838 //
839 // Patch resource to redfish service.
840 //
841 do {
842 RetryCount += 1;
843 Status = HttpSendReceive (
844 Service,
845 Uri,
846 HttpMethodPatch,
847 &Request,
848 Response
849 );
850 DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
851 if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryPatch)) {
852 break;
853 }
854
855 //
856 // Retry when BMC is not ready.
857 //
858 if ((Response->StatusCode != NULL)) {
859 DEBUG_CODE (
860 DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
861 );
862
863 if (!RedfishRetryRequired (Response->StatusCode)) {
864 break;
865 }
866
867 //
868 // Release response for next round of request.
869 //
870 This->FreeResponse (This, Response);
871 }
872
873 DEBUG ((DEBUG_WARN, "%a: RedfishPatchToUriEx failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryPatch));
874 if (Private->RetrySetting.RetryWait > 0) {
875 gBS->Stall (Private->RetrySetting.RetryWait);
876 }
877 } while (TRUE);
878
879 //
880 // Redfish resource is updated. Automatically expire the cached response
881 // so application can directly get resource from Redfish service again.
882 //
883 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
884 RedfishExpireResponse (This, Uri);
885
886 if (EFI_ERROR (Status) || !RedfishSuccessResponse (HttpMethodPatch, Response->StatusCode)) {
887 DEBUG_CODE (
888 DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
889 );
890 //
891 // Report status code for Redfish failure
892 //
893 ReportHttpError (HttpMethodPatch, Uri, Response->StatusCode);
894 DEBUG ((DEBUG_ERROR, "%a: patch %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryPatch, Status));
895 goto ON_RELEASE;
896 }
897
898ON_RELEASE:
899
900 return Status;
901}
902
903/**
904 Perform HTTP PUT to send redfish resource to given resource URI.
905 It's caller's responsibility to free Response by calling FreeResponse ().
906
907 @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
908 @param[in] Service Redfish service instance to perform HTTP PUT.
909 @param[in] Uri Target resource URI.
910 @param[in] Content Data to put.
911 @param[in] ContentSize Size of the Content to be send to Redfish service.
912 This is optional. When ContentSize is 0, ContentSize
913 is the size of Content.
914 @param[in] ContentType Type of the Content to be send to Redfish service.
915 This is optional. When ContentType is NULL, content
916 type HTTP_CONTENT_TYPE_APP_JSON will be used.
917 @param[out] Response HTTP response from redfish service.
918
919 @retval EFI_SUCCESS Resource is returned successfully.
920 @retval Others Errors occur.
921
922**/
923EFI_STATUS
924EFIAPI
925RedfishPutResource (
926 IN EDKII_REDFISH_HTTP_PROTOCOL *This,
927 IN REDFISH_SERVICE Service,
928 IN EFI_STRING Uri,
929 IN CHAR8 *Content,
930 IN UINTN ContentSize OPTIONAL,
931 IN CHAR8 *ContentType OPTIONAL,
932 OUT REDFISH_RESPONSE *Response
933 )
934{
935 EFI_STATUS Status;
936 UINTN RetryCount;
937 REDFISH_REQUEST Request;
938 REDFISH_HTTP_CACHE_PRIVATE *Private;
939
940 if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
941 return EFI_INVALID_PARAMETER;
942 }
943
944 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Put URI: %s\n", __func__, Uri));
945
946 Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
947 RetryCount = 0;
948 ZeroMem (Response, sizeof (REDFISH_RESPONSE));
949 ZeroMem (&Request, sizeof (REDFISH_REQUEST));
950
951 Request.Content = Content;
952 Request.ContentLength = ContentSize;
953 Request.ContentType = ContentType;
954
955 //
956 // Patch resource to redfish service.
957 //
958 do {
959 RetryCount += 1;
960 Status = HttpSendReceive (
961 Service,
962 Uri,
963 HttpMethodPut,
964 &Request,
965 Response
966 );
967 DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
968 if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryPut)) {
969 break;
970 }
971
972 //
973 // Retry when BMC is not ready.
974 //
975 if ((Response->StatusCode != NULL)) {
976 DEBUG_CODE (
977 DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
978 );
979
980 if (!RedfishRetryRequired (Response->StatusCode)) {
981 break;
982 }
983
984 //
985 // Release response for next round of request.
986 //
987 This->FreeResponse (This, Response);
988 }
989
990 DEBUG ((DEBUG_WARN, "%a: RedfishPutToUri failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryPut));
991 if (Private->RetrySetting.RetryWait > 0) {
992 gBS->Stall (Private->RetrySetting.RetryWait);
993 }
994 } while (TRUE);
995
996 //
997 // Redfish resource is updated. Automatically expire the cached response
998 // so application can directly get resource from Redfish service again.
999 //
1000 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
1001 RedfishExpireResponse (This, Uri);
1002
1003 if (EFI_ERROR (Status) || !RedfishSuccessResponse (HttpMethodPut, Response->StatusCode)) {
1004 DEBUG_CODE (
1005 DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
1006 );
1007 //
1008 // Report status code for Redfish failure
1009 //
1010 ReportHttpError (HttpMethodPut, Uri, Response->StatusCode);
1011 DEBUG ((DEBUG_ERROR, "%a: put %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryPut, Status));
1012 goto ON_RELEASE;
1013 }
1014
1015ON_RELEASE:
1016
1017 return Status;
1018}
1019
1020/**
1021 Perform HTTP POST to send redfish resource to given resource URI.
1022 It's caller's responsibility to free Response by calling FreeResponse ().
1023
1024 @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
1025 @param[in] Service Redfish service instance to perform HTTP POST.
1026 @param[in] Uri Target resource URI.
1027 @param[in] Content Data to post.
1028 @param[in] ContentSize Size of the Content to be send to Redfish service.
1029 This is optional. When ContentSize is 0, ContentSize
1030 is the size of Content.
1031 @param[in] ContentType Type of the Content to be send to Redfish service.
1032 This is optional. When ContentType is NULL, content
1033 type HTTP_CONTENT_TYPE_APP_JSON will be used.
1034 @param[out] Response HTTP response from redfish service.
1035
1036 @retval EFI_SUCCESS Resource is returned successfully.
1037 @retval Others Errors occur.
1038
1039**/
1040EFI_STATUS
1041EFIAPI
1042RedfishPostResource (
1043 IN EDKII_REDFISH_HTTP_PROTOCOL *This,
1044 IN REDFISH_SERVICE Service,
1045 IN EFI_STRING Uri,
1046 IN CHAR8 *Content,
1047 IN UINTN ContentSize OPTIONAL,
1048 IN CHAR8 *ContentType OPTIONAL,
1049 OUT REDFISH_RESPONSE *Response
1050 )
1051{
1052 EFI_STATUS Status;
1053 UINTN RetryCount;
1054 REDFISH_REQUEST Request;
1055 REDFISH_HTTP_CACHE_PRIVATE *Private;
1056
1057 if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (Content)) {
1058 return EFI_INVALID_PARAMETER;
1059 }
1060
1061 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Post URI: %s\n", __func__, Uri));
1062
1063 Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
1064 RetryCount = 0;
1065 ZeroMem (Response, sizeof (REDFISH_RESPONSE));
1066 ZeroMem (&Request, sizeof (REDFISH_REQUEST));
1067
1068 Request.Content = Content;
1069 Request.ContentLength = ContentSize;
1070 Request.ContentType = ContentType;
1071
1072 //
1073 // Patch resource to redfish service.
1074 //
1075 do {
1076 RetryCount += 1;
1077 Status = HttpSendReceive (
1078 Service,
1079 Uri,
1080 HttpMethodPost,
1081 &Request,
1082 Response
1083 );
1084 DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
1085 if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryPost)) {
1086 break;
1087 }
1088
1089 //
1090 // Retry when BMC is not ready.
1091 //
1092 if ((Response->StatusCode != NULL)) {
1093 DEBUG_CODE (
1094 DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
1095 );
1096
1097 if (!RedfishRetryRequired (Response->StatusCode)) {
1098 break;
1099 }
1100
1101 //
1102 // Release response for next round of request.
1103 //
1104 This->FreeResponse (This, Response);
1105 }
1106
1107 DEBUG ((DEBUG_WARN, "%a: RedfishPostToUri failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryPost));
1108 if (Private->RetrySetting.RetryWait > 0) {
1109 gBS->Stall (Private->RetrySetting.RetryWait);
1110 }
1111 } while (TRUE);
1112
1113 //
1114 // Redfish resource is updated. Automatically expire the cached response
1115 // so application can directly get resource from Redfish service again.
1116 //
1117 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
1118 RedfishExpireResponse (This, Uri);
1119
1120 if (EFI_ERROR (Status) || !RedfishSuccessResponse (HttpMethodPost, Response->StatusCode)) {
1121 DEBUG_CODE (
1122 DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
1123 );
1124 //
1125 // Report status code for Redfish failure
1126 //
1127 ReportHttpError (HttpMethodPost, Uri, Response->StatusCode);
1128 DEBUG ((DEBUG_ERROR, "%a: post %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryPost, Status));
1129 goto ON_RELEASE;
1130 }
1131
1132ON_RELEASE:
1133
1134 return Status;
1135}
1136
1137/**
1138 Perform HTTP DELETE to delete redfish resource on given resource URI.
1139 It's caller's responsibility to free Response by calling FreeResponse ().
1140
1141 @param[in] This Pointer to EDKII_REDFISH_HTTP_PROTOCOL instance.
1142 @param[in] Service Redfish service instance to perform HTTP DELETE.
1143 @param[in] Uri Target resource URI.
1144 @param[in] Content JSON represented properties to be deleted. This is
1145 optional.
1146 @param[in] ContentSize Size of the Content to be send to Redfish service.
1147 This is optional. When ContentSize is 0, ContentSize
1148 is the size of Content if Content is not NULL.
1149 @param[in] ContentType Type of the Content to be send to Redfish service.
1150 This is optional. When Content is not NULL and
1151 ContentType is NULL, content type HTTP_CONTENT_TYPE_APP_JSON
1152 will be used.
1153 @param[out] Response HTTP response from redfish service.
1154
1155 @retval EFI_SUCCESS Resource is returned successfully.
1156 @retval Others Errors occur.
1157
1158**/
1159EFI_STATUS
1160EFIAPI
1161RedfishDeleteResource (
1162 IN EDKII_REDFISH_HTTP_PROTOCOL *This,
1163 IN REDFISH_SERVICE Service,
1164 IN EFI_STRING Uri,
1165 IN CHAR8 *Content OPTIONAL,
1166 IN UINTN ContentSize OPTIONAL,
1167 IN CHAR8 *ContentType OPTIONAL,
1168 OUT REDFISH_RESPONSE *Response
1169 )
1170{
1171 EFI_STATUS Status;
1172 UINTN RetryCount;
1173 REDFISH_REQUEST Request;
1174 REDFISH_HTTP_CACHE_PRIVATE *Private;
1175
1176 if ((This == NULL) || (Service == NULL) || (Response == NULL) || IS_EMPTY_STRING (Uri)) {
1177 return EFI_INVALID_PARAMETER;
1178 }
1179
1180 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Delete URI: %s\n", __func__, Uri));
1181
1182 Private = REDFISH_HTTP_CACHE_PRIVATE_FROM_THIS (This);
1183 RetryCount = 0;
1184 ZeroMem (Response, sizeof (REDFISH_RESPONSE));
1185 ZeroMem (&Request, sizeof (REDFISH_REQUEST));
1186
1187 Request.Content = Content;
1188 Request.ContentLength = ContentSize;
1189 Request.ContentType = ContentType;
1190
1191 //
1192 // Patch resource to redfish service.
1193 //
1194 do {
1195 RetryCount += 1;
1196 Status = HttpSendReceive (
1197 Service,
1198 Uri,
1199 HttpMethodDelete,
1200 &Request,
1201 Response
1202 );
1203 DEBUG ((REDFISH_HTTP_CACHE_DEBUG_REQUEST, "%a: HTTP request: %s :%r\n", __func__, Uri, Status));
1204 if (!EFI_ERROR (Status) || (RetryCount >= Private->RetrySetting.MaximumRetryDelete)) {
1205 break;
1206 }
1207
1208 //
1209 // Retry when BMC is not ready.
1210 //
1211 if ((Response->StatusCode != NULL)) {
1212 DEBUG_CODE (
1213 DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
1214 );
1215
1216 if (!RedfishRetryRequired (Response->StatusCode)) {
1217 break;
1218 }
1219
1220 //
1221 // Release response for next round of request.
1222 //
1223 This->FreeResponse (This, Response);
1224 }
1225
1226 DEBUG ((DEBUG_WARN, "%a: RedfishDeleteByUri failed, retry (%d/%d)\n", __func__, RetryCount, Private->RetrySetting.MaximumRetryDelete));
1227 if (Private->RetrySetting.RetryWait > 0) {
1228 gBS->Stall (Private->RetrySetting.RetryWait);
1229 }
1230 } while (TRUE);
1231
1232 //
1233 // Redfish resource is updated. Automatically expire the cached response
1234 // so application can directly get resource from Redfish service again.
1235 //
1236 DEBUG ((REDFISH_HTTP_CACHE_DEBUG, "%a: Resource is updated, expire URI: %s\n", __func__, Uri));
1237 RedfishExpireResponse (This, Uri);
1238
1239 if (EFI_ERROR (Status) || !RedfishSuccessResponse (HttpMethodDelete, Response->StatusCode)) {
1240 DEBUG_CODE (
1241 DumpRedfishResponse (NULL, DEBUG_ERROR, Response);
1242 );
1243 //
1244 // Report status code for Redfish failure
1245 //
1246 ReportHttpError (HttpMethodDelete, Uri, Response->StatusCode);
1247 DEBUG ((DEBUG_ERROR, "%a: delete %s failed (%d/%d): %r\n", __func__, Uri, RetryCount, Private->RetrySetting.MaximumRetryDelete, Status));
1248 goto ON_RELEASE;
1249 }
1250
1251ON_RELEASE:
1252
1253 return Status;
1254}
1255
1256EDKII_REDFISH_HTTP_PROTOCOL mEdkIIRedfishHttpProtocol = {
1257 EDKII_REDFISH_HTTP_PROTOCOL_REVISION,
1258 RedfishCreateRedfishService,
1259 RedfishFreeRedfishService,
1260 RedfishJsonInRedfishPayload,
1261 RedfishGetResource,
1262 RedfishPatchResource,
1263 RedfishPutResource,
1264 RedfishPostResource,
1265 RedfishDeleteResource,
1266 RedfishFreeRequest,
1267 RedfishFreeResponse,
1268 RedfishExpireResponse
1269};
1270
1271/**
1272 Unloads an image.
1273
1274 @param[in] ImageHandle Handle that identifies the image to be unloaded.
1275
1276 @retval EFI_SUCCESS The image has been unloaded.
1277 @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
1278
1279**/
1280EFI_STATUS
1281EFIAPI
1282RedfishHttpDriverUnload (
1283 IN EFI_HANDLE ImageHandle
1284 )
1285{
1286 if (mRedfishHttpCachePrivate == NULL) {
1287 return EFI_SUCCESS;
1288 }
1289
1290 if (!IsListEmpty (&mRedfishHttpCachePrivate->CacheList.Head)) {
1291 ReleaseCacheList (&mRedfishHttpCachePrivate->CacheList);
1292 }
1293
1294 gBS->UninstallMultipleProtocolInterfaces (
1295 ImageHandle,
1296 &gEdkIIRedfishHttpProtocolGuid,
1297 &mRedfishHttpCachePrivate->Protocol,
1298 NULL
1299 );
1300
1301 FreePool (mRedfishHttpCachePrivate);
1302 mRedfishHttpCachePrivate = NULL;
1303
1304 return EFI_SUCCESS;
1305}
1306
1307/**
1308 This is a EDKII_REDFISH_CREDENTIAL_PROTOCOL notification event handler.
1309
1310 @param[in] Event Event whose notification function is being invoked.
1311 @param[in] Context Pointer to the notification function's context.
1312
1313**/
1314VOID
1315EFIAPI
1316CredentialProtocolInstalled (
1317 IN EFI_EVENT Event,
1318 IN VOID *Context
1319 )
1320{
1321 EFI_STATUS Status;
1322 REDFISH_HTTP_CACHE_PRIVATE *Private;
1323
1324 Private = (REDFISH_HTTP_CACHE_PRIVATE *)Context;
1325 if (Private->Signature != REDFISH_HTTP_DRIVER_SIGNATURE) {
1326 DEBUG ((DEBUG_ERROR, "%a: signature check failure\n", __func__));
1327 return;
1328 }
1329
1330 //
1331 // Locate HII credential protocol.
1332 //
1333 Status = gBS->LocateProtocol (
1334 &gEdkIIRedfishCredential2ProtocolGuid,
1335 NULL,
1336 (VOID **)&Private->CredentialProtocol
1337 );
1338 if (EFI_ERROR (Status)) {
1339 return;
1340 }
1341
1342 gBS->CloseEvent (Event);
1343}
1344
1345/**
1346 Main entry for this driver.
1347
1348 @param[in] ImageHandle Image handle this driver.
1349 @param[in] SystemTable Pointer to SystemTable.
1350
1351 @retval EFI_SUCCESS This function always complete successfully.
1352
1353**/
1354EFI_STATUS
1355EFIAPI
1356RedfishHttpEntryPoint (
1357 IN EFI_HANDLE ImageHandle,
1358 IN EFI_SYSTEM_TABLE *SystemTable
1359 )
1360{
1361 EFI_STATUS Status;
1362 VOID *Registration;
1363
1364 if (mRedfishHttpCachePrivate != NULL) {
1365 return EFI_ALREADY_STARTED;
1366 }
1367
1368 mRedfishHttpCachePrivate = AllocateZeroPool (sizeof (REDFISH_HTTP_CACHE_PRIVATE));
1369 if (mRedfishHttpCachePrivate == NULL) {
1370 return EFI_OUT_OF_RESOURCES;
1371 }
1372
1373 //
1374 // Initial cache list and protocol instance.
1375 //
1376 mRedfishHttpCachePrivate->Signature = REDFISH_HTTP_DRIVER_SIGNATURE;
1377 mRedfishHttpCachePrivate->ImageHandle = ImageHandle;
1378 CopyMem (&mRedfishHttpCachePrivate->Protocol, &mEdkIIRedfishHttpProtocol, sizeof (EDKII_REDFISH_HTTP_PROTOCOL));
1379 mRedfishHttpCachePrivate->CacheList.Capacity = REDFISH_HTTP_CACHE_LIST_SIZE;
1380 mRedfishHttpCachePrivate->CacheList.Count = 0x00;
1381 mRedfishHttpCachePrivate->CacheDisabled = PcdGetBool (PcdHttpCacheDisabled);
1382 InitializeListHead (&mRedfishHttpCachePrivate->CacheList.Head);
1383
1384 //
1385 // Get retry settings
1386 //
1387 mRedfishHttpCachePrivate->RetrySetting.MaximumRetryGet = PcdGet16 (PcdHttpGetRetry);
1388 mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPut = PcdGet16 (PcdHttpPutRetry);
1389 mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPatch = PcdGet16 (PcdHttpPatchRetry);
1390 mRedfishHttpCachePrivate->RetrySetting.MaximumRetryPost = PcdGet16 (PcdHttpPostRetry);
1391 mRedfishHttpCachePrivate->RetrySetting.MaximumRetryDelete = PcdGet16 (PcdHttpDeleteRetry);
1392 mRedfishHttpCachePrivate->RetrySetting.RetryWait = PcdGet16 (PcdHttpRetryWaitInSecond) * 1000000U;
1393
1394 //
1395 // Install the gEdkIIRedfishHttpProtocolGuid onto Handle.
1396 //
1397 Status = gBS->InstallMultipleProtocolInterfaces (
1398 &mRedfishHttpCachePrivate->ImageHandle,
1399 &gEdkIIRedfishHttpProtocolGuid,
1400 &mRedfishHttpCachePrivate->Protocol,
1401 NULL
1402 );
1403 if (EFI_ERROR (Status)) {
1404 DEBUG ((DEBUG_ERROR, "%a: cannot install Redfish http protocol: %r\n", __func__, Status));
1405 RedfishHttpDriverUnload (ImageHandle);
1406 return Status;
1407 }
1408
1409 //
1410 // Install protocol notification if credential protocol is installed.
1411 //
1412 mRedfishHttpCachePrivate->NotifyEvent = EfiCreateProtocolNotifyEvent (
1413 &gEdkIIRedfishCredential2ProtocolGuid,
1414 TPL_CALLBACK,
1415 CredentialProtocolInstalled,
1416 mRedfishHttpCachePrivate,
1417 &Registration
1418 );
1419 if (mRedfishHttpCachePrivate->NotifyEvent == NULL) {
1420 DEBUG ((DEBUG_ERROR, "%a: failed to create protocol notification for gEdkIIRedfishCredential2ProtocolGuid\n", __func__));
1421 ASSERT (FALSE);
1422 RedfishHttpDriverUnload (ImageHandle);
1423 return Status;
1424 }
1425
1426 return EFI_SUCCESS;
1427}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette