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
;
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
;
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
)
196 COMPILE_TIME_ASSERT (GRUB_NET_OUR_IPV4_HEADER_SIZE
== sizeof (*iph
));
198 if (nb
->tail
- nb
->data
+ sizeof (struct iphdr
) > inf
->card
->mtu
)
199 return send_fragmented (inf
, target
, nb
, proto
, *ll_target_addr
);
201 err
= grub_netbuff_push (nb
, sizeof (*iph
));
205 iph
= (struct iphdr
*) nb
->data
;
206 iph
->verhdrlen
= ((4 << 4) | 5);
208 iph
->len
= grub_cpu_to_be16 (nb
->tail
- nb
->data
);
209 iph
->ident
= grub_cpu_to_be16 (++id
);
212 iph
->protocol
= proto
;
213 iph
->src
= inf
->address
.ipv4
;
214 iph
->dest
= target
->ipv4
;
217 iph
->chksum
= grub_net_ip_chksum ((void *) nb
->data
, sizeof (*iph
));
219 return send_ethernet_packet (inf
, nb
, *ll_target_addr
,
220 GRUB_NET_ETHERTYPE_IP
);
224 handle_dgram (struct grub_net_buff
*nb
,
225 struct grub_net_card
*card
,
226 const grub_net_link_level_address_t
*source_hwaddress
,
227 const grub_net_link_level_address_t
*hwaddress
,
228 grub_net_ip_protocol_t proto
,
229 const grub_net_network_level_address_t
*source
,
230 const grub_net_network_level_address_t
*dest
,
233 struct grub_net_network_level_interface
*inf
= NULL
;
237 /* DHCP needs special treatment since we don't know IP yet. */
240 udph
= (struct udphdr
*) nb
->data
;
241 if (proto
== GRUB_NET_IP_UDP
&& grub_be_to_cpu16 (udph
->dst
) == 68)
243 const struct grub_net_bootp_packet
*bootp
;
246 grub_uint16_t chk
, expected
;
249 expected
= grub_net_ip_transport_checksum (nb
,
255 grub_dprintf ("net", "Invalid UDP checksum. "
256 "Expected %x, got %x\n",
257 grub_be_to_cpu16 (expected
),
258 grub_be_to_cpu16 (chk
));
259 grub_netbuff_free (nb
);
260 return GRUB_ERR_NONE
;
265 err
= grub_netbuff_pull (nb
, sizeof (*udph
));
268 grub_netbuff_free (nb
);
272 bootp
= (const struct grub_net_bootp_packet
*) nb
->data
;
274 FOR_NET_NETWORK_LEVEL_INTERFACES (inf
)
275 if (inf
->card
== card
276 && inf
->address
.type
== GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV
277 && inf
->hwaddress
.type
== GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
278 && grub_memcmp (inf
->hwaddress
.mac
, &bootp
->mac_addr
,
279 sizeof (inf
->hwaddress
.mac
)) == 0)
281 grub_net_process_dhcp (nb
, inf
->card
);
282 grub_netbuff_free (nb
);
283 return GRUB_ERR_NONE
;
285 grub_netbuff_free (nb
);
286 return GRUB_ERR_NONE
;
290 FOR_NET_NETWORK_LEVEL_INTERFACES (inf
)
292 if (inf
->card
== card
293 && grub_net_addr_cmp (&inf
->address
, dest
) == 0
294 && grub_net_hwaddr_cmp (&inf
->hwaddress
, hwaddress
) == 0)
296 /* Solicited node multicast. */
297 if (inf
->card
== card
298 && inf
->address
.type
== GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
299 && dest
->type
== GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
300 && dest
->ipv6
[0] == grub_be_to_cpu64_compile_time (0xff02ULL
<< 48)
301 && dest
->ipv6
[1] == (grub_be_to_cpu64_compile_time (0x01ff000000ULL
)
302 | (inf
->address
.ipv6
[1]
303 & grub_be_to_cpu64_compile_time (0xffffff)))
304 && hwaddress
->type
== GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
305 && hwaddress
->mac
[0] == 0x33 && hwaddress
->mac
[1] == 0x33
306 && hwaddress
->mac
[2] == 0xff
307 && hwaddress
->mac
[3] == ((grub_be_to_cpu64 (inf
->address
.ipv6
[1])
309 && hwaddress
->mac
[4] == ((grub_be_to_cpu64 (inf
->address
.ipv6
[1])
311 && hwaddress
->mac
[5] == ((grub_be_to_cpu64 (inf
->address
.ipv6
[1])
319 if (!inf
&& !(dest
->type
== GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
320 && dest
->ipv6
[0] == grub_be_to_cpu64_compile_time (0xff02ULL
322 && dest
->ipv6
[1] == grub_be_to_cpu64_compile_time (1)))
324 grub_netbuff_free (nb
);
325 return GRUB_ERR_NONE
;
332 case GRUB_NET_IP_UDP
:
333 return grub_net_recv_udp_packet (nb
, inf
, source
);
334 case GRUB_NET_IP_TCP
:
335 return grub_net_recv_tcp_packet (nb
, inf
, source
);
336 case GRUB_NET_IP_ICMP
:
337 return grub_net_recv_icmp_packet (nb
, inf
, source_hwaddress
, source
);
338 case GRUB_NET_IP_ICMPV6
:
339 return grub_net_recv_icmp6_packet (nb
, card
, inf
, source_hwaddress
,
342 grub_netbuff_free (nb
);
345 return GRUB_ERR_NONE
;
349 free_rsm (struct reassemble
*rsm
)
351 struct grub_net_buff
**nb
;
352 while ((nb
= grub_priority_queue_top (rsm
->pq
)))
354 grub_netbuff_free (*nb
);
355 grub_priority_queue_pop (rsm
->pq
);
357 grub_netbuff_free (rsm
->asm_netbuff
);
358 grub_priority_queue_destroy (rsm
->pq
);
363 free_old_fragments (void)
365 struct reassemble
*rsm
, **prev
;
366 grub_uint64_t limit_time
= grub_get_time_ms () - 90000;
368 for (prev
= &reassembles
, rsm
= *prev
; rsm
; rsm
= *prev
)
369 if (rsm
->last_time
< limit_time
)
381 grub_net_recv_ip4_packets (struct grub_net_buff
*nb
,
382 struct grub_net_card
*card
,
383 const grub_net_link_level_address_t
*hwaddress
,
384 const grub_net_link_level_address_t
*src_hwaddress
)
386 struct iphdr
*iph
= (struct iphdr
*) nb
->data
;
388 struct reassemble
*rsm
, **prev
;
390 if ((iph
->verhdrlen
>> 4) != 4)
392 grub_dprintf ("net", "Bad IP version: %d\n", (iph
->verhdrlen
>> 4));
393 grub_netbuff_free (nb
);
394 return GRUB_ERR_NONE
;
397 if ((iph
->verhdrlen
& 0xf) < 5)
399 grub_dprintf ("net", "IP header too short: %d\n",
400 (iph
->verhdrlen
& 0xf));
401 grub_netbuff_free (nb
);
402 return GRUB_ERR_NONE
;
405 if (nb
->tail
- nb
->data
< (grub_ssize_t
) ((iph
->verhdrlen
& 0xf)
406 * sizeof (grub_uint32_t
)))
408 grub_dprintf ("net", "IP packet too short: %" PRIdGRUB_SSIZE
"\n",
409 (grub_ssize_t
) (nb
->tail
- nb
->data
));
410 grub_netbuff_free (nb
);
411 return GRUB_ERR_NONE
;
416 grub_size_t expected_size
= grub_be_to_cpu16 (iph
->len
);
417 grub_size_t actual_size
= (nb
->tail
- nb
->data
);
418 if (actual_size
> expected_size
)
420 err
= grub_netbuff_unput (nb
, actual_size
- expected_size
);
423 grub_netbuff_free (nb
);
427 if (actual_size
< expected_size
)
429 grub_dprintf ("net", "Cut IP packet actual: %" PRIuGRUB_SIZE
430 ", expected %" PRIuGRUB_SIZE
"\n", actual_size
,
432 grub_netbuff_free (nb
);
433 return GRUB_ERR_NONE
;
437 /* Unfragmented packet. Good. */
438 if (((grub_be_to_cpu16 (iph
->frags
) & MORE_FRAGMENTS
) == 0)
439 && (grub_be_to_cpu16 (iph
->frags
) & OFFSET_MASK
) == 0)
441 grub_net_network_level_address_t source
;
442 grub_net_network_level_address_t dest
;
444 err
= grub_netbuff_pull (nb
, ((iph
->verhdrlen
& 0xf)
445 * sizeof (grub_uint32_t
)));
448 grub_netbuff_free (nb
);
452 source
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
453 source
.ipv4
= iph
->src
;
455 dest
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
456 dest
.ipv4
= iph
->dest
;
458 return handle_dgram (nb
, card
, src_hwaddress
, hwaddress
, iph
->protocol
,
459 &source
, &dest
, iph
->ttl
);
462 for (prev
= &reassembles
, rsm
= *prev
; rsm
; prev
= &rsm
->next
, rsm
= *prev
)
463 if (rsm
->source
== iph
->src
&& rsm
->dest
== iph
->dest
464 && rsm
->id
== iph
->ident
&& rsm
->proto
== iph
->protocol
)
468 rsm
= grub_malloc (sizeof (*rsm
));
471 rsm
->source
= iph
->src
;
472 rsm
->dest
= iph
->dest
;
473 rsm
->id
= iph
->ident
;
474 rsm
->proto
= iph
->protocol
;
475 rsm
->next
= reassembles
;
478 rsm
->pq
= grub_priority_queue_new (sizeof (struct grub_net_buff
**), cmp
);
484 rsm
->asm_netbuff
= 0;
489 if (rsm
->ttl
> iph
->ttl
)
491 rsm
->last_time
= grub_get_time_ms ();
492 free_old_fragments ();
494 err
= grub_priority_queue_push (rsm
->pq
, &nb
);
498 if (!(grub_be_to_cpu16 (iph
->frags
) & MORE_FRAGMENTS
))
500 rsm
->total_len
= (8 * (grub_be_to_cpu16 (iph
->frags
) & OFFSET_MASK
)
501 + (nb
->tail
- nb
->data
));
502 rsm
->total_len
-= ((iph
->verhdrlen
& 0xf) * sizeof (grub_uint32_t
));
503 rsm
->asm_netbuff
= grub_netbuff_alloc (rsm
->total_len
);
504 if (!rsm
->asm_netbuff
)
511 if (!rsm
->asm_netbuff
)
512 return GRUB_ERR_NONE
;
516 struct grub_net_buff
**nb_top_p
, *nb_top
;
519 struct grub_net_buff
*ret
;
520 grub_net_ip_protocol_t proto
;
523 grub_net_network_level_address_t source
;
524 grub_net_network_level_address_t dest
;
527 nb_top_p
= grub_priority_queue_top (rsm
->pq
);
529 return GRUB_ERR_NONE
;
531 grub_priority_queue_pop (rsm
->pq
);
532 iph
= (struct iphdr
*) nb_top
->data
;
533 err
= grub_netbuff_pull (nb_top
, ((iph
->verhdrlen
& 0xf)
534 * sizeof (grub_uint32_t
)));
537 grub_netbuff_free (nb_top
);
540 if (rsm
->cur_ptr
< (grub_size_t
) 8 * (grub_be_to_cpu16 (iph
->frags
)
543 grub_netbuff_free (nb_top
);
544 return GRUB_ERR_NONE
;
547 rsm
->cur_ptr
= (8 * (grub_be_to_cpu16 (iph
->frags
) & OFFSET_MASK
)
548 + (nb_top
->tail
- nb_top
->head
));
549 if ((grub_size_t
) 8 * (grub_be_to_cpu16 (iph
->frags
) & OFFSET_MASK
)
552 grub_netbuff_free (nb_top
);
555 copy
= nb_top
->tail
- nb_top
->data
;
556 if (rsm
->total_len
- 8 * (grub_be_to_cpu16 (iph
->frags
) & OFFSET_MASK
)
558 copy
= rsm
->total_len
- 8 * (grub_be_to_cpu16 (iph
->frags
)
560 grub_memcpy (&rsm
->asm_netbuff
->data
[8 * (grub_be_to_cpu16 (iph
->frags
)
564 if ((grub_be_to_cpu16 (iph
->frags
) & MORE_FRAGMENTS
))
566 grub_netbuff_free (nb_top
);
569 grub_netbuff_free (nb_top
);
571 ret
= rsm
->asm_netbuff
;
577 rsm
->asm_netbuff
= 0;
578 res_len
= rsm
->total_len
;
582 if (grub_netbuff_put (ret
, res_len
))
584 grub_netbuff_free (ret
);
585 return GRUB_ERR_NONE
;
588 source
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
591 dest
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
594 return handle_dgram (ret
, card
, src_hwaddress
,
595 hwaddress
, proto
, &source
, &dest
,
601 grub_net_send_ip6_packet (struct grub_net_network_level_interface
*inf
,
602 const grub_net_network_level_address_t
*target
,
603 const grub_net_link_level_address_t
*ll_target_addr
,
604 struct grub_net_buff
*nb
,
605 grub_net_ip_protocol_t proto
)
610 COMPILE_TIME_ASSERT (GRUB_NET_OUR_IPV6_HEADER_SIZE
== sizeof (*iph
));
612 if (nb
->tail
- nb
->data
+ sizeof (struct iphdr
) > inf
->card
->mtu
)
613 return grub_error (GRUB_ERR_NET_PACKET_TOO_BIG
, "packet too big");
615 err
= grub_netbuff_push (nb
, sizeof (*iph
));
619 iph
= (struct ip6hdr
*) nb
->data
;
620 iph
->version_class_flow
= grub_cpu_to_be32_compile_time ((6 << 28));
621 iph
->len
= grub_cpu_to_be16 (nb
->tail
- nb
->data
- sizeof (*iph
));
622 iph
->protocol
= proto
;
624 grub_memcpy (&iph
->src
, inf
->address
.ipv6
, sizeof (iph
->src
));
625 grub_memcpy (&iph
->dest
, target
->ipv6
, sizeof (iph
->dest
));
627 return send_ethernet_packet (inf
, nb
, *ll_target_addr
,
628 GRUB_NET_ETHERTYPE_IP6
);
632 grub_net_send_ip_packet (struct grub_net_network_level_interface
*inf
,
633 const grub_net_network_level_address_t
*target
,
634 const grub_net_link_level_address_t
*ll_target_addr
,
635 struct grub_net_buff
*nb
,
636 grub_net_ip_protocol_t proto
)
638 switch (target
->type
)
640 case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
:
641 return grub_net_send_ip4_packet (inf
, target
, ll_target_addr
, nb
, proto
);
642 case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
:
643 return grub_net_send_ip6_packet (inf
, target
, ll_target_addr
, nb
, proto
);
645 return grub_error (GRUB_ERR_BUG
, "not an IP");
650 grub_net_recv_ip6_packets (struct grub_net_buff
*nb
,
651 struct grub_net_card
*card
,
652 const grub_net_link_level_address_t
*hwaddress
,
653 const grub_net_link_level_address_t
*src_hwaddress
)
655 struct ip6hdr
*iph
= (struct ip6hdr
*) nb
->data
;
657 grub_net_network_level_address_t source
;
658 grub_net_network_level_address_t dest
;
660 if (nb
->tail
- nb
->data
< (grub_ssize_t
) sizeof (*iph
))
662 grub_dprintf ("net", "IP packet too short: %" PRIdGRUB_SSIZE
"\n",
663 (grub_ssize_t
) (nb
->tail
- nb
->data
));
664 grub_netbuff_free (nb
);
665 return GRUB_ERR_NONE
;
668 err
= grub_netbuff_pull (nb
, sizeof (*iph
));
671 grub_netbuff_free (nb
);
677 grub_size_t expected_size
= grub_be_to_cpu16 (iph
->len
);
678 grub_size_t actual_size
= (nb
->tail
- nb
->data
);
679 if (actual_size
> expected_size
)
681 err
= grub_netbuff_unput (nb
, actual_size
- expected_size
);
684 grub_netbuff_free (nb
);
688 if (actual_size
< expected_size
)
690 grub_dprintf ("net", "Cut IP packet actual: %" PRIuGRUB_SIZE
691 ", expected %" PRIuGRUB_SIZE
"\n", actual_size
,
693 grub_netbuff_free (nb
);
694 return GRUB_ERR_NONE
;
698 source
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
;
699 dest
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
;
700 grub_memcpy (source
.ipv6
, &iph
->src
, sizeof (source
.ipv6
));
701 grub_memcpy (dest
.ipv6
, &iph
->dest
, sizeof (dest
.ipv6
));
703 return handle_dgram (nb
, card
, src_hwaddress
, hwaddress
, iph
->protocol
,
704 &source
, &dest
, iph
->ttl
);
708 grub_net_recv_ip_packets (struct grub_net_buff
*nb
,
709 struct grub_net_card
*card
,
710 const grub_net_link_level_address_t
*hwaddress
,
711 const grub_net_link_level_address_t
*src_hwaddress
)
713 struct iphdr
*iph
= (struct iphdr
*) nb
->data
;
715 if ((iph
->verhdrlen
>> 4) == 4)
716 return grub_net_recv_ip4_packets (nb
, card
, hwaddress
, src_hwaddress
);
717 if ((iph
->verhdrlen
>> 4) == 6)
718 return grub_net_recv_ip6_packets (nb
, card
, hwaddress
, src_hwaddress
);
719 grub_dprintf ("net", "Bad IP version: %d\n", (iph
->verhdrlen
>> 4));
720 grub_netbuff_free (nb
);
721 return GRUB_ERR_NONE
;