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/>.
19 #include <grub/net/ip.h>
20 #include <grub/misc.h>
21 #include <grub/net/arp.h>
22 #include <grub/net/udp.h>
23 #include <grub/net/ethernet.h>
25 #include <grub/net/netbuff.h>
27 #include <grub/priority_queue.h>
28 #include <grub/time.h>
31 grub_uint8_t verhdrlen
;
37 grub_uint8_t protocol
;
41 } __attribute__ ((packed
)) ;
45 DONT_FRAGMENT
= 0x4000,
46 MORE_FRAGMENTS
= 0x2000,
50 typedef grub_uint64_t ip6addr
[2];
53 grub_uint32_t version_class_flow
;
55 grub_uint8_t protocol
;
59 } __attribute__ ((packed
)) ;
62 cmp (const void *a__
, const void *b__
)
64 struct grub_net_buff
*a_
= *(struct grub_net_buff
**) a__
;
65 struct grub_net_buff
*b_
= *(struct grub_net_buff
**) b__
;
66 struct iphdr
*a
= (struct iphdr
*) a_
->data
;
67 struct iphdr
*b
= (struct iphdr
*) b_
->data
;
68 /* We want the first elements to be on top. */
69 if ((grub_be_to_cpu16 (a
->frags
) & OFFSET_MASK
)
70 < (grub_be_to_cpu16 (b
->frags
) & OFFSET_MASK
))
72 if ((grub_be_to_cpu16 (a
->frags
) & OFFSET_MASK
)
73 > (grub_be_to_cpu16 (b
->frags
) & OFFSET_MASK
))
80 struct reassemble
*next
;
85 grub_uint64_t last_time
;
86 grub_priority_queue_t pq
;
87 struct grub_net_buff
*asm_netbuff
;
88 grub_size_t total_len
;
93 static struct reassemble
*reassembles
;
96 grub_net_ip_chksum (void *ipv
, grub_size_t len
)
98 grub_uint16_t
*ip
= (grub_uint16_t
*) ipv
;
99 grub_uint32_t sum
= 0;
101 for (; len
>= 2; len
-= 2)
103 sum
+= grub_be_to_cpu16 (grub_get_unaligned16 (ip
++));
109 sum
+= *((grub_uint8_t
*) ip
) << 8;
117 return grub_cpu_to_be16 ((~sum
) & 0x0000FFFF);
120 static int id
= 0x2400;
123 send_fragmented (struct grub_net_network_level_interface
* inf
,
124 const grub_net_network_level_address_t
* target
,
125 struct grub_net_buff
* nb
,
126 grub_net_ip_protocol_t proto
,
127 grub_net_link_level_address_t ll_target_addr
)
133 fraglen
= (inf
->card
->mtu
- sizeof (struct iphdr
)) & ~7;
136 while (nb
->tail
- nb
->data
)
138 grub_size_t len
= fraglen
;
139 struct grub_net_buff
*nb2
;
142 if ((grub_ssize_t
) len
> nb
->tail
- nb
->data
)
143 len
= nb
->tail
- nb
->data
;
144 nb2
= grub_netbuff_alloc (fraglen
+ sizeof (struct iphdr
)
145 + GRUB_NET_MAX_LINK_HEADER_SIZE
);
148 err
= grub_netbuff_reserve (nb2
, GRUB_NET_MAX_LINK_HEADER_SIZE
);
151 err
= grub_netbuff_put (nb2
, sizeof (struct iphdr
));
155 iph
= (struct iphdr
*) nb2
->data
;
156 iph
->verhdrlen
= ((4 << 4) | 5);
158 iph
->len
= grub_cpu_to_be16 (len
+ sizeof (struct iphdr
));
159 iph
->ident
= grub_cpu_to_be16 (id
);
160 iph
->frags
= grub_cpu_to_be16 (off
| (((grub_ssize_t
) len
161 == nb
->tail
- nb
->data
)
162 ? 0 : MORE_FRAGMENTS
));
164 iph
->protocol
= proto
;
165 iph
->src
= inf
->address
.ipv4
;
166 iph
->dest
= target
->ipv4
;
170 iph
->chksum
= grub_net_ip_chksum ((void *) nb2
->data
, sizeof (*iph
));
171 err
= grub_netbuff_put (nb2
, len
);
174 grub_memcpy (iph
+ 1, nb
->data
, len
);
175 err
= grub_netbuff_pull (nb
, len
);
178 err
= send_ethernet_packet (inf
, nb2
, ll_target_addr
,
179 GRUB_NET_ETHERTYPE_IP
);
183 return GRUB_ERR_NONE
;
187 grub_net_send_ip4_packet (struct grub_net_network_level_interface
*inf
,
188 const grub_net_network_level_address_t
*target
,
189 const grub_net_link_level_address_t
*ll_target_addr
,
190 struct grub_net_buff
*nb
,
191 grub_net_ip_protocol_t proto
)
195 COMPILE_TIME_ASSERT (GRUB_NET_OUR_IPV4_HEADER_SIZE
== sizeof (*iph
));
197 if (nb
->tail
- nb
->data
+ sizeof (struct iphdr
) > inf
->card
->mtu
)
198 return send_fragmented (inf
, target
, nb
, proto
, *ll_target_addr
);
200 grub_netbuff_push (nb
, sizeof (*iph
));
201 iph
= (struct iphdr
*) nb
->data
;
203 iph
->verhdrlen
= ((4 << 4) | 5);
205 iph
->len
= grub_cpu_to_be16 (nb
->tail
- nb
->data
);
206 iph
->ident
= grub_cpu_to_be16 (++id
);
209 iph
->protocol
= proto
;
210 iph
->src
= inf
->address
.ipv4
;
211 iph
->dest
= target
->ipv4
;
214 iph
->chksum
= grub_net_ip_chksum ((void *) nb
->data
, sizeof (*iph
));
216 return send_ethernet_packet (inf
, nb
, *ll_target_addr
,
217 GRUB_NET_ETHERTYPE_IP
);
221 handle_dgram (struct grub_net_buff
*nb
,
222 struct grub_net_card
*card
,
223 const grub_net_link_level_address_t
*source_hwaddress
,
224 const grub_net_link_level_address_t
*hwaddress
,
225 grub_net_ip_protocol_t proto
,
226 const grub_net_network_level_address_t
*source
,
227 const grub_net_network_level_address_t
*dest
,
230 struct grub_net_network_level_interface
*inf
= NULL
;
234 /* DHCP needs special treatment since we don't know IP yet. */
237 udph
= (struct udphdr
*) nb
->data
;
238 if (proto
== GRUB_NET_IP_UDP
&& grub_be_to_cpu16 (udph
->dst
) == 68)
240 const struct grub_net_bootp_packet
*bootp
;
243 grub_uint16_t chk
, expected
;
246 expected
= grub_net_ip_transport_checksum (nb
,
252 grub_dprintf ("net", "Invalid UDP checksum. "
253 "Expected %x, got %x\n",
254 grub_be_to_cpu16 (expected
),
255 grub_be_to_cpu16 (chk
));
256 grub_netbuff_free (nb
);
257 return GRUB_ERR_NONE
;
262 err
= grub_netbuff_pull (nb
, sizeof (*udph
));
265 grub_netbuff_free (nb
);
269 bootp
= (const struct grub_net_bootp_packet
*) nb
->data
;
271 FOR_NET_NETWORK_LEVEL_INTERFACES (inf
)
272 if (inf
->card
== card
273 && inf
->address
.type
== GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV
274 && inf
->hwaddress
.type
== GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
275 && grub_memcmp (inf
->hwaddress
.mac
, &bootp
->mac_addr
,
276 sizeof (inf
->hwaddress
.mac
)) == 0)
278 grub_net_process_dhcp (nb
, inf
->card
);
279 grub_netbuff_free (nb
);
280 return GRUB_ERR_NONE
;
282 grub_netbuff_free (nb
);
283 return GRUB_ERR_NONE
;
287 FOR_NET_NETWORK_LEVEL_INTERFACES (inf
)
289 if (inf
->card
== card
290 && grub_net_addr_cmp (&inf
->address
, dest
) == 0
291 && grub_net_hwaddr_cmp (&inf
->hwaddress
, hwaddress
) == 0)
293 /* Solicited node multicast. */
294 if (inf
->card
== card
295 && inf
->address
.type
== GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
296 && dest
->type
== GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
297 && dest
->ipv6
[0] == grub_be_to_cpu64_compile_time (0xff02ULL
<< 48)
298 && dest
->ipv6
[1] == (grub_be_to_cpu64_compile_time (0x01ff000000ULL
)
299 | (inf
->address
.ipv6
[1]
300 & grub_be_to_cpu64_compile_time (0xffffff)))
301 && hwaddress
->type
== GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
302 && hwaddress
->mac
[0] == 0x33 && hwaddress
->mac
[1] == 0x33
303 && hwaddress
->mac
[2] == 0xff
304 && hwaddress
->mac
[3] == ((grub_be_to_cpu64 (inf
->address
.ipv6
[1])
306 && hwaddress
->mac
[4] == ((grub_be_to_cpu64 (inf
->address
.ipv6
[1])
308 && hwaddress
->mac
[5] == ((grub_be_to_cpu64 (inf
->address
.ipv6
[1])
316 if (!inf
&& !(dest
->type
== GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
317 && dest
->ipv6
[0] == grub_be_to_cpu64_compile_time (0xff02ULL
319 && dest
->ipv6
[1] == grub_be_to_cpu64_compile_time (1)))
321 grub_netbuff_free (nb
);
322 return GRUB_ERR_NONE
;
329 case GRUB_NET_IP_UDP
:
330 return grub_net_recv_udp_packet (nb
, inf
, source
);
331 case GRUB_NET_IP_TCP
:
332 return grub_net_recv_tcp_packet (nb
, inf
, source
);
333 case GRUB_NET_IP_ICMP
:
334 return grub_net_recv_icmp_packet (nb
, inf
, source_hwaddress
, source
);
335 case GRUB_NET_IP_ICMPV6
:
336 return grub_net_recv_icmp6_packet (nb
, card
, inf
, source_hwaddress
,
339 grub_netbuff_free (nb
);
342 return GRUB_ERR_NONE
;
346 free_rsm (struct reassemble
*rsm
)
348 struct grub_net_buff
**nb
;
349 while ((nb
= grub_priority_queue_top (rsm
->pq
)))
351 grub_netbuff_free (*nb
);
352 grub_priority_queue_pop (rsm
->pq
);
354 grub_netbuff_free (rsm
->asm_netbuff
);
355 grub_priority_queue_destroy (rsm
->pq
);
360 free_old_fragments (void)
362 struct reassemble
*rsm
, **prev
;
363 grub_uint64_t limit_time
= grub_get_time_ms () - 90000;
365 for (prev
= &reassembles
, rsm
= *prev
; rsm
; rsm
= *prev
)
366 if (rsm
->last_time
< limit_time
)
378 grub_net_recv_ip4_packets (struct grub_net_buff
*nb
,
379 struct grub_net_card
*card
,
380 const grub_net_link_level_address_t
*hwaddress
,
381 const grub_net_link_level_address_t
*src_hwaddress
)
383 struct iphdr
*iph
= (struct iphdr
*) nb
->data
;
385 struct reassemble
*rsm
, **prev
;
387 if ((iph
->verhdrlen
>> 4) != 4)
389 grub_dprintf ("net", "Bad IP version: %d\n", (iph
->verhdrlen
>> 4));
390 grub_netbuff_free (nb
);
391 return GRUB_ERR_NONE
;
394 if ((iph
->verhdrlen
& 0xf) < 5)
396 grub_dprintf ("net", "IP header too short: %d\n",
397 (iph
->verhdrlen
& 0xf));
398 grub_netbuff_free (nb
);
399 return GRUB_ERR_NONE
;
402 if (nb
->tail
- nb
->data
< (grub_ssize_t
) ((iph
->verhdrlen
& 0xf)
403 * sizeof (grub_uint32_t
)))
405 grub_dprintf ("net", "IP packet too short: %" PRIdGRUB_SSIZE
"\n",
406 (nb
->tail
- nb
->data
));
407 grub_netbuff_free (nb
);
408 return GRUB_ERR_NONE
;
413 grub_size_t expected_size
= grub_be_to_cpu16 (iph
->len
);
414 grub_size_t actual_size
= (nb
->tail
- nb
->data
);
415 if (actual_size
> expected_size
)
417 err
= grub_netbuff_unput (nb
, actual_size
- expected_size
);
420 grub_netbuff_free (nb
);
424 if (actual_size
< expected_size
)
426 grub_dprintf ("net", "Cut IP packet actual: %" PRIuGRUB_SIZE
427 ", expected %" PRIuGRUB_SIZE
"\n", actual_size
,
429 grub_netbuff_free (nb
);
430 return GRUB_ERR_NONE
;
434 /* Unfragmented packet. Good. */
435 if (((grub_be_to_cpu16 (iph
->frags
) & MORE_FRAGMENTS
) == 0)
436 && (grub_be_to_cpu16 (iph
->frags
) & OFFSET_MASK
) == 0)
438 grub_net_network_level_address_t source
;
439 grub_net_network_level_address_t dest
;
441 err
= grub_netbuff_pull (nb
, ((iph
->verhdrlen
& 0xf)
442 * sizeof (grub_uint32_t
)));
445 grub_netbuff_free (nb
);
449 source
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
450 source
.ipv4
= iph
->src
;
452 dest
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
453 dest
.ipv4
= iph
->dest
;
455 return handle_dgram (nb
, card
, src_hwaddress
, hwaddress
, iph
->protocol
,
456 &source
, &dest
, iph
->ttl
);
459 for (prev
= &reassembles
, rsm
= *prev
; rsm
; prev
= &rsm
->next
, rsm
= *prev
)
460 if (rsm
->source
== iph
->src
&& rsm
->dest
== iph
->dest
461 && rsm
->id
== iph
->ident
&& rsm
->proto
== iph
->protocol
)
465 rsm
= grub_malloc (sizeof (*rsm
));
468 rsm
->source
= iph
->src
;
469 rsm
->dest
= iph
->dest
;
470 rsm
->id
= iph
->ident
;
471 rsm
->proto
= iph
->protocol
;
472 rsm
->next
= reassembles
;
475 rsm
->pq
= grub_priority_queue_new (sizeof (struct grub_net_buff
**), cmp
);
481 rsm
->asm_netbuff
= 0;
486 if (rsm
->ttl
> iph
->ttl
)
488 rsm
->last_time
= grub_get_time_ms ();
489 free_old_fragments ();
491 err
= grub_priority_queue_push (rsm
->pq
, &nb
);
495 if (!(grub_be_to_cpu16 (iph
->frags
) & MORE_FRAGMENTS
))
497 rsm
->total_len
= (8 * (grub_be_to_cpu16 (iph
->frags
) & OFFSET_MASK
)
498 + (nb
->tail
- nb
->data
));
499 rsm
->total_len
-= ((iph
->verhdrlen
& 0xf) * sizeof (grub_uint32_t
));
500 rsm
->asm_netbuff
= grub_netbuff_alloc (rsm
->total_len
);
501 if (!rsm
->asm_netbuff
)
508 if (!rsm
->asm_netbuff
)
509 return GRUB_ERR_NONE
;
513 struct grub_net_buff
**nb_top_p
, *nb_top
;
516 struct grub_net_buff
*ret
;
517 grub_net_ip_protocol_t proto
;
520 grub_net_network_level_address_t source
;
521 grub_net_network_level_address_t dest
;
524 nb_top_p
= grub_priority_queue_top (rsm
->pq
);
526 return GRUB_ERR_NONE
;
528 grub_priority_queue_pop (rsm
->pq
);
529 iph
= (struct iphdr
*) nb_top
->data
;
530 err
= grub_netbuff_pull (nb_top
, ((iph
->verhdrlen
& 0xf)
531 * sizeof (grub_uint32_t
)));
534 grub_netbuff_free (nb_top
);
537 if (rsm
->cur_ptr
< (grub_size_t
) 8 * (grub_be_to_cpu16 (iph
->frags
)
540 grub_netbuff_free (nb_top
);
541 return GRUB_ERR_NONE
;
544 rsm
->cur_ptr
= (8 * (grub_be_to_cpu16 (iph
->frags
) & OFFSET_MASK
)
545 + (nb_top
->tail
- nb_top
->head
));
546 if ((grub_size_t
) 8 * (grub_be_to_cpu16 (iph
->frags
) & OFFSET_MASK
)
549 grub_netbuff_free (nb_top
);
552 copy
= nb_top
->tail
- nb_top
->data
;
553 if (rsm
->total_len
- 8 * (grub_be_to_cpu16 (iph
->frags
) & OFFSET_MASK
)
555 copy
= rsm
->total_len
- 8 * (grub_be_to_cpu16 (iph
->frags
)
557 grub_memcpy (&rsm
->asm_netbuff
->data
[8 * (grub_be_to_cpu16 (iph
->frags
)
561 if ((grub_be_to_cpu16 (iph
->frags
) & MORE_FRAGMENTS
))
563 grub_netbuff_free (nb_top
);
566 grub_netbuff_free (nb_top
);
568 ret
= rsm
->asm_netbuff
;
574 rsm
->asm_netbuff
= 0;
575 res_len
= rsm
->total_len
;
579 if (grub_netbuff_put (ret
, res_len
))
581 grub_netbuff_free (ret
);
582 return GRUB_ERR_NONE
;
585 source
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
588 dest
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
591 return handle_dgram (ret
, card
, src_hwaddress
,
592 hwaddress
, proto
, &source
, &dest
,
598 grub_net_send_ip6_packet (struct grub_net_network_level_interface
*inf
,
599 const grub_net_network_level_address_t
*target
,
600 const grub_net_link_level_address_t
*ll_target_addr
,
601 struct grub_net_buff
*nb
,
602 grub_net_ip_protocol_t proto
)
606 COMPILE_TIME_ASSERT (GRUB_NET_OUR_IPV6_HEADER_SIZE
== sizeof (*iph
));
608 if (nb
->tail
- nb
->data
+ sizeof (struct iphdr
) > inf
->card
->mtu
)
609 return grub_error (GRUB_ERR_NET_PACKET_TOO_BIG
, "packet too big");
611 grub_netbuff_push (nb
, sizeof (*iph
));
612 iph
= (struct ip6hdr
*) nb
->data
;
614 iph
->version_class_flow
= grub_cpu_to_be32 ((6 << 28));
615 iph
->len
= grub_cpu_to_be16 (nb
->tail
- nb
->data
- sizeof (*iph
));
616 iph
->protocol
= proto
;
618 grub_memcpy (&iph
->src
, inf
->address
.ipv6
, sizeof (iph
->src
));
619 grub_memcpy (&iph
->dest
, target
->ipv6
, sizeof (iph
->dest
));
621 return send_ethernet_packet (inf
, nb
, *ll_target_addr
,
622 GRUB_NET_ETHERTYPE_IP6
);
626 grub_net_send_ip_packet (struct grub_net_network_level_interface
*inf
,
627 const grub_net_network_level_address_t
*target
,
628 const grub_net_link_level_address_t
*ll_target_addr
,
629 struct grub_net_buff
*nb
,
630 grub_net_ip_protocol_t proto
)
632 switch (target
->type
)
634 case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
:
635 return grub_net_send_ip4_packet (inf
, target
, ll_target_addr
, nb
, proto
);
636 case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
:
637 return grub_net_send_ip6_packet (inf
, target
, ll_target_addr
, nb
, proto
);
639 return grub_error (GRUB_ERR_BUG
, "not an IP");
644 grub_net_recv_ip6_packets (struct grub_net_buff
*nb
,
645 struct grub_net_card
*card
,
646 const grub_net_link_level_address_t
*hwaddress
,
647 const grub_net_link_level_address_t
*src_hwaddress
)
649 struct ip6hdr
*iph
= (struct ip6hdr
*) nb
->data
;
651 grub_net_network_level_address_t source
;
652 grub_net_network_level_address_t dest
;
654 if (nb
->tail
- nb
->data
< (grub_ssize_t
) sizeof (*iph
))
656 grub_dprintf ("net", "IP packet too short: %" PRIdGRUB_SSIZE
"\n",
657 nb
->tail
- nb
->data
);
658 grub_netbuff_free (nb
);
659 return GRUB_ERR_NONE
;
662 err
= grub_netbuff_pull (nb
, sizeof (*iph
));
665 grub_netbuff_free (nb
);
671 grub_size_t expected_size
= grub_be_to_cpu16 (iph
->len
);
672 grub_size_t actual_size
= (nb
->tail
- nb
->data
);
673 if (actual_size
> expected_size
)
675 err
= grub_netbuff_unput (nb
, actual_size
- expected_size
);
678 grub_netbuff_free (nb
);
682 if (actual_size
< expected_size
)
684 grub_dprintf ("net", "Cut IP packet actual: %" PRIuGRUB_SIZE
685 ", expected %" PRIuGRUB_SIZE
"\n", actual_size
,
687 grub_netbuff_free (nb
);
688 return GRUB_ERR_NONE
;
692 source
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
;
693 dest
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
;
694 grub_memcpy (source
.ipv6
, &iph
->src
, sizeof (source
.ipv6
));
695 grub_memcpy (dest
.ipv6
, &iph
->dest
, sizeof (dest
.ipv6
));
697 return handle_dgram (nb
, card
, src_hwaddress
, hwaddress
, iph
->protocol
,
698 &source
, &dest
, iph
->ttl
);
702 grub_net_recv_ip_packets (struct grub_net_buff
*nb
,
703 struct grub_net_card
*card
,
704 const grub_net_link_level_address_t
*hwaddress
,
705 const grub_net_link_level_address_t
*src_hwaddress
)
707 struct iphdr
*iph
= (struct iphdr
*) nb
->data
;
709 if ((iph
->verhdrlen
>> 4) == 4)
710 return grub_net_recv_ip4_packets (nb
, card
, hwaddress
, src_hwaddress
);
711 if ((iph
->verhdrlen
>> 4) == 6)
712 return grub_net_recv_ip6_packets (nb
, card
, hwaddress
, src_hwaddress
);
713 grub_dprintf ("net", "Bad IP version: %d\n", (iph
->verhdrlen
>> 4));
714 grub_netbuff_free (nb
);
715 return GRUB_ERR_NONE
;