/** 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); } }
/** 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); } }
/** This function fills the CHAP authentication information into the login PDU during the security negotiation stage in the iSCSI connection login. @param[in] Conn The iSCSI connection. @param[in, out] Pdu The PDU to send out. @retval EFI_SUCCESS All check passed and the phase-related CHAP authentication info is filled into the iSCSI PDU. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. @retval EFI_PROTOCOL_ERROR Some kind of protocol error occurred. **/ EFI_STATUS IScsiCHAPToSendReq ( IN ISCSI_CONNECTION *Conn, IN OUT NET_BUF *Pdu ) { EFI_STATUS Status; ISCSI_SESSION *Session; ISCSI_LOGIN_REQUEST *LoginReq; ISCSI_CHAP_AUTH_DATA *AuthData; CHAR8 *Value; CHAR8 ValueStr[256]; CHAR8 *Response; UINT32 RspLen; CHAR8 *Challenge; UINT32 ChallengeLen; ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION); Session = Conn->Session; AuthData = &Session->AuthData.CHAP; LoginReq = (ISCSI_LOGIN_REQUEST *) NetbufGetByte (Pdu, 0, 0); if (LoginReq == NULL) { return EFI_PROTOCOL_ERROR; } Status = EFI_SUCCESS; RspLen = 2 * ISCSI_CHAP_RSP_LEN + 3; Response = AllocateZeroPool (RspLen); if (Response == NULL) { return EFI_OUT_OF_RESOURCES; } ChallengeLen = 2 * ISCSI_CHAP_RSP_LEN + 3; Challenge = AllocateZeroPool (ChallengeLen); if (Challenge == NULL) { FreePool (Response); return EFI_OUT_OF_RESOURCES; } switch (Conn->AuthStep) { case ISCSI_AUTH_INITIAL: // // It's the initial Login Request. Fill in the key=value pairs mandatory // for the initial Login Request. // IScsiAddKeyValuePair (Pdu, ISCSI_KEY_INITIATOR_NAME, mPrivate->InitiatorName); IScsiAddKeyValuePair (Pdu, ISCSI_KEY_SESSION_TYPE, "Normal"); IScsiAddKeyValuePair ( Pdu, ISCSI_KEY_TARGET_NAME, Session->ConfigData->SessionConfigData.TargetName ); if (Session->AuthType == ISCSI_AUTH_TYPE_NONE) { Value = ISCSI_KEY_VALUE_NONE; ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT); } else { Value = ISCSI_AUTH_METHOD_CHAP; } IScsiAddKeyValuePair (Pdu, ISCSI_KEY_AUTH_METHOD, Value); break; case ISCSI_CHAP_STEP_ONE: // // First step, send the Login Request with CHAP_A=<A1,A2...> key-value pair. // AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", ISCSI_CHAP_ALGORITHM_MD5); IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, ValueStr); Conn->AuthStep = ISCSI_CHAP_STEP_TWO; break; case ISCSI_CHAP_STEP_THREE: // // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target authentication is // required too. // // CHAP_N=<N> // IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_NAME, (CHAR8 *) &AuthData->AuthConfig->CHAPName); // // CHAP_R=<R> // IScsiBinToHex ((UINT8 *) AuthData->CHAPResponse, ISCSI_CHAP_RSP_LEN, Response, &RspLen); IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_RESPONSE, Response); if (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL) { // // CHAP_I=<I> // IScsiGenRandom ((UINT8 *) &AuthData->OutIdentifier, 1); AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier); IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr); // // CHAP_C=<C> // IScsiGenRandom ((UINT8 *) AuthData->OutChallenge, ISCSI_CHAP_RSP_LEN); AuthData->OutChallengeLength = ISCSI_CHAP_RSP_LEN; IScsiBinToHex ((UINT8 *) AuthData->OutChallenge, ISCSI_CHAP_RSP_LEN, Challenge, &ChallengeLen); IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_CHALLENGE, Challenge); Conn->AuthStep = ISCSI_CHAP_STEP_FOUR; } // // Set the stage transition flag. // ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT); break; default: Status = EFI_PROTOCOL_ERROR; break; } FreePool (Response); FreePool (Challenge); return Status; }
/** Reply an ICMPv6 echo request. @param[in] IpSb The IP service that received the packet. @param[in] Head The IP head of the ICMPv6 informational message. @param[in] Packet The content of the ICMPv6 message with the IP head removed. @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. @retval EFI_SUCCESS Successfully answered the ICMPv6 Echo request. @retval Others Failed to answer the ICMPv6 Echo request. **/ EFI_STATUS Ip6IcmpReplyEcho ( IN IP6_SERVICE *IpSb, IN EFI_IP6_HEADER *Head, IN NET_BUF *Packet ) { IP6_ICMP_INFORMATION_HEAD *Icmp; NET_BUF *Data; EFI_STATUS Status; EFI_IP6_HEADER ReplyHead; Status = EFI_OUT_OF_RESOURCES; // // make a copy the packet, it is really a bad idea to // send the MNP's buffer back to MNP. // Data = NetbufDuplicate (Packet, NULL, IP6_MAX_HEADLEN); if (Data == NULL) { goto Exit; } // // Change the ICMP type to echo reply, exchange the source // and destination, then send it. The source is updated to // use specific destination. See RFC1122. SRR/RR option // update is omitted. // Icmp = (IP6_ICMP_INFORMATION_HEAD *) NetbufGetByte (Data, 0, NULL); if (Icmp == NULL) { NetbufFree (Data); goto Exit; } Icmp->Head.Type = ICMP_V6_ECHO_REPLY; Icmp->Head.Checksum = 0; // // Generate the IPv6 basic header // If the Echo Reply is a response to a Echo Request sent to one of the node's unicast address, // the Source address of the Echo Reply must be the same address. // ZeroMem (&ReplyHead, sizeof (EFI_IP6_HEADER)); ReplyHead.PayloadLength = HTONS ((UINT16) (Packet->TotalSize)); ReplyHead.NextHeader = IP6_ICMP; ReplyHead.HopLimit = IpSb->CurHopLimit; IP6_COPY_ADDRESS (&ReplyHead.DestinationAddress, &Head->SourceAddress); if (Ip6IsOneOfSetAddress (IpSb, &Head->DestinationAddress, NULL, NULL)) { IP6_COPY_ADDRESS (&ReplyHead.SourceAddress, &Head->DestinationAddress); } // // If source is unspecified, Ip6Output will select a source for us // Status = Ip6Output ( IpSb, NULL, NULL, Data, &ReplyHead, NULL, 0, Ip6SysPacketSent, NULL ); Exit: NetbufFree (Packet); return Status; }