]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/HttpDxe/HttpProto.c
NetworkPkg/HttpDxe: Decofigure Tcp4 before reconfiguring
[mirror_edk2.git] / NetworkPkg / HttpDxe / HttpProto.c
1 /** @file
2 Miscellaneous routines for HttpDxe driver.
3
4 Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "HttpDriver.h"
11
12 /**
13 The common notify function used in HTTP driver.
14
15 @param[in] Event The event signaled.
16 @param[in] Context The context.
17
18 **/
19 VOID
20 EFIAPI
21 HttpCommonNotify (
22 IN EFI_EVENT Event,
23 IN VOID *Context
24 )
25 {
26 if ((Event == NULL) || (Context == NULL)) {
27 return;
28 }
29
30 *((BOOLEAN *)Context) = TRUE;
31 }
32
33 /**
34 The notify function associated with Tx4Token for Tcp4->Transmit() or Tx6Token for Tcp6->Transmit().
35
36 @param[in] Context The context.
37
38 **/
39 VOID
40 EFIAPI
41 HttpTcpTransmitNotifyDpc (
42 IN VOID *Context
43 )
44 {
45 HTTP_TOKEN_WRAP *Wrap;
46 HTTP_PROTOCOL *HttpInstance;
47
48 if (Context == NULL) {
49 return;
50 }
51
52 Wrap = (HTTP_TOKEN_WRAP *)Context;
53 HttpInstance = Wrap->HttpInstance;
54
55 if (!HttpInstance->LocalAddressIsIPv6) {
56 Wrap->HttpToken->Status = Wrap->TcpWrap.Tx4Token.CompletionToken.Status;
57 gBS->SignalEvent (Wrap->HttpToken->Event);
58
59 //
60 // Free resources.
61 //
62 if (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {
63 FreePool (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer);
64 }
65
66 if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) {
67 gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);
68 }
69 } else {
70 Wrap->HttpToken->Status = Wrap->TcpWrap.Tx6Token.CompletionToken.Status;
71 gBS->SignalEvent (Wrap->HttpToken->Event);
72
73 //
74 // Free resources.
75 //
76 if (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) {
77 FreePool (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer);
78 }
79
80 if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) {
81 gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event);
82 }
83 }
84
85 Wrap->TcpWrap.IsTxDone = TRUE;
86
87 //
88 // Check pending TxTokens and sent out.
89 //
90 NetMapIterate (&Wrap->HttpInstance->TxTokens, HttpTcpTransmit, NULL);
91 }
92
93 /**
94 Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK.
95
96 @param Event The receive event delivered to TCP for transmit.
97 @param Context Context for the callback.
98
99 **/
100 VOID
101 EFIAPI
102 HttpTcpTransmitNotify (
103 IN EFI_EVENT Event,
104 IN VOID *Context
105 )
106 {
107 //
108 // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK
109 //
110 QueueDpc (TPL_CALLBACK, HttpTcpTransmitNotifyDpc, Context);
111 }
112
113 /**
114 The notify function associated with Rx4Token for Tcp4->Receive () or Rx6Token for Tcp6->Receive().
115
116 @param[in] Context The context.
117
118 **/
119 VOID
120 EFIAPI
121 HttpTcpReceiveNotifyDpc (
122 IN VOID *Context
123 )
124 {
125 HTTP_TOKEN_WRAP *Wrap;
126 NET_MAP_ITEM *Item;
127 UINTN Length;
128 EFI_STATUS Status;
129 HTTP_PROTOCOL *HttpInstance;
130 BOOLEAN UsingIpv6;
131
132 if (Context == NULL) {
133 return;
134 }
135
136 Wrap = (HTTP_TOKEN_WRAP *)Context;
137 HttpInstance = Wrap->HttpInstance;
138 UsingIpv6 = HttpInstance->LocalAddressIsIPv6;
139
140 if (UsingIpv6) {
141 gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);
142 Wrap->TcpWrap.Rx6Token.CompletionToken.Event = NULL;
143
144 if (EFI_ERROR (Wrap->TcpWrap.Rx6Token.CompletionToken.Status)) {
145 DEBUG ((DEBUG_ERROR, "HttpTcpReceiveNotifyDpc: %r!\n", Wrap->TcpWrap.Rx6Token.CompletionToken.Status));
146 Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status;
147 gBS->SignalEvent (Wrap->HttpToken->Event);
148
149 Item = NetMapFindKey (&HttpInstance->RxTokens, Wrap->HttpToken);
150 if (Item != NULL) {
151 NetMapRemoveItem (&HttpInstance->RxTokens, Item, NULL);
152 }
153
154 FreePool (Wrap);
155 Wrap = NULL;
156
157 return;
158 }
159 } else {
160 gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);
161 Wrap->TcpWrap.Rx4Token.CompletionToken.Event = NULL;
162
163 if (EFI_ERROR (Wrap->TcpWrap.Rx4Token.CompletionToken.Status)) {
164 DEBUG ((DEBUG_ERROR, "HttpTcpReceiveNotifyDpc: %r!\n", Wrap->TcpWrap.Rx4Token.CompletionToken.Status));
165 Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status;
166 gBS->SignalEvent (Wrap->HttpToken->Event);
167
168 Item = NetMapFindKey (&HttpInstance->RxTokens, Wrap->HttpToken);
169 if (Item != NULL) {
170 NetMapRemoveItem (&HttpInstance->RxTokens, Item, NULL);
171 }
172
173 FreePool (Wrap);
174 Wrap = NULL;
175
176 return;
177 }
178 }
179
180 //
181 // Check whether we receive a complete HTTP message.
182 //
183 ASSERT (HttpInstance->MsgParser != NULL);
184 if (UsingIpv6) {
185 Length = (UINTN)Wrap->TcpWrap.Rx6Data.FragmentTable[0].FragmentLength;
186 } else {
187 Length = (UINTN)Wrap->TcpWrap.Rx4Data.FragmentTable[0].FragmentLength;
188 }
189
190 //
191 // Record the CallbackData data.
192 //
193 HttpInstance->CallbackData.Wrap = (VOID *)Wrap;
194 HttpInstance->CallbackData.ParseData = Wrap->HttpToken->Message->Body;
195 HttpInstance->CallbackData.ParseDataLength = Length;
196
197 //
198 // Parse Body with CallbackData data.
199 //
200 Status = HttpParseMessageBody (
201 HttpInstance->MsgParser,
202 Length,
203 Wrap->HttpToken->Message->Body
204 );
205 if (EFI_ERROR (Status)) {
206 return;
207 }
208
209 if (HttpIsMessageComplete (HttpInstance->MsgParser)) {
210 //
211 // Free the MsgParse since we already have a full HTTP message.
212 //
213 HttpFreeMsgParser (HttpInstance->MsgParser);
214 HttpInstance->MsgParser = NULL;
215 }
216
217 Wrap->HttpToken->Message->BodyLength = Length;
218 ASSERT (HttpInstance->CacheBody == NULL);
219 //
220 // We receive part of header of next HTTP msg.
221 //
222 if (HttpInstance->NextMsg != NULL) {
223 Wrap->HttpToken->Message->BodyLength = HttpInstance->NextMsg -
224 (CHAR8 *)Wrap->HttpToken->Message->Body;
225 HttpInstance->CacheLen = Length - Wrap->HttpToken->Message->BodyLength;
226 if (HttpInstance->CacheLen != 0) {
227 HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen);
228 if (HttpInstance->CacheBody == NULL) {
229 return;
230 }
231
232 CopyMem (HttpInstance->CacheBody, HttpInstance->NextMsg, HttpInstance->CacheLen);
233 HttpInstance->NextMsg = HttpInstance->CacheBody;
234 HttpInstance->CacheOffset = 0;
235 }
236 }
237
238 Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);
239 if (Item != NULL) {
240 NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);
241 }
242
243 Wrap->TcpWrap.IsRxDone = TRUE;
244 if (UsingIpv6) {
245 Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status;
246 } else {
247 Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status;
248 }
249
250 gBS->SignalEvent (Wrap->HttpToken->Event);
251
252 //
253 // Check pending RxTokens and receive the HTTP message.
254 //
255 NetMapIterate (&Wrap->HttpInstance->RxTokens, HttpTcpReceive, NULL);
256
257 FreePool (Wrap);
258 Wrap = NULL;
259 }
260
261 /**
262 Request HttpTcpReceiveNotifyDpc as a DPC at TPL_CALLBACK.
263
264 @param Event The receive event delivered to TCP for receive.
265 @param Context Context for the callback.
266
267 **/
268 VOID
269 EFIAPI
270 HttpTcpReceiveNotify (
271 IN EFI_EVENT Event,
272 IN VOID *Context
273 )
274 {
275 //
276 // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK
277 //
278 QueueDpc (TPL_CALLBACK, HttpTcpReceiveNotifyDpc, Context);
279 }
280
281 /**
282 Create events for the TCP connection token and TCP close token.
283
284 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
285
286 @retval EFI_SUCCESS The events are created successfully.
287 @retval others Other error as indicated.
288
289 **/
290 EFI_STATUS
291 HttpCreateTcpConnCloseEvent (
292 IN HTTP_PROTOCOL *HttpInstance
293 )
294 {
295 EFI_STATUS Status;
296
297 if (!HttpInstance->LocalAddressIsIPv6) {
298 //
299 // Create events for various asynchronous operations.
300 //
301 Status = gBS->CreateEvent (
302 EVT_NOTIFY_SIGNAL,
303 TPL_NOTIFY,
304 HttpCommonNotify,
305 &HttpInstance->IsTcp4ConnDone,
306 &HttpInstance->Tcp4ConnToken.CompletionToken.Event
307 );
308 if (EFI_ERROR (Status)) {
309 goto ERROR;
310 }
311
312 //
313 // Initialize Tcp4CloseToken
314 //
315 Status = gBS->CreateEvent (
316 EVT_NOTIFY_SIGNAL,
317 TPL_NOTIFY,
318 HttpCommonNotify,
319 &HttpInstance->IsTcp4CloseDone,
320 &HttpInstance->Tcp4CloseToken.CompletionToken.Event
321 );
322 if (EFI_ERROR (Status)) {
323 goto ERROR;
324 }
325 } else {
326 //
327 // Create events for various asynchronous operations.
328 //
329 Status = gBS->CreateEvent (
330 EVT_NOTIFY_SIGNAL,
331 TPL_NOTIFY,
332 HttpCommonNotify,
333 &HttpInstance->IsTcp6ConnDone,
334 &HttpInstance->Tcp6ConnToken.CompletionToken.Event
335 );
336 if (EFI_ERROR (Status)) {
337 goto ERROR;
338 }
339
340 //
341 // Initialize Tcp6CloseToken
342 //
343 Status = gBS->CreateEvent (
344 EVT_NOTIFY_SIGNAL,
345 TPL_NOTIFY,
346 HttpCommonNotify,
347 &HttpInstance->IsTcp6CloseDone,
348 &HttpInstance->Tcp6CloseToken.CompletionToken.Event
349 );
350 if (EFI_ERROR (Status)) {
351 goto ERROR;
352 }
353 }
354
355 return EFI_SUCCESS;
356
357 ERROR:
358 //
359 // Error handling
360 //
361 HttpCloseTcpConnCloseEvent (HttpInstance);
362
363 return Status;
364 }
365
366 /**
367 Close events in the TCP connection token and TCP close token.
368
369 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
370
371 **/
372 VOID
373 HttpCloseTcpConnCloseEvent (
374 IN HTTP_PROTOCOL *HttpInstance
375 )
376 {
377 ASSERT (HttpInstance != NULL);
378
379 if (HttpInstance->LocalAddressIsIPv6) {
380 if (NULL != HttpInstance->Tcp6ConnToken.CompletionToken.Event) {
381 gBS->CloseEvent (HttpInstance->Tcp6ConnToken.CompletionToken.Event);
382 HttpInstance->Tcp6ConnToken.CompletionToken.Event = NULL;
383 }
384
385 if (NULL != HttpInstance->Tcp6CloseToken.CompletionToken.Event) {
386 gBS->CloseEvent (HttpInstance->Tcp6CloseToken.CompletionToken.Event);
387 HttpInstance->Tcp6CloseToken.CompletionToken.Event = NULL;
388 }
389 } else {
390 if (NULL != HttpInstance->Tcp4ConnToken.CompletionToken.Event) {
391 gBS->CloseEvent (HttpInstance->Tcp4ConnToken.CompletionToken.Event);
392 HttpInstance->Tcp4ConnToken.CompletionToken.Event = NULL;
393 }
394
395 if (NULL != HttpInstance->Tcp4CloseToken.CompletionToken.Event) {
396 gBS->CloseEvent (HttpInstance->Tcp4CloseToken.CompletionToken.Event);
397 HttpInstance->Tcp4CloseToken.CompletionToken.Event = NULL;
398 }
399 }
400 }
401
402 /**
403 Create event for the TCP transmit token.
404
405 @param[in] Wrap Point to HTTP token's wrap data.
406
407 @retval EFI_SUCCESS The events is created successfully.
408 @retval others Other error as indicated.
409
410 **/
411 EFI_STATUS
412 HttpCreateTcpTxEvent (
413 IN HTTP_TOKEN_WRAP *Wrap
414 )
415 {
416 EFI_STATUS Status;
417 HTTP_PROTOCOL *HttpInstance;
418 HTTP_TCP_TOKEN_WRAP *TcpWrap;
419
420 HttpInstance = Wrap->HttpInstance;
421 TcpWrap = &Wrap->TcpWrap;
422
423 if (!HttpInstance->LocalAddressIsIPv6) {
424 Status = gBS->CreateEvent (
425 EVT_NOTIFY_SIGNAL,
426 TPL_NOTIFY,
427 HttpTcpTransmitNotify,
428 Wrap,
429 &TcpWrap->Tx4Token.CompletionToken.Event
430 );
431 if (EFI_ERROR (Status)) {
432 return Status;
433 }
434
435 TcpWrap->Tx4Data.Push = TRUE;
436 TcpWrap->Tx4Data.Urgent = FALSE;
437 TcpWrap->Tx4Data.FragmentCount = 1;
438 TcpWrap->Tx4Token.Packet.TxData = &Wrap->TcpWrap.Tx4Data;
439 TcpWrap->Tx4Token.CompletionToken.Status = EFI_NOT_READY;
440 } else {
441 Status = gBS->CreateEvent (
442 EVT_NOTIFY_SIGNAL,
443 TPL_NOTIFY,
444 HttpTcpTransmitNotify,
445 Wrap,
446 &TcpWrap->Tx6Token.CompletionToken.Event
447 );
448 if (EFI_ERROR (Status)) {
449 return Status;
450 }
451
452 TcpWrap->Tx6Data.Push = TRUE;
453 TcpWrap->Tx6Data.Urgent = FALSE;
454 TcpWrap->Tx6Data.FragmentCount = 1;
455 TcpWrap->Tx6Token.Packet.TxData = &Wrap->TcpWrap.Tx6Data;
456 TcpWrap->Tx6Token.CompletionToken.Status = EFI_NOT_READY;
457 }
458
459 return EFI_SUCCESS;
460 }
461
462 /**
463 Create event for the TCP receive token which is used to receive HTTP header.
464
465 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
466
467 @retval EFI_SUCCESS The events is created successfully.
468 @retval others Other error as indicated.
469
470 **/
471 EFI_STATUS
472 HttpCreateTcpRxEventForHeader (
473 IN HTTP_PROTOCOL *HttpInstance
474 )
475 {
476 EFI_STATUS Status;
477
478 if (!HttpInstance->LocalAddressIsIPv6) {
479 Status = gBS->CreateEvent (
480 EVT_NOTIFY_SIGNAL,
481 TPL_NOTIFY,
482 HttpCommonNotify,
483 &HttpInstance->IsRxDone,
484 &HttpInstance->Rx4Token.CompletionToken.Event
485 );
486 if (EFI_ERROR (Status)) {
487 return Status;
488 }
489
490 HttpInstance->Rx4Data.FragmentCount = 1;
491 HttpInstance->Rx4Token.Packet.RxData = &HttpInstance->Rx4Data;
492 HttpInstance->Rx4Token.CompletionToken.Status = EFI_NOT_READY;
493 } else {
494 Status = gBS->CreateEvent (
495 EVT_NOTIFY_SIGNAL,
496 TPL_NOTIFY,
497 HttpCommonNotify,
498 &HttpInstance->IsRxDone,
499 &HttpInstance->Rx6Token.CompletionToken.Event
500 );
501 if (EFI_ERROR (Status)) {
502 return Status;
503 }
504
505 HttpInstance->Rx6Data.FragmentCount = 1;
506 HttpInstance->Rx6Token.Packet.RxData = &HttpInstance->Rx6Data;
507 HttpInstance->Rx6Token.CompletionToken.Status = EFI_NOT_READY;
508 }
509
510 return EFI_SUCCESS;
511 }
512
513 /**
514 Create event for the TCP receive token which is used to receive HTTP body.
515
516 @param[in] Wrap Point to HTTP token's wrap data.
517
518 @retval EFI_SUCCESS The events is created successfully.
519 @retval others Other error as indicated.
520
521 **/
522 EFI_STATUS
523 HttpCreateTcpRxEvent (
524 IN HTTP_TOKEN_WRAP *Wrap
525 )
526 {
527 EFI_STATUS Status;
528 HTTP_PROTOCOL *HttpInstance;
529 HTTP_TCP_TOKEN_WRAP *TcpWrap;
530
531 HttpInstance = Wrap->HttpInstance;
532 TcpWrap = &Wrap->TcpWrap;
533 if (!HttpInstance->LocalAddressIsIPv6) {
534 Status = gBS->CreateEvent (
535 EVT_NOTIFY_SIGNAL,
536 TPL_NOTIFY,
537 HttpTcpReceiveNotify,
538 Wrap,
539 &TcpWrap->Rx4Token.CompletionToken.Event
540 );
541 if (EFI_ERROR (Status)) {
542 return Status;
543 }
544
545 TcpWrap->Rx4Data.FragmentCount = 1;
546 TcpWrap->Rx4Token.Packet.RxData = &Wrap->TcpWrap.Rx4Data;
547 TcpWrap->Rx4Token.CompletionToken.Status = EFI_NOT_READY;
548 } else {
549 Status = gBS->CreateEvent (
550 EVT_NOTIFY_SIGNAL,
551 TPL_NOTIFY,
552 HttpTcpReceiveNotify,
553 Wrap,
554 &TcpWrap->Rx6Token.CompletionToken.Event
555 );
556 if (EFI_ERROR (Status)) {
557 return Status;
558 }
559
560 TcpWrap->Rx6Data.FragmentCount = 1;
561 TcpWrap->Rx6Token.Packet.RxData = &Wrap->TcpWrap.Rx6Data;
562 TcpWrap->Rx6Token.CompletionToken.Status = EFI_NOT_READY;
563 }
564
565 return EFI_SUCCESS;
566 }
567
568 /**
569 Close Events for Tcp Receive Tokens for HTTP body and HTTP header.
570
571 @param[in] Wrap Pointer to HTTP token's wrap data.
572
573 **/
574 VOID
575 HttpCloseTcpRxEvent (
576 IN HTTP_TOKEN_WRAP *Wrap
577 )
578 {
579 HTTP_PROTOCOL *HttpInstance;
580
581 ASSERT (Wrap != NULL);
582 HttpInstance = Wrap->HttpInstance;
583
584 if (HttpInstance->LocalAddressIsIPv6) {
585 if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {
586 gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);
587 }
588
589 if (HttpInstance->Rx6Token.CompletionToken.Event != NULL) {
590 gBS->CloseEvent (HttpInstance->Rx6Token.CompletionToken.Event);
591 HttpInstance->Rx6Token.CompletionToken.Event = NULL;
592 }
593 } else {
594 if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {
595 gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);
596 }
597
598 if (HttpInstance->Rx4Token.CompletionToken.Event != NULL) {
599 gBS->CloseEvent (HttpInstance->Rx4Token.CompletionToken.Event);
600 HttpInstance->Rx4Token.CompletionToken.Event = NULL;
601 }
602 }
603 }
604
605 /**
606 Initialize the HTTP_PROTOCOL structure to the unconfigured state.
607
608 @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
609 @param[in] IpVersion Indicate us TCP4 protocol or TCP6 protocol.
610
611 @retval EFI_SUCCESS HTTP_PROTOCOL structure is initialized successfully.
612 @retval Others Other error as indicated.
613
614 **/
615 EFI_STATUS
616 HttpInitProtocol (
617 IN OUT HTTP_PROTOCOL *HttpInstance,
618 IN BOOLEAN IpVersion
619 )
620 {
621 EFI_STATUS Status;
622 VOID *Interface;
623 BOOLEAN UsingIpv6;
624
625 ASSERT (HttpInstance != NULL);
626 UsingIpv6 = IpVersion;
627
628 if (!UsingIpv6) {
629 //
630 // Create TCP4 child.
631 //
632 Status = NetLibCreateServiceChild (
633 HttpInstance->Service->ControllerHandle,
634 HttpInstance->Service->Ip4DriverBindingHandle,
635 &gEfiTcp4ServiceBindingProtocolGuid,
636 &HttpInstance->Tcp4ChildHandle
637 );
638
639 if (EFI_ERROR (Status)) {
640 goto ON_ERROR;
641 }
642
643 Status = gBS->OpenProtocol (
644 HttpInstance->Tcp4ChildHandle,
645 &gEfiTcp4ProtocolGuid,
646 (VOID **)&Interface,
647 HttpInstance->Service->Ip4DriverBindingHandle,
648 HttpInstance->Service->ControllerHandle,
649 EFI_OPEN_PROTOCOL_BY_DRIVER
650 );
651
652 if (EFI_ERROR (Status)) {
653 goto ON_ERROR;
654 }
655
656 Status = gBS->OpenProtocol (
657 HttpInstance->Tcp4ChildHandle,
658 &gEfiTcp4ProtocolGuid,
659 (VOID **)&HttpInstance->Tcp4,
660 HttpInstance->Service->Ip4DriverBindingHandle,
661 HttpInstance->Handle,
662 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
663 );
664 if (EFI_ERROR (Status)) {
665 goto ON_ERROR;
666 }
667
668 Status = gBS->OpenProtocol (
669 HttpInstance->Service->Tcp4ChildHandle,
670 &gEfiTcp4ProtocolGuid,
671 (VOID **)&Interface,
672 HttpInstance->Service->Ip4DriverBindingHandle,
673 HttpInstance->Handle,
674 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
675 );
676 if (EFI_ERROR (Status)) {
677 goto ON_ERROR;
678 }
679 } else {
680 //
681 // Create TCP6 Child.
682 //
683 Status = NetLibCreateServiceChild (
684 HttpInstance->Service->ControllerHandle,
685 HttpInstance->Service->Ip6DriverBindingHandle,
686 &gEfiTcp6ServiceBindingProtocolGuid,
687 &HttpInstance->Tcp6ChildHandle
688 );
689
690 if (EFI_ERROR (Status)) {
691 goto ON_ERROR;
692 }
693
694 Status = gBS->OpenProtocol (
695 HttpInstance->Tcp6ChildHandle,
696 &gEfiTcp6ProtocolGuid,
697 (VOID **)&Interface,
698 HttpInstance->Service->Ip6DriverBindingHandle,
699 HttpInstance->Service->ControllerHandle,
700 EFI_OPEN_PROTOCOL_BY_DRIVER
701 );
702
703 if (EFI_ERROR (Status)) {
704 goto ON_ERROR;
705 }
706
707 Status = gBS->OpenProtocol (
708 HttpInstance->Tcp6ChildHandle,
709 &gEfiTcp6ProtocolGuid,
710 (VOID **)&HttpInstance->Tcp6,
711 HttpInstance->Service->Ip6DriverBindingHandle,
712 HttpInstance->Handle,
713 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
714 );
715
716 if (EFI_ERROR (Status)) {
717 goto ON_ERROR;
718 }
719
720 Status = gBS->OpenProtocol (
721 HttpInstance->Service->Tcp6ChildHandle,
722 &gEfiTcp6ProtocolGuid,
723 (VOID **)&Interface,
724 HttpInstance->Service->Ip6DriverBindingHandle,
725 HttpInstance->Handle,
726 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
727 );
728
729 if (EFI_ERROR (Status)) {
730 goto ON_ERROR;
731 }
732 }
733
734 HttpInstance->Url = AllocateZeroPool (HTTP_URL_BUFFER_LEN);
735 if (HttpInstance->Url == NULL) {
736 Status = EFI_OUT_OF_RESOURCES;
737 goto ON_ERROR;
738 }
739
740 return EFI_SUCCESS;
741
742 ON_ERROR:
743
744 if (HttpInstance->Tcp4ChildHandle != NULL) {
745 gBS->CloseProtocol (
746 HttpInstance->Tcp4ChildHandle,
747 &gEfiTcp4ProtocolGuid,
748 HttpInstance->Service->Ip4DriverBindingHandle,
749 HttpInstance->Service->ControllerHandle
750 );
751
752 gBS->CloseProtocol (
753 HttpInstance->Tcp4ChildHandle,
754 &gEfiTcp4ProtocolGuid,
755 HttpInstance->Service->Ip4DriverBindingHandle,
756 HttpInstance->Handle
757 );
758
759 NetLibDestroyServiceChild (
760 HttpInstance->Service->ControllerHandle,
761 HttpInstance->Service->Ip4DriverBindingHandle,
762 &gEfiTcp4ServiceBindingProtocolGuid,
763 HttpInstance->Tcp4ChildHandle
764 );
765 }
766
767 if (HttpInstance->Service->Tcp4ChildHandle != NULL) {
768 gBS->CloseProtocol (
769 HttpInstance->Service->Tcp4ChildHandle,
770 &gEfiTcp4ProtocolGuid,
771 HttpInstance->Service->Ip4DriverBindingHandle,
772 HttpInstance->Handle
773 );
774 }
775
776 if (HttpInstance->Tcp6ChildHandle != NULL) {
777 gBS->CloseProtocol (
778 HttpInstance->Tcp6ChildHandle,
779 &gEfiTcp6ProtocolGuid,
780 HttpInstance->Service->Ip6DriverBindingHandle,
781 HttpInstance->Service->ControllerHandle
782 );
783
784 gBS->CloseProtocol (
785 HttpInstance->Tcp6ChildHandle,
786 &gEfiTcp6ProtocolGuid,
787 HttpInstance->Service->Ip6DriverBindingHandle,
788 HttpInstance->Handle
789 );
790
791 NetLibDestroyServiceChild (
792 HttpInstance->Service->ControllerHandle,
793 HttpInstance->Service->Ip6DriverBindingHandle,
794 &gEfiTcp6ServiceBindingProtocolGuid,
795 HttpInstance->Tcp6ChildHandle
796 );
797 }
798
799 if (HttpInstance->Service->Tcp6ChildHandle != NULL) {
800 gBS->CloseProtocol (
801 HttpInstance->Service->Tcp6ChildHandle,
802 &gEfiTcp6ProtocolGuid,
803 HttpInstance->Service->Ip6DriverBindingHandle,
804 HttpInstance->Handle
805 );
806 }
807
808 return EFI_UNSUPPORTED;
809 }
810
811 /**
812 Clean up the HTTP child, release all the resources used by it.
813
814 @param[in] HttpInstance The HTTP child to clean up.
815
816 **/
817 VOID
818 HttpCleanProtocol (
819 IN HTTP_PROTOCOL *HttpInstance
820 )
821 {
822 HttpCloseConnection (HttpInstance);
823
824 HttpCloseTcpConnCloseEvent (HttpInstance);
825
826 if (HttpInstance->TimeoutEvent != NULL) {
827 gBS->CloseEvent (HttpInstance->TimeoutEvent);
828 HttpInstance->TimeoutEvent = NULL;
829 }
830
831 if (HttpInstance->CacheBody != NULL) {
832 FreePool (HttpInstance->CacheBody);
833 HttpInstance->CacheBody = NULL;
834 HttpInstance->NextMsg = NULL;
835 }
836
837 if (HttpInstance->RemoteHost != NULL) {
838 FreePool (HttpInstance->RemoteHost);
839 HttpInstance->RemoteHost = NULL;
840 }
841
842 if (HttpInstance->MsgParser != NULL) {
843 HttpFreeMsgParser (HttpInstance->MsgParser);
844 HttpInstance->MsgParser = NULL;
845 }
846
847 if (HttpInstance->Url != NULL) {
848 FreePool (HttpInstance->Url);
849 HttpInstance->Url = NULL;
850 }
851
852 NetMapClean (&HttpInstance->TxTokens);
853 NetMapClean (&HttpInstance->RxTokens);
854
855 if ((HttpInstance->TlsSb != NULL) && (HttpInstance->TlsChildHandle != NULL)) {
856 //
857 // Destroy the TLS instance.
858 //
859 HttpInstance->TlsSb->DestroyChild (HttpInstance->TlsSb, HttpInstance->TlsChildHandle);
860 HttpInstance->TlsChildHandle = NULL;
861 }
862
863 if (HttpInstance->Tcp4ChildHandle != NULL) {
864 gBS->CloseProtocol (
865 HttpInstance->Tcp4ChildHandle,
866 &gEfiTcp4ProtocolGuid,
867 HttpInstance->Service->Ip4DriverBindingHandle,
868 HttpInstance->Service->ControllerHandle
869 );
870
871 gBS->CloseProtocol (
872 HttpInstance->Tcp4ChildHandle,
873 &gEfiTcp4ProtocolGuid,
874 HttpInstance->Service->Ip4DriverBindingHandle,
875 HttpInstance->Handle
876 );
877
878 NetLibDestroyServiceChild (
879 HttpInstance->Service->ControllerHandle,
880 HttpInstance->Service->Ip4DriverBindingHandle,
881 &gEfiTcp4ServiceBindingProtocolGuid,
882 HttpInstance->Tcp4ChildHandle
883 );
884 }
885
886 if (HttpInstance->Service->Tcp4ChildHandle != NULL) {
887 gBS->CloseProtocol (
888 HttpInstance->Service->Tcp4ChildHandle,
889 &gEfiTcp4ProtocolGuid,
890 HttpInstance->Service->Ip4DriverBindingHandle,
891 HttpInstance->Handle
892 );
893 }
894
895 if (HttpInstance->Tcp6ChildHandle != NULL) {
896 gBS->CloseProtocol (
897 HttpInstance->Tcp6ChildHandle,
898 &gEfiTcp6ProtocolGuid,
899 HttpInstance->Service->Ip6DriverBindingHandle,
900 HttpInstance->Service->ControllerHandle
901 );
902
903 gBS->CloseProtocol (
904 HttpInstance->Tcp6ChildHandle,
905 &gEfiTcp6ProtocolGuid,
906 HttpInstance->Service->Ip6DriverBindingHandle,
907 HttpInstance->Handle
908 );
909
910 NetLibDestroyServiceChild (
911 HttpInstance->Service->ControllerHandle,
912 HttpInstance->Service->Ip6DriverBindingHandle,
913 &gEfiTcp6ServiceBindingProtocolGuid,
914 HttpInstance->Tcp6ChildHandle
915 );
916 }
917
918 if (HttpInstance->Service->Tcp6ChildHandle != NULL) {
919 gBS->CloseProtocol (
920 HttpInstance->Service->Tcp6ChildHandle,
921 &gEfiTcp6ProtocolGuid,
922 HttpInstance->Service->Ip6DriverBindingHandle,
923 HttpInstance->Handle
924 );
925 }
926
927 TlsCloseTxRxEvent (HttpInstance);
928 }
929
930 /**
931 Establish TCP connection with HTTP server.
932
933 @param[in] HttpInstance The HTTP instance private data.
934
935 @retval EFI_SUCCESS The TCP connection is established.
936 @retval Others Other error as indicated.
937
938 **/
939 EFI_STATUS
940 HttpCreateConnection (
941 IN HTTP_PROTOCOL *HttpInstance
942 )
943 {
944 EFI_STATUS Status;
945
946 //
947 // Connect to Http server
948 //
949 if (!HttpInstance->LocalAddressIsIPv6) {
950 HttpInstance->IsTcp4ConnDone = FALSE;
951 HttpInstance->Tcp4ConnToken.CompletionToken.Status = EFI_NOT_READY;
952 Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->Tcp4ConnToken);
953 HttpNotify (HttpEventConnectTcp, Status);
954 if (EFI_ERROR (Status)) {
955 DEBUG ((DEBUG_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status));
956 return Status;
957 }
958
959 while (!HttpInstance->IsTcp4ConnDone) {
960 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
961 }
962
963 Status = HttpInstance->Tcp4ConnToken.CompletionToken.Status;
964 } else {
965 HttpInstance->IsTcp6ConnDone = FALSE;
966 HttpInstance->Tcp6ConnToken.CompletionToken.Status = EFI_NOT_READY;
967 Status = HttpInstance->Tcp6->Connect (HttpInstance->Tcp6, &HttpInstance->Tcp6ConnToken);
968 HttpNotify (HttpEventConnectTcp, Status);
969 if (EFI_ERROR (Status)) {
970 DEBUG ((DEBUG_ERROR, "HttpCreateConnection: Tcp6->Connect() = %r\n", Status));
971 return Status;
972 }
973
974 while (!HttpInstance->IsTcp6ConnDone) {
975 HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
976 }
977
978 Status = HttpInstance->Tcp6ConnToken.CompletionToken.Status;
979 }
980
981 if (!EFI_ERROR (Status)) {
982 HttpInstance->State = HTTP_STATE_TCP_CONNECTED;
983 }
984
985 return Status;
986 }
987
988 /**
989 Close existing TCP connection.
990
991 @param[in] HttpInstance The HTTP instance private data.
992
993 @retval EFI_SUCCESS The TCP connection is closed.
994 @retval Others Other error as indicated.
995
996 **/
997 EFI_STATUS
998 HttpCloseConnection (
999 IN HTTP_PROTOCOL *HttpInstance
1000 )
1001 {
1002 EFI_STATUS Status;
1003
1004 if (HttpInstance->State == HTTP_STATE_TCP_CONNECTED) {
1005 if (HttpInstance->LocalAddressIsIPv6) {
1006 HttpInstance->Tcp6CloseToken.AbortOnClose = TRUE;
1007 HttpInstance->IsTcp6CloseDone = FALSE;
1008 Status = HttpInstance->Tcp6->Close (HttpInstance->Tcp6, &HttpInstance->Tcp6CloseToken);
1009 if (EFI_ERROR (Status)) {
1010 return Status;
1011 }
1012
1013 while (!HttpInstance->IsTcp6CloseDone) {
1014 HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
1015 }
1016 } else {
1017 HttpInstance->Tcp4CloseToken.AbortOnClose = TRUE;
1018 HttpInstance->IsTcp4CloseDone = FALSE;
1019 Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->Tcp4CloseToken);
1020 if (EFI_ERROR (Status)) {
1021 return Status;
1022 }
1023
1024 while (!HttpInstance->IsTcp4CloseDone) {
1025 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
1026 }
1027 }
1028 }
1029
1030 HttpInstance->State = HTTP_STATE_TCP_CLOSED;
1031 return EFI_SUCCESS;
1032 }
1033
1034 /**
1035 Configure TCP4 protocol child.
1036
1037 @param[in] HttpInstance The HTTP instance private data.
1038 @param[in] Wrap The HTTP token's wrap data.
1039
1040 @retval EFI_SUCCESS The TCP4 protocol child is configured.
1041 @retval Others Other error as indicated.
1042
1043 **/
1044 EFI_STATUS
1045 HttpConfigureTcp4 (
1046 IN HTTP_PROTOCOL *HttpInstance,
1047 IN HTTP_TOKEN_WRAP *Wrap
1048 )
1049 {
1050 EFI_STATUS Status;
1051 EFI_TCP4_CONFIG_DATA *Tcp4CfgData;
1052 EFI_TCP4_ACCESS_POINT *Tcp4AP;
1053 EFI_TCP4_OPTION *Tcp4Option;
1054
1055 ASSERT (HttpInstance != NULL);
1056
1057 Tcp4CfgData = &HttpInstance->Tcp4CfgData;
1058 ZeroMem (Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA));
1059
1060 Tcp4CfgData->TypeOfService = HTTP_TOS_DEAULT;
1061 Tcp4CfgData->TimeToLive = HTTP_TTL_DEAULT;
1062 Tcp4CfgData->ControlOption = &HttpInstance->Tcp4Option;
1063
1064 Tcp4AP = &Tcp4CfgData->AccessPoint;
1065 Tcp4AP->UseDefaultAddress = HttpInstance->IPv4Node.UseDefaultAddress;
1066 if (!Tcp4AP->UseDefaultAddress) {
1067 IP4_COPY_ADDRESS (&Tcp4AP->StationAddress, &HttpInstance->IPv4Node.LocalAddress);
1068 IP4_COPY_ADDRESS (&Tcp4AP->SubnetMask, &HttpInstance->IPv4Node.LocalSubnet);
1069 }
1070
1071 Tcp4AP->StationPort = HttpInstance->IPv4Node.LocalPort;
1072 Tcp4AP->RemotePort = HttpInstance->RemotePort;
1073 Tcp4AP->ActiveFlag = TRUE;
1074 IP4_COPY_ADDRESS (&Tcp4AP->RemoteAddress, &HttpInstance->RemoteAddr);
1075
1076 Tcp4Option = Tcp4CfgData->ControlOption;
1077 Tcp4Option->ReceiveBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1078 Tcp4Option->SendBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1079 Tcp4Option->MaxSynBackLog = HTTP_MAX_SYN_BACK_LOG;
1080 Tcp4Option->ConnectionTimeout = HTTP_CONNECTION_TIMEOUT;
1081 Tcp4Option->DataRetries = HTTP_DATA_RETRIES;
1082 Tcp4Option->FinTimeout = HTTP_FIN_TIMEOUT;
1083 Tcp4Option->KeepAliveProbes = HTTP_KEEP_ALIVE_PROBES;
1084 Tcp4Option->KeepAliveTime = HTTP_KEEP_ALIVE_TIME;
1085 Tcp4Option->KeepAliveInterval = HTTP_KEEP_ALIVE_INTERVAL;
1086 Tcp4Option->EnableNagle = TRUE;
1087 Tcp4CfgData->ControlOption = Tcp4Option;
1088
1089 if ((HttpInstance->State == HTTP_STATE_TCP_CONNECTED) ||
1090 (HttpInstance->State == HTTP_STATE_TCP_CLOSED))
1091 {
1092 Status = HttpInstance->Tcp4->Configure (HttpInstance->Tcp4, NULL);
1093 if (EFI_ERROR (Status)) {
1094 DEBUG ((DEBUG_ERROR, "HttpConfigureTcp4(NULL) - %r\n", Status));
1095 return Status;
1096 }
1097
1098 HttpInstance->State = HTTP_STATE_TCP_UNCONFIGED;
1099 }
1100
1101 Status = HttpInstance->Tcp4->Configure (HttpInstance->Tcp4, Tcp4CfgData);
1102 if (EFI_ERROR (Status)) {
1103 DEBUG ((DEBUG_ERROR, "HttpConfigureTcp4 - %r\n", Status));
1104 return Status;
1105 }
1106
1107 Status = HttpCreateTcpConnCloseEvent (HttpInstance);
1108 if (EFI_ERROR (Status)) {
1109 return Status;
1110 }
1111
1112 Status = HttpCreateTcpTxEvent (Wrap);
1113 if (EFI_ERROR (Status)) {
1114 return Status;
1115 }
1116
1117 HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
1118
1119 return EFI_SUCCESS;
1120 }
1121
1122 /**
1123 Configure TCP6 protocol child.
1124
1125 @param[in] HttpInstance The HTTP instance private data.
1126 @param[in] Wrap The HTTP token's wrap data.
1127
1128 @retval EFI_SUCCESS The TCP6 protocol child is configured.
1129 @retval Others Other error as indicated.
1130
1131 **/
1132 EFI_STATUS
1133 HttpConfigureTcp6 (
1134 IN HTTP_PROTOCOL *HttpInstance,
1135 IN HTTP_TOKEN_WRAP *Wrap
1136 )
1137 {
1138 EFI_STATUS Status;
1139 EFI_TCP6_CONFIG_DATA *Tcp6CfgData;
1140 EFI_TCP6_ACCESS_POINT *Tcp6Ap;
1141 EFI_TCP6_OPTION *Tcp6Option;
1142
1143 ASSERT (HttpInstance != NULL);
1144
1145 Tcp6CfgData = &HttpInstance->Tcp6CfgData;
1146 ZeroMem (Tcp6CfgData, sizeof (EFI_TCP6_CONFIG_DATA));
1147
1148 Tcp6CfgData->TrafficClass = 0;
1149 Tcp6CfgData->HopLimit = 255;
1150 Tcp6CfgData->ControlOption = &HttpInstance->Tcp6Option;
1151
1152 Tcp6Ap = &Tcp6CfgData->AccessPoint;
1153 Tcp6Ap->ActiveFlag = TRUE;
1154 Tcp6Ap->StationPort = HttpInstance->Ipv6Node.LocalPort;
1155 Tcp6Ap->RemotePort = HttpInstance->RemotePort;
1156 IP6_COPY_ADDRESS (&Tcp6Ap->StationAddress, &HttpInstance->Ipv6Node.LocalAddress);
1157 IP6_COPY_ADDRESS (&Tcp6Ap->RemoteAddress, &HttpInstance->RemoteIpv6Addr);
1158
1159 Tcp6Option = Tcp6CfgData->ControlOption;
1160 Tcp6Option->ReceiveBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1161 Tcp6Option->SendBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1162 Tcp6Option->MaxSynBackLog = HTTP_MAX_SYN_BACK_LOG;
1163 Tcp6Option->ConnectionTimeout = HTTP_CONNECTION_TIMEOUT;
1164 Tcp6Option->DataRetries = HTTP_DATA_RETRIES;
1165 Tcp6Option->FinTimeout = HTTP_FIN_TIMEOUT;
1166 Tcp6Option->KeepAliveProbes = HTTP_KEEP_ALIVE_PROBES;
1167 Tcp6Option->KeepAliveTime = HTTP_KEEP_ALIVE_TIME;
1168 Tcp6Option->KeepAliveInterval = HTTP_KEEP_ALIVE_INTERVAL;
1169 Tcp6Option->EnableNagle = TRUE;
1170
1171 Status = HttpInstance->Tcp6->Configure (HttpInstance->Tcp6, Tcp6CfgData);
1172 if (EFI_ERROR (Status)) {
1173 DEBUG ((DEBUG_ERROR, "HttpConfigureTcp6 - %r\n", Status));
1174 return Status;
1175 }
1176
1177 Status = HttpCreateTcpConnCloseEvent (HttpInstance);
1178 if (EFI_ERROR (Status)) {
1179 return Status;
1180 }
1181
1182 Status = HttpCreateTcpTxEvent (Wrap);
1183 if (EFI_ERROR (Status)) {
1184 return Status;
1185 }
1186
1187 HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
1188
1189 return EFI_SUCCESS;
1190 }
1191
1192 /**
1193 Check existing TCP connection, if in error state, recover TCP4 connection. Then,
1194 connect one TLS session if required.
1195
1196 @param[in] HttpInstance The HTTP instance private data.
1197
1198 @retval EFI_SUCCESS The TCP connection is established.
1199 @retval EFI_NOT_READY TCP4 protocol child is not created or configured.
1200 @retval Others Other error as indicated.
1201
1202 **/
1203 EFI_STATUS
1204 HttpConnectTcp4 (
1205 IN HTTP_PROTOCOL *HttpInstance
1206 )
1207 {
1208 EFI_STATUS Status;
1209 EFI_TCP4_CONNECTION_STATE Tcp4State;
1210
1211 if ((HttpInstance->State < HTTP_STATE_TCP_CONFIGED) || (HttpInstance->Tcp4 == NULL)) {
1212 return EFI_NOT_READY;
1213 }
1214
1215 Status = HttpInstance->Tcp4->GetModeData (
1216 HttpInstance->Tcp4,
1217 &Tcp4State,
1218 NULL,
1219 NULL,
1220 NULL,
1221 NULL
1222 );
1223 if (EFI_ERROR (Status)) {
1224 DEBUG ((DEBUG_ERROR, "Tcp4 GetModeData fail - %x\n", Status));
1225 return Status;
1226 }
1227
1228 if (Tcp4State == Tcp4StateEstablished) {
1229 return EFI_SUCCESS;
1230 } else if (Tcp4State > Tcp4StateEstablished ) {
1231 HttpCloseConnection (HttpInstance);
1232 }
1233
1234 Status = HttpCreateConnection (HttpInstance);
1235 if (EFI_ERROR (Status)) {
1236 DEBUG ((DEBUG_ERROR, "Tcp4 Connection fail - %x\n", Status));
1237 return Status;
1238 }
1239
1240 //
1241 // Tls session connection.
1242 //
1243 if (HttpInstance->UseHttps) {
1244 if (HttpInstance->TimeoutEvent == NULL) {
1245 //
1246 // Create TimeoutEvent for TLS connection.
1247 //
1248 Status = gBS->CreateEvent (
1249 EVT_TIMER,
1250 TPL_CALLBACK,
1251 NULL,
1252 NULL,
1253 &HttpInstance->TimeoutEvent
1254 );
1255 if (EFI_ERROR (Status)) {
1256 TlsCloseTxRxEvent (HttpInstance);
1257 return Status;
1258 }
1259 }
1260
1261 //
1262 // Start the timer, and wait Timeout seconds for connection.
1263 //
1264 Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
1265 if (EFI_ERROR (Status)) {
1266 TlsCloseTxRxEvent (HttpInstance);
1267 return Status;
1268 }
1269
1270 Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
1271 HttpNotify (HttpEventTlsConnectSession, Status);
1272
1273 gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
1274
1275 if (EFI_ERROR (Status)) {
1276 TlsCloseTxRxEvent (HttpInstance);
1277 return Status;
1278 }
1279 }
1280
1281 return Status;
1282 }
1283
1284 /**
1285 Check existing TCP connection, if in error state, recover TCP6 connection. Then,
1286 connect one TLS session if required.
1287
1288 @param[in] HttpInstance The HTTP instance private data.
1289
1290 @retval EFI_SUCCESS The TCP connection is established.
1291 @retval EFI_NOT_READY TCP6 protocol child is not created or configured.
1292 @retval Others Other error as indicated.
1293
1294 **/
1295 EFI_STATUS
1296 HttpConnectTcp6 (
1297 IN HTTP_PROTOCOL *HttpInstance
1298 )
1299 {
1300 EFI_STATUS Status;
1301 EFI_TCP6_CONNECTION_STATE Tcp6State;
1302
1303 if ((HttpInstance->State < HTTP_STATE_TCP_CONFIGED) || (HttpInstance->Tcp6 == NULL)) {
1304 return EFI_NOT_READY;
1305 }
1306
1307 Status = HttpInstance->Tcp6->GetModeData (
1308 HttpInstance->Tcp6,
1309 &Tcp6State,
1310 NULL,
1311 NULL,
1312 NULL,
1313 NULL
1314 );
1315
1316 if (EFI_ERROR (Status)) {
1317 DEBUG ((DEBUG_ERROR, "Tcp6 GetModeData fail - %x\n", Status));
1318 return Status;
1319 }
1320
1321 if (Tcp6State == Tcp6StateEstablished) {
1322 return EFI_SUCCESS;
1323 } else if (Tcp6State > Tcp6StateEstablished ) {
1324 HttpCloseConnection (HttpInstance);
1325 }
1326
1327 Status = HttpCreateConnection (HttpInstance);
1328 if (EFI_ERROR (Status)) {
1329 DEBUG ((DEBUG_ERROR, "Tcp6 Connection fail - %x\n", Status));
1330 return Status;
1331 }
1332
1333 //
1334 // Tls session connection.
1335 //
1336 if (HttpInstance->UseHttps) {
1337 if (HttpInstance->TimeoutEvent == NULL) {
1338 //
1339 // Create TimeoutEvent for TLS connection.
1340 //
1341 Status = gBS->CreateEvent (
1342 EVT_TIMER,
1343 TPL_CALLBACK,
1344 NULL,
1345 NULL,
1346 &HttpInstance->TimeoutEvent
1347 );
1348 if (EFI_ERROR (Status)) {
1349 TlsCloseTxRxEvent (HttpInstance);
1350 return Status;
1351 }
1352 }
1353
1354 //
1355 // Start the timer, and wait Timeout seconds for connection.
1356 //
1357 Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
1358 if (EFI_ERROR (Status)) {
1359 TlsCloseTxRxEvent (HttpInstance);
1360 return Status;
1361 }
1362
1363 Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
1364 HttpNotify (HttpEventTlsConnectSession, Status);
1365
1366 gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
1367
1368 if (EFI_ERROR (Status)) {
1369 TlsCloseTxRxEvent (HttpInstance);
1370 return Status;
1371 }
1372 }
1373
1374 return Status;
1375 }
1376
1377 /**
1378 Initialize Http session.
1379
1380 @param[in] HttpInstance The HTTP instance private data.
1381 @param[in] Wrap The HTTP token's wrap data.
1382 @param[in] Configure The Flag indicates whether need to initialize session.
1383 @param[in] TlsConfigure The Flag indicates whether it's the new Tls session.
1384
1385 @retval EFI_SUCCESS The initialization of session is done.
1386 @retval Others Other error as indicated.
1387
1388 **/
1389 EFI_STATUS
1390 HttpInitSession (
1391 IN HTTP_PROTOCOL *HttpInstance,
1392 IN HTTP_TOKEN_WRAP *Wrap,
1393 IN BOOLEAN Configure,
1394 IN BOOLEAN TlsConfigure
1395 )
1396 {
1397 EFI_STATUS Status;
1398
1399 ASSERT (HttpInstance != NULL);
1400
1401 //
1402 // Configure Tls session.
1403 //
1404 if (TlsConfigure) {
1405 Status = TlsConfigureSession (HttpInstance);
1406 if (EFI_ERROR (Status)) {
1407 return Status;
1408 }
1409 }
1410
1411 if (!HttpInstance->LocalAddressIsIPv6) {
1412 //
1413 // Configure TCP instance.
1414 //
1415 if (Configure) {
1416 Status = HttpConfigureTcp4 (HttpInstance, Wrap);
1417 if (EFI_ERROR (Status)) {
1418 return Status;
1419 }
1420 }
1421
1422 //
1423 // Connect TCP.
1424 //
1425 Status = HttpConnectTcp4 (HttpInstance);
1426 if (EFI_ERROR (Status)) {
1427 return Status;
1428 }
1429 } else {
1430 //
1431 // Configure TCP instance.
1432 //
1433 if (Configure) {
1434 Status = HttpConfigureTcp6 (HttpInstance, Wrap);
1435 if (EFI_ERROR (Status)) {
1436 return Status;
1437 }
1438 }
1439
1440 //
1441 // Connect TCP.
1442 //
1443 Status = HttpConnectTcp6 (HttpInstance);
1444 if (EFI_ERROR (Status)) {
1445 return Status;
1446 }
1447 }
1448
1449 return EFI_SUCCESS;
1450 }
1451
1452 /**
1453 Send the HTTP or HTTPS message through TCP4 or TCP6.
1454
1455 @param[in] HttpInstance The HTTP instance private data.
1456 @param[in] Wrap The HTTP token's wrap data.
1457 @param[in] TxString Buffer containing the HTTP message string.
1458 @param[in] TxStringLen Length of the HTTP message string in bytes.
1459
1460 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit queue.
1461 @retval Others Other error as indicated.
1462
1463 **/
1464 EFI_STATUS
1465 HttpTransmitTcp (
1466 IN HTTP_PROTOCOL *HttpInstance,
1467 IN HTTP_TOKEN_WRAP *Wrap,
1468 IN UINT8 *TxString,
1469 IN UINTN TxStringLen
1470 )
1471 {
1472 EFI_STATUS Status;
1473 EFI_TCP4_IO_TOKEN *Tx4Token;
1474 EFI_TCP4_PROTOCOL *Tcp4;
1475 EFI_TCP6_IO_TOKEN *Tx6Token;
1476 EFI_TCP6_PROTOCOL *Tcp6;
1477 UINT8 *TlsRecord;
1478 UINT16 PayloadSize;
1479 NET_FRAGMENT TempFragment;
1480 NET_FRAGMENT Fragment;
1481 UINTN RecordCount;
1482 UINTN RemainingLen;
1483
1484 Status = EFI_SUCCESS;
1485 TlsRecord = NULL;
1486 PayloadSize = 0;
1487 TempFragment.Len = 0;
1488 TempFragment.Bulk = NULL;
1489 Fragment.Len = 0;
1490 Fragment.Bulk = NULL;
1491 RecordCount = 0;
1492 RemainingLen = 0;
1493
1494 //
1495 // Need to encrypt data.
1496 //
1497 if (HttpInstance->UseHttps) {
1498 //
1499 // Allocate enough buffer for each TLS plaintext records.
1500 //
1501 TlsRecord = AllocateZeroPool (TLS_RECORD_HEADER_LENGTH + TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH);
1502 if (TlsRecord == NULL) {
1503 Status = EFI_OUT_OF_RESOURCES;
1504 return Status;
1505 }
1506
1507 //
1508 // Allocate enough buffer for all TLS ciphertext records.
1509 //
1510 RecordCount = TxStringLen / TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH + 1;
1511 Fragment.Bulk = AllocateZeroPool (RecordCount * (TLS_RECORD_HEADER_LENGTH + TLS_CIPHERTEXT_RECORD_MAX_PAYLOAD_LENGTH));
1512 if (Fragment.Bulk == NULL) {
1513 Status = EFI_OUT_OF_RESOURCES;
1514 goto ON_ERROR;
1515 }
1516
1517 //
1518 // Encrypt each TLS plaintext records.
1519 //
1520 RemainingLen = TxStringLen;
1521 while (RemainingLen != 0) {
1522 PayloadSize = (UINT16)MIN (TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH, RemainingLen);
1523
1524 ((TLS_RECORD_HEADER *)TlsRecord)->ContentType = TlsContentTypeApplicationData;
1525 ((TLS_RECORD_HEADER *)TlsRecord)->Version.Major = HttpInstance->TlsConfigData.Version.Major;
1526 ((TLS_RECORD_HEADER *)TlsRecord)->Version.Minor = HttpInstance->TlsConfigData.Version.Minor;
1527 ((TLS_RECORD_HEADER *)TlsRecord)->Length = PayloadSize;
1528
1529 CopyMem (TlsRecord + TLS_RECORD_HEADER_LENGTH, TxString + (TxStringLen - RemainingLen), PayloadSize);
1530
1531 Status = TlsProcessMessage (
1532 HttpInstance,
1533 TlsRecord,
1534 TLS_RECORD_HEADER_LENGTH + PayloadSize,
1535 EfiTlsEncrypt,
1536 &TempFragment
1537 );
1538 if (EFI_ERROR (Status)) {
1539 goto ON_ERROR;
1540 }
1541
1542 //
1543 // Record the processed/encrypted Packet.
1544 //
1545 CopyMem (Fragment.Bulk + Fragment.Len, TempFragment.Bulk, TempFragment.Len);
1546 Fragment.Len += TempFragment.Len;
1547
1548 FreePool (TempFragment.Bulk);
1549 TempFragment.Len = 0;
1550 TempFragment.Bulk = NULL;
1551
1552 RemainingLen -= (UINTN)PayloadSize;
1553 ZeroMem (TlsRecord, TLS_RECORD_HEADER_LENGTH + TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH);
1554 }
1555
1556 FreePool (TlsRecord);
1557 TlsRecord = NULL;
1558 }
1559
1560 if (!HttpInstance->LocalAddressIsIPv6) {
1561 Tcp4 = HttpInstance->Tcp4;
1562 Tx4Token = &Wrap->TcpWrap.Tx4Token;
1563
1564 if (HttpInstance->UseHttps) {
1565 Tx4Token->Packet.TxData->DataLength = Fragment.Len;
1566 Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = Fragment.Len;
1567 Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *)Fragment.Bulk;
1568 } else {
1569 Tx4Token->Packet.TxData->DataLength = (UINT32)TxStringLen;
1570 Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32)TxStringLen;
1571 Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *)TxString;
1572 }
1573
1574 Tx4Token->CompletionToken.Status = EFI_NOT_READY;
1575
1576 Wrap->TcpWrap.IsTxDone = FALSE;
1577 Status = Tcp4->Transmit (Tcp4, Tx4Token);
1578 if (EFI_ERROR (Status)) {
1579 DEBUG ((DEBUG_ERROR, "Transmit failed: %r\n", Status));
1580 goto ON_ERROR;
1581 }
1582 } else {
1583 Tcp6 = HttpInstance->Tcp6;
1584 Tx6Token = &Wrap->TcpWrap.Tx6Token;
1585
1586 if (HttpInstance->UseHttps) {
1587 Tx6Token->Packet.TxData->DataLength = Fragment.Len;
1588 Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = Fragment.Len;
1589 Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *)Fragment.Bulk;
1590 } else {
1591 Tx6Token->Packet.TxData->DataLength = (UINT32)TxStringLen;
1592 Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32)TxStringLen;
1593 Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *)TxString;
1594 }
1595
1596 Tx6Token->CompletionToken.Status = EFI_NOT_READY;
1597
1598 Wrap->TcpWrap.IsTxDone = FALSE;
1599 Status = Tcp6->Transmit (Tcp6, Tx6Token);
1600 if (EFI_ERROR (Status)) {
1601 DEBUG ((DEBUG_ERROR, "Transmit failed: %r\n", Status));
1602 goto ON_ERROR;
1603 }
1604 }
1605
1606 return Status;
1607
1608 ON_ERROR:
1609
1610 if (HttpInstance->UseHttps) {
1611 if (TlsRecord != NULL) {
1612 FreePool (TlsRecord);
1613 TlsRecord = NULL;
1614 }
1615
1616 if (Fragment.Bulk != NULL) {
1617 FreePool (Fragment.Bulk);
1618 Fragment.Bulk = NULL;
1619 }
1620 }
1621
1622 return Status;
1623 }
1624
1625 /**
1626 Check whether the user's token or event has already
1627 been enqueue on HTTP Tx or Rx Token list.
1628
1629 @param[in] Map The container of either user's transmit or receive
1630 token.
1631 @param[in] Item Current item to check against.
1632 @param[in] Context The Token to check against.
1633
1634 @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP
1635 @retval EFI_SUCCESS The current item isn't the same token/event as the
1636 context.
1637
1638 **/
1639 EFI_STATUS
1640 EFIAPI
1641 HttpTokenExist (
1642 IN NET_MAP *Map,
1643 IN NET_MAP_ITEM *Item,
1644 IN VOID *Context
1645 )
1646 {
1647 EFI_HTTP_TOKEN *Token;
1648 EFI_HTTP_TOKEN *TokenInItem;
1649
1650 Token = (EFI_HTTP_TOKEN *)Context;
1651 TokenInItem = (EFI_HTTP_TOKEN *)Item->Key;
1652
1653 if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
1654 return EFI_ACCESS_DENIED;
1655 }
1656
1657 return EFI_SUCCESS;
1658 }
1659
1660 /**
1661 Check whether the HTTP message associated with Tx4Token or Tx6Token is already sent out.
1662
1663 @param[in] Map The container of Tx4Token or Tx6Token.
1664 @param[in] Item Current item to check against.
1665 @param[in] Context The Token to check against.
1666
1667 @retval EFI_NOT_READY The HTTP message is still queued in the list.
1668 @retval EFI_SUCCESS The HTTP message has been sent out.
1669
1670 **/
1671 EFI_STATUS
1672 EFIAPI
1673 HttpTcpNotReady (
1674 IN NET_MAP *Map,
1675 IN NET_MAP_ITEM *Item,
1676 IN VOID *Context
1677 )
1678 {
1679 HTTP_TOKEN_WRAP *ValueInItem;
1680
1681 ValueInItem = (HTTP_TOKEN_WRAP *)Item->Value;
1682
1683 if (!ValueInItem->TcpWrap.IsTxDone) {
1684 return EFI_NOT_READY;
1685 }
1686
1687 return EFI_SUCCESS;
1688 }
1689
1690 /**
1691 Transmit the HTTP or HTTPS message by processing the associated HTTP token.
1692
1693 @param[in] Map The container of Tx4Token or Tx6Token.
1694 @param[in] Item Current item to check against.
1695 @param[in] Context The Token to check against.
1696
1697 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1698 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit
1699 queue.
1700
1701 **/
1702 EFI_STATUS
1703 EFIAPI
1704 HttpTcpTransmit (
1705 IN NET_MAP *Map,
1706 IN NET_MAP_ITEM *Item,
1707 IN VOID *Context
1708 )
1709 {
1710 HTTP_TOKEN_WRAP *ValueInItem;
1711 EFI_STATUS Status;
1712 CHAR8 *RequestMsg;
1713 CHAR8 *Url;
1714 UINTN UrlSize;
1715 UINTN RequestMsgSize;
1716
1717 RequestMsg = NULL;
1718
1719 ValueInItem = (HTTP_TOKEN_WRAP *)Item->Value;
1720 if (ValueInItem->TcpWrap.IsTxDone) {
1721 return EFI_SUCCESS;
1722 }
1723
1724 //
1725 // Parse the URI of the remote host.
1726 //
1727 UrlSize = StrLen (ValueInItem->HttpToken->Message->Data.Request->Url) + 1;
1728 Url = AllocatePool (UrlSize);
1729 if (Url == NULL) {
1730 return EFI_OUT_OF_RESOURCES;
1731 }
1732
1733 UnicodeStrToAsciiStrS (ValueInItem->HttpToken->Message->Data.Request->Url, Url, UrlSize);
1734
1735 //
1736 // Create request message.
1737 //
1738 Status = HttpGenRequestMessage (
1739 ValueInItem->HttpToken->Message,
1740 Url,
1741 &RequestMsg,
1742 &RequestMsgSize
1743 );
1744 FreePool (Url);
1745
1746 if (EFI_ERROR (Status) || (NULL == RequestMsg)) {
1747 return Status;
1748 }
1749
1750 ASSERT (RequestMsg != NULL);
1751
1752 //
1753 // Transmit the request message.
1754 //
1755 Status = HttpTransmitTcp (
1756 ValueInItem->HttpInstance,
1757 ValueInItem,
1758 (UINT8 *)RequestMsg,
1759 RequestMsgSize
1760 );
1761 FreePool (RequestMsg);
1762 return Status;
1763 }
1764
1765 /**
1766 Receive the HTTP response by processing the associated HTTP token.
1767
1768 @param[in] Map The container of Rx4Token or Rx6Token.
1769 @param[in] Item Current item to check against.
1770 @param[in] Context The Token to check against.
1771
1772 @retval EFI_SUCCESS The HTTP response is queued into TCP receive
1773 queue.
1774 @retval Others Other error as indicated.
1775
1776 **/
1777 EFI_STATUS
1778 EFIAPI
1779 HttpTcpReceive (
1780 IN NET_MAP *Map,
1781 IN NET_MAP_ITEM *Item,
1782 IN VOID *Context
1783 )
1784 {
1785 //
1786 // Process the queued HTTP response.
1787 //
1788 return HttpResponseWorker ((HTTP_TOKEN_WRAP *)Item->Value);
1789 }
1790
1791 /**
1792 Receive the HTTP header by processing the associated HTTP token.
1793
1794 @param[in] HttpInstance The HTTP instance private data.
1795 @param[in, out] SizeofHeaders The HTTP header length.
1796 @param[in, out] BufferSize The size of buffer to cache the header message.
1797 @param[in] Timeout The time to wait for receiving the header packet.
1798
1799 @retval EFI_SUCCESS The HTTP header is received.
1800 @retval Others Other errors as indicated.
1801
1802 **/
1803 EFI_STATUS
1804 HttpTcpReceiveHeader (
1805 IN HTTP_PROTOCOL *HttpInstance,
1806 IN OUT UINTN *SizeofHeaders,
1807 IN OUT UINTN *BufferSize,
1808 IN EFI_EVENT Timeout
1809 )
1810 {
1811 EFI_STATUS Status;
1812 EFI_TCP4_IO_TOKEN *Rx4Token;
1813 EFI_TCP4_PROTOCOL *Tcp4;
1814 EFI_TCP6_IO_TOKEN *Rx6Token;
1815 EFI_TCP6_PROTOCOL *Tcp6;
1816 CHAR8 **EndofHeader;
1817 CHAR8 **HttpHeaders;
1818 CHAR8 *Buffer;
1819 NET_FRAGMENT Fragment;
1820
1821 ASSERT (HttpInstance != NULL);
1822
1823 EndofHeader = HttpInstance->EndofHeader;
1824 HttpHeaders = HttpInstance->HttpHeaders;
1825 Tcp4 = HttpInstance->Tcp4;
1826 Tcp6 = HttpInstance->Tcp6;
1827 Buffer = NULL;
1828 Rx4Token = NULL;
1829 Rx6Token = NULL;
1830 Fragment.Len = 0;
1831 Fragment.Bulk = NULL;
1832
1833 if (HttpInstance->LocalAddressIsIPv6) {
1834 ASSERT (Tcp6 != NULL);
1835 } else {
1836 ASSERT (Tcp4 != NULL);
1837 }
1838
1839 if (!HttpInstance->UseHttps) {
1840 Status = HttpCreateTcpRxEventForHeader (HttpInstance);
1841 if (EFI_ERROR (Status)) {
1842 return Status;
1843 }
1844 }
1845
1846 if (!HttpInstance->LocalAddressIsIPv6) {
1847 if (!HttpInstance->UseHttps) {
1848 Rx4Token = &HttpInstance->Rx4Token;
1849 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
1850 if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
1851 Status = EFI_OUT_OF_RESOURCES;
1852 return Status;
1853 }
1854 }
1855
1856 //
1857 // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1858 //
1859 while (*EndofHeader == NULL) {
1860 if (!HttpInstance->UseHttps) {
1861 HttpInstance->IsRxDone = FALSE;
1862 Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN;
1863 Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
1864 Status = Tcp4->Receive (Tcp4, Rx4Token);
1865 if (EFI_ERROR (Status)) {
1866 DEBUG ((DEBUG_ERROR, "Tcp4 receive failed: %r\n", Status));
1867 return Status;
1868 }
1869
1870 while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1871 Tcp4->Poll (Tcp4);
1872 }
1873
1874 if (!HttpInstance->IsRxDone) {
1875 //
1876 // Cancel the Token before close its Event.
1877 //
1878 Tcp4->Cancel (HttpInstance->Tcp4, &Rx4Token->CompletionToken);
1879 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
1880 Rx4Token->CompletionToken.Status = EFI_TIMEOUT;
1881 }
1882
1883 Status = Rx4Token->CompletionToken.Status;
1884 if (EFI_ERROR (Status)) {
1885 return Status;
1886 }
1887
1888 Fragment.Len = Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength;
1889 Fragment.Bulk = (UINT8 *)Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer;
1890 } else {
1891 if (Fragment.Bulk != NULL) {
1892 FreePool (Fragment.Bulk);
1893 Fragment.Bulk = NULL;
1894 }
1895
1896 Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
1897 if (EFI_ERROR (Status)) {
1898 DEBUG ((DEBUG_ERROR, "Tcp4 receive failed: %r\n", Status));
1899 return Status;
1900 }
1901 }
1902
1903 //
1904 // Append the response string along with a Null-terminator.
1905 //
1906 *BufferSize = *SizeofHeaders + Fragment.Len;
1907 Buffer = AllocatePool (*BufferSize + 1);
1908 if (Buffer == NULL) {
1909 Status = EFI_OUT_OF_RESOURCES;
1910 return Status;
1911 }
1912
1913 if (*HttpHeaders != NULL) {
1914 CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
1915 FreePool (*HttpHeaders);
1916 }
1917
1918 CopyMem (
1919 Buffer + *SizeofHeaders,
1920 Fragment.Bulk,
1921 Fragment.Len
1922 );
1923 *(Buffer + *BufferSize) = '\0';
1924 *HttpHeaders = Buffer;
1925 *SizeofHeaders = *BufferSize;
1926
1927 //
1928 // Check whether we received end of HTTP headers.
1929 //
1930 *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
1931 }
1932
1933 //
1934 // Free the buffer.
1935 //
1936 if ((Rx4Token != NULL) && (Rx4Token->Packet.RxData != NULL) && (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL)) {
1937 FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
1938 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
1939 Fragment.Bulk = NULL;
1940 }
1941
1942 if (Fragment.Bulk != NULL) {
1943 FreePool (Fragment.Bulk);
1944 Fragment.Bulk = NULL;
1945 }
1946 } else {
1947 if (!HttpInstance->UseHttps) {
1948 Rx6Token = &HttpInstance->Rx6Token;
1949 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
1950 if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
1951 Status = EFI_OUT_OF_RESOURCES;
1952 return Status;
1953 }
1954 }
1955
1956 //
1957 // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1958 //
1959 while (*EndofHeader == NULL) {
1960 if (!HttpInstance->UseHttps) {
1961 HttpInstance->IsRxDone = FALSE;
1962 Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN;
1963 Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
1964 Status = Tcp6->Receive (Tcp6, Rx6Token);
1965 if (EFI_ERROR (Status)) {
1966 DEBUG ((DEBUG_ERROR, "Tcp6 receive failed: %r\n", Status));
1967 return Status;
1968 }
1969
1970 while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1971 Tcp6->Poll (Tcp6);
1972 }
1973
1974 if (!HttpInstance->IsRxDone) {
1975 //
1976 // Cancel the Token before close its Event.
1977 //
1978 Tcp6->Cancel (HttpInstance->Tcp6, &Rx6Token->CompletionToken);
1979 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
1980 Rx6Token->CompletionToken.Status = EFI_TIMEOUT;
1981 }
1982
1983 Status = Rx6Token->CompletionToken.Status;
1984 if (EFI_ERROR (Status)) {
1985 return Status;
1986 }
1987
1988 Fragment.Len = Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength;
1989 Fragment.Bulk = (UINT8 *)Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer;
1990 } else {
1991 if (Fragment.Bulk != NULL) {
1992 FreePool (Fragment.Bulk);
1993 Fragment.Bulk = NULL;
1994 }
1995
1996 Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
1997 if (EFI_ERROR (Status)) {
1998 DEBUG ((DEBUG_ERROR, "Tcp6 receive failed: %r\n", Status));
1999 return Status;
2000 }
2001 }
2002
2003 //
2004 // Append the response string along with a Null-terminator.
2005 //
2006 *BufferSize = *SizeofHeaders + Fragment.Len;
2007 Buffer = AllocatePool (*BufferSize + 1);
2008 if (Buffer == NULL) {
2009 Status = EFI_OUT_OF_RESOURCES;
2010 return Status;
2011 }
2012
2013 if (*HttpHeaders != NULL) {
2014 CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
2015 FreePool (*HttpHeaders);
2016 }
2017
2018 CopyMem (
2019 Buffer + *SizeofHeaders,
2020 Fragment.Bulk,
2021 Fragment.Len
2022 );
2023 *(Buffer + *BufferSize) = '\0';
2024 *HttpHeaders = Buffer;
2025 *SizeofHeaders = *BufferSize;
2026
2027 //
2028 // Check whether we received end of HTTP headers.
2029 //
2030 *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
2031 }
2032
2033 //
2034 // Free the buffer.
2035 //
2036 if ((Rx6Token != NULL) && (Rx6Token->Packet.RxData != NULL) && (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL)) {
2037 FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
2038 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
2039 Fragment.Bulk = NULL;
2040 }
2041
2042 if (Fragment.Bulk != NULL) {
2043 FreePool (Fragment.Bulk);
2044 Fragment.Bulk = NULL;
2045 }
2046 }
2047
2048 //
2049 // Skip the CRLF after the HTTP headers.
2050 //
2051 *EndofHeader = *EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR);
2052
2053 *SizeofHeaders = *EndofHeader - *HttpHeaders;
2054
2055 return EFI_SUCCESS;
2056 }
2057
2058 /**
2059 Receive the HTTP body by processing the associated HTTP token.
2060
2061 @param[in] Wrap The HTTP token's wrap data.
2062 @param[in] HttpMsg The HTTP message data.
2063
2064 @retval EFI_SUCCESS The HTTP body is received.
2065 @retval Others Other error as indicated.
2066
2067 **/
2068 EFI_STATUS
2069 HttpTcpReceiveBody (
2070 IN HTTP_TOKEN_WRAP *Wrap,
2071 IN EFI_HTTP_MESSAGE *HttpMsg
2072 )
2073 {
2074 EFI_STATUS Status;
2075 HTTP_PROTOCOL *HttpInstance;
2076 EFI_TCP6_PROTOCOL *Tcp6;
2077 EFI_TCP6_IO_TOKEN *Rx6Token;
2078 EFI_TCP4_PROTOCOL *Tcp4;
2079 EFI_TCP4_IO_TOKEN *Rx4Token;
2080
2081 HttpInstance = Wrap->HttpInstance;
2082 Tcp4 = HttpInstance->Tcp4;
2083 Tcp6 = HttpInstance->Tcp6;
2084 Rx4Token = NULL;
2085 Rx6Token = NULL;
2086
2087 if (HttpInstance->LocalAddressIsIPv6) {
2088 ASSERT (Tcp6 != NULL);
2089 } else {
2090 ASSERT (Tcp4 != NULL);
2091 }
2092
2093 if (HttpInstance->LocalAddressIsIPv6) {
2094 Rx6Token = &Wrap->TcpWrap.Rx6Token;
2095 Rx6Token->Packet.RxData->DataLength = (UINT32)MIN (MAX_UINT32, HttpMsg->BodyLength);
2096 Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32)MIN (MAX_UINT32, HttpMsg->BodyLength);
2097 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *)HttpMsg->Body;
2098 Rx6Token->CompletionToken.Status = EFI_NOT_READY;
2099
2100 Status = Tcp6->Receive (Tcp6, Rx6Token);
2101 if (EFI_ERROR (Status)) {
2102 DEBUG ((DEBUG_ERROR, "Tcp6 receive failed: %r\n", Status));
2103 return Status;
2104 }
2105 } else {
2106 Rx4Token = &Wrap->TcpWrap.Rx4Token;
2107 Rx4Token->Packet.RxData->DataLength = (UINT32)MIN (MAX_UINT32, HttpMsg->BodyLength);
2108 Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32)MIN (MAX_UINT32, HttpMsg->BodyLength);
2109 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *)HttpMsg->Body;
2110
2111 Rx4Token->CompletionToken.Status = EFI_NOT_READY;
2112 Status = Tcp4->Receive (Tcp4, Rx4Token);
2113 if (EFI_ERROR (Status)) {
2114 DEBUG ((DEBUG_ERROR, "Tcp4 receive failed: %r\n", Status));
2115 return Status;
2116 }
2117 }
2118
2119 return EFI_SUCCESS;
2120 }
2121
2122 /**
2123 Clean up Tcp Tokens while the Tcp transmission error occurs.
2124
2125 @param[in] Wrap Pointer to HTTP token's wrap data.
2126
2127 **/
2128 VOID
2129 HttpTcpTokenCleanup (
2130 IN HTTP_TOKEN_WRAP *Wrap
2131 )
2132 {
2133 HTTP_PROTOCOL *HttpInstance;
2134 EFI_TCP4_IO_TOKEN *Rx4Token;
2135 EFI_TCP6_IO_TOKEN *Rx6Token;
2136
2137 ASSERT (Wrap != NULL);
2138 HttpInstance = Wrap->HttpInstance;
2139 Rx4Token = NULL;
2140 Rx6Token = NULL;
2141
2142 if (HttpInstance->LocalAddressIsIPv6) {
2143 Rx6Token = &Wrap->TcpWrap.Rx6Token;
2144
2145 if (Rx6Token->CompletionToken.Event != NULL) {
2146 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
2147 Rx6Token->CompletionToken.Event = NULL;
2148 }
2149
2150 FreePool (Wrap);
2151
2152 Rx6Token = &HttpInstance->Rx6Token;
2153
2154 if (Rx6Token->CompletionToken.Event != NULL) {
2155 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
2156 Rx6Token->CompletionToken.Event = NULL;
2157 }
2158
2159 if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
2160 FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
2161 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
2162 }
2163 } else {
2164 Rx4Token = &Wrap->TcpWrap.Rx4Token;
2165
2166 if (Rx4Token->CompletionToken.Event != NULL) {
2167 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
2168 Rx4Token->CompletionToken.Event = NULL;
2169 }
2170
2171 FreePool (Wrap);
2172
2173 Rx4Token = &HttpInstance->Rx4Token;
2174
2175 if (Rx4Token->CompletionToken.Event != NULL) {
2176 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
2177 Rx4Token->CompletionToken.Event = NULL;
2178 }
2179
2180 if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
2181 FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
2182 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
2183 }
2184 }
2185 }
2186
2187 /**
2188 Send Events via EDKII_HTTP_CALLBACK_PROTOCOL.
2189
2190 @param[in] Event The event that occurs in the current state.
2191 @param[in] EventStatus The Status of Event, EFI_SUCCESS or other errors.
2192
2193 **/
2194 VOID
2195 HttpNotify (
2196 IN EDKII_HTTP_CALLBACK_EVENT Event,
2197 IN EFI_STATUS EventStatus
2198 )
2199 {
2200 EFI_STATUS Status;
2201 EFI_HANDLE *Handles;
2202 UINTN Index;
2203 UINTN HandleCount;
2204 EFI_HANDLE Handle;
2205 EDKII_HTTP_CALLBACK_PROTOCOL *HttpCallback;
2206
2207 DEBUG ((DEBUG_INFO, "HttpNotify: Event - %d, EventStatus - %r\n", Event, EventStatus));
2208
2209 Handles = NULL;
2210 HandleCount = 0;
2211 Status = gBS->LocateHandleBuffer (
2212 ByProtocol,
2213 &gEdkiiHttpCallbackProtocolGuid,
2214 NULL,
2215 &HandleCount,
2216 &Handles
2217 );
2218 if (Status == EFI_SUCCESS) {
2219 for (Index = 0; Index < HandleCount; Index++) {
2220 Handle = Handles[Index];
2221 Status = gBS->HandleProtocol (
2222 Handle,
2223 &gEdkiiHttpCallbackProtocolGuid,
2224 (VOID **)&HttpCallback
2225 );
2226 if (Status == EFI_SUCCESS) {
2227 DEBUG ((DEBUG_INFO, "HttpNotify: Notifying %p\n", HttpCallback));
2228 HttpCallback->Callback (
2229 HttpCallback,
2230 Event,
2231 EventStatus
2232 );
2233 }
2234 }
2235
2236 FreePool (Handles);
2237 }
2238 }