--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "Ip4Impl.h"\r
+\r
+\r
+/**\r
+ Return the cast type (Unicast/Boradcast) specific to an\r
+ interface. All the addresses are host byte ordered.\r
+\r
+ @param[in] IpAddr The IP address to classify in host byte order\r
+ @param[in] IpIf The interface that IpAddr received from\r
+\r
+ @return The cast type of this IP address specific to the interface.\r
+ @retval IP4_LOCAL_HOST The IpAddr equals to the interface's address\r
+ @retval IP4_SUBNET_BROADCAST The IpAddr is a directed subnet boradcast to the\r
+ interface\r
+ @retval IP4_NET_BROADCAST The IpAddr is a network broadcast to the interface\r
+ @retval 0 Otherwise.\r
+\r
+**/\r
+INTN\r
+Ip4GetNetCast (\r
+ IN IP4_ADDR IpAddr,\r
+ IN IP4_INTERFACE *IpIf\r
+ )\r
+{\r
+ if (IpAddr == IpIf->Ip) {\r
+ return IP4_LOCAL_HOST;\r
+\r
+ } else if (IpAddr == IpIf->SubnetBrdcast) {\r
+ return IP4_SUBNET_BROADCAST;\r
+\r
+ } else if (IpAddr == IpIf->NetBrdcast) {\r
+ return IP4_NET_BROADCAST;\r
+\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+ Find the cast type of the packet related to the local host.\r
+ This isn't the same as link layer cast type. For example, DHCP\r
+ server may send local broadcast to the local unicast MAC.\r
+\r
+ @param[in] IpSb The IP4 service binding instance that received the\r
+ packet\r
+ @param[in] Dst The destination address in the packet (host byte\r
+ order)\r
+ @param[in] Src The source address in the packet (host byte order)\r
+\r
+ @return The cast type for the Dst, it will return on the first non-promiscuous\r
+ cast type to a configured interface. If the packet doesn't match any of\r
+ the interface, multicast address and local broadcast address are checked.\r
+\r
+**/\r
+INTN\r
+Ip4GetHostCast (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_ADDR Dst,\r
+ IN IP4_ADDR Src\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ IP4_INTERFACE *IpIf;\r
+ INTN Type;\r
+ INTN Class;\r
+\r
+ Type = 0;\r
+\r
+ if (IpSb->MnpConfigData.EnablePromiscuousReceive) {\r
+ Type = IP4_PROMISCUOUS;\r
+ }\r
+\r
+ //\r
+ // Go through the interface list of the IP service, most likely.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
+ IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
+\r
+ //\r
+ // Skip the unconfigured interface and invalid source address:\r
+ // source address can't be broadcast.\r
+ //\r
+ if (!IpIf->Configured || IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {\r
+ continue;\r
+ }\r
+\r
+ if ((Class = Ip4GetNetCast (Dst, IpIf)) > Type) {\r
+ return Class;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If it is local broadcast address. The source address must\r
+ // be a unicast address on one of the direct connected network.\r
+ // If it is a multicast address, accept it only if we are in\r
+ // the group.\r
+ //\r
+ if (Dst == IP4_ALLONE_ADDRESS) {\r
+ IpIf = Ip4FindNet (IpSb, Src);\r
+\r
+ if (IpIf != NULL && !IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {\r
+ return IP4_LOCAL_BROADCAST;\r
+ }\r
+\r
+ } else if (IP4_IS_MULTICAST (Dst) && Ip4FindGroup (&IpSb->IgmpCtrl, Dst) != NULL) {\r
+ return IP4_MULTICAST;\r
+ }\r
+\r
+ return Type;\r
+}\r
+\r
+\r
+/**\r
+ Find an interface whose configured IP address is Ip.\r
+\r
+ @param[in] IpSb The IP4 service binding instance\r
+ @param[in] Ip The Ip address (host byte order) to find\r
+\r
+ @return The IP4_INTERFACE point if found, otherwise NULL\r
+\r
+**/\r
+IP4_INTERFACE *\r
+Ip4FindInterface (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_ADDR Ip\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ IP4_INTERFACE *IpIf;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
+ IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
+\r
+ if (IpIf->Configured && (IpIf->Ip == Ip)) {\r
+ return IpIf;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Find an interface that Ip is on that connected network.\r
+\r
+ @param[in] IpSb The IP4 service binding instance\r
+ @param[in] Ip The Ip address (host byte order) to find\r
+\r
+ @return The IP4_INTERFACE point if found, otherwise NULL\r
+\r
+**/\r
+IP4_INTERFACE *\r
+Ip4FindNet (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_ADDR Ip\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ IP4_INTERFACE *IpIf;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
+ IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
+\r
+ if (IpIf->Configured && IP4_NET_EQUAL (Ip, IpIf->Ip, IpIf->SubnetMask)) {\r
+ return IpIf;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Find an interface of the service with the same Ip/Netmask pair.\r
+\r
+ @param[in] IpSb Ip4 service binding instance\r
+ @param[in] Ip The Ip adress to find (host byte order)\r
+ @param[in] Netmask The network to find (host byte order)\r
+\r
+ @return The IP4_INTERFACE point if found, otherwise NULL\r
+\r
+**/\r
+IP4_INTERFACE *\r
+Ip4FindStationAddress (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_ADDR Ip,\r
+ IN IP4_ADDR Netmask\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ IP4_INTERFACE *IpIf;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
+ IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
+\r
+ if (IpIf->Configured && (IpIf->Ip == Ip) && (IpIf->SubnetMask == Netmask)) {\r
+ return IpIf;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Get the MAC address for a multicast IP address. Call\r
+ Mnp's McastIpToMac to find the MAC address in stead of\r
+ hard code the NIC to be Ethernet.\r
+\r
+ @param[in] Mnp The Mnp instance to get the MAC address.\r
+ @param[in] Multicast The multicast IP address to translate.\r
+ @param[out] Mac The buffer to hold the translated address.\r
+\r
+ @retval EFI_SUCCESS if the multicast IP is successfully translated to a\r
+ multicast MAC address.\r
+ @retval other Otherwise some error.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4GetMulticastMac (\r
+ IN EFI_MANAGED_NETWORK_PROTOCOL *Mnp,\r
+ IN IP4_ADDR Multicast,\r
+ OUT EFI_MAC_ADDRESS *Mac\r
+ )\r
+{\r
+ EFI_IP_ADDRESS EfiIp;\r
+\r
+ EFI_IP4 (EfiIp.v4) = HTONL (Multicast);\r
+ return Mnp->McastIpToMac (Mnp, FALSE, &EfiIp, Mac);\r
+}\r
+\r
+\r
+/**\r
+ Convert the multibyte field in IP header's byter order.\r
+ In spite of its name, it can also be used to convert from\r
+ host to network byte order.\r
+\r
+ @param[in] Head The IP head to convert\r
+\r
+ @return Point to the converted IP head\r
+\r
+**/\r
+IP4_HEAD *\r
+Ip4NtohHead (\r
+ IN IP4_HEAD *Head\r
+ )\r
+{\r
+ Head->TotalLen = NTOHS (Head->TotalLen);\r
+ Head->Id = NTOHS (Head->Id);\r
+ Head->Fragment = NTOHS (Head->Fragment);\r
+ Head->Src = NTOHL (Head->Src);\r
+ Head->Dst = NTOHL (Head->Dst);\r
+\r
+ return Head;\r
+}\r
+\r
+\r
+/**\r
+ Validate that Ip/Netmask pair is OK to be used as station\r
+ address. Only continuous netmasks are supported. and check\r
+ that StationAddress is a unicast address on the newtwork.\r
+\r
+ @param[in] Ip The IP address to validate.\r
+ @param[in] Netmask The netmaks of the IP.\r
+\r
+ @retval TRUE The Ip/Netmask pair is valid.\r
+ @retval FALSE The Ip/Netmask pair is invalid.\r
+\r
+**/\r
+BOOLEAN\r
+Ip4StationAddressValid (\r
+ IN IP4_ADDR Ip,\r
+ IN IP4_ADDR Netmask\r
+ )\r
+{\r
+ //\r
+ // Only support the station address with 0.0.0.0/0 to enable DHCP client.\r
+ //\r
+ if (Netmask == IP4_ALLZERO_ADDRESS) {\r
+ return (BOOLEAN) (Ip == IP4_ALLZERO_ADDRESS);\r
+ }\r
+\r
+ //\r
+ // Only support the continuous net masks\r
+ //\r
+ if (NetGetMaskLength (Netmask) == (IP4_MASK_MAX + 1)) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Station address can't be class D or class E address\r
+ //\r
+ if (NetGetIpClass (Ip) > IP4_ADDR_CLASSC) {\r
+ return FALSE;\r
+ }\r
+\r
+ return NetIp4IsUnicast (Ip, Netmask);\r
+}\r