2 The ICMPv6 handle routines to process the ICMPv6 control messages.
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php.
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 EFI_IP6_ICMP_TYPE mIp6SupportedIcmp
[23] = {
22 ICMP_V6_DEST_UNREACHABLE
,
23 ICMP_V6_NO_ROUTE_TO_DEST
26 ICMP_V6_DEST_UNREACHABLE
,
27 ICMP_V6_COMM_PROHIBITED
30 ICMP_V6_DEST_UNREACHABLE
,
34 ICMP_V6_DEST_UNREACHABLE
,
35 ICMP_V6_ADDR_UNREACHABLE
38 ICMP_V6_DEST_UNREACHABLE
,
39 ICMP_V6_PORT_UNREACHABLE
42 ICMP_V6_DEST_UNREACHABLE
,
43 ICMP_V6_SOURCE_ADDR_FAILED
46 ICMP_V6_DEST_UNREACHABLE
,
47 ICMP_V6_ROUTE_REJECTED
51 ICMP_V6_PACKET_TOO_BIG
,
56 ICMP_V6_TIME_EXCEEDED
,
57 ICMP_V6_TIMEOUT_HOP_LIMIT
60 ICMP_V6_TIME_EXCEEDED
,
61 ICMP_V6_TIMEOUT_REASSEMBLE
65 ICMP_V6_PARAMETER_PROBLEM
,
66 ICMP_V6_ERRONEOUS_HEADER
69 ICMP_V6_PARAMETER_PROBLEM
,
70 ICMP_V6_UNRECOGNIZE_NEXT_HDR
73 ICMP_V6_PARAMETER_PROBLEM
,
74 ICMP_V6_UNRECOGNIZE_OPTION
87 ICMP_V6_LISTENER_QUERY
,
91 ICMP_V6_LISTENER_REPORT
,
95 ICMP_V6_LISTENER_REPORT_2
,
99 ICMP_V6_LISTENER_DONE
,
104 ICMP_V6_ROUTER_SOLICIT
,
108 ICMP_V6_ROUTER_ADVERTISE
,
112 ICMP_V6_NEIGHBOR_SOLICIT
,
116 ICMP_V6_NEIGHBOR_ADVERTISE
,
122 Reply an ICMPv6 echo request.
124 @param[in] IpSb The IP service that received the packet.
125 @param[in] Head The IP head of the ICMPv6 informational message.
126 @param[in] Packet The content of the ICMPv6 message with the IP head
129 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
130 @retval EFI_SUCCESS Successfully answered the ICMPv6 Echo request.
131 @retval Others Failed to answer the ICMPv6 Echo request.
136 IN IP6_SERVICE
*IpSb
,
137 IN EFI_IP6_HEADER
*Head
,
141 IP6_ICMP_INFORMATION_HEAD
*Icmp
;
144 EFI_IP6_HEADER ReplyHead
;
146 Status
= EFI_OUT_OF_RESOURCES
;
148 // make a copy the packet, it is really a bad idea to
149 // send the MNP's buffer back to MNP.
151 Data
= NetbufDuplicate (Packet
, NULL
, IP6_MAX_HEADLEN
);
157 // Change the ICMP type to echo reply, exchange the source
158 // and destination, then send it. The source is updated to
159 // use specific destination. See RFC1122. SRR/RR option
160 // update is omitted.
162 Icmp
= (IP6_ICMP_INFORMATION_HEAD
*) NetbufGetByte (Data
, 0, NULL
);
168 Icmp
->Head
.Type
= ICMP_V6_ECHO_REPLY
;
169 Icmp
->Head
.Checksum
= 0;
172 // Generate the IPv6 basic header
173 // If the Echo Reply is a response to a Echo Request sent to one of the node's unicast address,
174 // the Source address of the Echo Reply must be the same address.
176 ZeroMem (&ReplyHead
, sizeof (EFI_IP6_HEADER
));
178 ReplyHead
.PayloadLength
= HTONS ((UINT16
) (Packet
->TotalSize
));
179 ReplyHead
.NextHeader
= IP6_ICMP
;
180 ReplyHead
.HopLimit
= IpSb
->CurHopLimit
;
181 IP6_COPY_ADDRESS (&ReplyHead
.DestinationAddress
, &Head
->SourceAddress
);
183 if (Ip6IsOneOfSetAddress (IpSb
, &Head
->DestinationAddress
, NULL
, NULL
)) {
184 IP6_COPY_ADDRESS (&ReplyHead
.SourceAddress
, &Head
->DestinationAddress
);
188 // If source is unspecified, Ip6Output will select a source for us
208 Process Packet Too Big message sent by a router in response to a packet that
209 it cannot forward because the packet is larger than the MTU of outgoing link.
210 Since this driver already uses IPv6 minimum link MTU as the maximum packet size,
211 if Packet Too Big message is still received, do not reduce the packet size, but
212 rather include a Fragment header in the subsequent packets.
214 @param[in] IpSb The IP service that received the packet.
215 @param[in] Head The IP head of the ICMPv6 error packet.
216 @param[in] Packet The content of the ICMPv6 error with the IP head
219 @retval EFI_SUCCESS The ICMPv6 error processed successfully.
220 @retval EFI_OUT_OF_RESOURCES Failed to finish the operation due to lack of
222 @retval EFI_NOT_FOUND The packet too big message is not sent to us.
226 Ip6ProcessPacketTooBig (
227 IN IP6_SERVICE
*IpSb
,
228 IN EFI_IP6_HEADER
*Head
,
232 IP6_ICMP_ERROR_HEAD Icmp
;
234 IP6_ROUTE_ENTRY
*RouteEntry
;
235 EFI_IPv6_ADDRESS
*DestAddress
;
237 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*) &Icmp
);
238 Mtu
= NTOHL (Icmp
.Fourth
);
239 DestAddress
= &Icmp
.IpHead
.DestinationAddress
;
241 if (Mtu
< IP6_MIN_LINK_MTU
) {
243 // Normally the multicast address is considered to be on-link and not recorded
244 // in route table. Here it is added into the table since the MTU information
247 if (IP6_IS_MULTICAST (DestAddress
)) {
248 RouteEntry
= Ip6CreateRouteEntry (DestAddress
, 128, NULL
);
249 if (RouteEntry
== NULL
) {
251 return EFI_OUT_OF_RESOURCES
;
254 RouteEntry
->Flag
= IP6_DIRECT_ROUTE
| IP6_PACKET_TOO_BIG
;
255 InsertHeadList (&IpSb
->RouteTable
->RouteArea
[128], &RouteEntry
->Link
);
256 IpSb
->RouteTable
->TotalNum
++;
258 RouteEntry
= Ip6FindRouteEntry (IpSb
->RouteTable
, DestAddress
, NULL
);
259 if (RouteEntry
== NULL
) {
261 return EFI_NOT_FOUND
;
264 RouteEntry
->Flag
= RouteEntry
->Flag
| IP6_PACKET_TOO_BIG
;
266 Ip6FreeRouteEntry (RouteEntry
);
275 Process the ICMPv6 error packet, and deliver the packet to upper layer.
277 @param[in] IpSb The IP service that received the packet.
278 @param[in] Head The IP head of the ICMPv6 error packet.
279 @param[in] Packet The content of the ICMPv6 error with the IP head
282 @retval EFI_SUCCESS The ICMPv6 error processed successfully.
283 @retval EFI_INVALID_PARAMETER The packet is invalid.
284 @retval Others Failed to process the packet.
288 Ip6ProcessIcmpError (
289 IN IP6_SERVICE
*IpSb
,
290 IN EFI_IP6_HEADER
*Head
,
294 IP6_ICMP_ERROR_HEAD Icmp
;
297 // Check the validity of the packet
299 if (Packet
->TotalSize
< sizeof (Icmp
)) {
303 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*) &Icmp
);
304 if (Icmp
.Head
.Type
== ICMP_V6_PACKET_TOO_BIG
) {
305 return Ip6ProcessPacketTooBig (IpSb
, Head
, Packet
);
309 // Notify the upper-layer process that an ICMPv6 eror message is received.
311 IP6_GET_CLIP_INFO (Packet
)->Status
= EFI_ICMP_ERROR
;
312 return Ip6Demultiplex (IpSb
, Head
, Packet
);
317 return EFI_INVALID_PARAMETER
;
321 Process the ICMPv6 informational messages. If it is an ICMPv6 echo
322 request, answer it. If it is a MLD message, trigger MLD routines to
323 process it. If it is a ND message, trigger ND routines to process it.
324 Otherwise, deliver it to upper layer.
326 @param[in] IpSb The IP service that receivd the packet.
327 @param[in] Head The IP head of the ICMPv6 informational packet.
328 @param[in] Packet The content of the ICMPv6 informational packet
329 with IP head removed.
331 @retval EFI_INVALID_PARAMETER The packet is invalid.
332 @retval EFI_SUCCESS The ICMPv6 informational message processed.
333 @retval Others Failed to process ICMPv6 informational message.
337 Ip6ProcessIcmpInformation (
338 IN IP6_SERVICE
*IpSb
,
339 IN EFI_IP6_HEADER
*Head
,
343 IP6_ICMP_INFORMATION_HEAD Icmp
;
346 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
347 NET_CHECK_SIGNATURE (Packet
, NET_BUF_SIGNATURE
);
348 ASSERT (Head
!= NULL
);
350 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*) &Icmp
);
351 Status
= EFI_INVALID_PARAMETER
;
353 switch (Icmp
.Head
.Type
) {
354 case ICMP_V6_ECHO_REQUEST
:
356 // If ICMPv6 echo, reply it
358 if (Icmp
.Head
.Code
== 0) {
359 Status
= Ip6IcmpReplyEcho (IpSb
, Head
, Packet
);
362 case ICMP_V6_LISTENER_QUERY
:
363 Status
= Ip6ProcessMldQuery (IpSb
, Head
, Packet
);
365 case ICMP_V6_LISTENER_REPORT
:
366 case ICMP_V6_LISTENER_REPORT_2
:
367 Status
= Ip6ProcessMldReport (IpSb
, Head
, Packet
);
369 case ICMP_V6_NEIGHBOR_SOLICIT
:
370 Status
= Ip6ProcessNeighborSolicit (IpSb
, Head
, Packet
);
372 case ICMP_V6_NEIGHBOR_ADVERTISE
:
373 Status
= Ip6ProcessNeighborAdvertise (IpSb
, Head
, Packet
);
375 case ICMP_V6_ROUTER_ADVERTISE
:
376 Status
= Ip6ProcessRouterAdvertise (IpSb
, Head
, Packet
);
378 case ICMP_V6_REDIRECT
:
379 Status
= Ip6ProcessRedirect (IpSb
, Head
, Packet
);
381 case ICMP_V6_ECHO_REPLY
:
382 Status
= Ip6Demultiplex (IpSb
, Head
, Packet
);
385 Status
= EFI_INVALID_PARAMETER
;
393 Handle the ICMPv6 packet. First validate the message format,
394 then, according to the message types, process it as an informational packet or
397 @param[in] IpSb The IP service that received the packet.
398 @param[in] Head The IP head of the ICMPv6 packet.
399 @param[in] Packet The content of the ICMPv6 packet with IP head
402 @retval EFI_INVALID_PARAMETER The packet is malformated.
403 @retval EFI_SUCCESS The ICMPv6 message successfully processed.
404 @retval Others Failed to handle the ICMPv6 packet.
409 IN IP6_SERVICE
*IpSb
,
410 IN EFI_IP6_HEADER
*Head
,
415 UINT16 PseudoCheckSum
;
419 // Check the validity of the incoming packet.
421 if (Packet
->TotalSize
< sizeof (Icmp
)) {
425 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*) &Icmp
);
428 // Make sure checksum is valid.
430 PseudoCheckSum
= NetIp6PseudoHeadChecksum (
431 &Head
->SourceAddress
,
432 &Head
->DestinationAddress
,
436 CheckSum
= (UINT16
) ~NetAddChecksum (PseudoCheckSum
, NetbufChecksum (Packet
));
442 // According to the packet type, call corresponding process
444 if (Icmp
.Type
<= ICMP_V6_ERROR_MAX
) {
445 return Ip6ProcessIcmpError (IpSb
, Head
, Packet
);
447 return Ip6ProcessIcmpInformation (IpSb
, Head
, Packet
);
452 return EFI_INVALID_PARAMETER
;
456 Retrieve the Prefix address according to the PrefixLength by clear the useless
459 @param[in] PrefixLength The prefix length of the prefix.
460 @param[in, out] Prefix On input, points to the original prefix address
461 with dirty bits; on output, points to the updated
462 address with useless bit clear.
467 IN UINT8 PrefixLength
,
468 IN OUT EFI_IPv6_ADDRESS
*Prefix
476 ASSERT ((Prefix
!= NULL
) && (PrefixLength
< IP6_PREFIX_MAX
));
478 if (PrefixLength
== 0) {
479 ZeroMem (Prefix
, sizeof (EFI_IPv6_ADDRESS
));
483 if (PrefixLength
>= IP6_PREFIX_MAX
) {
487 Byte
= (UINT8
) (PrefixLength
/ 8);
488 Bit
= (UINT8
) (PrefixLength
% 8);
489 Value
= Prefix
->Addr
[Byte
];
492 ZeroMem (Prefix
->Addr
+ Byte
, 16 - Byte
);
496 Mask
= (UINT8
) (0xFF << (8 - Bit
));
497 Prefix
->Addr
[Byte
] = (UINT8
) (Value
& Mask
);
503 Check whether the DestinationAddress is an anycast address.
505 @param[in] IpSb The IP service that received the packet.
506 @param[in] DestinationAddress Points to the Destination Address of the packet.
508 @retval TRUE The DestinationAddress is anycast address.
509 @retval FALSE The DestinationAddress is not anycast address.
514 IN IP6_SERVICE
*IpSb
,
515 IN EFI_IPv6_ADDRESS
*DestinationAddress
518 IP6_PREFIX_LIST_ENTRY
*PrefixEntry
;
519 EFI_IPv6_ADDRESS Prefix
;
522 ZeroMem (&Prefix
, sizeof (EFI_IPv6_ADDRESS
));
527 // If the address is known as on-link or autonomous prefix, record it as
531 PrefixEntry
= Ip6FindPrefixListEntry (IpSb
, Flag
, 255, DestinationAddress
);
532 if (PrefixEntry
!= NULL
) {
533 IP6_COPY_ADDRESS (&Prefix
, &PrefixEntry
->Prefix
);
534 Ip6GetPrefix (PrefixEntry
->PrefixLength
, &Prefix
);
535 if (EFI_IP6_EQUAL (&Prefix
, DestinationAddress
)) {
540 Flag
= (BOOLEAN
) !Flag
;
547 Generate ICMPv6 error message and send it out to DestinationAddress. Currently
548 Destination Unreachable message, Time Exceeded message and Parameter Problem
549 message are supported.
551 @param[in] IpSb The IP service that received the packet.
552 @param[in] Packet The packet which invoking ICMPv6 error.
553 @param[in] SourceAddress If not NULL, points to the SourceAddress.
554 Otherwise, the IP layer will select a source address
555 according to the DestinationAddress.
556 @param[in] DestinationAddress Points to the Destination Address of the ICMPv6
558 @param[in] Type The type of the ICMPv6 message.
559 @param[in] Code The additional level of the ICMPv6 message.
560 @param[in] Pointer If not NULL, identifies the octet offset within
561 the invoking packet where the error was detected.
563 @retval EFI_INVALID_PARAMETER The packet is malformated.
564 @retval EFI_OUT_OF_RESOURCES There is no sufficient resource to complete the
566 @retval EFI_SUCCESS The ICMPv6 message was successfully sent out.
567 @retval Others Failed to generate the ICMPv6 packet.
572 IN IP6_SERVICE
*IpSb
,
574 IN EFI_IPv6_ADDRESS
*SourceAddress OPTIONAL
,
575 IN EFI_IPv6_ADDRESS
*DestinationAddress
,
578 IN UINT32
*Pointer OPTIONAL
585 IP6_ICMP_INFORMATION_HEAD
*IcmpHead
;
588 if (DestinationAddress
== NULL
) {
589 return EFI_INVALID_PARAMETER
;
593 // An ICMPv6 error message must not be originated as a result of receiving
594 // a packet whose source address does not uniquely identify a single node --
595 // e.g., the IPv6 Unspecified Address, an IPv6 multicast address, or an address
596 // known by the ICMP message originator to be an IPv6 anycast address.
598 if (NetIp6IsUnspecifiedAddr (DestinationAddress
) ||
599 IP6_IS_MULTICAST (DestinationAddress
) ||
600 Ip6IsAnycast (IpSb
, DestinationAddress
)
602 return EFI_INVALID_PARAMETER
;
606 case ICMP_V6_DEST_UNREACHABLE
:
607 case ICMP_V6_TIME_EXCEEDED
:
610 case ICMP_V6_PARAMETER_PROBLEM
:
611 if (Pointer
== NULL
) {
612 return EFI_INVALID_PARAMETER
;
618 return EFI_INVALID_PARAMETER
;
621 PacketLen
= sizeof (IP6_ICMP_ERROR_HEAD
) + Packet
->TotalSize
;
623 if (PacketLen
> IpSb
->MaxPacketSize
) {
624 PacketLen
= IpSb
->MaxPacketSize
;
627 ErrorMsg
= NetbufAlloc (PacketLen
);
628 if (ErrorMsg
== NULL
) {
629 return EFI_OUT_OF_RESOURCES
;
632 PayloadLen
= (UINT16
) (PacketLen
- sizeof (EFI_IP6_HEADER
));
635 // Create the basic IPv6 header.
637 ZeroMem (&Head
, sizeof (EFI_IP6_HEADER
));
639 Head
.PayloadLength
= HTONS (PayloadLen
);
640 Head
.NextHeader
= IP6_ICMP
;
641 Head
.HopLimit
= IpSb
->CurHopLimit
;
643 if (SourceAddress
!= NULL
) {
644 IP6_COPY_ADDRESS (&Head
.SourceAddress
, SourceAddress
);
646 ZeroMem (&Head
.SourceAddress
, sizeof (EFI_IPv6_ADDRESS
));
649 IP6_COPY_ADDRESS (&Head
.DestinationAddress
, DestinationAddress
);
651 NetbufReserve (ErrorMsg
, sizeof (EFI_IP6_HEADER
));
654 // Fill in the ICMP error message head
656 IcmpHead
= (IP6_ICMP_INFORMATION_HEAD
*) NetbufAllocSpace (ErrorMsg
, sizeof (IP6_ICMP_INFORMATION_HEAD
), FALSE
);
657 if (IcmpHead
== NULL
) {
658 NetbufFree (ErrorMsg
);
659 return EFI_OUT_OF_RESOURCES
;
662 ZeroMem (IcmpHead
, sizeof (IP6_ICMP_INFORMATION_HEAD
));
663 IcmpHead
->Head
.Type
= Type
;
664 IcmpHead
->Head
.Code
= Code
;
666 if (Pointer
!= NULL
) {
667 IcmpHead
->Fourth
= HTONL (*Pointer
);
671 // Fill in the ICMP error message body
673 PayloadLen
-= sizeof (IP6_ICMP_INFORMATION_HEAD
);
674 ErrorBody
= NetbufAllocSpace (ErrorMsg
, PayloadLen
, FALSE
);
675 if (ErrorBody
!= NULL
) {
676 ZeroMem (ErrorBody
, PayloadLen
);
677 NetbufCopy (Packet
, 0, PayloadLen
, ErrorBody
);
681 // Transmit the packet
683 return Ip6Output (IpSb
, NULL
, NULL
, ErrorMsg
, &Head
, NULL
, 0, Ip6SysPacketSent
, NULL
);