Ip6Icmp.c 19 KB

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