]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Ip6Dxe/Ip6Icmp.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / NetworkPkg / Ip6Dxe / Ip6Icmp.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 The ICMPv6 handle routines to process the ICMPv6 control messages.\r
3\r
f75a7f56 4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
40696972 5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
f75a7f56 6\r
ecf98fbc 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a3bcde70
HT
8\r
9**/\r
10\r
11#include "Ip6Impl.h"\r
12\r
d1050b9d 13EFI_IP6_ICMP_TYPE mIp6SupportedIcmp[23] = {\r
a3bcde70
HT
14 {\r
15 ICMP_V6_DEST_UNREACHABLE,\r
16 ICMP_V6_NO_ROUTE_TO_DEST\r
17 },\r
18 {\r
19 ICMP_V6_DEST_UNREACHABLE,\r
20 ICMP_V6_COMM_PROHIBITED\r
21 },\r
22 {\r
23 ICMP_V6_DEST_UNREACHABLE,\r
24 ICMP_V6_BEYOND_SCOPE\r
25 },\r
26 {\r
27 ICMP_V6_DEST_UNREACHABLE,\r
28 ICMP_V6_ADDR_UNREACHABLE\r
29 },\r
30 {\r
31 ICMP_V6_DEST_UNREACHABLE,\r
32 ICMP_V6_PORT_UNREACHABLE\r
33 },\r
34 {\r
35 ICMP_V6_DEST_UNREACHABLE,\r
36 ICMP_V6_SOURCE_ADDR_FAILED\r
37 },\r
38 {\r
39 ICMP_V6_DEST_UNREACHABLE,\r
40 ICMP_V6_ROUTE_REJECTED\r
41 },\r
42\r
43 {\r
44 ICMP_V6_PACKET_TOO_BIG,\r
45 ICMP_V6_DEFAULT_CODE\r
46 },\r
47\r
48 {\r
49 ICMP_V6_TIME_EXCEEDED,\r
50 ICMP_V6_TIMEOUT_HOP_LIMIT\r
51 },\r
52 {\r
53 ICMP_V6_TIME_EXCEEDED,\r
54 ICMP_V6_TIMEOUT_REASSEMBLE\r
55 },\r
56\r
57 {\r
58 ICMP_V6_PARAMETER_PROBLEM,\r
59 ICMP_V6_ERRONEOUS_HEADER\r
60 },\r
61 {\r
62 ICMP_V6_PARAMETER_PROBLEM,\r
63 ICMP_V6_UNRECOGNIZE_NEXT_HDR\r
64 },\r
65 {\r
66 ICMP_V6_PARAMETER_PROBLEM,\r
67 ICMP_V6_UNRECOGNIZE_OPTION\r
68 },\r
69\r
70 {\r
71 ICMP_V6_ECHO_REQUEST,\r
72 ICMP_V6_DEFAULT_CODE\r
73 },\r
74 {\r
75 ICMP_V6_ECHO_REPLY,\r
76 ICMP_V6_DEFAULT_CODE\r
77 },\r
78\r
79 {\r
80 ICMP_V6_LISTENER_QUERY,\r
81 ICMP_V6_DEFAULT_CODE\r
82 },\r
83 {\r
84 ICMP_V6_LISTENER_REPORT,\r
85 ICMP_V6_DEFAULT_CODE\r
86 },\r
87 {\r
88 ICMP_V6_LISTENER_REPORT_2,\r
89 ICMP_V6_DEFAULT_CODE\r
90 },\r
91 {\r
92 ICMP_V6_LISTENER_DONE,\r
93 ICMP_V6_DEFAULT_CODE\r
94 },\r
95\r
96 {\r
97 ICMP_V6_ROUTER_SOLICIT,\r
98 ICMP_V6_DEFAULT_CODE\r
99 },\r
100 {\r
101 ICMP_V6_ROUTER_ADVERTISE,\r
102 ICMP_V6_DEFAULT_CODE\r
103 },\r
104 {\r
105 ICMP_V6_NEIGHBOR_SOLICIT,\r
106 ICMP_V6_DEFAULT_CODE\r
107 },\r
108 {\r
109 ICMP_V6_NEIGHBOR_ADVERTISE,\r
110 ICMP_V6_DEFAULT_CODE\r
111 },\r
112};\r
113\r
114/**\r
115 Reply an ICMPv6 echo request.\r
116\r
117 @param[in] IpSb The IP service that received the packet.\r
118 @param[in] Head The IP head of the ICMPv6 informational message.\r
119 @param[in] Packet The content of the ICMPv6 message with the IP head\r
120 removed.\r
121\r
122 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
123 @retval EFI_SUCCESS Successfully answered the ICMPv6 Echo request.\r
124 @retval Others Failed to answer the ICMPv6 Echo request.\r
125\r
126**/\r
127EFI_STATUS\r
128Ip6IcmpReplyEcho (\r
d1050b9d
MK
129 IN IP6_SERVICE *IpSb,\r
130 IN EFI_IP6_HEADER *Head,\r
131 IN NET_BUF *Packet\r
a3bcde70
HT
132 )\r
133{\r
d1050b9d
MK
134 IP6_ICMP_INFORMATION_HEAD *Icmp;\r
135 NET_BUF *Data;\r
136 EFI_STATUS Status;\r
137 EFI_IP6_HEADER ReplyHead;\r
a3bcde70
HT
138\r
139 Status = EFI_OUT_OF_RESOURCES;\r
140 //\r
141 // make a copy the packet, it is really a bad idea to\r
142 // send the MNP's buffer back to MNP.\r
143 //\r
144 Data = NetbufDuplicate (Packet, NULL, IP6_MAX_HEADLEN);\r
145 if (Data == NULL) {\r
146 goto Exit;\r
147 }\r
148\r
149 //\r
150 // Change the ICMP type to echo reply, exchange the source\r
151 // and destination, then send it. The source is updated to\r
152 // use specific destination. See RFC1122. SRR/RR option\r
153 // update is omitted.\r
154 //\r
d1050b9d 155 Icmp = (IP6_ICMP_INFORMATION_HEAD *)NetbufGetByte (Data, 0, NULL);\r
a3bcde70
HT
156 if (Icmp == NULL) {\r
157 NetbufFree (Data);\r
158 goto Exit;\r
159 }\r
160\r
161 Icmp->Head.Type = ICMP_V6_ECHO_REPLY;\r
162 Icmp->Head.Checksum = 0;\r
163\r
164 //\r
165 // Generate the IPv6 basic header\r
166 // If the Echo Reply is a response to a Echo Request sent to one of the node's unicast address,\r
167 // the Source address of the Echo Reply must be the same address.\r
168 //\r
169 ZeroMem (&ReplyHead, sizeof (EFI_IP6_HEADER));\r
170\r
d1050b9d
MK
171 ReplyHead.PayloadLength = HTONS ((UINT16)(Packet->TotalSize));\r
172 ReplyHead.NextHeader = IP6_ICMP;\r
173 ReplyHead.HopLimit = IpSb->CurHopLimit;\r
a3bcde70
HT
174 IP6_COPY_ADDRESS (&ReplyHead.DestinationAddress, &Head->SourceAddress);\r
175\r
176 if (Ip6IsOneOfSetAddress (IpSb, &Head->DestinationAddress, NULL, NULL)) {\r
177 IP6_COPY_ADDRESS (&ReplyHead.SourceAddress, &Head->DestinationAddress);\r
178 }\r
179\r
180 //\r
181 // If source is unspecified, Ip6Output will select a source for us\r
182 //\r
183 Status = Ip6Output (\r
184 IpSb,\r
185 NULL,\r
186 NULL,\r
187 Data,\r
188 &ReplyHead,\r
189 NULL,\r
190 0,\r
191 Ip6SysPacketSent,\r
192 NULL\r
193 );\r
194\r
195Exit:\r
196 NetbufFree (Packet);\r
197 return Status;\r
198}\r
199\r
200/**\r
201 Process Packet Too Big message sent by a router in response to a packet that\r
202 it cannot forward because the packet is larger than the MTU of outgoing link.\r
203 Since this driver already uses IPv6 minimum link MTU as the maximum packet size,\r
204 if Packet Too Big message is still received, do not reduce the packet size, but\r
205 rather include a Fragment header in the subsequent packets.\r
206\r
207 @param[in] IpSb The IP service that received the packet.\r
208 @param[in] Head The IP head of the ICMPv6 error packet.\r
209 @param[in] Packet The content of the ICMPv6 error with the IP head\r
210 removed.\r
211\r
212 @retval EFI_SUCCESS The ICMPv6 error processed successfully.\r
213 @retval EFI_OUT_OF_RESOURCES Failed to finish the operation due to lack of\r
214 resource.\r
215 @retval EFI_NOT_FOUND The packet too big message is not sent to us.\r
216\r
217**/\r
218EFI_STATUS\r
219Ip6ProcessPacketTooBig (\r
d1050b9d
MK
220 IN IP6_SERVICE *IpSb,\r
221 IN EFI_IP6_HEADER *Head,\r
222 IN NET_BUF *Packet\r
a3bcde70
HT
223 )\r
224{\r
d1050b9d
MK
225 IP6_ICMP_ERROR_HEAD Icmp;\r
226 UINT32 Mtu;\r
227 IP6_ROUTE_ENTRY *RouteEntry;\r
228 EFI_IPv6_ADDRESS *DestAddress;\r
a3bcde70 229\r
d1050b9d 230 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *)&Icmp);\r
a3bcde70
HT
231 Mtu = NTOHL (Icmp.Fourth);\r
232 DestAddress = &Icmp.IpHead.DestinationAddress;\r
233\r
234 if (Mtu < IP6_MIN_LINK_MTU) {\r
235 //\r
236 // Normally the multicast address is considered to be on-link and not recorded\r
237 // in route table. Here it is added into the table since the MTU information\r
238 // need be recorded.\r
239 //\r
240 if (IP6_IS_MULTICAST (DestAddress)) {\r
241 RouteEntry = Ip6CreateRouteEntry (DestAddress, 128, NULL);\r
242 if (RouteEntry == NULL) {\r
243 NetbufFree (Packet);\r
244 return EFI_OUT_OF_RESOURCES;\r
245 }\r
246\r
247 RouteEntry->Flag = IP6_DIRECT_ROUTE | IP6_PACKET_TOO_BIG;\r
248 InsertHeadList (&IpSb->RouteTable->RouteArea[128], &RouteEntry->Link);\r
249 IpSb->RouteTable->TotalNum++;\r
250 } else {\r
251 RouteEntry = Ip6FindRouteEntry (IpSb->RouteTable, DestAddress, NULL);\r
252 if (RouteEntry == NULL) {\r
253 NetbufFree (Packet);\r
254 return EFI_NOT_FOUND;\r
255 }\r
256\r
257 RouteEntry->Flag = RouteEntry->Flag | IP6_PACKET_TOO_BIG;\r
258\r
259 Ip6FreeRouteEntry (RouteEntry);\r
260 }\r
261 }\r
262\r
263 NetbufFree (Packet);\r
264 return EFI_SUCCESS;\r
265}\r
266\r
267/**\r
268 Process the ICMPv6 error packet, and deliver the packet to upper layer.\r
269\r
270 @param[in] IpSb The IP service that received the packet.\r
271 @param[in] Head The IP head of the ICMPv6 error packet.\r
272 @param[in] Packet The content of the ICMPv6 error with the IP head\r
273 removed.\r
274\r
275 @retval EFI_SUCCESS The ICMPv6 error processed successfully.\r
276 @retval EFI_INVALID_PARAMETER The packet is invalid.\r
277 @retval Others Failed to process the packet.\r
278\r
279**/\r
280EFI_STATUS\r
281Ip6ProcessIcmpError (\r
d1050b9d
MK
282 IN IP6_SERVICE *IpSb,\r
283 IN EFI_IP6_HEADER *Head,\r
284 IN NET_BUF *Packet\r
a3bcde70
HT
285 )\r
286{\r
d1050b9d 287 IP6_ICMP_ERROR_HEAD Icmp;\r
a3bcde70
HT
288\r
289 //\r
290 // Check the validity of the packet\r
291 //\r
292 if (Packet->TotalSize < sizeof (Icmp)) {\r
293 goto DROP;\r
294 }\r
295\r
d1050b9d 296 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *)&Icmp);\r
a3bcde70
HT
297 if (Icmp.Head.Type == ICMP_V6_PACKET_TOO_BIG) {\r
298 return Ip6ProcessPacketTooBig (IpSb, Head, Packet);\r
299 }\r
300\r
301 //\r
7de8045a 302 // Notify the upper-layer process that an ICMPv6 error message is received.\r
a3bcde70
HT
303 //\r
304 IP6_GET_CLIP_INFO (Packet)->Status = EFI_ICMP_ERROR;\r
305 return Ip6Demultiplex (IpSb, Head, Packet);\r
306\r
307DROP:\r
308 NetbufFree (Packet);\r
309 Packet = NULL;\r
310 return EFI_INVALID_PARAMETER;\r
311}\r
312\r
313/**\r
314 Process the ICMPv6 informational messages. If it is an ICMPv6 echo\r
315 request, answer it. If it is a MLD message, trigger MLD routines to\r
316 process it. If it is a ND message, trigger ND routines to process it.\r
317 Otherwise, deliver it to upper layer.\r
318\r
319 @param[in] IpSb The IP service that receivd the packet.\r
320 @param[in] Head The IP head of the ICMPv6 informational packet.\r
321 @param[in] Packet The content of the ICMPv6 informational packet\r
322 with IP head removed.\r
323\r
324 @retval EFI_INVALID_PARAMETER The packet is invalid.\r
325 @retval EFI_SUCCESS The ICMPv6 informational message processed.\r
326 @retval Others Failed to process ICMPv6 informational message.\r
327\r
328**/\r
329EFI_STATUS\r
330Ip6ProcessIcmpInformation (\r
d1050b9d
MK
331 IN IP6_SERVICE *IpSb,\r
332 IN EFI_IP6_HEADER *Head,\r
333 IN NET_BUF *Packet\r
a3bcde70
HT
334 )\r
335{\r
d1050b9d
MK
336 IP6_ICMP_INFORMATION_HEAD Icmp;\r
337 EFI_STATUS Status;\r
a3bcde70
HT
338\r
339 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
340 NET_CHECK_SIGNATURE (Packet, NET_BUF_SIGNATURE);\r
341 ASSERT (Head != NULL);\r
342\r
d1050b9d 343 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *)&Icmp);\r
a3bcde70
HT
344 Status = EFI_INVALID_PARAMETER;\r
345\r
346 switch (Icmp.Head.Type) {\r
d1050b9d
MK
347 case ICMP_V6_ECHO_REQUEST:\r
348 //\r
349 // If ICMPv6 echo, reply it\r
350 //\r
351 if (Icmp.Head.Code == 0) {\r
352 Status = Ip6IcmpReplyEcho (IpSb, Head, Packet);\r
353 }\r
354\r
355 break;\r
356 case ICMP_V6_LISTENER_QUERY:\r
357 Status = Ip6ProcessMldQuery (IpSb, Head, Packet);\r
358 break;\r
359 case ICMP_V6_LISTENER_REPORT:\r
360 case ICMP_V6_LISTENER_REPORT_2:\r
361 Status = Ip6ProcessMldReport (IpSb, Head, Packet);\r
362 break;\r
363 case ICMP_V6_NEIGHBOR_SOLICIT:\r
364 Status = Ip6ProcessNeighborSolicit (IpSb, Head, Packet);\r
365 break;\r
366 case ICMP_V6_NEIGHBOR_ADVERTISE:\r
367 Status = Ip6ProcessNeighborAdvertise (IpSb, Head, Packet);\r
368 break;\r
369 case ICMP_V6_ROUTER_ADVERTISE:\r
370 Status = Ip6ProcessRouterAdvertise (IpSb, Head, Packet);\r
371 break;\r
372 case ICMP_V6_REDIRECT:\r
373 Status = Ip6ProcessRedirect (IpSb, Head, Packet);\r
374 break;\r
375 case ICMP_V6_ECHO_REPLY:\r
376 Status = Ip6Demultiplex (IpSb, Head, Packet);\r
377 break;\r
378 default:\r
379 Status = EFI_INVALID_PARAMETER;\r
380 break;\r
a3bcde70
HT
381 }\r
382\r
383 return Status;\r
384}\r
385\r
386/**\r
387 Handle the ICMPv6 packet. First validate the message format,\r
388 then, according to the message types, process it as an informational packet or\r
389 an error packet.\r
390\r
391 @param[in] IpSb The IP service that received the packet.\r
392 @param[in] Head The IP head of the ICMPv6 packet.\r
393 @param[in] Packet The content of the ICMPv6 packet with IP head\r
394 removed.\r
395\r
8d774c74 396 @retval EFI_INVALID_PARAMETER The packet is malformatted.\r
a3bcde70
HT
397 @retval EFI_SUCCESS The ICMPv6 message successfully processed.\r
398 @retval Others Failed to handle the ICMPv6 packet.\r
399\r
400**/\r
401EFI_STATUS\r
402Ip6IcmpHandle (\r
d1050b9d
MK
403 IN IP6_SERVICE *IpSb,\r
404 IN EFI_IP6_HEADER *Head,\r
405 IN NET_BUF *Packet\r
a3bcde70
HT
406 )\r
407{\r
d1050b9d
MK
408 IP6_ICMP_HEAD Icmp;\r
409 UINT16 PseudoCheckSum;\r
410 UINT16 CheckSum;\r
a3bcde70
HT
411\r
412 //\r
413 // Check the validity of the incoming packet.\r
414 //\r
415 if (Packet->TotalSize < sizeof (Icmp)) {\r
416 goto DROP;\r
417 }\r
418\r
d1050b9d 419 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *)&Icmp);\r
a3bcde70
HT
420\r
421 //\r
422 // Make sure checksum is valid.\r
423 //\r
424 PseudoCheckSum = NetIp6PseudoHeadChecksum (\r
425 &Head->SourceAddress,\r
426 &Head->DestinationAddress,\r
427 IP6_ICMP,\r
428 Packet->TotalSize\r
429 );\r
430 CheckSum = (UINT16) ~NetAddChecksum (PseudoCheckSum, NetbufChecksum (Packet));\r
431 if (CheckSum != 0) {\r
432 goto DROP;\r
433 }\r
434\r
435 //\r
436 // According to the packet type, call corresponding process\r
437 //\r
438 if (Icmp.Type <= ICMP_V6_ERROR_MAX) {\r
439 return Ip6ProcessIcmpError (IpSb, Head, Packet);\r
440 } else {\r
441 return Ip6ProcessIcmpInformation (IpSb, Head, Packet);\r
442 }\r
443\r
444DROP:\r
445 NetbufFree (Packet);\r
446 return EFI_INVALID_PARAMETER;\r
447}\r
448\r
449/**\r
450 Retrieve the Prefix address according to the PrefixLength by clear the useless\r
451 bits.\r
452\r
453 @param[in] PrefixLength The prefix length of the prefix.\r
454 @param[in, out] Prefix On input, points to the original prefix address\r
455 with dirty bits; on output, points to the updated\r
456 address with useless bit clear.\r
457\r
458**/\r
459VOID\r
460Ip6GetPrefix (\r
d1050b9d
MK
461 IN UINT8 PrefixLength,\r
462 IN OUT EFI_IPv6_ADDRESS *Prefix\r
a3bcde70
HT
463 )\r
464{\r
d1050b9d
MK
465 UINT8 Byte;\r
466 UINT8 Bit;\r
467 UINT8 Mask;\r
468 UINT8 Value;\r
a3bcde70 469\r
c720da28 470 ASSERT ((Prefix != NULL) && (PrefixLength < IP6_PREFIX_MAX));\r
a3bcde70
HT
471\r
472 if (PrefixLength == 0) {\r
473 ZeroMem (Prefix, sizeof (EFI_IPv6_ADDRESS));\r
d1050b9d 474 return;\r
a3bcde70
HT
475 }\r
476\r
c720da28 477 if (PrefixLength >= IP6_PREFIX_MAX) {\r
d1050b9d 478 return;\r
a3bcde70
HT
479 }\r
480\r
d1050b9d
MK
481 Byte = (UINT8)(PrefixLength / 8);\r
482 Bit = (UINT8)(PrefixLength % 8);\r
a3bcde70
HT
483 Value = Prefix->Addr[Byte];\r
484\r
40696972 485 if (Byte > 0) {\r
a3bcde70
HT
486 ZeroMem (Prefix->Addr + Byte, 16 - Byte);\r
487 }\r
488\r
489 if (Bit > 0) {\r
d1050b9d
MK
490 Mask = (UINT8)(0xFF << (8 - Bit));\r
491 Prefix->Addr[Byte] = (UINT8)(Value & Mask);\r
a3bcde70 492 }\r
a3bcde70
HT
493}\r
494\r
495/**\r
496 Check whether the DestinationAddress is an anycast address.\r
497\r
498 @param[in] IpSb The IP service that received the packet.\r
499 @param[in] DestinationAddress Points to the Destination Address of the packet.\r
500\r
501 @retval TRUE The DestinationAddress is anycast address.\r
502 @retval FALSE The DestinationAddress is not anycast address.\r
503\r
504**/\r
505BOOLEAN\r
506Ip6IsAnycast (\r
d1050b9d
MK
507 IN IP6_SERVICE *IpSb,\r
508 IN EFI_IPv6_ADDRESS *DestinationAddress\r
a3bcde70
HT
509 )\r
510{\r
d1050b9d
MK
511 IP6_PREFIX_LIST_ENTRY *PrefixEntry;\r
512 EFI_IPv6_ADDRESS Prefix;\r
513 BOOLEAN Flag;\r
a3bcde70
HT
514\r
515 ZeroMem (&Prefix, sizeof (EFI_IPv6_ADDRESS));\r
516\r
517 Flag = FALSE;\r
518\r
519 //\r
520 // If the address is known as on-link or autonomous prefix, record it as\r
521 // anycast address.\r
522 //\r
523 do {\r
524 PrefixEntry = Ip6FindPrefixListEntry (IpSb, Flag, 255, DestinationAddress);\r
525 if (PrefixEntry != NULL) {\r
526 IP6_COPY_ADDRESS (&Prefix, &PrefixEntry->Prefix);\r
527 Ip6GetPrefix (PrefixEntry->PrefixLength, &Prefix);\r
528 if (EFI_IP6_EQUAL (&Prefix, DestinationAddress)) {\r
529 return TRUE;\r
530 }\r
531 }\r
532\r
533 Flag = (BOOLEAN) !Flag;\r
534 } while (Flag);\r
535\r
536 return FALSE;\r
537}\r
538\r
539/**\r
540 Generate ICMPv6 error message and send it out to DestinationAddress. Currently\r
541 Destination Unreachable message, Time Exceeded message and Parameter Problem\r
542 message are supported.\r
543\r
544 @param[in] IpSb The IP service that received the packet.\r
545 @param[in] Packet The packet which invoking ICMPv6 error.\r
546 @param[in] SourceAddress If not NULL, points to the SourceAddress.\r
547 Otherwise, the IP layer will select a source address\r
548 according to the DestinationAddress.\r
549 @param[in] DestinationAddress Points to the Destination Address of the ICMPv6\r
550 error message.\r
551 @param[in] Type The type of the ICMPv6 message.\r
552 @param[in] Code The additional level of the ICMPv6 message.\r
553 @param[in] Pointer If not NULL, identifies the octet offset within\r
554 the invoking packet where the error was detected.\r
555\r
8d774c74 556 @retval EFI_INVALID_PARAMETER The packet is malformatted.\r
a3bcde70
HT
557 @retval EFI_OUT_OF_RESOURCES There is no sufficient resource to complete the\r
558 operation.\r
559 @retval EFI_SUCCESS The ICMPv6 message was successfully sent out.\r
560 @retval Others Failed to generate the ICMPv6 packet.\r
561\r
562**/\r
563EFI_STATUS\r
564Ip6SendIcmpError (\r
d1050b9d
MK
565 IN IP6_SERVICE *IpSb,\r
566 IN NET_BUF *Packet,\r
567 IN EFI_IPv6_ADDRESS *SourceAddress OPTIONAL,\r
568 IN EFI_IPv6_ADDRESS *DestinationAddress,\r
569 IN UINT8 Type,\r
570 IN UINT8 Code,\r
571 IN UINT32 *Pointer OPTIONAL\r
a3bcde70
HT
572 )\r
573{\r
d1050b9d
MK
574 UINT32 PacketLen;\r
575 NET_BUF *ErrorMsg;\r
576 UINT16 PayloadLen;\r
577 EFI_IP6_HEADER Head;\r
578 IP6_ICMP_INFORMATION_HEAD *IcmpHead;\r
579 UINT8 *ErrorBody;\r
a3bcde70
HT
580\r
581 if (DestinationAddress == NULL) {\r
582 return EFI_INVALID_PARAMETER;\r
583 }\r
584\r
585 //\r
586 // An ICMPv6 error message must not be originated as a result of receiving\r
587 // a packet whose source address does not uniquely identify a single node --\r
588 // e.g., the IPv6 Unspecified Address, an IPv6 multicast address, or an address\r
589 // known by the ICMP message originator to be an IPv6 anycast address.\r
590 //\r
591 if (NetIp6IsUnspecifiedAddr (DestinationAddress) ||\r
592 IP6_IS_MULTICAST (DestinationAddress) ||\r
593 Ip6IsAnycast (IpSb, DestinationAddress)\r
d1050b9d
MK
594 )\r
595 {\r
a3bcde70
HT
596 return EFI_INVALID_PARAMETER;\r
597 }\r
598\r
599 switch (Type) {\r
d1050b9d
MK
600 case ICMP_V6_DEST_UNREACHABLE:\r
601 case ICMP_V6_TIME_EXCEEDED:\r
602 break;\r
a3bcde70 603\r
d1050b9d
MK
604 case ICMP_V6_PARAMETER_PROBLEM:\r
605 if (Pointer == NULL) {\r
606 return EFI_INVALID_PARAMETER;\r
607 }\r
a3bcde70 608\r
d1050b9d 609 break;\r
a3bcde70 610\r
d1050b9d
MK
611 default:\r
612 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
613 }\r
614\r
615 PacketLen = sizeof (IP6_ICMP_ERROR_HEAD) + Packet->TotalSize;\r
616\r
617 if (PacketLen > IpSb->MaxPacketSize) {\r
618 PacketLen = IpSb->MaxPacketSize;\r
619 }\r
620\r
621 ErrorMsg = NetbufAlloc (PacketLen);\r
622 if (ErrorMsg == NULL) {\r
623 return EFI_OUT_OF_RESOURCES;\r
624 }\r
625\r
d1050b9d 626 PayloadLen = (UINT16)(PacketLen - sizeof (EFI_IP6_HEADER));\r
a3bcde70
HT
627\r
628 //\r
629 // Create the basic IPv6 header.\r
630 //\r
631 ZeroMem (&Head, sizeof (EFI_IP6_HEADER));\r
632\r
d1050b9d
MK
633 Head.PayloadLength = HTONS (PayloadLen);\r
634 Head.NextHeader = IP6_ICMP;\r
635 Head.HopLimit = IpSb->CurHopLimit;\r
a3bcde70
HT
636\r
637 if (SourceAddress != NULL) {\r
638 IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);\r
639 } else {\r
640 ZeroMem (&Head.SourceAddress, sizeof (EFI_IPv6_ADDRESS));\r
641 }\r
642\r
643 IP6_COPY_ADDRESS (&Head.DestinationAddress, DestinationAddress);\r
644\r
645 NetbufReserve (ErrorMsg, sizeof (EFI_IP6_HEADER));\r
646\r
647 //\r
648 // Fill in the ICMP error message head\r
649 //\r
d1050b9d 650 IcmpHead = (IP6_ICMP_INFORMATION_HEAD *)NetbufAllocSpace (ErrorMsg, sizeof (IP6_ICMP_INFORMATION_HEAD), FALSE);\r
a3bcde70
HT
651 if (IcmpHead == NULL) {\r
652 NetbufFree (ErrorMsg);\r
653 return EFI_OUT_OF_RESOURCES;\r
654 }\r
655\r
656 ZeroMem (IcmpHead, sizeof (IP6_ICMP_INFORMATION_HEAD));\r
657 IcmpHead->Head.Type = Type;\r
658 IcmpHead->Head.Code = Code;\r
659\r
660 if (Pointer != NULL) {\r
661 IcmpHead->Fourth = HTONL (*Pointer);\r
662 }\r
663\r
664 //\r
665 // Fill in the ICMP error message body\r
666 //\r
667 PayloadLen -= sizeof (IP6_ICMP_INFORMATION_HEAD);\r
d1050b9d 668 ErrorBody = NetbufAllocSpace (ErrorMsg, PayloadLen, FALSE);\r
a3bcde70
HT
669 if (ErrorBody != NULL) {\r
670 ZeroMem (ErrorBody, PayloadLen);\r
671 NetbufCopy (Packet, 0, PayloadLen, ErrorBody);\r
672 }\r
673\r
674 //\r
675 // Transmit the packet\r
676 //\r
677 return Ip6Output (IpSb, NULL, NULL, ErrorMsg, &Head, NULL, 0, Ip6SysPacketSent, NULL);\r
678}\r