NetworkPkg/HttpDxe: HTTPS support over IPv4 and IPv6
[mirror_edk2.git] / NetworkPkg / HttpDxe / HttpProto.c
1 /** @file
2 Miscellaneous routines for HttpDxe driver.
3
4 Copyright (c) 2015 - 2016, 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->ImageHandle,
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->ImageHandle,
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->ImageHandle,
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->ImageHandle,
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->ImageHandle,
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->ImageHandle,
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->ImageHandle,
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->ImageHandle,
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->ImageHandle,
760 HttpInstance->Service->ControllerHandle
761 );
762
763 gBS->CloseProtocol (
764 HttpInstance->Tcp4ChildHandle,
765 &gEfiTcp4ProtocolGuid,
766 HttpInstance->Service->ImageHandle,
767 HttpInstance->Handle
768 );
769
770 NetLibDestroyServiceChild (
771 HttpInstance->Service->ControllerHandle,
772 HttpInstance->Service->ImageHandle,
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->ImageHandle,
783 HttpInstance->Handle
784 );
785 }
786
787 if (HttpInstance->Tcp6ChildHandle != NULL) {
788 gBS->CloseProtocol (
789 HttpInstance->Tcp6ChildHandle,
790 &gEfiTcp6ProtocolGuid,
791 HttpInstance->Service->ImageHandle,
792 HttpInstance->Service->ControllerHandle
793 );
794
795 gBS->CloseProtocol (
796 HttpInstance->Tcp6ChildHandle,
797 &gEfiTcp6ProtocolGuid,
798 HttpInstance->Service->ImageHandle,
799 HttpInstance->Handle
800 );
801
802 NetLibDestroyServiceChild (
803 HttpInstance->Service->ControllerHandle,
804 HttpInstance->Service->ImageHandle,
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->ImageHandle,
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->Tcp4ChildHandle != NULL) {
868 gBS->CloseProtocol (
869 HttpInstance->Tcp4ChildHandle,
870 &gEfiTcp4ProtocolGuid,
871 HttpInstance->Service->ImageHandle,
872 HttpInstance->Service->ControllerHandle
873 );
874
875 gBS->CloseProtocol (
876 HttpInstance->Tcp4ChildHandle,
877 &gEfiTcp4ProtocolGuid,
878 HttpInstance->Service->ImageHandle,
879 HttpInstance->Handle
880 );
881
882 NetLibDestroyServiceChild (
883 HttpInstance->Service->ControllerHandle,
884 HttpInstance->Service->ImageHandle,
885 &gEfiTcp4ServiceBindingProtocolGuid,
886 HttpInstance->Tcp4ChildHandle
887 );
888 }
889
890 if (HttpInstance->Service->Tcp4ChildHandle != NULL) {
891 gBS->CloseProtocol (
892 HttpInstance->Service->Tcp4ChildHandle,
893 &gEfiTcp4ProtocolGuid,
894 HttpInstance->Service->ImageHandle,
895 HttpInstance->Handle
896 );
897 }
898
899 if (HttpInstance->Tcp6ChildHandle != NULL) {
900 gBS->CloseProtocol (
901 HttpInstance->Tcp6ChildHandle,
902 &gEfiTcp6ProtocolGuid,
903 HttpInstance->Service->ImageHandle,
904 HttpInstance->Service->ControllerHandle
905 );
906
907 gBS->CloseProtocol (
908 HttpInstance->Tcp6ChildHandle,
909 &gEfiTcp6ProtocolGuid,
910 HttpInstance->Service->ImageHandle,
911 HttpInstance->Handle
912 );
913
914 NetLibDestroyServiceChild (
915 HttpInstance->Service->ControllerHandle,
916 HttpInstance->Service->ImageHandle,
917 &gEfiTcp6ServiceBindingProtocolGuid,
918 HttpInstance->Tcp6ChildHandle
919 );
920 }
921
922 if (HttpInstance->Service->Tcp6ChildHandle != NULL) {
923 gBS->CloseProtocol (
924 HttpInstance->Service->Tcp6ChildHandle,
925 &gEfiTcp6ProtocolGuid,
926 HttpInstance->Service->ImageHandle,
927 HttpInstance->Handle
928 );
929 }
930
931 TlsCloseTxRxEvent (HttpInstance);
932 }
933
934 /**
935 Establish TCP connection with HTTP server.
936
937 @param[in] HttpInstance The HTTP instance private data.
938
939 @retval EFI_SUCCESS The TCP connection is established.
940 @retval Others Other error as indicated.
941
942 **/
943 EFI_STATUS
944 HttpCreateConnection (
945 IN HTTP_PROTOCOL *HttpInstance
946 )
947 {
948 EFI_STATUS Status;
949
950 //
951 // Connect to Http server
952 //
953 if (!HttpInstance->LocalAddressIsIPv6) {
954 HttpInstance->IsTcp4ConnDone = FALSE;
955 HttpInstance->Tcp4ConnToken.CompletionToken.Status = EFI_NOT_READY;
956 Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->Tcp4ConnToken);
957 if (EFI_ERROR (Status)) {
958 DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status));
959 return Status;
960 }
961
962 while (!HttpInstance->IsTcp4ConnDone) {
963 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
964 }
965
966 Status = HttpInstance->Tcp4ConnToken.CompletionToken.Status;
967
968 } else {
969 HttpInstance->IsTcp6ConnDone = FALSE;
970 HttpInstance->Tcp6ConnToken.CompletionToken.Status = EFI_NOT_READY;
971 Status = HttpInstance->Tcp6->Connect (HttpInstance->Tcp6, &HttpInstance->Tcp6ConnToken);
972 if (EFI_ERROR (Status)) {
973 DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp6->Connect() = %r\n", Status));
974 return Status;
975 }
976
977 while(!HttpInstance->IsTcp6ConnDone) {
978 HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
979 }
980
981 Status = HttpInstance->Tcp6ConnToken.CompletionToken.Status;
982 }
983
984 if (!EFI_ERROR (Status)) {
985 HttpInstance->State = HTTP_STATE_TCP_CONNECTED;
986 }
987
988 return Status;
989 }
990
991 /**
992 Close existing TCP connection.
993
994 @param[in] HttpInstance The HTTP instance private data.
995
996 @retval EFI_SUCCESS The TCP connection is closed.
997 @retval Others Other error as indicated.
998
999 **/
1000 EFI_STATUS
1001 HttpCloseConnection (
1002 IN HTTP_PROTOCOL *HttpInstance
1003 )
1004 {
1005 EFI_STATUS Status;
1006
1007 if (HttpInstance->State == HTTP_STATE_TCP_CONNECTED) {
1008
1009 if (HttpInstance->LocalAddressIsIPv6) {
1010 HttpInstance->Tcp6CloseToken.AbortOnClose = TRUE;
1011 HttpInstance->IsTcp6CloseDone = FALSE;
1012 Status = HttpInstance->Tcp6->Close (HttpInstance->Tcp6, &HttpInstance->Tcp6CloseToken);
1013 if (EFI_ERROR (Status)) {
1014 return Status;
1015 }
1016
1017 while (!HttpInstance->IsTcp6CloseDone) {
1018 HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
1019 }
1020
1021 } else {
1022 HttpInstance->Tcp4CloseToken.AbortOnClose = TRUE;
1023 HttpInstance->IsTcp4CloseDone = FALSE;
1024 Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->Tcp4CloseToken);
1025 if (EFI_ERROR (Status)) {
1026 return Status;
1027 }
1028
1029 while (!HttpInstance->IsTcp4CloseDone) {
1030 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
1031 }
1032 }
1033
1034 }
1035
1036 HttpInstance->State = HTTP_STATE_TCP_CLOSED;
1037 return EFI_SUCCESS;
1038 }
1039
1040 /**
1041 Configure TCP4 protocol child.
1042
1043 @param[in] HttpInstance The HTTP instance private data.
1044 @param[in] Wrap The HTTP token's wrap data.
1045
1046 @retval EFI_SUCCESS The TCP4 protocol child is configured.
1047 @retval Others Other error as indicated.
1048
1049 **/
1050 EFI_STATUS
1051 HttpConfigureTcp4 (
1052 IN HTTP_PROTOCOL *HttpInstance,
1053 IN HTTP_TOKEN_WRAP *Wrap
1054 )
1055 {
1056 EFI_STATUS Status;
1057 EFI_TCP4_CONFIG_DATA *Tcp4CfgData;
1058 EFI_TCP4_ACCESS_POINT *Tcp4AP;
1059 EFI_TCP4_OPTION *Tcp4Option;
1060
1061 ASSERT (HttpInstance != NULL);
1062
1063
1064 Tcp4CfgData = &HttpInstance->Tcp4CfgData;
1065 ZeroMem (Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA));
1066
1067 Tcp4CfgData->TypeOfService = HTTP_TOS_DEAULT;
1068 Tcp4CfgData->TimeToLive = HTTP_TTL_DEAULT;
1069 Tcp4CfgData->ControlOption = &HttpInstance->Tcp4Option;
1070
1071 Tcp4AP = &Tcp4CfgData->AccessPoint;
1072 Tcp4AP->UseDefaultAddress = HttpInstance->IPv4Node.UseDefaultAddress;
1073 if (!Tcp4AP->UseDefaultAddress) {
1074 IP4_COPY_ADDRESS (&Tcp4AP->StationAddress, &HttpInstance->IPv4Node.LocalAddress);
1075 IP4_COPY_ADDRESS (&Tcp4AP->SubnetMask, &HttpInstance->IPv4Node.LocalSubnet);
1076 }
1077
1078 Tcp4AP->StationPort = HttpInstance->IPv4Node.LocalPort;
1079 Tcp4AP->RemotePort = HttpInstance->RemotePort;
1080 Tcp4AP->ActiveFlag = TRUE;
1081 IP4_COPY_ADDRESS (&Tcp4AP->RemoteAddress, &HttpInstance->RemoteAddr);
1082
1083 Tcp4Option = Tcp4CfgData->ControlOption;
1084 Tcp4Option->ReceiveBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1085 Tcp4Option->SendBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1086 Tcp4Option->MaxSynBackLog = HTTP_MAX_SYN_BACK_LOG;
1087 Tcp4Option->ConnectionTimeout = HTTP_CONNECTION_TIMEOUT;
1088 Tcp4Option->DataRetries = HTTP_DATA_RETRIES;
1089 Tcp4Option->FinTimeout = HTTP_FIN_TIMEOUT;
1090 Tcp4Option->KeepAliveProbes = HTTP_KEEP_ALIVE_PROBES;
1091 Tcp4Option->KeepAliveTime = HTTP_KEEP_ALIVE_TIME;
1092 Tcp4Option->KeepAliveInterval = HTTP_KEEP_ALIVE_INTERVAL;
1093 Tcp4Option->EnableNagle = TRUE;
1094 Tcp4CfgData->ControlOption = Tcp4Option;
1095
1096 Status = HttpInstance->Tcp4->Configure (HttpInstance->Tcp4, Tcp4CfgData);
1097 if (EFI_ERROR (Status)) {
1098 DEBUG ((EFI_D_ERROR, "HttpConfigureTcp4 - %r\n", Status));
1099 return Status;
1100 }
1101
1102 Status = HttpCreateTcpConnCloseEvent (HttpInstance);
1103 if (EFI_ERROR (Status)) {
1104 return Status;
1105 }
1106
1107 Status = HttpCreateTcpTxEvent (Wrap);
1108 if (EFI_ERROR (Status)) {
1109 return Status;
1110 }
1111
1112 HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
1113
1114 return EFI_SUCCESS;
1115 }
1116
1117 /**
1118 Configure TCP6 protocol child.
1119
1120 @param[in] HttpInstance The HTTP instance private data.
1121 @param[in] Wrap The HTTP token's wrap data.
1122
1123 @retval EFI_SUCCESS The TCP6 protocol child is configured.
1124 @retval Others Other error as indicated.
1125
1126 **/
1127 EFI_STATUS
1128 HttpConfigureTcp6 (
1129 IN HTTP_PROTOCOL *HttpInstance,
1130 IN HTTP_TOKEN_WRAP *Wrap
1131 )
1132 {
1133 EFI_STATUS Status;
1134 EFI_TCP6_CONFIG_DATA *Tcp6CfgData;
1135 EFI_TCP6_ACCESS_POINT *Tcp6Ap;
1136 EFI_TCP6_OPTION *Tcp6Option;
1137
1138 ASSERT (HttpInstance != NULL);
1139
1140 Tcp6CfgData = &HttpInstance->Tcp6CfgData;
1141 ZeroMem (Tcp6CfgData, sizeof (EFI_TCP6_CONFIG_DATA));
1142
1143 Tcp6CfgData->TrafficClass = 0;
1144 Tcp6CfgData->HopLimit = 255;
1145 Tcp6CfgData->ControlOption = &HttpInstance->Tcp6Option;
1146
1147 Tcp6Ap = &Tcp6CfgData->AccessPoint;
1148 Tcp6Ap->ActiveFlag = TRUE;
1149 Tcp6Ap->StationPort = HttpInstance->Ipv6Node.LocalPort;
1150 Tcp6Ap->RemotePort = HttpInstance->RemotePort;
1151 IP6_COPY_ADDRESS (&Tcp6Ap->StationAddress, &HttpInstance->Ipv6Node.LocalAddress);
1152 IP6_COPY_ADDRESS (&Tcp6Ap->RemoteAddress , &HttpInstance->RemoteIpv6Addr);
1153
1154 Tcp6Option = Tcp6CfgData->ControlOption;
1155 Tcp6Option->ReceiveBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1156 Tcp6Option->SendBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1157 Tcp6Option->MaxSynBackLog = HTTP_MAX_SYN_BACK_LOG;
1158 Tcp6Option->ConnectionTimeout = HTTP_CONNECTION_TIMEOUT;
1159 Tcp6Option->DataRetries = HTTP_DATA_RETRIES;
1160 Tcp6Option->FinTimeout = HTTP_FIN_TIMEOUT;
1161 Tcp6Option->KeepAliveProbes = HTTP_KEEP_ALIVE_PROBES;
1162 Tcp6Option->KeepAliveTime = HTTP_KEEP_ALIVE_TIME;
1163 Tcp6Option->KeepAliveInterval = HTTP_KEEP_ALIVE_INTERVAL;
1164 Tcp6Option->EnableNagle = TRUE;
1165
1166 Status = HttpInstance->Tcp6->Configure (HttpInstance->Tcp6, Tcp6CfgData);
1167 if (EFI_ERROR (Status)) {
1168 DEBUG ((EFI_D_ERROR, "HttpConfigureTcp6 - %r\n", Status));
1169 return Status;
1170 }
1171
1172 Status = HttpCreateTcpConnCloseEvent (HttpInstance);
1173 if (EFI_ERROR (Status)) {
1174 return Status;
1175 }
1176
1177 Status = HttpCreateTcpTxEvent (Wrap);
1178 if (EFI_ERROR (Status)) {
1179 return Status;
1180 }
1181
1182 HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
1183
1184 return EFI_SUCCESS;
1185
1186 }
1187
1188 /**
1189 Check existing TCP connection, if in error state, recover TCP4 connection. Then,
1190 connect one TLS session if required.
1191
1192 @param[in] HttpInstance The HTTP instance private data.
1193
1194 @retval EFI_SUCCESS The TCP connection is established.
1195 @retval EFI_NOT_READY TCP4 protocol child is not created or configured.
1196 @retval Others Other error as indicated.
1197
1198 **/
1199 EFI_STATUS
1200 HttpConnectTcp4 (
1201 IN HTTP_PROTOCOL *HttpInstance
1202 )
1203 {
1204 EFI_STATUS Status;
1205 EFI_TCP4_CONNECTION_STATE Tcp4State;
1206
1207
1208 if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp4 == NULL) {
1209 return EFI_NOT_READY;
1210 }
1211
1212 Status = HttpInstance->Tcp4->GetModeData(
1213 HttpInstance->Tcp4,
1214 &Tcp4State,
1215 NULL,
1216 NULL,
1217 NULL,
1218 NULL
1219 );
1220 if (EFI_ERROR(Status)){
1221 DEBUG ((EFI_D_ERROR, "Tcp4 GetModeData fail - %x\n", Status));
1222 return Status;
1223 }
1224
1225 if (Tcp4State == Tcp4StateEstablished) {
1226 return EFI_SUCCESS;
1227 } else if (Tcp4State > Tcp4StateEstablished ) {
1228 HttpCloseConnection(HttpInstance);
1229 }
1230
1231 Status = HttpCreateConnection (HttpInstance);
1232 if (EFI_ERROR(Status)){
1233 DEBUG ((EFI_D_ERROR, "Tcp4 Connection fail - %x\n", Status));
1234 return Status;
1235 }
1236
1237 //
1238 // Tls session connection.
1239 //
1240 if (HttpInstance->UseHttps) {
1241 if (HttpInstance->TimeoutEvent == NULL) {
1242 //
1243 // Create TimeoutEvent for TLS connection.
1244 //
1245 Status = gBS->CreateEvent (
1246 EVT_TIMER,
1247 TPL_CALLBACK,
1248 NULL,
1249 NULL,
1250 &HttpInstance->TimeoutEvent
1251 );
1252 if (EFI_ERROR (Status)) {
1253 TlsCloseTxRxEvent (HttpInstance);
1254 return Status;
1255 }
1256 }
1257
1258 //
1259 // Start the timer, and wait Timeout seconds for connection.
1260 //
1261 Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
1262 if (EFI_ERROR (Status)) {
1263 TlsCloseTxRxEvent (HttpInstance);
1264 return Status;
1265 }
1266
1267 Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
1268
1269 gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
1270
1271 if (EFI_ERROR (Status)) {
1272 TlsCloseTxRxEvent (HttpInstance);
1273 return Status;
1274 }
1275 }
1276
1277 return Status;
1278 }
1279
1280 /**
1281 Check existing TCP connection, if in error state, recover TCP6 connection. Then,
1282 connect one TLS session if required.
1283
1284 @param[in] HttpInstance The HTTP instance private data.
1285
1286 @retval EFI_SUCCESS The TCP connection is established.
1287 @retval EFI_NOT_READY TCP6 protocol child is not created or configured.
1288 @retval Others Other error as indicated.
1289
1290 **/
1291 EFI_STATUS
1292 HttpConnectTcp6 (
1293 IN HTTP_PROTOCOL *HttpInstance
1294 )
1295 {
1296 EFI_STATUS Status;
1297 EFI_TCP6_CONNECTION_STATE Tcp6State;
1298
1299 if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp6 == NULL) {
1300 return EFI_NOT_READY;
1301 }
1302
1303 Status = HttpInstance->Tcp6->GetModeData (
1304 HttpInstance->Tcp6,
1305 &Tcp6State,
1306 NULL,
1307 NULL,
1308 NULL,
1309 NULL
1310 );
1311
1312 if (EFI_ERROR(Status)){
1313 DEBUG ((EFI_D_ERROR, "Tcp6 GetModeData fail - %x\n", Status));
1314 return Status;
1315 }
1316
1317 if (Tcp6State == Tcp6StateEstablished) {
1318 return EFI_SUCCESS;
1319 } else if (Tcp6State > Tcp6StateEstablished ) {
1320 HttpCloseConnection(HttpInstance);
1321 }
1322
1323 Status = HttpCreateConnection (HttpInstance);
1324 if (EFI_ERROR(Status)){
1325 DEBUG ((EFI_D_ERROR, "Tcp6 Connection fail - %x\n", Status));
1326 return Status;
1327 }
1328
1329 //
1330 // Tls session connection.
1331 //
1332 if (HttpInstance->UseHttps) {
1333 if (HttpInstance->TimeoutEvent == NULL) {
1334 //
1335 // Create TimeoutEvent for TLS connection.
1336 //
1337 Status = gBS->CreateEvent (
1338 EVT_TIMER,
1339 TPL_CALLBACK,
1340 NULL,
1341 NULL,
1342 &HttpInstance->TimeoutEvent
1343 );
1344 if (EFI_ERROR (Status)) {
1345 TlsCloseTxRxEvent (HttpInstance);
1346 return Status;
1347 }
1348 }
1349
1350 //
1351 // Start the timer, and wait Timeout seconds for connection.
1352 //
1353 Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
1354 if (EFI_ERROR (Status)) {
1355 TlsCloseTxRxEvent (HttpInstance);
1356 return Status;
1357 }
1358
1359 Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
1360
1361 gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
1362
1363 if (EFI_ERROR (Status)) {
1364 TlsCloseTxRxEvent (HttpInstance);
1365 return Status;
1366 }
1367 }
1368
1369 return Status;
1370 }
1371
1372 /**
1373 Initialize Http session.
1374
1375 @param[in] HttpInstance The HTTP instance private data.
1376 @param[in] Wrap The HTTP token's wrap data.
1377 @param[in] Configure The Flag indicates whether need to initialize session.
1378 @param[in] TlsConfigure The Flag indicates whether it's the new Tls session.
1379
1380 @retval EFI_SUCCESS The initialization of session is done.
1381 @retval Others Other error as indicated.
1382
1383 **/
1384 EFI_STATUS
1385 HttpInitSession (
1386 IN HTTP_PROTOCOL *HttpInstance,
1387 IN HTTP_TOKEN_WRAP *Wrap,
1388 IN BOOLEAN Configure,
1389 IN BOOLEAN TlsConfigure
1390 )
1391 {
1392 EFI_STATUS Status;
1393 ASSERT (HttpInstance != NULL);
1394
1395 //
1396 // Configure Tls session.
1397 //
1398 if (TlsConfigure) {
1399 Status = TlsConfigureSession (HttpInstance);
1400 if (EFI_ERROR (Status)) {
1401 return Status;
1402 }
1403 }
1404
1405 if (!HttpInstance->LocalAddressIsIPv6) {
1406 //
1407 // Configure TCP instance.
1408 //
1409 if (Configure) {
1410 Status = HttpConfigureTcp4 (HttpInstance, Wrap);
1411 if (EFI_ERROR (Status)) {
1412 return Status;
1413 }
1414 }
1415
1416 //
1417 // Connect TCP.
1418 //
1419 Status = HttpConnectTcp4 (HttpInstance);
1420 if (EFI_ERROR (Status)) {
1421 return Status;
1422 }
1423 } else {
1424 //
1425 // Configure TCP instance.
1426 //
1427 if (Configure) {
1428 Status = HttpConfigureTcp6 (HttpInstance, Wrap);
1429 if (EFI_ERROR (Status)) {
1430 return Status;
1431 }
1432 }
1433
1434 //
1435 // Connect TCP.
1436 //
1437 Status = HttpConnectTcp6 (HttpInstance);
1438 if (EFI_ERROR (Status)) {
1439 return Status;
1440 }
1441 }
1442
1443 return EFI_SUCCESS;
1444
1445 }
1446
1447 /**
1448 Send the HTTP or HTTPS message through TCP4 or TCP6.
1449
1450 @param[in] HttpInstance The HTTP instance private data.
1451 @param[in] Wrap The HTTP token's wrap data.
1452 @param[in] TxString Buffer containing the HTTP message string.
1453 @param[in] TxStringLen Length of the HTTP message string in bytes.
1454
1455 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit queue.
1456 @retval Others Other error as indicated.
1457
1458 **/
1459 EFI_STATUS
1460 HttpTransmitTcp (
1461 IN HTTP_PROTOCOL *HttpInstance,
1462 IN HTTP_TOKEN_WRAP *Wrap,
1463 IN UINT8 *TxString,
1464 IN UINTN TxStringLen
1465 )
1466 {
1467 EFI_STATUS Status;
1468 EFI_TCP4_IO_TOKEN *Tx4Token;
1469 EFI_TCP4_PROTOCOL *Tcp4;
1470 EFI_TCP6_IO_TOKEN *Tx6Token;
1471 EFI_TCP6_PROTOCOL *Tcp6;
1472 UINT8 *Buffer;
1473 UINTN BufferSize;
1474 NET_FRAGMENT TempFragment;
1475
1476 Status = EFI_SUCCESS;
1477 Buffer = NULL;
1478
1479 //
1480 // Need to encrypt data.
1481 //
1482 if (HttpInstance->UseHttps) {
1483 //
1484 // Build BufferOut data
1485 //
1486 BufferSize = sizeof (TLS_RECORD_HEADER) + TxStringLen;
1487 Buffer = AllocateZeroPool (BufferSize);
1488 if (Buffer == NULL) {
1489 Status = EFI_OUT_OF_RESOURCES;
1490 return Status;
1491 }
1492 ((TLS_RECORD_HEADER *) Buffer)->ContentType = TLS_CONTENT_TYPE_APPLICATION_DATA;
1493 ((TLS_RECORD_HEADER *) Buffer)->Version.Major = HttpInstance->TlsConfigData.Version.Major;
1494 ((TLS_RECORD_HEADER *) Buffer)->Version.Minor = HttpInstance->TlsConfigData.Version.Minor;
1495 ((TLS_RECORD_HEADER *) Buffer)->Length = (UINT16) (TxStringLen);
1496 CopyMem (Buffer + sizeof (TLS_RECORD_HEADER), TxString, TxStringLen);
1497
1498 //
1499 // Encrypt Packet.
1500 //
1501 Status = TlsProcessMessage (
1502 HttpInstance,
1503 Buffer,
1504 BufferSize,
1505 EfiTlsEncrypt,
1506 &TempFragment
1507 );
1508
1509 FreePool (Buffer);
1510
1511 if (EFI_ERROR (Status)) {
1512 return Status;
1513 }
1514 }
1515
1516 if (!HttpInstance->LocalAddressIsIPv6) {
1517 Tcp4 = HttpInstance->Tcp4;
1518 Tx4Token = &Wrap->TcpWrap.Tx4Token;
1519
1520 if (HttpInstance->UseHttps) {
1521 Tx4Token->Packet.TxData->DataLength = TempFragment.Len;
1522 Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = TempFragment.Len;
1523 Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TempFragment.Bulk;
1524 } else {
1525 Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
1526 Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;
1527 Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;
1528 }
1529
1530 Tx4Token->CompletionToken.Status = EFI_NOT_READY;
1531
1532 Wrap->TcpWrap.IsTxDone = FALSE;
1533 Status = Tcp4->Transmit (Tcp4, Tx4Token);
1534 if (EFI_ERROR (Status)) {
1535 DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));
1536 return Status;
1537 }
1538
1539 } else {
1540 Tcp6 = HttpInstance->Tcp6;
1541 Tx6Token = &Wrap->TcpWrap.Tx6Token;
1542
1543 if (HttpInstance->UseHttps) {
1544 Tx6Token->Packet.TxData->DataLength = TempFragment.Len;
1545 Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = TempFragment.Len;
1546 Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TempFragment.Bulk;
1547 } else {
1548 Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
1549 Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;
1550 Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;
1551 }
1552
1553 Tx6Token->CompletionToken.Status = EFI_NOT_READY;
1554
1555 Wrap->TcpWrap.IsTxDone = FALSE;
1556 Status = Tcp6->Transmit (Tcp6, Tx6Token);
1557 if (EFI_ERROR (Status)) {
1558 DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));
1559 return Status;
1560 }
1561 }
1562
1563 return Status;
1564 }
1565
1566 /**
1567 Check whether the user's token or event has already
1568 been enqueue on HTTP Tx or Rx Token list.
1569
1570 @param[in] Map The container of either user's transmit or receive
1571 token.
1572 @param[in] Item Current item to check against.
1573 @param[in] Context The Token to check againist.
1574
1575 @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP
1576 @retval EFI_SUCCESS The current item isn't the same token/event as the
1577 context.
1578
1579 **/
1580 EFI_STATUS
1581 EFIAPI
1582 HttpTokenExist (
1583 IN NET_MAP *Map,
1584 IN NET_MAP_ITEM *Item,
1585 IN VOID *Context
1586 )
1587 {
1588 EFI_HTTP_TOKEN *Token;
1589 EFI_HTTP_TOKEN *TokenInItem;
1590
1591 Token = (EFI_HTTP_TOKEN *) Context;
1592 TokenInItem = (EFI_HTTP_TOKEN *) Item->Key;
1593
1594 if (Token == TokenInItem || Token->Event == TokenInItem->Event) {
1595 return EFI_ACCESS_DENIED;
1596 }
1597
1598 return EFI_SUCCESS;
1599 }
1600
1601 /**
1602 Check whether the HTTP message associated with Tx4Token or Tx6Token is already sent out.
1603
1604 @param[in] Map The container of Tx4Token or Tx6Token.
1605 @param[in] Item Current item to check against.
1606 @param[in] Context The Token to check againist.
1607
1608 @retval EFI_NOT_READY The HTTP message is still queued in the list.
1609 @retval EFI_SUCCESS The HTTP message has been sent out.
1610
1611 **/
1612 EFI_STATUS
1613 EFIAPI
1614 HttpTcpNotReady (
1615 IN NET_MAP *Map,
1616 IN NET_MAP_ITEM *Item,
1617 IN VOID *Context
1618 )
1619 {
1620 HTTP_TOKEN_WRAP *ValueInItem;
1621
1622 ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
1623
1624 if (!ValueInItem->TcpWrap.IsTxDone) {
1625 return EFI_NOT_READY;
1626 }
1627
1628 return EFI_SUCCESS;
1629 }
1630
1631 /**
1632 Transmit the HTTP or HTTPS mssage by processing the associated HTTP token.
1633
1634 @param[in] Map The container of Tx4Token or Tx6Token.
1635 @param[in] Item Current item to check against.
1636 @param[in] Context The Token to check againist.
1637
1638 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1639 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit
1640 queue.
1641
1642 **/
1643 EFI_STATUS
1644 EFIAPI
1645 HttpTcpTransmit (
1646 IN NET_MAP *Map,
1647 IN NET_MAP_ITEM *Item,
1648 IN VOID *Context
1649 )
1650 {
1651 HTTP_TOKEN_WRAP *ValueInItem;
1652 EFI_STATUS Status;
1653 CHAR8 *RequestMsg;
1654 CHAR8 *Url;
1655 UINTN UrlSize;
1656 UINTN RequestMsgSize;
1657
1658 ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
1659 if (ValueInItem->TcpWrap.IsTxDone) {
1660 return EFI_SUCCESS;
1661 }
1662
1663 //
1664 // Parse the URI of the remote host.
1665 //
1666 UrlSize = StrLen (ValueInItem->HttpToken->Message->Data.Request->Url) + 1;
1667 Url = AllocatePool (UrlSize);
1668 if (Url == NULL) {
1669 return EFI_OUT_OF_RESOURCES;
1670 }
1671
1672 UnicodeStrToAsciiStrS (ValueInItem->HttpToken->Message->Data.Request->Url, Url, UrlSize);
1673
1674 //
1675 // Create request message.
1676 //
1677 Status = HttpGenRequestMessage (
1678 ValueInItem->HttpToken->Message,
1679 Url,
1680 &RequestMsg,
1681 &RequestMsgSize
1682 );
1683 FreePool (Url);
1684
1685 if (EFI_ERROR (Status)){
1686 return Status;
1687 }
1688
1689 //
1690 // Transmit the request message.
1691 //
1692 Status = HttpTransmitTcp (
1693 ValueInItem->HttpInstance,
1694 ValueInItem,
1695 (UINT8*) RequestMsg,
1696 RequestMsgSize
1697 );
1698 FreePool (RequestMsg);
1699 return Status;
1700 }
1701
1702 /**
1703 Receive the HTTP response by processing the associated HTTP token.
1704
1705 @param[in] Map The container of Rx4Token or Rx6Token.
1706 @param[in] Item Current item to check against.
1707 @param[in] Context The Token to check againist.
1708
1709 @retval EFI_SUCCESS The HTTP response is queued into TCP receive
1710 queue.
1711 @retval Others Other error as indicated.
1712
1713 **/
1714 EFI_STATUS
1715 EFIAPI
1716 HttpTcpReceive (
1717 IN NET_MAP *Map,
1718 IN NET_MAP_ITEM *Item,
1719 IN VOID *Context
1720 )
1721 {
1722 //
1723 // Process the queued HTTP response.
1724 //
1725 return HttpResponseWorker ((HTTP_TOKEN_WRAP *) Item->Value);
1726 }
1727
1728 /**
1729 Receive the HTTP header by processing the associated HTTP token.
1730
1731 @param[in] HttpInstance The HTTP instance private data.
1732 @param[in, out] SizeofHeaders The HTTP header length.
1733 @param[in, out] BufferSize The size of buffer to cacahe the header message.
1734 @param[in] Timeout The time to wait for receiving the header packet.
1735
1736 @retval EFI_SUCCESS The HTTP header is received.
1737 @retval Others Other errors as indicated.
1738
1739 **/
1740 EFI_STATUS
1741 HttpTcpReceiveHeader (
1742 IN HTTP_PROTOCOL *HttpInstance,
1743 IN OUT UINTN *SizeofHeaders,
1744 IN OUT UINTN *BufferSize,
1745 IN EFI_EVENT Timeout
1746 )
1747 {
1748 EFI_STATUS Status;
1749 EFI_TCP4_IO_TOKEN *Rx4Token;
1750 EFI_TCP4_PROTOCOL *Tcp4;
1751 EFI_TCP6_IO_TOKEN *Rx6Token;
1752 EFI_TCP6_PROTOCOL *Tcp6;
1753 CHAR8 **EndofHeader;
1754 CHAR8 **HttpHeaders;
1755 CHAR8 *Buffer;
1756 NET_FRAGMENT Fragment;
1757
1758 ASSERT (HttpInstance != NULL);
1759
1760 EndofHeader = HttpInstance->EndofHeader;
1761 HttpHeaders = HttpInstance->HttpHeaders;
1762 Tcp4 = HttpInstance->Tcp4;
1763 Tcp6 = HttpInstance->Tcp6;
1764 Buffer = NULL;
1765 Rx4Token = NULL;
1766 Rx6Token = NULL;
1767 Fragment.Len = 0;
1768 Fragment.Bulk = NULL;
1769
1770 if (HttpInstance->LocalAddressIsIPv6) {
1771 ASSERT (Tcp6 != NULL);
1772 } else {
1773 ASSERT (Tcp4 != NULL);
1774 }
1775
1776 if (!HttpInstance->UseHttps) {
1777 Status = HttpCreateTcpRxEventForHeader (HttpInstance);
1778 if (EFI_ERROR (Status)) {
1779 return Status;
1780 }
1781 }
1782
1783 if (!HttpInstance->LocalAddressIsIPv6) {
1784 if (!HttpInstance->UseHttps) {
1785 Rx4Token = &HttpInstance->Rx4Token;
1786 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
1787 if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
1788 Status = EFI_OUT_OF_RESOURCES;
1789 return Status;
1790 }
1791 }
1792
1793 //
1794 // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1795 //
1796 while (*EndofHeader == NULL) {
1797 if (!HttpInstance->UseHttps) {
1798 HttpInstance->IsRxDone = FALSE;
1799 Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN;
1800 Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
1801 Status = Tcp4->Receive (Tcp4, Rx4Token);
1802 if (EFI_ERROR (Status)) {
1803 DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
1804 return Status;
1805 }
1806
1807 while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1808 Tcp4->Poll (Tcp4);
1809 }
1810
1811 if (!HttpInstance->IsRxDone) {
1812 //
1813 // Cancle the Token before close its Event.
1814 //
1815 Tcp4->Cancel (HttpInstance->Tcp4, &Rx4Token->CompletionToken);
1816 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
1817 Rx4Token->CompletionToken.Status = EFI_TIMEOUT;
1818 }
1819
1820 Status = Rx4Token->CompletionToken.Status;
1821 if (EFI_ERROR (Status)) {
1822 return Status;
1823 }
1824
1825 Fragment.Len = Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength;
1826 Fragment.Bulk = (UINT8 *) Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer;
1827 } else {
1828 if (Fragment.Bulk != NULL) {
1829 FreePool (Fragment.Bulk);
1830 Fragment.Bulk = NULL;
1831 }
1832
1833 Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
1834 if (EFI_ERROR (Status)) {
1835 DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
1836 return Status;
1837 }
1838 }
1839
1840 //
1841 // Append the response string.
1842 //
1843 *BufferSize = *SizeofHeaders + Fragment.Len;
1844 Buffer = AllocateZeroPool (*BufferSize);
1845 if (Buffer == NULL) {
1846 Status = EFI_OUT_OF_RESOURCES;
1847 return Status;
1848 }
1849
1850 if (*HttpHeaders != NULL) {
1851 CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
1852 FreePool (*HttpHeaders);
1853 }
1854
1855 CopyMem (
1856 Buffer + *SizeofHeaders,
1857 Fragment.Bulk,
1858 Fragment.Len
1859 );
1860 *HttpHeaders = Buffer;
1861 *SizeofHeaders = *BufferSize;
1862
1863 //
1864 // Check whether we received end of HTTP headers.
1865 //
1866 *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
1867 };
1868
1869 //
1870 // Free the buffer.
1871 //
1872 if (Rx4Token != NULL && Rx4Token->Packet.RxData != NULL && Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
1873 FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
1874 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
1875 Fragment.Bulk = NULL;
1876 }
1877
1878 if (Fragment.Bulk != NULL) {
1879 FreePool (Fragment.Bulk);
1880 Fragment.Bulk = NULL;
1881 }
1882 } else {
1883 if (!HttpInstance->UseHttps) {
1884 Rx6Token = &HttpInstance->Rx6Token;
1885 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
1886 if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
1887 Status = EFI_OUT_OF_RESOURCES;
1888 return Status;
1889 }
1890 }
1891
1892 //
1893 // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1894 //
1895 while (*EndofHeader == NULL) {
1896 if (!HttpInstance->UseHttps) {
1897 HttpInstance->IsRxDone = FALSE;
1898 Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN;
1899 Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
1900 Status = Tcp6->Receive (Tcp6, Rx6Token);
1901 if (EFI_ERROR (Status)) {
1902 DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
1903 return Status;
1904 }
1905
1906 while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1907 Tcp6->Poll (Tcp6);
1908 }
1909
1910 if (!HttpInstance->IsRxDone) {
1911 //
1912 // Cancle the Token before close its Event.
1913 //
1914 Tcp6->Cancel (HttpInstance->Tcp6, &Rx6Token->CompletionToken);
1915 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
1916 Rx6Token->CompletionToken.Status = EFI_TIMEOUT;
1917 }
1918
1919 Status = Rx6Token->CompletionToken.Status;
1920 if (EFI_ERROR (Status)) {
1921 return Status;
1922 }
1923
1924 Fragment.Len = Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength;
1925 Fragment.Bulk = (UINT8 *) Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer;
1926 } else {
1927 if (Fragment.Bulk != NULL) {
1928 FreePool (Fragment.Bulk);
1929 Fragment.Bulk = NULL;
1930 }
1931
1932 Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
1933 if (EFI_ERROR (Status)) {
1934 DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
1935 return Status;
1936 }
1937 }
1938
1939 //
1940 // Append the response string.
1941 //
1942 *BufferSize = *SizeofHeaders + Fragment.Len;
1943 Buffer = AllocateZeroPool (*BufferSize);
1944 if (Buffer == NULL) {
1945 Status = EFI_OUT_OF_RESOURCES;
1946 return Status;
1947 }
1948
1949 if (*HttpHeaders != NULL) {
1950 CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
1951 FreePool (*HttpHeaders);
1952 }
1953
1954 CopyMem (
1955 Buffer + *SizeofHeaders,
1956 Fragment.Bulk,
1957 Fragment.Len
1958 );
1959 *HttpHeaders = Buffer;
1960 *SizeofHeaders = *BufferSize;
1961
1962 //
1963 // Check whether we received end of HTTP headers.
1964 //
1965 *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
1966 };
1967
1968 //
1969 // Free the buffer.
1970 //
1971 if (Rx6Token != NULL && Rx6Token->Packet.RxData != NULL && Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
1972 FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
1973 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
1974 Fragment.Bulk = NULL;
1975 }
1976
1977 if (Fragment.Bulk != NULL) {
1978 FreePool (Fragment.Bulk);
1979 Fragment.Bulk = NULL;
1980 }
1981 }
1982
1983 //
1984 // Skip the CRLF after the HTTP headers.
1985 //
1986 *EndofHeader = *EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR);
1987
1988 return EFI_SUCCESS;
1989 }
1990
1991 /**
1992 Receive the HTTP body by processing the associated HTTP token.
1993
1994 @param[in] Wrap The HTTP token's wrap data.
1995 @param[in] HttpMsg The HTTP message data.
1996
1997 @retval EFI_SUCCESS The HTTP body is received.
1998 @retval Others Other error as indicated.
1999
2000 **/
2001 EFI_STATUS
2002 HttpTcpReceiveBody (
2003 IN HTTP_TOKEN_WRAP *Wrap,
2004 IN EFI_HTTP_MESSAGE *HttpMsg
2005 )
2006 {
2007 EFI_STATUS Status;
2008 HTTP_PROTOCOL *HttpInstance;
2009 EFI_TCP6_PROTOCOL *Tcp6;
2010 EFI_TCP6_IO_TOKEN *Rx6Token;
2011 EFI_TCP4_PROTOCOL *Tcp4;
2012 EFI_TCP4_IO_TOKEN *Rx4Token;
2013
2014 HttpInstance = Wrap->HttpInstance;
2015 Tcp4 = HttpInstance->Tcp4;
2016 Tcp6 = HttpInstance->Tcp6;
2017 Rx4Token = NULL;
2018 Rx6Token = NULL;
2019
2020 if (HttpInstance->LocalAddressIsIPv6) {
2021 ASSERT (Tcp6 != NULL);
2022 } else {
2023 ASSERT (Tcp4 != NULL);
2024 }
2025
2026 if (HttpInstance->LocalAddressIsIPv6) {
2027 Rx6Token = &Wrap->TcpWrap.Rx6Token;
2028 Rx6Token ->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;
2029 Rx6Token ->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;
2030 Rx6Token ->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;
2031 Rx6Token->CompletionToken.Status = EFI_NOT_READY;
2032
2033 Status = Tcp6->Receive (Tcp6, Rx6Token);
2034 if (EFI_ERROR (Status)) {
2035 DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
2036 return Status;
2037 }
2038 } else {
2039 Rx4Token = &Wrap->TcpWrap.Rx4Token;
2040 Rx4Token->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;
2041 Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;
2042 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;
2043
2044 Rx4Token->CompletionToken.Status = EFI_NOT_READY;
2045 Status = Tcp4->Receive (Tcp4, Rx4Token);
2046 if (EFI_ERROR (Status)) {
2047 DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
2048 return Status;
2049 }
2050 }
2051
2052 return EFI_SUCCESS;
2053
2054 }
2055
2056 /**
2057 Clean up Tcp Tokens while the Tcp transmission error occurs.
2058
2059 @param[in] Wrap Pointer to HTTP token's wrap data.
2060
2061 **/
2062 VOID
2063 HttpTcpTokenCleanup (
2064 IN HTTP_TOKEN_WRAP *Wrap
2065 )
2066 {
2067 HTTP_PROTOCOL *HttpInstance;
2068 EFI_TCP4_IO_TOKEN *Rx4Token;
2069 EFI_TCP6_IO_TOKEN *Rx6Token;
2070
2071 ASSERT (Wrap != NULL);
2072 HttpInstance = Wrap->HttpInstance;
2073 Rx4Token = NULL;
2074 Rx6Token = NULL;
2075
2076 if (HttpInstance->LocalAddressIsIPv6) {
2077 Rx6Token = &Wrap->TcpWrap.Rx6Token;
2078
2079 if (Rx6Token->CompletionToken.Event != NULL) {
2080 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
2081 Rx6Token->CompletionToken.Event = NULL;
2082 }
2083
2084 FreePool (Wrap);
2085
2086 Rx6Token = &HttpInstance->Rx6Token;
2087
2088 if (Rx6Token->CompletionToken.Event != NULL) {
2089 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
2090 Rx6Token->CompletionToken.Event = NULL;
2091 }
2092
2093 if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
2094 FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
2095 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
2096 }
2097
2098 } else {
2099 Rx4Token = &Wrap->TcpWrap.Rx4Token;
2100
2101 if (Rx4Token->CompletionToken.Event != NULL) {
2102 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
2103 Rx4Token->CompletionToken.Event = NULL;
2104 }
2105
2106 FreePool (Wrap);
2107
2108 Rx4Token = &HttpInstance->Rx4Token;
2109
2110 if (Rx4Token->CompletionToken.Event != NULL) {
2111 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
2112 Rx4Token->CompletionToken.Event = NULL;
2113 }
2114
2115
2116 if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
2117 FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
2118 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
2119 }
2120 }
2121
2122 }