2 The ICMPv6 handle routines to process the ICMPv6 control messages.
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 EFI_IP6_ICMP_TYPE mIp6SupportedIcmp
[23] = {
21 ICMP_V6_DEST_UNREACHABLE
,
22 ICMP_V6_NO_ROUTE_TO_DEST
25 ICMP_V6_DEST_UNREACHABLE
,
26 ICMP_V6_COMM_PROHIBITED
29 ICMP_V6_DEST_UNREACHABLE
,
33 ICMP_V6_DEST_UNREACHABLE
,
34 ICMP_V6_ADDR_UNREACHABLE
37 ICMP_V6_DEST_UNREACHABLE
,
38 ICMP_V6_PORT_UNREACHABLE
41 ICMP_V6_DEST_UNREACHABLE
,
42 ICMP_V6_SOURCE_ADDR_FAILED
45 ICMP_V6_DEST_UNREACHABLE
,
46 ICMP_V6_ROUTE_REJECTED
50 ICMP_V6_PACKET_TOO_BIG
,
55 ICMP_V6_TIME_EXCEEDED
,
56 ICMP_V6_TIMEOUT_HOP_LIMIT
59 ICMP_V6_TIME_EXCEEDED
,
60 ICMP_V6_TIMEOUT_REASSEMBLE
64 ICMP_V6_PARAMETER_PROBLEM
,
65 ICMP_V6_ERRONEOUS_HEADER
68 ICMP_V6_PARAMETER_PROBLEM
,
69 ICMP_V6_UNRECOGNIZE_NEXT_HDR
72 ICMP_V6_PARAMETER_PROBLEM
,
73 ICMP_V6_UNRECOGNIZE_OPTION
86 ICMP_V6_LISTENER_QUERY
,
90 ICMP_V6_LISTENER_REPORT
,
94 ICMP_V6_LISTENER_REPORT_2
,
98 ICMP_V6_LISTENER_DONE
,
103 ICMP_V6_ROUTER_SOLICIT
,
107 ICMP_V6_ROUTER_ADVERTISE
,
111 ICMP_V6_NEIGHBOR_SOLICIT
,
115 ICMP_V6_NEIGHBOR_ADVERTISE
,
121 Reply an ICMPv6 echo request.
123 @param[in] IpSb The IP service that received the packet.
124 @param[in] Head The IP head of the ICMPv6 informational message.
125 @param[in] Packet The content of the ICMPv6 message with the IP head
128 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
129 @retval EFI_SUCCESS Successfully answered the ICMPv6 Echo request.
130 @retval Others Failed to answer the ICMPv6 Echo request.
135 IN IP6_SERVICE
*IpSb
,
136 IN EFI_IP6_HEADER
*Head
,
140 IP6_ICMP_INFORMATION_HEAD
*Icmp
;
143 EFI_IP6_HEADER ReplyHead
;
145 Status
= EFI_OUT_OF_RESOURCES
;
147 // make a copy the packet, it is really a bad idea to
148 // send the MNP's buffer back to MNP.
150 Data
= NetbufDuplicate (Packet
, NULL
, IP6_MAX_HEADLEN
);
156 // Change the ICMP type to echo reply, exchange the source
157 // and destination, then send it. The source is updated to
158 // use specific destination. See RFC1122. SRR/RR option
159 // update is omitted.
161 Icmp
= (IP6_ICMP_INFORMATION_HEAD
*) NetbufGetByte (Data
, 0, NULL
);
167 Icmp
->Head
.Type
= ICMP_V6_ECHO_REPLY
;
168 Icmp
->Head
.Checksum
= 0;
171 // Generate the IPv6 basic header
172 // If the Echo Reply is a response to a Echo Request sent to one of the node's unicast address,
173 // the Source address of the Echo Reply must be the same address.
175 ZeroMem (&ReplyHead
, sizeof (EFI_IP6_HEADER
));
177 ReplyHead
.PayloadLength
= HTONS ((UINT16
) (Packet
->TotalSize
));
178 ReplyHead
.NextHeader
= IP6_ICMP
;
179 ReplyHead
.HopLimit
= IpSb
->CurHopLimit
;
180 IP6_COPY_ADDRESS (&ReplyHead
.DestinationAddress
, &Head
->SourceAddress
);
182 if (Ip6IsOneOfSetAddress (IpSb
, &Head
->DestinationAddress
, NULL
, NULL
)) {
183 IP6_COPY_ADDRESS (&ReplyHead
.SourceAddress
, &Head
->DestinationAddress
);
187 // If source is unspecified, Ip6Output will select a source for us
207 Process Packet Too Big message sent by a router in response to a packet that
208 it cannot forward because the packet is larger than the MTU of outgoing link.
209 Since this driver already uses IPv6 minimum link MTU as the maximum packet size,
210 if Packet Too Big message is still received, do not reduce the packet size, but
211 rather include a Fragment header in the subsequent packets.
213 @param[in] IpSb The IP service that received the packet.
214 @param[in] Head The IP head of the ICMPv6 error packet.
215 @param[in] Packet The content of the ICMPv6 error with the IP head
218 @retval EFI_SUCCESS The ICMPv6 error processed successfully.
219 @retval EFI_OUT_OF_RESOURCES Failed to finish the operation due to lack of
221 @retval EFI_NOT_FOUND The packet too big message is not sent to us.
225 Ip6ProcessPacketTooBig (
226 IN IP6_SERVICE
*IpSb
,
227 IN EFI_IP6_HEADER
*Head
,
231 IP6_ICMP_ERROR_HEAD Icmp
;
233 IP6_ROUTE_ENTRY
*RouteEntry
;
234 EFI_IPv6_ADDRESS
*DestAddress
;
236 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*) &Icmp
);
237 Mtu
= NTOHL (Icmp
.Fourth
);
238 DestAddress
= &Icmp
.IpHead
.DestinationAddress
;
240 if (Mtu
< IP6_MIN_LINK_MTU
) {
242 // Normally the multicast address is considered to be on-link and not recorded
243 // in route table. Here it is added into the table since the MTU information
246 if (IP6_IS_MULTICAST (DestAddress
)) {
247 RouteEntry
= Ip6CreateRouteEntry (DestAddress
, 128, NULL
);
248 if (RouteEntry
== NULL
) {
250 return EFI_OUT_OF_RESOURCES
;
253 RouteEntry
->Flag
= IP6_DIRECT_ROUTE
| IP6_PACKET_TOO_BIG
;
254 InsertHeadList (&IpSb
->RouteTable
->RouteArea
[128], &RouteEntry
->Link
);
255 IpSb
->RouteTable
->TotalNum
++;
257 RouteEntry
= Ip6FindRouteEntry (IpSb
->RouteTable
, DestAddress
, NULL
);
258 if (RouteEntry
== NULL
) {
260 return EFI_NOT_FOUND
;
263 RouteEntry
->Flag
= RouteEntry
->Flag
| IP6_PACKET_TOO_BIG
;
265 Ip6FreeRouteEntry (RouteEntry
);
274 Process the ICMPv6 error packet, and deliver the packet to upper layer.
276 @param[in] IpSb The IP service that received the packet.
277 @param[in] Head The IP head of the ICMPv6 error packet.
278 @param[in] Packet The content of the ICMPv6 error with the IP head
281 @retval EFI_SUCCESS The ICMPv6 error processed successfully.
282 @retval EFI_INVALID_PARAMETER The packet is invalid.
283 @retval Others Failed to process the packet.
287 Ip6ProcessIcmpError (
288 IN IP6_SERVICE
*IpSb
,
289 IN EFI_IP6_HEADER
*Head
,
293 IP6_ICMP_ERROR_HEAD Icmp
;
296 // Check the validity of the packet
298 if (Packet
->TotalSize
< sizeof (Icmp
)) {
302 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*) &Icmp
);
303 if (Icmp
.Head
.Type
== ICMP_V6_PACKET_TOO_BIG
) {
304 return Ip6ProcessPacketTooBig (IpSb
, Head
, Packet
);
308 // Notify the upper-layer process that an ICMPv6 eror message is received.
310 IP6_GET_CLIP_INFO (Packet
)->Status
= EFI_ICMP_ERROR
;
311 return Ip6Demultiplex (IpSb
, Head
, Packet
);
316 return EFI_INVALID_PARAMETER
;
320 Process the ICMPv6 informational messages. If it is an ICMPv6 echo
321 request, answer it. If it is a MLD message, trigger MLD routines to
322 process it. If it is a ND message, trigger ND routines to process it.
323 Otherwise, deliver it to upper layer.
325 @param[in] IpSb The IP service that receivd the packet.
326 @param[in] Head The IP head of the ICMPv6 informational packet.
327 @param[in] Packet The content of the ICMPv6 informational packet
328 with IP head removed.
330 @retval EFI_INVALID_PARAMETER The packet is invalid.
331 @retval EFI_SUCCESS The ICMPv6 informational message processed.
332 @retval Others Failed to process ICMPv6 informational message.
336 Ip6ProcessIcmpInformation (
337 IN IP6_SERVICE
*IpSb
,
338 IN EFI_IP6_HEADER
*Head
,
342 IP6_ICMP_INFORMATION_HEAD Icmp
;
345 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
346 NET_CHECK_SIGNATURE (Packet
, NET_BUF_SIGNATURE
);
347 ASSERT (Head
!= NULL
);
349 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*) &Icmp
);
350 Status
= EFI_INVALID_PARAMETER
;
352 switch (Icmp
.Head
.Type
) {
353 case ICMP_V6_ECHO_REQUEST
:
355 // If ICMPv6 echo, reply it
357 if (Icmp
.Head
.Code
== 0) {
358 Status
= Ip6IcmpReplyEcho (IpSb
, Head
, Packet
);
361 case ICMP_V6_LISTENER_QUERY
:
362 Status
= Ip6ProcessMldQuery (IpSb
, Head
, Packet
);
364 case ICMP_V6_LISTENER_REPORT
:
365 case ICMP_V6_LISTENER_REPORT_2
:
366 Status
= Ip6ProcessMldReport (IpSb
, Head
, Packet
);
368 case ICMP_V6_NEIGHBOR_SOLICIT
:
369 Status
= Ip6ProcessNeighborSolicit (IpSb
, Head
, Packet
);
371 case ICMP_V6_NEIGHBOR_ADVERTISE
:
372 Status
= Ip6ProcessNeighborAdvertise (IpSb
, Head
, Packet
);
374 case ICMP_V6_ROUTER_ADVERTISE
:
375 Status
= Ip6ProcessRouterAdvertise (IpSb
, Head
, Packet
);
377 case ICMP_V6_REDIRECT
:
378 Status
= Ip6ProcessRedirect (IpSb
, Head
, Packet
);
380 case ICMP_V6_ECHO_REPLY
:
381 Status
= Ip6Demultiplex (IpSb
, Head
, Packet
);
384 Status
= EFI_INVALID_PARAMETER
;
392 Handle the ICMPv6 packet. First validate the message format,
393 then, according to the message types, process it as an informational packet or
396 @param[in] IpSb The IP service that received the packet.
397 @param[in] Head The IP head of the ICMPv6 packet.
398 @param[in] Packet The content of the ICMPv6 packet with IP head
401 @retval EFI_INVALID_PARAMETER The packet is malformated.
402 @retval EFI_SUCCESS The ICMPv6 message successfully processed.
403 @retval Others Failed to handle the ICMPv6 packet.
408 IN IP6_SERVICE
*IpSb
,
409 IN EFI_IP6_HEADER
*Head
,
414 UINT16 PseudoCheckSum
;
418 // Check the validity of the incoming packet.
420 if (Packet
->TotalSize
< sizeof (Icmp
)) {
424 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*) &Icmp
);
427 // Make sure checksum is valid.
429 PseudoCheckSum
= NetIp6PseudoHeadChecksum (
430 &Head
->SourceAddress
,
431 &Head
->DestinationAddress
,
435 CheckSum
= (UINT16
) ~NetAddChecksum (PseudoCheckSum
, NetbufChecksum (Packet
));
441 // According to the packet type, call corresponding process
443 if (Icmp
.Type
<= ICMP_V6_ERROR_MAX
) {
444 return Ip6ProcessIcmpError (IpSb
, Head
, Packet
);
446 return Ip6ProcessIcmpInformation (IpSb
, Head
, Packet
);
451 return EFI_INVALID_PARAMETER
;
455 Retrieve the Prefix address according to the PrefixLength by clear the useless
458 @param[in] PrefixLength The prefix length of the prefix.
459 @param[in, out] Prefix On input, points to the original prefix address
460 with dirty bits; on output, points to the updated
461 address with useless bit clear.
466 IN UINT8 PrefixLength
,
467 IN OUT EFI_IPv6_ADDRESS
*Prefix
475 ASSERT ((Prefix
!= NULL
) && (PrefixLength
< IP6_PREFIX_NUM
));
477 if (PrefixLength
== 0) {
478 ZeroMem (Prefix
, sizeof (EFI_IPv6_ADDRESS
));
482 if (PrefixLength
== IP6_PREFIX_NUM
- 1) {
486 Byte
= (UINT8
) (PrefixLength
/ 8);
487 Bit
= (UINT8
) (PrefixLength
% 8);
488 Value
= Prefix
->Addr
[Byte
];
490 if ((Byte
> 0) && (Byte
< 16)) {
491 ZeroMem (Prefix
->Addr
+ Byte
, 16 - Byte
);
495 Mask
= (UINT8
) (0xFF << (8 - Bit
));
496 Prefix
->Addr
[Byte
] = (UINT8
) (Value
& Mask
);
502 Check whether the DestinationAddress is an anycast address.
504 @param[in] IpSb The IP service that received the packet.
505 @param[in] DestinationAddress Points to the Destination Address of the packet.
507 @retval TRUE The DestinationAddress is anycast address.
508 @retval FALSE The DestinationAddress is not anycast address.
513 IN IP6_SERVICE
*IpSb
,
514 IN EFI_IPv6_ADDRESS
*DestinationAddress
517 IP6_PREFIX_LIST_ENTRY
*PrefixEntry
;
518 EFI_IPv6_ADDRESS Prefix
;
521 ZeroMem (&Prefix
, sizeof (EFI_IPv6_ADDRESS
));
526 // If the address is known as on-link or autonomous prefix, record it as
530 PrefixEntry
= Ip6FindPrefixListEntry (IpSb
, Flag
, 255, DestinationAddress
);
531 if (PrefixEntry
!= NULL
) {
532 IP6_COPY_ADDRESS (&Prefix
, &PrefixEntry
->Prefix
);
533 Ip6GetPrefix (PrefixEntry
->PrefixLength
, &Prefix
);
534 if (EFI_IP6_EQUAL (&Prefix
, DestinationAddress
)) {
539 Flag
= (BOOLEAN
) !Flag
;
546 Generate ICMPv6 error message and send it out to DestinationAddress. Currently
547 Destination Unreachable message, Time Exceeded message and Parameter Problem
548 message are supported.
550 @param[in] IpSb The IP service that received the packet.
551 @param[in] Packet The packet which invoking ICMPv6 error.
552 @param[in] SourceAddress If not NULL, points to the SourceAddress.
553 Otherwise, the IP layer will select a source address
554 according to the DestinationAddress.
555 @param[in] DestinationAddress Points to the Destination Address of the ICMPv6
557 @param[in] Type The type of the ICMPv6 message.
558 @param[in] Code The additional level of the ICMPv6 message.
559 @param[in] Pointer If not NULL, identifies the octet offset within
560 the invoking packet where the error was detected.
562 @retval EFI_INVALID_PARAMETER The packet is malformated.
563 @retval EFI_OUT_OF_RESOURCES There is no sufficient resource to complete the
565 @retval EFI_SUCCESS The ICMPv6 message was successfully sent out.
566 @retval Others Failed to generate the ICMPv6 packet.
571 IN IP6_SERVICE
*IpSb
,
573 IN EFI_IPv6_ADDRESS
*SourceAddress OPTIONAL
,
574 IN EFI_IPv6_ADDRESS
*DestinationAddress
,
577 IN UINT32
*Pointer OPTIONAL
584 IP6_ICMP_INFORMATION_HEAD
*IcmpHead
;
587 if (DestinationAddress
== NULL
) {
588 return EFI_INVALID_PARAMETER
;
592 // An ICMPv6 error message must not be originated as a result of receiving
593 // a packet whose source address does not uniquely identify a single node --
594 // e.g., the IPv6 Unspecified Address, an IPv6 multicast address, or an address
595 // known by the ICMP message originator to be an IPv6 anycast address.
597 if (NetIp6IsUnspecifiedAddr (DestinationAddress
) ||
598 IP6_IS_MULTICAST (DestinationAddress
) ||
599 Ip6IsAnycast (IpSb
, DestinationAddress
)
601 return EFI_INVALID_PARAMETER
;
605 case ICMP_V6_DEST_UNREACHABLE
:
606 case ICMP_V6_TIME_EXCEEDED
:
609 case ICMP_V6_PARAMETER_PROBLEM
:
610 if (Pointer
== NULL
) {
611 return EFI_INVALID_PARAMETER
;
617 return EFI_INVALID_PARAMETER
;
620 PacketLen
= sizeof (IP6_ICMP_ERROR_HEAD
) + Packet
->TotalSize
;
622 if (PacketLen
> IpSb
->MaxPacketSize
) {
623 PacketLen
= IpSb
->MaxPacketSize
;
626 ErrorMsg
= NetbufAlloc (PacketLen
);
627 if (ErrorMsg
== NULL
) {
628 return EFI_OUT_OF_RESOURCES
;
631 PayloadLen
= (UINT16
) (PacketLen
- sizeof (EFI_IP6_HEADER
));
634 // Create the basic IPv6 header.
636 ZeroMem (&Head
, sizeof (EFI_IP6_HEADER
));
638 Head
.PayloadLength
= HTONS (PayloadLen
);
639 Head
.NextHeader
= IP6_ICMP
;
640 Head
.HopLimit
= IpSb
->CurHopLimit
;
642 if (SourceAddress
!= NULL
) {
643 IP6_COPY_ADDRESS (&Head
.SourceAddress
, SourceAddress
);
645 ZeroMem (&Head
.SourceAddress
, sizeof (EFI_IPv6_ADDRESS
));
648 IP6_COPY_ADDRESS (&Head
.DestinationAddress
, DestinationAddress
);
650 NetbufReserve (ErrorMsg
, sizeof (EFI_IP6_HEADER
));
653 // Fill in the ICMP error message head
655 IcmpHead
= (IP6_ICMP_INFORMATION_HEAD
*) NetbufAllocSpace (ErrorMsg
, sizeof (IP6_ICMP_INFORMATION_HEAD
), FALSE
);
656 if (IcmpHead
== NULL
) {
657 NetbufFree (ErrorMsg
);
658 return EFI_OUT_OF_RESOURCES
;
661 ZeroMem (IcmpHead
, sizeof (IP6_ICMP_INFORMATION_HEAD
));
662 IcmpHead
->Head
.Type
= Type
;
663 IcmpHead
->Head
.Code
= Code
;
665 if (Pointer
!= NULL
) {
666 IcmpHead
->Fourth
= HTONL (*Pointer
);
670 // Fill in the ICMP error message body
672 PayloadLen
-= sizeof (IP6_ICMP_INFORMATION_HEAD
);
673 ErrorBody
= NetbufAllocSpace (ErrorMsg
, PayloadLen
, FALSE
);
674 if (ErrorBody
!= NULL
) {
675 ZeroMem (ErrorBody
, PayloadLen
);
676 NetbufCopy (Packet
, 0, PayloadLen
, ErrorBody
);
680 // Transmit the packet
682 return Ip6Output (IpSb
, NULL
, NULL
, ErrorMsg
, &Head
, NULL
, 0, Ip6SysPacketSent
, NULL
);