icmp6.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2010,2011 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/net.h>
  19. #include <grub/net/ip.h>
  20. #include <grub/net/netbuff.h>
  21. struct icmp_header
  22. {
  23. grub_uint8_t type;
  24. grub_uint8_t code;
  25. grub_uint16_t checksum;
  26. } GRUB_PACKED;
  27. struct ping_header
  28. {
  29. grub_uint16_t id;
  30. grub_uint16_t seq;
  31. } GRUB_PACKED;
  32. struct router_adv
  33. {
  34. grub_uint8_t ttl;
  35. grub_uint8_t flags;
  36. grub_uint16_t router_lifetime;
  37. grub_uint32_t reachable_time;
  38. grub_uint32_t retrans_timer;
  39. grub_uint8_t options[0];
  40. } GRUB_PACKED;
  41. struct option_header
  42. {
  43. grub_uint8_t type;
  44. grub_uint8_t len;
  45. } GRUB_PACKED;
  46. struct prefix_option
  47. {
  48. struct option_header header;
  49. grub_uint8_t prefixlen;
  50. grub_uint8_t flags;
  51. grub_uint32_t valid_lifetime;
  52. grub_uint32_t preferred_lifetime;
  53. grub_uint32_t reserved;
  54. grub_uint64_t prefix[2];
  55. } GRUB_PACKED;
  56. struct neighbour_solicit
  57. {
  58. grub_uint32_t reserved;
  59. grub_uint64_t target[2];
  60. } GRUB_PACKED;
  61. struct neighbour_advertise
  62. {
  63. grub_uint32_t flags;
  64. grub_uint64_t target[2];
  65. } GRUB_PACKED;
  66. struct router_solicit
  67. {
  68. grub_uint32_t reserved;
  69. } GRUB_PACKED;
  70. enum
  71. {
  72. FLAG_SLAAC = 0x40
  73. };
  74. enum
  75. {
  76. ICMP6_ECHO = 128,
  77. ICMP6_ECHO_REPLY = 129,
  78. ICMP6_ROUTER_SOLICIT = 133,
  79. ICMP6_ROUTER_ADVERTISE = 134,
  80. ICMP6_NEIGHBOUR_SOLICIT = 135,
  81. ICMP6_NEIGHBOUR_ADVERTISE = 136,
  82. };
  83. enum
  84. {
  85. OPTION_SOURCE_LINK_LAYER_ADDRESS = 1,
  86. OPTION_TARGET_LINK_LAYER_ADDRESS = 2,
  87. OPTION_PREFIX = 3
  88. };
  89. enum
  90. {
  91. FLAG_SOLICITED = (1 << 30),
  92. FLAG_OVERRIDE = (1 << 29)
  93. };
  94. grub_err_t
  95. grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
  96. struct grub_net_card *card,
  97. struct grub_net_network_level_interface *inf,
  98. const grub_net_link_level_address_t *ll_src,
  99. const grub_net_network_level_address_t *source,
  100. const grub_net_network_level_address_t *dest,
  101. grub_uint8_t ttl)
  102. {
  103. struct icmp_header *icmph;
  104. struct grub_net_network_level_interface *orig_inf = inf;
  105. grub_err_t err;
  106. grub_uint16_t checksum;
  107. icmph = (struct icmp_header *) nb->data;
  108. if (nb->tail - nb->data < (grub_ssize_t) sizeof (*icmph))
  109. {
  110. grub_netbuff_free (nb);
  111. return GRUB_ERR_NONE;
  112. }
  113. checksum = icmph->checksum;
  114. icmph->checksum = 0;
  115. if (checksum != grub_net_ip_transport_checksum (nb,
  116. GRUB_NET_IP_ICMPV6,
  117. source,
  118. dest))
  119. {
  120. grub_dprintf ("net", "invalid ICMPv6 checksum: %04x instead of %04x\n",
  121. checksum,
  122. grub_net_ip_transport_checksum (nb,
  123. GRUB_NET_IP_ICMPV6,
  124. source,
  125. dest));
  126. icmph->checksum = checksum;
  127. grub_netbuff_free (nb);
  128. return GRUB_ERR_NONE;
  129. }
  130. icmph->checksum = checksum;
  131. err = grub_netbuff_pull (nb, sizeof (*icmph));
  132. if (err)
  133. {
  134. grub_netbuff_free (nb);
  135. return err;
  136. }
  137. grub_dprintf ("net", "ICMPv6 message: %02x, %02x\n",
  138. icmph->type, icmph->code);
  139. switch (icmph->type)
  140. {
  141. case ICMP6_ECHO:
  142. /* Don't accept multicast pings. */
  143. if (!inf)
  144. break;
  145. {
  146. struct grub_net_buff *nb_reply;
  147. struct icmp_header *icmphr;
  148. if (icmph->code)
  149. break;
  150. nb_reply = grub_netbuff_alloc (nb->tail - nb->data + 512);
  151. if (!nb_reply)
  152. {
  153. grub_netbuff_free (nb);
  154. return grub_errno;
  155. }
  156. err = grub_netbuff_reserve (nb_reply, nb->tail - nb->data + 512);
  157. if (err)
  158. goto ping_fail;
  159. err = grub_netbuff_push (nb_reply, nb->tail - nb->data);
  160. if (err)
  161. goto ping_fail;
  162. grub_memcpy (nb_reply->data, nb->data, nb->tail - nb->data);
  163. err = grub_netbuff_push (nb_reply, sizeof (*icmphr));
  164. if (err)
  165. goto ping_fail;
  166. icmphr = (struct icmp_header *) nb_reply->data;
  167. icmphr->type = ICMP6_ECHO_REPLY;
  168. icmphr->code = 0;
  169. icmphr->checksum = 0;
  170. icmphr->checksum = grub_net_ip_transport_checksum (nb_reply,
  171. GRUB_NET_IP_ICMPV6,
  172. &inf->address,
  173. source);
  174. err = grub_net_send_ip_packet (inf, source, ll_src, nb_reply,
  175. GRUB_NET_IP_ICMPV6);
  176. ping_fail:
  177. grub_netbuff_free (nb);
  178. grub_netbuff_free (nb_reply);
  179. return err;
  180. }
  181. case ICMP6_NEIGHBOUR_SOLICIT:
  182. {
  183. struct neighbour_solicit *nbh;
  184. struct grub_net_buff *nb_reply;
  185. struct option_header *ohdr;
  186. struct neighbour_advertise *adv;
  187. struct icmp_header *icmphr;
  188. grub_uint8_t *ptr;
  189. if (icmph->code)
  190. break;
  191. if (ttl != 0xff)
  192. break;
  193. nbh = (struct neighbour_solicit *) nb->data;
  194. err = grub_netbuff_pull (nb, sizeof (*nbh));
  195. if (err)
  196. {
  197. grub_netbuff_free (nb);
  198. return err;
  199. }
  200. for (ptr = (grub_uint8_t *) nb->data; ptr < nb->tail;
  201. ptr += ohdr->len * 8)
  202. {
  203. ohdr = (struct option_header *) ptr;
  204. if (ohdr->len == 0 || ptr + 8 * ohdr->len > nb->tail)
  205. {
  206. grub_netbuff_free (nb);
  207. return GRUB_ERR_NONE;
  208. }
  209. if (ohdr->type == OPTION_SOURCE_LINK_LAYER_ADDRESS
  210. && ohdr->len == 1)
  211. {
  212. grub_net_link_level_address_t ll_address;
  213. ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
  214. grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
  215. grub_net_link_layer_add_address (card, source, &ll_address, 0);
  216. }
  217. }
  218. FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
  219. {
  220. if (inf->card == card
  221. && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
  222. && grub_memcmp (&inf->address.ipv6, &nbh->target, 16) == 0)
  223. break;
  224. }
  225. if (!inf)
  226. break;
  227. nb_reply = grub_netbuff_alloc (sizeof (struct neighbour_advertise)
  228. + sizeof (struct option_header)
  229. + 6
  230. + sizeof (struct icmp_header)
  231. + GRUB_NET_OUR_IPV6_HEADER_SIZE
  232. + GRUB_NET_MAX_LINK_HEADER_SIZE);
  233. if (!nb_reply)
  234. {
  235. grub_netbuff_free (nb);
  236. return grub_errno;
  237. }
  238. err = grub_netbuff_reserve (nb_reply,
  239. sizeof (struct neighbour_advertise)
  240. + sizeof (struct option_header)
  241. + 6
  242. + sizeof (struct icmp_header)
  243. + GRUB_NET_OUR_IPV6_HEADER_SIZE
  244. + GRUB_NET_MAX_LINK_HEADER_SIZE);
  245. if (err)
  246. goto ndp_fail;
  247. err = grub_netbuff_push (nb_reply, 6);
  248. if (err)
  249. goto ndp_fail;
  250. grub_memcpy (nb_reply->data, inf->hwaddress.mac, 6);
  251. err = grub_netbuff_push (nb_reply, sizeof (*ohdr));
  252. if (err)
  253. goto ndp_fail;
  254. ohdr = (struct option_header *) nb_reply->data;
  255. ohdr->type = OPTION_TARGET_LINK_LAYER_ADDRESS;
  256. ohdr->len = 1;
  257. err = grub_netbuff_push (nb_reply, sizeof (*adv));
  258. if (err)
  259. goto ndp_fail;
  260. adv = (struct neighbour_advertise *) nb_reply->data;
  261. adv->flags = grub_cpu_to_be32_compile_time (FLAG_SOLICITED
  262. | FLAG_OVERRIDE);
  263. grub_memcpy (&adv->target, &nbh->target, 16);
  264. err = grub_netbuff_push (nb_reply, sizeof (*icmphr));
  265. if (err)
  266. goto ndp_fail;
  267. icmphr = (struct icmp_header *) nb_reply->data;
  268. icmphr->type = ICMP6_NEIGHBOUR_ADVERTISE;
  269. icmphr->code = 0;
  270. icmphr->checksum = 0;
  271. icmphr->checksum = grub_net_ip_transport_checksum (nb_reply,
  272. GRUB_NET_IP_ICMPV6,
  273. &inf->address,
  274. source);
  275. err = grub_net_send_ip_packet (inf, source, ll_src, nb_reply,
  276. GRUB_NET_IP_ICMPV6);
  277. ndp_fail:
  278. grub_netbuff_free (nb);
  279. grub_netbuff_free (nb_reply);
  280. return err;
  281. }
  282. case ICMP6_NEIGHBOUR_ADVERTISE:
  283. {
  284. struct neighbour_advertise *nbh;
  285. grub_uint8_t *ptr;
  286. struct option_header *ohdr;
  287. if (icmph->code)
  288. break;
  289. if (ttl != 0xff)
  290. break;
  291. nbh = (struct neighbour_advertise *) nb->data;
  292. err = grub_netbuff_pull (nb, sizeof (*nbh));
  293. if (err)
  294. {
  295. grub_netbuff_free (nb);
  296. return err;
  297. }
  298. for (ptr = (grub_uint8_t *) nb->data; ptr < nb->tail;
  299. ptr += ohdr->len * 8)
  300. {
  301. ohdr = (struct option_header *) ptr;
  302. if (ohdr->len == 0 || ptr + 8 * ohdr->len > nb->tail)
  303. {
  304. grub_netbuff_free (nb);
  305. return GRUB_ERR_NONE;
  306. }
  307. if (ohdr->type == OPTION_TARGET_LINK_LAYER_ADDRESS
  308. && ohdr->len == 1)
  309. {
  310. grub_net_link_level_address_t ll_address;
  311. ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
  312. grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
  313. grub_net_link_layer_add_address (card, source, &ll_address, 0);
  314. }
  315. }
  316. break;
  317. }
  318. case ICMP6_ROUTER_ADVERTISE:
  319. {
  320. grub_uint8_t *ptr;
  321. struct option_header *ohdr;
  322. struct router_adv *radv;
  323. struct grub_net_network_level_interface *route_inf = NULL;
  324. int default_route = 0;
  325. if (icmph->code)
  326. break;
  327. radv = (struct router_adv *)nb->data;
  328. err = grub_netbuff_pull (nb, sizeof (struct router_adv));
  329. if (err)
  330. {
  331. grub_netbuff_free (nb);
  332. return err;
  333. }
  334. if (grub_be_to_cpu16 (radv->router_lifetime) > 0)
  335. {
  336. struct grub_net_route *route;
  337. FOR_NET_ROUTES (route)
  338. {
  339. if (!grub_memcmp (&route->gw, source, sizeof (route->gw)))
  340. break;
  341. }
  342. if (route == NULL)
  343. default_route = 1;
  344. }
  345. for (ptr = (grub_uint8_t *) nb->data; ptr < nb->tail;
  346. ptr += ohdr->len * 8)
  347. {
  348. ohdr = (struct option_header *) ptr;
  349. if (ohdr->len == 0 || ptr + 8 * ohdr->len > nb->tail)
  350. {
  351. grub_netbuff_free (nb);
  352. return GRUB_ERR_NONE;
  353. }
  354. if (ohdr->type == OPTION_SOURCE_LINK_LAYER_ADDRESS
  355. && ohdr->len == 1)
  356. {
  357. grub_net_link_level_address_t ll_address;
  358. ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
  359. grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
  360. grub_net_link_layer_add_address (card, source, &ll_address, 0);
  361. }
  362. if (ohdr->type == OPTION_PREFIX && ohdr->len == 4)
  363. {
  364. struct prefix_option *opt = (struct prefix_option *) ptr;
  365. struct grub_net_slaac_mac_list *slaac;
  366. if (!(opt->flags & FLAG_SLAAC)
  367. || (grub_be_to_cpu64 (opt->prefix[0]) >> 48) == 0xfe80
  368. || (grub_be_to_cpu32 (opt->preferred_lifetime)
  369. > grub_be_to_cpu32 (opt->valid_lifetime))
  370. || opt->prefixlen != 64)
  371. {
  372. grub_dprintf ("net", "discarded prefix: %d, %d, %d, %d\n",
  373. !(opt->flags & FLAG_SLAAC),
  374. (grub_be_to_cpu64 (opt->prefix[0]) >> 48) == 0xfe80,
  375. (grub_be_to_cpu32 (opt->preferred_lifetime)
  376. > grub_be_to_cpu32 (opt->valid_lifetime)),
  377. opt->prefixlen != 64);
  378. continue;
  379. }
  380. for (slaac = card->slaac_list; slaac; slaac = slaac->next)
  381. {
  382. grub_net_network_level_address_t addr;
  383. grub_net_network_level_netaddress_t netaddr;
  384. if (slaac->address.type
  385. != GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET)
  386. continue;
  387. addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
  388. addr.ipv6[0] = opt->prefix[0];
  389. addr.ipv6[1] = grub_net_ipv6_get_id (&slaac->address);
  390. netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
  391. netaddr.ipv6.base[0] = opt->prefix[0];
  392. netaddr.ipv6.base[1] = 0;
  393. netaddr.ipv6.masksize = 64;
  394. FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
  395. {
  396. if (inf->card == card
  397. && grub_net_addr_cmp (&inf->address, &addr) == 0)
  398. break;
  399. }
  400. /* Update lease time if needed here once we have
  401. lease times. */
  402. if (inf)
  403. {
  404. if (!route_inf)
  405. route_inf = inf;
  406. continue;
  407. }
  408. grub_dprintf ("net", "creating slaac\n");
  409. {
  410. char *name;
  411. name = grub_xasprintf ("%s:%d",
  412. slaac->name, slaac->slaac_counter++);
  413. if (!name)
  414. {
  415. grub_errno = GRUB_ERR_NONE;
  416. continue;
  417. }
  418. inf = grub_net_add_addr (name,
  419. card, &addr,
  420. &slaac->address, 0);
  421. if (!route_inf)
  422. route_inf = inf;
  423. grub_net_add_route (name, netaddr, inf);
  424. grub_free (name);
  425. }
  426. }
  427. }
  428. }
  429. if (default_route)
  430. {
  431. char *name;
  432. grub_net_network_level_netaddress_t netaddr;
  433. name = grub_xasprintf ("%s:ra:default6", card->name);
  434. if (!name)
  435. {
  436. grub_errno = GRUB_ERR_NONE;
  437. goto next;
  438. }
  439. /* Default routes take alll of the traffic, so make the mask huge */
  440. netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
  441. netaddr.ipv6.masksize = 0;
  442. netaddr.ipv6.base[0] = 0;
  443. netaddr.ipv6.base[1] = 0;
  444. /* May not have gotten slaac info, find a global address on this
  445. card. */
  446. if (route_inf == NULL && orig_inf != NULL)
  447. {
  448. FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
  449. {
  450. if (inf->card == card && inf != orig_inf
  451. && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
  452. && grub_net_hwaddr_cmp(&inf->hwaddress,
  453. &orig_inf->hwaddress) == 0)
  454. {
  455. route_inf = inf;
  456. break;
  457. }
  458. }
  459. }
  460. if (route_inf != NULL)
  461. grub_net_add_route_gw (name, netaddr, *source, route_inf);
  462. grub_free (name);
  463. }
  464. next:
  465. if (ptr != nb->tail)
  466. break;
  467. }
  468. };
  469. grub_netbuff_free (nb);
  470. return GRUB_ERR_NONE;
  471. }
  472. grub_err_t
  473. grub_net_icmp6_send_request (struct grub_net_network_level_interface *inf,
  474. const grub_net_network_level_address_t *proto_addr)
  475. {
  476. struct grub_net_buff *nb;
  477. grub_err_t err = GRUB_ERR_NONE;
  478. int i;
  479. struct option_header *ohdr;
  480. struct neighbour_solicit *sol;
  481. struct icmp_header *icmphr;
  482. grub_net_network_level_address_t multicast;
  483. grub_net_link_level_address_t ll_multicast;
  484. grub_uint8_t *nbd;
  485. multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
  486. multicast.ipv6[0] = grub_be_to_cpu64_compile_time (0xff02ULL << 48);
  487. multicast.ipv6[1] = (grub_be_to_cpu64_compile_time (0x01ff000000ULL)
  488. | (proto_addr->ipv6[1]
  489. & grub_be_to_cpu64_compile_time (0xffffff)));
  490. err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast);
  491. if (err)
  492. return err;
  493. nb = grub_netbuff_alloc (sizeof (struct neighbour_solicit)
  494. + sizeof (struct option_header)
  495. + 6
  496. + sizeof (struct icmp_header)
  497. + GRUB_NET_OUR_IPV6_HEADER_SIZE
  498. + GRUB_NET_MAX_LINK_HEADER_SIZE);
  499. if (!nb)
  500. return grub_errno;
  501. err = grub_netbuff_reserve (nb,
  502. sizeof (struct neighbour_solicit)
  503. + sizeof (struct option_header)
  504. + 6
  505. + sizeof (struct icmp_header)
  506. + GRUB_NET_OUR_IPV6_HEADER_SIZE
  507. + GRUB_NET_MAX_LINK_HEADER_SIZE);
  508. err = grub_netbuff_push (nb, 6);
  509. if (err)
  510. goto fail;
  511. grub_memcpy (nb->data, inf->hwaddress.mac, 6);
  512. err = grub_netbuff_push (nb, sizeof (*ohdr));
  513. if (err)
  514. goto fail;
  515. ohdr = (struct option_header *) nb->data;
  516. ohdr->type = OPTION_SOURCE_LINK_LAYER_ADDRESS;
  517. ohdr->len = 1;
  518. err = grub_netbuff_push (nb, sizeof (*sol));
  519. if (err)
  520. goto fail;
  521. sol = (struct neighbour_solicit *) nb->data;
  522. sol->reserved = 0;
  523. grub_memcpy (&sol->target, &proto_addr->ipv6, 16);
  524. err = grub_netbuff_push (nb, sizeof (*icmphr));
  525. if (err)
  526. goto fail;
  527. icmphr = (struct icmp_header *) nb->data;
  528. icmphr->type = ICMP6_NEIGHBOUR_SOLICIT;
  529. icmphr->code = 0;
  530. icmphr->checksum = 0;
  531. icmphr->checksum = grub_net_ip_transport_checksum (nb,
  532. GRUB_NET_IP_ICMPV6,
  533. &inf->address,
  534. &multicast);
  535. nbd = nb->data;
  536. err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb,
  537. GRUB_NET_IP_ICMPV6);
  538. if (err)
  539. goto fail;
  540. for (i = 0; i < GRUB_NET_TRIES; i++)
  541. {
  542. if (grub_net_link_layer_resolve_check (inf, proto_addr))
  543. break;
  544. grub_net_poll_cards (GRUB_NET_INTERVAL + (i * GRUB_NET_INTERVAL_ADDITION),
  545. 0);
  546. if (grub_net_link_layer_resolve_check (inf, proto_addr))
  547. break;
  548. nb->data = nbd;
  549. err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb,
  550. GRUB_NET_IP_ICMPV6);
  551. if (err)
  552. break;
  553. }
  554. fail:
  555. grub_netbuff_free (nb);
  556. return err;
  557. }
  558. grub_err_t
  559. grub_net_icmp6_send_router_solicit (struct grub_net_network_level_interface *inf)
  560. {
  561. struct grub_net_buff *nb;
  562. grub_err_t err = GRUB_ERR_NONE;
  563. grub_net_network_level_address_t multicast;
  564. grub_net_link_level_address_t ll_multicast;
  565. struct option_header *ohdr;
  566. struct router_solicit *sol;
  567. struct icmp_header *icmphr;
  568. multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
  569. multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48);
  570. multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x02ULL);
  571. err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast);
  572. if (err)
  573. return err;
  574. nb = grub_netbuff_alloc (sizeof (struct router_solicit)
  575. + sizeof (struct option_header)
  576. + 6
  577. + sizeof (struct icmp_header)
  578. + GRUB_NET_OUR_IPV6_HEADER_SIZE
  579. + GRUB_NET_MAX_LINK_HEADER_SIZE);
  580. if (!nb)
  581. return grub_errno;
  582. err = grub_netbuff_reserve (nb,
  583. sizeof (struct router_solicit)
  584. + sizeof (struct option_header)
  585. + 6
  586. + sizeof (struct icmp_header)
  587. + GRUB_NET_OUR_IPV6_HEADER_SIZE
  588. + GRUB_NET_MAX_LINK_HEADER_SIZE);
  589. if (err)
  590. goto fail;
  591. err = grub_netbuff_push (nb, 6);
  592. if (err)
  593. goto fail;
  594. grub_memcpy (nb->data, inf->hwaddress.mac, 6);
  595. err = grub_netbuff_push (nb, sizeof (*ohdr));
  596. if (err)
  597. goto fail;
  598. ohdr = (struct option_header *) nb->data;
  599. ohdr->type = OPTION_SOURCE_LINK_LAYER_ADDRESS;
  600. ohdr->len = 1;
  601. err = grub_netbuff_push (nb, sizeof (*sol));
  602. if (err)
  603. goto fail;
  604. sol = (struct router_solicit *) nb->data;
  605. sol->reserved = 0;
  606. err = grub_netbuff_push (nb, sizeof (*icmphr));
  607. if (err)
  608. goto fail;
  609. icmphr = (struct icmp_header *) nb->data;
  610. icmphr->type = ICMP6_ROUTER_SOLICIT;
  611. icmphr->code = 0;
  612. icmphr->checksum = 0;
  613. icmphr->checksum = grub_net_ip_transport_checksum (nb,
  614. GRUB_NET_IP_ICMPV6,
  615. &inf->address,
  616. &multicast);
  617. err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb,
  618. GRUB_NET_IP_ICMPV6);
  619. fail:
  620. grub_netbuff_free (nb);
  621. return err;
  622. }