/** Create the DNS instance and initialize it. @param[in] Service The pointer to the DNS service. @param[out] Instance The pointer to the DNS instance. @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. @retval EFI_SUCCESS The DNS instance is created. **/ EFI_STATUS DnsCreateInstance ( IN DNS_SERVICE *Service, OUT DNS_INSTANCE **Instance ) { DNS_INSTANCE *DnsIns; *Instance = NULL; DnsIns = AllocateZeroPool (sizeof (DNS_INSTANCE)); if (DnsIns == NULL) { return EFI_OUT_OF_RESOURCES; } DnsIns->Signature = DNS_INSTANCE_SIGNATURE; InitializeListHead (&DnsIns->Link); DnsIns->State = DNS_STATE_UNCONFIGED; DnsIns->InDestroy = FALSE; DnsIns->Service = Service; if (Service->IpVersion == IP_VERSION_4) { CopyMem (&DnsIns->Dns4, &mDns4Protocol, sizeof (DnsIns->Dns4)); NetMapInit (&DnsIns->Dns4TxTokens); } else { CopyMem (&DnsIns->Dns6, &mDns6Protocol, sizeof (DnsIns->Dns6)); NetMapInit (&DnsIns->Dns6TxTokens); } DnsIns->UdpIo = UdpIoCreateIo ( Service->ControllerHandle, /// NicHandle Service->ImageHandle, DnsConfigNullUdp, Service->IpVersion, DnsIns ); if (DnsIns->UdpIo == NULL) { FreePool (DnsIns); return EFI_OUT_OF_RESOURCES; } *Instance = DnsIns; return EFI_SUCCESS; }
/** Create a MTFTP child for the service binding instance, then install the MTFTP protocol to the ChildHandle. @param This The MTFTP service binding instance. @param ChildHandle The Child handle to install the MTFTP protocol. @retval EFI_INVALID_PARAMETER The parameter is invalid. @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the new child. @retval EFI_SUCCESS The child is successfully create. **/ EFI_STATUS EFIAPI Mtftp4ServiceBindingCreateChild ( IN EFI_SERVICE_BINDING_PROTOCOL *This, IN EFI_HANDLE *ChildHandle ) { MTFTP4_SERVICE *MtftpSb; MTFTP4_PROTOCOL *Instance; EFI_STATUS Status; EFI_TPL OldTpl; VOID *Udp4; if ((This == NULL) || (ChildHandle == NULL)) { return EFI_INVALID_PARAMETER; } Instance = AllocatePool (sizeof (*Instance)); if (Instance == NULL) { return EFI_OUT_OF_RESOURCES; } MtftpSb = MTFTP4_SERVICE_FROM_THIS (This); Mtftp4InitProtocol (MtftpSb, Instance); Instance->UnicastPort = UdpIoCreateIo ( MtftpSb->Controller, MtftpSb->Image, Mtftp4ConfigNullUdp, UDP_IO_UDP4_VERSION, Instance ); if (Instance->UnicastPort == NULL) { FreePool (Instance); return EFI_OUT_OF_RESOURCES; } // // Install the MTFTP protocol onto ChildHandle // Status = gBS->InstallMultipleProtocolInterfaces ( ChildHandle, &gEfiMtftp4ProtocolGuid, &Instance->Mtftp4, NULL ); if (EFI_ERROR (Status)) { UdpIoFreeIo (Instance->UnicastPort); FreePool (Instance); return Status; } Instance->Handle = *ChildHandle; // // Open the Udp4 protocol BY_CHILD. // Status = gBS->OpenProtocol ( MtftpSb->ConnectUdp->UdpHandle, &gEfiUdp4ProtocolGuid, (VOID **) &Udp4, gMtftp4DriverBinding.DriverBindingHandle, Instance->Handle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); if (EFI_ERROR (Status)) { goto ON_ERROR; } // // Open the Udp4 protocol by child. // Status = gBS->OpenProtocol ( Instance->UnicastPort->UdpHandle, &gEfiUdp4ProtocolGuid, (VOID **) &Udp4, gMtftp4DriverBinding.DriverBindingHandle, Instance->Handle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); if (EFI_ERROR (Status)) { // // Close the Udp4 protocol. // gBS->CloseProtocol ( MtftpSb->ConnectUdp->UdpHandle, &gEfiUdp4ProtocolGuid, gMtftp4DriverBinding.DriverBindingHandle, ChildHandle ); goto ON_ERROR; } // // Add it to the parent's child list. // OldTpl = gBS->RaiseTPL (TPL_CALLBACK); InsertTailList (&MtftpSb->Children, &Instance->Link); MtftpSb->ChildrenNum++; gBS->RestoreTPL (OldTpl); return EFI_SUCCESS; ON_ERROR: if (Instance->Handle != NULL) { gBS->UninstallMultipleProtocolInterfaces ( Instance->Handle, &gEfiMtftp4ProtocolGuid, &Instance->Mtftp4, NULL ); } UdpIoFreeIo (Instance->UnicastPort); FreePool (Instance); return Status; }
/** Create then initialize a MTFTP service binding instance. @param Controller The controller to install the MTFTP service binding on @param Image The driver binding image of the MTFTP driver @param Service The variable to receive the created service binding instance. @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the instance @retval EFI_DEVICE_ERROR Failed to create a NULL UDP port to keep connection with UDP. @retval EFI_SUCCESS The service instance is created for the controller. **/ EFI_STATUS Mtftp4CreateService ( IN EFI_HANDLE Controller, IN EFI_HANDLE Image, OUT MTFTP4_SERVICE **Service ) { MTFTP4_SERVICE *MtftpSb; EFI_STATUS Status; *Service = NULL; MtftpSb = AllocatePool (sizeof (MTFTP4_SERVICE)); if (MtftpSb == NULL) { return EFI_OUT_OF_RESOURCES; } MtftpSb->Signature = MTFTP4_SERVICE_SIGNATURE; MtftpSb->ServiceBinding = gMtftp4ServiceBindingTemplete; MtftpSb->ChildrenNum = 0; InitializeListHead (&MtftpSb->Children); MtftpSb->Timer = NULL; MtftpSb->TimerToGetMap = NULL; MtftpSb->Controller = Controller; MtftpSb->Image = Image; MtftpSb->ConnectUdp = NULL; // // Create the timer and a udp to be notified when UDP is uninstalled // Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL | EVT_TIMER, TPL_CALLBACK, Mtftp4OnTimerTick, MtftpSb, &MtftpSb->Timer ); if (EFI_ERROR (Status)) { FreePool (MtftpSb); return Status; } // // Create the timer used to time out the procedure which is used to // get the default IP address. // Status = gBS->CreateEvent ( EVT_TIMER, TPL_CALLBACK, NULL, NULL, &MtftpSb->TimerToGetMap ); if (EFI_ERROR (Status)) { gBS->CloseEvent (MtftpSb->Timer); FreePool (MtftpSb); return Status; } MtftpSb->ConnectUdp = UdpIoCreateIo ( Controller, Image, Mtftp4ConfigNullUdp, UDP_IO_UDP4_VERSION, NULL ); if (MtftpSb->ConnectUdp == NULL) { gBS->CloseEvent (MtftpSb->TimerToGetMap); gBS->CloseEvent (MtftpSb->Timer); FreePool (MtftpSb); return EFI_DEVICE_ERROR; } *Service = MtftpSb; return EFI_SUCCESS; }
/** Function to process the OACK. It will first validate the OACK packet, then update the various negotiated parameters. @param Instance The download MTFTP session @param Packet The packet received @param Len The packet length @param Multicast Whether this packet is received as a multicast @param Completed Returns whether the download has completed. NOT used by this function. @retval EFI_DEVICE_ERROR Failed to create/start a multicast UDP child @retval EFI_TFTP_ERROR Some error happened during the process @retval EFI_SUCCESS The OACK is successfully processed. **/ EFI_STATUS Mtftp4RrqHandleOack ( IN OUT MTFTP4_PROTOCOL *Instance, IN EFI_MTFTP4_PACKET *Packet, IN UINT32 Len, IN BOOLEAN Multicast, OUT BOOLEAN *Completed ) { MTFTP4_OPTION Reply; EFI_STATUS Status; INTN Expected; EFI_UDP4_PROTOCOL *Udp4; *Completed = FALSE; // // If already started the master download, don't change the // setting. Master download always succeeds. // Expected = Mtftp4GetNextBlockNum (&Instance->Blocks); ASSERT (Expected != -1); if (Instance->Master && (Expected != 1)) { return EFI_SUCCESS; } // // Parse and validate the options from server // ZeroMem (&Reply, sizeof (MTFTP4_OPTION)); Status = Mtftp4ParseOptionOack (Packet, Len, &Reply); if (EFI_ERROR (Status) || !Mtftp4RrqOackValid (Instance, &Reply, &Instance->RequestOption)) { // // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES. // if (Status != EFI_OUT_OF_RESOURCES) { Mtftp4SendError ( Instance, EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION, (UINT8 *) "Mal-formated OACK packet" ); } return EFI_TFTP_ERROR; } if ((Reply.Exist & MTFTP4_MCAST_EXIST) != 0) { // // Save the multicast info. Always update the Master, only update the // multicast IP address, block size, timeoute at the first time. If IP // address is updated, create a UDP child to receive the multicast. // Instance->Master = Reply.Master; if (Instance->McastIp == 0) { if ((Reply.McastIp == 0) || (Reply.McastPort == 0)) { Mtftp4SendError ( Instance, EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION, (UINT8 *) "Illegal multicast setting" ); return EFI_TFTP_ERROR; } // // Create a UDP child then start receive the multicast from it. // Instance->McastIp = Reply.McastIp; Instance->McastPort = Reply.McastPort; if (Instance->McastUdpPort == NULL) { Instance->McastUdpPort = UdpIoCreateIo ( Instance->Service->Controller, Instance->Service->Image, Mtftp4RrqConfigMcastPort, UDP_IO_UDP4_VERSION, Instance ); if (Instance->McastUdpPort != NULL) { Status = gBS->OpenProtocol ( Instance->McastUdpPort->UdpHandle, &gEfiUdp4ProtocolGuid, (VOID **) &Udp4, Instance->Service->Image, Instance->Handle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); if (EFI_ERROR (Status)) { UdpIoFreeIo (Instance->McastUdpPort); Instance->McastUdpPort = NULL; return EFI_DEVICE_ERROR; } } } if (Instance->McastUdpPort == NULL) { return EFI_DEVICE_ERROR; } Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0); if (EFI_ERROR (Status)) { Mtftp4SendError ( Instance, EFI_MTFTP4_ERRORCODE_ACCESS_VIOLATION, (UINT8 *) "Failed to create socket to receive multicast packet" ); return Status; } // // Update the parameters used. // if (Reply.BlkSize != 0) { Instance->BlkSize = Reply.BlkSize; } if (Reply.Timeout != 0) { Instance->Timeout = Reply.Timeout; } } } else { Instance->Master = TRUE; if (Reply.BlkSize != 0) { Instance->BlkSize = Reply.BlkSize; } if (Reply.Timeout != 0) { Instance->Timeout = Reply.Timeout; } } // // Send an ACK to (Expected - 1) which is 0 for unicast download, // or tell the server we want to receive the Expected block. // return Mtftp4RrqSendAck (Instance, (UINT16) (Expected - 1)); }
/** Create then initialize a Dns service binding instance. @param Controller The controller to install the DNS service binding on @param Image The driver binding image of the DNS driver @param IpVersion IpVersion for this service @param Service The variable to receive the created service binding instance. @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the instance. @retval EFI_DEVICE_ERROR Failed to create a NULL UDP port to keep connection with UDP. @retval EFI_SUCCESS The service instance is created for the controller. **/ EFI_STATUS DnsCreateService ( IN EFI_HANDLE Controller, IN EFI_HANDLE Image, IN UINT8 IpVersion, OUT DNS_SERVICE **Service ) { EFI_STATUS Status; DNS_SERVICE *DnsSb; Status = EFI_SUCCESS; DnsSb = NULL; *Service = NULL; DnsSb = AllocateZeroPool (sizeof (DNS_SERVICE)); if (DnsSb == NULL) { return EFI_OUT_OF_RESOURCES; } DnsSb->Signature = DNS_SERVICE_SIGNATURE; if (IpVersion == IP_VERSION_4) { DnsSb->ServiceBinding = mDns4ServiceBinding; } else { DnsSb->ServiceBinding = mDns6ServiceBinding; } DnsSb->Dns4ChildrenNum = 0; InitializeListHead (&DnsSb->Dns4ChildrenList); DnsSb->Dns6ChildrenNum = 0; InitializeListHead (&DnsSb->Dns6ChildrenList); DnsSb->ControllerHandle = Controller; DnsSb->ImageHandle = Image; DnsSb->TimerToGetMap = NULL; DnsSb->Timer = NULL; DnsSb->IpVersion = IpVersion; // // Create the timer used to time out the procedure which is used to // get the default IP address. // if (DnsSb->IpVersion == IP_VERSION_4) { Status = gBS->CreateEvent ( EVT_TIMER, TPL_CALLBACK, NULL, NULL, &DnsSb->TimerToGetMap ); if (EFI_ERROR (Status)) { FreePool (DnsSb); return Status; } } // // Create the timer to retransmit packets. // Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL | EVT_TIMER, TPL_CALLBACK, DnsOnTimerRetransmit, DnsSb, &DnsSb->Timer ); if (EFI_ERROR (Status)) { if (DnsSb->TimerToGetMap != NULL) { gBS->CloseEvent (DnsSb->TimerToGetMap); } FreePool (DnsSb); return Status; } DnsSb->ConnectUdp = NULL; DnsSb->ConnectUdp = UdpIoCreateIo ( Controller, Image, DnsConfigNullUdp, DnsSb->IpVersion, NULL ); if (DnsSb->ConnectUdp == NULL) { if (DnsSb->TimerToGetMap != NULL) { gBS->CloseEvent (DnsSb->TimerToGetMap); } gBS->CloseEvent (DnsSb->Timer); FreePool (DnsSb); return EFI_DEVICE_ERROR; } *Service = DnsSb; return Status; }
/** Process the OACK packet for Rrq. @param[in] Instance The pointer to the Mtftp6 instance. @param[in] Packet The pointer to the received packet. @param[in] Len The length of the packet. @param[out] UdpPacket The net buf of received packet. @param[out] IsCompleted If TRUE, the download has been completed. Otherwise, the download has not been completed. @retval EFI_DEVICE_ERROR Failed to create/start a multicast Udp6 child. @retval EFI_TFTP_ERROR An error happened during the process. @retval EFI_SUCCESS The OACK packet successfully processed. **/ EFI_STATUS Mtftp6RrqHandleOack ( IN MTFTP6_INSTANCE *Instance, IN EFI_MTFTP6_PACKET *Packet, IN UINT32 Len, OUT NET_BUF **UdpPacket, OUT BOOLEAN *IsCompleted ) { EFI_MTFTP6_OPTION *Options; UINT32 Count; MTFTP6_EXT_OPTION_INFO ExtInfo; EFI_STATUS Status; INTN Expected; *IsCompleted = FALSE; // // If already started the master download, don't change the // setting. Master download always succeeds. // Expected = Mtftp6GetNextBlockNum (&Instance->BlkList); ASSERT (Expected != -1); if (Instance->IsMaster && Expected != 1) { return EFI_SUCCESS; } ZeroMem (&ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO)); // // Parse the options in the packet. // Status = Mtftp6ParseStart (Packet, Len, &Count, &Options); if (EFI_ERROR (Status)) { return Status; } // // Parse the extensive options in the packet. // Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, &ExtInfo); if (EFI_ERROR (Status) || !Mtftp6RrqOackValid (Instance, &ExtInfo, &Instance->ExtInfo)) { // // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES. // if (Status != EFI_OUT_OF_RESOURCES) { // // Free the received packet before send new packet in ReceiveNotify, // since the udpio might need to be reconfigured. // NetbufFree (*UdpPacket); *UdpPacket = NULL; // // Send the Mtftp6 error message if invalid packet. // Mtftp6SendError ( Instance, EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION, (UINT8 *) "Mal-formated OACK packet" ); } return EFI_TFTP_ERROR; } if ((ExtInfo.BitMap & MTFTP6_OPT_MCAST_BIT) != 0) { // // Save the multicast info. Always update the Master, only update the // multicast IP address, block size, timeoute at the first time. If IP // address is updated, create a UDP child to receive the multicast. // Instance->IsMaster = ExtInfo.IsMaster; if (NetIp6IsUnspecifiedAddr (&Instance->McastIp)) { if (NetIp6IsUnspecifiedAddr (&ExtInfo.McastIp) || ExtInfo.McastPort == 0) { // // Free the received packet before send new packet in ReceiveNotify, // since the udpio might need to be reconfigured. // NetbufFree (*UdpPacket); *UdpPacket = NULL; // // Send the Mtftp6 error message if invalid multi-cast setting. // Mtftp6SendError ( Instance, EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION, (UINT8 *) "Illegal multicast setting" ); return EFI_TFTP_ERROR; } // // Create a UDP child then start receive the multicast from it. // CopyMem ( &Instance->McastIp, &ExtInfo.McastIp, sizeof (EFI_IP_ADDRESS) ); Instance->McastPort = ExtInfo.McastPort; Instance->McastUdpIo = UdpIoCreateIo ( Instance->Service->Controller, Instance->Service->Image, Mtftp6RrqConfigMcastUdpIo, UDP_IO_UDP6_VERSION, Instance ); if (Instance->McastUdpIo == NULL) { return EFI_DEVICE_ERROR; } Status = UdpIoRecvDatagram ( Instance->McastUdpIo, Mtftp6RrqInput, Instance, 0 ); if (EFI_ERROR (Status)) { // // Free the received packet before send new packet in ReceiveNotify, // since the udpio might need to be reconfigured. // NetbufFree (*UdpPacket); *UdpPacket = NULL; // // Send the Mtftp6 error message if failed to create Udp6Io to receive. // Mtftp6SendError ( Instance, EFI_MTFTP6_ERRORCODE_ACCESS_VIOLATION, (UINT8 *) "Failed to create socket to receive multicast packet" ); return Status; } // // Update the parameters used. // if (ExtInfo.BlkSize != 0) { Instance->BlkSize = ExtInfo.BlkSize; } if (ExtInfo.Timeout != 0) { Instance->Timeout = ExtInfo.Timeout; } } } else { Instance->IsMaster = TRUE; if (ExtInfo.BlkSize != 0) { Instance->BlkSize = ExtInfo.BlkSize; } if (ExtInfo.Timeout != 0) { Instance->Timeout = ExtInfo.Timeout; } } // // Free the received packet before send new packet in ReceiveNotify, // since the udpio might need to be reconfigured. // NetbufFree (*UdpPacket); *UdpPacket = NULL; // // Send an ACK to (Expected - 1) which is 0 for unicast download, // or tell the server we want to receive the Expected block. // return Mtftp6RrqSendAck (Instance, (UINT16) (Expected - 1)); }