]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/HttpDxe/HttpProto.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 if ((HttpInstance->State == HTTP_STATE_TCP_CONNECTED) ||
1172 (HttpInstance->State == HTTP_STATE_TCP_CLOSED))
1173 {
1174 Status = HttpInstance->Tcp6->Configure (HttpInstance->Tcp6, NULL);
1175 if (EFI_ERROR (Status)) {
1176 DEBUG ((DEBUG_ERROR, "HttpConfigureTcp6(NULL) - %r\n", Status));
1177 return Status;
1178 }
1179
1180 HttpInstance->State = HTTP_STATE_TCP_UNCONFIGED;
1181 }
1182
1183 Status = HttpInstance->Tcp6->Configure (HttpInstance->Tcp6, Tcp6CfgData);
1184 if (EFI_ERROR (Status)) {
1185 DEBUG ((DEBUG_ERROR, "HttpConfigureTcp6 - %r\n", Status));
1186 return Status;
1187 }
1188
1189 Status = HttpCreateTcpConnCloseEvent (HttpInstance);
1190 if (EFI_ERROR (Status)) {
1191 return Status;
1192 }
1193
1194 Status = HttpCreateTcpTxEvent (Wrap);
1195 if (EFI_ERROR (Status)) {
1196 return Status;
1197 }
1198
1199 HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
1200
1201 return EFI_SUCCESS;
1202 }
1203
1204 /**
1205 Check existing TCP connection, if in error state, recover TCP4 connection. Then,
1206 connect one TLS session if required.
1207
1208 @param[in] HttpInstance The HTTP instance private data.
1209
1210 @retval EFI_SUCCESS The TCP connection is established.
1211 @retval EFI_NOT_READY TCP4 protocol child is not created or configured.
1212 @retval Others Other error as indicated.
1213
1214 **/
1215 EFI_STATUS
1216 HttpConnectTcp4 (
1217 IN HTTP_PROTOCOL *HttpInstance
1218 )
1219 {
1220 EFI_STATUS Status;
1221 EFI_TCP4_CONNECTION_STATE Tcp4State;
1222
1223 if ((HttpInstance->State < HTTP_STATE_TCP_CONFIGED) || (HttpInstance->Tcp4 == NULL)) {
1224 return EFI_NOT_READY;
1225 }
1226
1227 Status = HttpInstance->Tcp4->GetModeData (
1228 HttpInstance->Tcp4,
1229 &Tcp4State,
1230 NULL,
1231 NULL,
1232 NULL,
1233 NULL
1234 );
1235 if (EFI_ERROR (Status)) {
1236 DEBUG ((DEBUG_ERROR, "Tcp4 GetModeData fail - %x\n", Status));
1237 return Status;
1238 }
1239
1240 if (Tcp4State == Tcp4StateEstablished) {
1241 return EFI_SUCCESS;
1242 } else if (Tcp4State > Tcp4StateEstablished ) {
1243 HttpCloseConnection (HttpInstance);
1244 }
1245
1246 Status = HttpCreateConnection (HttpInstance);
1247 if (EFI_ERROR (Status)) {
1248 DEBUG ((DEBUG_ERROR, "Tcp4 Connection fail - %x\n", Status));
1249 return Status;
1250 }
1251
1252 //
1253 // Tls session connection.
1254 //
1255 if (HttpInstance->UseHttps) {
1256 if (HttpInstance->TimeoutEvent == NULL) {
1257 //
1258 // Create TimeoutEvent for TLS connection.
1259 //
1260 Status = gBS->CreateEvent (
1261 EVT_TIMER,
1262 TPL_CALLBACK,
1263 NULL,
1264 NULL,
1265 &HttpInstance->TimeoutEvent
1266 );
1267 if (EFI_ERROR (Status)) {
1268 TlsCloseTxRxEvent (HttpInstance);
1269 return Status;
1270 }
1271 }
1272
1273 //
1274 // Start the timer, and wait Timeout seconds for connection.
1275 //
1276 Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
1277 if (EFI_ERROR (Status)) {
1278 TlsCloseTxRxEvent (HttpInstance);
1279 return Status;
1280 }
1281
1282 Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
1283 HttpNotify (HttpEventTlsConnectSession, Status);
1284
1285 gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
1286
1287 if (EFI_ERROR (Status)) {
1288 TlsCloseTxRxEvent (HttpInstance);
1289 return Status;
1290 }
1291 }
1292
1293 return Status;
1294 }
1295
1296 /**
1297 Check existing TCP connection, if in error state, recover TCP6 connection. Then,
1298 connect one TLS session if required.
1299
1300 @param[in] HttpInstance The HTTP instance private data.
1301
1302 @retval EFI_SUCCESS The TCP connection is established.
1303 @retval EFI_NOT_READY TCP6 protocol child is not created or configured.
1304 @retval Others Other error as indicated.
1305
1306 **/
1307 EFI_STATUS
1308 HttpConnectTcp6 (
1309 IN HTTP_PROTOCOL *HttpInstance
1310 )
1311 {
1312 EFI_STATUS Status;
1313 EFI_TCP6_CONNECTION_STATE Tcp6State;
1314
1315 if ((HttpInstance->State < HTTP_STATE_TCP_CONFIGED) || (HttpInstance->Tcp6 == NULL)) {
1316 return EFI_NOT_READY;
1317 }
1318
1319 Status = HttpInstance->Tcp6->GetModeData (
1320 HttpInstance->Tcp6,
1321 &Tcp6State,
1322 NULL,
1323 NULL,
1324 NULL,
1325 NULL
1326 );
1327
1328 if (EFI_ERROR (Status)) {
1329 DEBUG ((DEBUG_ERROR, "Tcp6 GetModeData fail - %x\n", Status));
1330 return Status;
1331 }
1332
1333 if (Tcp6State == Tcp6StateEstablished) {
1334 return EFI_SUCCESS;
1335 } else if (Tcp6State > Tcp6StateEstablished ) {
1336 HttpCloseConnection (HttpInstance);
1337 }
1338
1339 Status = HttpCreateConnection (HttpInstance);
1340 if (EFI_ERROR (Status)) {
1341 DEBUG ((DEBUG_ERROR, "Tcp6 Connection fail - %x\n", Status));
1342 return Status;
1343 }
1344
1345 //
1346 // Tls session connection.
1347 //
1348 if (HttpInstance->UseHttps) {
1349 if (HttpInstance->TimeoutEvent == NULL) {
1350 //
1351 // Create TimeoutEvent for TLS connection.
1352 //
1353 Status = gBS->CreateEvent (
1354 EVT_TIMER,
1355 TPL_CALLBACK,
1356 NULL,
1357 NULL,
1358 &HttpInstance->TimeoutEvent
1359 );
1360 if (EFI_ERROR (Status)) {
1361 TlsCloseTxRxEvent (HttpInstance);
1362 return Status;
1363 }
1364 }
1365
1366 //
1367 // Start the timer, and wait Timeout seconds for connection.
1368 //
1369 Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
1370 if (EFI_ERROR (Status)) {
1371 TlsCloseTxRxEvent (HttpInstance);
1372 return Status;
1373 }
1374
1375 Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
1376 HttpNotify (HttpEventTlsConnectSession, Status);
1377
1378 gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
1379
1380 if (EFI_ERROR (Status)) {
1381 TlsCloseTxRxEvent (HttpInstance);
1382 return Status;
1383 }
1384 }
1385
1386 return Status;
1387 }
1388
1389 /**
1390 Initialize Http session.
1391
1392 @param[in] HttpInstance The HTTP instance private data.
1393 @param[in] Wrap The HTTP token's wrap data.
1394 @param[in] Configure The Flag indicates whether need to initialize session.
1395 @param[in] TlsConfigure The Flag indicates whether it's the new Tls session.
1396
1397 @retval EFI_SUCCESS The initialization of session is done.
1398 @retval Others Other error as indicated.
1399
1400 **/
1401 EFI_STATUS
1402 HttpInitSession (
1403 IN HTTP_PROTOCOL *HttpInstance,
1404 IN HTTP_TOKEN_WRAP *Wrap,
1405 IN BOOLEAN Configure,
1406 IN BOOLEAN TlsConfigure
1407 )
1408 {
1409 EFI_STATUS Status;
1410
1411 ASSERT (HttpInstance != NULL);
1412
1413 //
1414 // Configure Tls session.
1415 //
1416 if (TlsConfigure) {
1417 Status = TlsConfigureSession (HttpInstance);
1418 if (EFI_ERROR (Status)) {
1419 return Status;
1420 }
1421 }
1422
1423 if (!HttpInstance->LocalAddressIsIPv6) {
1424 //
1425 // Configure TCP instance.
1426 //
1427 if (Configure) {
1428 Status = HttpConfigureTcp4 (HttpInstance, Wrap);
1429 if (EFI_ERROR (Status)) {
1430 return Status;
1431 }
1432 }
1433
1434 //
1435 // Connect TCP.
1436 //
1437 Status = HttpConnectTcp4 (HttpInstance);
1438 if (EFI_ERROR (Status)) {
1439 return Status;
1440 }
1441 } else {
1442 //
1443 // Configure TCP instance.
1444 //
1445 if (Configure) {
1446 Status = HttpConfigureTcp6 (HttpInstance, Wrap);
1447 if (EFI_ERROR (Status)) {
1448 return Status;
1449 }
1450 }
1451
1452 //
1453 // Connect TCP.
1454 //
1455 Status = HttpConnectTcp6 (HttpInstance);
1456 if (EFI_ERROR (Status)) {
1457 return Status;
1458 }
1459 }
1460
1461 return EFI_SUCCESS;
1462 }
1463
1464 /**
1465 Send the HTTP or HTTPS message through TCP4 or TCP6.
1466
1467 @param[in] HttpInstance The HTTP instance private data.
1468 @param[in] Wrap The HTTP token's wrap data.
1469 @param[in] TxString Buffer containing the HTTP message string.
1470 @param[in] TxStringLen Length of the HTTP message string in bytes.
1471
1472 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit queue.
1473 @retval Others Other error as indicated.
1474
1475 **/
1476 EFI_STATUS
1477 HttpTransmitTcp (
1478 IN HTTP_PROTOCOL *HttpInstance,
1479 IN HTTP_TOKEN_WRAP *Wrap,
1480 IN UINT8 *TxString,
1481 IN UINTN TxStringLen
1482 )
1483 {
1484 EFI_STATUS Status;
1485 EFI_TCP4_IO_TOKEN *Tx4Token;
1486 EFI_TCP4_PROTOCOL *Tcp4;
1487 EFI_TCP6_IO_TOKEN *Tx6Token;
1488 EFI_TCP6_PROTOCOL *Tcp6;
1489 UINT8 *TlsRecord;
1490 UINT16 PayloadSize;
1491 NET_FRAGMENT TempFragment;
1492 NET_FRAGMENT Fragment;
1493 UINTN RecordCount;
1494 UINTN RemainingLen;
1495
1496 Status = EFI_SUCCESS;
1497 TlsRecord = NULL;
1498 PayloadSize = 0;
1499 TempFragment.Len = 0;
1500 TempFragment.Bulk = NULL;
1501 Fragment.Len = 0;
1502 Fragment.Bulk = NULL;
1503 RecordCount = 0;
1504 RemainingLen = 0;
1505
1506 //
1507 // Need to encrypt data.
1508 //
1509 if (HttpInstance->UseHttps) {
1510 //
1511 // Allocate enough buffer for each TLS plaintext records.
1512 //
1513 TlsRecord = AllocateZeroPool (TLS_RECORD_HEADER_LENGTH + TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH);
1514 if (TlsRecord == NULL) {
1515 Status = EFI_OUT_OF_RESOURCES;
1516 return Status;
1517 }
1518
1519 //
1520 // Allocate enough buffer for all TLS ciphertext records.
1521 //
1522 RecordCount = TxStringLen / TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH + 1;
1523 Fragment.Bulk = AllocateZeroPool (RecordCount * (TLS_RECORD_HEADER_LENGTH + TLS_CIPHERTEXT_RECORD_MAX_PAYLOAD_LENGTH));
1524 if (Fragment.Bulk == NULL) {
1525 Status = EFI_OUT_OF_RESOURCES;
1526 goto ON_ERROR;
1527 }
1528
1529 //
1530 // Encrypt each TLS plaintext records.
1531 //
1532 RemainingLen = TxStringLen;
1533 while (RemainingLen != 0) {
1534 PayloadSize = (UINT16)MIN (TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH, RemainingLen);
1535
1536 ((TLS_RECORD_HEADER *)TlsRecord)->ContentType = TlsContentTypeApplicationData;
1537 ((TLS_RECORD_HEADER *)TlsRecord)->Version.Major = HttpInstance->TlsConfigData.Version.Major;
1538 ((TLS_RECORD_HEADER *)TlsRecord)->Version.Minor = HttpInstance->TlsConfigData.Version.Minor;
1539 ((TLS_RECORD_HEADER *)TlsRecord)->Length = PayloadSize;
1540
1541 CopyMem (TlsRecord + TLS_RECORD_HEADER_LENGTH, TxString + (TxStringLen - RemainingLen), PayloadSize);
1542
1543 Status = TlsProcessMessage (
1544 HttpInstance,
1545 TlsRecord,
1546 TLS_RECORD_HEADER_LENGTH + PayloadSize,
1547 EfiTlsEncrypt,
1548 &TempFragment
1549 );
1550 if (EFI_ERROR (Status)) {
1551 goto ON_ERROR;
1552 }
1553
1554 //
1555 // Record the processed/encrypted Packet.
1556 //
1557 CopyMem (Fragment.Bulk + Fragment.Len, TempFragment.Bulk, TempFragment.Len);
1558 Fragment.Len += TempFragment.Len;
1559
1560 FreePool (TempFragment.Bulk);
1561 TempFragment.Len = 0;
1562 TempFragment.Bulk = NULL;
1563
1564 RemainingLen -= (UINTN)PayloadSize;
1565 ZeroMem (TlsRecord, TLS_RECORD_HEADER_LENGTH + TLS_PLAINTEXT_RECORD_MAX_PAYLOAD_LENGTH);
1566 }
1567
1568 FreePool (TlsRecord);
1569 TlsRecord = NULL;
1570 }
1571
1572 if (!HttpInstance->LocalAddressIsIPv6) {
1573 Tcp4 = HttpInstance->Tcp4;
1574 Tx4Token = &Wrap->TcpWrap.Tx4Token;
1575
1576 if (HttpInstance->UseHttps) {
1577 Tx4Token->Packet.TxData->DataLength = Fragment.Len;
1578 Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = Fragment.Len;
1579 Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *)Fragment.Bulk;
1580 } else {
1581 Tx4Token->Packet.TxData->DataLength = (UINT32)TxStringLen;
1582 Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32)TxStringLen;
1583 Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *)TxString;
1584 }
1585
1586 Tx4Token->CompletionToken.Status = EFI_NOT_READY;
1587
1588 Wrap->TcpWrap.IsTxDone = FALSE;
1589 Status = Tcp4->Transmit (Tcp4, Tx4Token);
1590 if (EFI_ERROR (Status)) {
1591 DEBUG ((DEBUG_ERROR, "Transmit failed: %r\n", Status));
1592 goto ON_ERROR;
1593 }
1594 } else {
1595 Tcp6 = HttpInstance->Tcp6;
1596 Tx6Token = &Wrap->TcpWrap.Tx6Token;
1597
1598 if (HttpInstance->UseHttps) {
1599 Tx6Token->Packet.TxData->DataLength = Fragment.Len;
1600 Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = Fragment.Len;
1601 Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *)Fragment.Bulk;
1602 } else {
1603 Tx6Token->Packet.TxData->DataLength = (UINT32)TxStringLen;
1604 Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32)TxStringLen;
1605 Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *)TxString;
1606 }
1607
1608 Tx6Token->CompletionToken.Status = EFI_NOT_READY;
1609
1610 Wrap->TcpWrap.IsTxDone = FALSE;
1611 Status = Tcp6->Transmit (Tcp6, Tx6Token);
1612 if (EFI_ERROR (Status)) {
1613 DEBUG ((DEBUG_ERROR, "Transmit failed: %r\n", Status));
1614 goto ON_ERROR;
1615 }
1616 }
1617
1618 return Status;
1619
1620 ON_ERROR:
1621
1622 if (HttpInstance->UseHttps) {
1623 if (TlsRecord != NULL) {
1624 FreePool (TlsRecord);
1625 TlsRecord = NULL;
1626 }
1627
1628 if (Fragment.Bulk != NULL) {
1629 FreePool (Fragment.Bulk);
1630 Fragment.Bulk = NULL;
1631 }
1632 }
1633
1634 return Status;
1635 }
1636
1637 /**
1638 Check whether the user's token or event has already
1639 been enqueue on HTTP Tx or Rx Token list.
1640
1641 @param[in] Map The container of either user's transmit or receive
1642 token.
1643 @param[in] Item Current item to check against.
1644 @param[in] Context The Token to check against.
1645
1646 @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP
1647 @retval EFI_SUCCESS The current item isn't the same token/event as the
1648 context.
1649
1650 **/
1651 EFI_STATUS
1652 EFIAPI
1653 HttpTokenExist (
1654 IN NET_MAP *Map,
1655 IN NET_MAP_ITEM *Item,
1656 IN VOID *Context
1657 )
1658 {
1659 EFI_HTTP_TOKEN *Token;
1660 EFI_HTTP_TOKEN *TokenInItem;
1661
1662 Token = (EFI_HTTP_TOKEN *)Context;
1663 TokenInItem = (EFI_HTTP_TOKEN *)Item->Key;
1664
1665 if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
1666 return EFI_ACCESS_DENIED;
1667 }
1668
1669 return EFI_SUCCESS;
1670 }
1671
1672 /**
1673 Check whether the HTTP message associated with Tx4Token or Tx6Token is already sent out.
1674
1675 @param[in] Map The container of Tx4Token or Tx6Token.
1676 @param[in] Item Current item to check against.
1677 @param[in] Context The Token to check against.
1678
1679 @retval EFI_NOT_READY The HTTP message is still queued in the list.
1680 @retval EFI_SUCCESS The HTTP message has been sent out.
1681
1682 **/
1683 EFI_STATUS
1684 EFIAPI
1685 HttpTcpNotReady (
1686 IN NET_MAP *Map,
1687 IN NET_MAP_ITEM *Item,
1688 IN VOID *Context
1689 )
1690 {
1691 HTTP_TOKEN_WRAP *ValueInItem;
1692
1693 ValueInItem = (HTTP_TOKEN_WRAP *)Item->Value;
1694
1695 if (!ValueInItem->TcpWrap.IsTxDone) {
1696 return EFI_NOT_READY;
1697 }
1698
1699 return EFI_SUCCESS;
1700 }
1701
1702 /**
1703 Transmit the HTTP or HTTPS message by processing the associated HTTP token.
1704
1705 @param[in] Map The container of Tx4Token or Tx6Token.
1706 @param[in] Item Current item to check against.
1707 @param[in] Context The Token to check against.
1708
1709 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1710 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit
1711 queue.
1712
1713 **/
1714 EFI_STATUS
1715 EFIAPI
1716 HttpTcpTransmit (
1717 IN NET_MAP *Map,
1718 IN NET_MAP_ITEM *Item,
1719 IN VOID *Context
1720 )
1721 {
1722 HTTP_TOKEN_WRAP *ValueInItem;
1723 EFI_STATUS Status;
1724 CHAR8 *RequestMsg;
1725 CHAR8 *Url;
1726 UINTN UrlSize;
1727 UINTN RequestMsgSize;
1728
1729 RequestMsg = NULL;
1730
1731 ValueInItem = (HTTP_TOKEN_WRAP *)Item->Value;
1732 if (ValueInItem->TcpWrap.IsTxDone) {
1733 return EFI_SUCCESS;
1734 }
1735
1736 //
1737 // Parse the URI of the remote host.
1738 //
1739 UrlSize = StrLen (ValueInItem->HttpToken->Message->Data.Request->Url) + 1;
1740 Url = AllocatePool (UrlSize);
1741 if (Url == NULL) {
1742 return EFI_OUT_OF_RESOURCES;
1743 }
1744
1745 UnicodeStrToAsciiStrS (ValueInItem->HttpToken->Message->Data.Request->Url, Url, UrlSize);
1746
1747 //
1748 // Create request message.
1749 //
1750 Status = HttpGenRequestMessage (
1751 ValueInItem->HttpToken->Message,
1752 Url,
1753 &RequestMsg,
1754 &RequestMsgSize
1755 );
1756 FreePool (Url);
1757
1758 if (EFI_ERROR (Status) || (NULL == RequestMsg)) {
1759 return Status;
1760 }
1761
1762 ASSERT (RequestMsg != NULL);
1763
1764 //
1765 // Transmit the request message.
1766 //
1767 Status = HttpTransmitTcp (
1768 ValueInItem->HttpInstance,
1769 ValueInItem,
1770 (UINT8 *)RequestMsg,
1771 RequestMsgSize
1772 );
1773 FreePool (RequestMsg);
1774 return Status;
1775 }
1776
1777 /**
1778 Receive the HTTP response by processing the associated HTTP token.
1779
1780 @param[in] Map The container of Rx4Token or Rx6Token.
1781 @param[in] Item Current item to check against.
1782 @param[in] Context The Token to check against.
1783
1784 @retval EFI_SUCCESS The HTTP response is queued into TCP receive
1785 queue.
1786 @retval Others Other error as indicated.
1787
1788 **/
1789 EFI_STATUS
1790 EFIAPI
1791 HttpTcpReceive (
1792 IN NET_MAP *Map,
1793 IN NET_MAP_ITEM *Item,
1794 IN VOID *Context
1795 )
1796 {
1797 //
1798 // Process the queued HTTP response.
1799 //
1800 return HttpResponseWorker ((HTTP_TOKEN_WRAP *)Item->Value);
1801 }
1802
1803 /**
1804 Receive the HTTP header by processing the associated HTTP token.
1805
1806 @param[in] HttpInstance The HTTP instance private data.
1807 @param[in, out] SizeofHeaders The HTTP header length.
1808 @param[in, out] BufferSize The size of buffer to cache the header message.
1809 @param[in] Timeout The time to wait for receiving the header packet.
1810
1811 @retval EFI_SUCCESS The HTTP header is received.
1812 @retval Others Other errors as indicated.
1813
1814 **/
1815 EFI_STATUS
1816 HttpTcpReceiveHeader (
1817 IN HTTP_PROTOCOL *HttpInstance,
1818 IN OUT UINTN *SizeofHeaders,
1819 IN OUT UINTN *BufferSize,
1820 IN EFI_EVENT Timeout
1821 )
1822 {
1823 EFI_STATUS Status;
1824 EFI_TCP4_IO_TOKEN *Rx4Token;
1825 EFI_TCP4_PROTOCOL *Tcp4;
1826 EFI_TCP6_IO_TOKEN *Rx6Token;
1827 EFI_TCP6_PROTOCOL *Tcp6;
1828 CHAR8 **EndofHeader;
1829 CHAR8 **HttpHeaders;
1830 CHAR8 *Buffer;
1831 NET_FRAGMENT Fragment;
1832
1833 ASSERT (HttpInstance != NULL);
1834
1835 EndofHeader = HttpInstance->EndofHeader;
1836 HttpHeaders = HttpInstance->HttpHeaders;
1837 Tcp4 = HttpInstance->Tcp4;
1838 Tcp6 = HttpInstance->Tcp6;
1839 Buffer = NULL;
1840 Rx4Token = NULL;
1841 Rx6Token = NULL;
1842 Fragment.Len = 0;
1843 Fragment.Bulk = NULL;
1844
1845 if (HttpInstance->LocalAddressIsIPv6) {
1846 ASSERT (Tcp6 != NULL);
1847 } else {
1848 ASSERT (Tcp4 != NULL);
1849 }
1850
1851 if (!HttpInstance->UseHttps) {
1852 Status = HttpCreateTcpRxEventForHeader (HttpInstance);
1853 if (EFI_ERROR (Status)) {
1854 return Status;
1855 }
1856 }
1857
1858 if (!HttpInstance->LocalAddressIsIPv6) {
1859 if (!HttpInstance->UseHttps) {
1860 Rx4Token = &HttpInstance->Rx4Token;
1861 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
1862 if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
1863 Status = EFI_OUT_OF_RESOURCES;
1864 return Status;
1865 }
1866 }
1867
1868 //
1869 // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1870 //
1871 while (*EndofHeader == NULL) {
1872 if (!HttpInstance->UseHttps) {
1873 HttpInstance->IsRxDone = FALSE;
1874 Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN;
1875 Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
1876 Status = Tcp4->Receive (Tcp4, Rx4Token);
1877 if (EFI_ERROR (Status)) {
1878 DEBUG ((DEBUG_ERROR, "Tcp4 receive failed: %r\n", Status));
1879 return Status;
1880 }
1881
1882 while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1883 Tcp4->Poll (Tcp4);
1884 }
1885
1886 if (!HttpInstance->IsRxDone) {
1887 //
1888 // Cancel the Token before close its Event.
1889 //
1890 Tcp4->Cancel (HttpInstance->Tcp4, &Rx4Token->CompletionToken);
1891 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
1892 Rx4Token->CompletionToken.Status = EFI_TIMEOUT;
1893 }
1894
1895 Status = Rx4Token->CompletionToken.Status;
1896 if (EFI_ERROR (Status)) {
1897 return Status;
1898 }
1899
1900 Fragment.Len = Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength;
1901 Fragment.Bulk = (UINT8 *)Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer;
1902 } else {
1903 if (Fragment.Bulk != NULL) {
1904 FreePool (Fragment.Bulk);
1905 Fragment.Bulk = NULL;
1906 }
1907
1908 Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
1909 if (EFI_ERROR (Status)) {
1910 DEBUG ((DEBUG_ERROR, "Tcp4 receive failed: %r\n", Status));
1911 return Status;
1912 }
1913 }
1914
1915 //
1916 // Append the response string along with a Null-terminator.
1917 //
1918 *BufferSize = *SizeofHeaders + Fragment.Len;
1919 Buffer = AllocatePool (*BufferSize + 1);
1920 if (Buffer == NULL) {
1921 Status = EFI_OUT_OF_RESOURCES;
1922 return Status;
1923 }
1924
1925 if (*HttpHeaders != NULL) {
1926 CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
1927 FreePool (*HttpHeaders);
1928 }
1929
1930 CopyMem (
1931 Buffer + *SizeofHeaders,
1932 Fragment.Bulk,
1933 Fragment.Len
1934 );
1935 *(Buffer + *BufferSize) = '\0';
1936 *HttpHeaders = Buffer;
1937 *SizeofHeaders = *BufferSize;
1938
1939 //
1940 // Check whether we received end of HTTP headers.
1941 //
1942 *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
1943 }
1944
1945 //
1946 // Free the buffer.
1947 //
1948 if ((Rx4Token != NULL) && (Rx4Token->Packet.RxData != NULL) && (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL)) {
1949 FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
1950 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
1951 Fragment.Bulk = NULL;
1952 }
1953
1954 if (Fragment.Bulk != NULL) {
1955 FreePool (Fragment.Bulk);
1956 Fragment.Bulk = NULL;
1957 }
1958 } else {
1959 if (!HttpInstance->UseHttps) {
1960 Rx6Token = &HttpInstance->Rx6Token;
1961 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
1962 if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
1963 Status = EFI_OUT_OF_RESOURCES;
1964 return Status;
1965 }
1966 }
1967
1968 //
1969 // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1970 //
1971 while (*EndofHeader == NULL) {
1972 if (!HttpInstance->UseHttps) {
1973 HttpInstance->IsRxDone = FALSE;
1974 Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN;
1975 Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
1976 Status = Tcp6->Receive (Tcp6, Rx6Token);
1977 if (EFI_ERROR (Status)) {
1978 DEBUG ((DEBUG_ERROR, "Tcp6 receive failed: %r\n", Status));
1979 return Status;
1980 }
1981
1982 while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1983 Tcp6->Poll (Tcp6);
1984 }
1985
1986 if (!HttpInstance->IsRxDone) {
1987 //
1988 // Cancel the Token before close its Event.
1989 //
1990 Tcp6->Cancel (HttpInstance->Tcp6, &Rx6Token->CompletionToken);
1991 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
1992 Rx6Token->CompletionToken.Status = EFI_TIMEOUT;
1993 }
1994
1995 Status = Rx6Token->CompletionToken.Status;
1996 if (EFI_ERROR (Status)) {
1997 return Status;
1998 }
1999
2000 Fragment.Len = Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength;
2001 Fragment.Bulk = (UINT8 *)Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer;
2002 } else {
2003 if (Fragment.Bulk != NULL) {
2004 FreePool (Fragment.Bulk);
2005 Fragment.Bulk = NULL;
2006 }
2007
2008 Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
2009 if (EFI_ERROR (Status)) {
2010 DEBUG ((DEBUG_ERROR, "Tcp6 receive failed: %r\n", Status));
2011 return Status;
2012 }
2013 }
2014
2015 //
2016 // Append the response string along with a Null-terminator.
2017 //
2018 *BufferSize = *SizeofHeaders + Fragment.Len;
2019 Buffer = AllocatePool (*BufferSize + 1);
2020 if (Buffer == NULL) {
2021 Status = EFI_OUT_OF_RESOURCES;
2022 return Status;
2023 }
2024
2025 if (*HttpHeaders != NULL) {
2026 CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
2027 FreePool (*HttpHeaders);
2028 }
2029
2030 CopyMem (
2031 Buffer + *SizeofHeaders,
2032 Fragment.Bulk,
2033 Fragment.Len
2034 );
2035 *(Buffer + *BufferSize) = '\0';
2036 *HttpHeaders = Buffer;
2037 *SizeofHeaders = *BufferSize;
2038
2039 //
2040 // Check whether we received end of HTTP headers.
2041 //
2042 *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
2043 }
2044
2045 //
2046 // Free the buffer.
2047 //
2048 if ((Rx6Token != NULL) && (Rx6Token->Packet.RxData != NULL) && (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL)) {
2049 FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
2050 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
2051 Fragment.Bulk = NULL;
2052 }
2053
2054 if (Fragment.Bulk != NULL) {
2055 FreePool (Fragment.Bulk);
2056 Fragment.Bulk = NULL;
2057 }
2058 }
2059
2060 //
2061 // Skip the CRLF after the HTTP headers.
2062 //
2063 *EndofHeader = *EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR);
2064
2065 *SizeofHeaders = *EndofHeader - *HttpHeaders;
2066
2067 return EFI_SUCCESS;
2068 }
2069
2070 /**
2071 Receive the HTTP body by processing the associated HTTP token.
2072
2073 @param[in] Wrap The HTTP token's wrap data.
2074 @param[in] HttpMsg The HTTP message data.
2075
2076 @retval EFI_SUCCESS The HTTP body is received.
2077 @retval Others Other error as indicated.
2078
2079 **/
2080 EFI_STATUS
2081 HttpTcpReceiveBody (
2082 IN HTTP_TOKEN_WRAP *Wrap,
2083 IN EFI_HTTP_MESSAGE *HttpMsg
2084 )
2085 {
2086 EFI_STATUS Status;
2087 HTTP_PROTOCOL *HttpInstance;
2088 EFI_TCP6_PROTOCOL *Tcp6;
2089 EFI_TCP6_IO_TOKEN *Rx6Token;
2090 EFI_TCP4_PROTOCOL *Tcp4;
2091 EFI_TCP4_IO_TOKEN *Rx4Token;
2092
2093 HttpInstance = Wrap->HttpInstance;
2094 Tcp4 = HttpInstance->Tcp4;
2095 Tcp6 = HttpInstance->Tcp6;
2096 Rx4Token = NULL;
2097 Rx6Token = NULL;
2098
2099 if (HttpInstance->LocalAddressIsIPv6) {
2100 ASSERT (Tcp6 != NULL);
2101 } else {
2102 ASSERT (Tcp4 != NULL);
2103 }
2104
2105 if (HttpInstance->LocalAddressIsIPv6) {
2106 Rx6Token = &Wrap->TcpWrap.Rx6Token;
2107 Rx6Token->Packet.RxData->DataLength = (UINT32)MIN (MAX_UINT32, HttpMsg->BodyLength);
2108 Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32)MIN (MAX_UINT32, HttpMsg->BodyLength);
2109 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *)HttpMsg->Body;
2110 Rx6Token->CompletionToken.Status = EFI_NOT_READY;
2111
2112 Status = Tcp6->Receive (Tcp6, Rx6Token);
2113 if (EFI_ERROR (Status)) {
2114 DEBUG ((DEBUG_ERROR, "Tcp6 receive failed: %r\n", Status));
2115 return Status;
2116 }
2117 } else {
2118 Rx4Token = &Wrap->TcpWrap.Rx4Token;
2119 Rx4Token->Packet.RxData->DataLength = (UINT32)MIN (MAX_UINT32, HttpMsg->BodyLength);
2120 Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32)MIN (MAX_UINT32, HttpMsg->BodyLength);
2121 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *)HttpMsg->Body;
2122
2123 Rx4Token->CompletionToken.Status = EFI_NOT_READY;
2124 Status = Tcp4->Receive (Tcp4, Rx4Token);
2125 if (EFI_ERROR (Status)) {
2126 DEBUG ((DEBUG_ERROR, "Tcp4 receive failed: %r\n", Status));
2127 return Status;
2128 }
2129 }
2130
2131 return EFI_SUCCESS;
2132 }
2133
2134 /**
2135 Clean up Tcp Tokens while the Tcp transmission error occurs.
2136
2137 @param[in] Wrap Pointer to HTTP token's wrap data.
2138
2139 **/
2140 VOID
2141 HttpTcpTokenCleanup (
2142 IN HTTP_TOKEN_WRAP *Wrap
2143 )
2144 {
2145 HTTP_PROTOCOL *HttpInstance;
2146 EFI_TCP4_IO_TOKEN *Rx4Token;
2147 EFI_TCP6_IO_TOKEN *Rx6Token;
2148
2149 ASSERT (Wrap != NULL);
2150 HttpInstance = Wrap->HttpInstance;
2151 Rx4Token = NULL;
2152 Rx6Token = NULL;
2153
2154 if (HttpInstance->LocalAddressIsIPv6) {
2155 Rx6Token = &Wrap->TcpWrap.Rx6Token;
2156
2157 if (Rx6Token->CompletionToken.Event != NULL) {
2158 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
2159 Rx6Token->CompletionToken.Event = NULL;
2160 }
2161
2162 FreePool (Wrap);
2163
2164 Rx6Token = &HttpInstance->Rx6Token;
2165
2166 if (Rx6Token->CompletionToken.Event != NULL) {
2167 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
2168 Rx6Token->CompletionToken.Event = NULL;
2169 }
2170
2171 if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
2172 FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
2173 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
2174 }
2175 } else {
2176 Rx4Token = &Wrap->TcpWrap.Rx4Token;
2177
2178 if (Rx4Token->CompletionToken.Event != NULL) {
2179 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
2180 Rx4Token->CompletionToken.Event = NULL;
2181 }
2182
2183 FreePool (Wrap);
2184
2185 Rx4Token = &HttpInstance->Rx4Token;
2186
2187 if (Rx4Token->CompletionToken.Event != NULL) {
2188 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
2189 Rx4Token->CompletionToken.Event = NULL;
2190 }
2191
2192 if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
2193 FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
2194 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
2195 }
2196 }
2197 }
2198
2199 /**
2200 Send Events via EDKII_HTTP_CALLBACK_PROTOCOL.
2201
2202 @param[in] Event The event that occurs in the current state.
2203 @param[in] EventStatus The Status of Event, EFI_SUCCESS or other errors.
2204
2205 **/
2206 VOID
2207 HttpNotify (
2208 IN EDKII_HTTP_CALLBACK_EVENT Event,
2209 IN EFI_STATUS EventStatus
2210 )
2211 {
2212 EFI_STATUS Status;
2213 EFI_HANDLE *Handles;
2214 UINTN Index;
2215 UINTN HandleCount;
2216 EFI_HANDLE Handle;
2217 EDKII_HTTP_CALLBACK_PROTOCOL *HttpCallback;
2218
2219 DEBUG ((DEBUG_INFO, "HttpNotify: Event - %d, EventStatus - %r\n", Event, EventStatus));
2220
2221 Handles = NULL;
2222 HandleCount = 0;
2223 Status = gBS->LocateHandleBuffer (
2224 ByProtocol,
2225 &gEdkiiHttpCallbackProtocolGuid,
2226 NULL,
2227 &HandleCount,
2228 &Handles
2229 );
2230 if (Status == EFI_SUCCESS) {
2231 for (Index = 0; Index < HandleCount; Index++) {
2232 Handle = Handles[Index];
2233 Status = gBS->HandleProtocol (
2234 Handle,
2235 &gEdkiiHttpCallbackProtocolGuid,
2236 (VOID **)&HttpCallback
2237 );
2238 if (Status == EFI_SUCCESS) {
2239 DEBUG ((DEBUG_INFO, "HttpNotify: Notifying %p\n", HttpCallback));
2240 HttpCallback->Callback (
2241 HttpCallback,
2242 Event,
2243 EventStatus
2244 );
2245 }
2246 }
2247
2248 FreePool (Handles);
2249 }
2250 }