/** Process the ICMPv6 informational messages. If it is an ICMPv6 echo request, answer it. If it is a MLD message, trigger MLD routines to process it. If it is a ND message, trigger ND routines to process it. Otherwise, deliver it to upper layer. @param[in] IpSb The IP service that receivd the packet. @param[in] Head The IP head of the ICMPv6 informational packet. @param[in] Packet The content of the ICMPv6 informational packet with IP head removed. @retval EFI_INVALID_PARAMETER The packet is invalid. @retval EFI_SUCCESS The ICMPv6 informational message processed. @retval Others Failed to process ICMPv6 informational message. **/ EFI_STATUS Ip6ProcessIcmpInformation ( IN IP6_SERVICE *IpSb, IN EFI_IP6_HEADER *Head, IN NET_BUF *Packet ) { IP6_ICMP_INFORMATION_HEAD Icmp; EFI_STATUS Status; NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE); NET_CHECK_SIGNATURE (Packet, NET_BUF_SIGNATURE); ASSERT (Head != NULL); NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp); Status = EFI_INVALID_PARAMETER; switch (Icmp.Head.Type) { case ICMP_V6_ECHO_REQUEST: // // If ICMPv6 echo, reply it // if (Icmp.Head.Code == 0) { Status = Ip6IcmpReplyEcho (IpSb, Head, Packet); } break; case ICMP_V6_LISTENER_QUERY: Status = Ip6ProcessMldQuery (IpSb, Head, Packet); break; case ICMP_V6_LISTENER_REPORT: case ICMP_V6_LISTENER_REPORT_2: Status = Ip6ProcessMldReport (IpSb, Head, Packet); break; case ICMP_V6_NEIGHBOR_SOLICIT: Status = Ip6ProcessNeighborSolicit (IpSb, Head, Packet); break; case ICMP_V6_NEIGHBOR_ADVERTISE: Status = Ip6ProcessNeighborAdvertise (IpSb, Head, Packet); break; case ICMP_V6_ROUTER_ADVERTISE: Status = Ip6ProcessRouterAdvertise (IpSb, Head, Packet); break; case ICMP_V6_REDIRECT: Status = Ip6ProcessRedirect (IpSb, Head, Packet); break; case ICMP_V6_ECHO_REPLY: Status = Ip6Demultiplex (IpSb, Head, Packet); break; default: Status = EFI_INVALID_PARAMETER; break; } return Status; }
EFIAPI NetbufClone ( IN NET_BUF *Nbuf ) { NET_BUF *Clone; NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); Clone = AllocatePool (NET_BUF_SIZE (Nbuf->BlockOpNum)); if (Clone == NULL) { return NULL; } Clone->Signature = NET_BUF_SIGNATURE; Clone->RefCnt = 1; InitializeListHead (&Clone->List); Clone->Ip = Nbuf->Ip; Clone->Tcp = Nbuf->Tcp; CopyMem (Clone->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA); NET_GET_REF (Nbuf->Vector); Clone->Vector = Nbuf->Vector; Clone->BlockOpNum = Nbuf->BlockOpNum; Clone->TotalSize = Nbuf->TotalSize; CopyMem (Clone->BlockOp, Nbuf->BlockOp, sizeof (NET_BLOCK_OP) * Nbuf->BlockOpNum); return Clone; }
/** Free the net buffer and its associated NET_VECTOR. Decrease the reference count of the net buffer by one. Free the associated net vector and itself if the reference count of the net buffer is decreased to 0. The net vector free operation just decrease the reference count of the net vector by one and do the real resource free operation when the reference count of the net vector is 0. @param[in] Nbuf Pointer to the NET_BUF to be freed. **/ VOID EFIAPI NetbufFree ( IN NET_BUF *Nbuf ) { ASSERT (Nbuf != NULL); NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); ASSERT (Nbuf->RefCnt > 0); Nbuf->RefCnt--; if (Nbuf->RefCnt == 0) { // // Update Vector only when NBuf is to be released. That is, // all the sharing of Nbuf increse Vector's RefCnt by one // NetbufFreeVector (Nbuf->Vector); FreePool (Nbuf); } }
/** Free the net vector. Decrease the reference count of the net vector by one. The real resource free operation isn't performed until the reference count of the net vector is decreased to 0. @param[in] Vector Pointer to the NET_VECTOR to be freed. **/ VOID NetbufFreeVector ( IN NET_VECTOR *Vector ) { UINT32 Index; ASSERT (Vector != NULL); NET_CHECK_SIGNATURE (Vector, NET_VECTOR_SIGNATURE); ASSERT (Vector->RefCnt > 0); Vector->RefCnt--; if (Vector->RefCnt > 0) { return; } if (Vector->Free != NULL) { // // Call external free function to free the vector if it // isn't NULL. If NET_VECTOR_OWN_FIRST is set, release the // first block since it is allocated by us // if ((Vector->Flag & NET_VECTOR_OWN_FIRST) != 0) { gBS->FreePool (Vector->Block[0].Bulk); } Vector->Free (Vector->Arg); } else { // // Free each memory block associated with the Vector // for (Index = 0; Index < Vector->BlockNum; Index++) { gBS->FreePool (Vector->Block[Index].Bulk); } } FreePool (Vector); }
/** 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); } }
/** Convert the network configuration data into the IFR data. @param[in] Instance The IP4 config2 instance. @param[in, out] IfrNvData The IFR nv data. @retval EFI_SUCCESS The configure parameter to IFR data was set successfully. @retval EFI_INVALID_PARAMETER Source instance or target IFR data is not available. @retval Others Other errors as indicated. **/ EFI_STATUS Ip4Config2ConvertConfigNvDataToIfrNvData ( IN IP4_CONFIG2_INSTANCE *Instance, IN OUT IP4_CONFIG2_IFR_NVDATA *IfrNvData ) { IP4_SERVICE *IpSb; EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2; EFI_IP4_CONFIG2_INTERFACE_INFO *Ip4Info; EFI_IP4_CONFIG2_POLICY Policy; UINTN DataSize; UINTN GatewaySize; EFI_IPv4_ADDRESS GatewayAddress; EFI_STATUS Status; UINTN DnsSize; UINTN DnsCount; EFI_IPv4_ADDRESS *DnsAddress; Status = EFI_SUCCESS; Ip4Config2 = &Instance->Ip4Config2; Ip4Info = NULL; DnsAddress = NULL; GatewaySize = sizeof (EFI_IPv4_ADDRESS); if ((IfrNvData == NULL) || (Instance == NULL)) { return EFI_INVALID_PARAMETER; } NET_CHECK_SIGNATURE (Instance, IP4_CONFIG2_INSTANCE_SIGNATURE); IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance); if (IpSb->DefaultInterface->Configured) { IfrNvData->Configure = 1; } else { IfrNvData->Configure = 0; goto Exit; } // // Get the Policy info. // DataSize = sizeof (EFI_IP4_CONFIG2_POLICY); Status = Ip4Config2->GetData ( Ip4Config2, Ip4Config2DataTypePolicy, &DataSize, &Policy ); if (EFI_ERROR (Status)) { goto Exit; } if (Policy == Ip4Config2PolicyStatic) { IfrNvData->DhcpEnable = FALSE; } else if (Policy == Ip4Config2PolicyDhcp) { IfrNvData->DhcpEnable = TRUE; goto Exit; } // // Get the interface info. // DataSize = 0; Status = Ip4Config2->GetData ( Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, NULL ); if (Status != EFI_BUFFER_TOO_SMALL) { return Status; } Ip4Info = AllocateZeroPool (DataSize); if (Ip4Info == NULL) { Status = EFI_OUT_OF_RESOURCES; return Status; } Status = Ip4Config2->GetData ( Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Ip4Info ); if (EFI_ERROR (Status)) { goto Exit; } // // Get the Gateway info. // Status = Ip4Config2->GetData ( Ip4Config2, Ip4Config2DataTypeGateway, &GatewaySize, &GatewayAddress ); if (EFI_ERROR (Status)) { goto Exit; } // // Get the Dns info. // DnsSize = 0; Status = Ip4Config2->GetData ( Ip4Config2, Ip4Config2DataTypeDnsServer, &DnsSize, NULL ); if ((Status != EFI_BUFFER_TOO_SMALL) && (Status != EFI_NOT_FOUND)) { goto Exit; } DnsCount = (UINT32) (DnsSize / sizeof (EFI_IPv4_ADDRESS)); if (DnsSize > 0) { DnsAddress = AllocateZeroPool(DnsSize); if (DnsAddress == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Exit; } Status = Ip4Config2->GetData ( Ip4Config2, Ip4Config2DataTypeDnsServer, &DnsSize, DnsAddress ); if (EFI_ERROR (Status)) { goto Exit; } } Ip4Config2IpToStr (&Ip4Info->StationAddress, IfrNvData->StationAddress); Ip4Config2IpToStr (&Ip4Info->SubnetMask, IfrNvData->SubnetMask); Ip4Config2IpToStr (&GatewayAddress, IfrNvData->GatewayAddress); Status = Ip4Config2IpListToStr (DnsAddress, DnsCount, IfrNvData->DnsAddress); Exit: if (DnsAddress != NULL) { FreePool(DnsAddress); } if (Ip4Info != NULL) { FreePool(Ip4Info); } return 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); } }
STATIC VOID ArpCleanService ( IN ARP_SERVICE_DATA *ArpService ) /*++ Routine Description: Clean the arp service context data. Arguments: ArpService - Pointer to the buffer containing the arp service context data. Returns: None. --*/ { NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE); if (ArpService->PeriodicTimer != NULL) { // // Cancle and close the PeriodicTimer. // gBS->SetTimer (ArpService->PeriodicTimer, TimerCancel, 0); gBS->CloseEvent (ArpService->PeriodicTimer); } if (ArpService->RxToken.Event != NULL) { // // Cancle the RxToken and close the event in the RxToken. // ArpService->Mnp->Cancel (ArpService->Mnp, NULL); gBS->CloseEvent (ArpService->RxToken.Event); } if (ArpService->Mnp != NULL) { // // Reset the Mnp child and close the Mnp protocol. // ArpService->Mnp->Configure (ArpService->Mnp, NULL); gBS->CloseProtocol ( ArpService->MnpChildHandle, &gEfiManagedNetworkProtocolGuid, ArpService->ImageHandle, ArpService->ControllerHandle ); } if (ArpService->MnpChildHandle != NULL) { // // Destroy the mnp child. // NetLibDestroyServiceChild( ArpService->ControllerHandle, ArpService->ImageHandle, &gEfiManagedNetworkServiceBindingProtocolGuid, ArpService->MnpChildHandle ); } }