From b659408b933f40765960e877de3e1f8ceaab52cb Mon Sep 17 00:00:00 2001 From: Zhang Lubo Date: Mon, 9 Nov 2015 03:30:42 +0000 Subject: NetworkPkg:Enable Http Boot over Ipv6 stack Add new features to support Http boot over ipv6 stack. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo Reviewed-by: Fu Siyuan Reviewed-by: Ye Ting Reviewed-by: Wu Jiaxin git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18743 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/HttpDxe/HttpDns.c | 207 ++++++- NetworkPkg/HttpDxe/HttpDns.h | 20 + NetworkPkg/HttpDxe/HttpDriver.c | 806 +++++++++++++++++-------- NetworkPkg/HttpDxe/HttpDriver.h | 143 ++++- NetworkPkg/HttpDxe/HttpDxe.inf | 5 + NetworkPkg/HttpDxe/HttpDxe.uni | Bin 1822 -> 1854 bytes NetworkPkg/HttpDxe/HttpImpl.c | 374 +++++------- NetworkPkg/HttpDxe/HttpProto.c | 1253 +++++++++++++++++++++++++++++++++------ NetworkPkg/HttpDxe/HttpProto.h | 193 ++++-- 9 files changed, 2312 insertions(+), 689 deletions(-) (limited to 'NetworkPkg/HttpDxe') diff --git a/NetworkPkg/HttpDxe/HttpDns.c b/NetworkPkg/HttpDxe/HttpDns.c index daebc173b5..0f5fe18072 100644 --- a/NetworkPkg/HttpDxe/HttpDns.c +++ b/NetworkPkg/HttpDxe/HttpDns.c @@ -194,11 +194,11 @@ Exit: Dns4->Configure (Dns4, NULL); gBS->CloseProtocol ( - Dns4Handle, - &gEfiDns4ProtocolGuid, - Service->ImageHandle, - Service->ControllerHandle - ); + Dns4Handle, + &gEfiDns4ProtocolGuid, + Service->ImageHandle, + Service->ControllerHandle + ); } if (Dns4Handle != NULL) { @@ -216,3 +216,200 @@ Exit: return Status; } + +/** + Retrieve the host address using the EFI_DNS6_PROTOCOL. + + @param[in] HttpInstance Pointer to HTTP_PROTOCOL instance. + @param[in] HostName Pointer to buffer containing hostname. + @param[out] IpAddress On output, pointer to buffer containing IPv6 address. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_DEVICE_ERROR An unexpected network error occurred. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +HttpDns6 ( + IN HTTP_PROTOCOL *HttpInstance, + IN CHAR16 *HostName, + OUT EFI_IPv6_ADDRESS *IpAddress + ) +{ + EFI_STATUS Status; + HTTP_SERVICE *Service; + EFI_DNS6_PROTOCOL *Dns6; + EFI_DNS6_CONFIG_DATA Dns6ConfigData; + EFI_DNS6_COMPLETION_TOKEN Token; + EFI_HANDLE Dns6Handle; + EFI_IP6_CONFIG_PROTOCOL *Ip6Config; + EFI_IPv6_ADDRESS *DnsServerList; + UINTN DnsServerListCount; + UINTN DataSize; + BOOLEAN IsDone; + + + Service = HttpInstance->Service; + ASSERT (Service != NULL); + + DnsServerList = NULL; + DnsServerListCount = 0; + Dns6 = NULL; + Dns6Handle = NULL; + ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN)); + + // + // Get DNS server list from EFI IPv6 Configuration protocol. + // + Status = gBS->HandleProtocol (Service->ControllerHandle, &gEfiIp6ConfigProtocolGuid, (VOID **) &Ip6Config); + if (!EFI_ERROR (Status)) { + // + // Get the required size. + // + DataSize = 0; + Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL); + if (Status == EFI_BUFFER_TOO_SMALL) { + DnsServerList = AllocatePool (DataSize); + if (DnsServerList == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList); + if (EFI_ERROR (Status)) { + FreePool (DnsServerList); + DnsServerList = NULL; + } else { + DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS); + } + } + } + + // + // Create a DNSv6 child instance and get the protocol. + // + Status = NetLibCreateServiceChild ( + Service->ControllerHandle, + Service->ImageHandle, + &gEfiDns6ServiceBindingProtocolGuid, + &Dns6Handle + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + Status = gBS->OpenProtocol ( + Dns6Handle, + &gEfiDns6ProtocolGuid, + (VOID **) &Dns6, + Service->ImageHandle, + Service->ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Configure DNS6 instance for the DNS server address and protocol. + // + ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA)); + Dns6ConfigData.DnsServerCount = (UINT32)DnsServerListCount; + Dns6ConfigData.DnsServerList = DnsServerList; + Dns6ConfigData.EnableDnsCache = TRUE; + Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP; + IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp, &HttpInstance->Ipv6Node.LocalAddress); + Status = Dns6->Configure ( + Dns6, + &Dns6ConfigData + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + Token.Status = EFI_NOT_READY; + IsDone = FALSE; + // + // Create event to set the IsDone flag when name resolution is finished. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpCommonNotify, + &IsDone, + &Token.Event + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Start asynchronous name resolution. + // + Status = Dns6->HostNameToIp (Dns6, HostName, &Token); + if (EFI_ERROR (Status)) { + goto Exit; + } + + while (!IsDone) { + Dns6->Poll (Dns6); + } + + // + // Name resolution is done, check result. + // + Status = Token.Status; + if (!EFI_ERROR (Status)) { + if (Token.RspData.H2AData == NULL) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + // + // We just return the first IPv6 address from DNS protocol. + // + IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList); + Status = EFI_SUCCESS; + } + +Exit: + + if (Token.Event != NULL) { + gBS->CloseEvent (Token.Event); + } + if (Token.RspData.H2AData != NULL) { + if (Token.RspData.H2AData->IpList != NULL) { + FreePool (Token.RspData.H2AData->IpList); + } + FreePool (Token.RspData.H2AData); + } + + if (Dns6 != NULL) { + Dns6->Configure (Dns6, NULL); + + gBS->CloseProtocol ( + Dns6Handle, + &gEfiDns6ProtocolGuid, + Service->ImageHandle, + Service->ControllerHandle + ); + } + + if (Dns6Handle != NULL) { + NetLibDestroyServiceChild ( + Service->ControllerHandle, + Service->ImageHandle, + &gEfiDns6ServiceBindingProtocolGuid, + Dns6Handle + ); + } + + if (DnsServerList != NULL) { + FreePool (DnsServerList); + } + + return Status; +} diff --git a/NetworkPkg/HttpDxe/HttpDns.h b/NetworkPkg/HttpDxe/HttpDns.h index 0fb418635c..fa0c8f4a99 100644 --- a/NetworkPkg/HttpDxe/HttpDns.h +++ b/NetworkPkg/HttpDxe/HttpDns.h @@ -35,4 +35,24 @@ HttpDns4 ( OUT EFI_IPv4_ADDRESS *IpAddress ); +/** + Retrieve the host address using the EFI_DNS6_PROTOCOL. + + @param[in] HttpInstance Pointer to HTTP_PROTOCOL instance. + @param[in] HostName Pointer to buffer containing hostname. + @param[out] IpAddress On output, pointer to buffer containing IPv6 address. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_DEVICE_ERROR An unexpected network error occurred. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +HttpDns6 ( + IN HTTP_PROTOCOL *HttpInstance, + IN CHAR16 *HostName, + OUT EFI_IPv6_ADDRESS *IpAddress + ); + #endif \ No newline at end of file diff --git a/NetworkPkg/HttpDxe/HttpDriver.c b/NetworkPkg/HttpDxe/HttpDriver.c index bd1d04e78c..2518f4e707 100644 --- a/NetworkPkg/HttpDxe/HttpDriver.c +++ b/NetworkPkg/HttpDxe/HttpDriver.c @@ -20,15 +20,25 @@ EFI_HTTP_UTILITIES_PROTOCOL *mHttpUtilities = NULL; /// /// Driver Binding Protocol instance /// -EFI_DRIVER_BINDING_PROTOCOL gHttpDxeDriverBinding = { - HttpDxeDriverBindingSupported, - HttpDxeDriverBindingStart, - HttpDxeDriverBindingStop, +EFI_DRIVER_BINDING_PROTOCOL gHttpDxeIp4DriverBinding = { + HttpDxeIp4DriverBindingSupported, + HttpDxeIp4DriverBindingStart, + HttpDxeIp4DriverBindingStop, HTTP_DRIVER_VERSION, NULL, NULL }; +EFI_DRIVER_BINDING_PROTOCOL gHttpDxeIp6DriverBinding = { + HttpDxeIp6DriverBindingSupported, + HttpDxeIp6DriverBindingStart, + HttpDxeIp6DriverBindingStop, + HTTP_DRIVER_VERSION, + NULL, + NULL +}; + + /** Create a HTTP driver service binding private instance. @@ -73,33 +83,59 @@ HttpCreateService ( /** Release all the resource used the HTTP service binding instance. - @param HttpService The HTTP private instance. - + @param[in] HttpService The HTTP private instance. + @param[in] UsingIpv6 Indicate use TCP4 protocol or TCP6 protocol. + if TRUE, use Tcp6 protocol. + if FALSE, use Tcp4 protocl. **/ VOID HttpCleanService ( - IN HTTP_SERVICE *HttpService + IN HTTP_SERVICE *HttpService, + IN BOOLEAN UsingIpv6 ) -{ +{ + if (HttpService == NULL) { return ; } - - if (HttpService->TcpChildHandle != NULL) { - gBS->CloseProtocol ( - HttpService->TcpChildHandle, - &gEfiTcp4ProtocolGuid, - HttpService->ImageHandle, - HttpService->ControllerHandle - ); - - NetLibDestroyServiceChild ( - HttpService->ControllerHandle, - HttpService->ImageHandle, - &gEfiTcp4ServiceBindingProtocolGuid, - HttpService->TcpChildHandle - ); + if (!UsingIpv6) { + if (HttpService->Tcp4ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpService->Tcp4ChildHandle, + &gEfiTcp4ProtocolGuid, + HttpService->ImageHandle, + HttpService->ControllerHandle + ); + + NetLibDestroyServiceChild ( + HttpService->ControllerHandle, + HttpService->ImageHandle, + &gEfiTcp4ServiceBindingProtocolGuid, + HttpService->Tcp4ChildHandle + ); + + HttpService->Tcp4ChildHandle = NULL; + } + } else { + if (HttpService->Tcp6ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpService->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + HttpService->ImageHandle, + HttpService->ControllerHandle + ); + + NetLibDestroyServiceChild ( + HttpService->ControllerHandle, + HttpService->ImageHandle, + &gEfiTcp6ServiceBindingProtocolGuid, + HttpService->Tcp6ChildHandle + ); + + HttpService->Tcp6ChildHandle = NULL; + } } + } /** @@ -107,7 +143,7 @@ HttpCleanService ( in the system. @param[in] Event Not used. - @param[in] Context The pointer to the IP4 config2 instance data. + @param[in] Context The pointer to the IP4 config2 instance data or IP6 Config instance data. **/ VOID @@ -122,7 +158,7 @@ HttpUtilitiesInstalledCallback ( NULL, (VOID **) &mHttpUtilities ); - + // // Close the event if Http utilities protocol is loacted. // @@ -150,6 +186,7 @@ HttpDxeDriverEntryPoint ( IN EFI_SYSTEM_TABLE *SystemTable ) { + EFI_STATUS Status; VOID *Registration; gBS->LocateProtocol ( @@ -174,14 +211,39 @@ HttpDxeDriverEntryPoint ( // // Install UEFI Driver Model protocol(s). // - return EfiLibInstallDriverBindingComponentName2 ( - ImageHandle, - SystemTable, - &gHttpDxeDriverBinding, + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gHttpDxeIp4DriverBinding, + ImageHandle, + &gHttpDxeComponentName, + &gHttpDxeComponentName2 + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gHttpDxeIp6DriverBinding, + NULL, + &gHttpDxeComponentName, + &gHttpDxeComponentName2 + ); + if (EFI_ERROR (Status)) { + gBS->UninstallMultipleProtocolInterfaces ( ImageHandle, + &gEfiDriverBindingProtocolGuid, + &gHttpDxeIp4DriverBinding, + &gEfiComponentName2ProtocolGuid, + &gHttpDxeComponentName2, + &gEfiComponentNameProtocolGuid, &gHttpDxeComponentName, - &gHttpDxeComponentName2 + NULL ); + } + return Status; } /** @@ -223,6 +285,309 @@ HttpDestroyChildEntryInHandleBuffer ( return ServiceBinding->DestroyChild (ServiceBinding, HttpInstance->Handle); } +/** + Test to see if this driver supports ControllerHandle. This is the worker function for + HttpDxeIp4(6)DriverBindingSupported. + + @param[in] This The pointer to the driver binding protocol. + @param[in] ControllerHandle The handle of device to be tested. + @param[in] RemainingDevicePath Optional parameter used to pick a specific child + device to be started. + @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +HttpDxeSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL, + IN UINT8 IpVersion + ) +{ + EFI_STATUS Status; + EFI_GUID *TcpServiceBindingProtocolGuid; + + if (IpVersion == IP_VERSION_4) { + TcpServiceBindingProtocolGuid = &gEfiTcp4ServiceBindingProtocolGuid; + } else { + TcpServiceBindingProtocolGuid = &gEfiTcp6ServiceBindingProtocolGuid; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + TcpServiceBindingProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + Start this driver on ControllerHandle. This is the worker function for + HttpDxeIp4(6)DriverBindingStart. + + @param[in] This The pointer to the driver binding protocol. + @param[in] ControllerHandle The handle of device to be started. + @param[in] RemainingDevicePath Optional parameter used to pick a specific child + device to be started. + @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. + + + @retval EFI_SUCCESS This driver is installed to ControllerHandle. + @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +HttpDxeStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL, + IN UINT8 IpVersion + ) +{ + EFI_STATUS Status; + EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; + HTTP_SERVICE *HttpService; + VOID *Interface; + BOOLEAN UsingIpv6; + + UsingIpv6 = FALSE; + + // + // Test for the Http service binding protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiHttpServiceBindingProtocolGuid, + (VOID **) &ServiceBinding, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (!EFI_ERROR (Status)) { + HttpService = HTTP_SERVICE_FROM_PROTOCOL (ServiceBinding); + } else { + Status = HttpCreateService (ControllerHandle, This->DriverBindingHandle, &HttpService); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (HttpService != NULL); + + // + // Install the HttpServiceBinding Protocol onto Controller + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiHttpServiceBindingProtocolGuid, + &HttpService->ServiceBinding, + NULL + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + } + + if (IpVersion == IP_VERSION_4) { + + if (HttpService->Tcp4ChildHandle == NULL) { + // + // Create a TCP4 child instance, but do not configure it. This will establish the parent-child relationship. + // + Status = NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiTcp4ServiceBindingProtocolGuid, + &HttpService->Tcp4ChildHandle + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status = gBS->OpenProtocol ( + HttpService->Tcp4ChildHandle, + &gEfiTcp4ProtocolGuid, + &Interface, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + } else { + return EFI_ALREADY_STARTED; + } + + } else { + UsingIpv6 = TRUE; + + if (HttpService->Tcp6ChildHandle == NULL) { + // + // Create a TCP6 child instance, but do not configure it. This will establish the parent-child relationship. + // + Status = NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiTcp6ServiceBindingProtocolGuid, + &HttpService->Tcp6ChildHandle + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status = gBS->OpenProtocol ( + HttpService->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + &Interface, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + } else { + return EFI_ALREADY_STARTED; + } + + } + + return EFI_SUCCESS; + +ON_ERROR: + + if (HttpService != NULL) { + HttpCleanService (HttpService, UsingIpv6); + if (HttpService->Tcp4ChildHandle == NULL && HttpService->Tcp6ChildHandle == NULL) { + FreePool (HttpService); + } + } + + return Status; + + +} + +/** + Stop this driver on ControllerHandle. This is the worker function for + HttpDxeIp4(6)DriverBindingStop. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to stop driver on. + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of + children is zero stop the entire bus driver. + @param[in] ChildHandleBuffer List of Child Handles to Stop. + @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. + + @retval EFI_SUCCESS This driver was removed ControllerHandle. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval Others This driver was not removed from this device + +**/ +EFI_STATUS +EFIAPI +HttpDxeStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer, + IN UINT8 IpVersion + ) +{ + EFI_HANDLE NicHandle; + EFI_STATUS Status; + EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; + HTTP_SERVICE *HttpService; + LIST_ENTRY *List; + HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context; + BOOLEAN UsingIpv6; + + // + // HTTP driver opens TCP4(6) child, So, Controller is a TCP4(6) + // child handle. Locate the Nic handle first. Then get the + // HTTP private data back. + // + if (IpVersion == IP_VERSION_4) { + UsingIpv6 = FALSE; + NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid); + } else { + UsingIpv6 = TRUE; + NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiTcp6ProtocolGuid); + } + + if (NicHandle == NULL) { + return EFI_SUCCESS; + } + + Status = gBS->OpenProtocol ( + NicHandle, + &gEfiHttpServiceBindingProtocolGuid, + (VOID **) &ServiceBinding, + This->DriverBindingHandle, + NicHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (!EFI_ERROR (Status)) { + + HttpService = HTTP_SERVICE_FROM_PROTOCOL (ServiceBinding); + + if (NumberOfChildren != 0) { + // + // Destroy the HTTP child instance in ChildHandleBuffer. + // + List = &HttpService->ChildrenList; + Context.ServiceBinding = ServiceBinding; + Context.NumberOfChildren = NumberOfChildren; + Context.ChildHandleBuffer = ChildHandleBuffer; + Status = NetDestroyLinkList ( + List, + HttpDestroyChildEntryInHandleBuffer, + &Context, + NULL + ); + } else { + + HttpCleanService (HttpService, UsingIpv6); + + if (HttpService->Tcp4ChildHandle == NULL && HttpService->Tcp6ChildHandle == NULL) { + gBS->UninstallProtocolInterface ( + NicHandle, + &gEfiHttpServiceBindingProtocolGuid, + ServiceBinding + ); + FreePool (HttpService); + } + Status = EFI_SUCCESS; + } + } + + return Status; + +} + /** Tests to see if this driver supports a given controller. If a child device is provided, it further tests to see if this driver supports creating a handle for the specified child device. @@ -267,41 +632,18 @@ HttpDestroyChildEntryInHandleBuffer ( **/ EFI_STATUS EFIAPI -HttpDxeDriverBindingSupported ( +HttpDxeIp4DriverBindingSupported ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL ) { - EFI_STATUS Status; - - // - // Test for the HttpServiceBinding protocol. - // - Status = gBS->OpenProtocol ( - ControllerHandle, - &gEfiHttpServiceBindingProtocolGuid, - NULL, - This->DriverBindingHandle, - ControllerHandle, - EFI_OPEN_PROTOCOL_TEST_PROTOCOL - ); - if (!EFI_ERROR (Status)) { - return EFI_ALREADY_STARTED; - } - - // - // Test for the Tcp4 Protocol - // - return gBS->OpenProtocol ( - ControllerHandle, - &gEfiTcp4ServiceBindingProtocolGuid, - NULL, - This->DriverBindingHandle, - ControllerHandle, - EFI_OPEN_PROTOCOL_TEST_PROTOCOL - ); - + return HttpDxeSupported ( + This, + ControllerHandle, + RemainingDevicePath, + IP_VERSION_4 + ); } /** @@ -342,90 +684,173 @@ HttpDxeDriverBindingSupported ( **/ EFI_STATUS EFIAPI -HttpDxeDriverBindingStart ( +HttpDxeIp4DriverBindingStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL ) { - EFI_STATUS Status; - HTTP_SERVICE *HttpService; - VOID *Interface; + return HttpDxeStart ( + This, + ControllerHandle, + RemainingDevicePath, + IP_VERSION_4 + ); +} + +/** + Stops a device controller or a bus controller. - // - // Test for the Http service binding protocol - // - Status = gBS->OpenProtocol ( - ControllerHandle, - &gEfiHttpServiceBindingProtocolGuid, - NULL, - This->DriverBindingHandle, - ControllerHandle, - EFI_OPEN_PROTOCOL_TEST_PROTOCOL - ); + The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0. - if (Status == EFI_SUCCESS) { - return EFI_ALREADY_STARTED; - } + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. - Status = HttpCreateService (ControllerHandle, This->DriverBindingHandle, &HttpService); - if (EFI_ERROR (Status)) { - return Status; - } +**/ +EFI_STATUS +EFIAPI +HttpDxeIp4DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +{ + return HttpDxeStop ( + This, + ControllerHandle, + NumberOfChildren, + ChildHandleBuffer, + IP_VERSION_4 + ); +} - ASSERT (HttpService != NULL); +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. - // - // Create a TCP child instance, but do not configure it. This will establish the parent-child relationship. - // - Status = NetLibCreateServiceChild ( - ControllerHandle, - This->DriverBindingHandle, - &gEfiTcp4ServiceBindingProtocolGuid, - &HttpService->TcpChildHandle - ); + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Because ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. - Status = gBS->OpenProtocol ( - HttpService->TcpChildHandle, - &gEfiTcp4ProtocolGuid, - &Interface, - This->DriverBindingHandle, - ControllerHandle, - EFI_OPEN_PROTOCOL_BY_DRIVER - ); - - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +HttpDxeIp6DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + return HttpDxeSupported ( + This, + ControllerHandle, + RemainingDevicePath, + IP_VERSION_6 + ); - // - // Install the HttpServiceBinding Protocol onto Controller - // - Status = gBS->InstallMultipleProtocolInterfaces ( - &ControllerHandle, - &gEfiHttpServiceBindingProtocolGuid, - &HttpService->ServiceBinding, - NULL - ); +} - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } +/** + Starts a device controller or a bus controller. - return EFI_SUCCESS; + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned + EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified by This must + have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. -ON_ERROR: + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child handle is created by this + driver. - if (HttpService != NULL) { - HttpCleanService (HttpService); - FreePool (HttpService); - } - - return Status; + @retval EFI_SUCCESS The device was started. + @retval EFI_ALREADY_STARTED This device is already running on ControllerHandle. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +HttpDxeIp6DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + return HttpDxeStart ( + This, + ControllerHandle, + RemainingDevicePath, + IP_VERSION_6 + ); } /** @@ -456,78 +881,21 @@ ON_ERROR: **/ EFI_STATUS EFIAPI -HttpDxeDriverBindingStop ( +HttpDxeIp6DriverBindingStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer OPTIONAL ) { - EFI_HANDLE NicHandle; - EFI_STATUS Status; - EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; - HTTP_SERVICE *HttpService; - LIST_ENTRY *List; - HTTP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context; - - // - // HTTP driver opens TCP child, So, Controller is a TCP - // child handle. Locate the Nic handle first. Then get the - // HTTP private data back. - // - NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid); - if (NicHandle == NULL) { - return EFI_SUCCESS; - } - - Status = gBS->OpenProtocol ( - NicHandle, - &gEfiHttpServiceBindingProtocolGuid, - (VOID **) &ServiceBinding, - This->DriverBindingHandle, - NicHandle, - EFI_OPEN_PROTOCOL_GET_PROTOCOL - ); - - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - HttpService = HTTP_SERVICE_FROM_PROTOCOL (ServiceBinding); - - if (!IsListEmpty (&HttpService->ChildrenList)) { - // - // Destroy the HTTP child instance in ChildHandleBuffer. - // - List = &HttpService->ChildrenList; - Context.ServiceBinding = ServiceBinding; - Context.NumberOfChildren = NumberOfChildren; - Context.ChildHandleBuffer = ChildHandleBuffer; - Status = NetDestroyLinkList ( - List, - HttpDestroyChildEntryInHandleBuffer, - &Context, - NULL - ); - } - - if (NumberOfChildren == 0 && IsListEmpty (&HttpService->ChildrenList)) { - gBS->UninstallProtocolInterface ( - NicHandle, - &gEfiHttpServiceBindingProtocolGuid, - ServiceBinding + return HttpDxeStop ( + This, + ControllerHandle, + NumberOfChildren, + ChildHandleBuffer, + IP_VERSION_6 ); - - HttpCleanService (HttpService); - - FreePool (HttpService); - - Status = EFI_SUCCESS; - } - - return Status; } - /** Creates a child handle and installs a protocol. @@ -557,7 +925,6 @@ HttpServiceBindingCreateChild ( HTTP_SERVICE *HttpService; HTTP_PROTOCOL *HttpInstance; EFI_STATUS Status; - VOID *Interface; EFI_TPL OldTpl; if ((This == NULL) || (ChildHandle == NULL)) { @@ -569,6 +936,12 @@ HttpServiceBindingCreateChild ( if (HttpInstance == NULL) { return EFI_OUT_OF_RESOURCES; } + + HttpInstance->Signature = HTTP_PROTOCOL_SIGNATURE; + HttpInstance->Service = HttpService; + CopyMem (&HttpInstance->Http, &mEfiHttpTemplate, sizeof (HttpInstance->Http)); + NetMapInit (&HttpInstance->TxTokens); + NetMapInit (&HttpInstance->RxTokens); // // Install HTTP protocol onto ChildHandle @@ -584,27 +957,7 @@ HttpServiceBindingCreateChild ( goto ON_ERROR; } - HttpInstance->Handle = *ChildHandle; - - Status = HttpInitProtocol (HttpService, HttpInstance); - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } - - // - // Open the default Tcp4 protocol by child. - // - Status = gBS->OpenProtocol ( - HttpService->TcpChildHandle, - &gEfiTcp4ProtocolGuid, - (VOID **) &Interface, - gHttpDxeDriverBinding.DriverBindingHandle, - HttpInstance->Handle, - EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER - ); - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } + HttpInstance->Handle = *ChildHandle; // // Add it to the HTTP service's child list. @@ -619,8 +972,9 @@ HttpServiceBindingCreateChild ( return EFI_SUCCESS; ON_ERROR: - - HttpCleanProtocol (HttpInstance); + + NetMapClean (&HttpInstance->TxTokens); + NetMapClean (&HttpInstance->RxTokens); FreePool (HttpInstance); return Status; @@ -664,8 +1018,8 @@ HttpServiceBindingDestroyChild ( ChildHandle, &gEfiHttpProtocolGuid, (VOID **) &Http, - gHttpDxeDriverBinding.DriverBindingHandle, - ChildHandle, + NULL, + NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { @@ -681,16 +1035,6 @@ HttpServiceBindingDestroyChild ( return EFI_SUCCESS; } - // - // Close the Tcp4 protocol. - // - gBS->CloseProtocol ( - HttpService->TcpChildHandle, - &gEfiTcp4ProtocolGuid, - gHttpDxeDriverBinding.DriverBindingHandle, - ChildHandle - ); - HttpInstance->InDestroy = TRUE; // @@ -706,11 +1050,11 @@ HttpServiceBindingDestroyChild ( HttpInstance->InDestroy = FALSE; return Status; } - - OldTpl = gBS->RaiseTPL (TPL_CALLBACK); - + HttpCleanProtocol (HttpInstance); - + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + RemoveEntryList (&HttpInstance->Link); HttpService->ChildrenNumber--; diff --git a/NetworkPkg/HttpDxe/HttpDriver.h b/NetworkPkg/HttpDxe/HttpDriver.h index eea8d5169e..8fda6b2be4 100644 --- a/NetworkPkg/HttpDxe/HttpDriver.h +++ b/NetworkPkg/HttpDxe/HttpDriver.h @@ -43,8 +43,12 @@ // #include #include +#include #include +#include #include +#include + // // Produced Protocols @@ -59,7 +63,9 @@ // // Protocol instances // -extern EFI_DRIVER_BINDING_PROTOCOL gHttpDxeDriverBinding; +extern EFI_DRIVER_BINDING_PROTOCOL gHttpDxeIp4DriverBinding; +extern EFI_DRIVER_BINDING_PROTOCOL gHttpDxeIp6DriverBinding; + extern EFI_COMPONENT_NAME2_PROTOCOL gHttpDxeComponentName2; extern EFI_COMPONENT_NAME_PROTOCOL gHttpDxeComponentName; @@ -123,7 +129,7 @@ typedef struct { **/ EFI_STATUS EFIAPI -HttpDxeDriverBindingSupported ( +HttpDxeIp4DriverBindingSupported ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL @@ -166,7 +172,7 @@ HttpDxeDriverBindingSupported ( **/ EFI_STATUS EFIAPI -HttpDxeDriverBindingStart ( +HttpDxeIp4DriverBindingStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL @@ -200,13 +206,142 @@ HttpDxeDriverBindingStart ( **/ EFI_STATUS EFIAPI -HttpDxeDriverBindingStop ( +HttpDxeIp4DriverBindingStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer OPTIONAL ); +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. + + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Because ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +HttpDxeIp6DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Starts a device controller or a bus controller. + + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned + EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified by This must + have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child handle is created by this + driver. + + @retval EFI_SUCCESS The device was started. + @retval EFI_ALREADY_STARTED This device is already running on ControllerHandle. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +HttpDxeIp6DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Stops a device controller or a bus controller. + + The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed, or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + +**/ +EFI_STATUS +EFIAPI +HttpDxeIp6DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ); + /** Creates a child handle and installs a protocol. diff --git a/NetworkPkg/HttpDxe/HttpDxe.inf b/NetworkPkg/HttpDxe/HttpDxe.inf index 0d3bd00cf7..bf2cbee5f7 100644 --- a/NetworkPkg/HttpDxe/HttpDxe.inf +++ b/NetworkPkg/HttpDxe/HttpDxe.inf @@ -56,9 +56,14 @@ gEfiHttpUtilitiesProtocolGuid ## CONSUMES gEfiTcp4ServiceBindingProtocolGuid ## TO_START gEfiTcp4ProtocolGuid ## TO_START + gEfiTcp6ServiceBindingProtocolGuid ## TO_START + gEfiTcp6ProtocolGuid ## TO_START gEfiDns4ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES gEfiDns4ProtocolGuid ## SOMETIMES_CONSUMES + gEfiDns6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES + gEfiDns6ProtocolGuid ## SOMETIMES_CONSUMES gEfiIp4Config2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiIp6ConfigProtocolGuid ## SOMETIMES_CONSUMES [UserExtensions.TianoCore."ExtraFiles"] HttpDxeExtra.uni \ No newline at end of file diff --git a/NetworkPkg/HttpDxe/HttpDxe.uni b/NetworkPkg/HttpDxe/HttpDxe.uni index f9c2ac812e..d6792dd41e 100644 Binary files a/NetworkPkg/HttpDxe/HttpDxe.uni and b/NetworkPkg/HttpDxe/HttpDxe.uni differ diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c index f1e3e53411..c527da0872 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.c +++ b/NetworkPkg/HttpDxe/HttpImpl.c @@ -51,6 +51,8 @@ EfiHttpGetModeData ( ) { HTTP_PROTOCOL *HttpInstance; + EFI_HTTPv4_ACCESS_POINT *Http4AccessPoint; + EFI_HTTPv6_ACCESS_POINT *Http6AccessPoint; if ((This == NULL) || (HttpConfigData == NULL)) { return EFI_INVALID_PARAMETER; @@ -58,24 +60,32 @@ EfiHttpGetModeData ( HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This); ASSERT (HttpInstance != NULL); - + if (HttpInstance->State < HTTP_STATE_HTTP_CONFIGED) { return EFI_NOT_STARTED; } - if (HttpConfigData->AccessPoint.IPv4Node == NULL) { - return EFI_INVALID_PARAMETER; - } - HttpConfigData->HttpVersion = HttpInstance->HttpVersion; HttpConfigData->TimeOutMillisec = HttpInstance->TimeOutMillisec; HttpConfigData->LocalAddressIsIPv6 = HttpInstance->LocalAddressIsIPv6; - CopyMem ( - HttpConfigData->AccessPoint.IPv4Node, - &HttpInstance->IPv4Node, - sizeof (HttpInstance->IPv4Node) + if (HttpInstance->LocalAddressIsIPv6) { + Http6AccessPoint = AllocateZeroPool (sizeof (EFI_HTTPv6_ACCESS_POINT)); + CopyMem ( + Http6AccessPoint, + &HttpInstance->Ipv6Node, + sizeof (HttpInstance->Ipv6Node) ); + HttpConfigData->AccessPoint.IPv6Node = Http6AccessPoint; + } else { + Http4AccessPoint = AllocateZeroPool (sizeof (EFI_HTTPv4_ACCESS_POINT)); + CopyMem ( + Http4AccessPoint, + &HttpInstance->IPv4Node, + sizeof (HttpInstance->IPv4Node) + ); + HttpConfigData->AccessPoint.IPv4Node = Http4AccessPoint; + } return EFI_SUCCESS; } @@ -120,8 +130,13 @@ EfiHttpConfigure ( { HTTP_PROTOCOL *HttpInstance; EFI_STATUS Status; - - if (This == NULL) { + + // + // Check input parameters. + // + if (This == NULL || + (HttpConfigData != NULL && ((HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) || + (!HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL)))) { return EFI_INVALID_PARAMETER; } @@ -129,18 +144,7 @@ EfiHttpConfigure ( ASSERT (HttpInstance != NULL && HttpInstance->Service != NULL); if (HttpConfigData != NULL) { - // - // Check input parameters. - // - if (HttpConfigData->LocalAddressIsIPv6) { - if (HttpConfigData->AccessPoint.IPv6Node == NULL) { - return EFI_INVALID_PARAMETER; - } - } else { - if (HttpConfigData->AccessPoint.IPv4Node == NULL) { - return EFI_INVALID_PARAMETER; - } - } + // // Now configure this HTTP instance. // @@ -151,33 +155,38 @@ EfiHttpConfigure ( HttpInstance->HttpVersion = HttpConfigData->HttpVersion; HttpInstance->TimeOutMillisec = HttpConfigData->TimeOutMillisec; HttpInstance->LocalAddressIsIPv6 = HttpConfigData->LocalAddressIsIPv6; - - if (HttpConfigData->LocalAddressIsIPv6) { - return EFI_UNSUPPORTED; + + if (HttpConfigData->LocalAddressIsIPv6) { + CopyMem ( + &HttpInstance->Ipv6Node, + HttpConfigData->AccessPoint.IPv6Node, + sizeof (HttpInstance->Ipv6Node) + ); } else { CopyMem ( &HttpInstance->IPv4Node, HttpConfigData->AccessPoint.IPv4Node, sizeof (HttpInstance->IPv4Node) ); - - HttpInstance->State = HTTP_STATE_HTTP_CONFIGED; - return EFI_SUCCESS; } + // + // Creat Tcp child + // + Status = HttpInitProtocol (HttpInstance, HttpInstance->LocalAddressIsIPv6); + if (EFI_ERROR (Status)) { + return Status; + } + + HttpInstance->State = HTTP_STATE_HTTP_CONFIGED; + return EFI_SUCCESS; } else { - if (HttpInstance->LocalAddressIsIPv6) { - return EFI_UNSUPPORTED; - } else { - HttpCleanProtocol (HttpInstance); - Status = HttpInitProtocol (HttpInstance->Service, HttpInstance); - if (EFI_ERROR (Status)) { - return Status; - } - - HttpInstance->State = HTTP_STATE_UNCONFIGED; - return EFI_SUCCESS; - } + // + // Reset all the resources related to HttpInsance. + // + HttpCleanProtocol (HttpInstance); + HttpInstance->State = HTTP_STATE_UNCONFIGED; + return EFI_SUCCESS; } } @@ -264,10 +273,6 @@ EfiHttpRequest ( return EFI_NOT_STARTED; } - if (HttpInstance->LocalAddressIsIPv6) { - return EFI_UNSUPPORTED; - } - // // Check whether the token already existed. // @@ -291,7 +296,8 @@ EfiHttpRequest ( } FreePool (HttpInstance->Url); HttpInstance->Url = Url; - } + } + UnicodeStrToAsciiStr (Request->Url, Url); UrlParser = NULL; @@ -340,7 +346,7 @@ EfiHttpRequest ( Wrap->HttpToken = Token; Wrap->HttpInstance = HttpInstance; - Status = HttpCreateTcp4TxEvent (Wrap); + Status = HttpCreateTcpTxEvent (Wrap); if (EFI_ERROR (Status)) { goto Error1; } @@ -379,24 +385,35 @@ EfiHttpRequest ( if (Configure) { // - // Parse Url for IPv4 address, if failed, perform DNS resolution. + // Parse Url for IPv4 or IPv6 address, if failed, perform DNS resolution. // - Status = NetLibAsciiStrToIp4 (HostName, &HttpInstance->RemoteAddr); + if (!HttpInstance->LocalAddressIsIPv6) { + Status = NetLibAsciiStrToIp4 (HostName, &HttpInstance->RemoteAddr); + } else { + Status = NetLibAsciiStrToIp6 (HostName, &HttpInstance->RemoteIpv6Addr); + } + if (EFI_ERROR (Status)) { - HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (UINT16)); + HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (CHAR16)); if (HostNameStr == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error1; } - + AsciiStrToUnicodeStr (HostName, HostNameStr); - Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr); + if (!HttpInstance->LocalAddressIsIPv6) { + Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr); + } else { + Status = HttpDns6 (HttpInstance, HostNameStr, &HttpInstance->RemoteIpv6Addr); + } + FreePool (HostNameStr); if (EFI_ERROR (Status)) { goto Error1; } } + // // Save the RemotePort and RemoteHost. // @@ -410,7 +427,7 @@ EfiHttpRequest ( // // The request URL is different from previous calls to Request(), close existing TCP instance. // - ASSERT (HttpInstance->Tcp4 != NULL); + ASSERT (HttpInstance->Tcp4 != NULL &&HttpInstance->Tcp6 != NULL); HttpCloseConnection (HttpInstance); EfiHttpCancel (This, NULL); } @@ -429,25 +446,16 @@ EfiHttpRequest ( Wrap->TcpWrap.Method = Request->Method; if (Configure) { - // - // Configure TCP instance. - // - Status = HttpConfigureTcp4 (HttpInstance, Wrap); - if (EFI_ERROR (Status)) { - goto Error1; - } - // - // Connect TCP. - // - Status = HttpConnectTcp4 (HttpInstance); + Status = HttpInitTcp (HttpInstance, Wrap); if (EFI_ERROR (Status)) { goto Error2; } + } else { // // For the new HTTP token, create TX TCP token events. // - Status = HttpCreateTcp4TxEvent (Wrap); + Status = HttpCreateTcpTxEvent (Wrap); if (EFI_ERROR (Status)) { goto Error1; } @@ -488,7 +496,7 @@ EfiHttpRequest ( // // Transmit the request message. // - Status = HttpTransmitTcp4 ( + Status = HttpTransmitTcp ( HttpInstance, Wrap, (UINT8*) RequestStr, @@ -499,11 +507,11 @@ EfiHttpRequest ( } DispatchDpc (); - + if (HostName != NULL) { FreePool (HostName); } - + return EFI_SUCCESS; Error5: @@ -517,15 +525,19 @@ Error4: Error3: HttpCloseConnection (HttpInstance); - Error2: - HttpCloseTcp4ConnCloseEvent (HttpInstance); - if (NULL != Wrap->TcpWrap.TxToken.CompletionToken.Event) { - gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event); - Wrap->TcpWrap.TxToken.CompletionToken.Event = NULL; + HttpCloseTcpConnCloseEvent (HttpInstance); + if (NULL != Wrap->TcpWrap.Tx4Token.CompletionToken.Event) { + gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event); + Wrap->TcpWrap.Tx4Token.CompletionToken.Event = NULL; + } + if (NULL != Wrap->TcpWrap.Tx6Token.CompletionToken.Event) { + gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event); + Wrap->TcpWrap.Tx6Token.CompletionToken.Event = NULL; } Error1: + if (HostName != NULL) { FreePool (HostName); } @@ -541,7 +553,7 @@ Error1: } /** - Cancel a TxToken or RxToken. + Cancel a user's Token. @param[in] Map The HTTP instance's token queue. @param[in] Item Object container for one HTTP token and token's wrap. @@ -562,6 +574,7 @@ HttpCancelTokens ( EFI_HTTP_TOKEN *Token; HTTP_TOKEN_WRAP *Wrap; + HTTP_PROTOCOL *HttpInstance; Token = (EFI_HTTP_TOKEN *) Context; @@ -575,24 +588,41 @@ HttpCancelTokens ( Wrap = (HTTP_TOKEN_WRAP *) Item->Value; ASSERT (Wrap != NULL); + HttpInstance = Wrap->HttpInstance; // // Free resources. // NetMapRemoveItem (Map, Item, NULL); - if (Wrap->TcpWrap.TxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event); - } + if (!HttpInstance->LocalAddressIsIPv6) { + if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event); + } + + if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); + } + + if (Wrap->TcpWrap.Rx4Token.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Wrap->TcpWrap.Rx4Token.Packet.RxData->FragmentTable[0].FragmentBuffer); + } - if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event); - } + } else { + if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event); + } + + if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); + } - if (Wrap->TcpWrap.RxToken.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { - FreePool (Wrap->TcpWrap.RxToken.Packet.RxData->FragmentTable[0].FragmentBuffer); + if (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer); + } } + FreePool (Wrap); // @@ -747,7 +777,7 @@ HttpBodyParserCallback ( Wrap->HttpInstance->NextMsg = Data; // - // Free TxToken since already received corrsponding HTTP response. + // Free Tx4Token or Tx6Token since already received corrsponding HTTP response. // FreePool (Wrap); @@ -761,7 +791,7 @@ HttpBodyParserCallback ( @retval EFI_SUCCESS Allocation succeeded. @retval EFI_OUT_OF_RESOURCES Failed to complete the opration due to lack of resources. - @retval EFI_NOT_READY Can't find a corresponding TxToken or + @retval EFI_NOT_READY Can't find a corresponding Tx4Token/Tx6Token or the EFI_HTTP_UTILITIES_PROTOCOL is not available. **/ @@ -772,12 +802,9 @@ HttpResponseWorker ( { EFI_STATUS Status; EFI_HTTP_MESSAGE *HttpMsg; - EFI_TCP4_IO_TOKEN *RxToken; - EFI_TCP4_PROTOCOL *Tcp4; CHAR8 *EndofHeader; CHAR8 *HttpHeaders; UINTN SizeofHeaders; - CHAR8 *Buffer; UINTN BufferSize; UINTN StatusCode; CHAR8 *Tmp; @@ -796,23 +823,21 @@ HttpResponseWorker ( HttpInstance = Wrap->HttpInstance; Token = Wrap->HttpToken; - HttpMsg = Token->Message; - Tcp4 = HttpInstance->Tcp4; - ASSERT (Tcp4 != NULL); - HttpMsg->Headers = NULL; - HttpHeaders = NULL; - SizeofHeaders = 0; - Buffer = NULL; - BufferSize = 0; - EndofHeader = NULL; + HttpInstance->EndofHeader = NULL; + HttpInstance->HttpHeaders = NULL; + HttpMsg->Headers = NULL; + HttpHeaders = NULL; + SizeofHeaders = 0; + BufferSize = 0; + EndofHeader = NULL; if (HttpMsg->Data.Response != NULL) { // // Need receive the HTTP headers, prepare buffer. // - Status = HttpCreateTcp4RxEventForHeader (HttpInstance); + Status = HttpCreateTcpRxEventForHeader (HttpInstance); if (EFI_ERROR (Status)) { goto Error; } @@ -843,70 +868,15 @@ HttpResponseWorker ( // Check whether we cached the whole HTTP headers. // EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR); - } - - RxToken = &HttpInstance->RxToken; - RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN); - if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Error; - } - - // - // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL. - // - while (EndofHeader == NULL) { - HttpInstance->IsRxDone = FALSE; - RxToken->Packet.RxData->DataLength = DEF_BUF_LEN; - RxToken->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN; - Status = Tcp4->Receive (Tcp4, RxToken); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status)); - goto Error; - } - - while (!HttpInstance->IsRxDone) { - Tcp4->Poll (Tcp4); - } - - Status = RxToken->CompletionToken.Status; - if (EFI_ERROR (Status)) { - goto Error; - } - - // - // Append the response string. - // - BufferSize = SizeofHeaders + RxToken->Packet.RxData->FragmentTable[0].FragmentLength; - Buffer = AllocateZeroPool (BufferSize); - if (Buffer == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Error; - } - - if (HttpHeaders != NULL) { - CopyMem (Buffer, HttpHeaders, SizeofHeaders); - FreePool (HttpHeaders); - } - - CopyMem ( - Buffer + SizeofHeaders, - RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer, - RxToken->Packet.RxData->FragmentTable[0].FragmentLength - ); - HttpHeaders = Buffer; - SizeofHeaders = BufferSize; + } - // - // Check whether we received end of HTTP headers. - // - EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR); - }; + HttpInstance->EndofHeader = &EndofHeader; + HttpInstance->HttpHeaders = &HttpHeaders; - // - // Skip the CRLF after the HTTP headers. - // - EndofHeader = EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR); + Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize); + if (EFI_ERROR (Status)) { + goto Error; + } // // Cache the part of body. @@ -927,9 +897,6 @@ HttpResponseWorker ( HttpInstance->CacheLen = BodyLen; } - FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer); - RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; - // // Search for Status Code. // @@ -997,7 +964,7 @@ HttpResponseWorker ( } // - // The first TxToken not transmitted yet, insert back and return error. + // The first Tx Token not transmitted yet, insert back and return error. // if (!ValueInItem->TcpWrap.IsTxDone) { goto Error2; @@ -1108,16 +1075,8 @@ HttpResponseWorker ( // // We still need receive more data when there is no cache data and MsgParser is not NULL; // - RxToken = &Wrap->TcpWrap.RxToken; - - RxToken->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength; - RxToken->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength; - RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body; - - RxToken->CompletionToken.Status = EFI_NOT_READY; - Status = Tcp4->Receive (Tcp4, RxToken); + Status = HttpTcpReceiveBody (Wrap, HttpMsg); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status)); goto Error; } @@ -1130,18 +1089,7 @@ Exit: } Token->Status = Status; gBS->SignalEvent (Token->Event); - - if (Wrap != NULL) { - if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event); - } - } - - if (HttpInstance->RxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (HttpInstance->RxToken.CompletionToken.Event); - HttpInstance->RxToken.CompletionToken.Event = NULL; - } - + HttpCloseTcpRxEvent (Wrap); FreePool (Wrap); return Status; @@ -1149,28 +1097,7 @@ Error2: NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem); Error: - if (Wrap != NULL) { - if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event); - } - RxToken = &Wrap->TcpWrap.RxToken; - if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { - FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer); - RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; - } - FreePool (Wrap); - } - - if (HttpInstance->RxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (HttpInstance->RxToken.CompletionToken.Event); - HttpInstance->RxToken.CompletionToken.Event = NULL; - } - - RxToken = &HttpInstance->RxToken; - if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { - FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer); - RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; - } + HttpTcpTokenCleanup (Wrap); if (HttpHeaders != NULL) { FreePool (HttpHeaders); @@ -1268,10 +1195,6 @@ EfiHttpResponse ( return EFI_NOT_STARTED; } - if (HttpInstance->LocalAddressIsIPv6) { - return EFI_UNSUPPORTED; - } - // // Check whether the token already existed. // @@ -1287,7 +1210,7 @@ EfiHttpResponse ( Wrap->HttpInstance = HttpInstance; Wrap->HttpToken = Token; - Status = HttpCreateTcp4RxEvent (Wrap); + Status = HttpCreateTcpRxEvent (Wrap); if (EFI_ERROR (Status)) { goto Error; } @@ -1308,8 +1231,12 @@ EfiHttpResponse ( Error: if (Wrap != NULL) { - if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event); + if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); + } + + if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); } FreePool (Wrap); } @@ -1343,8 +1270,8 @@ EfiHttpPoll ( IN EFI_HTTP_PROTOCOL *This ) { - HTTP_PROTOCOL *HttpInstance; EFI_STATUS Status; + HTTP_PROTOCOL *HttpInstance; if (This == NULL) { return EFI_INVALID_PARAMETER; @@ -1353,17 +1280,18 @@ EfiHttpPoll ( HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This); ASSERT (HttpInstance != NULL); - if (HttpInstance->LocalAddressIsIPv6) { - return EFI_UNSUPPORTED; - } - - if (HttpInstance->Tcp4 == NULL || HttpInstance->State != HTTP_STATE_TCP_CONNECTED) { + if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED || (HttpInstance->Tcp4 == NULL && + HttpInstance->Tcp6 == NULL)) { return EFI_NOT_STARTED; } - - Status = HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); - + + if (HttpInstance->LocalAddressIsIPv6) { + Status = HttpInstance->Tcp6->Poll (HttpInstance->Tcp6); + } else { + Status = HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); + } + DispatchDpc (); - + return Status; } diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c index 57ea207389..39837a3c82 100644 --- a/NetworkPkg/HttpDxe/HttpProto.c +++ b/NetworkPkg/HttpDxe/HttpProto.c @@ -37,7 +37,7 @@ HttpCommonNotify ( } /** - The notify function associated with TxToken for Tcp4->Transmit(). + The notify function associated with Tx4Token for Tcp4->Transmit() or Tx6Token for Tcp6->Transmit(). @param[in] Context The context. @@ -49,25 +49,46 @@ HttpTcpTransmitNotifyDpc ( ) { HTTP_TOKEN_WRAP *Wrap; + HTTP_PROTOCOL *HttpInstance; if (Context == NULL) { return ; } + + Wrap = (HTTP_TOKEN_WRAP *) Context; + HttpInstance = Wrap->HttpInstance; + + if (!HttpInstance->LocalAddressIsIPv6) { + Wrap->HttpToken->Status = Wrap->TcpWrap.Tx4Token.CompletionToken.Status; + gBS->SignalEvent (Wrap->HttpToken->Event); + + // + // Free resources. + // + if (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer); + } - Wrap = (HTTP_TOKEN_WRAP *) Context; - Wrap->HttpToken->Status = Wrap->TcpWrap.TxToken.CompletionToken.Status; - gBS->SignalEvent (Wrap->HttpToken->Event); + if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event); + } + + } else { + Wrap->HttpToken->Status = Wrap->TcpWrap.Tx6Token.CompletionToken.Status; + gBS->SignalEvent (Wrap->HttpToken->Event); + + // + // Free resources. + // + if (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer); + } - // - // Free resources. - // - if (Wrap->TcpWrap.TxToken.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) { - FreePool (Wrap->TcpWrap.TxToken.Packet.TxData->FragmentTable[0].FragmentBuffer); + if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event); + } } - if (Wrap->TcpWrap.TxToken.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.TxToken.CompletionToken.Event); - } Wrap->TcpWrap.IsTxDone = TRUE; @@ -98,9 +119,8 @@ HttpTcpTransmitNotify ( QueueDpc (TPL_CALLBACK, HttpTcpTransmitNotifyDpc, Context); } - /** - The notify function associated with RxToken for Tcp4->Receive (). + The notify function associated with Rx4Token for Tcp4->Receive () or Rx6Token for Tcp6->Receive(). @param[in] Context The context. @@ -116,25 +136,41 @@ HttpTcpReceiveNotifyDpc ( UINTN Length; EFI_STATUS Status; HTTP_PROTOCOL *HttpInstance; + BOOLEAN UsingIpv6; if (Context == NULL) { return ; } Wrap = (HTTP_TOKEN_WRAP *) Context; - gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event); - if (EFI_ERROR (Wrap->TcpWrap.RxToken.CompletionToken.Status)) { - return ; - } - HttpInstance = Wrap->HttpInstance; + UsingIpv6 = HttpInstance->LocalAddressIsIPv6; + + if (UsingIpv6) { + gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); + + if (EFI_ERROR (Wrap->TcpWrap.Rx6Token.CompletionToken.Status)) { + return ; + } + + } else { + gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); + + if (EFI_ERROR (Wrap->TcpWrap.Rx4Token.CompletionToken.Status)) { + return ; + } + } // // Check whether we receive a complete HTTP message. // ASSERT (HttpInstance->MsgParser != NULL); + if (UsingIpv6) { + Length = (UINTN) Wrap->TcpWrap.Rx6Data.FragmentTable[0].FragmentLength; + } else { + Length = (UINTN) Wrap->TcpWrap.Rx4Data.FragmentTable[0].FragmentLength; + } - Length = (UINTN) Wrap->TcpWrap.RxData.FragmentTable[0].FragmentLength; Status = HttpParseMessageBody ( HttpInstance->MsgParser, Length, @@ -179,7 +215,12 @@ HttpTcpReceiveNotifyDpc ( Wrap->TcpWrap.IsRxDone = TRUE; - Wrap->HttpToken->Status = Wrap->TcpWrap.RxToken.CompletionToken.Status; + if (UsingIpv6) { + Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status; + } else { + Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status; + } + gBS->SignalEvent (Wrap->HttpToken->Event); @@ -211,9 +252,8 @@ HttpTcpReceiveNotify ( QueueDpc (TPL_CALLBACK, HttpTcpReceiveNotifyDpc, Context); } - /** - Create events for the TCP4 connection token and TCP4 close token. + Create events for the TCP connection token and TCP close token. @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure. @@ -222,11 +262,13 @@ HttpTcpReceiveNotify ( **/ EFI_STATUS -HttpCreateTcp4ConnCloseEvent ( +HttpCreateTcpConnCloseEvent ( IN HTTP_PROTOCOL *HttpInstance ) { EFI_STATUS Status; + + if (!HttpInstance->LocalAddressIsIPv6) { // // Create events for variuos asynchronous operations. // @@ -234,66 +276,109 @@ HttpCreateTcp4ConnCloseEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, HttpCommonNotify, - &HttpInstance->IsConnDone, - &HttpInstance->ConnToken.CompletionToken.Event + &HttpInstance->IsTcp4ConnDone, + &HttpInstance->Tcp4ConnToken.CompletionToken.Event ); if (EFI_ERROR (Status)) { goto ERROR; } // - // Initialize CloseToken + // Initialize Tcp4CloseToken + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpCommonNotify, + &HttpInstance->IsTcp4CloseDone, + &HttpInstance->Tcp4CloseToken.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + goto ERROR; + } + + } else { + // + // Create events for variuos asynchronous operations. // Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, HttpCommonNotify, - &HttpInstance->IsCloseDone, - &HttpInstance->CloseToken.CompletionToken.Event + &HttpInstance->IsTcp6ConnDone, + &HttpInstance->Tcp6ConnToken.CompletionToken.Event ); if (EFI_ERROR (Status)) { goto ERROR; } - + // + // Initialize Tcp6CloseToken + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpCommonNotify, + &HttpInstance->IsTcp6CloseDone, + &HttpInstance->Tcp6CloseToken.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + goto ERROR; + } + } + return EFI_SUCCESS; ERROR: // // Error handling // - HttpCloseTcp4ConnCloseEvent (HttpInstance); + HttpCloseTcpConnCloseEvent (HttpInstance); return Status; } /** - Close events in the TCP4 connection token and TCP4 close token. + Close events in the TCP connection token and TCP close token. @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure. **/ VOID -HttpCloseTcp4ConnCloseEvent ( +HttpCloseTcpConnCloseEvent ( IN HTTP_PROTOCOL *HttpInstance ) { ASSERT (HttpInstance != NULL); - if (NULL != HttpInstance->ConnToken.CompletionToken.Event) { - gBS->CloseEvent (HttpInstance->ConnToken.CompletionToken.Event); - HttpInstance->ConnToken.CompletionToken.Event = NULL; - } + if (HttpInstance->LocalAddressIsIPv6) { + if (NULL != HttpInstance->Tcp6ConnToken.CompletionToken.Event) { + gBS->CloseEvent (HttpInstance->Tcp6ConnToken.CompletionToken.Event); + HttpInstance->Tcp6ConnToken.CompletionToken.Event = NULL; + } - if (NULL != HttpInstance->CloseToken.CompletionToken.Event) { - gBS->CloseEvent(HttpInstance->CloseToken.CompletionToken.Event); - HttpInstance->CloseToken.CompletionToken.Event = NULL; - } + if (NULL != HttpInstance->Tcp6CloseToken.CompletionToken.Event) { + gBS->CloseEvent(HttpInstance->Tcp6CloseToken.CompletionToken.Event); + HttpInstance->Tcp6CloseToken.CompletionToken.Event = NULL; + } + + } else { + if (NULL != HttpInstance->Tcp4ConnToken.CompletionToken.Event) { + gBS->CloseEvent (HttpInstance->Tcp4ConnToken.CompletionToken.Event); + HttpInstance->Tcp4ConnToken.CompletionToken.Event = NULL; + } + + if (NULL != HttpInstance->Tcp4CloseToken.CompletionToken.Event) { + gBS->CloseEvent(HttpInstance->Tcp4CloseToken.CompletionToken.Event); + HttpInstance->Tcp4CloseToken.CompletionToken.Event = NULL; + } + } + } /** - Create event for the TCP4 transmit token. + Create event for the TCP transmit token. @param[in] Wrap Point to HTTP token's wrap data. @@ -302,37 +387,61 @@ HttpCloseTcp4ConnCloseEvent ( **/ EFI_STATUS -HttpCreateTcp4TxEvent ( +HttpCreateTcpTxEvent ( IN HTTP_TOKEN_WRAP *Wrap ) { EFI_STATUS Status; + HTTP_PROTOCOL *HttpInstance; HTTP_TCP_TOKEN_WRAP *TcpWrap; + HttpInstance = Wrap->HttpInstance; TcpWrap = &Wrap->TcpWrap; - Status = gBS->CreateEvent ( - EVT_NOTIFY_SIGNAL, - TPL_NOTIFY, - HttpTcpTransmitNotify, - Wrap, - &TcpWrap->TxToken.CompletionToken.Event - ); - if (EFI_ERROR (Status)) { - return Status; - } + if (!HttpInstance->LocalAddressIsIPv6) { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpTcpTransmitNotify, + Wrap, + &TcpWrap->Tx4Token.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + + TcpWrap->Tx4Data.Push = TRUE; + TcpWrap->Tx4Data.Urgent = FALSE; + TcpWrap->Tx4Data.FragmentCount = 1; + TcpWrap->Tx4Token.Packet.TxData = &Wrap->TcpWrap.Tx4Data; + TcpWrap->Tx4Token.CompletionToken.Status = EFI_NOT_READY; - TcpWrap->TxData.Push = TRUE; - TcpWrap->TxData.Urgent = FALSE; - TcpWrap->TxData.FragmentCount = 1; - TcpWrap->TxToken.Packet.TxData = &Wrap->TcpWrap.TxData; - TcpWrap->TxToken.CompletionToken.Status = EFI_NOT_READY; + } else { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpTcpTransmitNotify, + Wrap, + &TcpWrap->Tx6Token.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + TcpWrap->Tx6Data.Push = TRUE; + TcpWrap->Tx6Data.Urgent = FALSE; + TcpWrap->Tx6Data.FragmentCount = 1; + TcpWrap->Tx6Token.Packet.TxData = &Wrap->TcpWrap.Tx6Data; + TcpWrap->Tx6Token.CompletionToken.Status =EFI_NOT_READY; + + + } + return EFI_SUCCESS; } /** - Create event for the TCP4 receive token which is used to receive HTTP header. + Create event for the TCP receive token which is used to receive HTTP header. @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure. @@ -341,33 +450,52 @@ HttpCreateTcp4TxEvent ( **/ EFI_STATUS -HttpCreateTcp4RxEventForHeader ( +HttpCreateTcpRxEventForHeader ( IN HTTP_PROTOCOL *HttpInstance ) { EFI_STATUS Status; + if (!HttpInstance->LocalAddressIsIPv6) { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpCommonNotify, + &HttpInstance->IsRxDone, + &HttpInstance->Rx4Token.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + + HttpInstance->Rx4Data.FragmentCount = 1; + HttpInstance->Rx4Token.Packet.RxData = &HttpInstance->Rx4Data; + HttpInstance->Rx4Token.CompletionToken.Status = EFI_NOT_READY; - Status = gBS->CreateEvent ( - EVT_NOTIFY_SIGNAL, - TPL_NOTIFY, - HttpCommonNotify, - &HttpInstance->IsRxDone, - &HttpInstance->RxToken.CompletionToken.Event - ); - if (EFI_ERROR (Status)) { - return Status; + } else { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpCommonNotify, + &HttpInstance->IsRxDone, + &HttpInstance->Rx6Token.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + + HttpInstance->Rx6Data.FragmentCount =1; + HttpInstance->Rx6Token.Packet.RxData = &HttpInstance->Rx6Data; + HttpInstance->Rx6Token.CompletionToken.Status = EFI_NOT_READY; + } - HttpInstance->RxData.FragmentCount = 1; - HttpInstance->RxToken.Packet.RxData = &HttpInstance->RxData; - HttpInstance->RxToken.CompletionToken.Status = EFI_NOT_READY; return EFI_SUCCESS; } /** - Create event for the TCP4 receive token which is used to receive HTTP body. + Create event for the TCP receive token which is used to receive HTTP body. @param[in] Wrap Point to HTTP token's wrap data. @@ -376,38 +504,101 @@ HttpCreateTcp4RxEventForHeader ( **/ EFI_STATUS -HttpCreateTcp4RxEvent ( +HttpCreateTcpRxEvent ( IN HTTP_TOKEN_WRAP *Wrap ) { EFI_STATUS Status; + HTTP_PROTOCOL *HttpInstance; HTTP_TCP_TOKEN_WRAP *TcpWrap; + HttpInstance = Wrap->HttpInstance; TcpWrap = &Wrap->TcpWrap; + if (!HttpInstance->LocalAddressIsIPv6) { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpTcpReceiveNotify, + Wrap, + &TcpWrap->Rx4Token.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + + TcpWrap->Rx4Data.FragmentCount = 1; + TcpWrap->Rx4Token.Packet.RxData = &Wrap->TcpWrap.Rx4Data; + TcpWrap->Rx4Token.CompletionToken.Status = EFI_NOT_READY; - Status = gBS->CreateEvent ( - EVT_NOTIFY_SIGNAL, - TPL_NOTIFY, - HttpTcpReceiveNotify, - Wrap, - &TcpWrap->RxToken.CompletionToken.Event - ); - if (EFI_ERROR (Status)) { - return Status; + } else { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + HttpTcpReceiveNotify, + Wrap, + &TcpWrap->Rx6Token.CompletionToken.Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + + TcpWrap->Rx6Data.FragmentCount = 1; + TcpWrap->Rx6Token.Packet.RxData = &Wrap->TcpWrap.Rx6Data; + TcpWrap->Rx6Token.CompletionToken.Status = EFI_NOT_READY; } + + return EFI_SUCCESS; +} - TcpWrap->RxData.FragmentCount = 1; - TcpWrap->RxToken.Packet.RxData = &Wrap->TcpWrap.RxData; - TcpWrap->RxToken.CompletionToken.Status = EFI_NOT_READY; +/** + Close Events for Tcp Receive Tokens for HTTP body and HTTP header. - return EFI_SUCCESS; + @param[in] Wrap Pointer to HTTP token's wrap data. + +**/ +VOID +HttpCloseTcpRxEvent ( + IN HTTP_TOKEN_WRAP *Wrap + ) +{ + HTTP_PROTOCOL *HttpInstance; + EFI_TCP4_IO_TOKEN *Rx4Token; + EFI_TCP6_IO_TOKEN *Rx6Token; + + HttpInstance = Wrap->HttpInstance; + Rx4Token = NULL; + Rx6Token = NULL; + + if (HttpInstance->LocalAddressIsIPv6) { + if (Wrap != NULL) { + if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); + } + } + + if (HttpInstance->Rx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (HttpInstance->Rx6Token.CompletionToken.Event); + HttpInstance->Rx6Token.CompletionToken.Event = NULL; + } + } else { + if (Wrap != NULL) { + if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); + } + } + + if (HttpInstance->Rx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (HttpInstance->Rx4Token.CompletionToken.Event); + HttpInstance->Rx4Token.CompletionToken.Event = NULL; + } + } } /** Intiialize the HTTP_PROTOCOL structure to the unconfigured state. - @param[in] HttpSb The HTTP service private instance. @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure. + @param[in] IpVersion Indicate us TCP4 protocol or TCP6 protocol. @retval EFI_SUCCESS HTTP_PROTOCOL structure is initialized successfully. @retval Others Other error as indicated. @@ -415,95 +606,198 @@ HttpCreateTcp4RxEvent ( **/ EFI_STATUS HttpInitProtocol ( - IN HTTP_SERVICE *HttpSb, - IN OUT HTTP_PROTOCOL *HttpInstance + IN OUT HTTP_PROTOCOL *HttpInstance, + IN BOOLEAN IpVersion ) { EFI_STATUS Status; VOID *Interface; + BOOLEAN UsingIpv6; + + ASSERT (HttpInstance != NULL); + UsingIpv6 = IpVersion; + + if (!UsingIpv6) { + // + // Create TCP4 child. + // + Status = NetLibCreateServiceChild ( + HttpInstance->Service->ControllerHandle, + HttpInstance->Service->ImageHandle, + &gEfiTcp4ServiceBindingProtocolGuid, + &HttpInstance->Tcp4ChildHandle + ); - ASSERT ((HttpSb != NULL) && (HttpInstance != NULL)); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - HttpInstance->Signature = HTTP_PROTOCOL_SIGNATURE; - CopyMem (&HttpInstance->Http, &mEfiHttpTemplate, sizeof (HttpInstance->Http)); - HttpInstance->Service = HttpSb; + Status = gBS->OpenProtocol ( + HttpInstance->Tcp4ChildHandle, + &gEfiTcp4ProtocolGuid, + (VOID **) &Interface, + HttpInstance->Service->ImageHandle, + HttpInstance->Service->ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - // - // Create TCP child. - // - Status = NetLibCreateServiceChild ( - HttpInstance->Service->ControllerHandle, - HttpInstance->Service->ImageHandle, - &gEfiTcp4ServiceBindingProtocolGuid, - &HttpInstance->TcpChildHandle - ); + Status = gBS->OpenProtocol ( + HttpInstance->Tcp4ChildHandle, + &gEfiTcp4ProtocolGuid, + (VOID **) &HttpInstance->Tcp4, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR(Status)) { + goto ON_ERROR; + } - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } + Status = gBS->OpenProtocol ( + HttpInstance->Service->Tcp4ChildHandle, + &gEfiTcp4ProtocolGuid, + (VOID **) &Interface, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR(Status)) { + goto ON_ERROR; + } + } else { + // + // Create TCP6 Child. + // + Status = NetLibCreateServiceChild ( + HttpInstance->Service->ControllerHandle, + HttpInstance->Service->ImageHandle, + &gEfiTcp6ServiceBindingProtocolGuid, + &HttpInstance->Tcp6ChildHandle + ); - Status = gBS->OpenProtocol ( - HttpInstance->TcpChildHandle, - &gEfiTcp4ProtocolGuid, - (VOID **) &Interface, - HttpInstance->Service->ImageHandle, - HttpInstance->Service->ControllerHandle, - EFI_OPEN_PROTOCOL_BY_DRIVER - ); - - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Status = gBS->OpenProtocol ( - HttpInstance->TcpChildHandle, - &gEfiTcp4ProtocolGuid, - (VOID **) &HttpInstance->Tcp4, - HttpInstance->Service->ImageHandle, - HttpInstance->Handle, - EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER - ); - if (EFI_ERROR(Status)) { - goto ON_ERROR; - } + Status = gBS->OpenProtocol ( + HttpInstance->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + (VOID **) &Interface, + HttpInstance->Service->ImageHandle, + HttpInstance->Service->ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status = gBS->OpenProtocol ( + HttpInstance->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + (VOID **) &HttpInstance->Tcp6, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + + if (EFI_ERROR(Status)) { + goto ON_ERROR; + } + + Status = gBS->OpenProtocol ( + HttpInstance->Service->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + (VOID **) &Interface, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR(Status)) { + goto ON_ERROR; + } + } + HttpInstance->Url = AllocateZeroPool (HTTP_URL_BUFFER_LEN); if (HttpInstance->Url == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ON_ERROR; } - NetMapInit (&HttpInstance->TxTokens); - NetMapInit (&HttpInstance->RxTokens); - return EFI_SUCCESS; ON_ERROR: - if (HttpInstance->TcpChildHandle != NULL) { + if (HttpInstance->Tcp4ChildHandle != NULL) { gBS->CloseProtocol ( - HttpInstance->TcpChildHandle, + HttpInstance->Tcp4ChildHandle, &gEfiTcp4ProtocolGuid, HttpInstance->Service->ImageHandle, HttpInstance->Service->ControllerHandle ); gBS->CloseProtocol ( - HttpInstance->TcpChildHandle, + HttpInstance->Tcp4ChildHandle, &gEfiTcp4ProtocolGuid, HttpInstance->Service->ImageHandle, HttpInstance->Handle - ); + ); NetLibDestroyServiceChild ( HttpInstance->Service->ControllerHandle, HttpInstance->Service->ImageHandle, &gEfiTcp4ServiceBindingProtocolGuid, - HttpInstance->TcpChildHandle + HttpInstance->Tcp4ChildHandle ); } + + if (HttpInstance->Service->Tcp4ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpInstance->Service->Tcp4ChildHandle, + &gEfiTcp4ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle + ); + } + + if (HttpInstance->Tcp6ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpInstance->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Service->ControllerHandle + ); - return Status; + gBS->CloseProtocol ( + HttpInstance->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle + ); + + NetLibDestroyServiceChild ( + HttpInstance->Service->ControllerHandle, + HttpInstance->Service->ImageHandle, + &gEfiTcp6ServiceBindingProtocolGuid, + HttpInstance->Tcp6ChildHandle + ); + } + + if (HttpInstance->Service->Tcp6ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpInstance->Service->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle + ); + } + + return EFI_UNSUPPORTED; } @@ -520,7 +814,7 @@ HttpCleanProtocol ( { HttpCloseConnection (HttpInstance); - HttpCloseTcp4ConnCloseEvent (HttpInstance); + HttpCloseTcpConnCloseEvent (HttpInstance); if (HttpInstance->CacheBody != NULL) { FreePool (HttpInstance->CacheBody); @@ -537,25 +831,25 @@ HttpCleanProtocol ( HttpFreeMsgParser (HttpInstance->MsgParser); HttpInstance->MsgParser = NULL; } - + if (HttpInstance->Url != NULL) { FreePool (HttpInstance->Url); HttpInstance->Url = NULL; } - + NetMapClean (&HttpInstance->TxTokens); NetMapClean (&HttpInstance->RxTokens); - if (HttpInstance->TcpChildHandle != NULL) { + if (HttpInstance->Tcp4ChildHandle != NULL) { gBS->CloseProtocol ( - HttpInstance->TcpChildHandle, + HttpInstance->Tcp4ChildHandle, &gEfiTcp4ProtocolGuid, HttpInstance->Service->ImageHandle, HttpInstance->Service->ControllerHandle ); gBS->CloseProtocol ( - HttpInstance->TcpChildHandle, + HttpInstance->Tcp4ChildHandle, &gEfiTcp4ProtocolGuid, HttpInstance->Service->ImageHandle, HttpInstance->Handle @@ -565,9 +859,51 @@ HttpCleanProtocol ( HttpInstance->Service->ControllerHandle, HttpInstance->Service->ImageHandle, &gEfiTcp4ServiceBindingProtocolGuid, - HttpInstance->TcpChildHandle + HttpInstance->Tcp4ChildHandle ); } + + if (HttpInstance->Service->Tcp4ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpInstance->Service->Tcp4ChildHandle, + &gEfiTcp4ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle + ); + } + + if (HttpInstance->Tcp6ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpInstance->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Service->ControllerHandle + ); + + gBS->CloseProtocol ( + HttpInstance->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle + ); + + NetLibDestroyServiceChild ( + HttpInstance->Service->ControllerHandle, + HttpInstance->Service->ImageHandle, + &gEfiTcp6ServiceBindingProtocolGuid, + HttpInstance->Tcp6ChildHandle + ); + } + + if (HttpInstance->Service->Tcp6ChildHandle != NULL) { + gBS->CloseProtocol ( + HttpInstance->Service->Tcp6ChildHandle, + &gEfiTcp6ProtocolGuid, + HttpInstance->Service->ImageHandle, + HttpInstance->Handle + ); + } + } /** @@ -586,27 +922,40 @@ HttpCreateConnection ( { EFI_STATUS Status; - // - // Create events for variuos asynchronous operations. - // - HttpInstance->IsConnDone = FALSE; - // // Connect to Http server // - HttpInstance->ConnToken.CompletionToken.Status = EFI_NOT_READY; - Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->ConnToken); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status)); - return Status; - } - - while (!HttpInstance->IsConnDone) { - HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); - } + if (!HttpInstance->LocalAddressIsIPv6) { + HttpInstance->IsTcp4ConnDone = FALSE; + HttpInstance->Tcp4ConnToken.CompletionToken.Status = EFI_NOT_READY; + Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->Tcp4ConnToken); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status)); + return Status; + } + + while (!HttpInstance->IsTcp4ConnDone) { + HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); + } + + Status = HttpInstance->Tcp4ConnToken.CompletionToken.Status; + + } else { + HttpInstance->IsTcp6ConnDone = FALSE; + HttpInstance->Tcp6ConnToken.CompletionToken.Status = EFI_NOT_READY; + Status = HttpInstance->Tcp6->Connect (HttpInstance->Tcp6, &HttpInstance->Tcp6ConnToken); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp6->Connect() = %r\n", Status)); + return Status; + } - Status = HttpInstance->ConnToken.CompletionToken.Status; + while(!HttpInstance->IsTcp6ConnDone) { + HttpInstance->Tcp6->Poll (HttpInstance->Tcp6); + } + Status = HttpInstance->Tcp6ConnToken.CompletionToken.Status; + } + if (!EFI_ERROR (Status)) { HttpInstance->State = HTTP_STATE_TCP_CONNECTED; } @@ -631,17 +980,32 @@ HttpCloseConnection ( EFI_STATUS Status; if (HttpInstance->State == HTTP_STATE_TCP_CONNECTED) { - HttpInstance->CloseToken.AbortOnClose = TRUE; - HttpInstance->IsCloseDone = FALSE; - - Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->CloseToken); - if (EFI_ERROR (Status)) { - return Status; - } - while (!HttpInstance->IsCloseDone) { - HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); + if (HttpInstance->LocalAddressIsIPv6) { + HttpInstance->Tcp6CloseToken.AbortOnClose = TRUE; + HttpInstance->IsTcp6CloseDone = FALSE; + Status = HttpInstance->Tcp6->Close (HttpInstance->Tcp6, &HttpInstance->Tcp6CloseToken); + if (EFI_ERROR (Status)) { + return Status; + } + + while (!HttpInstance->IsTcp6CloseDone) { + HttpInstance->Tcp6->Poll (HttpInstance->Tcp6); + } + + } else { + HttpInstance->Tcp4CloseToken.AbortOnClose = TRUE; + HttpInstance->IsTcp4CloseDone = FALSE; + Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->Tcp4CloseToken); + if (EFI_ERROR (Status)) { + return Status; + } + + while (!HttpInstance->IsTcp4CloseDone) { + HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); + } } + } HttpInstance->State = HTTP_STATE_TCP_CLOSED; @@ -710,12 +1074,82 @@ HttpConfigureTcp4 ( return Status; } - Status = HttpCreateTcp4ConnCloseEvent (HttpInstance); + Status = HttpCreateTcpConnCloseEvent (HttpInstance); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = HttpCreateTcpTxEvent (Wrap); + if (EFI_ERROR (Status)) { + return Status; + } + + HttpInstance->State = HTTP_STATE_TCP_CONFIGED; + + return EFI_SUCCESS; +} + +/** + Configure TCP6 protocol child. + + @param[in] HttpInstance The HTTP instance private data. + @param[in] Wrap The HTTP token's wrap data. + + @retval EFI_SUCCESS The TCP6 protocol child is configured. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpConfigureTcp6 ( + IN HTTP_PROTOCOL *HttpInstance, + IN HTTP_TOKEN_WRAP *Wrap + ) +{ + EFI_STATUS Status; + EFI_TCP6_CONFIG_DATA *Tcp6CfgData; + EFI_TCP6_ACCESS_POINT *Tcp6Ap; + EFI_TCP6_OPTION *Tcp6Option; + + ASSERT (HttpInstance != NULL); + + Tcp6CfgData = &HttpInstance->Tcp6CfgData; + ZeroMem (Tcp6CfgData, sizeof (EFI_TCP6_CONFIG_DATA)); + + Tcp6CfgData->TrafficClass = 0; + Tcp6CfgData->HopLimit = 255; + Tcp6CfgData->ControlOption = &HttpInstance->Tcp6Option; + + Tcp6Ap = &Tcp6CfgData->AccessPoint; + Tcp6Ap->ActiveFlag = TRUE; + Tcp6Ap->StationPort = HttpInstance->Ipv6Node.LocalPort; + Tcp6Ap->RemotePort = HttpInstance->RemotePort; + IP6_COPY_ADDRESS (&Tcp6Ap->StationAddress, &HttpInstance->Ipv6Node.LocalAddress); + IP6_COPY_ADDRESS (&Tcp6Ap->RemoteAddress , &HttpInstance->RemoteIpv6Addr); + + Tcp6Option = Tcp6CfgData->ControlOption; + Tcp6Option->ReceiveBufferSize = HTTP_BUFFER_SIZE_DEAULT; + Tcp6Option->SendBufferSize = HTTP_BUFFER_SIZE_DEAULT; + Tcp6Option->MaxSynBackLog = HTTP_MAX_SYN_BACK_LOG; + Tcp6Option->ConnectionTimeout = HTTP_CONNECTION_TIMEOUT; + Tcp6Option->DataRetries = HTTP_DATA_RETRIES; + Tcp6Option->FinTimeout = HTTP_FIN_TIMEOUT; + Tcp6Option->KeepAliveProbes = HTTP_KEEP_ALIVE_PROBES; + Tcp6Option->KeepAliveTime = HTTP_KEEP_ALIVE_TIME; + Tcp6Option->KeepAliveInterval = HTTP_KEEP_ALIVE_INTERVAL; + Tcp6Option->EnableNagle = TRUE; + + Status = HttpInstance->Tcp6->Configure (HttpInstance->Tcp6, Tcp6CfgData); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "HttpConfigureTcp6 - %r\n", Status)); + return Status; + } + + Status = HttpCreateTcpConnCloseEvent (HttpInstance); if (EFI_ERROR (Status)) { return Status; } - Status = HttpCreateTcp4TxEvent (Wrap); + Status = HttpCreateTcpTxEvent (Wrap); if (EFI_ERROR (Status)) { return Status; } @@ -723,10 +1157,11 @@ HttpConfigureTcp4 ( HttpInstance->State = HTTP_STATE_TCP_CONFIGED; return EFI_SUCCESS; + } /** - Check existing TCP connection, if in error state, receover TCP4 connection. + Check existing TCP connection, if in error state, recover TCP4 connection. @param[in] HttpInstance The HTTP instance private data. @@ -769,7 +1204,105 @@ HttpConnectTcp4 ( } /** - Send the HTTP message through TCP4. + Check existing TCP connection, if in error state, recover TCP6 connection. + + @param[in] HttpInstance The HTTP instance private data. + + @retval EFI_SUCCESS The TCP connection is established. + @retval EFI_NOT_READY TCP6 protocol child is not created or configured. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpConnectTcp6 ( + IN HTTP_PROTOCOL *HttpInstance + ) +{ + EFI_STATUS Status; + EFI_TCP6_CONNECTION_STATE Tcp6State; + + if (HttpInstance->State != HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp6 == NULL) { + return EFI_NOT_READY; + } + + Status = HttpInstance->Tcp6->GetModeData ( + HttpInstance->Tcp6, + &Tcp6State, + NULL, + NULL, + NULL, + NULL + ); + + if (EFI_ERROR(Status)){ + DEBUG ((EFI_D_ERROR, "Tcp6 GetModeData fail - %x\n", Status)); + return Status; + } + + if (Tcp6State > Tcp6StateEstablished) { + HttpCloseConnection (HttpInstance); + } + + return HttpCreateConnection (HttpInstance); +} + +/** + Initialize TCP related data. + + @param[in] HttpInstance The HTTP instance private data. + @param[in] Wrap The HTTP token's wrap data. + + @retval EFI_SUCCESS The initialization of TCP instance is done. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpInitTcp ( + IN HTTP_PROTOCOL *HttpInstance, + IN HTTP_TOKEN_WRAP *Wrap + ) +{ + EFI_STATUS Status; + ASSERT (HttpInstance != NULL); + + if (!HttpInstance->LocalAddressIsIPv6) { + // + // Configure TCP instance. + // + Status = HttpConfigureTcp4 (HttpInstance, Wrap); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Connect TCP. + // + Status = HttpConnectTcp4 (HttpInstance); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + // + // Configure TCP instance. + // + Status = HttpConfigureTcp6 (HttpInstance, Wrap); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Connect TCP. + // + Status = HttpConnectTcp6 (HttpInstance); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; + +} + +/** + Send the HTTP message through TCP4 or TCP6. @param[in] HttpInstance The HTTP instance private data. @param[in] Wrap The HTTP token's wrap data. @@ -781,7 +1314,7 @@ HttpConnectTcp4 ( **/ EFI_STATUS -HttpTransmitTcp4 ( +HttpTransmitTcp ( IN HTTP_PROTOCOL *HttpInstance, IN HTTP_TOKEN_WRAP *Wrap, IN UINT8 *TxString, @@ -789,23 +1322,44 @@ HttpTransmitTcp4 ( ) { EFI_STATUS Status; - EFI_TCP4_IO_TOKEN *TxToken; + EFI_TCP4_IO_TOKEN *Tx4Token; EFI_TCP4_PROTOCOL *Tcp4; + EFI_TCP6_IO_TOKEN *Tx6Token; + EFI_TCP6_PROTOCOL *Tcp6; - Tcp4 = HttpInstance->Tcp4; - TxToken = &Wrap->TcpWrap.TxToken; + if (!HttpInstance->LocalAddressIsIPv6) { + Tcp4 = HttpInstance->Tcp4; + Tx4Token = &Wrap->TcpWrap.Tx4Token; + + Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen; + Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen; + Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString; + Tx4Token->CompletionToken.Status = EFI_NOT_READY; + + Wrap->TcpWrap.IsTxDone = FALSE; + Status = Tcp4->Transmit (Tcp4, Tx4Token); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status)); + return Status; + } - TxToken->Packet.TxData->DataLength = (UINT32) TxStringLen; - TxToken->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen; - TxToken->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString; - TxToken->CompletionToken.Status = EFI_NOT_READY; + } else { + Tcp6 = HttpInstance->Tcp6; + Tx6Token = &Wrap->TcpWrap.Tx6Token; - Wrap->TcpWrap.IsTxDone = FALSE; - Status = Tcp4->Transmit (Tcp4, TxToken); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status)); - return Status; + Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen; + Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen; + Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString; + Tx6Token->CompletionToken.Status = EFI_NOT_READY; + + Wrap->TcpWrap.IsTxDone = FALSE; + Status = Tcp6->Transmit (Tcp6, Tx6Token); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status)); + return Status; + } } + return Status; } @@ -913,7 +1467,7 @@ HttpMappingToStatusCode ( /** Check whether the user's token or event has already - been enqueue on HTTP TxToken or RxToken list. + been enqueue on HTTP Tx or Rx Token list. @param[in] Map The container of either user's transmit or receive token. @@ -947,9 +1501,9 @@ HttpTokenExist ( } /** - Check whether the HTTP message associated with TxToken is already sent out. + Check whether the HTTP message associated with Tx4Token or Tx6Token is already sent out. - @param[in] Map The container of TxToken. + @param[in] Map The container of Tx4Token or Tx6Token. @param[in] Item Current item to check against. @param[in] Context The Token to check againist. @@ -979,7 +1533,7 @@ HttpTcpNotReady ( /** Transmit the HTTP mssage by processing the associated HTTP token. - @param[in] Map The container of TxToken. + @param[in] Map The container of Tx4Token or Tx6Token. @param[in] Item Current item to check against. @param[in] Context The Token to check againist. @@ -1032,7 +1586,7 @@ HttpTcpTransmit ( // // Transmit the request message. // - Status = HttpTransmitTcp4 ( + Status = HttpTransmitTcp ( ValueInItem->HttpInstance, ValueInItem, (UINT8*) RequestStr, @@ -1045,7 +1599,7 @@ HttpTcpTransmit ( /** Receive the HTTP response by processing the associated HTTP token. - @param[in] Map The container of RxToken. + @param[in] Map The container of Rx4Token or Rx6Token. @param[in] Item Current item to check against. @param[in] Context The Token to check againist. @@ -1068,6 +1622,319 @@ HttpTcpReceive ( return HttpResponseWorker ((HTTP_TOKEN_WRAP *) Item->Value); } +/** + Receive the HTTP header by processing the associated HTTP token. + + @param[in] HttpInstance The HTTP instance private data. + @param[in, out] SizeofHeaders The HTTP header length. + @param[in, out] BufferSize The size of buffer to cacahe the header message. + + @retval EFI_SUCCESS The HTTP header is received. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +HttpTcpReceiveHeader ( + IN HTTP_PROTOCOL *HttpInstance, + IN OUT UINTN *SizeofHeaders, + IN OUT UINTN *BufferSize + ) +{ + EFI_STATUS Status; + EFI_TCP4_IO_TOKEN *Rx4Token; + EFI_TCP4_PROTOCOL *Tcp4; + EFI_TCP6_IO_TOKEN *Rx6Token; + EFI_TCP6_PROTOCOL *Tcp6; + CHAR8 **EndofHeader; + CHAR8 **HttpHeaders; + CHAR8 *Buffer; + + ASSERT (HttpInstance != NULL); + + EndofHeader = HttpInstance->EndofHeader; + HttpHeaders = HttpInstance->HttpHeaders; + Tcp4 = HttpInstance->Tcp4; + Tcp6 = HttpInstance->Tcp6; + Buffer = NULL; + Rx4Token = NULL; + Rx6Token = NULL; + + if (HttpInstance->LocalAddressIsIPv6) { + ASSERT (Tcp6 != NULL); + } else { + ASSERT (Tcp4 != NULL); + } + + if (!HttpInstance->LocalAddressIsIPv6) { + Rx4Token = &HttpInstance->Rx4Token; + Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN); + if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + return Status; + } + + // + // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL. + // + while (*EndofHeader == NULL) { + HttpInstance->IsRxDone = FALSE; + Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN; + Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN; + Status = Tcp4->Receive (Tcp4, Rx4Token); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status)); + return Status; + } + + while (!HttpInstance->IsRxDone) { + Tcp4->Poll (Tcp4); + } + + Status = Rx4Token->CompletionToken.Status; + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Append the response string. + // + *BufferSize = (*SizeofHeaders) + Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength; + Buffer = AllocateZeroPool (*BufferSize); + if (Buffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + return Status; + } + + if (*HttpHeaders != NULL) { + CopyMem (Buffer, *HttpHeaders, (*SizeofHeaders)); + FreePool (*HttpHeaders); + } + + CopyMem ( + Buffer + (*SizeofHeaders), + Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer, + Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength + ); + *HttpHeaders = Buffer; + *SizeofHeaders = *BufferSize; + + // + // Check whether we received end of HTTP headers. + // + *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR); + } + FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer); + Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; + + } else { + Rx6Token = &HttpInstance->Rx6Token; + Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN); + if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + return Status; + } + + // + // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL. + // + while (*EndofHeader == NULL) { + HttpInstance->IsRxDone = FALSE; + Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN; + Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN; + Status = Tcp6->Receive (Tcp6, Rx6Token); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status)); + return Status; + } + + while (!HttpInstance->IsRxDone) { + Tcp6->Poll (Tcp6); + } + + Status = Rx6Token->CompletionToken.Status; + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Append the response string. + // + *BufferSize = (*SizeofHeaders) + Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength; + Buffer = AllocateZeroPool (*BufferSize); + if (Buffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + return Status; + } + + if (*HttpHeaders != NULL) { + CopyMem (Buffer, *HttpHeaders, (*SizeofHeaders)); + FreePool (*HttpHeaders); + } + + CopyMem ( + Buffer + (*SizeofHeaders), + Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer, + Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength + ); + *HttpHeaders = Buffer; + *SizeofHeaders = *BufferSize; + + // + // Check whether we received end of HTTP headers. + // + *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR); + + } + FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer); + Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; + } + + // + // Skip the CRLF after the HTTP headers. + // + *EndofHeader = *EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR); + + return EFI_SUCCESS; +} + +/** + Receive the HTTP body by processing the associated HTTP token. + + @param[in] Wrap The HTTP token's wrap data. + @param[in] HttpMsg The HTTP message data. + + @retval EFI_SUCCESS The HTTP body is received. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpTcpReceiveBody ( + IN HTTP_TOKEN_WRAP *Wrap, + IN EFI_HTTP_MESSAGE *HttpMsg + ) +{ + EFI_STATUS Status; + HTTP_PROTOCOL *HttpInstance; + EFI_TCP6_PROTOCOL *Tcp6; + EFI_TCP6_IO_TOKEN *Rx6Token; + EFI_TCP4_PROTOCOL *Tcp4; + EFI_TCP4_IO_TOKEN *Rx4Token; + + HttpInstance = Wrap->HttpInstance; + Tcp4 = HttpInstance->Tcp4; + Tcp6 = HttpInstance->Tcp6; + Rx4Token = NULL; + Rx6Token = NULL; + + + if (HttpInstance->LocalAddressIsIPv6) { + ASSERT (Tcp6 != NULL); + } else { + ASSERT (Tcp4 != NULL); + } + + if (HttpInstance->LocalAddressIsIPv6) { + Rx6Token = &Wrap->TcpWrap.Rx6Token; + Rx6Token ->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength; + Rx6Token ->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength; + Rx6Token ->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body; + Rx6Token->CompletionToken.Status = EFI_NOT_READY; + + Status = Tcp6->Receive (Tcp6, Rx6Token); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status)); + return Status; + } + + } else { + Rx4Token = &Wrap->TcpWrap.Rx4Token; + Rx4Token->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength; + Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength; + Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body; + + Rx4Token->CompletionToken.Status = EFI_NOT_READY; + Status = Tcp4->Receive (Tcp4, Rx4Token); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status)); + return Status; + } + } + + return EFI_SUCCESS; + +} + +/** + Clean up Tcp Tokens while the Tcp transmission error occurs. + + @param[in] Wrap Pointer to HTTP token's wrap data. + +**/ +VOID +HttpTcpTokenCleanup ( + IN HTTP_TOKEN_WRAP *Wrap + ) +{ + HTTP_PROTOCOL *HttpInstance; + EFI_TCP4_IO_TOKEN *Rx4Token; + EFI_TCP6_IO_TOKEN *Rx6Token; + + HttpInstance = Wrap->HttpInstance; + Rx4Token = NULL; + Rx6Token = NULL; + + if (HttpInstance->LocalAddressIsIPv6) { + if (Wrap != NULL) { + if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); + } + + Rx6Token = &Wrap->TcpWrap.Rx6Token; + if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer); + Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; + } + FreePool (Wrap); + } + + if (HttpInstance->Rx6Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (HttpInstance->Rx6Token.CompletionToken.Event); + HttpInstance->Rx6Token.CompletionToken.Event = NULL; + } + + Rx6Token = &HttpInstance->Rx6Token; + if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer); + Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; + } + + } else { + if (Wrap != NULL) { + if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); + } + Rx4Token = &Wrap->TcpWrap.Rx4Token; + if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer); + Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; + } + FreePool (Wrap); + } + + if (HttpInstance->Rx4Token.CompletionToken.Event != NULL) { + gBS->CloseEvent (HttpInstance->Rx4Token.CompletionToken.Event); + HttpInstance->Rx4Token.CompletionToken.Event = NULL; + } + + Rx4Token = &HttpInstance->Rx4Token; + if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { + FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer); + Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; + } + } + +} + /** Generate HTTP request string. diff --git a/NetworkPkg/HttpDxe/HttpProto.h b/NetworkPkg/HttpDxe/HttpProto.h index c37b80c8ec..a15e0a87be 100644 --- a/NetworkPkg/HttpDxe/HttpProto.h +++ b/NetworkPkg/HttpDxe/HttpProto.h @@ -27,6 +27,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. HTTP_SERVICE_SIGNATURE \ ) + // // The state of HTTP protocol. It starts from UNCONFIGED. // @@ -58,18 +59,23 @@ typedef struct _HTTP_SERVICE { EFI_SERVICE_BINDING_PROTOCOL ServiceBinding; EFI_HANDLE ImageHandle; EFI_HANDLE ControllerHandle; + EFI_HANDLE Tcp4ChildHandle; + EFI_HANDLE Tcp6ChildHandle; LIST_ENTRY ChildrenList; UINTN ChildrenNumber; - EFI_HANDLE TcpChildHandle; INTN State; } HTTP_SERVICE; typedef struct { - EFI_TCP4_IO_TOKEN TxToken; - EFI_TCP4_TRANSMIT_DATA TxData; + EFI_TCP4_IO_TOKEN Tx4Token; + EFI_TCP4_TRANSMIT_DATA Tx4Data; + EFI_TCP6_IO_TOKEN Tx6Token; + EFI_TCP6_TRANSMIT_DATA Tx6Data; + EFI_TCP4_IO_TOKEN Rx4Token; + EFI_TCP4_RECEIVE_DATA Rx4Data; + EFI_TCP6_IO_TOKEN Rx6Token; + EFI_TCP6_RECEIVE_DATA Rx6Data; BOOLEAN IsTxDone; - EFI_TCP4_IO_TOKEN RxToken; - EFI_TCP4_RECEIVE_DATA RxData; BOOLEAN IsRxDone; UINTN BodyLen; EFI_HTTP_METHOD Method; @@ -84,26 +90,43 @@ typedef struct _HTTP_PROTOCOL { BOOLEAN InDestroy; INTN State; - EFI_HANDLE TcpChildHandle; + EFI_HANDLE Tcp4ChildHandle; EFI_TCP4_PROTOCOL *Tcp4; EFI_TCP4_CONFIG_DATA Tcp4CfgData; EFI_TCP4_OPTION Tcp4Option; - EFI_TCP4_CONNECTION_TOKEN ConnToken; - BOOLEAN IsConnDone; - EFI_TCP4_CLOSE_TOKEN CloseToken; - BOOLEAN IsCloseDone; - + EFI_TCP4_CONNECTION_TOKEN Tcp4ConnToken; + BOOLEAN IsTcp4ConnDone; + EFI_TCP4_CLOSE_TOKEN Tcp4CloseToken; + BOOLEAN IsTcp4CloseDone; CHAR8 *RemoteHost; UINT16 RemotePort; EFI_IPv4_ADDRESS RemoteAddr; + + EFI_HANDLE Tcp6ChildHandle; + EFI_TCP6_PROTOCOL *Tcp6; + EFI_TCP6_CONFIG_DATA Tcp6CfgData; + EFI_TCP6_OPTION Tcp6Option; + + EFI_TCP6_CONNECTION_TOKEN Tcp6ConnToken; + BOOLEAN IsTcp6ConnDone; + EFI_TCP6_CLOSE_TOKEN Tcp6CloseToken; + BOOLEAN IsTcp6CloseDone; + EFI_IPv6_ADDRESS RemoteIpv6Addr; + + + // - // RxToken used for receiving HTTP header. + // Rx4Token or Rx6Token used for receiving HTTP header. // - EFI_TCP4_IO_TOKEN RxToken; - EFI_TCP4_RECEIVE_DATA RxData; + EFI_TCP4_IO_TOKEN Rx4Token; + EFI_TCP4_RECEIVE_DATA Rx4Data; + EFI_TCP6_IO_TOKEN Rx6Token; + EFI_TCP6_RECEIVE_DATA Rx6Data; BOOLEAN IsRxDone; + CHAR8 **EndofHeader; + CHAR8 **HttpHeaders; CHAR8 *CacheBody; CHAR8 *NextMsg; UINTN CacheLen; @@ -119,6 +142,7 @@ typedef struct _HTTP_PROTOCOL { BOOLEAN LocalAddressIsIPv6; EFI_HTTPv4_ACCESS_POINT IPv4Node; + EFI_HTTPv6_ACCESS_POINT Ipv6Node; NET_MAP TxTokens; NET_MAP RxTokens; @@ -158,7 +182,7 @@ HttpCommonNotify ( ); /** - Create events for the TCP4 connection token and TCP4 close token. + Create events for the TCP connection token and TCP close token. @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure. @@ -167,23 +191,23 @@ HttpCommonNotify ( **/ EFI_STATUS -HttpCreateTcp4ConnCloseEvent ( +HttpCreateTcpConnCloseEvent ( IN HTTP_PROTOCOL *HttpInstance ); /** - Close events in the TCP4 connection token and TCP4 close token. + Close events in the TCP connection token and TCP close token. @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure. **/ VOID -HttpCloseTcp4ConnCloseEvent ( +HttpCloseTcpConnCloseEvent ( IN HTTP_PROTOCOL *HttpInstance ); /** - Create event for the TCP4 transmit token. + Create event for the TCP transmit token. @param[in] Wrap Point to HTTP token's wrap data. @@ -192,12 +216,12 @@ HttpCloseTcp4ConnCloseEvent ( **/ EFI_STATUS -HttpCreateTcp4TxEvent ( +HttpCreateTcpTxEvent ( IN HTTP_TOKEN_WRAP *Wrap ); /** - Create event for the TCP4 receive token which is used to receive HTTP header. + Create event for the TCP receive token which is used to receive HTTP header. @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure. @@ -206,12 +230,12 @@ HttpCreateTcp4TxEvent ( **/ EFI_STATUS -HttpCreateTcp4RxEventForHeader ( +HttpCreateTcpRxEventForHeader ( IN HTTP_PROTOCOL *HttpInstance ); /** - Create event for the TCP4 receive token which is used to receive HTTP body. + Create event for the TCP receive token which is used to receive HTTP body. @param[in] Wrap Point to HTTP token's wrap data. @@ -220,15 +244,26 @@ HttpCreateTcp4RxEventForHeader ( **/ EFI_STATUS -HttpCreateTcp4RxEvent ( +HttpCreateTcpRxEvent ( IN HTTP_TOKEN_WRAP *Wrap ); +/** + Close Events for Tcp Receive Tokens for HTTP body and HTTP header. + + @param[in] Wrap Pointer to HTTP token's wrap data. + +**/ +VOID +HttpCloseTcpRxEvent ( + IN HTTP_TOKEN_WRAP *Wrap + ); + /** Intiialize the HTTP_PROTOCOL structure to the unconfigured state. - @param[in] HttpSb The HTTP service private instance. @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure. + @param[in] IpVersion Indicate us TCP4 protocol or TCP6 protocol. @retval EFI_SUCCESS HTTP_PROTOCOL structure is initialized successfully. @retval Others Other error as indicated. @@ -236,8 +271,8 @@ HttpCreateTcp4RxEvent ( **/ EFI_STATUS HttpInitProtocol ( - IN HTTP_SERVICE *HttpSb, - IN OUT HTTP_PROTOCOL *HttpInstance + IN OUT HTTP_PROTOCOL *HttpInstance, + IN BOOLEAN IpVersion ); /** @@ -295,6 +330,22 @@ HttpConfigureTcp4 ( IN HTTP_TOKEN_WRAP *Wrap ); +/** + Configure TCP6 protocol child. + + @param[in] HttpInstance The HTTP instance private data. + @param[in] Wrap The HTTP token's wrap data. + + @retval EFI_SUCCESS The TCP6 protocol child is configured. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpConfigureTcp6 ( + IN HTTP_PROTOCOL *HttpInstance, + IN HTTP_TOKEN_WRAP *Wrap + ); + /** Check existing TCP connection, if in error state, receover TCP4 connection. @@ -311,7 +362,22 @@ HttpConnectTcp4 ( ); /** - Send the HTTP message through TCP4. + Check existing TCP connection, if in error state, recover TCP6 connection. + + @param[in] HttpInstance The HTTP instance private data. + + @retval EFI_SUCCESS The TCP connection is established. + @retval EFI_NOT_READY TCP6 protocol child is not created or configured. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpConnectTcp6 ( + IN HTTP_PROTOCOL *HttpInstance + ); + +/** + Send the HTTP message through TCP4 or TCP6. @param[in] HttpInstance The HTTP instance private data. @param[in] Wrap The HTTP token's wrap data. @@ -323,7 +389,7 @@ HttpConnectTcp4 ( **/ EFI_STATUS -HttpTransmitTcp4 ( +HttpTransmitTcp ( IN HTTP_PROTOCOL *HttpInstance, IN HTTP_TOKEN_WRAP *Wrap, IN UINT8 *TxString, @@ -346,7 +412,7 @@ HttpMappingToStatusCode ( /** Check whether the user's token or event has already - been enqueue on HTTP TxToken or RxToken list. + been enqueue on HTTP Tx or Rx Token list. @param[in] Map The container of either user's transmit or receive token. @@ -367,7 +433,7 @@ HttpTokenExist ( ); /** - Check whether the HTTP message associated with TxToken is already sent out. + Check whether the HTTP message associated with TxToken or Tx6Token is already sent out. @param[in] Map The container of TxToken. @param[in] Item Current item to check against. @@ -385,10 +451,26 @@ HttpTcpNotReady ( IN VOID *Context ); +/** + Initialize TCP related data. + + @param[in] HttpInstance The HTTP instance private data. + @param[in] Wrap The HTTP token's wrap data. + + @retval EFI_SUCCESS The initialization of TCP instance is done. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpInitTcp ( + IN HTTP_PROTOCOL *HttpInstance, + IN HTTP_TOKEN_WRAP *Wrap + ); + /** Transmit the HTTP mssage by processing the associated HTTP token. - @param[in] Map The container of TxToken. + @param[in] Map The container of TxToken or Tx6Token. @param[in] Item Current item to check against. @param[in] Context The Token to check againist. @@ -408,7 +490,7 @@ HttpTcpTransmit ( /** Receive the HTTP response by processing the associated HTTP token. - @param[in] Map The container of RxToken. + @param[in] Map The container of Rx4Token or Rx6Token. @param[in] Item Current item to check against. @param[in] Context The Token to check againist. @@ -425,6 +507,51 @@ HttpTcpReceive ( IN VOID *Context ); +/** + Receive the HTTP header by processing the associated HTTP token. + + @param[in] HttpInstance The HTTP instance private data. + @param[in, out] SizeofHeaders The HTTP header length. + @param[in, out] BufferSize The size of buffer to cacahe the header message. + + @retval EFI_SUCCESS The HTTP header is received. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +HttpTcpReceiveHeader ( + IN HTTP_PROTOCOL *HttpInstance, + IN OUT UINTN *SizeofHeaders, + IN OUT UINTN *BufferSize + ); + +/** + Receive the HTTP body by processing the associated HTTP token. + + @param[in] Wrap The HTTP token's wrap data. + @param[in] HttpMsg The HTTP message data. + + @retval EFI_SUCCESS The HTTP body is received. + @retval Others Other error as indicated. + +**/ +EFI_STATUS +HttpTcpReceiveBody ( + IN HTTP_TOKEN_WRAP *Wrap, + IN EFI_HTTP_MESSAGE *HttpMsg + ); + +/** + Clean up Tcp Tokens while the Tcp transmission error occurs. + + @param[in] Wrap Pointer to HTTP token's wrap data. + +**/ +VOID +HttpTcpTokenCleanup ( + IN HTTP_TOKEN_WRAP *Wrap + ); + /** Generate HTTP request string. -- cgit v1.2.3