/** Start the MTFTP session for upload. It will first init some states, then send the WRQ request packet, and start receiving the packet. @param Instance The MTFTP session @param Operation Redundant parameter, which is always EFI_MTFTP4_OPCODE_WRQ here. @retval EFI_SUCCESS The upload process has been started. @retval Others Failed to start the upload. **/ EFI_STATUS Mtftp4WrqStart ( IN MTFTP4_PROTOCOL *Instance, IN UINT16 Operation ) { EFI_STATUS Status; // // The valid block number range are [0, 0xffff]. For example: // the client sends an WRQ request to the server, the server // ACK with an ACK0 to let client start transfer the first // packet. // Status = Mtftp4InitBlockRange (&Instance->Blocks, 0, 0xffff); if (EFI_ERROR (Status)) { return Status; } Status = Mtftp4SendRequest (Instance); if (EFI_ERROR (Status)) { return Status; } return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0); }
/** Start the MTFTP session to download. It will first initialize some of the internal states then build and send a RRQ reqeuest packet, at last, it will start receive for the downloading. @param Instance The Mtftp session @param Operation The MTFTP opcode, it may be a EFI_MTFTP4_OPCODE_RRQ or EFI_MTFTP4_OPCODE_DIR. @retval EFI_SUCCESS The mtftp download session is started. @retval Others Failed to start downloading. **/ EFI_STATUS Mtftp4RrqStart ( IN MTFTP4_PROTOCOL *Instance, IN UINT16 Operation ) { EFI_STATUS Status; // // The valid block number range are [1, 0xffff]. For example: // the client sends an RRQ request to the server, the server // transfers the DATA1 block. If option negoitation is ongoing, // the server will send back an OACK, then client will send ACK0. // Status = Mtftp4InitBlockRange (&Instance->Blocks, 1, 0xffff); if (EFI_ERROR (Status)) { return Status; } Status = Mtftp4SendRequest (Instance); if (EFI_ERROR (Status)) { return Status; } return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0); }
/** The input process routine for MTFTP upload. @param UdpPacket The received MTFTP packet. @param EndPoint The local/remote access point @param IoStatus The result of the packet receiving @param Context Opaque parameter for the callback, which is the MTFTP session. **/ VOID EFIAPI Mtftp4WrqInput ( IN NET_BUF *UdpPacket, IN UDP_END_POINT *EndPoint, IN EFI_STATUS IoStatus, IN VOID *Context ) { MTFTP4_PROTOCOL *Instance; EFI_MTFTP4_PACKET *Packet; BOOLEAN Completed; EFI_STATUS Status; UINT32 Len; UINT16 Opcode; Instance = (MTFTP4_PROTOCOL *) Context; NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE); Completed = FALSE; Packet = NULL; Status = EFI_SUCCESS; if (EFI_ERROR (IoStatus)) { Status = IoStatus; goto ON_EXIT; } ASSERT (UdpPacket != NULL); if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) { goto ON_EXIT; } // // Client send initial request to server's listening port. Server // will select a UDP port to communicate with the client. // if (EndPoint->RemotePort != Instance->ConnectedPort) { if (Instance->ConnectedPort != 0) { goto ON_EXIT; } else { Instance->ConnectedPort = EndPoint->RemotePort; } } // // Copy the MTFTP packet to a continuous buffer if it isn't already so. // Len = UdpPacket->TotalSize; if (UdpPacket->BlockOpNum > 1) { Packet = AllocatePool (Len); if (Packet == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ON_EXIT; } NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet); } else { Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL); ASSERT (Packet != NULL); } Opcode = NTOHS (Packet->OpCode); // // Call the user's CheckPacket if provided. Abort the transmission // if CheckPacket returns an EFI_ERROR code. // if ((Instance->Token->CheckPacket != NULL) && ((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) { Status = Instance->Token->CheckPacket ( &Instance->Mtftp4, Instance->Token, (UINT16) Len, Packet ); if (EFI_ERROR (Status)) { // // Send an error message to the server to inform it // if (Opcode != EFI_MTFTP4_OPCODE_ERROR) { Mtftp4SendError ( Instance, EFI_MTFTP4_ERRORCODE_REQUEST_DENIED, (UINT8 *) "User aborted the transfer" ); } Status = EFI_ABORTED; goto ON_EXIT; } } switch (Opcode) { case EFI_MTFTP4_OPCODE_ACK: if (Len != MTFTP4_OPCODE_LEN + MTFTP4_BLKNO_LEN) { goto ON_EXIT; } Status = Mtftp4WrqHandleAck (Instance, Packet, Len, &Completed); break; case EFI_MTFTP4_OPCODE_OACK: if (Len <= MTFTP4_OPCODE_LEN) { goto ON_EXIT; } Status = Mtftp4WrqHandleOack (Instance, Packet, Len, &Completed); break; case EFI_MTFTP4_OPCODE_ERROR: Status = EFI_TFTP_ERROR; break; default: break; } ON_EXIT: // // Free the resources, then if !EFI_ERROR (Status) and not completed, // restart the receive, otherwise end the session. // if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) { FreePool (Packet); } if (UdpPacket != NULL) { NetbufFree (UdpPacket); } if (!EFI_ERROR (Status) && !Completed) { Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0); } // // Status may have been updated by UdpIoRecvDatagram // if (EFI_ERROR (Status) || Completed) { Mtftp4CleanOperation (Instance, Status); } }
/** 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)); }
/** The packet process callback for Mtftp6 download. @param[in] UdpPacket The pointer to the packet received. @param[in] UdpEpt The pointer to the Udp6 access point. @param[in] IoStatus The status from Udp6 instance. @param[in] Context The pointer to the context. **/ VOID EFIAPI Mtftp6RrqInput ( IN NET_BUF *UdpPacket, IN UDP_END_POINT *UdpEpt, IN EFI_STATUS IoStatus, IN VOID *Context ) { MTFTP6_INSTANCE *Instance; EFI_MTFTP6_PACKET *Packet; BOOLEAN IsCompleted; BOOLEAN IsMcast; EFI_STATUS Status; UINT16 Opcode; UINT32 TotalNum; UINT32 Len; Instance = (MTFTP6_INSTANCE *) Context; NET_CHECK_SIGNATURE (Instance, MTFTP6_INSTANCE_SIGNATURE); Status = EFI_SUCCESS; Packet = NULL; IsCompleted = FALSE; IsMcast = FALSE; TotalNum = 0; // // Return error status if Udp6 instance failed to receive. // if (EFI_ERROR (IoStatus)) { Status = IoStatus; goto ON_EXIT; } ASSERT (UdpPacket != NULL); if (UdpPacket->TotalSize < MTFTP6_OPCODE_LEN) { goto ON_EXIT; } // // Find the port this packet is from to restart receive correctly. // if (CompareMem ( Ip6Swap128 (&UdpEpt->LocalAddr.v6), &Instance->McastIp, sizeof (EFI_IPv6_ADDRESS) ) == 0) { IsMcast = TRUE; } else { IsMcast = FALSE; } // // Client send initial request to server's listening port. Server // will select a UDP port to communicate with the client. The server // is required to use the same port as RemotePort to multicast the // data. // if (UdpEpt->RemotePort != Instance->ServerDataPort) { if (Instance->ServerDataPort != 0) { goto ON_EXIT; } else { // // For the subsequent exchange of requests, reconfigure the udpio as // (serverip, serverport, localip, localport). // Ususally, the client set serverport as 0 to receive and reset it // once the first packet arrives to send ack. // Instance->ServerDataPort = UdpEpt->RemotePort; } } // // Copy the MTFTP packet to a continuous buffer if it isn't already so. // Len = UdpPacket->TotalSize; TotalNum = UdpPacket->BlockOpNum; if (TotalNum > 1) { Packet = AllocateZeroPool (Len); if (Packet == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ON_EXIT; } NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet); } else { Packet = (EFI_MTFTP6_PACKET *) NetbufGetByte (UdpPacket, 0, NULL); ASSERT (Packet != NULL); } Opcode = NTOHS (Packet->OpCode); // // Callback to the user's CheckPacket if provided. Abort the transmission // if CheckPacket returns an EFI_ERROR code. // if ((Instance->Token->CheckPacket != NULL) && (Opcode == EFI_MTFTP6_OPCODE_OACK || Opcode == EFI_MTFTP6_OPCODE_ERROR) ) { Status = Instance->Token->CheckPacket ( &Instance->Mtftp6, Instance->Token, (UINT16) Len, Packet ); if (EFI_ERROR (Status)) { // // Send an error message to the server to inform it // if (Opcode != EFI_MTFTP6_OPCODE_ERROR) { // // 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 user aborted the current session. // Mtftp6SendError ( Instance, EFI_MTFTP6_ERRORCODE_REQUEST_DENIED, (UINT8 *) "User aborted the transfer" ); } Status = EFI_ABORTED; goto ON_EXIT; } } // // Switch the process routines by the operation code. // switch (Opcode) { case EFI_MTFTP6_OPCODE_DATA: if ((Len > (UINT32) (MTFTP6_DATA_HEAD_LEN + Instance->BlkSize)) || (Len < (UINT32) MTFTP6_DATA_HEAD_LEN)) { goto ON_EXIT; } // // Handle the data packet of Rrq. // Status = Mtftp6RrqHandleData ( Instance, Packet, Len, &UdpPacket, &IsCompleted ); break; case EFI_MTFTP6_OPCODE_OACK: if (IsMcast || Len <= MTFTP6_OPCODE_LEN) { goto ON_EXIT; } // // Handle the Oack packet of Rrq. // Status = Mtftp6RrqHandleOack ( Instance, Packet, Len, &UdpPacket, &IsCompleted ); break; default: // // Drop and return eror if received error message. // Status = EFI_TFTP_ERROR; break; } ON_EXIT: // // Free the resources, then if !EFI_ERROR (Status), restart the // receive, otherwise end the session. // if (Packet != NULL && TotalNum > 1) { FreePool (Packet); } if (UdpPacket != NULL) { NetbufFree (UdpPacket); } if (!EFI_ERROR (Status) && !IsCompleted) { if (IsMcast) { Status = UdpIoRecvDatagram ( Instance->McastUdpIo, Mtftp6RrqInput, Instance, 0 ); } else { Status = UdpIoRecvDatagram ( Instance->UdpIo, Mtftp6RrqInput, Instance, 0 ); } } // // Clean up the current session if failed to continue. // if (EFI_ERROR (Status) || IsCompleted) { Mtftp6OperationClean (Instance, 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)); }
/** Starts the DHCPv6 standard S.A.R.R. process. The Start() function starts the DHCPv6 standard process. This function can be called only when the state of Dhcp6 instance is in the Dhcp6Init state. If the DHCP process completes successfully, the state of the Dhcp6 instance will be transferred through Dhcp6Selecting and Dhcp6Requesting to the Dhcp6Bound state. Refer to rfc-3315 for precise state transitions during this process. At the time when each event occurs in this process, the callback function that was set by EFI_DHCP6_PROTOCOL.Configure() will be called, and the user can take this opportunity to control the process. @param[in] This The pointer to Dhcp6 protocol. @retval EFI_SUCCESS The DHCPv6 standard process has started, or it has completed when CompletionEvent is NULL. @retval EFI_ACCESS_DENIED The EFI DHCPv6 Child instance hasn't been configured. @retval EFI_INVALID_PARAMETER This is NULL. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. @retval EFI_TIMEOUT The DHCPv6 configuration process failed because no response was received from the server within the specified timeout value. @retval EFI_ABORTED The user aborted the DHCPv6 process. @retval EFI_ALREADY_STARTED Some other Dhcp6 instance already started the DHCPv6 standard process. @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. @retval EFI_NO_MEDIA There was a media error. **/ EFI_STATUS EFIAPI EfiDhcp6Start ( IN EFI_DHCP6_PROTOCOL *This ) { EFI_STATUS Status; EFI_TPL OldTpl; DHCP6_INSTANCE *Instance; DHCP6_SERVICE *Service; if (This == NULL) { return EFI_INVALID_PARAMETER; } Instance = DHCP6_INSTANCE_FROM_THIS (This); Service = Instance->Service; // // The instance hasn't been configured. // if (Instance->Config == NULL) { return EFI_ACCESS_DENIED; } ASSERT (Instance->IaCb.Ia != NULL); // // The instance has already been started. // if (Instance->IaCb.Ia->State != Dhcp6Init) { return EFI_ALREADY_STARTED; } OldTpl = gBS->RaiseTPL (TPL_CALLBACK); Instance->UdpSts = EFI_ALREADY_STARTED; // // Need to clear initial time to make sure that elapsed-time // is set to 0 for first Solicit. // Instance->StartTime = 0; // // Send the solicit message to start S.A.R.R process. // Status = Dhcp6SendSolicitMsg (Instance); if (EFI_ERROR (Status)) { goto ON_ERROR; } // // Register receive callback for the stateful exchange process. // Status = UdpIoRecvDatagram( Service->UdpIo, Dhcp6ReceivePacket, Service, 0 ); if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) { goto ON_ERROR; } gBS->RestoreTPL (OldTpl); // // Poll udp out of the net tpl if synchronous call. // if (Instance->Config->IaInfoEvent == NULL) { while (Instance->UdpSts == EFI_ALREADY_STARTED) { Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6); } return Instance->UdpSts; } return EFI_SUCCESS; ON_ERROR: gBS->RestoreTPL (OldTpl); return Status; }
/** Starts the DHCPv6 standard S.A.R.R. process. The Start() function starts the DHCPv6 standard process. This function can be called only when the state of Dhcp6 instance is in the Dhcp6Init state. If the DHCP process completes successfully, the state of the Dhcp6 instance will be transferred through Dhcp6Selecting and Dhcp6Requesting to the Dhcp6Bound state. Refer to rfc-3315 for precise state transitions during this process. At the time when each event occurs in this process, the callback function that was set by EFI_DHCP6_PROTOCOL.Configure() will be called, and the user can take this opportunity to control the process. @param[in] This The pointer to Dhcp6 protocol. @retval EFI_SUCCESS The DHCPv6 standard process has started, or it has completed when CompletionEvent is NULL. @retval EFI_ACCESS_DENIED The EFI DHCPv6 Child instance hasn't been configured. @retval EFI_INVALID_PARAMETER This is NULL. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. @retval EFI_TIMEOUT The DHCPv6 configuration process failed because no response was received from the server within the specified timeout value. @retval EFI_ABORTED The user aborted the DHCPv6 process. @retval EFI_ALREADY_STARTED Some other Dhcp6 instance already started the DHCPv6 standard process. @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. @retval EFI_NO_MEDIA There was a media error. **/ EFI_STATUS EFIAPI EfiDhcp6Start ( IN EFI_DHCP6_PROTOCOL *This ) { EFI_STATUS Status; EFI_TPL OldTpl; DHCP6_INSTANCE *Instance; DHCP6_SERVICE *Service; EFI_STATUS MediaStatus; if (This == NULL) { return EFI_INVALID_PARAMETER; } Instance = DHCP6_INSTANCE_FROM_THIS (This); Service = Instance->Service; // // The instance hasn't been configured. // if (Instance->Config == NULL) { return EFI_ACCESS_DENIED; } ASSERT (Instance->IaCb.Ia != NULL); // // The instance has already been started. // if (Instance->IaCb.Ia->State != Dhcp6Init) { return EFI_ALREADY_STARTED; } OldTpl = gBS->RaiseTPL (TPL_CALLBACK); // // Check Media Satus. // MediaStatus = EFI_SUCCESS; NetLibDetectMediaWaitTimeout (Service->Controller, DHCP_CHECK_MEDIA_WAITING_TIME, &MediaStatus); if (MediaStatus != EFI_SUCCESS) { Status = EFI_NO_MEDIA; goto ON_ERROR; } Instance->UdpSts = EFI_ALREADY_STARTED; // // Send the solicit message to start S.A.R.R process. // Status = Dhcp6SendSolicitMsg (Instance); if (EFI_ERROR (Status)) { goto ON_ERROR; } // // Register receive callback for the stateful exchange process. // Status = UdpIoRecvDatagram( Service->UdpIo, Dhcp6ReceivePacket, Service, 0 ); if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) { goto ON_ERROR; } gBS->RestoreTPL (OldTpl); // // Poll udp out of the net tpl if synchronous call. // if (Instance->Config->IaInfoEvent == NULL) { while (Instance->UdpSts == EFI_ALREADY_STARTED) { Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6); } return Instance->UdpSts; } return EFI_SUCCESS; ON_ERROR: gBS->RestoreTPL (OldTpl); return Status; }