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