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