]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/HttpDxe/HttpProto.c
NetworkPkg: Fix incorrect buffer free in HttpDxe
[mirror_edk2.git] / NetworkPkg / HttpDxe / HttpProto.c
1 /** @file
2 Miscellaneous routines for HttpDxe driver.
3
4 Copyright (c) 2015, 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
152 if (EFI_ERROR (Wrap->TcpWrap.Rx6Token.CompletionToken.Status)) {
153 Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status;
154 gBS->SignalEvent (Wrap->HttpToken->Event);
155 FreePool (Wrap);
156 return ;
157 }
158
159 } else {
160 gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);
161
162 if (EFI_ERROR (Wrap->TcpWrap.Rx4Token.CompletionToken.Status)) {
163 Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status;
164 gBS->SignalEvent (Wrap->HttpToken->Event);
165 FreePool (Wrap);
166 return ;
167 }
168 }
169
170 //
171 // Check whether we receive a complete HTTP message.
172 //
173 ASSERT (HttpInstance->MsgParser != NULL);
174 if (UsingIpv6) {
175 Length = (UINTN) Wrap->TcpWrap.Rx6Data.FragmentTable[0].FragmentLength;
176 } else {
177 Length = (UINTN) Wrap->TcpWrap.Rx4Data.FragmentTable[0].FragmentLength;
178 }
179
180 Status = HttpParseMessageBody (
181 HttpInstance->MsgParser,
182 Length,
183 Wrap->HttpToken->Message->Body
184 );
185 if (EFI_ERROR (Status)) {
186 return ;
187 }
188
189 if (HttpIsMessageComplete (HttpInstance->MsgParser)) {
190 //
191 // Free the MsgParse since we already have a full HTTP message.
192 //
193 HttpFreeMsgParser (HttpInstance->MsgParser);
194 HttpInstance->MsgParser = NULL;
195 }
196
197 Wrap->HttpToken->Message->BodyLength = Length;
198 ASSERT (HttpInstance->CacheBody == NULL);
199 //
200 // We receive part of header of next HTTP msg.
201 //
202 if (HttpInstance->NextMsg != NULL) {
203 Wrap->HttpToken->Message->BodyLength = HttpInstance->NextMsg -
204 (CHAR8 *) Wrap->HttpToken->Message->Body;
205 HttpInstance->CacheLen = Length - Wrap->HttpToken->Message->BodyLength;
206 if (HttpInstance->CacheLen != 0) {
207 HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen);
208 if (HttpInstance->CacheBody == NULL) {
209 return ;
210 }
211 CopyMem (HttpInstance->CacheBody, HttpInstance->NextMsg, HttpInstance->CacheLen);
212 HttpInstance->NextMsg = HttpInstance->CacheBody;
213 HttpInstance->CacheOffset = 0;
214 }
215 }
216
217 Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);
218 if (Item != NULL) {
219 NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);
220 }
221
222
223 Wrap->TcpWrap.IsRxDone = TRUE;
224 if (UsingIpv6) {
225 Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status;
226 } else {
227 Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status;
228 }
229
230
231 gBS->SignalEvent (Wrap->HttpToken->Event);
232
233 //
234 // Check pending RxTokens and receive the HTTP message.
235 //
236 NetMapIterate (&Wrap->HttpInstance->RxTokens, HttpTcpReceive, NULL);
237
238 FreePool (Wrap);
239 }
240
241 /**
242 Request HttpTcpReceiveNotifyDpc as a DPC at TPL_CALLBACK.
243
244 @param Event The receive event delivered to TCP for receive.
245 @param Context Context for the callback.
246
247 **/
248 VOID
249 EFIAPI
250 HttpTcpReceiveNotify (
251 IN EFI_EVENT Event,
252 IN VOID *Context
253 )
254 {
255 //
256 // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK
257 //
258 QueueDpc (TPL_CALLBACK, HttpTcpReceiveNotifyDpc, Context);
259 }
260
261 /**
262 Create events for the TCP connection token and TCP close token.
263
264 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
265
266 @retval EFI_SUCCESS The events are created successfully.
267 @retval others Other error as indicated.
268
269 **/
270 EFI_STATUS
271 HttpCreateTcpConnCloseEvent (
272 IN HTTP_PROTOCOL *HttpInstance
273 )
274 {
275 EFI_STATUS Status;
276
277 if (!HttpInstance->LocalAddressIsIPv6) {
278 //
279 // Create events for variuos asynchronous operations.
280 //
281 Status = gBS->CreateEvent (
282 EVT_NOTIFY_SIGNAL,
283 TPL_NOTIFY,
284 HttpCommonNotify,
285 &HttpInstance->IsTcp4ConnDone,
286 &HttpInstance->Tcp4ConnToken.CompletionToken.Event
287 );
288 if (EFI_ERROR (Status)) {
289 goto ERROR;
290 }
291
292 //
293 // Initialize Tcp4CloseToken
294 //
295 Status = gBS->CreateEvent (
296 EVT_NOTIFY_SIGNAL,
297 TPL_NOTIFY,
298 HttpCommonNotify,
299 &HttpInstance->IsTcp4CloseDone,
300 &HttpInstance->Tcp4CloseToken.CompletionToken.Event
301 );
302 if (EFI_ERROR (Status)) {
303 goto ERROR;
304 }
305
306 } else {
307 //
308 // Create events for variuos asynchronous operations.
309 //
310 Status = gBS->CreateEvent (
311 EVT_NOTIFY_SIGNAL,
312 TPL_NOTIFY,
313 HttpCommonNotify,
314 &HttpInstance->IsTcp6ConnDone,
315 &HttpInstance->Tcp6ConnToken.CompletionToken.Event
316 );
317 if (EFI_ERROR (Status)) {
318 goto ERROR;
319 }
320
321 //
322 // Initialize Tcp6CloseToken
323 //
324 Status = gBS->CreateEvent (
325 EVT_NOTIFY_SIGNAL,
326 TPL_NOTIFY,
327 HttpCommonNotify,
328 &HttpInstance->IsTcp6CloseDone,
329 &HttpInstance->Tcp6CloseToken.CompletionToken.Event
330 );
331 if (EFI_ERROR (Status)) {
332 goto ERROR;
333 }
334 }
335
336 return EFI_SUCCESS;
337
338 ERROR:
339 //
340 // Error handling
341 //
342 HttpCloseTcpConnCloseEvent (HttpInstance);
343
344 return Status;
345 }
346
347
348 /**
349 Close events in the TCP connection token and TCP close token.
350
351 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
352
353 **/
354 VOID
355 HttpCloseTcpConnCloseEvent (
356 IN HTTP_PROTOCOL *HttpInstance
357 )
358 {
359 ASSERT (HttpInstance != NULL);
360
361 if (HttpInstance->LocalAddressIsIPv6) {
362 if (NULL != HttpInstance->Tcp6ConnToken.CompletionToken.Event) {
363 gBS->CloseEvent (HttpInstance->Tcp6ConnToken.CompletionToken.Event);
364 HttpInstance->Tcp6ConnToken.CompletionToken.Event = NULL;
365 }
366
367 if (NULL != HttpInstance->Tcp6CloseToken.CompletionToken.Event) {
368 gBS->CloseEvent(HttpInstance->Tcp6CloseToken.CompletionToken.Event);
369 HttpInstance->Tcp6CloseToken.CompletionToken.Event = NULL;
370 }
371
372 } else {
373 if (NULL != HttpInstance->Tcp4ConnToken.CompletionToken.Event) {
374 gBS->CloseEvent (HttpInstance->Tcp4ConnToken.CompletionToken.Event);
375 HttpInstance->Tcp4ConnToken.CompletionToken.Event = NULL;
376 }
377
378 if (NULL != HttpInstance->Tcp4CloseToken.CompletionToken.Event) {
379 gBS->CloseEvent(HttpInstance->Tcp4CloseToken.CompletionToken.Event);
380 HttpInstance->Tcp4CloseToken.CompletionToken.Event = NULL;
381 }
382 }
383
384 }
385
386 /**
387 Create event for the TCP transmit token.
388
389 @param[in] Wrap Point to HTTP token's wrap data.
390
391 @retval EFI_SUCCESS The events is created successfully.
392 @retval others Other error as indicated.
393
394 **/
395 EFI_STATUS
396 HttpCreateTcpTxEvent (
397 IN HTTP_TOKEN_WRAP *Wrap
398 )
399 {
400 EFI_STATUS Status;
401 HTTP_PROTOCOL *HttpInstance;
402 HTTP_TCP_TOKEN_WRAP *TcpWrap;
403
404 HttpInstance = Wrap->HttpInstance;
405 TcpWrap = &Wrap->TcpWrap;
406
407 if (!HttpInstance->LocalAddressIsIPv6) {
408 Status = gBS->CreateEvent (
409 EVT_NOTIFY_SIGNAL,
410 TPL_NOTIFY,
411 HttpTcpTransmitNotify,
412 Wrap,
413 &TcpWrap->Tx4Token.CompletionToken.Event
414 );
415 if (EFI_ERROR (Status)) {
416 return Status;
417 }
418
419 TcpWrap->Tx4Data.Push = TRUE;
420 TcpWrap->Tx4Data.Urgent = FALSE;
421 TcpWrap->Tx4Data.FragmentCount = 1;
422 TcpWrap->Tx4Token.Packet.TxData = &Wrap->TcpWrap.Tx4Data;
423 TcpWrap->Tx4Token.CompletionToken.Status = EFI_NOT_READY;
424
425 } else {
426 Status = gBS->CreateEvent (
427 EVT_NOTIFY_SIGNAL,
428 TPL_NOTIFY,
429 HttpTcpTransmitNotify,
430 Wrap,
431 &TcpWrap->Tx6Token.CompletionToken.Event
432 );
433 if (EFI_ERROR (Status)) {
434 return Status;
435 }
436
437 TcpWrap->Tx6Data.Push = TRUE;
438 TcpWrap->Tx6Data.Urgent = FALSE;
439 TcpWrap->Tx6Data.FragmentCount = 1;
440 TcpWrap->Tx6Token.Packet.TxData = &Wrap->TcpWrap.Tx6Data;
441 TcpWrap->Tx6Token.CompletionToken.Status =EFI_NOT_READY;
442
443
444 }
445
446 return EFI_SUCCESS;
447 }
448
449 /**
450 Create event for the TCP receive token which is used to receive HTTP header.
451
452 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
453
454 @retval EFI_SUCCESS The events is created successfully.
455 @retval others Other error as indicated.
456
457 **/
458 EFI_STATUS
459 HttpCreateTcpRxEventForHeader (
460 IN HTTP_PROTOCOL *HttpInstance
461 )
462 {
463 EFI_STATUS Status;
464
465 if (!HttpInstance->LocalAddressIsIPv6) {
466 Status = gBS->CreateEvent (
467 EVT_NOTIFY_SIGNAL,
468 TPL_NOTIFY,
469 HttpCommonNotify,
470 &HttpInstance->IsRxDone,
471 &HttpInstance->Rx4Token.CompletionToken.Event
472 );
473 if (EFI_ERROR (Status)) {
474 return Status;
475 }
476
477 HttpInstance->Rx4Data.FragmentCount = 1;
478 HttpInstance->Rx4Token.Packet.RxData = &HttpInstance->Rx4Data;
479 HttpInstance->Rx4Token.CompletionToken.Status = EFI_NOT_READY;
480
481 } else {
482 Status = gBS->CreateEvent (
483 EVT_NOTIFY_SIGNAL,
484 TPL_NOTIFY,
485 HttpCommonNotify,
486 &HttpInstance->IsRxDone,
487 &HttpInstance->Rx6Token.CompletionToken.Event
488 );
489 if (EFI_ERROR (Status)) {
490 return Status;
491 }
492
493 HttpInstance->Rx6Data.FragmentCount =1;
494 HttpInstance->Rx6Token.Packet.RxData = &HttpInstance->Rx6Data;
495 HttpInstance->Rx6Token.CompletionToken.Status = EFI_NOT_READY;
496
497 }
498
499
500 return EFI_SUCCESS;
501 }
502
503 /**
504 Create event for the TCP receive token which is used to receive HTTP body.
505
506 @param[in] Wrap Point to HTTP token's wrap data.
507
508 @retval EFI_SUCCESS The events is created successfully.
509 @retval others Other error as indicated.
510
511 **/
512 EFI_STATUS
513 HttpCreateTcpRxEvent (
514 IN HTTP_TOKEN_WRAP *Wrap
515 )
516 {
517 EFI_STATUS Status;
518 HTTP_PROTOCOL *HttpInstance;
519 HTTP_TCP_TOKEN_WRAP *TcpWrap;
520
521 HttpInstance = Wrap->HttpInstance;
522 TcpWrap = &Wrap->TcpWrap;
523 if (!HttpInstance->LocalAddressIsIPv6) {
524 Status = gBS->CreateEvent (
525 EVT_NOTIFY_SIGNAL,
526 TPL_NOTIFY,
527 HttpTcpReceiveNotify,
528 Wrap,
529 &TcpWrap->Rx4Token.CompletionToken.Event
530 );
531 if (EFI_ERROR (Status)) {
532 return Status;
533 }
534
535 TcpWrap->Rx4Data.FragmentCount = 1;
536 TcpWrap->Rx4Token.Packet.RxData = &Wrap->TcpWrap.Rx4Data;
537 TcpWrap->Rx4Token.CompletionToken.Status = EFI_NOT_READY;
538
539 } else {
540 Status = gBS->CreateEvent (
541 EVT_NOTIFY_SIGNAL,
542 TPL_NOTIFY,
543 HttpTcpReceiveNotify,
544 Wrap,
545 &TcpWrap->Rx6Token.CompletionToken.Event
546 );
547 if (EFI_ERROR (Status)) {
548 return Status;
549 }
550
551 TcpWrap->Rx6Data.FragmentCount = 1;
552 TcpWrap->Rx6Token.Packet.RxData = &Wrap->TcpWrap.Rx6Data;
553 TcpWrap->Rx6Token.CompletionToken.Status = EFI_NOT_READY;
554 }
555
556 return EFI_SUCCESS;
557 }
558
559 /**
560 Close Events for Tcp Receive Tokens for HTTP body and HTTP header.
561
562 @param[in] Wrap Pointer to HTTP token's wrap data.
563
564 **/
565 VOID
566 HttpCloseTcpRxEvent (
567 IN HTTP_TOKEN_WRAP *Wrap
568 )
569 {
570 HTTP_PROTOCOL *HttpInstance;
571
572 ASSERT (Wrap != NULL);
573 HttpInstance = Wrap->HttpInstance;
574
575 if (HttpInstance->LocalAddressIsIPv6) {
576 if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {
577 gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);
578 }
579
580 if (HttpInstance->Rx6Token.CompletionToken.Event != NULL) {
581 gBS->CloseEvent (HttpInstance->Rx6Token.CompletionToken.Event);
582 HttpInstance->Rx6Token.CompletionToken.Event = NULL;
583 }
584 } else {
585 if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {
586 gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);
587 }
588
589 if (HttpInstance->Rx4Token.CompletionToken.Event != NULL) {
590 gBS->CloseEvent (HttpInstance->Rx4Token.CompletionToken.Event);
591 HttpInstance->Rx4Token.CompletionToken.Event = NULL;
592 }
593 }
594 }
595
596 /**
597 Intiialize the HTTP_PROTOCOL structure to the unconfigured state.
598
599 @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
600 @param[in] IpVersion Indicate us TCP4 protocol or TCP6 protocol.
601
602 @retval EFI_SUCCESS HTTP_PROTOCOL structure is initialized successfully.
603 @retval Others Other error as indicated.
604
605 **/
606 EFI_STATUS
607 HttpInitProtocol (
608 IN OUT HTTP_PROTOCOL *HttpInstance,
609 IN BOOLEAN IpVersion
610 )
611 {
612 EFI_STATUS Status;
613 VOID *Interface;
614 BOOLEAN UsingIpv6;
615
616 ASSERT (HttpInstance != NULL);
617 UsingIpv6 = IpVersion;
618
619 if (!UsingIpv6) {
620 //
621 // Create TCP4 child.
622 //
623 Status = NetLibCreateServiceChild (
624 HttpInstance->Service->ControllerHandle,
625 HttpInstance->Service->ImageHandle,
626 &gEfiTcp4ServiceBindingProtocolGuid,
627 &HttpInstance->Tcp4ChildHandle
628 );
629
630 if (EFI_ERROR (Status)) {
631 goto ON_ERROR;
632 }
633
634 Status = gBS->OpenProtocol (
635 HttpInstance->Tcp4ChildHandle,
636 &gEfiTcp4ProtocolGuid,
637 (VOID **) &Interface,
638 HttpInstance->Service->ImageHandle,
639 HttpInstance->Service->ControllerHandle,
640 EFI_OPEN_PROTOCOL_BY_DRIVER
641 );
642
643 if (EFI_ERROR (Status)) {
644 goto ON_ERROR;
645 }
646
647 Status = gBS->OpenProtocol (
648 HttpInstance->Tcp4ChildHandle,
649 &gEfiTcp4ProtocolGuid,
650 (VOID **) &HttpInstance->Tcp4,
651 HttpInstance->Service->ImageHandle,
652 HttpInstance->Handle,
653 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
654 );
655 if (EFI_ERROR(Status)) {
656 goto ON_ERROR;
657 }
658
659 Status = gBS->OpenProtocol (
660 HttpInstance->Service->Tcp4ChildHandle,
661 &gEfiTcp4ProtocolGuid,
662 (VOID **) &Interface,
663 HttpInstance->Service->ImageHandle,
664 HttpInstance->Handle,
665 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
666 );
667 if (EFI_ERROR(Status)) {
668 goto ON_ERROR;
669 }
670 } else {
671 //
672 // Create TCP6 Child.
673 //
674 Status = NetLibCreateServiceChild (
675 HttpInstance->Service->ControllerHandle,
676 HttpInstance->Service->ImageHandle,
677 &gEfiTcp6ServiceBindingProtocolGuid,
678 &HttpInstance->Tcp6ChildHandle
679 );
680
681 if (EFI_ERROR (Status)) {
682 goto ON_ERROR;
683 }
684
685 Status = gBS->OpenProtocol (
686 HttpInstance->Tcp6ChildHandle,
687 &gEfiTcp6ProtocolGuid,
688 (VOID **) &Interface,
689 HttpInstance->Service->ImageHandle,
690 HttpInstance->Service->ControllerHandle,
691 EFI_OPEN_PROTOCOL_BY_DRIVER
692 );
693
694 if (EFI_ERROR (Status)) {
695 goto ON_ERROR;
696 }
697
698 Status = gBS->OpenProtocol (
699 HttpInstance->Tcp6ChildHandle,
700 &gEfiTcp6ProtocolGuid,
701 (VOID **) &HttpInstance->Tcp6,
702 HttpInstance->Service->ImageHandle,
703 HttpInstance->Handle,
704 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
705 );
706
707 if (EFI_ERROR(Status)) {
708 goto ON_ERROR;
709 }
710
711 Status = gBS->OpenProtocol (
712 HttpInstance->Service->Tcp6ChildHandle,
713 &gEfiTcp6ProtocolGuid,
714 (VOID **) &Interface,
715 HttpInstance->Service->ImageHandle,
716 HttpInstance->Handle,
717 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
718 );
719
720 if (EFI_ERROR(Status)) {
721 goto ON_ERROR;
722 }
723 }
724
725 HttpInstance->Url = AllocateZeroPool (HTTP_URL_BUFFER_LEN);
726 if (HttpInstance->Url == NULL) {
727 Status = EFI_OUT_OF_RESOURCES;
728 goto ON_ERROR;
729 }
730
731 return EFI_SUCCESS;
732
733 ON_ERROR:
734
735 if (HttpInstance->Tcp4ChildHandle != NULL) {
736 gBS->CloseProtocol (
737 HttpInstance->Tcp4ChildHandle,
738 &gEfiTcp4ProtocolGuid,
739 HttpInstance->Service->ImageHandle,
740 HttpInstance->Service->ControllerHandle
741 );
742
743 gBS->CloseProtocol (
744 HttpInstance->Tcp4ChildHandle,
745 &gEfiTcp4ProtocolGuid,
746 HttpInstance->Service->ImageHandle,
747 HttpInstance->Handle
748 );
749
750 NetLibDestroyServiceChild (
751 HttpInstance->Service->ControllerHandle,
752 HttpInstance->Service->ImageHandle,
753 &gEfiTcp4ServiceBindingProtocolGuid,
754 HttpInstance->Tcp4ChildHandle
755 );
756 }
757
758 if (HttpInstance->Service->Tcp4ChildHandle != NULL) {
759 gBS->CloseProtocol (
760 HttpInstance->Service->Tcp4ChildHandle,
761 &gEfiTcp4ProtocolGuid,
762 HttpInstance->Service->ImageHandle,
763 HttpInstance->Handle
764 );
765 }
766
767 if (HttpInstance->Tcp6ChildHandle != NULL) {
768 gBS->CloseProtocol (
769 HttpInstance->Tcp6ChildHandle,
770 &gEfiTcp6ProtocolGuid,
771 HttpInstance->Service->ImageHandle,
772 HttpInstance->Service->ControllerHandle
773 );
774
775 gBS->CloseProtocol (
776 HttpInstance->Tcp6ChildHandle,
777 &gEfiTcp6ProtocolGuid,
778 HttpInstance->Service->ImageHandle,
779 HttpInstance->Handle
780 );
781
782 NetLibDestroyServiceChild (
783 HttpInstance->Service->ControllerHandle,
784 HttpInstance->Service->ImageHandle,
785 &gEfiTcp6ServiceBindingProtocolGuid,
786 HttpInstance->Tcp6ChildHandle
787 );
788 }
789
790 if (HttpInstance->Service->Tcp6ChildHandle != NULL) {
791 gBS->CloseProtocol (
792 HttpInstance->Service->Tcp6ChildHandle,
793 &gEfiTcp6ProtocolGuid,
794 HttpInstance->Service->ImageHandle,
795 HttpInstance->Handle
796 );
797 }
798
799 return EFI_UNSUPPORTED;
800
801 }
802
803 /**
804 Clean up the HTTP child, release all the resources used by it.
805
806 @param[in] HttpInstance The HTTP child to clean up.
807
808 **/
809 VOID
810 HttpCleanProtocol (
811 IN HTTP_PROTOCOL *HttpInstance
812 )
813 {
814 HttpCloseConnection (HttpInstance);
815
816 HttpCloseTcpConnCloseEvent (HttpInstance);
817
818 if (HttpInstance->TimeoutEvent != NULL) {
819 gBS->CloseEvent (HttpInstance->TimeoutEvent);
820 HttpInstance->TimeoutEvent = NULL;
821 }
822
823 if (HttpInstance->CacheBody != NULL) {
824 FreePool (HttpInstance->CacheBody);
825 HttpInstance->CacheBody = NULL;
826 HttpInstance->NextMsg = NULL;
827 }
828
829 if (HttpInstance->RemoteHost != NULL) {
830 FreePool (HttpInstance->RemoteHost);
831 HttpInstance->RemoteHost = NULL;
832 }
833
834 if (HttpInstance->MsgParser != NULL) {
835 HttpFreeMsgParser (HttpInstance->MsgParser);
836 HttpInstance->MsgParser = NULL;
837 }
838
839 if (HttpInstance->Url != NULL) {
840 FreePool (HttpInstance->Url);
841 HttpInstance->Url = NULL;
842 }
843
844 NetMapClean (&HttpInstance->TxTokens);
845 NetMapClean (&HttpInstance->RxTokens);
846
847 if (HttpInstance->Tcp4ChildHandle != NULL) {
848 gBS->CloseProtocol (
849 HttpInstance->Tcp4ChildHandle,
850 &gEfiTcp4ProtocolGuid,
851 HttpInstance->Service->ImageHandle,
852 HttpInstance->Service->ControllerHandle
853 );
854
855 gBS->CloseProtocol (
856 HttpInstance->Tcp4ChildHandle,
857 &gEfiTcp4ProtocolGuid,
858 HttpInstance->Service->ImageHandle,
859 HttpInstance->Handle
860 );
861
862 NetLibDestroyServiceChild (
863 HttpInstance->Service->ControllerHandle,
864 HttpInstance->Service->ImageHandle,
865 &gEfiTcp4ServiceBindingProtocolGuid,
866 HttpInstance->Tcp4ChildHandle
867 );
868 }
869
870 if (HttpInstance->Service->Tcp4ChildHandle != NULL) {
871 gBS->CloseProtocol (
872 HttpInstance->Service->Tcp4ChildHandle,
873 &gEfiTcp4ProtocolGuid,
874 HttpInstance->Service->ImageHandle,
875 HttpInstance->Handle
876 );
877 }
878
879 if (HttpInstance->Tcp6ChildHandle != NULL) {
880 gBS->CloseProtocol (
881 HttpInstance->Tcp6ChildHandle,
882 &gEfiTcp6ProtocolGuid,
883 HttpInstance->Service->ImageHandle,
884 HttpInstance->Service->ControllerHandle
885 );
886
887 gBS->CloseProtocol (
888 HttpInstance->Tcp6ChildHandle,
889 &gEfiTcp6ProtocolGuid,
890 HttpInstance->Service->ImageHandle,
891 HttpInstance->Handle
892 );
893
894 NetLibDestroyServiceChild (
895 HttpInstance->Service->ControllerHandle,
896 HttpInstance->Service->ImageHandle,
897 &gEfiTcp6ServiceBindingProtocolGuid,
898 HttpInstance->Tcp6ChildHandle
899 );
900 }
901
902 if (HttpInstance->Service->Tcp6ChildHandle != NULL) {
903 gBS->CloseProtocol (
904 HttpInstance->Service->Tcp6ChildHandle,
905 &gEfiTcp6ProtocolGuid,
906 HttpInstance->Service->ImageHandle,
907 HttpInstance->Handle
908 );
909 }
910
911 }
912
913 /**
914 Establish TCP connection with HTTP server.
915
916 @param[in] HttpInstance The HTTP instance private data.
917
918 @retval EFI_SUCCESS The TCP connection is established.
919 @retval Others Other error as indicated.
920
921 **/
922 EFI_STATUS
923 HttpCreateConnection (
924 IN HTTP_PROTOCOL *HttpInstance
925 )
926 {
927 EFI_STATUS Status;
928
929 //
930 // Connect to Http server
931 //
932 if (!HttpInstance->LocalAddressIsIPv6) {
933 HttpInstance->IsTcp4ConnDone = FALSE;
934 HttpInstance->Tcp4ConnToken.CompletionToken.Status = EFI_NOT_READY;
935 Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->Tcp4ConnToken);
936 if (EFI_ERROR (Status)) {
937 DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status));
938 return Status;
939 }
940
941 while (!HttpInstance->IsTcp4ConnDone) {
942 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
943 }
944
945 Status = HttpInstance->Tcp4ConnToken.CompletionToken.Status;
946
947 } else {
948 HttpInstance->IsTcp6ConnDone = FALSE;
949 HttpInstance->Tcp6ConnToken.CompletionToken.Status = EFI_NOT_READY;
950 Status = HttpInstance->Tcp6->Connect (HttpInstance->Tcp6, &HttpInstance->Tcp6ConnToken);
951 if (EFI_ERROR (Status)) {
952 DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp6->Connect() = %r\n", Status));
953 return Status;
954 }
955
956 while(!HttpInstance->IsTcp6ConnDone) {
957 HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
958 }
959
960 Status = HttpInstance->Tcp6ConnToken.CompletionToken.Status;
961 }
962
963 if (!EFI_ERROR (Status)) {
964 HttpInstance->State = HTTP_STATE_TCP_CONNECTED;
965 }
966
967 return Status;
968 }
969
970 /**
971 Close existing TCP connection.
972
973 @param[in] HttpInstance The HTTP instance private data.
974
975 @retval EFI_SUCCESS The TCP connection is closed.
976 @retval Others Other error as indicated.
977
978 **/
979 EFI_STATUS
980 HttpCloseConnection (
981 IN HTTP_PROTOCOL *HttpInstance
982 )
983 {
984 EFI_STATUS Status;
985
986 if (HttpInstance->State == HTTP_STATE_TCP_CONNECTED) {
987
988 if (HttpInstance->LocalAddressIsIPv6) {
989 HttpInstance->Tcp6CloseToken.AbortOnClose = TRUE;
990 HttpInstance->IsTcp6CloseDone = FALSE;
991 Status = HttpInstance->Tcp6->Close (HttpInstance->Tcp6, &HttpInstance->Tcp6CloseToken);
992 if (EFI_ERROR (Status)) {
993 return Status;
994 }
995
996 while (!HttpInstance->IsTcp6CloseDone) {
997 HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
998 }
999
1000 } else {
1001 HttpInstance->Tcp4CloseToken.AbortOnClose = TRUE;
1002 HttpInstance->IsTcp4CloseDone = FALSE;
1003 Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->Tcp4CloseToken);
1004 if (EFI_ERROR (Status)) {
1005 return Status;
1006 }
1007
1008 while (!HttpInstance->IsTcp4CloseDone) {
1009 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
1010 }
1011 }
1012
1013 }
1014
1015 HttpInstance->State = HTTP_STATE_TCP_CLOSED;
1016 return EFI_SUCCESS;
1017 }
1018
1019 /**
1020 Configure TCP4 protocol child.
1021
1022 @param[in] HttpInstance The HTTP instance private data.
1023 @param[in] Wrap The HTTP token's wrap data.
1024
1025 @retval EFI_SUCCESS The TCP4 protocol child is configured.
1026 @retval Others Other error as indicated.
1027
1028 **/
1029 EFI_STATUS
1030 HttpConfigureTcp4 (
1031 IN HTTP_PROTOCOL *HttpInstance,
1032 IN HTTP_TOKEN_WRAP *Wrap
1033 )
1034 {
1035 EFI_STATUS Status;
1036 EFI_TCP4_CONFIG_DATA *Tcp4CfgData;
1037 EFI_TCP4_ACCESS_POINT *Tcp4AP;
1038 EFI_TCP4_OPTION *Tcp4Option;
1039
1040 ASSERT (HttpInstance != NULL);
1041
1042
1043 Tcp4CfgData = &HttpInstance->Tcp4CfgData;
1044 ZeroMem (Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA));
1045
1046 Tcp4CfgData->TypeOfService = HTTP_TOS_DEAULT;
1047 Tcp4CfgData->TimeToLive = HTTP_TTL_DEAULT;
1048 Tcp4CfgData->ControlOption = &HttpInstance->Tcp4Option;
1049
1050 Tcp4AP = &Tcp4CfgData->AccessPoint;
1051 Tcp4AP->UseDefaultAddress = HttpInstance->IPv4Node.UseDefaultAddress;
1052 if (!Tcp4AP->UseDefaultAddress) {
1053 IP4_COPY_ADDRESS (&Tcp4AP->StationAddress, &HttpInstance->IPv4Node.LocalAddress);
1054 IP4_COPY_ADDRESS (&Tcp4AP->SubnetMask, &HttpInstance->IPv4Node.LocalSubnet);
1055 }
1056
1057 Tcp4AP->StationPort = HttpInstance->IPv4Node.LocalPort;
1058 Tcp4AP->RemotePort = HttpInstance->RemotePort;
1059 Tcp4AP->ActiveFlag = TRUE;
1060 IP4_COPY_ADDRESS (&Tcp4AP->RemoteAddress, &HttpInstance->RemoteAddr);
1061
1062 Tcp4Option = Tcp4CfgData->ControlOption;
1063 Tcp4Option->ReceiveBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1064 Tcp4Option->SendBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1065 Tcp4Option->MaxSynBackLog = HTTP_MAX_SYN_BACK_LOG;
1066 Tcp4Option->ConnectionTimeout = HTTP_CONNECTION_TIMEOUT;
1067 Tcp4Option->DataRetries = HTTP_DATA_RETRIES;
1068 Tcp4Option->FinTimeout = HTTP_FIN_TIMEOUT;
1069 Tcp4Option->KeepAliveProbes = HTTP_KEEP_ALIVE_PROBES;
1070 Tcp4Option->KeepAliveTime = HTTP_KEEP_ALIVE_TIME;
1071 Tcp4Option->KeepAliveInterval = HTTP_KEEP_ALIVE_INTERVAL;
1072 Tcp4Option->EnableNagle = TRUE;
1073 Tcp4CfgData->ControlOption = Tcp4Option;
1074
1075 Status = HttpInstance->Tcp4->Configure (HttpInstance->Tcp4, Tcp4CfgData);
1076 if (EFI_ERROR (Status)) {
1077 DEBUG ((EFI_D_ERROR, "HttpConfigureTcp4 - %r\n", Status));
1078 return Status;
1079 }
1080
1081 Status = HttpCreateTcpConnCloseEvent (HttpInstance);
1082 if (EFI_ERROR (Status)) {
1083 return Status;
1084 }
1085
1086 Status = HttpCreateTcpTxEvent (Wrap);
1087 if (EFI_ERROR (Status)) {
1088 return Status;
1089 }
1090
1091 HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
1092
1093 return EFI_SUCCESS;
1094 }
1095
1096 /**
1097 Configure TCP6 protocol child.
1098
1099 @param[in] HttpInstance The HTTP instance private data.
1100 @param[in] Wrap The HTTP token's wrap data.
1101
1102 @retval EFI_SUCCESS The TCP6 protocol child is configured.
1103 @retval Others Other error as indicated.
1104
1105 **/
1106 EFI_STATUS
1107 HttpConfigureTcp6 (
1108 IN HTTP_PROTOCOL *HttpInstance,
1109 IN HTTP_TOKEN_WRAP *Wrap
1110 )
1111 {
1112 EFI_STATUS Status;
1113 EFI_TCP6_CONFIG_DATA *Tcp6CfgData;
1114 EFI_TCP6_ACCESS_POINT *Tcp6Ap;
1115 EFI_TCP6_OPTION *Tcp6Option;
1116
1117 ASSERT (HttpInstance != NULL);
1118
1119 Tcp6CfgData = &HttpInstance->Tcp6CfgData;
1120 ZeroMem (Tcp6CfgData, sizeof (EFI_TCP6_CONFIG_DATA));
1121
1122 Tcp6CfgData->TrafficClass = 0;
1123 Tcp6CfgData->HopLimit = 255;
1124 Tcp6CfgData->ControlOption = &HttpInstance->Tcp6Option;
1125
1126 Tcp6Ap = &Tcp6CfgData->AccessPoint;
1127 Tcp6Ap->ActiveFlag = TRUE;
1128 Tcp6Ap->StationPort = HttpInstance->Ipv6Node.LocalPort;
1129 Tcp6Ap->RemotePort = HttpInstance->RemotePort;
1130 IP6_COPY_ADDRESS (&Tcp6Ap->StationAddress, &HttpInstance->Ipv6Node.LocalAddress);
1131 IP6_COPY_ADDRESS (&Tcp6Ap->RemoteAddress , &HttpInstance->RemoteIpv6Addr);
1132
1133 Tcp6Option = Tcp6CfgData->ControlOption;
1134 Tcp6Option->ReceiveBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1135 Tcp6Option->SendBufferSize = HTTP_BUFFER_SIZE_DEAULT;
1136 Tcp6Option->MaxSynBackLog = HTTP_MAX_SYN_BACK_LOG;
1137 Tcp6Option->ConnectionTimeout = HTTP_CONNECTION_TIMEOUT;
1138 Tcp6Option->DataRetries = HTTP_DATA_RETRIES;
1139 Tcp6Option->FinTimeout = HTTP_FIN_TIMEOUT;
1140 Tcp6Option->KeepAliveProbes = HTTP_KEEP_ALIVE_PROBES;
1141 Tcp6Option->KeepAliveTime = HTTP_KEEP_ALIVE_TIME;
1142 Tcp6Option->KeepAliveInterval = HTTP_KEEP_ALIVE_INTERVAL;
1143 Tcp6Option->EnableNagle = TRUE;
1144
1145 Status = HttpInstance->Tcp6->Configure (HttpInstance->Tcp6, Tcp6CfgData);
1146 if (EFI_ERROR (Status)) {
1147 DEBUG ((EFI_D_ERROR, "HttpConfigureTcp6 - %r\n", Status));
1148 return Status;
1149 }
1150
1151 Status = HttpCreateTcpConnCloseEvent (HttpInstance);
1152 if (EFI_ERROR (Status)) {
1153 return Status;
1154 }
1155
1156 Status = HttpCreateTcpTxEvent (Wrap);
1157 if (EFI_ERROR (Status)) {
1158 return Status;
1159 }
1160
1161 HttpInstance->State = HTTP_STATE_TCP_CONFIGED;
1162
1163 return EFI_SUCCESS;
1164
1165 }
1166
1167 /**
1168 Check existing TCP connection, if in error state, recover TCP4 connection.
1169
1170 @param[in] HttpInstance The HTTP instance private data.
1171
1172 @retval EFI_SUCCESS The TCP connection is established.
1173 @retval EFI_NOT_READY TCP4 protocol child is not created or configured.
1174 @retval Others Other error as indicated.
1175
1176 **/
1177 EFI_STATUS
1178 HttpConnectTcp4 (
1179 IN HTTP_PROTOCOL *HttpInstance
1180 )
1181 {
1182 EFI_STATUS Status;
1183 EFI_TCP4_CONNECTION_STATE Tcp4State;
1184
1185
1186 if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp4 == NULL) {
1187 return EFI_NOT_READY;
1188 }
1189
1190 Status = HttpInstance->Tcp4->GetModeData(
1191 HttpInstance->Tcp4,
1192 &Tcp4State,
1193 NULL,
1194 NULL,
1195 NULL,
1196 NULL
1197 );
1198 if (EFI_ERROR(Status)){
1199 DEBUG ((EFI_D_ERROR, "Tcp4 GetModeData fail - %x\n", Status));
1200 return Status;
1201 }
1202
1203 if (Tcp4State == Tcp4StateEstablished) {
1204 return EFI_SUCCESS;
1205 } else if (Tcp4State > Tcp4StateEstablished ) {
1206 HttpCloseConnection(HttpInstance);
1207 }
1208
1209 return HttpCreateConnection (HttpInstance);
1210 }
1211
1212 /**
1213 Check existing TCP connection, if in error state, recover TCP6 connection.
1214
1215 @param[in] HttpInstance The HTTP instance private data.
1216
1217 @retval EFI_SUCCESS The TCP connection is established.
1218 @retval EFI_NOT_READY TCP6 protocol child is not created or configured.
1219 @retval Others Other error as indicated.
1220
1221 **/
1222 EFI_STATUS
1223 HttpConnectTcp6 (
1224 IN HTTP_PROTOCOL *HttpInstance
1225 )
1226 {
1227 EFI_STATUS Status;
1228 EFI_TCP6_CONNECTION_STATE Tcp6State;
1229
1230 if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp6 == NULL) {
1231 return EFI_NOT_READY;
1232 }
1233
1234 Status = HttpInstance->Tcp6->GetModeData (
1235 HttpInstance->Tcp6,
1236 &Tcp6State,
1237 NULL,
1238 NULL,
1239 NULL,
1240 NULL
1241 );
1242
1243 if (EFI_ERROR(Status)){
1244 DEBUG ((EFI_D_ERROR, "Tcp6 GetModeData fail - %x\n", Status));
1245 return Status;
1246 }
1247
1248 if (Tcp6State == Tcp6StateEstablished) {
1249 return EFI_SUCCESS;
1250 } else if (Tcp6State > Tcp6StateEstablished ) {
1251 HttpCloseConnection(HttpInstance);
1252 }
1253
1254 return HttpCreateConnection (HttpInstance);
1255 }
1256
1257 /**
1258 Initialize TCP related data.
1259
1260 @param[in] HttpInstance The HTTP instance private data.
1261 @param[in] Wrap The HTTP token's wrap data.
1262 @param[in] Configure The Flag indicates whether the first time to initialize Tcp.
1263
1264 @retval EFI_SUCCESS The initialization of TCP instance is done.
1265 @retval Others Other error as indicated.
1266
1267 **/
1268 EFI_STATUS
1269 HttpInitTcp (
1270 IN HTTP_PROTOCOL *HttpInstance,
1271 IN HTTP_TOKEN_WRAP *Wrap,
1272 IN BOOLEAN Configure
1273 )
1274 {
1275 EFI_STATUS Status;
1276 ASSERT (HttpInstance != NULL);
1277
1278 if (!HttpInstance->LocalAddressIsIPv6) {
1279 //
1280 // Configure TCP instance.
1281 //
1282 if (Configure) {
1283 Status = HttpConfigureTcp4 (HttpInstance, Wrap);
1284 if (EFI_ERROR (Status)) {
1285 return Status;
1286 }
1287 }
1288
1289 //
1290 // Connect TCP.
1291 //
1292 Status = HttpConnectTcp4 (HttpInstance);
1293 if (EFI_ERROR (Status)) {
1294 return Status;
1295 }
1296 } else {
1297 //
1298 // Configure TCP instance.
1299 //
1300 if (Configure) {
1301 Status = HttpConfigureTcp6 (HttpInstance, Wrap);
1302 if (EFI_ERROR (Status)) {
1303 return Status;
1304 }
1305 }
1306
1307 //
1308 // Connect TCP.
1309 //
1310 Status = HttpConnectTcp6 (HttpInstance);
1311 if (EFI_ERROR (Status)) {
1312 return Status;
1313 }
1314 }
1315
1316 return EFI_SUCCESS;
1317
1318 }
1319
1320 /**
1321 Send the HTTP message through TCP4 or TCP6.
1322
1323 @param[in] HttpInstance The HTTP instance private data.
1324 @param[in] Wrap The HTTP token's wrap data.
1325 @param[in] TxString Buffer containing the HTTP message string.
1326 @param[in] TxStringLen Length of the HTTP message string in bytes.
1327
1328 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit queue.
1329 @retval Others Other error as indicated.
1330
1331 **/
1332 EFI_STATUS
1333 HttpTransmitTcp (
1334 IN HTTP_PROTOCOL *HttpInstance,
1335 IN HTTP_TOKEN_WRAP *Wrap,
1336 IN UINT8 *TxString,
1337 IN UINTN TxStringLen
1338 )
1339 {
1340 EFI_STATUS Status;
1341 EFI_TCP4_IO_TOKEN *Tx4Token;
1342 EFI_TCP4_PROTOCOL *Tcp4;
1343 EFI_TCP6_IO_TOKEN *Tx6Token;
1344 EFI_TCP6_PROTOCOL *Tcp6;
1345
1346 if (!HttpInstance->LocalAddressIsIPv6) {
1347 Tcp4 = HttpInstance->Tcp4;
1348 Tx4Token = &Wrap->TcpWrap.Tx4Token;
1349
1350 Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
1351 Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;
1352 Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;
1353 Tx4Token->CompletionToken.Status = EFI_NOT_READY;
1354
1355 Wrap->TcpWrap.IsTxDone = FALSE;
1356 Status = Tcp4->Transmit (Tcp4, Tx4Token);
1357 if (EFI_ERROR (Status)) {
1358 DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));
1359 return Status;
1360 }
1361
1362 } else {
1363 Tcp6 = HttpInstance->Tcp6;
1364 Tx6Token = &Wrap->TcpWrap.Tx6Token;
1365
1366 Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
1367 Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;
1368 Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;
1369 Tx6Token->CompletionToken.Status = EFI_NOT_READY;
1370
1371 Wrap->TcpWrap.IsTxDone = FALSE;
1372 Status = Tcp6->Transmit (Tcp6, Tx6Token);
1373 if (EFI_ERROR (Status)) {
1374 DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));
1375 return Status;
1376 }
1377 }
1378
1379
1380 return Status;
1381 }
1382
1383 /**
1384 Check whether the user's token or event has already
1385 been enqueue on HTTP Tx or Rx Token list.
1386
1387 @param[in] Map The container of either user's transmit or receive
1388 token.
1389 @param[in] Item Current item to check against.
1390 @param[in] Context The Token to check againist.
1391
1392 @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP
1393 @retval EFI_SUCCESS The current item isn't the same token/event as the
1394 context.
1395
1396 **/
1397 EFI_STATUS
1398 EFIAPI
1399 HttpTokenExist (
1400 IN NET_MAP *Map,
1401 IN NET_MAP_ITEM *Item,
1402 IN VOID *Context
1403 )
1404 {
1405 EFI_HTTP_TOKEN *Token;
1406 EFI_HTTP_TOKEN *TokenInItem;
1407
1408 Token = (EFI_HTTP_TOKEN *) Context;
1409 TokenInItem = (EFI_HTTP_TOKEN *) Item->Key;
1410
1411 if (Token == TokenInItem || Token->Event == TokenInItem->Event) {
1412 return EFI_ACCESS_DENIED;
1413 }
1414
1415 return EFI_SUCCESS;
1416 }
1417
1418 /**
1419 Check whether the HTTP message associated with Tx4Token or Tx6Token is already sent out.
1420
1421 @param[in] Map The container of Tx4Token or Tx6Token.
1422 @param[in] Item Current item to check against.
1423 @param[in] Context The Token to check againist.
1424
1425 @retval EFI_NOT_READY The HTTP message is still queued in the list.
1426 @retval EFI_SUCCESS The HTTP message has been sent out.
1427
1428 **/
1429 EFI_STATUS
1430 EFIAPI
1431 HttpTcpNotReady (
1432 IN NET_MAP *Map,
1433 IN NET_MAP_ITEM *Item,
1434 IN VOID *Context
1435 )
1436 {
1437 HTTP_TOKEN_WRAP *ValueInItem;
1438
1439 ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
1440
1441 if (!ValueInItem->TcpWrap.IsTxDone) {
1442 return EFI_NOT_READY;
1443 }
1444
1445 return EFI_SUCCESS;
1446 }
1447
1448 /**
1449 Transmit the HTTP mssage by processing the associated HTTP token.
1450
1451 @param[in] Map The container of Tx4Token or Tx6Token.
1452 @param[in] Item Current item to check against.
1453 @param[in] Context The Token to check againist.
1454
1455 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1456 @retval EFI_SUCCESS The HTTP message is queued into TCP transmit
1457 queue.
1458
1459 **/
1460 EFI_STATUS
1461 EFIAPI
1462 HttpTcpTransmit (
1463 IN NET_MAP *Map,
1464 IN NET_MAP_ITEM *Item,
1465 IN VOID *Context
1466 )
1467 {
1468 HTTP_TOKEN_WRAP *ValueInItem;
1469 EFI_STATUS Status;
1470 CHAR8 *RequestMsg;
1471 CHAR8 *Url;
1472 UINTN RequestMsgSize;
1473
1474 ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value;
1475 if (ValueInItem->TcpWrap.IsTxDone) {
1476 return EFI_SUCCESS;
1477 }
1478
1479 //
1480 // Parse the URI of the remote host.
1481 //
1482 Url = AllocatePool (StrLen (ValueInItem->HttpToken->Message->Data.Request->Url) + 1);
1483 if (Url == NULL) {
1484 return EFI_OUT_OF_RESOURCES;
1485 }
1486
1487 UnicodeStrToAsciiStr (ValueInItem->HttpToken->Message->Data.Request->Url, Url);
1488
1489 //
1490 // Create request message.
1491 //
1492 Status = HttpGenRequestMessage (
1493 ValueInItem->HttpToken->Message,
1494 Url,
1495 &RequestMsg,
1496 &RequestMsgSize
1497 );
1498 FreePool (Url);
1499
1500 if (EFI_ERROR (Status)){
1501 return Status;
1502 }
1503
1504 //
1505 // Transmit the request message.
1506 //
1507 Status = HttpTransmitTcp (
1508 ValueInItem->HttpInstance,
1509 ValueInItem,
1510 (UINT8*) RequestMsg,
1511 RequestMsgSize
1512 );
1513 FreePool (RequestMsg);
1514 return Status;
1515 }
1516
1517 /**
1518 Receive the HTTP response by processing the associated HTTP token.
1519
1520 @param[in] Map The container of Rx4Token or Rx6Token.
1521 @param[in] Item Current item to check against.
1522 @param[in] Context The Token to check againist.
1523
1524 @retval EFI_SUCCESS The HTTP response is queued into TCP receive
1525 queue.
1526 @retval Others Other error as indicated.
1527
1528 **/
1529 EFI_STATUS
1530 EFIAPI
1531 HttpTcpReceive (
1532 IN NET_MAP *Map,
1533 IN NET_MAP_ITEM *Item,
1534 IN VOID *Context
1535 )
1536 {
1537 //
1538 // Process the queued HTTP response.
1539 //
1540 return HttpResponseWorker ((HTTP_TOKEN_WRAP *) Item->Value);
1541 }
1542
1543 /**
1544 Receive the HTTP header by processing the associated HTTP token.
1545
1546 @param[in] HttpInstance The HTTP instance private data.
1547 @param[in, out] SizeofHeaders The HTTP header length.
1548 @param[in, out] BufferSize The size of buffer to cacahe the header message.
1549 @param[in] Timeout The time to wait for receiving the header packet.
1550
1551 @retval EFI_SUCCESS The HTTP header is received.
1552 @retval Others Other errors as indicated.
1553
1554 **/
1555 EFI_STATUS
1556 HttpTcpReceiveHeader (
1557 IN HTTP_PROTOCOL *HttpInstance,
1558 IN OUT UINTN *SizeofHeaders,
1559 IN OUT UINTN *BufferSize,
1560 IN EFI_EVENT Timeout
1561 )
1562 {
1563 EFI_STATUS Status;
1564 EFI_TCP4_IO_TOKEN *Rx4Token;
1565 EFI_TCP4_PROTOCOL *Tcp4;
1566 EFI_TCP6_IO_TOKEN *Rx6Token;
1567 EFI_TCP6_PROTOCOL *Tcp6;
1568 CHAR8 **EndofHeader;
1569 CHAR8 **HttpHeaders;
1570 CHAR8 *Buffer;
1571
1572 ASSERT (HttpInstance != NULL);
1573
1574 EndofHeader = HttpInstance->EndofHeader;
1575 HttpHeaders = HttpInstance->HttpHeaders;
1576 Tcp4 = HttpInstance->Tcp4;
1577 Tcp6 = HttpInstance->Tcp6;
1578 Buffer = NULL;
1579 Rx4Token = NULL;
1580 Rx6Token = NULL;
1581
1582 if (HttpInstance->LocalAddressIsIPv6) {
1583 ASSERT (Tcp6 != NULL);
1584 } else {
1585 ASSERT (Tcp4 != NULL);
1586 }
1587
1588 if (!HttpInstance->LocalAddressIsIPv6) {
1589 Rx4Token = &HttpInstance->Rx4Token;
1590 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
1591 if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
1592 Status = EFI_OUT_OF_RESOURCES;
1593 return Status;
1594 }
1595
1596 //
1597 // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1598 //
1599 while (*EndofHeader == NULL) {
1600 HttpInstance->IsRxDone = FALSE;
1601 Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN;
1602 Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
1603 Status = Tcp4->Receive (Tcp4, Rx4Token);
1604 if (EFI_ERROR (Status)) {
1605 DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
1606 return Status;
1607 }
1608
1609 while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1610 Tcp4->Poll (Tcp4);
1611 }
1612
1613 if (!HttpInstance->IsRxDone) {
1614 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
1615 Rx4Token->CompletionToken.Status = EFI_TIMEOUT;
1616 }
1617
1618 Status = Rx4Token->CompletionToken.Status;
1619 if (EFI_ERROR (Status)) {
1620 return Status;
1621 }
1622
1623 //
1624 // Append the response string.
1625 //
1626 *BufferSize = (*SizeofHeaders) + Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength;
1627 Buffer = AllocateZeroPool (*BufferSize);
1628 if (Buffer == NULL) {
1629 Status = EFI_OUT_OF_RESOURCES;
1630 return Status;
1631 }
1632
1633 if (*HttpHeaders != NULL) {
1634 CopyMem (Buffer, *HttpHeaders, (*SizeofHeaders));
1635 FreePool (*HttpHeaders);
1636 }
1637
1638 CopyMem (
1639 Buffer + (*SizeofHeaders),
1640 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer,
1641 Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength
1642 );
1643 *HttpHeaders = Buffer;
1644 *SizeofHeaders = *BufferSize;
1645
1646 //
1647 // Check whether we received end of HTTP headers.
1648 //
1649 *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
1650 }
1651 FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
1652 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
1653
1654 } else {
1655 Rx6Token = &HttpInstance->Rx6Token;
1656 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
1657 if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
1658 Status = EFI_OUT_OF_RESOURCES;
1659 return Status;
1660 }
1661
1662 //
1663 // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
1664 //
1665 while (*EndofHeader == NULL) {
1666 HttpInstance->IsRxDone = FALSE;
1667 Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN;
1668 Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
1669 Status = Tcp6->Receive (Tcp6, Rx6Token);
1670 if (EFI_ERROR (Status)) {
1671 DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
1672 return Status;
1673 }
1674
1675 while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1676 Tcp6->Poll (Tcp6);
1677 }
1678
1679 if (!HttpInstance->IsRxDone) {
1680 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
1681 Rx6Token->CompletionToken.Status = EFI_TIMEOUT;
1682 }
1683
1684 Status = Rx6Token->CompletionToken.Status;
1685 if (EFI_ERROR (Status)) {
1686 return Status;
1687 }
1688
1689 //
1690 // Append the response string.
1691 //
1692 *BufferSize = (*SizeofHeaders) + Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength;
1693 Buffer = AllocateZeroPool (*BufferSize);
1694 if (Buffer == NULL) {
1695 Status = EFI_OUT_OF_RESOURCES;
1696 return Status;
1697 }
1698
1699 if (*HttpHeaders != NULL) {
1700 CopyMem (Buffer, *HttpHeaders, (*SizeofHeaders));
1701 FreePool (*HttpHeaders);
1702 }
1703
1704 CopyMem (
1705 Buffer + (*SizeofHeaders),
1706 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer,
1707 Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength
1708 );
1709 *HttpHeaders = Buffer;
1710 *SizeofHeaders = *BufferSize;
1711
1712 //
1713 // Check whether we received end of HTTP headers.
1714 //
1715 *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
1716
1717 }
1718 FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
1719 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
1720 }
1721
1722 //
1723 // Skip the CRLF after the HTTP headers.
1724 //
1725 *EndofHeader = *EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR);
1726
1727 return EFI_SUCCESS;
1728 }
1729
1730 /**
1731 Receive the HTTP body by processing the associated HTTP token.
1732
1733 @param[in] Wrap The HTTP token's wrap data.
1734 @param[in] HttpMsg The HTTP message data.
1735 @param[in] Timeout The time to wait for receiving the body packet.
1736
1737 @retval EFI_SUCCESS The HTTP body is received.
1738 @retval Others Other error as indicated.
1739
1740 **/
1741 EFI_STATUS
1742 HttpTcpReceiveBody (
1743 IN HTTP_TOKEN_WRAP *Wrap,
1744 IN EFI_HTTP_MESSAGE *HttpMsg,
1745 IN EFI_EVENT Timeout
1746 )
1747 {
1748 EFI_STATUS Status;
1749 HTTP_PROTOCOL *HttpInstance;
1750 EFI_TCP6_PROTOCOL *Tcp6;
1751 EFI_TCP6_IO_TOKEN *Rx6Token;
1752 EFI_TCP4_PROTOCOL *Tcp4;
1753 EFI_TCP4_IO_TOKEN *Rx4Token;
1754
1755 HttpInstance = Wrap->HttpInstance;
1756 Tcp4 = HttpInstance->Tcp4;
1757 Tcp6 = HttpInstance->Tcp6;
1758 Rx4Token = NULL;
1759 Rx6Token = NULL;
1760
1761 if (HttpInstance->LocalAddressIsIPv6) {
1762 ASSERT (Tcp6 != NULL);
1763 } else {
1764 ASSERT (Tcp4 != NULL);
1765 }
1766
1767 if (HttpInstance->LocalAddressIsIPv6) {
1768 Rx6Token = &Wrap->TcpWrap.Rx6Token;
1769 Rx6Token ->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;
1770 Rx6Token ->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;
1771 Rx6Token ->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;
1772 Rx6Token->CompletionToken.Status = EFI_NOT_READY;
1773
1774 Status = Tcp6->Receive (Tcp6, Rx6Token);
1775 if (EFI_ERROR (Status)) {
1776 DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
1777 return Status;
1778 }
1779
1780 while (!Wrap->TcpWrap.IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1781 Tcp6->Poll (Tcp6);
1782 }
1783
1784 if (!Wrap->TcpWrap.IsRxDone) {
1785 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
1786 Rx6Token->CompletionToken.Status = EFI_TIMEOUT;
1787 Wrap->HttpToken->Status = Rx6Token->CompletionToken.Status;
1788 gBS->SignalEvent (Wrap->HttpToken->Event);
1789 }
1790 } else {
1791 Rx4Token = &Wrap->TcpWrap.Rx4Token;
1792 Rx4Token->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;
1793 Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;
1794 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;
1795
1796 Rx4Token->CompletionToken.Status = EFI_NOT_READY;
1797 Status = Tcp4->Receive (Tcp4, Rx4Token);
1798 if (EFI_ERROR (Status)) {
1799 DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
1800 return Status;
1801 }
1802
1803 while (!Wrap->TcpWrap.IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1804 Tcp4->Poll (Tcp4);
1805 }
1806
1807 if (!Wrap->TcpWrap.IsRxDone) {
1808 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
1809 Rx4Token->CompletionToken.Status = EFI_TIMEOUT;
1810 Wrap->HttpToken->Status = Rx4Token->CompletionToken.Status;
1811 gBS->SignalEvent (Wrap->HttpToken->Event);
1812 }
1813 }
1814
1815 return EFI_SUCCESS;
1816
1817 }
1818
1819 /**
1820 Clean up Tcp Tokens while the Tcp transmission error occurs.
1821
1822 @param[in] Wrap Pointer to HTTP token's wrap data.
1823
1824 **/
1825 VOID
1826 HttpTcpTokenCleanup (
1827 IN HTTP_TOKEN_WRAP *Wrap
1828 )
1829 {
1830 HTTP_PROTOCOL *HttpInstance;
1831 EFI_TCP4_IO_TOKEN *Rx4Token;
1832 EFI_TCP6_IO_TOKEN *Rx6Token;
1833
1834 ASSERT (Wrap != NULL);
1835 HttpInstance = Wrap->HttpInstance;
1836 Rx4Token = NULL;
1837 Rx6Token = NULL;
1838
1839 if (HttpInstance->LocalAddressIsIPv6) {
1840 Rx6Token = &Wrap->TcpWrap.Rx6Token;
1841
1842 if (Rx6Token->CompletionToken.Event != NULL) {
1843 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
1844 Rx6Token->CompletionToken.Event = NULL;
1845 }
1846
1847 FreePool (Wrap);
1848
1849 Rx6Token = &HttpInstance->Rx6Token;
1850
1851 if (Rx6Token->CompletionToken.Event != NULL) {
1852 gBS->CloseEvent (Rx6Token->CompletionToken.Event);
1853 Rx6Token->CompletionToken.Event = NULL;
1854 }
1855
1856 if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
1857 FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
1858 Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
1859 }
1860
1861 } else {
1862 Rx4Token = &Wrap->TcpWrap.Rx4Token;
1863
1864 if (Rx4Token->CompletionToken.Event != NULL) {
1865 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
1866 Rx4Token->CompletionToken.Event = NULL;
1867 }
1868
1869 FreePool (Wrap);
1870
1871 Rx4Token = &HttpInstance->Rx4Token;
1872
1873 if (Rx4Token->CompletionToken.Event != NULL) {
1874 gBS->CloseEvent (Rx4Token->CompletionToken.Event);
1875 Rx4Token->CompletionToken.Event = NULL;
1876 }
1877
1878
1879 if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
1880 FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
1881 Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
1882 }
1883 }
1884
1885 }