NetworkPkg: Move Network library and drivers from MdeModulePkg to NetworkPkg
[mirror_edk2.git] / NetworkPkg / Ip4Dxe / Ip4Common.c
1 /** @file\r
2 \r
3 Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>\r
4 SPDX-License-Identifier: BSD-2-Clause-Patent\r
5 \r
6 **/\r
7 \r
8 #include "Ip4Impl.h"\r
9 \r
10 \r
11 /**\r
12   Return the cast type (Unicast/Boradcast) specific to an\r
13   interface. All the addresses are host byte ordered.\r
14 \r
15   @param[in]  IpAddr                The IP address to classify in host byte order\r
16   @param[in]  IpIf                  The interface that IpAddr received from\r
17 \r
18   @return The cast type of this IP address specific to the interface.\r
19   @retval IP4_LOCAL_HOST        The IpAddr equals to the interface's address\r
20   @retval IP4_SUBNET_BROADCAST  The IpAddr is a directed subnet boradcast to  the\r
21                                 interface\r
22   @retval IP4_NET_BROADCAST     The IpAddr is a network broadcast to the interface\r
23   @retval 0                     Otherwise.\r
24 \r
25 **/\r
26 INTN\r
27 Ip4GetNetCast (\r
28   IN  IP4_ADDR          IpAddr,\r
29   IN  IP4_INTERFACE     *IpIf\r
30   )\r
31 {\r
32   if (IpAddr == IpIf->Ip) {\r
33     return IP4_LOCAL_HOST;\r
34 \r
35   } else if (IpAddr == IpIf->SubnetBrdcast) {\r
36     return IP4_SUBNET_BROADCAST;\r
37 \r
38   } else if (IpAddr == IpIf->NetBrdcast) {\r
39     return IP4_NET_BROADCAST;\r
40 \r
41   }\r
42 \r
43   return 0;\r
44 }\r
45 \r
46 \r
47 /**\r
48   Find the cast type of the packet related to the local host.\r
49   This isn't the same as link layer cast type. For example, DHCP\r
50   server may send local broadcast to the local unicast MAC.\r
51 \r
52   @param[in]  IpSb                  The IP4 service binding instance that received the\r
53                                     packet\r
54   @param[in]  Dst                   The destination address in the packet (host byte\r
55                                     order)\r
56   @param[in]  Src                   The source address in the packet (host byte order)\r
57 \r
58   @return The cast type for the Dst, it will return on the first non-promiscuous\r
59           cast type to a configured interface. If the packet doesn't match any of\r
60           the interface, multicast address and local broadcast address are checked.\r
61 \r
62 **/\r
63 INTN\r
64 Ip4GetHostCast (\r
65   IN  IP4_SERVICE       *IpSb,\r
66   IN  IP4_ADDR          Dst,\r
67   IN  IP4_ADDR          Src\r
68   )\r
69 {\r
70   LIST_ENTRY            *Entry;\r
71   IP4_INTERFACE         *IpIf;\r
72   INTN                  Type;\r
73   INTN                  Class;\r
74 \r
75   Type = 0;\r
76 \r
77   if (IpSb->MnpConfigData.EnablePromiscuousReceive) {\r
78     Type = IP4_PROMISCUOUS;\r
79   }\r
80 \r
81   //\r
82   // Go through the interface list of the IP service, most likely.\r
83   //\r
84   NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
85     IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
86 \r
87     //\r
88     // Skip the unconfigured interface and invalid source address:\r
89     // source address can't be broadcast.\r
90     //\r
91     if (!IpIf->Configured || IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {\r
92       continue;\r
93     }\r
94 \r
95     if ((Class = Ip4GetNetCast (Dst, IpIf)) > Type) {\r
96       return Class;\r
97     }\r
98   }\r
99 \r
100   //\r
101   // If it is local broadcast address. The source address must\r
102   // be a unicast address on one of the direct connected network.\r
103   // If it is a multicast address, accept it only if we are in\r
104   // the group.\r
105   //\r
106   if (Dst == IP4_ALLONE_ADDRESS) {\r
107     IpIf = Ip4FindNet (IpSb, Src);\r
108 \r
109     if (IpIf != NULL && !IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {\r
110       return IP4_LOCAL_BROADCAST;\r
111     }\r
112 \r
113   } else if (IP4_IS_MULTICAST (Dst) && Ip4FindGroup (&IpSb->IgmpCtrl, Dst) != NULL) {\r
114     return IP4_MULTICAST;\r
115   }\r
116 \r
117   return Type;\r
118 }\r
119 \r
120 \r
121 /**\r
122   Find an interface whose configured IP address is Ip.\r
123 \r
124   @param[in]  IpSb                  The IP4 service binding instance\r
125   @param[in]  Ip                    The Ip address (host byte order) to find\r
126 \r
127   @return The IP4_INTERFACE point if found, otherwise NULL\r
128 \r
129 **/\r
130 IP4_INTERFACE *\r
131 Ip4FindInterface (\r
132   IN IP4_SERVICE        *IpSb,\r
133   IN IP4_ADDR           Ip\r
134   )\r
135 {\r
136   LIST_ENTRY            *Entry;\r
137   IP4_INTERFACE         *IpIf;\r
138 \r
139   NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
140     IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
141 \r
142     if (IpIf->Configured && (IpIf->Ip == Ip)) {\r
143       return IpIf;\r
144     }\r
145   }\r
146 \r
147   return NULL;\r
148 }\r
149 \r
150 \r
151 /**\r
152   Find an interface that Ip is on that connected network.\r
153 \r
154   @param[in]  IpSb                  The IP4 service binding instance\r
155   @param[in]  Ip                    The Ip address (host byte order) to find\r
156 \r
157   @return The IP4_INTERFACE point if found, otherwise NULL\r
158 \r
159 **/\r
160 IP4_INTERFACE *\r
161 Ip4FindNet (\r
162   IN IP4_SERVICE        *IpSb,\r
163   IN IP4_ADDR           Ip\r
164   )\r
165 {\r
166   LIST_ENTRY            *Entry;\r
167   IP4_INTERFACE         *IpIf;\r
168 \r
169   NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
170     IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
171 \r
172     if (IpIf->Configured && IP4_NET_EQUAL (Ip, IpIf->Ip, IpIf->SubnetMask)) {\r
173       return IpIf;\r
174     }\r
175   }\r
176 \r
177   return NULL;\r
178 }\r
179 \r
180 \r
181 /**\r
182   Find an interface of the service with the same Ip/Netmask pair.\r
183 \r
184   @param[in]  IpSb                  Ip4 service binding instance\r
185   @param[in]  Ip                    The Ip adress to find (host byte order)\r
186   @param[in]  Netmask               The network to find (host byte order)\r
187 \r
188   @return The IP4_INTERFACE point if found, otherwise NULL\r
189 \r
190 **/\r
191 IP4_INTERFACE *\r
192 Ip4FindStationAddress (\r
193   IN IP4_SERVICE        *IpSb,\r
194   IN IP4_ADDR           Ip,\r
195   IN IP4_ADDR           Netmask\r
196   )\r
197 {\r
198   LIST_ENTRY      *Entry;\r
199   IP4_INTERFACE   *IpIf;\r
200 \r
201   NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
202     IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
203 \r
204     if (IpIf->Configured && (IpIf->Ip == Ip) && (IpIf->SubnetMask == Netmask)) {\r
205       return IpIf;\r
206     }\r
207   }\r
208 \r
209   return NULL;\r
210 }\r
211 \r
212 \r
213 /**\r
214   Get the MAC address for a multicast IP address. Call\r
215   Mnp's McastIpToMac to find the MAC address in stead of\r
216   hard code the NIC to be Ethernet.\r
217 \r
218   @param[in]  Mnp                   The Mnp instance to get the MAC address.\r
219   @param[in]  Multicast             The multicast IP address to translate.\r
220   @param[out] Mac                   The buffer to hold the translated address.\r
221 \r
222   @retval EFI_SUCCESS if the multicast IP is successfully translated to a\r
223                       multicast MAC address.\r
224   @retval other       Otherwise some error.\r
225 \r
226 **/\r
227 EFI_STATUS\r
228 Ip4GetMulticastMac (\r
229   IN  EFI_MANAGED_NETWORK_PROTOCOL *Mnp,\r
230   IN  IP4_ADDR                     Multicast,\r
231   OUT EFI_MAC_ADDRESS              *Mac\r
232   )\r
233 {\r
234   EFI_IP_ADDRESS        EfiIp;\r
235 \r
236   EFI_IP4 (EfiIp.v4) = HTONL (Multicast);\r
237   return Mnp->McastIpToMac (Mnp, FALSE, &EfiIp, Mac);\r
238 }\r
239 \r
240 \r
241 /**\r
242   Convert the multibyte field in IP header's byter order.\r
243   In spite of its name, it can also be used to convert from\r
244   host to network byte order.\r
245 \r
246   @param[in]  Head                  The IP head to convert\r
247 \r
248   @return Point to the converted IP head\r
249 \r
250 **/\r
251 IP4_HEAD *\r
252 Ip4NtohHead (\r
253   IN IP4_HEAD           *Head\r
254   )\r
255 {\r
256   Head->TotalLen  = NTOHS (Head->TotalLen);\r
257   Head->Id        = NTOHS (Head->Id);\r
258   Head->Fragment  = NTOHS (Head->Fragment);\r
259   Head->Src       = NTOHL (Head->Src);\r
260   Head->Dst       = NTOHL (Head->Dst);\r
261 \r
262   return Head;\r
263 }\r
264 \r
265 \r
266 /**\r
267   Validate that Ip/Netmask pair is OK to be used as station\r
268   address. Only continuous netmasks are supported. and check\r
269   that StationAddress is a unicast address on the newtwork.\r
270 \r
271   @param[in]  Ip                 The IP address to validate.\r
272   @param[in]  Netmask            The netmaks of the IP.\r
273 \r
274   @retval TRUE                   The Ip/Netmask pair is valid.\r
275   @retval FALSE                  The Ip/Netmask pair is invalid.\r
276 \r
277 **/\r
278 BOOLEAN\r
279 Ip4StationAddressValid (\r
280   IN IP4_ADDR               Ip,\r
281   IN IP4_ADDR               Netmask\r
282   )\r
283 {\r
284   //\r
285   // Only support the station address with 0.0.0.0/0 to enable DHCP client.\r
286   //\r
287   if (Netmask == IP4_ALLZERO_ADDRESS) {\r
288     return (BOOLEAN) (Ip == IP4_ALLZERO_ADDRESS);\r
289   }\r
290 \r
291   //\r
292   // Only support the continuous net masks\r
293   //\r
294   if (NetGetMaskLength (Netmask) == (IP4_MASK_MAX + 1)) {\r
295     return FALSE;\r
296   }\r
297 \r
298   //\r
299   // Station address can't be class D or class E address\r
300   //\r
301   if (NetGetIpClass (Ip) > IP4_ADDR_CLASSC) {\r
302     return FALSE;\r
303   }\r
304 \r
305   return NetIp4IsUnicast (Ip, Netmask);\r
306 }\r