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