1 /** @file 2 3 Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR> 4 This program and the accompanying materials 5 are licensed and made available under the terms and conditions of the BSD License 6 which accompanies this distribution. The full text of the license may be found at 7 http://opensource.org/licenses/bsd-license.php 8 9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12 **/ 13 14 #include "Ip4Impl.h" 15 16 IP4_ICMP_CLASS 17 mIcmpClass[] = { 18 {ICMP_ECHO_REPLY, ICMP_QUERY_MESSAGE }, 19 {1, ICMP_INVALID_MESSAGE}, 20 {2, ICMP_INVALID_MESSAGE}, 21 {ICMP_DEST_UNREACHABLE, ICMP_ERROR_MESSAGE }, 22 {ICMP_SOURCE_QUENCH, ICMP_ERROR_MESSAGE }, 23 {ICMP_REDIRECT, ICMP_ERROR_MESSAGE }, 24 {6, ICMP_INVALID_MESSAGE}, 25 {7, ICMP_INVALID_MESSAGE}, 26 {ICMP_ECHO_REQUEST, ICMP_QUERY_MESSAGE }, 27 {9, ICMP_INVALID_MESSAGE}, 28 {10, ICMP_INVALID_MESSAGE}, 29 {ICMP_TIME_EXCEEDED, ICMP_ERROR_MESSAGE }, 30 {ICMP_PARAMETER_PROBLEM, ICMP_ERROR_MESSAGE }, 31 {ICMP_TIMESTAMP , ICMP_QUERY_MESSAGE }, 32 {14, ICMP_INVALID_MESSAGE}, 33 {ICMP_INFO_REQUEST , ICMP_QUERY_MESSAGE }, 34 {ICMP_INFO_REPLY , ICMP_QUERY_MESSAGE }, 35 }; 36 37 EFI_IP4_ICMP_TYPE 38 mIp4SupportedIcmp[23] = { 39 {ICMP_ECHO_REPLY, ICMP_DEFAULT_CODE }, 40 41 {ICMP_DEST_UNREACHABLE, ICMP_NET_UNREACHABLE }, 42 {ICMP_DEST_UNREACHABLE, ICMP_HOST_UNREACHABLE }, 43 {ICMP_DEST_UNREACHABLE, ICMP_PROTO_UNREACHABLE }, 44 {ICMP_DEST_UNREACHABLE, ICMP_PORT_UNREACHABLE }, 45 {ICMP_DEST_UNREACHABLE, ICMP_FRAGMENT_FAILED }, 46 {ICMP_DEST_UNREACHABLE, ICMP_SOURCEROUTE_FAILED }, 47 {ICMP_DEST_UNREACHABLE, ICMP_NET_UNKNOWN }, 48 {ICMP_DEST_UNREACHABLE, ICMP_HOST_UNKNOWN }, 49 {ICMP_DEST_UNREACHABLE, ICMP_SOURCE_ISOLATED }, 50 {ICMP_DEST_UNREACHABLE, ICMP_NET_PROHIBITED }, 51 {ICMP_DEST_UNREACHABLE, ICMP_HOST_PROHIBITED }, 52 {ICMP_DEST_UNREACHABLE, ICMP_NET_UNREACHABLE_TOS }, 53 {ICMP_DEST_UNREACHABLE, ICMP_HOST_UNREACHABLE_TOS}, 54 55 {ICMP_SOURCE_QUENCH, ICMP_DEFAULT_CODE }, 56 57 {ICMP_REDIRECT, ICMP_NET_REDIRECT }, 58 {ICMP_REDIRECT, ICMP_HOST_REDIRECT }, 59 {ICMP_REDIRECT, ICMP_NET_TOS_REDIRECT }, 60 {ICMP_REDIRECT, ICMP_HOST_TOS_REDIRECT }, 61 62 {ICMP_ECHO_REQUEST, ICMP_DEFAULT_CODE }, 63 64 {ICMP_TIME_EXCEEDED, ICMP_TIMEOUT_IN_TRANSIT }, 65 {ICMP_TIME_EXCEEDED, ICMP_TIMEOUT_REASSEMBLE }, 66 67 {ICMP_PARAMETER_PROBLEM, ICMP_DEFAULT_CODE }, 68 }; 69 70 71 72 /** 73 Process the ICMP redirect. Find the instance then update 74 its route cache. 75 76 All kinds of redirect is treated as host redirect as 77 specified by RFC1122 3.3.1.2: 78 "Since the subnet mask appropriate to the destination 79 address is generally not known, a Network Redirect 80 message SHOULD be treated identically to a Host Redirect 81 message;" 82 83 @param[in] IpSb The IP4 service binding instance that received 84 the packet. 85 @param[in] Head The IP head of the received ICMPpacket. 86 @param[in] Packet The content of the ICMP redirect packet with IP 87 head removed. 88 @param[in] Icmp The buffer to store the ICMP error message if 89 something is wrong. 90 91 @retval EFI_INVALID_PARAMETER The parameter is invalid 92 @retval EFI_SUCCESS Successfully updated the route caches 93 94 **/ 95 EFI_STATUS 96 Ip4ProcessIcmpRedirect ( 97 IN IP4_SERVICE *IpSb, 98 IN IP4_HEAD *Head, 99 IN NET_BUF *Packet, 100 IN IP4_ICMP_ERROR_HEAD *Icmp 101 ) 102 { 103 LIST_ENTRY *Entry; 104 IP4_PROTOCOL *Ip4Instance; 105 IP4_ROUTE_CACHE_ENTRY *CacheEntry; 106 IP4_INTERFACE *IpIf; 107 IP4_ADDR Gateway; 108 IP4_ADDR Src; 109 IP4_ADDR Dst; 110 111 // 112 // Find the interface whose IP address is the source of the 113 // orgianl IP packet. 114 // 115 IpIf = Ip4FindInterface (IpSb, NTOHL (Icmp->IpHead.Src)); 116 Gateway = NTOHL (Icmp->Fourth); 117 118 // 119 // discard the packet if the new gateway address it specifies 120 // is not on the same connected net through which the Redirect 121 // arrived. (RFC1122 3.2.2.2). 122 // 123 if ((IpIf == NULL) || !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask)) { 124 NetbufFree (Packet); 125 return EFI_INVALID_PARAMETER; 126 } 127 128 // 129 // Update each IP child's route cache on the interface. 130 // 131 NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) { 132 Ip4Instance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink); 133 134 if (Ip4Instance->RouteTable == NULL) { 135 continue; 136 } 137 138 Dst = NTOHL (Icmp->IpHead.Dst); 139 Src = NTOHL (Icmp->IpHead.Src); 140 CacheEntry = Ip4FindRouteCache (Ip4Instance->RouteTable, Dst, Src); 141 142 // 143 // Only update the route cache's gateway if the source of the 144 // Redirect is the current first-hop gateway 145 // 146 if ((CacheEntry != NULL) && (NTOHL (Head->Src) == CacheEntry->NextHop)) { 147 CacheEntry->NextHop = Gateway; 148 } 149 } 150 151 NetbufFree (Packet); 152 return EFI_SUCCESS; 153 } 154 155 156 /** 157 Process the ICMP error packet. If it is an ICMP redirect packet, 158 update call Ip4ProcessIcmpRedirect to update the IP instance's 159 route cache, otherwise, deliver the packet to upper layer. 160 161 @param[in] IpSb The IP4 service that received the packet. 162 @param[in] Head The IP4 head of the ICMP error packet 163 @param[in] Packet The content of the ICMP error with IP4 head 164 removed. 165 166 @retval EFI_SUCCESS The ICMP error is processed successfully. 167 @retval EFI_INVALID_PARAMETER The packet is invalid 168 @retval Others Failed to process the packet. 169 170 **/ 171 EFI_STATUS 172 Ip4ProcessIcmpError ( 173 IN IP4_SERVICE *IpSb, 174 IN IP4_HEAD *Head, 175 IN NET_BUF *Packet 176 ) 177 { 178 IP4_ICMP_ERROR_HEAD Icmp; 179 180 if (Packet->TotalSize < sizeof (Icmp)) { 181 NetbufFree (Packet); 182 return EFI_INVALID_PARAMETER; 183 } 184 185 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp); 186 187 // 188 // If it is an ICMP redirect error, update the route cache 189 // as RFC1122. Otherwise, demultiplex it to IP instances. 190 // 191 if (Icmp.Head.Type == ICMP_REDIRECT) { 192 return Ip4ProcessIcmpRedirect (IpSb, Head, Packet, &Icmp); 193 } 194 195 IP4_GET_CLIP_INFO (Packet)->Status = EFI_ICMP_ERROR; 196 return Ip4Demultiplex (IpSb, Head, Packet, NULL, 0); 197 } 198 199 200 /** 201 Replay an ICMP echo request. 202 203 @param[in] IpSb The IP4 service that receivd the packet 204 @param[in] Head The IP4 head of the ICMP error packet 205 @param[in] Packet The content of the ICMP error with IP4 head 206 removed. 207 208 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource. 209 @retval EFI_SUCCESS The ICMP Echo request is successfully answered. 210 @retval Others Failed to answer the ICMP echo request. 211 212 **/ 213 EFI_STATUS 214 Ip4IcmpReplyEcho ( 215 IN IP4_SERVICE *IpSb, 216 IN IP4_HEAD *Head, 217 IN NET_BUF *Packet 218 ) 219 { 220 IP4_ICMP_QUERY_HEAD *Icmp; 221 NET_BUF *Data; 222 EFI_STATUS Status; 223 IP4_HEAD ReplyHead; 224 225 // 226 // make a copy the packet, it is really a bad idea to 227 // send the MNP's buffer back to MNP. 228 // 229 Data = NetbufDuplicate (Packet, NULL, IP4_MAX_HEADLEN); 230 231 if (Data == NULL) { 232 Status = EFI_OUT_OF_RESOURCES; 233 goto ON_EXIT; 234 } 235 236 // 237 // Change the ICMP type to echo reply, exchange the source 238 // and destination, then send it. The source is updated to 239 // use specific destination. See RFC1122. SRR/RR option 240 // update is omitted. 241 // 242 Icmp = (IP4_ICMP_QUERY_HEAD *) NetbufGetByte (Data, 0, NULL); 243 ASSERT (Icmp != NULL); 244 Icmp->Head.Type = ICMP_ECHO_REPLY; 245 Icmp->Head.Checksum = 0; 246 Icmp->Head.Checksum = (UINT16) (~NetblockChecksum ((UINT8 *) Icmp, Data->TotalSize)); 247 248 ReplyHead.Tos = 0; 249 ReplyHead.Fragment = 0; 250 ReplyHead.Ttl = 64; 251 ReplyHead.Protocol = EFI_IP_PROTO_ICMP; 252 ReplyHead.Src = 0; 253 254 // 255 // Ip4Output will select a source for us 256 // 257 ReplyHead.Dst = Head->Src; 258 259 Status = Ip4Output ( 260 IpSb, 261 NULL, 262 Data, 263 &ReplyHead, 264 NULL, 265 0, 266 IP4_ALLZERO_ADDRESS, 267 Ip4SysPacketSent, 268 NULL 269 ); 270 271 ON_EXIT: 272 NetbufFree (Packet); 273 return Status; 274 } 275 276 277 /** 278 Process the ICMP query message. If it is an ICMP echo 279 request, answer it. Otherwise deliver it to upper layer. 280 281 @param[in] IpSb The IP4 service that receivd the packet 282 @param[in] Head The IP4 head of the ICMP query packet 283 @param[in] Packet The content of the ICMP query with IP4 head 284 removed. 285 286 @retval EFI_INVALID_PARAMETER The packet is invalid 287 @retval EFI_SUCCESS The ICMP query message is processed 288 @retval Others Failed to process ICMP query. 289 290 **/ 291 EFI_STATUS 292 Ip4ProcessIcmpQuery ( 293 IN IP4_SERVICE *IpSb, 294 IN IP4_HEAD *Head, 295 IN NET_BUF *Packet 296 ) 297 { 298 IP4_ICMP_QUERY_HEAD Icmp; 299 300 if (Packet->TotalSize < sizeof (Icmp)) { 301 NetbufFree (Packet); 302 return EFI_INVALID_PARAMETER; 303 } 304 305 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp); 306 307 if (Icmp.Head.Type == ICMP_ECHO_REQUEST) { 308 return Ip4IcmpReplyEcho (IpSb, Head, Packet); 309 } 310 311 return Ip4Demultiplex (IpSb, Head, Packet, NULL, 0); 312 } 313 314 315 /** 316 Handle the ICMP packet. First validate the message format, 317 then according to the message types, process it as query or 318 error packet. 319 320 @param[in] IpSb The IP4 service that receivd the packet. 321 @param[in] Head The IP4 head of the ICMP query packet. 322 @param[in] Packet The content of the ICMP query with IP4 head 323 removed. 324 325 @retval EFI_INVALID_PARAMETER The packet is malformated. 326 @retval EFI_SUCCESS The ICMP message is successfully processed. 327 @retval Others Failed to handle ICMP packet. 328 329 **/ 330 EFI_STATUS 331 Ip4IcmpHandle ( 332 IN IP4_SERVICE *IpSb, 333 IN IP4_HEAD *Head, 334 IN NET_BUF *Packet 335 ) 336 { 337 IP4_ICMP_HEAD Icmp; 338 UINT16 Checksum; 339 340 if (Packet->TotalSize < sizeof (Icmp)) { 341 goto DROP; 342 } 343 344 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp); 345 346 if (Icmp.Type > ICMP_TYPE_MAX) { 347 goto DROP; 348 } 349 350 Checksum = (UINT16) (~NetbufChecksum (Packet)); 351 if ((Icmp.Checksum != 0) && (Checksum != 0)) { 352 goto DROP; 353 } 354 355 if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_ERROR_MESSAGE) { 356 return Ip4ProcessIcmpError (IpSb, Head, Packet); 357 358 } else if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_QUERY_MESSAGE) { 359 return Ip4ProcessIcmpQuery (IpSb, Head, Packet); 360 361 } 362 363 DROP: 364 NetbufFree (Packet); 365 return EFI_INVALID_PARAMETER; 366 } 367