From 878ddf1fc3540a715f63594ed22b6929e881afb4 Mon Sep 17 00:00:00 2001 From: bbahnsen Date: Fri, 21 Apr 2006 22:54:32 +0000 Subject: Initial import. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Universal/Network/PxeBc/Dxe/pxe_bc_arp.c | 617 +++++++++++++++++++++ 1 file changed, 617 insertions(+) create mode 100644 EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c (limited to 'EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c') diff --git a/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c new file mode 100644 index 0000000000..801f592042 --- /dev/null +++ b/EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c @@ -0,0 +1,617 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + pxe_bc_arp.c + +Abstract: + +--*/ + + +#include "bc.h" + +// +// Definitions for ARP +// Per RFC 826 +// +STATIC ARP_HEADER ArpHeader; + +#pragma pack(1) +STATIC struct { + UINT8 MediaHeader[14]; + ARP_HEADER ArpHeader; + UINT8 ArpData[64]; +} ArpReplyPacket; +#pragma pack() + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +InitArpHeader ( + VOID + ) +/*++ +Routine description: + Initialize ARP packet header. + +Parameters: + none + +Returns: + none + +--*/ +{ + ArpHeader.HwType = HTONS (ETHERNET_ADD_SPC); + ArpHeader.ProtType = HTONS (ETHER_TYPE_IP); + ArpHeader.HwAddLen = ENET_HWADDLEN; + ArpHeader.ProtAddLen = IPV4_PROTADDLEN; + ArpHeader.OpCode = HTONS (ARP_REQUEST); + + CopyMem (&ArpReplyPacket.ArpHeader, &ArpHeader, sizeof (ARP_HEADER)); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +VOID +HandleArpReceive ( + IN PXE_BASECODE_DEVICE *Private, + IN ARP_PACKET *ArpPacketPtr, + IN VOID *MediaHeader + ) +/*++ +Routine description: + Process ARP packet. + +Parameters: + Private := Pointer to PxeBc interface + ArpPacketPtr := Pointer to ARP packet + MediaHeader := Pointer to media header. +Returns: +--*/ +{ + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + EFI_SIMPLE_NETWORK_MODE *SnpMode; + EFI_MAC_ADDRESS TmpMacAddr; + UINTN Index; + UINT8 *SrcHwAddr; + UINT8 *SrcPrAddr; + UINT8 *DstHwAddr; + UINT8 *DstPrAddr; + UINT8 *TmpPtr; + + // + // + // + PxeBcMode = Private->EfiBc.Mode; + SnpMode = Private->SimpleNetwork->Mode; + + // + // For now only ethernet addresses are supported. + // This will need to be updated when other media + // layers are supported by PxeBc, Snp and UNDI. + // + if (ArpPacketPtr->ArpHeader.HwType != HTONS (ETHERNET_ADD_SPC)) { + return ; + } + // + // For now only IP protocol addresses are supported. + // This will need to be updated when other protocol + // types are supported by PxeBc, Snp and UNDI. + // + if (ArpPacketPtr->ArpHeader.ProtType != HTONS (ETHER_TYPE_IP)) { + return ; + } + // + // For now only SNP hardware address sizes are supported. + // + if (ArpPacketPtr->ArpHeader.HwAddLen != SnpMode->HwAddressSize) { + return ; + } + // + // For now only PxeBc protocol address sizes are supported. + // + if (ArpPacketPtr->ArpHeader.ProtAddLen != Private->IpLength) { + return ; + } + // + // Ignore out of range opcodes + // + switch (ArpPacketPtr->ArpHeader.OpCode) { + case HTONS (ARP_REPLY): + case HTONS (ARP_REQUEST): + break; + + default: + return ; + } + // + // update entry in our ARP cache if we have it + // + SrcHwAddr = (UINT8 *) &ArpPacketPtr->SrcHardwareAddr; + SrcPrAddr = SrcHwAddr + SnpMode->HwAddressSize; + + for (Index = 0; Index < PxeBcMode->ArpCacheEntries; ++Index) { + if (CompareMem ( + &PxeBcMode->ArpCache[Index].IpAddr, + SrcPrAddr, + Private->IpLength + )) { + continue; + } + + CopyMem ( + &PxeBcMode->ArpCache[Index].MacAddr, + SrcHwAddr, + SnpMode->HwAddressSize + ); + + break; + } + // + // Done if ARP packet was not for us. + // + DstHwAddr = SrcPrAddr + Private->IpLength; + DstPrAddr = DstHwAddr + SnpMode->HwAddressSize; + + if (CompareMem (DstPrAddr, &PxeBcMode->StationIp, Private->IpLength)) { + return ; + // + // not for us + // + } + // + // for us - if we did not update entry, add it + // + if (Index == PxeBcMode->ArpCacheEntries) { + // + // if we have a full table, get rid of oldest + // + if (Index == PXE_ARP_CACHE_SIZE) { + Index = Private->OldestArpEntry; + + if (++Private->OldestArpEntry == PXE_ARP_CACHE_SIZE) { + Private->OldestArpEntry = 0; + } + } else { + ++PxeBcMode->ArpCacheEntries; + } + + CopyMem ( + &PxeBcMode->ArpCache[Index].MacAddr, + SrcHwAddr, + SnpMode->HwAddressSize + ); + + CopyMem ( + &PxeBcMode->ArpCache[Index].IpAddr, + SrcPrAddr, + Private->IpLength + ); + } + // + // if this is not a request or we don't yet have an IP, finished + // + if (ArpPacketPtr->ArpHeader.OpCode != HTONS (ARP_REQUEST) || !Private->GoodStationIp) { + return ; + } + // + // Assemble ARP reply. + // + // + // Create media header. [ dest mac | src mac | prot ] + // + CopyMem ( + &ArpReplyPacket.MediaHeader[0], + SrcHwAddr, + SnpMode->HwAddressSize + ); + + CopyMem ( + &ArpReplyPacket.MediaHeader[SnpMode->HwAddressSize], + &SnpMode->CurrentAddress, + SnpMode->HwAddressSize + ); + + CopyMem ( + &ArpReplyPacket.MediaHeader[2 * SnpMode->HwAddressSize], + &((UINT8 *) MediaHeader)[2 * SnpMode->HwAddressSize], + sizeof (UINT16) + ); + + // + // ARP reply header is almost filled in, + // just insert the correct opcode. + // + ArpReplyPacket.ArpHeader.OpCode = HTONS (ARP_REPLY); + + // + // Now fill in ARP data. [ src mac | src prot | dest mac | dest prot ] + // + TmpPtr = ArpReplyPacket.ArpData; + CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize); + + TmpPtr += SnpMode->HwAddressSize; + CopyMem (TmpPtr, &PxeBcMode->StationIp, Private->IpLength); + + TmpPtr += Private->IpLength; + CopyMem (TmpPtr, SrcHwAddr, SnpMode->HwAddressSize); + + TmpPtr += SnpMode->HwAddressSize; + CopyMem (TmpPtr, SrcPrAddr, Private->IpLength); + + // + // Now send out the ARP reply. + // + CopyMem (&TmpMacAddr, SrcHwAddr, sizeof (EFI_MAC_ADDRESS)); + + SendPacket ( + Private, + &ArpReplyPacket.MediaHeader, + &ArpReplyPacket.ArpHeader, + sizeof (ARP_HEADER) + 2 * (Private->IpLength + SnpMode->HwAddressSize), + &TmpMacAddr, + PXE_PROTOCOL_ETHERNET_ARP, + EFI_PXE_BASE_CODE_FUNCTION_ARP + ); + + // + // Give time (100 microseconds) for ARP reply to get onto wire. + // + gBS->Stall (1000); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +BOOLEAN +GetHwAddr ( + IN PXE_BASECODE_DEVICE *Private, + IN EFI_IP_ADDRESS *ProtocolAddrPtr, + OUT EFI_MAC_ADDRESS *HardwareAddrPtr + ) +/*++ +Routine description: + Locate IP address in ARP cache and return MAC address. + +Parameters: + Private := Pointer to PxeBc interface + ProtocolAddrPtr := Pointer to IP address + HardwareAddrPtr := Pointer to MAC address storage + +Returns: + TRUE := If IP address was found and MAC address was stored + FALSE := If IP address was not found +--*/ +{ + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + UINTN HardwareAddrLength; + UINTN Index; + + PxeBcMode = Private->EfiBc.Mode; + HardwareAddrLength = Private->SimpleNetwork->Mode->HwAddressSize; + + for (Index = 0; Index < PxeBcMode->ArpCacheEntries; ++Index) { + if (!CompareMem ( + ProtocolAddrPtr, + &PxeBcMode->ArpCache[Index].IpAddr, + Private->IpLength + )) { + CopyMem ( + HardwareAddrPtr, + &PxeBcMode->ArpCache[Index].MacAddr, + HardwareAddrLength + ); + + return TRUE; + } + } + + return FALSE; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +STATIC +EFI_STATUS +SendRequest ( + IN PXE_BASECODE_DEVICE *Private, + IN EFI_IP_ADDRESS *ProtocolAddrPtr, + IN EFI_MAC_ADDRESS *HardwareAddrPtr + ) +/*++ +Routine description: + Transmit ARP request packet + +Parameters: + Private := Pointer to PxeBc interface + ProtocolAddrPtr := Pointer IP address to find + HardwareAddrPtr := Pointer to MAC address to find + +Returns: + EFI_SUCCESS := ARP request sent + other := ARP request could not be sent +--*/ +{ + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + EFI_SIMPLE_NETWORK_MODE *SnpMode; + ARP_PACKET *ArpPacket; + EFI_STATUS Status; + UINTN HardwareAddrLength; + UINT8 *SrcProtocolAddrPtr; + UINT8 *DestHardwareAddrptr; + UINT8 *DestProtocolAddrPtr; + + // + // + // + PxeBcMode = Private->EfiBc.Mode; + SnpMode = Private->SimpleNetwork->Mode; + HardwareAddrLength = SnpMode->HwAddressSize; + + // + // Allocate ARP buffer + // + if (Private->ArpBuffer == NULL) { + Status = gBS->AllocatePool ( + EfiBootServicesData, + SnpMode->MediaHeaderSize + sizeof (ARP_PACKET), + (VOID **) &Private->ArpBuffer + ); + + if (EFI_ERROR (Status)) { + return Status; + } + } + + ArpPacket = (VOID *) (Private->ArpBuffer + SnpMode->MediaHeaderSize); + + // + // for now, only handle one kind of hw and pr address + // + ArpPacket->ArpHeader = ArpHeader; + ArpPacket->ArpHeader.HwAddLen = (UINT8) HardwareAddrLength; + ArpPacket->ArpHeader.ProtAddLen = (UINT8) Private->IpLength; + + // + // rest more generic + // + SrcProtocolAddrPtr = (UINT8 *) (&ArpPacket->SrcHardwareAddr) + HardwareAddrLength; + DestHardwareAddrptr = SrcProtocolAddrPtr + Private->IpLength; + DestProtocolAddrPtr = DestHardwareAddrptr + HardwareAddrLength; + + CopyMem (DestProtocolAddrPtr, ProtocolAddrPtr, Private->IpLength); + CopyMem (DestHardwareAddrptr, HardwareAddrPtr, HardwareAddrLength); + CopyMem (SrcProtocolAddrPtr, &PxeBcMode->StationIp, Private->IpLength); + CopyMem ( + &ArpPacket->SrcHardwareAddr, + &SnpMode->CurrentAddress, + HardwareAddrLength + ); + + return SendPacket ( + Private, + Private->ArpBuffer, + ArpPacket, + sizeof (ARP_HEADER) + ((Private->IpLength + HardwareAddrLength) << 1), + &SnpMode->BroadcastAddress, + PXE_PROTOCOL_ETHERNET_ARP, + EFI_PXE_BASE_CODE_FUNCTION_ARP + ); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +// +// check for address - if not there, send ARP request, wait and check again +// not how it would be done in a full system +// +#define ARP_REQUEST_TIMEOUT_MS 500 // try for half a second + + //////////////////////////////////////////////////////////// +// +// BC Arp Routine +// +EFI_STATUS +EFIAPI +BcArp ( + IN EFI_PXE_BASE_CODE_PROTOCOL * This, + IN EFI_IP_ADDRESS * ProtocolAddrPtr, + OUT EFI_MAC_ADDRESS * HardwareAddrPtr OPTIONAL + ) +/*++ +Routine description: + PxeBc ARP API. + +Parameters: + This := Pointer to PxeBc interface + ProtocolAddrPtr := Pointer to IP address to find + HardwareAddrPtr := Pointer to MAC address found. + +Returns: +--*/ +{ + EFI_MAC_ADDRESS Mac; + EFI_STATUS StatCode; + PXE_BASECODE_DEVICE *Private; + + // + // Lock the instance data and make sure started + // + StatCode = EFI_SUCCESS; + + if (This == NULL) { + DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL")); + return EFI_INVALID_PARAMETER; + } + + Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE); + + if (Private == NULL) { + DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL")); + return EFI_INVALID_PARAMETER; + } + + EfiAcquireLock (&Private->Lock); + + if (This->Mode == NULL || !This->Mode->Started) { + DEBUG ((EFI_D_ERROR, "BC was not started.")); + EfiReleaseLock (&Private->Lock); + return EFI_NOT_STARTED; + } + + DEBUG ((EFI_D_INFO, "\nBcArp()")); + + // + // Issue BC command + // + if (ProtocolAddrPtr == NULL) { + DEBUG ( + (EFI_D_INFO, + "\nBcArp() Exit #1 %Xh (%r)", + EFI_INVALID_PARAMETER, + EFI_INVALID_PARAMETER) + ); + + EfiReleaseLock (&Private->Lock); + return EFI_INVALID_PARAMETER; + } + + if (HardwareAddrPtr == NULL) { + HardwareAddrPtr = &Mac; + } + + ZeroMem (HardwareAddrPtr, Private->SimpleNetwork->Mode->HwAddressSize); + + if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) { + DEBUG ( + (EFI_D_INFO, + "\nBcArp() Exit #2 %Xh (%r)", + EFI_SUCCESS, + EFI_SUCCESS) + ); + + EfiReleaseLock (&Private->Lock); + return EFI_SUCCESS; + } + + StatCode = DoArp (Private, ProtocolAddrPtr, HardwareAddrPtr); + + DEBUG ((EFI_D_INFO, "\nBcArp() Exit #3 %Xh (%r)", StatCode, StatCode)); + + EfiReleaseLock (&Private->Lock); + return StatCode; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +EFI_STATUS +DoArp ( + IN PXE_BASECODE_DEVICE *Private, + IN EFI_IP_ADDRESS *ProtocolAddrPtr, + OUT EFI_MAC_ADDRESS *HardwareAddrPtr + ) +/*++ +Routine description: + Internal ARP implementation. + +Parameters: + Private := Pointer to PxeBc interface + ProtocolAddrPtr := Pointer to IP address to find + HardwareAddrPtr := Pointer to MAC address found + +Returns: + EFI_SUCCESS := MAC address found + other := MAC address could not be found +--*/ +{ + EFI_STATUS StatCode; + EFI_EVENT TimeoutEvent; + UINTN HeaderSize; + UINTN BufferSize; + UINT16 Protocol; + + DEBUG ((EFI_D_INFO, "\nDoArp()")); + + // + // + // + StatCode = SendRequest (Private, ProtocolAddrPtr, HardwareAddrPtr); + + if (EFI_ERROR (StatCode)) { + DEBUG ((EFI_D_INFO, "\nDoArp() Exit #1 %Xh (%r)", StatCode, StatCode)); + return StatCode; + } + // + // + // + StatCode = gBS->CreateEvent ( + EFI_EVENT_TIMER, + EFI_TPL_CALLBACK, + NULL, + NULL, + &TimeoutEvent + ); + + if (EFI_ERROR (StatCode)) { + return StatCode; + } + + StatCode = gBS->SetTimer ( + TimeoutEvent, + TimerRelative, + ARP_REQUEST_TIMEOUT_MS * 10000 + ); + + if (EFI_ERROR (StatCode)) { + gBS->CloseEvent (TimeoutEvent); + return StatCode; + } + // + // + // + for (;;) { + StatCode = WaitForReceive ( + Private, + EFI_PXE_BASE_CODE_FUNCTION_ARP, + TimeoutEvent, + &HeaderSize, + &BufferSize, + &Protocol + ); + + if (EFI_ERROR (StatCode)) { + break; + } + + if (Protocol != PXE_PROTOCOL_ETHERNET_ARP) { + continue; + } + + HandleArpReceive ( + Private, + (ARP_PACKET *) (Private->ReceiveBufferPtr + HeaderSize), + Private->ReceiveBufferPtr + ); + + if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) { + break; + } + } + + DEBUG ( + (EFI_D_INFO, + "\nDoArp() Exit #2 %Xh, (%r)", + StatCode, + StatCode) + ); + + gBS->CloseEvent (TimeoutEvent); + + return StatCode; +} + +/* eof - pxe_bc_arp.c */ -- cgit v1.2.3