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 SPDX-License-Identifier: BSD-2-Clause-Patent
13 EFI_IP6_ICMP_TYPE mIp6SupportedIcmp
[23] = {
15 ICMP_V6_DEST_UNREACHABLE
,
16 ICMP_V6_NO_ROUTE_TO_DEST
19 ICMP_V6_DEST_UNREACHABLE
,
20 ICMP_V6_COMM_PROHIBITED
23 ICMP_V6_DEST_UNREACHABLE
,
27 ICMP_V6_DEST_UNREACHABLE
,
28 ICMP_V6_ADDR_UNREACHABLE
31 ICMP_V6_DEST_UNREACHABLE
,
32 ICMP_V6_PORT_UNREACHABLE
35 ICMP_V6_DEST_UNREACHABLE
,
36 ICMP_V6_SOURCE_ADDR_FAILED
39 ICMP_V6_DEST_UNREACHABLE
,
40 ICMP_V6_ROUTE_REJECTED
44 ICMP_V6_PACKET_TOO_BIG
,
49 ICMP_V6_TIME_EXCEEDED
,
50 ICMP_V6_TIMEOUT_HOP_LIMIT
53 ICMP_V6_TIME_EXCEEDED
,
54 ICMP_V6_TIMEOUT_REASSEMBLE
58 ICMP_V6_PARAMETER_PROBLEM
,
59 ICMP_V6_ERRONEOUS_HEADER
62 ICMP_V6_PARAMETER_PROBLEM
,
63 ICMP_V6_UNRECOGNIZE_NEXT_HDR
66 ICMP_V6_PARAMETER_PROBLEM
,
67 ICMP_V6_UNRECOGNIZE_OPTION
80 ICMP_V6_LISTENER_QUERY
,
84 ICMP_V6_LISTENER_REPORT
,
88 ICMP_V6_LISTENER_REPORT_2
,
92 ICMP_V6_LISTENER_DONE
,
97 ICMP_V6_ROUTER_SOLICIT
,
101 ICMP_V6_ROUTER_ADVERTISE
,
105 ICMP_V6_NEIGHBOR_SOLICIT
,
109 ICMP_V6_NEIGHBOR_ADVERTISE
,
115 Reply an ICMPv6 echo request.
117 @param[in] IpSb The IP service that received the packet.
118 @param[in] Head The IP head of the ICMPv6 informational message.
119 @param[in] Packet The content of the ICMPv6 message with the IP head
122 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
123 @retval EFI_SUCCESS Successfully answered the ICMPv6 Echo request.
124 @retval Others Failed to answer the ICMPv6 Echo request.
129 IN IP6_SERVICE
*IpSb
,
130 IN EFI_IP6_HEADER
*Head
,
134 IP6_ICMP_INFORMATION_HEAD
*Icmp
;
137 EFI_IP6_HEADER ReplyHead
;
139 Status
= EFI_OUT_OF_RESOURCES
;
141 // make a copy the packet, it is really a bad idea to
142 // send the MNP's buffer back to MNP.
144 Data
= NetbufDuplicate (Packet
, NULL
, IP6_MAX_HEADLEN
);
150 // Change the ICMP type to echo reply, exchange the source
151 // and destination, then send it. The source is updated to
152 // use specific destination. See RFC1122. SRR/RR option
153 // update is omitted.
155 Icmp
= (IP6_ICMP_INFORMATION_HEAD
*)NetbufGetByte (Data
, 0, NULL
);
161 Icmp
->Head
.Type
= ICMP_V6_ECHO_REPLY
;
162 Icmp
->Head
.Checksum
= 0;
165 // Generate the IPv6 basic header
166 // If the Echo Reply is a response to a Echo Request sent to one of the node's unicast address,
167 // the Source address of the Echo Reply must be the same address.
169 ZeroMem (&ReplyHead
, sizeof (EFI_IP6_HEADER
));
171 ReplyHead
.PayloadLength
= HTONS ((UINT16
)(Packet
->TotalSize
));
172 ReplyHead
.NextHeader
= IP6_ICMP
;
173 ReplyHead
.HopLimit
= IpSb
->CurHopLimit
;
174 IP6_COPY_ADDRESS (&ReplyHead
.DestinationAddress
, &Head
->SourceAddress
);
176 if (Ip6IsOneOfSetAddress (IpSb
, &Head
->DestinationAddress
, NULL
, NULL
)) {
177 IP6_COPY_ADDRESS (&ReplyHead
.SourceAddress
, &Head
->DestinationAddress
);
181 // If source is unspecified, Ip6Output will select a source for us
201 Process Packet Too Big message sent by a router in response to a packet that
202 it cannot forward because the packet is larger than the MTU of outgoing link.
203 Since this driver already uses IPv6 minimum link MTU as the maximum packet size,
204 if Packet Too Big message is still received, do not reduce the packet size, but
205 rather include a Fragment header in the subsequent packets.
207 @param[in] IpSb The IP service that received the packet.
208 @param[in] Head The IP head of the ICMPv6 error packet.
209 @param[in] Packet The content of the ICMPv6 error with the IP head
212 @retval EFI_SUCCESS The ICMPv6 error processed successfully.
213 @retval EFI_OUT_OF_RESOURCES Failed to finish the operation due to lack of
215 @retval EFI_NOT_FOUND The packet too big message is not sent to us.
219 Ip6ProcessPacketTooBig (
220 IN IP6_SERVICE
*IpSb
,
221 IN EFI_IP6_HEADER
*Head
,
225 IP6_ICMP_ERROR_HEAD Icmp
;
227 IP6_ROUTE_ENTRY
*RouteEntry
;
228 EFI_IPv6_ADDRESS
*DestAddress
;
230 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*)&Icmp
);
231 Mtu
= NTOHL (Icmp
.Fourth
);
232 DestAddress
= &Icmp
.IpHead
.DestinationAddress
;
234 if (Mtu
< IP6_MIN_LINK_MTU
) {
236 // Normally the multicast address is considered to be on-link and not recorded
237 // in route table. Here it is added into the table since the MTU information
240 if (IP6_IS_MULTICAST (DestAddress
)) {
241 RouteEntry
= Ip6CreateRouteEntry (DestAddress
, 128, NULL
);
242 if (RouteEntry
== NULL
) {
244 return EFI_OUT_OF_RESOURCES
;
247 RouteEntry
->Flag
= IP6_DIRECT_ROUTE
| IP6_PACKET_TOO_BIG
;
248 InsertHeadList (&IpSb
->RouteTable
->RouteArea
[128], &RouteEntry
->Link
);
249 IpSb
->RouteTable
->TotalNum
++;
251 RouteEntry
= Ip6FindRouteEntry (IpSb
->RouteTable
, DestAddress
, NULL
);
252 if (RouteEntry
== NULL
) {
254 return EFI_NOT_FOUND
;
257 RouteEntry
->Flag
= RouteEntry
->Flag
| IP6_PACKET_TOO_BIG
;
259 Ip6FreeRouteEntry (RouteEntry
);
268 Process the ICMPv6 error packet, and deliver the packet to upper layer.
270 @param[in] IpSb The IP service that received the packet.
271 @param[in] Head The IP head of the ICMPv6 error packet.
272 @param[in] Packet The content of the ICMPv6 error with the IP head
275 @retval EFI_SUCCESS The ICMPv6 error processed successfully.
276 @retval EFI_INVALID_PARAMETER The packet is invalid.
277 @retval Others Failed to process the packet.
281 Ip6ProcessIcmpError (
282 IN IP6_SERVICE
*IpSb
,
283 IN EFI_IP6_HEADER
*Head
,
287 IP6_ICMP_ERROR_HEAD Icmp
;
290 // Check the validity of the packet
292 if (Packet
->TotalSize
< sizeof (Icmp
)) {
296 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*)&Icmp
);
297 if (Icmp
.Head
.Type
== ICMP_V6_PACKET_TOO_BIG
) {
298 return Ip6ProcessPacketTooBig (IpSb
, Head
, Packet
);
302 // Notify the upper-layer process that an ICMPv6 error message is received.
304 IP6_GET_CLIP_INFO (Packet
)->Status
= EFI_ICMP_ERROR
;
305 return Ip6Demultiplex (IpSb
, Head
, Packet
);
310 return EFI_INVALID_PARAMETER
;
314 Process the ICMPv6 informational messages. If it is an ICMPv6 echo
315 request, answer it. If it is a MLD message, trigger MLD routines to
316 process it. If it is a ND message, trigger ND routines to process it.
317 Otherwise, deliver it to upper layer.
319 @param[in] IpSb The IP service that receivd the packet.
320 @param[in] Head The IP head of the ICMPv6 informational packet.
321 @param[in] Packet The content of the ICMPv6 informational packet
322 with IP head removed.
324 @retval EFI_INVALID_PARAMETER The packet is invalid.
325 @retval EFI_SUCCESS The ICMPv6 informational message processed.
326 @retval Others Failed to process ICMPv6 informational message.
330 Ip6ProcessIcmpInformation (
331 IN IP6_SERVICE
*IpSb
,
332 IN EFI_IP6_HEADER
*Head
,
336 IP6_ICMP_INFORMATION_HEAD Icmp
;
339 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
340 NET_CHECK_SIGNATURE (Packet
, NET_BUF_SIGNATURE
);
341 ASSERT (Head
!= NULL
);
343 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*)&Icmp
);
344 Status
= EFI_INVALID_PARAMETER
;
346 switch (Icmp
.Head
.Type
) {
347 case ICMP_V6_ECHO_REQUEST
:
349 // If ICMPv6 echo, reply it
351 if (Icmp
.Head
.Code
== 0) {
352 Status
= Ip6IcmpReplyEcho (IpSb
, Head
, Packet
);
356 case ICMP_V6_LISTENER_QUERY
:
357 Status
= Ip6ProcessMldQuery (IpSb
, Head
, Packet
);
359 case ICMP_V6_LISTENER_REPORT
:
360 case ICMP_V6_LISTENER_REPORT_2
:
361 Status
= Ip6ProcessMldReport (IpSb
, Head
, Packet
);
363 case ICMP_V6_NEIGHBOR_SOLICIT
:
364 Status
= Ip6ProcessNeighborSolicit (IpSb
, Head
, Packet
);
366 case ICMP_V6_NEIGHBOR_ADVERTISE
:
367 Status
= Ip6ProcessNeighborAdvertise (IpSb
, Head
, Packet
);
369 case ICMP_V6_ROUTER_ADVERTISE
:
370 Status
= Ip6ProcessRouterAdvertise (IpSb
, Head
, Packet
);
372 case ICMP_V6_REDIRECT
:
373 Status
= Ip6ProcessRedirect (IpSb
, Head
, Packet
);
375 case ICMP_V6_ECHO_REPLY
:
376 Status
= Ip6Demultiplex (IpSb
, Head
, Packet
);
379 Status
= EFI_INVALID_PARAMETER
;
387 Handle the ICMPv6 packet. First validate the message format,
388 then, according to the message types, process it as an informational packet or
391 @param[in] IpSb The IP service that received the packet.
392 @param[in] Head The IP head of the ICMPv6 packet.
393 @param[in] Packet The content of the ICMPv6 packet with IP head
396 @retval EFI_INVALID_PARAMETER The packet is malformatted.
397 @retval EFI_SUCCESS The ICMPv6 message successfully processed.
398 @retval Others Failed to handle the ICMPv6 packet.
403 IN IP6_SERVICE
*IpSb
,
404 IN EFI_IP6_HEADER
*Head
,
409 UINT16 PseudoCheckSum
;
413 // Check the validity of the incoming packet.
415 if (Packet
->TotalSize
< sizeof (Icmp
)) {
419 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*)&Icmp
);
422 // Make sure checksum is valid.
424 PseudoCheckSum
= NetIp6PseudoHeadChecksum (
425 &Head
->SourceAddress
,
426 &Head
->DestinationAddress
,
430 CheckSum
= (UINT16
) ~NetAddChecksum (PseudoCheckSum
, NetbufChecksum (Packet
));
436 // According to the packet type, call corresponding process
438 if (Icmp
.Type
<= ICMP_V6_ERROR_MAX
) {
439 return Ip6ProcessIcmpError (IpSb
, Head
, Packet
);
441 return Ip6ProcessIcmpInformation (IpSb
, Head
, Packet
);
446 return EFI_INVALID_PARAMETER
;
450 Retrieve the Prefix address according to the PrefixLength by clear the useless
453 @param[in] PrefixLength The prefix length of the prefix.
454 @param[in, out] Prefix On input, points to the original prefix address
455 with dirty bits; on output, points to the updated
456 address with useless bit clear.
461 IN UINT8 PrefixLength
,
462 IN OUT EFI_IPv6_ADDRESS
*Prefix
470 ASSERT ((Prefix
!= NULL
) && (PrefixLength
< IP6_PREFIX_MAX
));
472 if (PrefixLength
== 0) {
473 ZeroMem (Prefix
, sizeof (EFI_IPv6_ADDRESS
));
477 if (PrefixLength
>= IP6_PREFIX_MAX
) {
481 Byte
= (UINT8
)(PrefixLength
/ 8);
482 Bit
= (UINT8
)(PrefixLength
% 8);
483 Value
= Prefix
->Addr
[Byte
];
486 ZeroMem (Prefix
->Addr
+ Byte
, 16 - Byte
);
490 Mask
= (UINT8
)(0xFF << (8 - Bit
));
491 Prefix
->Addr
[Byte
] = (UINT8
)(Value
& Mask
);
496 Check whether the DestinationAddress is an anycast address.
498 @param[in] IpSb The IP service that received the packet.
499 @param[in] DestinationAddress Points to the Destination Address of the packet.
501 @retval TRUE The DestinationAddress is anycast address.
502 @retval FALSE The DestinationAddress is not anycast address.
507 IN IP6_SERVICE
*IpSb
,
508 IN EFI_IPv6_ADDRESS
*DestinationAddress
511 IP6_PREFIX_LIST_ENTRY
*PrefixEntry
;
512 EFI_IPv6_ADDRESS Prefix
;
515 ZeroMem (&Prefix
, sizeof (EFI_IPv6_ADDRESS
));
520 // If the address is known as on-link or autonomous prefix, record it as
524 PrefixEntry
= Ip6FindPrefixListEntry (IpSb
, Flag
, 255, DestinationAddress
);
525 if (PrefixEntry
!= NULL
) {
526 IP6_COPY_ADDRESS (&Prefix
, &PrefixEntry
->Prefix
);
527 Ip6GetPrefix (PrefixEntry
->PrefixLength
, &Prefix
);
528 if (EFI_IP6_EQUAL (&Prefix
, DestinationAddress
)) {
533 Flag
= (BOOLEAN
) !Flag
;
540 Generate ICMPv6 error message and send it out to DestinationAddress. Currently
541 Destination Unreachable message, Time Exceeded message and Parameter Problem
542 message are supported.
544 @param[in] IpSb The IP service that received the packet.
545 @param[in] Packet The packet which invoking ICMPv6 error.
546 @param[in] SourceAddress If not NULL, points to the SourceAddress.
547 Otherwise, the IP layer will select a source address
548 according to the DestinationAddress.
549 @param[in] DestinationAddress Points to the Destination Address of the ICMPv6
551 @param[in] Type The type of the ICMPv6 message.
552 @param[in] Code The additional level of the ICMPv6 message.
553 @param[in] Pointer If not NULL, identifies the octet offset within
554 the invoking packet where the error was detected.
556 @retval EFI_INVALID_PARAMETER The packet is malformatted.
557 @retval EFI_OUT_OF_RESOURCES There is no sufficient resource to complete the
559 @retval EFI_SUCCESS The ICMPv6 message was successfully sent out.
560 @retval Others Failed to generate the ICMPv6 packet.
565 IN IP6_SERVICE
*IpSb
,
567 IN EFI_IPv6_ADDRESS
*SourceAddress OPTIONAL
,
568 IN EFI_IPv6_ADDRESS
*DestinationAddress
,
571 IN UINT32
*Pointer OPTIONAL
578 IP6_ICMP_INFORMATION_HEAD
*IcmpHead
;
581 if (DestinationAddress
== NULL
) {
582 return EFI_INVALID_PARAMETER
;
586 // An ICMPv6 error message must not be originated as a result of receiving
587 // a packet whose source address does not uniquely identify a single node --
588 // e.g., the IPv6 Unspecified Address, an IPv6 multicast address, or an address
589 // known by the ICMP message originator to be an IPv6 anycast address.
591 if (NetIp6IsUnspecifiedAddr (DestinationAddress
) ||
592 IP6_IS_MULTICAST (DestinationAddress
) ||
593 Ip6IsAnycast (IpSb
, DestinationAddress
)
596 return EFI_INVALID_PARAMETER
;
600 case ICMP_V6_DEST_UNREACHABLE
:
601 case ICMP_V6_TIME_EXCEEDED
:
604 case ICMP_V6_PARAMETER_PROBLEM
:
605 if (Pointer
== NULL
) {
606 return EFI_INVALID_PARAMETER
;
612 return EFI_INVALID_PARAMETER
;
615 PacketLen
= sizeof (IP6_ICMP_ERROR_HEAD
) + Packet
->TotalSize
;
617 if (PacketLen
> IpSb
->MaxPacketSize
) {
618 PacketLen
= IpSb
->MaxPacketSize
;
621 ErrorMsg
= NetbufAlloc (PacketLen
);
622 if (ErrorMsg
== NULL
) {
623 return EFI_OUT_OF_RESOURCES
;
626 PayloadLen
= (UINT16
)(PacketLen
- sizeof (EFI_IP6_HEADER
));
629 // Create the basic IPv6 header.
631 ZeroMem (&Head
, sizeof (EFI_IP6_HEADER
));
633 Head
.PayloadLength
= HTONS (PayloadLen
);
634 Head
.NextHeader
= IP6_ICMP
;
635 Head
.HopLimit
= IpSb
->CurHopLimit
;
637 if (SourceAddress
!= NULL
) {
638 IP6_COPY_ADDRESS (&Head
.SourceAddress
, SourceAddress
);
640 ZeroMem (&Head
.SourceAddress
, sizeof (EFI_IPv6_ADDRESS
));
643 IP6_COPY_ADDRESS (&Head
.DestinationAddress
, DestinationAddress
);
645 NetbufReserve (ErrorMsg
, sizeof (EFI_IP6_HEADER
));
648 // Fill in the ICMP error message head
650 IcmpHead
= (IP6_ICMP_INFORMATION_HEAD
*)NetbufAllocSpace (ErrorMsg
, sizeof (IP6_ICMP_INFORMATION_HEAD
), FALSE
);
651 if (IcmpHead
== NULL
) {
652 NetbufFree (ErrorMsg
);
653 return EFI_OUT_OF_RESOURCES
;
656 ZeroMem (IcmpHead
, sizeof (IP6_ICMP_INFORMATION_HEAD
));
657 IcmpHead
->Head
.Type
= Type
;
658 IcmpHead
->Head
.Code
= Code
;
660 if (Pointer
!= NULL
) {
661 IcmpHead
->Fourth
= HTONL (*Pointer
);
665 // Fill in the ICMP error message body
667 PayloadLen
-= sizeof (IP6_ICMP_INFORMATION_HEAD
);
668 ErrorBody
= NetbufAllocSpace (ErrorMsg
, PayloadLen
, FALSE
);
669 if (ErrorBody
!= NULL
) {
670 ZeroMem (ErrorBody
, PayloadLen
);
671 NetbufCopy (Packet
, 0, PayloadLen
, ErrorBody
);
675 // Transmit the packet
677 return Ip6Output (IpSb
, NULL
, NULL
, ErrorMsg
, &Head
, NULL
, 0, Ip6SysPacketSent
, NULL
);