VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/NetworkPkg/HttpDxe/HttpProto.c@ 106129

Last change on this file since 106129 was 105670, checked in by vboxsync, 3 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

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

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