]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootSupport.c
MdePkg: Convert the UNIX to DOS end of line format
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootSupport.c
CommitLineData
c4545d76
FS
1/** @file
2 Support functions implementation for UEFI HTTP boot driver.
3
4Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials are licensed and made available under
6the terms and conditions of the BSD License that accompanies this distribution.
7The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php.
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "HttpBootDxe.h"
16
17
18/**
19 Get the Nic handle using any child handle in the IPv4 stack.
20
21 @param[in] ControllerHandle Pointer to child handle over IPv4.
22
23 @return NicHandle The pointer to the Nic handle.
24 @return NULL Can't find the Nic handle.
25
26**/
27EFI_HANDLE
28HttpBootGetNicByIp4Children (
29 IN EFI_HANDLE ControllerHandle
30 )
31{
32 EFI_HANDLE NicHandle;
33
34 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiHttpProtocolGuid);
35 if (NicHandle == NULL) {
36 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);
37 if (NicHandle == NULL) {
38 return NULL;
39 }
40 }
41
42 return NicHandle;
43}
44
45
46/**
47 This function is to convert UINTN to ASCII string with the required formatting.
48
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.
52
53**/
54VOID
55HttpBootUintnToAscDecWithFormat (
56 IN UINTN Number,
57 IN UINT8 *Buffer,
58 IN INTN Length
59 )
60{
61 UINTN Remainder;
62
63 while (Length > 0) {
64 Length--;
65 Remainder = Number % 10;
66 Number /= 10;
67 Buffer[Length] = (UINT8) ('0' + Remainder);
68 }
69}
70
71/**
72 This function is to display the IPv4 address.
73
74 @param[in] Ip The pointer to the IPv4 address.
75
76**/
77VOID
78HttpBootShowIp4Addr (
79 IN EFI_IPv4_ADDRESS *Ip
80 )
81{
82 UINTN Index;
83
84 for (Index = 0; Index < 4; Index++) {
85 AsciiPrint ("%d", Ip->Addr[Index]);
86 if (Index < 3) {
87 AsciiPrint (".");
88 }
89 }
90}
91
92/**
93 Create a HTTP_IO_HEADER to hold the HTTP header items.
94
95 @param[in] MaxHeaderCount The maximun number of HTTP header in this holder.
96
97 @return A pointer of the HTTP header holder or NULL if failed.
98
99**/
100HTTP_IO_HEADER *
101HttpBootCreateHeader (
102 UINTN MaxHeaderCount
103)
104{
105 HTTP_IO_HEADER *HttpIoHeader;
106
107 if (MaxHeaderCount == 0) {
108 return NULL;
109 }
110
111 HttpIoHeader = AllocateZeroPool (sizeof (HTTP_IO_HEADER) + MaxHeaderCount * sizeof (EFI_HTTP_HEADER));
112 if (HttpIoHeader == NULL) {
113 return NULL;
114 }
115
116 HttpIoHeader->MaxHeaderCount = MaxHeaderCount;
117 HttpIoHeader->Headers = (EFI_HTTP_HEADER *) (HttpIoHeader + 1);
118
119 return HttpIoHeader;
120}
121
122/**
123 Destroy the HTTP_IO_HEADER and release the resouces.
124
125 @param[in] HttpIoHeader Point to the HTTP header holder to be destroyed.
126
127**/
128VOID
129HttpBootFreeHeader (
130 IN HTTP_IO_HEADER *HttpIoHeader
131 )
132{
133 UINTN Index;
134
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);
140 }
141 }
142 FreePool (HttpIoHeader);
143 }
144}
145
146/**
147 Find a specified header field according to the field name.
148
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.
152
153 @return Pointer to the found header or NULL.
154
155**/
156EFI_HTTP_HEADER *
157HttpBootFindHeader (
158 IN UINTN HeaderCount,
159 IN EFI_HTTP_HEADER *Headers,
160 IN CHAR8 *FieldName
161 )
162{
163 UINTN Index;
164
165 if (HeaderCount == 0 || Headers == NULL || FieldName == NULL) {
166 return NULL;
167 }
168
169 for (Index = 0; Index < HeaderCount; Index++){
170 //
171 // Field names are case-insensitive (RFC 2616).
172 //
173 if (AsciiStriCmp (Headers[Index].FieldName, FieldName) == 0) {
174 return &Headers[Index];
175 }
176 }
177 return NULL;
178}
179
180/**
181 Set or update a HTTP header with the field name and corresponding value.
182
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.
186
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.
191
192**/
193EFI_STATUS
194HttpBootSetHeader (
195 IN HTTP_IO_HEADER *HttpIoHeader,
196 IN CHAR8 *FieldName,
197 IN CHAR8 *FieldValue
198 )
199{
200 EFI_HTTP_HEADER *Header;
201 UINTN StrSize;
202 CHAR8 *NewFieldValue;
203
204 if (HttpIoHeader == NULL || FieldName == NULL || FieldValue == NULL) {
205 return EFI_INVALID_PARAMETER;
206 }
207
208 Header = HttpBootFindHeader (HttpIoHeader->HeaderCount, HttpIoHeader->Headers, FieldName);
209 if (Header == NULL) {
210 //
211 // Add a new header.
212 //
213 if (HttpIoHeader->HeaderCount >= HttpIoHeader->MaxHeaderCount) {
214 return EFI_OUT_OF_RESOURCES;
215 }
216 Header = &HttpIoHeader->Headers[HttpIoHeader->HeaderCount];
217
218 StrSize = AsciiStrSize (FieldName);
219 Header->FieldName = AllocatePool (StrSize);
220 if (Header->FieldName == NULL) {
221 return EFI_OUT_OF_RESOURCES;
222 }
223 CopyMem (Header->FieldName, FieldName, StrSize);
224 Header->FieldName[StrSize -1] = '\0';
225
226 StrSize = AsciiStrSize (FieldValue);
227 Header->FieldValue = AllocatePool (StrSize);
228 if (Header->FieldValue == NULL) {
229 FreePool (Header->FieldName);
230 return EFI_OUT_OF_RESOURCES;
231 }
232 CopyMem (Header->FieldValue, FieldValue, StrSize);
233 Header->FieldValue[StrSize -1] = '\0';
234
235 HttpIoHeader->HeaderCount++;
236 } else {
237 //
238 // Update an existing one.
239 //
240 StrSize = AsciiStrSize (FieldValue);
241 NewFieldValue = AllocatePool (StrSize);
242 if (NewFieldValue == NULL) {
243 return EFI_OUT_OF_RESOURCES;
244 }
245 CopyMem (NewFieldValue, FieldValue, StrSize);
246 NewFieldValue[StrSize -1] = '\0';
247
248 if (Header->FieldValue != NULL) {
249 FreePool (Header->FieldValue);
250 }
251 Header->FieldValue = NewFieldValue;
252 }
253
254 return EFI_SUCCESS;
255}
256
257/**
258 Notify the callback function when an event is triggered.
259
260 @param[in] Event The triggered event.
261 @param[in] Context The opaque parameter to the function.
262
263**/
264VOID
265EFIAPI
266HttpIoCommonNotify (
267 IN EFI_EVENT Event,
268 IN VOID *Context
269 )
270{
271 *((BOOLEAN *) Context) = TRUE;
272}
273
274/**
275 Create a HTTP_IO to access the HTTP service. It will create and configure
276 a HTTP child handle.
277
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.
283
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.
290
291**/
292EFI_STATUS
293HttpIoCreateIo (
294 IN EFI_HANDLE Image,
295 IN EFI_HANDLE Controller,
296 IN UINT8 IpVersion,
297 IN HTTP_IO_CONFIG_DATA *ConfigData,
298 OUT HTTP_IO *HttpIo
299 )
300{
301 EFI_STATUS Status;
302 EFI_HTTP_CONFIG_DATA HttpConfigData;
303 EFI_HTTPv4_ACCESS_POINT Http4AccessPoint;
304 EFI_HTTP_PROTOCOL *Http;
305 EFI_EVENT Event;
306
307 if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (HttpIo == NULL)) {
308 return EFI_INVALID_PARAMETER;
309 }
310
311 if (IpVersion != IP_VERSION_4 && IpVersion != IP_VERSION_6) {
312 return EFI_UNSUPPORTED;
313 }
314
315 ZeroMem (HttpIo, sizeof (HTTP_IO));
316
317 //
318 // Create the HTTP child instance and get the HTTP protocol.
319 //
320 Status = NetLibCreateServiceChild (
321 Controller,
322 Image,
323 &gEfiHttpServiceBindingProtocolGuid,
324 &HttpIo->Handle
325 );
326 if (EFI_ERROR (Status)) {
327 return Status;
328 }
329
330 Status = gBS->OpenProtocol (
331 HttpIo->Handle,
332 &gEfiHttpProtocolGuid,
333 (VOID **) &Http,
334 Image,
335 Controller,
336 EFI_OPEN_PROTOCOL_BY_DRIVER
337 );
338 if (EFI_ERROR (Status) || (Http == NULL)) {
339 goto ON_ERROR;
340 }
341
342 //
343 // Init the configuration data and configure the HTTP child.
344 //
345 HttpIo->Image = Image;
346 HttpIo->Controller = Controller;
347 HttpIo->IpVersion = IpVersion;
348 HttpIo->Http = Http;
349
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;
355
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;
361 } else {
362 ASSERT (FALSE);
363 }
364
365 Status = Http->Configure (Http, &HttpConfigData);
366 if (EFI_ERROR (Status)) {
367 goto ON_ERROR;
368 }
369
370 //
371 // Create events for variuos asynchronous operations.
372 //
373 Status = gBS->CreateEvent (
374 EVT_NOTIFY_SIGNAL,
375 TPL_NOTIFY,
376 HttpIoCommonNotify,
377 &HttpIo->IsTxDone,
378 &Event
379 );
380 if (EFI_ERROR (Status)) {
381 goto ON_ERROR;
382 }
383 HttpIo->ReqToken.Event = Event;
384 HttpIo->ReqToken.Message = &HttpIo->ReqMessage;
385
386 Status = gBS->CreateEvent (
387 EVT_NOTIFY_SIGNAL,
388 TPL_NOTIFY,
389 HttpIoCommonNotify,
390 &HttpIo->IsRxDone,
391 &Event
392 );
393 if (EFI_ERROR (Status)) {
394 goto ON_ERROR;
395 }
396 HttpIo->RspToken.Event = Event;
397 HttpIo->RspToken.Message = &HttpIo->RspMessage;
398
399 return EFI_SUCCESS;
400
401ON_ERROR:
402 HttpIoDestroyIo (HttpIo);
403
404 return Status;
405}
406
407/**
408 Destroy the HTTP_IO and release the resouces.
409
410 @param[in] HttpIo The HTTP_IO which wraps the HTTP service to be destroyed.
411
412**/
413VOID
414HttpIoDestroyIo (
415 IN HTTP_IO *HttpIo
416 )
417{
418 EFI_HTTP_PROTOCOL *Http;
419 EFI_EVENT Event;
420
421 if (HttpIo == NULL) {
422 return;
423 }
424
425 Event = HttpIo->ReqToken.Event;
426 if (Event != NULL) {
427 gBS->CloseEvent (Event);
428 }
429
430 Event = HttpIo->RspToken.Event;
431 if (Event != NULL) {
432 gBS->CloseEvent (Event);
433 }
434
435 Http = HttpIo->Http;
436 if (Http != NULL) {
437 Http->Configure (Http, NULL);
438 gBS->CloseProtocol (
439 HttpIo->Handle,
440 &gEfiHttpProtocolGuid,
441 HttpIo->Image,
442 HttpIo->Controller
443 );
444 }
445
446 NetLibDestroyServiceChild (
447 HttpIo->Controller,
448 HttpIo->Image,
449 &gEfiHttpServiceBindingProtocolGuid,
450 HttpIo->Handle
451 );
452}
453
454/**
455 Synchronously send a HTTP REQUEST message to the server.
456
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.
463
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.
469
470**/
471EFI_STATUS
472HttpIoSendRequest (
473 IN HTTP_IO *HttpIo,
474 IN EFI_HTTP_REQUEST_DATA *Request,
475 IN UINTN HeaderCount,
476 IN EFI_HTTP_HEADER *Headers,
477 IN UINTN BodyLength,
478 IN VOID *Body
479 )
480{
481 EFI_STATUS Status;
482 EFI_HTTP_PROTOCOL *Http;
483
484 if (HttpIo == NULL || HttpIo->Http == NULL) {
485 return EFI_INVALID_PARAMETER;
486 }
487
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;
494
495 //
496 // Queue the request token to HTTP instances.
497 //
498 Http = HttpIo->Http;
499 HttpIo->IsTxDone = FALSE;
500 Status = Http->Request (
501 Http,
502 &HttpIo->ReqToken
503 );
504 if (EFI_ERROR (Status)) {
505 return Status;
506 }
507
508 //
509 // Poll the network until transmit finish.
510 //
511 while (!HttpIo->IsTxDone) {
512 Http->Poll (Http);
513 }
514
515 return HttpIo->ReqToken.Status;
516}
517
518/**
519 Synchronously receive a HTTP RESPONSE message from the server.
520
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.
525
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.
531
532**/
533EFI_STATUS
534HttpIoRecvResponse (
535 IN HTTP_IO *HttpIo,
536 IN BOOLEAN RecvMsgHeader,
537 OUT HTTP_IO_RESOPNSE_DATA *ResponseData
538 )
539{
540 EFI_STATUS Status;
541 EFI_HTTP_PROTOCOL *Http;
542
543 if (HttpIo == NULL || HttpIo->Http == NULL || ResponseData == NULL) {
544 return EFI_INVALID_PARAMETER;
545 }
546
547 //
548 // Queue the response token to HTTP instances.
549 //
550 HttpIo->RspToken.Status = EFI_NOT_READY;
551 if (RecvMsgHeader) {
552 HttpIo->RspToken.Message->Data.Response = &ResponseData->Response;
553 } else {
554 HttpIo->RspToken.Message->Data.Response = NULL;
555 }
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;
560
561 Http = HttpIo->Http;
562 HttpIo->IsRxDone = FALSE;
563 Status = Http->Response (
564 Http,
565 &HttpIo->RspToken
566 );
567
568 if (EFI_ERROR (Status)) {
569 return Status;
570 }
571
572 //
573 // Poll the network until transmit finish.
574 //
575 while (!HttpIo->IsRxDone) {
576 Http->Poll (Http);
577 }
578
579 //
580 // Store the received data into the wrapper.
581 //
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;
587 }
588
589 return Status;
590}