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
,
231 grub_uint16_t
*vlantag
,
234 struct grub_net_network_level_interface
*inf
= NULL
;
238 /* DHCP needs special treatment since we don't know IP yet. */
241 udph
= (struct udphdr
*) nb
->data
;
242 if (proto
== GRUB_NET_IP_UDP
&& grub_be_to_cpu16 (udph
->dst
) == 68)
244 const struct grub_net_bootp_packet
*bootp
;
247 grub_uint16_t chk
, expected
;
250 expected
= grub_net_ip_transport_checksum (nb
,
256 grub_dprintf ("net", "Invalid UDP checksum. "
257 "Expected %x, got %x\n",
258 grub_be_to_cpu16 (expected
),
259 grub_be_to_cpu16 (chk
));
260 grub_netbuff_free (nb
);
261 return GRUB_ERR_NONE
;
266 err
= grub_netbuff_pull (nb
, sizeof (*udph
));
269 grub_netbuff_free (nb
);
273 bootp
= (const struct grub_net_bootp_packet
*) nb
->data
;
275 FOR_NET_NETWORK_LEVEL_INTERFACES (inf
)
276 if (inf
->card
== card
277 && inf
->address
.type
== GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV
278 && inf
->hwaddress
.type
== GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
279 && grub_memcmp (inf
->hwaddress
.mac
, &bootp
->mac_addr
,
280 sizeof (inf
->hwaddress
.mac
)) == 0)
282 grub_net_process_dhcp (nb
, inf
);
283 grub_netbuff_free (nb
);
284 return GRUB_ERR_NONE
;
286 grub_netbuff_free (nb
);
287 return GRUB_ERR_NONE
;
291 FOR_NET_NETWORK_LEVEL_INTERFACES (inf
)
293 if (inf
->card
== card
294 && grub_net_addr_cmp (&inf
->address
, dest
) == 0
295 && grub_net_hwaddr_cmp (&inf
->hwaddress
, hwaddress
) == 0)
298 /* Verify vlantag id */
299 if (inf
->card
== card
&& inf
->vlantag
!= *vlantag
)
301 grub_dprintf ("net", "invalid vlantag! %x != %x\n",
302 inf
->vlantag
, *vlantag
);
306 /* Solicited node multicast. */
307 if (inf
->card
== card
308 && inf
->address
.type
== GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
309 && dest
->type
== GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
310 && dest
->ipv6
[0] == grub_be_to_cpu64_compile_time (0xff02ULL
<< 48)
311 && dest
->ipv6
[1] == (grub_be_to_cpu64_compile_time (0x01ff000000ULL
)
312 | (inf
->address
.ipv6
[1]
313 & grub_be_to_cpu64_compile_time (0xffffff)))
314 && hwaddress
->type
== GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
315 && hwaddress
->mac
[0] == 0x33 && hwaddress
->mac
[1] == 0x33
316 && hwaddress
->mac
[2] == 0xff
317 && hwaddress
->mac
[3] == ((grub_be_to_cpu64 (inf
->address
.ipv6
[1])
319 && hwaddress
->mac
[4] == ((grub_be_to_cpu64 (inf
->address
.ipv6
[1])
321 && hwaddress
->mac
[5] == ((grub_be_to_cpu64 (inf
->address
.ipv6
[1])
329 if (!inf
&& !(dest
->type
== GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
330 && dest
->ipv6
[0] == grub_be_to_cpu64_compile_time (0xff02ULL
332 && dest
->ipv6
[1] == grub_be_to_cpu64_compile_time (1)))
334 grub_netbuff_free (nb
);
335 return GRUB_ERR_NONE
;
342 case GRUB_NET_IP_UDP
:
343 return grub_net_recv_udp_packet (nb
, inf
, source
);
344 case GRUB_NET_IP_TCP
:
345 return grub_net_recv_tcp_packet (nb
, inf
, source
);
346 case GRUB_NET_IP_ICMP
:
347 return grub_net_recv_icmp_packet (nb
, inf
, source_hwaddress
, source
);
348 case GRUB_NET_IP_ICMPV6
:
349 return grub_net_recv_icmp6_packet (nb
, card
, inf
, source_hwaddress
,
352 grub_netbuff_free (nb
);
355 return GRUB_ERR_NONE
;
359 free_rsm (struct reassemble
*rsm
)
361 struct grub_net_buff
**nb
;
362 while ((nb
= grub_priority_queue_top (rsm
->pq
)))
364 grub_netbuff_free (*nb
);
365 grub_priority_queue_pop (rsm
->pq
);
367 grub_netbuff_free (rsm
->asm_netbuff
);
368 grub_priority_queue_destroy (rsm
->pq
);
373 free_old_fragments (void)
375 struct reassemble
*rsm
, **prev
;
376 grub_uint64_t limit_time
= grub_get_time_ms ();
378 limit_time
= (limit_time
> 90000) ? limit_time
- 90000 : 0;
380 for (prev
= &reassembles
, rsm
= *prev
; rsm
; rsm
= *prev
)
381 if (rsm
->last_time
< limit_time
)
393 grub_net_recv_ip4_packets (struct grub_net_buff
*nb
,
394 struct grub_net_card
*card
,
395 const grub_net_link_level_address_t
*hwaddress
,
396 const grub_net_link_level_address_t
*src_hwaddress
,
397 grub_uint16_t
*vlantag
)
399 struct iphdr
*iph
= (struct iphdr
*) nb
->data
;
401 struct reassemble
*rsm
, **prev
;
403 if ((iph
->verhdrlen
>> 4) != 4)
405 grub_dprintf ("net", "Bad IP version: %d\n", (iph
->verhdrlen
>> 4));
406 grub_netbuff_free (nb
);
407 return GRUB_ERR_NONE
;
410 if ((iph
->verhdrlen
& 0xf) < 5)
412 grub_dprintf ("net", "IP header too short: %d\n",
413 (iph
->verhdrlen
& 0xf));
414 grub_netbuff_free (nb
);
415 return GRUB_ERR_NONE
;
418 if (nb
->tail
- nb
->data
< (grub_ssize_t
) ((iph
->verhdrlen
& 0xf)
419 * sizeof (grub_uint32_t
)))
421 grub_dprintf ("net", "IP packet too short: %" PRIdGRUB_SSIZE
"\n",
422 (grub_ssize_t
) (nb
->tail
- nb
->data
));
423 grub_netbuff_free (nb
);
424 return GRUB_ERR_NONE
;
429 grub_size_t expected_size
= grub_be_to_cpu16 (iph
->len
);
430 grub_size_t actual_size
= (nb
->tail
- nb
->data
);
431 if (actual_size
> expected_size
)
433 err
= grub_netbuff_unput (nb
, actual_size
- expected_size
);
436 grub_netbuff_free (nb
);
440 if (actual_size
< expected_size
)
442 grub_dprintf ("net", "Cut IP packet actual: %" PRIuGRUB_SIZE
443 ", expected %" PRIuGRUB_SIZE
"\n", actual_size
,
445 grub_netbuff_free (nb
);
446 return GRUB_ERR_NONE
;
450 /* Unfragmented packet. Good. */
451 if (((grub_be_to_cpu16 (iph
->frags
) & MORE_FRAGMENTS
) == 0)
452 && (grub_be_to_cpu16 (iph
->frags
) & OFFSET_MASK
) == 0)
454 grub_net_network_level_address_t source
;
455 grub_net_network_level_address_t dest
;
457 err
= grub_netbuff_pull (nb
, ((iph
->verhdrlen
& 0xf)
458 * sizeof (grub_uint32_t
)));
461 grub_netbuff_free (nb
);
465 source
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
466 source
.ipv4
= iph
->src
;
468 dest
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
469 dest
.ipv4
= iph
->dest
;
471 return handle_dgram (nb
, card
, src_hwaddress
, hwaddress
, iph
->protocol
,
472 &source
, &dest
, vlantag
, iph
->ttl
);
475 for (prev
= &reassembles
, rsm
= *prev
; rsm
; prev
= &rsm
->next
, rsm
= *prev
)
476 if (rsm
->source
== iph
->src
&& rsm
->dest
== iph
->dest
477 && rsm
->id
== iph
->ident
&& rsm
->proto
== iph
->protocol
)
481 rsm
= grub_malloc (sizeof (*rsm
));
484 rsm
->source
= iph
->src
;
485 rsm
->dest
= iph
->dest
;
486 rsm
->id
= iph
->ident
;
487 rsm
->proto
= iph
->protocol
;
488 rsm
->next
= reassembles
;
491 rsm
->pq
= grub_priority_queue_new (sizeof (struct grub_net_buff
**), cmp
);
497 rsm
->asm_netbuff
= 0;
502 if (rsm
->ttl
> iph
->ttl
)
504 rsm
->last_time
= grub_get_time_ms ();
505 free_old_fragments ();
507 err
= grub_priority_queue_push (rsm
->pq
, &nb
);
511 if (!(grub_be_to_cpu16 (iph
->frags
) & MORE_FRAGMENTS
))
513 rsm
->total_len
= (8 * (grub_be_to_cpu16 (iph
->frags
) & OFFSET_MASK
)
514 + (nb
->tail
- nb
->data
));
515 rsm
->total_len
-= ((iph
->verhdrlen
& 0xf) * sizeof (grub_uint32_t
));
516 rsm
->asm_netbuff
= grub_netbuff_alloc (rsm
->total_len
);
517 if (!rsm
->asm_netbuff
)
524 if (!rsm
->asm_netbuff
)
525 return GRUB_ERR_NONE
;
529 struct grub_net_buff
**nb_top_p
, *nb_top
;
532 struct grub_net_buff
*ret
;
533 grub_net_ip_protocol_t proto
;
536 grub_net_network_level_address_t source
;
537 grub_net_network_level_address_t dest
;
540 nb_top_p
= grub_priority_queue_top (rsm
->pq
);
542 return GRUB_ERR_NONE
;
544 grub_priority_queue_pop (rsm
->pq
);
545 iph
= (struct iphdr
*) nb_top
->data
;
546 err
= grub_netbuff_pull (nb_top
, ((iph
->verhdrlen
& 0xf)
547 * sizeof (grub_uint32_t
)));
550 grub_netbuff_free (nb_top
);
553 if (rsm
->cur_ptr
< (grub_size_t
) 8 * (grub_be_to_cpu16 (iph
->frags
)
556 grub_netbuff_free (nb_top
);
557 return GRUB_ERR_NONE
;
560 rsm
->cur_ptr
= (8 * (grub_be_to_cpu16 (iph
->frags
) & OFFSET_MASK
)
561 + (nb_top
->tail
- nb_top
->head
));
562 if ((grub_size_t
) 8 * (grub_be_to_cpu16 (iph
->frags
) & OFFSET_MASK
)
565 grub_netbuff_free (nb_top
);
568 copy
= nb_top
->tail
- nb_top
->data
;
569 if (rsm
->total_len
- 8 * (grub_be_to_cpu16 (iph
->frags
) & OFFSET_MASK
)
571 copy
= rsm
->total_len
- 8 * (grub_be_to_cpu16 (iph
->frags
)
573 grub_memcpy (&rsm
->asm_netbuff
->data
[8 * (grub_be_to_cpu16 (iph
->frags
)
577 if ((grub_be_to_cpu16 (iph
->frags
) & MORE_FRAGMENTS
))
579 grub_netbuff_free (nb_top
);
582 grub_netbuff_free (nb_top
);
584 ret
= rsm
->asm_netbuff
;
590 rsm
->asm_netbuff
= 0;
591 res_len
= rsm
->total_len
;
595 if (grub_netbuff_put (ret
, res_len
))
597 grub_netbuff_free (ret
);
598 return GRUB_ERR_NONE
;
601 source
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
604 dest
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
607 return handle_dgram (ret
, card
, src_hwaddress
,
608 hwaddress
, proto
, &source
, &dest
, vlantag
,
614 grub_net_send_ip6_packet (struct grub_net_network_level_interface
*inf
,
615 const grub_net_network_level_address_t
*target
,
616 const grub_net_link_level_address_t
*ll_target_addr
,
617 struct grub_net_buff
*nb
,
618 grub_net_ip_protocol_t proto
)
623 COMPILE_TIME_ASSERT (GRUB_NET_OUR_IPV6_HEADER_SIZE
== sizeof (*iph
));
625 if (nb
->tail
- nb
->data
+ sizeof (struct iphdr
) > inf
->card
->mtu
)
626 return grub_error (GRUB_ERR_NET_PACKET_TOO_BIG
, "packet too big");
628 err
= grub_netbuff_push (nb
, sizeof (*iph
));
632 iph
= (struct ip6hdr
*) nb
->data
;
633 iph
->version_class_flow
= grub_cpu_to_be32_compile_time ((6 << 28));
634 iph
->len
= grub_cpu_to_be16 (nb
->tail
- nb
->data
- sizeof (*iph
));
635 iph
->protocol
= proto
;
637 grub_memcpy (&iph
->src
, inf
->address
.ipv6
, sizeof (iph
->src
));
638 grub_memcpy (&iph
->dest
, target
->ipv6
, sizeof (iph
->dest
));
640 return send_ethernet_packet (inf
, nb
, *ll_target_addr
,
641 GRUB_NET_ETHERTYPE_IP6
);
645 grub_net_send_ip_packet (struct grub_net_network_level_interface
*inf
,
646 const grub_net_network_level_address_t
*target
,
647 const grub_net_link_level_address_t
*ll_target_addr
,
648 struct grub_net_buff
*nb
,
649 grub_net_ip_protocol_t proto
)
651 switch (target
->type
)
653 case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
:
654 return grub_net_send_ip4_packet (inf
, target
, ll_target_addr
, nb
, proto
);
655 case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
:
656 return grub_net_send_ip6_packet (inf
, target
, ll_target_addr
, nb
, proto
);
658 return grub_error (GRUB_ERR_BUG
, "not an IP");
663 grub_net_recv_ip6_packets (struct grub_net_buff
*nb
,
664 struct grub_net_card
*card
,
665 const grub_net_link_level_address_t
*hwaddress
,
666 const grub_net_link_level_address_t
*src_hwaddress
,
667 grub_uint16_t
*vlantag
)
669 struct ip6hdr
*iph
= (struct ip6hdr
*) nb
->data
;
671 grub_net_network_level_address_t source
;
672 grub_net_network_level_address_t dest
;
674 if (nb
->tail
- nb
->data
< (grub_ssize_t
) sizeof (*iph
))
676 grub_dprintf ("net", "IP packet too short: %" PRIdGRUB_SSIZE
"\n",
677 (grub_ssize_t
) (nb
->tail
- nb
->data
));
678 grub_netbuff_free (nb
);
679 return GRUB_ERR_NONE
;
682 err
= grub_netbuff_pull (nb
, sizeof (*iph
));
685 grub_netbuff_free (nb
);
691 grub_size_t expected_size
= grub_be_to_cpu16 (iph
->len
);
692 grub_size_t actual_size
= (nb
->tail
- nb
->data
);
693 if (actual_size
> expected_size
)
695 err
= grub_netbuff_unput (nb
, actual_size
- expected_size
);
698 grub_netbuff_free (nb
);
702 if (actual_size
< expected_size
)
704 grub_dprintf ("net", "Cut IP packet actual: %" PRIuGRUB_SIZE
705 ", expected %" PRIuGRUB_SIZE
"\n", actual_size
,
707 grub_netbuff_free (nb
);
708 return GRUB_ERR_NONE
;
712 source
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
;
713 dest
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
;
714 grub_memcpy (source
.ipv6
, &iph
->src
, sizeof (source
.ipv6
));
715 grub_memcpy (dest
.ipv6
, &iph
->dest
, sizeof (dest
.ipv6
));
717 return handle_dgram (nb
, card
, src_hwaddress
, hwaddress
, iph
->protocol
,
718 &source
, &dest
, vlantag
, iph
->ttl
);
722 grub_net_recv_ip_packets (struct grub_net_buff
*nb
,
723 struct grub_net_card
*card
,
724 const grub_net_link_level_address_t
*hwaddress
,
725 const grub_net_link_level_address_t
*src_hwaddress
,
726 grub_uint16_t
*vlantag
)
728 struct iphdr
*iph
= (struct iphdr
*) nb
->data
;
730 if ((iph
->verhdrlen
>> 4) == 4)
731 return grub_net_recv_ip4_packets (nb
, card
, hwaddress
, src_hwaddress
,
733 if ((iph
->verhdrlen
>> 4) == 6)
734 return grub_net_recv_ip6_packets (nb
, card
, hwaddress
, src_hwaddress
,
736 grub_dprintf ("net", "Bad IP version: %d\n", (iph
->verhdrlen
>> 4));
737 grub_netbuff_free (nb
);
738 return GRUB_ERR_NONE
;