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