2 Support functions implementation for UEFI HTTP boot driver.
4 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available under
6 the terms and conditions of the BSD License that accompanies this distribution.
7 The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
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.
15 #include "HttpBootDxe.h"
19 Get the Nic handle using any child handle in the IPv4 stack.
21 @param[in] ControllerHandle Pointer to child handle over IPv4.
23 @return NicHandle The pointer to the Nic handle.
24 @return NULL Can't find the Nic handle.
28 HttpBootGetNicByIp4Children (
29 IN EFI_HANDLE ControllerHandle
34 NicHandle
= NetLibGetNicHandle (ControllerHandle
, &gEfiHttpProtocolGuid
);
35 if (NicHandle
== NULL
) {
36 NicHandle
= NetLibGetNicHandle (ControllerHandle
, &gEfiDhcp4ProtocolGuid
);
37 if (NicHandle
== NULL
) {
47 This function is to convert UINTN to ASCII string with the required formatting.
49 @param[in] Number Numeric value to be converted.
50 @param[in] Buffer The pointer to the buffer for ASCII string.
51 @param[in] Length The length of the required format.
55 HttpBootUintnToAscDecWithFormat (
65 Remainder
= Number
% 10;
67 Buffer
[Length
] = (UINT8
) ('0' + Remainder
);
72 This function is to display the IPv4 address.
74 @param[in] Ip The pointer to the IPv4 address.
79 IN EFI_IPv4_ADDRESS
*Ip
84 for (Index
= 0; Index
< 4; Index
++) {
85 AsciiPrint ("%d", Ip
->Addr
[Index
]);
93 Create a HTTP_IO_HEADER to hold the HTTP header items.
95 @param[in] MaxHeaderCount The maximun number of HTTP header in this holder.
97 @return A pointer of the HTTP header holder or NULL if failed.
101 HttpBootCreateHeader (
105 HTTP_IO_HEADER
*HttpIoHeader
;
107 if (MaxHeaderCount
== 0) {
111 HttpIoHeader
= AllocateZeroPool (sizeof (HTTP_IO_HEADER
) + MaxHeaderCount
* sizeof (EFI_HTTP_HEADER
));
112 if (HttpIoHeader
== NULL
) {
116 HttpIoHeader
->MaxHeaderCount
= MaxHeaderCount
;
117 HttpIoHeader
->Headers
= (EFI_HTTP_HEADER
*) (HttpIoHeader
+ 1);
123 Destroy the HTTP_IO_HEADER and release the resouces.
125 @param[in] HttpIoHeader Point to the HTTP header holder to be destroyed.
130 IN HTTP_IO_HEADER
*HttpIoHeader
135 if (HttpIoHeader
!= NULL
) {
136 if (HttpIoHeader
->HeaderCount
!= 0) {
137 for (Index
= 0; Index
< HttpIoHeader
->HeaderCount
; Index
++) {
138 FreePool (HttpIoHeader
->Headers
[Index
].FieldName
);
139 FreePool (HttpIoHeader
->Headers
[Index
].FieldValue
);
142 FreePool (HttpIoHeader
);
147 Find a specified header field according to the field name.
149 @param[in] HeaderCount Number of HTTP header structures in Headers list.
150 @param[in] Headers Array containing list of HTTP headers.
151 @param[in] FieldName Null terminated string which describes a field name.
153 @return Pointer to the found header or NULL.
158 IN UINTN HeaderCount
,
159 IN EFI_HTTP_HEADER
*Headers
,
165 if (HeaderCount
== 0 || Headers
== NULL
|| FieldName
== NULL
) {
169 for (Index
= 0; Index
< HeaderCount
; Index
++){
171 // Field names are case-insensitive (RFC 2616).
173 if (AsciiStriCmp (Headers
[Index
].FieldName
, FieldName
) == 0) {
174 return &Headers
[Index
];
181 Set or update a HTTP header with the field name and corresponding value.
183 @param[in] HttpIoHeader Point to the HTTP header holder.
184 @param[in] FieldName Null terminated string which describes a field name.
185 @param[in] FieldValue Null terminated string which describes the corresponding field value.
187 @retval EFI_SUCCESS The HTTP header has been set or updated.
188 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
189 @retval EFI_OUT_OF_RESOURCES Insufficient resource to complete the operation.
190 @retval Other Unexpected error happened.
195 IN HTTP_IO_HEADER
*HttpIoHeader
,
200 EFI_HTTP_HEADER
*Header
;
202 CHAR8
*NewFieldValue
;
204 if (HttpIoHeader
== NULL
|| FieldName
== NULL
|| FieldValue
== NULL
) {
205 return EFI_INVALID_PARAMETER
;
208 Header
= HttpBootFindHeader (HttpIoHeader
->HeaderCount
, HttpIoHeader
->Headers
, FieldName
);
209 if (Header
== NULL
) {
213 if (HttpIoHeader
->HeaderCount
>= HttpIoHeader
->MaxHeaderCount
) {
214 return EFI_OUT_OF_RESOURCES
;
216 Header
= &HttpIoHeader
->Headers
[HttpIoHeader
->HeaderCount
];
218 StrSize
= AsciiStrSize (FieldName
);
219 Header
->FieldName
= AllocatePool (StrSize
);
220 if (Header
->FieldName
== NULL
) {
221 return EFI_OUT_OF_RESOURCES
;
223 CopyMem (Header
->FieldName
, FieldName
, StrSize
);
224 Header
->FieldName
[StrSize
-1] = '\0';
226 StrSize
= AsciiStrSize (FieldValue
);
227 Header
->FieldValue
= AllocatePool (StrSize
);
228 if (Header
->FieldValue
== NULL
) {
229 FreePool (Header
->FieldName
);
230 return EFI_OUT_OF_RESOURCES
;
232 CopyMem (Header
->FieldValue
, FieldValue
, StrSize
);
233 Header
->FieldValue
[StrSize
-1] = '\0';
235 HttpIoHeader
->HeaderCount
++;
238 // Update an existing one.
240 StrSize
= AsciiStrSize (FieldValue
);
241 NewFieldValue
= AllocatePool (StrSize
);
242 if (NewFieldValue
== NULL
) {
243 return EFI_OUT_OF_RESOURCES
;
245 CopyMem (NewFieldValue
, FieldValue
, StrSize
);
246 NewFieldValue
[StrSize
-1] = '\0';
248 if (Header
->FieldValue
!= NULL
) {
249 FreePool (Header
->FieldValue
);
251 Header
->FieldValue
= NewFieldValue
;
258 Notify the callback function when an event is triggered.
260 @param[in] Event The triggered event.
261 @param[in] Context The opaque parameter to the function.
271 *((BOOLEAN
*) Context
) = TRUE
;
275 Create a HTTP_IO to access the HTTP service. It will create and configure
278 @param[in] Image The handle of the driver image.
279 @param[in] Controller The handle of the controller.
280 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
281 @param[in] ConfigData The HTTP_IO configuration data.
282 @param[out] HttpIo The HTTP_IO.
284 @retval EFI_SUCCESS The HTTP_IO is created and configured.
285 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
286 @retval EFI_UNSUPPORTED One or more of the control options are not
287 supported in the implementation.
288 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
289 @retval Others Failed to create the HTTP_IO or configure it.
295 IN EFI_HANDLE Controller
,
297 IN HTTP_IO_CONFIG_DATA
*ConfigData
,
302 EFI_HTTP_CONFIG_DATA HttpConfigData
;
303 EFI_HTTPv4_ACCESS_POINT Http4AccessPoint
;
304 EFI_HTTP_PROTOCOL
*Http
;
307 if ((Image
== NULL
) || (Controller
== NULL
) || (ConfigData
== NULL
) || (HttpIo
== NULL
)) {
308 return EFI_INVALID_PARAMETER
;
311 if (IpVersion
!= IP_VERSION_4
&& IpVersion
!= IP_VERSION_6
) {
312 return EFI_UNSUPPORTED
;
315 ZeroMem (HttpIo
, sizeof (HTTP_IO
));
318 // Create the HTTP child instance and get the HTTP protocol.
320 Status
= NetLibCreateServiceChild (
323 &gEfiHttpServiceBindingProtocolGuid
,
326 if (EFI_ERROR (Status
)) {
330 Status
= gBS
->OpenProtocol (
332 &gEfiHttpProtocolGuid
,
336 EFI_OPEN_PROTOCOL_BY_DRIVER
338 if (EFI_ERROR (Status
) || (Http
== NULL
)) {
343 // Init the configuration data and configure the HTTP child.
345 HttpIo
->Image
= Image
;
346 HttpIo
->Controller
= Controller
;
347 HttpIo
->IpVersion
= IpVersion
;
350 ZeroMem (&HttpConfigData
, sizeof (EFI_HTTP_CONFIG_DATA
));
351 HttpConfigData
.HttpVersion
= HttpVersion11
;
352 HttpConfigData
.TimeOutMillisec
= ConfigData
->Config4
.RequestTimeOut
;
353 if (HttpIo
->IpVersion
== IP_VERSION_4
) {
354 HttpConfigData
.LocalAddressIsIPv6
= FALSE
;
356 Http4AccessPoint
.UseDefaultAddress
= ConfigData
->Config4
.UseDefaultAddress
;
357 Http4AccessPoint
.LocalPort
= ConfigData
->Config4
.LocalPort
;
358 IP4_COPY_ADDRESS (&Http4AccessPoint
.LocalAddress
, &ConfigData
->Config4
.LocalIp
);
359 IP4_COPY_ADDRESS (&Http4AccessPoint
.LocalSubnet
, &ConfigData
->Config4
.SubnetMask
);
360 HttpConfigData
.AccessPoint
.IPv4Node
= &Http4AccessPoint
;
365 Status
= Http
->Configure (Http
, &HttpConfigData
);
366 if (EFI_ERROR (Status
)) {
371 // Create events for variuos asynchronous operations.
373 Status
= gBS
->CreateEvent (
380 if (EFI_ERROR (Status
)) {
383 HttpIo
->ReqToken
.Event
= Event
;
384 HttpIo
->ReqToken
.Message
= &HttpIo
->ReqMessage
;
386 Status
= gBS
->CreateEvent (
393 if (EFI_ERROR (Status
)) {
396 HttpIo
->RspToken
.Event
= Event
;
397 HttpIo
->RspToken
.Message
= &HttpIo
->RspMessage
;
402 HttpIoDestroyIo (HttpIo
);
408 Destroy the HTTP_IO and release the resouces.
410 @param[in] HttpIo The HTTP_IO which wraps the HTTP service to be destroyed.
418 EFI_HTTP_PROTOCOL
*Http
;
421 if (HttpIo
== NULL
) {
425 Event
= HttpIo
->ReqToken
.Event
;
427 gBS
->CloseEvent (Event
);
430 Event
= HttpIo
->RspToken
.Event
;
432 gBS
->CloseEvent (Event
);
437 Http
->Configure (Http
, NULL
);
440 &gEfiHttpProtocolGuid
,
446 NetLibDestroyServiceChild (
449 &gEfiHttpServiceBindingProtocolGuid
,
455 Synchronously send a HTTP REQUEST message to the server.
457 @param[in] HttpIo The HttpIo wrapping the HTTP service.
458 @param[in] Request A pointer to storage such data as URL and HTTP method.
459 @param[in] HeaderCount Number of HTTP header structures in Headers list.
460 @param[in] Headers Array containing list of HTTP headers.
461 @param[in] BodyLength Length in bytes of the HTTP body.
462 @param[in] Body Body associated with the HTTP request.
464 @retval EFI_SUCCESS The HTTP request is trasmitted.
465 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
466 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
467 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
468 @retval Others Other errors as indicated.
474 IN EFI_HTTP_REQUEST_DATA
*Request
,
475 IN UINTN HeaderCount
,
476 IN EFI_HTTP_HEADER
*Headers
,
482 EFI_HTTP_PROTOCOL
*Http
;
484 if (HttpIo
== NULL
|| HttpIo
->Http
== NULL
) {
485 return EFI_INVALID_PARAMETER
;
488 HttpIo
->ReqToken
.Status
= EFI_NOT_READY
;
489 HttpIo
->ReqToken
.Message
->Data
.Request
= Request
;
490 HttpIo
->ReqToken
.Message
->HeaderCount
= HeaderCount
;
491 HttpIo
->ReqToken
.Message
->Headers
= Headers
;
492 HttpIo
->ReqToken
.Message
->BodyLength
= BodyLength
;
493 HttpIo
->ReqToken
.Message
->Body
= Body
;
496 // Queue the request token to HTTP instances.
499 HttpIo
->IsTxDone
= FALSE
;
500 Status
= Http
->Request (
504 if (EFI_ERROR (Status
)) {
509 // Poll the network until transmit finish.
511 while (!HttpIo
->IsTxDone
) {
515 return HttpIo
->ReqToken
.Status
;
519 Synchronously receive a HTTP RESPONSE message from the server.
521 @param[in] HttpIo The HttpIo wrapping the HTTP service.
522 @param[in] RecvMsgHeader TRUE to receive a new HTTP response (from message header).
523 FALSE to continue receive the previous response message.
524 @param[out] ResponseData Point to a wrapper of the received response data.
526 @retval EFI_SUCCESS The HTTP resopnse is received.
527 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
528 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
529 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
530 @retval Others Other errors as indicated.
536 IN BOOLEAN RecvMsgHeader
,
537 OUT HTTP_IO_RESOPNSE_DATA
*ResponseData
541 EFI_HTTP_PROTOCOL
*Http
;
543 if (HttpIo
== NULL
|| HttpIo
->Http
== NULL
|| ResponseData
== NULL
) {
544 return EFI_INVALID_PARAMETER
;
548 // Queue the response token to HTTP instances.
550 HttpIo
->RspToken
.Status
= EFI_NOT_READY
;
552 HttpIo
->RspToken
.Message
->Data
.Response
= &ResponseData
->Response
;
554 HttpIo
->RspToken
.Message
->Data
.Response
= NULL
;
556 HttpIo
->RspToken
.Message
->HeaderCount
= 0;
557 HttpIo
->RspToken
.Message
->Headers
= NULL
;
558 HttpIo
->RspToken
.Message
->BodyLength
= ResponseData
->BodyLength
;
559 HttpIo
->RspToken
.Message
->Body
= ResponseData
->Body
;
562 HttpIo
->IsRxDone
= FALSE
;
563 Status
= Http
->Response (
568 if (EFI_ERROR (Status
)) {
573 // Poll the network until transmit finish.
575 while (!HttpIo
->IsRxDone
) {
580 // Store the received data into the wrapper.
582 Status
= HttpIo
->ReqToken
.Status
;
583 if (!EFI_ERROR (Status
)) {
584 ResponseData
->HeaderCount
= HttpIo
->RspToken
.Message
->HeaderCount
;
585 ResponseData
->Headers
= HttpIo
->RspToken
.Message
->Headers
;
586 ResponseData
->BodyLength
= HttpIo
->RspToken
.Message
->BodyLength
;