-/*++\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_ip.c\r
-\r
-Abstract:\r
-\r
---*/\r
-\r
-\r
-#include "Bc.h"\r
-\r
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
-BOOLEAN\r
-OnSameSubnet (\r
- IN UINTN IpLength,\r
- IN EFI_IP_ADDRESS *Ip1,\r
- IN EFI_IP_ADDRESS *Ip2,\r
- IN EFI_IP_ADDRESS *SubnetMask\r
- )\r
-/*++\r
-\r
- Routine Description:\r
- Check if two IP addresses are on the same subnet.\r
-\r
- Arguments:\r
- IpLength - Length of IP address in bytes.\r
- Ip1 - IP address to check.\r
- Ip2 - IP address to check.\r
- SubnetMask - Subnet mask to check with.\r
-\r
- Returns:\r
- TRUE - IP addresses are on the same subnet.\r
- FALSE - IP addresses are on different subnets.\r
-\r
---*/\r
-{\r
- if (IpLength == 0 || Ip1 == NULL || Ip2 == NULL || SubnetMask == NULL) {\r
- return FALSE;\r
- }\r
-\r
- while (IpLength-- != 0) {\r
- if ((Ip1->v6.Addr[IpLength] ^ Ip2->v6.Addr[IpLength]) & SubnetMask->v6.Addr[IpLength]) {\r
- return FALSE;\r
- }\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
-VOID\r
-IpAddRouter (\r
- IN PXE_BASECODE_DEVICE *Private,\r
- IN EFI_IP_ADDRESS *RouterIpPtr\r
- )\r
-/*++\r
-\r
- Routine Description:\r
- Add router to router table.\r
-\r
- Arguments:\r
- Private - Pointer PxeBc instance data.\r
- RouterIpPtr - Pointer to router IP address.\r
-\r
- Returns:\r
- Nothing\r
-\r
---*/\r
-{\r
- EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
- UINTN Index;\r
-\r
- if (Private == NULL || RouterIpPtr == NULL) {\r
- return ;\r
- }\r
-\r
- PxeBcMode = Private->EfiBc.Mode;\r
-\r
- //\r
- // if we are filled up or this is not on the same subnet, forget it\r
- //\r
- if ((PxeBcMode->RouteTableEntries == PXE_ROUTER_TABLE_SIZE) ||\r
- !OnSameSubnet(Private->IpLength, &PxeBcMode->StationIp, RouterIpPtr, &PxeBcMode->SubnetMask)) {\r
- return ;\r
- }\r
- //\r
- // make sure we don't already have it\r
- //\r
- for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {\r
- if (!CompareMem (\r
- &PxeBcMode->RouteTable[Index].GwAddr,\r
- RouterIpPtr,\r
- Private->IpLength\r
- )) {\r
- return ;\r
- }\r
- }\r
- //\r
- // keep it\r
- //\r
- ZeroMem (\r
- &PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries],\r
- sizeof (EFI_PXE_BASE_CODE_ROUTE_ENTRY)\r
- );\r
-\r
- CopyMem (\r
- &PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries++].GwAddr,\r
- RouterIpPtr,\r
- Private->IpLength\r
- );\r
-}\r
-\r
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
-\r
-//\r
-// return router ip to use for DestIp (0 if none)\r
-//\r
-STATIC\r
-EFI_IP_ADDRESS *\r
-GetRouterIp (\r
- PXE_BASECODE_DEVICE *Private,\r
- EFI_IP_ADDRESS *DestIpPtr\r
- )\r
-{\r
- EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
- UINTN Index;\r
-\r
- if (Private == NULL || DestIpPtr == NULL) {\r
- return NULL;\r
- }\r
-\r
- PxeBcMode = Private->EfiBc.Mode;\r
-\r
- for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {\r
- if (OnSameSubnet (\r
- Private->IpLength,\r
- &PxeBcMode->RouteTable[Index].IpAddr,\r
- DestIpPtr,\r
- &PxeBcMode->RouteTable[Index].SubnetMask\r
- )) {\r
- return &PxeBcMode->RouteTable[Index].GwAddr;\r
- }\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
-\r
-//\r
-// routine to send ipv4 packet\r
-// ipv4 header of length HdrLth in TransmitBufferPtr\r
-// routine fills in ipv4hdr Ver_Hdl, TotalLength, and Checksum, moves in Data\r
-// and gets dest MAC address\r
-//\r
-#define IP_TX_BUFFER ((IPV4_BUFFER *) Private->TransmitBufferPtr)\r
-#define IP_TX_HEADER IP_TX_BUFFER->IpHeader\r
-\r
-EFI_STATUS\r
-Ipv4Xmt (\r
- PXE_BASECODE_DEVICE *Private,\r
- UINT32 GatewayIp,\r
- UINTN IpHeaderLength,\r
- UINTN TotalHeaderLength,\r
- VOID *Data,\r
- UINTN DataLength,\r
- EFI_PXE_BASE_CODE_FUNCTION Function\r
- )\r
-{\r
- EFI_MAC_ADDRESS DestMac;\r
- EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
- EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
- EFI_STATUS StatCode;\r
- UINTN PacketLength;\r
-\r
- Snp = Private->SimpleNetwork;\r
- PxeBcMode = Private->EfiBc.Mode;\r
- StatCode = EFI_SUCCESS;\r
- PacketLength = TotalHeaderLength + DataLength;\r
-\r
- //\r
- // get dest MAC address\r
- // multicast - convert to hw equiv\r
- // unicast on same net, use arp\r
- // on different net, arp for router\r
- //\r
- if (IP_TX_HEADER.DestAddr.L == BROADCAST_IPv4) {\r
- CopyMem (&DestMac, &Snp->Mode->BroadcastAddress, sizeof (DestMac));\r
- } else if (IS_MULTICAST (&IP_TX_HEADER.DestAddr)) {\r
- StatCode = (*Snp->MCastIpToMac) (Snp, PxeBcMode->UsingIpv6, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr, &DestMac);\r
- } else {\r
- UINT32 Ip;\r
-\r
- if (OnSameSubnet (\r
- Private->IpLength,\r
- &PxeBcMode->StationIp,\r
- (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr,\r
- &PxeBcMode->SubnetMask\r
- )) {\r
- Ip = IP_TX_HEADER.DestAddr.L;\r
- } else if (GatewayIp != 0) {\r
- Ip = GatewayIp;\r
- } else {\r
- EFI_IP_ADDRESS *TmpIp;\r
-\r
- TmpIp = GetRouterIp (Private, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr);\r
-\r
- if (TmpIp == NULL) {\r
- DEBUG (\r
- (EFI_D_WARN,\r
- "\nIpv4Xmit() Exit #1 %xh (%r)",\r
- EFI_NO_RESPONSE,\r
- EFI_NO_RESPONSE)\r
- );\r
-\r
- return EFI_NO_RESPONSE;\r
- //\r
- // no router\r
- //\r
- }\r
-\r
- Ip = TmpIp->Addr[0];\r
- }\r
-\r
- if (!GetHwAddr (\r
- Private,\r
- (EFI_IP_ADDRESS *) &Ip,\r
- (EFI_MAC_ADDRESS *) &DestMac\r
- )) {\r
- if (!PxeBcMode->AutoArp) {\r
- DEBUG (\r
- (EFI_D_WARN,\r
- "\nIpv4Xmit() Exit #2 %xh (%r)",\r
- EFI_DEVICE_ERROR,\r
- EFI_DEVICE_ERROR)\r
- );\r
-\r
- return EFI_DEVICE_ERROR;\r
- } else {\r
- StatCode = DoArp (\r
- Private,\r
- (EFI_IP_ADDRESS *) &Ip,\r
- (EFI_MAC_ADDRESS *) &DestMac\r
- );\r
- }\r
- }\r
- }\r
-\r
- if (EFI_ERROR (StatCode)) {\r
- DEBUG ((EFI_D_WARN, "\nIpv4Xmit() Exit #3 %xh (%r)", StatCode, StatCode));\r
- return StatCode;\r
- }\r
- //\r
- // fill in packet info\r
- //\r
- SET_IPV4_VER_HDL (&IP_TX_HEADER, IpHeaderLength);\r
- IP_TX_HEADER.TotalLength = HTONS (PacketLength);\r
- IP_TX_HEADER.HeaderChecksum = IpChecksum ((UINT16 *) &IP_TX_HEADER, IpHeaderLength);\r
- CopyMem (((UINT8 *) &IP_TX_HEADER) + TotalHeaderLength, Data, DataLength);\r
-\r
- //\r
- // send it\r
- //\r
- return SendPacket (\r
- Private,\r
- (UINT8 *) &IP_TX_HEADER - Snp->Mode->MediaHeaderSize,\r
- &IP_TX_HEADER,\r
- PacketLength,\r
- &DestMac,\r
- PXE_PROTOCOL_ETHERNET_IP,\r
- Function\r
- );\r
-}\r
-\r
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
-\r
-//\r
-// send ipv4 packet with option\r
-//\r
-EFI_STATUS\r
-Ipv4SendWOp (\r
- PXE_BASECODE_DEVICE *Private,\r
- UINT32 GatewayIp,\r
- UINT8 *Msg,\r
- UINTN MessageLength,\r
- UINT8 Prot,\r
- UINT8 *Option,\r
- UINTN OptionLength,\r
- UINT32 DestIp,\r
- EFI_PXE_BASE_CODE_FUNCTION Function\r
- )\r
-{\r
- EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
- UINTN HdrLth;\r
-\r
- PxeBcMode = Private->EfiBc.Mode;\r
- HdrLth = sizeof (IPV4_HEADER) + OptionLength;\r
-\r
- ZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));\r
- IP_TX_HEADER.TimeToLive = PxeBcMode->TTL;\r
- IP_TX_HEADER.TypeOfService = PxeBcMode->ToS;\r
- IP_TX_HEADER.Protocol = Prot;\r
- IP_TX_HEADER.SrcAddr.L = *(UINT32 *) &PxeBcMode->StationIp;\r
- IP_TX_HEADER.DestAddr.L = DestIp;\r
- IP_TX_HEADER.Id = Random (Private);\r
- CopyMem (IP_TX_BUFFER->u.Data, Option, OptionLength);\r
- return Ipv4Xmt (\r
- Private,\r
- GatewayIp,\r
- HdrLth,\r
- HdrLth,\r
- Msg,\r
- MessageLength,\r
- Function\r
- );\r
-}\r
-\r
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
-\r
-//\r
-// send MessageLength message at MessagePtr - higher level protocol header already in TransmitBufferPtr, length HdrSize\r
-//\r
-EFI_STATUS\r
-Ip4Send (\r
- PXE_BASECODE_DEVICE *Private, // pointer to instance data\r
- UINTN MayFrag, //\r
- UINT8 Prot, // protocol\r
- UINT32 SrcIp, // Source IP address\r
- UINT32 DestIp, // Destination IP address\r
- UINT32 GatewayIp, // used if not NULL and needed\r
- UINTN HdrSize, // protocol header byte length\r
- UINT8 *MessagePtr, // pointer to data\r
- UINTN MessageLength // data byte length\r
- )\r
-{\r
- EFI_STATUS StatCode;\r
- UINTN TotDataLength;\r
-\r
- TotDataLength = HdrSize + MessageLength;\r
-\r
- if (TotDataLength > MAX_IPV4_DATA_SIZE) {\r
- DEBUG (\r
- (EFI_D_WARN,\r
- "\nIp4Send() Exit #1 %xh (%r)",\r
- EFI_BAD_BUFFER_SIZE,\r
- EFI_BAD_BUFFER_SIZE)\r
- );\r
-\r
- return EFI_BAD_BUFFER_SIZE;\r
- }\r
-\r
- ZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));\r
- IP_TX_HEADER.TimeToLive = DEFAULT_TTL;\r
- IP_TX_HEADER.Protocol = Prot;\r
- IP_TX_HEADER.SrcAddr.L = SrcIp;\r
- IP_TX_HEADER.DestAddr.L = DestIp;\r
- IP_TX_HEADER.Id = Random (Private);\r
-\r
- if (!MayFrag) {\r
- *(UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_NO_FRAG >> 8;\r
- }\r
- //\r
- // check for need to fragment\r
- //\r
- if (TotDataLength > MAX_IPV4_FRAME_DATA_SIZE) {\r
- UINTN DataLengthSent;\r
- UINT16 FragmentOffset;\r
-\r
- FragmentOffset = IP_MORE_FRAG;\r
- //\r
- // frag offset field\r
- //\r
- if (!MayFrag) {\r
- DEBUG (\r
- (EFI_D_WARN,\r
- "\nIp4Send() Exit #2 %xh (%r)",\r
- EFI_BAD_BUFFER_SIZE,\r
- EFI_BAD_BUFFER_SIZE)\r
- );\r
-\r
- return EFI_BAD_BUFFER_SIZE;\r
- }\r
- //\r
- // send out in fragments - first includes upper level header\r
- // all are max and include more frag bit except last\r
- //\r
- * (UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_MORE_FRAG >> 8;\r
-\r
-#define IPV4_FRAG_SIZE (MAX_IPV4_FRAME_DATA_SIZE & 0xfff8)\r
-#define IPV4_FRAG_OFF_INC (IPV4_FRAG_SIZE >> 3)\r
-\r
- DataLengthSent = IPV4_FRAG_SIZE - HdrSize;\r
-\r
- StatCode = Ipv4Xmt (\r
- Private,\r
- GatewayIp,\r
- sizeof (IPV4_HEADER),\r
- sizeof (IPV4_HEADER) + HdrSize,\r
- MessagePtr,\r
- DataLengthSent,\r
- Private->Function\r
- );\r
-\r
- if (EFI_ERROR (StatCode)) {\r
- DEBUG (\r
- (EFI_D_WARN,\r
- "\nIp4Send() Exit #3 %xh (%r)",\r
- StatCode,\r
- StatCode)\r
- );\r
-\r
- return StatCode;\r
- }\r
-\r
- MessagePtr += DataLengthSent;\r
- MessageLength -= DataLengthSent;\r
- FragmentOffset += IPV4_FRAG_OFF_INC;\r
- IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset);\r
-\r
- while (MessageLength > IPV4_FRAG_SIZE) {\r
- StatCode = Ipv4Xmt (\r
- Private,\r
- GatewayIp,\r
- sizeof (IPV4_HEADER),\r
- sizeof (IPV4_HEADER),\r
- MessagePtr,\r
- IPV4_FRAG_SIZE,\r
- Private->Function\r
- );\r
-\r
- if (EFI_ERROR (StatCode)) {\r
- DEBUG (\r
- (EFI_D_WARN,\r
- "\nIp4Send() Exit #3 %xh (%r)",\r
- StatCode,\r
- StatCode)\r
- );\r
-\r
- return StatCode;\r
- }\r
-\r
- MessagePtr += IPV4_FRAG_SIZE;\r
- MessageLength -= IPV4_FRAG_SIZE;\r
- FragmentOffset += IPV4_FRAG_OFF_INC;\r
- IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset);\r
- }\r
-\r
- * (UINT8 *) (&IP_TX_HEADER.FragmentFields) &= ~(IP_MORE_FRAG >> 8);\r
- HdrSize = 0;\r
- }\r
- //\r
- // transmit\r
- //\r
- return Ipv4Xmt (\r
- Private,\r
- GatewayIp,\r
- sizeof (IPV4_HEADER),\r
- sizeof (IPV4_HEADER) + HdrSize,\r
- MessagePtr,\r
- MessageLength,\r
- Private->Function\r
- );\r
-}\r
-\r
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
-\r
-//\r
-// return true if dst IP in receive header matched with what's enabled\r
-//\r
-STATIC\r
-BOOLEAN\r
-IPgood (\r
- PXE_BASECODE_DEVICE *Private,\r
- IPV4_HEADER *IpHeader\r
- )\r
-{\r
- EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
- UINTN Index;\r
-\r
- PxeBcMode = Private->EfiBc.Mode;\r
-\r
- if (PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) {\r
- return TRUE;\r
- }\r
-\r
- if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) &&\r
- IS_MULTICAST (&IpHeader->DestAddr)\r
- ) {\r
- return TRUE;\r
- }\r
-\r
- if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) &&\r
- PxeBcMode->StationIp.Addr[0] == IpHeader->DestAddr.L\r
- ) {\r
- return TRUE;\r
- }\r
-\r
- if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) && IpHeader->DestAddr.L == BROADCAST_IPv4) {\r
- return TRUE;\r
- }\r
-\r
- for (Index = 0; Index < PxeBcMode->IpFilter.IpCnt; ++Index) {\r
- if (IpHeader->DestAddr.L == PxeBcMode->IpFilter.IpList[Index].Addr[0]) {\r
- return TRUE;\r
- }\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
-\r
-//\r
-// receive up to MessageLength message into MessagePtr for protocol Prot\r
-// return message length, src/dest ips if select any, and pointer to protocol\r
-// header routine will filter based on source and/or dest ip if OpFlags set.\r
-//\r
-EFI_STATUS\r
-IpReceive (\r
- PXE_BASECODE_DEVICE *Private,\r
- PXE_OPFLAGS OpFlags,\r
- EFI_IP_ADDRESS *SrcIpPtr,\r
- EFI_IP_ADDRESS *DestIpPtr,\r
- UINT8 Prot,\r
- VOID *HeaderPtr,\r
- UINTN HdrSize,\r
- UINT8 *MessagePtr,\r
- UINTN *MessageLengthPtr,\r
- EFI_EVENT TimeoutEvent\r
- )\r
-{\r
- EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
- EFI_STATUS StatCode;\r
- UINTN ByteCount;\r
- UINTN FragmentCount;\r
- UINTN ExpectedPacketLength;\r
- UINTN Id;\r
- BOOLEAN GotFirstFragment;\r
- BOOLEAN GotLastFragment;\r
-\r
- DEBUG (\r
- (EFI_D_NET,\r
- "\nIpReceive() Hdr=%Xh HdrSz=%d Data=%Xh DataSz=%d",\r
- HeaderPtr,\r
- HdrSize,\r
- MessagePtr,\r
- *MessageLengthPtr)\r
- );\r
-\r
- PxeBcMode = Private->EfiBc.Mode;\r
- PxeBcMode->IcmpErrorReceived = FALSE;\r
-\r
- ExpectedPacketLength = 0;\r
- GotFirstFragment = FALSE;\r
- GotLastFragment = FALSE;\r
- FragmentCount = 0;\r
- ByteCount = 0;\r
- Id = 0;\r
-\r
- for (;;) {\r
- IPV4_HEADER IpHdr;\r
- UINTN FFlds;\r
- UINTN TotalLength;\r
- UINTN FragmentOffset;\r
- UINTN HeaderSize;\r
- UINTN BufferSize;\r
- UINTN IpHeaderLength;\r
- UINTN DataLength;\r
- UINT16 Protocol;\r
- UINT8 *NextHdrPtr;\r
- UINT8 *PacketPtr;\r
-\r
- StatCode = WaitForReceive (\r
- Private,\r
- Private->Function,\r
- TimeoutEvent,\r
- &HeaderSize,\r
- &BufferSize,\r
- &Protocol\r
- );\r
-\r
- if (EFI_ERROR (StatCode)) {\r
- return StatCode;\r
- }\r
-\r
- PacketPtr = Private->ReceiveBufferPtr + HeaderSize;\r
-\r
- if (Protocol == PXE_PROTOCOL_ETHERNET_ARP) {\r
- HandleArpReceive (\r
- Private,\r
- (ARP_PACKET *) PacketPtr,\r
- Private->ReceiveBufferPtr\r
- );\r
-\r
- continue;\r
- }\r
-\r
- if (Protocol != PXE_PROTOCOL_ETHERNET_IP) {\r
- continue;\r
- }\r
-\r
-#define IpRxHeader ((IPV4_HEADER *) PacketPtr)\r
-\r
- //\r
- // filter for version & check sum\r
- //\r
- IpHeaderLength = IPV4_HEADER_LENGTH (IpRxHeader);\r
-\r
- if ((IpRxHeader->VersionIhl >> 4) != IPVER4) {\r
- continue;\r
- }\r
-\r
- if (IpChecksum ((UINT16 *) IpRxHeader, IpHeaderLength)) {\r
- continue;\r
- }\r
-\r
- CopyMem (&IpHdr, IpRxHeader, sizeof (IpHdr));\r
- //IpHdr = *IpRxHeader;\r
- TotalLength = NTOHS (IpHdr.TotalLength);\r
-\r
- if (IpHdr.Protocol == PROT_TCP) {\r
- //\r
- // The NextHdrPtr is used to seed the header buffer we are passing back.\r
- // That being the case, we want to see everything in pPkt which contains\r
- // everything but the ethernet (or whatever) frame. IP + TCP in this case.\r
- //\r
- DataLength = TotalLength;\r
- NextHdrPtr = PacketPtr;\r
- } else {\r
- DataLength = TotalLength - IpHeaderLength;\r
- NextHdrPtr = PacketPtr + IpHeaderLength;\r
- }\r
- //\r
- // If this is an ICMP, it might not be for us.\r
- // Double check the state of the IP stack and the\r
- // packet fields before assuming it is an ICMP\r
- // error. ICMP requests are not supported by the\r
- // PxeBc IP stack and should be ignored.\r
- //\r
- if (IpHdr.Protocol == PROT_ICMP) {\r
- ICMPV4_HEADER *Icmpv4;\r
-\r
- Icmpv4 = (ICMPV4_HEADER *) NextHdrPtr;\r
-\r
- //\r
- // For now only obvious ICMP error replies will be accepted by\r
- // this stack. This still makes us vulnerable to DoS attacks.\r
- // But at least we will not be killed by DHCP daemons.\r
- //\r
- switch (Icmpv4->Type) {\r
- case ICMP_REDIRECT:\r
- case ICMP_ECHO:\r
- case ICMP_ROUTER_ADV:\r
- case ICMP_ROUTER_SOLICIT:\r
- case ICMP_TIMESTAMP:\r
- case ICMP_TIMESTAMP_REPLY:\r
- case ICMP_INFO_REQ:\r
- case ICMP_INFO_REQ_REPLY:\r
- case ICMP_SUBNET_MASK_REQ:\r
- case ICMP_SUBNET_MASK_REPLY:\r
- default:\r
- continue;\r
-\r
- //\r
- // %%TBD - This should be implemented.\r
- //\r
- case ICMP_ECHO_REPLY:\r
- continue;\r
-\r
- case ICMP_DEST_UNREACHABLE:\r
- case ICMP_TIME_EXCEEDED:\r
- case ICMP_PARAMETER_PROBLEM:\r
- case ICMP_SOURCE_QUENCH:\r
- PxeBcMode->IcmpErrorReceived = TRUE;\r
-\r
- CopyMem (\r
- &PxeBcMode->IcmpError,\r
- NextHdrPtr,\r
- sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)\r
- );\r
-\r
- DEBUG (\r
- (EFI_D_NET,\r
- "\nIpReceive() Exit #1 %Xh (%r)",\r
- EFI_ICMP_ERROR,\r
- EFI_ICMP_ERROR)\r
- );\r
- }\r
-\r
- return EFI_ICMP_ERROR;\r
- }\r
-\r
- if (IpHdr.Protocol == PROT_IGMP) {\r
- HandleIgmp (Private, (IGMPV2_MESSAGE *) NextHdrPtr, DataLength);\r
-\r
- DEBUG ((EFI_D_NET, "\n IGMP"));\r
- continue;\r
- }\r
- //\r
- // check for protocol\r
- //\r
- if (IpHdr.Protocol != Prot) {\r
- continue;\r
- }\r
- //\r
- // do filtering\r
- //\r
- if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) && SrcIpPtr && SrcIpPtr->Addr[0] != IpHdr.SrcAddr.L) {\r
- DEBUG ((EFI_D_NET, "\n Not expected source IP address."));\r
- continue;\r
- }\r
-\r
- if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) {\r
- if (!IPgood (Private, &IpHdr)) {\r
- continue;\r
- }\r
- } else if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP)) {\r
- if (DestIpPtr == NULL) {\r
- if (PxeBcMode->StationIp.Addr[0] != IpHdr.DestAddr.L) {\r
- continue;\r
- }\r
- } else if (DestIpPtr->Addr[0] != IpHdr.DestAddr.L) {\r
- continue;\r
- }\r
- }\r
- //\r
- // get some data we need\r
- //\r
- FFlds = NTOHS (IpHdr.FragmentFields);\r
- FragmentOffset = ((FFlds & IP_FRAG_OFF_MSK) << 3);\r
-\r
- /* Keep count of fragments that belong to this session.\r
- * If we get packets with a different IP ID number,\r
- * ignore them. Ignored packets should be handled\r
- * by the upper level protocol.\r
- */\r
- if (FragmentCount == 0) {\r
- Id = IpHdr.Id;\r
-\r
- if (DestIpPtr != NULL) {\r
- DestIpPtr->Addr[0] = IpHdr.DestAddr.L;\r
- }\r
-\r
- if (SrcIpPtr != NULL) {\r
- SrcIpPtr->Addr[0] = IpHdr.SrcAddr.L;\r
- }\r
- } else {\r
- if (IpHdr.Id != Id) {\r
- continue;\r
- }\r
- }\r
-\r
- ++FragmentCount;\r
-\r
- /* Fragment management.\r
- */\r
- if (FragmentOffset == 0) {\r
- /* This is the first fragment (may also be the\r
- * only fragment).\r
- */\r
- GotFirstFragment = TRUE;\r
-\r
- /* If there is a separate protocol header buffer,\r
- * copy the header, adjust the data pointer and\r
- * the data length.\r
- */\r
- if (HdrSize != 0) {\r
- CopyMem (HeaderPtr, NextHdrPtr, HdrSize);\r
-\r
- NextHdrPtr += HdrSize;\r
- DataLength -= HdrSize;\r
- }\r
- } else {\r
- /* If there is a separate protocol header buffer,\r
- * adjust the fragment offset.\r
- */\r
- FragmentOffset -= HdrSize;\r
- }\r
-\r
- /* See if this is the last fragment.\r
- */\r
- if (!(FFlds & IP_MORE_FRAG)) {\r
- //\r
- // This is the last fragment (may also be the only fragment).\r
- //\r
- GotLastFragment = TRUE;\r
-\r
- /* Compute the expected length of the assembled\r
- * packet. This will be used to decide if we\r
- * have gotten all of the fragments.\r
- */\r
- ExpectedPacketLength = FragmentOffset + DataLength;\r
- }\r
-\r
- DEBUG (\r
- (EFI_D_NET,\r
- "\n ID = %Xh Off = %d Len = %d",\r
- Id,\r
- FragmentOffset,\r
- DataLength)\r
- );\r
-\r
- /* Check for receive buffer overflow.\r
- */\r
- if (FragmentOffset + DataLength > *MessageLengthPtr) {\r
- /* There is not enough space in the receive\r
- * buffer for the fragment.\r
- */\r
- DEBUG (\r
- (EFI_D_NET,\r
- "\nIpReceive() Exit #3 %Xh (%r)",\r
- EFI_BUFFER_TOO_SMALL,\r
- EFI_BUFFER_TOO_SMALL)\r
- );\r
-\r
- return EFI_BUFFER_TOO_SMALL;\r
- }\r
-\r
- /* Copy data into receive buffer.\r
- */\r
- if (DataLength != 0) {\r
- DEBUG ((EFI_D_NET, " To = %Xh", MessagePtr + FragmentOffset));\r
-\r
- CopyMem (MessagePtr + FragmentOffset, NextHdrPtr, DataLength);\r
- ByteCount += DataLength;\r
- }\r
-\r
- /* If we have seen the first and last fragments and\r
- * the receive byte count is at least as large as the\r
- * expected byte count, return SUCCESS.\r
- *\r
- * We could be tricked by receiving a fragment twice\r
- * but the upper level protocol should figure this\r
- * out.\r
- */\r
- if (GotFirstFragment && GotLastFragment && ByteCount >= ExpectedPacketLength) {\r
- *MessageLengthPtr = ExpectedPacketLength;\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-}\r
-\r
-/* eof - pxe_bc_ip.c */\r