/** The event handle for UDP receive request. It will build a NET_BUF from the recieved UDP data, then deliver it to the receiver. @param[in] Context The UDP RX token. **/ VOID EFIAPI UdpIoOnDgramRcvdDpc ( IN VOID *Context ) { EFI_STATUS Status; VOID *Token; VOID *RxData; VOID *Session; UDP_RX_TOKEN *RxToken; UDP_END_POINT EndPoint; NET_BUF *Netbuf; RxToken = (UDP_RX_TOKEN *) Context; ZeroMem (&EndPoint, sizeof(UDP_END_POINT)); ASSERT ((RxToken->Signature == UDP_IO_RX_SIGNATURE) && (RxToken == RxToken->UdpIo->RecvRequest)); ASSERT ((RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) || (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION)); // // Clear the receive request first in case that the caller // wants to restart the receive in the callback. // RxToken->UdpIo->RecvRequest = NULL; if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { Token = &RxToken->Token.Udp4; RxData = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.RxData; Status = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status; } else { Token = &RxToken->Token.Udp6; RxData = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.RxData; Status = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status; } if (EFI_ERROR (Status) || RxData == NULL) { if (Status != EFI_ABORTED) { // // Invoke the CallBack only if the reception is not actively aborted. // RxToken->CallBack (NULL, NULL, Status, RxToken->Context); } UdpIoFreeRxToken (RxToken); return; } // // Build a NET_BUF from the UDP receive data, then deliver it up. // if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { if (((EFI_UDP4_RECEIVE_DATA *) RxData)->DataLength == 0) { // // Discard zero length data payload packet. // goto Resume; } Netbuf = NetbufFromExt ( (NET_FRAGMENT *)((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentTable, ((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentCount, 0, (UINT32) RxToken->HeadLen, UdpIoRecycleDgram, RxToken ); if (Netbuf == NULL) { gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal); RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context); UdpIoFreeRxToken (RxToken); return; } Session = &((EFI_UDP4_RECEIVE_DATA *) RxData)->UdpSession; EndPoint.LocalPort = ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort; EndPoint.RemotePort = ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort; CopyMem ( &EndPoint.LocalAddr, &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress, sizeof (EFI_IPv4_ADDRESS) ); CopyMem ( &EndPoint.RemoteAddr, &((EFI_UDP4_SESSION_DATA *) Session)->SourceAddress, sizeof (EFI_IPv4_ADDRESS) ); EndPoint.LocalAddr.Addr[0] = NTOHL (EndPoint.LocalAddr.Addr[0]); EndPoint.RemoteAddr.Addr[0] = NTOHL (EndPoint.RemoteAddr.Addr[0]); } else { if (((EFI_UDP6_RECEIVE_DATA *) RxData)->DataLength == 0) { // // Discard zero length data payload packet. // goto Resume; } Netbuf = NetbufFromExt ( (NET_FRAGMENT *)((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentTable, ((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentCount, 0, (UINT32) RxToken->HeadLen, UdpIoRecycleDgram, RxToken ); if (Netbuf == NULL) { gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal); RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context); UdpIoFreeRxToken (RxToken); return; } Session = &((EFI_UDP6_RECEIVE_DATA *) RxData)->UdpSession; EndPoint.LocalPort = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort; EndPoint.RemotePort = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort; CopyMem ( &EndPoint.LocalAddr, &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress, sizeof (EFI_IPv6_ADDRESS) ); CopyMem ( &EndPoint.RemoteAddr, &((EFI_UDP6_SESSION_DATA *) Session)->SourceAddress, sizeof (EFI_IPv6_ADDRESS) ); Ip6Swap128 (&EndPoint.LocalAddr.v6); Ip6Swap128 (&EndPoint.RemoteAddr.v6); } RxToken->CallBack (Netbuf, &EndPoint, EFI_SUCCESS, RxToken->Context); return; Resume: if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal); RxToken->UdpIo->Protocol.Udp4->Receive (RxToken->UdpIo->Protocol.Udp4, &RxToken->Token.Udp4); } else { gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal); RxToken->UdpIo->Protocol.Udp6->Receive (RxToken->UdpIo->Protocol.Udp6, &RxToken->Token.Udp6); } }
/** 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); } }