+ Status = gBS->LocateProtocol (&gEfiIpSec2ProtocolGuid, NULL, (VOID **) &IpSec);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Private = IPSEC_PRIVATE_DATA_FROM_IPSEC (IpSec);\r
+\r
+ if (IpVersion == IP_VERSION_4) {\r
+ //\r
+ // Try to open a udp4 io for input.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiUdp4ServiceBindingProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = IkeOpenInputUdp4 (Private, ControllerHandle, This->DriverBindingHandle);\r
+ }\r
+ } else {\r
+ //\r
+ // Try to open a udp6 io for input.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiUdp6ServiceBindingProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = IkeOpenInputUdp6 (Private, ControllerHandle, This->DriverBindingHandle);\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Stop this driver on ControllerHandle. This is the worker function\r
+ for IpSec4(6)DriverbindingStop.\r
+\r
+ @param[in] This Protocol instance pointer.\r
+ @param[in] ControllerHandle Handle of a device to stop the driver on.\r
+ @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If the number of\r
+ children is zero, stop the entire bus driver.\r
+ @param[in] ChildHandleBuffer List of Child Handles to Stop.\r
+ @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.\r
+\r
+ @retval EFI_SUCCES This driver removed ControllerHandle.\r
+ @retval other This driver was not removed from this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IpSecStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer,\r
+ IN UINT8 IpVersion\r
+ )\r
+{\r
+ EFI_IPSEC2_PROTOCOL *IpSec;\r
+ EFI_STATUS Status;\r
+ IPSEC_PRIVATE_DATA *Private;\r
+ IKE_UDP_SERVICE *UdpSrv;\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *Next;\r
+ IKEV2_SA_SESSION *Ikev2SaSession;\r
+\r
+ //\r
+ // Locate ipsec protocol to get private data.\r
+ //\r
+ Status = gBS->LocateProtocol (&gEfiIpSec2ProtocolGuid, NULL, (VOID **) &IpSec);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Private = IPSEC_PRIVATE_DATA_FROM_IPSEC (IpSec);\r
+\r
+ //\r
+ // The SAs are shared by both IP4 and IP6 stack. So we skip the cleanup\r
+ // and leave the SAs unchanged if the other IP stack is still running.\r
+ //\r
+ if ((IpVersion == IP_VERSION_4 && Private->Udp6Num ==0) ||\r
+ (IpVersion == IP_VERSION_6 && Private->Udp4Num ==0)) {\r
+ //\r
+ // If IKEv2 SAs are under establishing, delete it directly.\r
+ //\r
+ if (!IsListEmpty (&Private->Ikev2SessionList)) {\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Private->Ikev2SessionList) {\r
+ Ikev2SaSession = IKEV2_SA_SESSION_BY_SESSION (Entry);\r
+ RemoveEntryList (&Ikev2SaSession->BySessionTable);\r
+ Ikev2SaSessionFree (Ikev2SaSession);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Delete established IKEv2 SAs.\r
+ //\r
+ if (!IsListEmpty (&Private->Ikev2EstablishedList)) {\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Private->Ikev2EstablishedList) {\r
+ Ikev2SaSession = IKEV2_SA_SESSION_BY_SESSION (Entry);\r
+ RemoveEntryList (&Ikev2SaSession->BySessionTable);\r
+ Ikev2SaSessionFree (Ikev2SaSession);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (IpVersion == IP_VERSION_4) {\r
+ //\r
+ // If has udp4 io opened on the controller, close and free it.\r
+ //\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Private->Udp4List) {\r
+\r
+ UdpSrv = IPSEC_UDP_SERVICE_FROM_LIST (Entry);\r
+ //\r
+ // Find the right udp service which installed on the appointed nic handle.\r
+ //\r
+ if (UdpSrv->Input != NULL && ControllerHandle == UdpSrv->Input->UdpHandle) {\r
+ UdpIoFreeIo (UdpSrv->Input);\r
+ UdpSrv->Input = NULL;\r
+ }\r
+\r
+ if (UdpSrv->Output != NULL && ControllerHandle == UdpSrv->Output->UdpHandle) {\r
+ UdpIoFreeIo (UdpSrv->Output);\r
+ UdpSrv->Output = NULL;\r
+ }\r
+\r
+ if (UdpSrv->Input == NULL && UdpSrv->Output == NULL) {\r
+ RemoveEntryList (&UdpSrv->List);\r
+ FreePool (UdpSrv);\r
+ ASSERT (Private->Udp4Num > 0);\r
+ Private->Udp4Num--;\r
+ }\r
+ }\r
+ } else {\r
+ //\r
+ // If has udp6 io opened on the controller, close and free it.\r
+ //\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Private->Udp6List) {\r
+\r
+ UdpSrv = IPSEC_UDP_SERVICE_FROM_LIST (Entry);\r
+ //\r
+ // Find the right udp service which installed on the appointed nic handle.\r
+ //\r
+ if (UdpSrv->Input != NULL && ControllerHandle == UdpSrv->Input->UdpHandle) {\r
+ UdpIoFreeIo (UdpSrv->Input);\r
+ UdpSrv->Input = NULL;\r
+ }\r
+\r
+ if (UdpSrv->Output != NULL && ControllerHandle == UdpSrv->Output->UdpHandle) {\r
+ UdpIoFreeIo (UdpSrv->Output);\r
+ UdpSrv->Output = NULL;\r
+ }\r
+\r
+ if (UdpSrv->Input == NULL && UdpSrv->Output == NULL) {\r
+ RemoveEntryList (&UdpSrv->List);\r
+ FreePool (UdpSrv);\r
+ ASSERT (Private->Udp6Num > 0);\r
+ Private->Udp6Num--;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Test to see if this driver supports ControllerHandle.\r
+\r
+ @param[in] This Protocol instance pointer.\r
+ @param[in] ControllerHandle Handle of device to test.\r
+ @param[in] RemainingDevicePath Optional parameter used to pick a specific child\r
+ device to start.\r
+\r
+ @retval EFI_SUCCES This driver supports this device.\r
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
+ @retval other This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IpSec4DriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
+ )\r
+{\r
+ return IpSecSupported (\r
+ This,\r
+ ControllerHandle,\r
+ RemainingDevicePath,\r
+ IP_VERSION_4\r
+ );\r