2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2010,2011 Free Software Foundation, Inc.
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.
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.
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/>.
20 #include <grub/net/ip.h>
21 #include <grub/net/netbuff.h>
27 grub_uint16_t checksum
;
28 } __attribute__ ((packed
));
34 } __attribute__ ((packed
));
40 grub_uint16_t router_lifetime
;
41 grub_uint32_t reachable_time
;
42 grub_uint32_t retrans_timer
;
43 grub_uint8_t options
[0];
44 } __attribute__ ((packed
));
50 } __attribute__ ((packed
));
54 struct option_header header
;
55 grub_uint8_t prefixlen
;
57 grub_uint32_t valid_lifetime
;
58 grub_uint32_t prefered_lifetime
;
59 grub_uint32_t reserved
;
60 grub_uint64_t prefix
[2];
61 } __attribute__ ((packed
));
63 struct neighbour_solicit
65 grub_uint32_t reserved
;
66 grub_uint64_t target
[2];
67 } __attribute__ ((packed
));
69 struct neighbour_advertise
72 grub_uint64_t target
[2];
73 } __attribute__ ((packed
));
83 ICMP6_ECHO_REPLY
= 129,
84 ICMP6_ROUTER_ADVERTISE
= 134,
85 ICMP6_NEIGHBOUR_SOLICIT
= 135,
86 ICMP6_NEIGHBOUR_ADVERTISE
= 136,
91 OPTION_SOURCE_LINK_LAYER_ADDRESS
= 1,
92 OPTION_TARGET_LINK_LAYER_ADDRESS
= 2,
98 FLAG_SOLICITED
= (1 << 30),
99 FLAG_OVERRIDE
= (1 << 29)
103 grub_net_recv_icmp6_packet (struct grub_net_buff
*nb
,
104 struct grub_net_card
*card
,
105 struct grub_net_network_level_interface
*inf
,
106 const grub_net_link_level_address_t
*ll_src
,
107 const grub_net_network_level_address_t
*source
,
108 const grub_net_network_level_address_t
*dest
,
111 struct icmp_header
*icmph
;
113 grub_uint16_t checksum
;
115 icmph
= (struct icmp_header
*) nb
->data
;
117 if (nb
->tail
- nb
->data
< (grub_ssize_t
) sizeof (*icmph
))
119 grub_netbuff_free (nb
);
120 return GRUB_ERR_NONE
;
123 checksum
= icmph
->checksum
;
125 if (checksum
!= grub_net_ip_transport_checksum (nb
,
130 grub_dprintf ("net", "invalid ICMPv6 checksum: %04x instead of %04x\n",
132 grub_net_ip_transport_checksum (nb
,
136 icmph
->checksum
= checksum
;
137 grub_netbuff_free (nb
);
138 return GRUB_ERR_NONE
;
140 icmph
->checksum
= checksum
;
142 err
= grub_netbuff_pull (nb
, sizeof (*icmph
));
145 grub_netbuff_free (nb
);
149 grub_dprintf ("net", "ICMPv6 message: %02x, %02x\n",
150 icmph
->type
, icmph
->code
);
154 /* Don't accept multicast pings. */
158 struct grub_net_buff
*nb_reply
;
159 struct icmp_header
*icmphr
;
162 nb_reply
= grub_netbuff_alloc (nb
->tail
- nb
->data
+ 512);
165 grub_netbuff_free (nb
);
168 err
= grub_netbuff_reserve (nb_reply
, nb
->tail
- nb
->data
+ 512);
171 err
= grub_netbuff_push (nb_reply
, nb
->tail
- nb
->data
);
174 grub_memcpy (nb_reply
->data
, nb
->data
, nb
->tail
- nb
->data
);
175 err
= grub_netbuff_push (nb_reply
, sizeof (*icmphr
));
178 icmphr
= (struct icmp_header
*) nb_reply
->data
;
179 icmphr
->type
= ICMP6_ECHO_REPLY
;
181 icmphr
->checksum
= 0;
182 icmphr
->checksum
= grub_net_ip_transport_checksum (nb_reply
,
186 err
= grub_net_send_ip_packet (inf
, source
, ll_src
, nb_reply
,
190 grub_netbuff_free (nb
);
191 grub_netbuff_free (nb_reply
);
194 case ICMP6_NEIGHBOUR_SOLICIT
:
196 struct neighbour_solicit
*nbh
;
197 struct grub_net_buff
*nb_reply
;
198 struct option_header
*ohdr
;
199 struct neighbour_advertise
*adv
;
200 struct icmp_header
*icmphr
;
207 nbh
= (struct neighbour_solicit
*) nb
->data
;
208 err
= grub_netbuff_pull (nb
, sizeof (struct router_adv
));
211 grub_netbuff_free (nb
);
214 for (ptr
= (grub_uint8_t
*) nb
->data
; ptr
< nb
->tail
;
215 ptr
+= ohdr
->len
* 8)
217 ohdr
= (struct option_header
*) ptr
;
218 if (ohdr
->len
== 0 || ptr
+ 8 * ohdr
->len
> nb
->tail
)
220 grub_netbuff_free (nb
);
221 return GRUB_ERR_NONE
;
223 if (ohdr
->type
== OPTION_SOURCE_LINK_LAYER_ADDRESS
226 grub_net_link_level_address_t ll_address
;
227 ll_address
.type
= GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
;
228 grub_memcpy (ll_address
.mac
, ohdr
+ 1, sizeof (ll_address
.mac
));
229 grub_net_link_layer_add_address (card
, source
, &ll_address
, 0);
232 FOR_NET_NETWORK_LEVEL_INTERFACES (inf
)
234 if (inf
->card
== card
235 && inf
->address
.type
== GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
236 && grub_memcmp (&inf
->address
.ipv6
, &nbh
->target
, 16) == 0)
242 nb_reply
= grub_netbuff_alloc (sizeof (struct neighbour_advertise
)
243 + sizeof (struct option_header
)
245 + sizeof (struct icmp_header
)
246 + GRUB_NET_OUR_IPV6_HEADER_SIZE
247 + GRUB_NET_MAX_LINK_HEADER_SIZE
);
250 grub_netbuff_free (nb
);
253 err
= grub_netbuff_reserve (nb_reply
,
254 sizeof (struct neighbour_advertise
)
255 + sizeof (struct option_header
)
257 + sizeof (struct icmp_header
)
258 + GRUB_NET_OUR_IPV6_HEADER_SIZE
259 + GRUB_NET_MAX_LINK_HEADER_SIZE
);
263 err
= grub_netbuff_push (nb_reply
, 6);
266 grub_memcpy (nb_reply
->data
, inf
->hwaddress
.mac
, 6);
267 err
= grub_netbuff_push (nb_reply
, sizeof (*ohdr
));
270 ohdr
= (struct option_header
*) nb_reply
->data
;
271 ohdr
->type
= OPTION_TARGET_LINK_LAYER_ADDRESS
;
273 err
= grub_netbuff_push (nb_reply
, sizeof (*adv
));
276 adv
= (struct neighbour_advertise
*) nb_reply
->data
;
277 adv
->flags
= grub_cpu_to_be32_compile_time (FLAG_SOLICITED
279 grub_memcpy (&adv
->target
, &nbh
->target
, 16);
281 err
= grub_netbuff_push (nb_reply
, sizeof (*icmphr
));
284 icmphr
= (struct icmp_header
*) nb_reply
->data
;
285 icmphr
->type
= ICMP6_NEIGHBOUR_ADVERTISE
;
287 icmphr
->checksum
= 0;
288 icmphr
->checksum
= grub_net_ip_transport_checksum (nb_reply
,
292 err
= grub_net_send_ip_packet (inf
, source
, ll_src
, nb_reply
,
296 grub_netbuff_free (nb
);
297 grub_netbuff_free (nb_reply
);
300 case ICMP6_NEIGHBOUR_ADVERTISE
:
302 struct neighbour_advertise
*nbh
;
304 struct option_header
*ohdr
;
310 nbh
= (struct neighbour_advertise
*) nb
->data
;
311 err
= grub_netbuff_pull (nb
, sizeof (*nbh
));
314 grub_netbuff_free (nb
);
318 for (ptr
= (grub_uint8_t
*) nb
->data
; ptr
< nb
->tail
;
319 ptr
+= ohdr
->len
* 8)
321 ohdr
= (struct option_header
*) ptr
;
322 if (ohdr
->len
== 0 || ptr
+ 8 * ohdr
->len
> nb
->tail
)
324 grub_netbuff_free (nb
);
325 return GRUB_ERR_NONE
;
327 if (ohdr
->type
== OPTION_TARGET_LINK_LAYER_ADDRESS
330 grub_net_link_level_address_t ll_address
;
331 ll_address
.type
= GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
;
332 grub_memcpy (ll_address
.mac
, ohdr
+ 1, sizeof (ll_address
.mac
));
333 grub_net_link_layer_add_address (card
, source
, &ll_address
, 0);
338 case ICMP6_ROUTER_ADVERTISE
:
341 struct option_header
*ohdr
;
344 err
= grub_netbuff_pull (nb
, sizeof (struct router_adv
));
347 grub_netbuff_free (nb
);
350 for (ptr
= (grub_uint8_t
*) nb
->data
; ptr
< nb
->tail
;
351 ptr
+= ohdr
->len
* 8)
353 ohdr
= (struct option_header
*) ptr
;
354 if (ohdr
->len
== 0 || ptr
+ 8 * ohdr
->len
> nb
->tail
)
356 grub_netbuff_free (nb
);
357 return GRUB_ERR_NONE
;
359 if (ohdr
->type
== OPTION_SOURCE_LINK_LAYER_ADDRESS
362 grub_net_link_level_address_t ll_address
;
363 ll_address
.type
= GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
;
364 grub_memcpy (ll_address
.mac
, ohdr
+ 1, sizeof (ll_address
.mac
));
365 grub_net_link_layer_add_address (card
, source
, &ll_address
, 0);
367 if (ohdr
->type
== OPTION_PREFIX
&& ohdr
->len
== 4)
369 struct prefix_option
*opt
= (struct prefix_option
*) ptr
;
370 struct grub_net_slaac_mac_list
*slaac
;
371 if (!(opt
->flags
& FLAG_SLAAC
)
372 || (grub_be_to_cpu64 (opt
->prefix
[0]) >> 48) == 0xfe80
373 || (grub_be_to_cpu32 (opt
->prefered_lifetime
)
374 > grub_be_to_cpu32 (opt
->valid_lifetime
))
375 || opt
->prefixlen
!= 64)
377 grub_dprintf ("net", "discarded prefix: %d, %d, %d, %d\n",
378 !(opt
->flags
& FLAG_SLAAC
),
379 (grub_be_to_cpu64 (opt
->prefix
[0]) >> 48) == 0xfe80,
380 (grub_be_to_cpu32 (opt
->prefered_lifetime
)
381 > grub_be_to_cpu32 (opt
->valid_lifetime
)),
382 opt
->prefixlen
!= 64);
385 for (slaac
= card
->slaac_list
; slaac
; slaac
= slaac
->next
)
387 grub_net_network_level_address_t addr
;
388 grub_net_network_level_netaddress_t netaddr
;
390 if (slaac
->address
.type
391 != GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
)
393 addr
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
;
394 addr
.ipv6
[0] = opt
->prefix
[0];
395 addr
.ipv6
[1] = grub_net_ipv6_get_id (&slaac
->address
);
396 netaddr
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
;
397 netaddr
.ipv6
.base
[0] = opt
->prefix
[0];
398 netaddr
.ipv6
.base
[1] = 0;
399 netaddr
.ipv6
.masksize
= 64;
401 FOR_NET_NETWORK_LEVEL_INTERFACES (inf
)
403 if (inf
->card
== card
404 && grub_net_addr_cmp (&inf
->address
, &addr
) == 0)
407 /* Update lease time if needed here once we have
412 grub_dprintf ("net", "creating slaac\n");
415 char name
[grub_strlen (slaac
->name
)
416 + sizeof (":XXXXXXXXXXXXXXXXXXXX")];
417 grub_snprintf (name
, sizeof (name
), "%s:%d",
418 slaac
->name
, slaac
->slaac_counter
++);
419 inf
= grub_net_add_addr (name
,
422 grub_net_add_route (name
, netaddr
, inf
);
432 grub_netbuff_free (nb
);
433 return GRUB_ERR_NONE
;
437 grub_net_icmp6_send_request (struct grub_net_network_level_interface
*inf
,
438 const grub_net_network_level_address_t
*proto_addr
)
440 struct grub_net_buff
*nb
;
441 grub_err_t err
= GRUB_ERR_NONE
;
443 struct option_header
*ohdr
;
444 struct neighbour_solicit
*sol
;
445 struct icmp_header
*icmphr
;
446 grub_net_network_level_address_t multicast
;
447 grub_net_link_level_address_t ll_multicast
;
449 multicast
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
;
450 multicast
.ipv6
[0] = grub_be_to_cpu64_compile_time (0xff02ULL
<< 48);
451 multicast
.ipv6
[1] = (grub_be_to_cpu64_compile_time (0x01ff000000ULL
)
452 | (proto_addr
->ipv6
[1]
453 & grub_be_to_cpu64_compile_time (0xffffff)));
455 err
= grub_net_link_layer_resolve (inf
, &multicast
, &ll_multicast
);
459 nb
= grub_netbuff_alloc (sizeof (struct neighbour_solicit
)
460 + sizeof (struct option_header
)
462 + sizeof (struct icmp_header
)
463 + GRUB_NET_OUR_IPV6_HEADER_SIZE
464 + GRUB_NET_MAX_LINK_HEADER_SIZE
);
467 err
= grub_netbuff_reserve (nb
,
468 sizeof (struct neighbour_solicit
)
469 + sizeof (struct option_header
)
471 + sizeof (struct icmp_header
)
472 + GRUB_NET_OUR_IPV6_HEADER_SIZE
473 + GRUB_NET_MAX_LINK_HEADER_SIZE
);
474 err
= grub_netbuff_push (nb
, 6);
478 grub_memcpy (nb
->data
, inf
->hwaddress
.mac
, 6);
479 err
= grub_netbuff_push (nb
, sizeof (*ohdr
));
483 ohdr
= (struct option_header
*) nb
->data
;
484 ohdr
->type
= OPTION_SOURCE_LINK_LAYER_ADDRESS
;
486 err
= grub_netbuff_push (nb
, sizeof (*sol
));
490 sol
= (struct neighbour_solicit
*) nb
->data
;
492 grub_memcpy (&sol
->target
, &proto_addr
->ipv6
, 16);
494 err
= grub_netbuff_push (nb
, sizeof (*icmphr
));
498 icmphr
= (struct icmp_header
*) nb
->data
;
499 icmphr
->type
= ICMP6_NEIGHBOUR_SOLICIT
;
501 icmphr
->checksum
= 0;
502 icmphr
->checksum
= grub_net_ip_transport_checksum (nb
,
507 err
= grub_net_send_ip_packet (inf
, &multicast
, &ll_multicast
, nb
,
512 for (i
= 0; i
< GRUB_NET_TRIES
; i
++)
514 if (grub_net_link_layer_resolve_check (inf
, proto_addr
))
516 grub_net_poll_cards (GRUB_NET_INTERVAL
, 0);
517 if (grub_net_link_layer_resolve_check (inf
, proto_addr
))
520 err
= grub_net_send_ip_packet (inf
, &multicast
, &ll_multicast
, nb
,
527 grub_netbuff_free (nb
);