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/>.
21 #include <grub/i18n.h>
22 #include <grub/command.h>
23 #include <grub/net/ip.h>
24 #include <grub/net/netbuff.h>
25 #include <grub/net/udp.h>
26 #include <grub/datetime.h>
29 parse_dhcp_vendor (const char *name
, const void *vend
, int limit
, int *mask
)
31 const grub_uint8_t
*ptr
, *ptr0
;
35 if (ptr
[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0
36 || ptr
[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1
37 || ptr
[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2
38 || ptr
[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3
)
40 ptr
= ptr
+ sizeof (grub_uint32_t
);
41 while (ptr
- ptr0
< limit
)
44 grub_uint8_t taglength
;
49 if (tagtype
== GRUB_NET_BOOTP_PAD
)
53 if (tagtype
== GRUB_NET_BOOTP_END
)
60 case GRUB_NET_BOOTP_NETMASK
:
64 for (i
= 0; i
< 32; i
++)
65 if (!(ptr
[i
/ 8] & (1 << (7 - (i
% 8)))))
71 case GRUB_NET_BOOTP_ROUTER
:
74 grub_net_network_level_netaddress_t target
;
75 grub_net_network_level_address_t gw
;
78 target
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
80 target
.ipv4
.masksize
= 0;
81 gw
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
82 grub_memcpy (&gw
.ipv4
, ptr
, sizeof (gw
.ipv4
));
83 rname
= grub_xasprintf ("%s:default", name
);
85 grub_net_add_route_gw (rname
, target
, gw
, NULL
);
89 case GRUB_NET_BOOTP_DNS
:
92 for (i
= 0; i
< taglength
/ 4; i
++)
94 struct grub_net_network_level_address s
;
95 s
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
96 s
.ipv4
= grub_get_unaligned32 (ptr
);
97 s
.option
= DNS_OPTION_PREFER_IPV4
;
98 grub_net_add_dns_server (&s
);
103 case GRUB_NET_BOOTP_HOSTNAME
:
104 grub_env_set_net_property (name
, "hostname", (const char *) ptr
,
108 case GRUB_NET_BOOTP_DOMAIN
:
109 grub_env_set_net_property (name
, "domain", (const char *) ptr
,
113 case GRUB_NET_BOOTP_ROOT_PATH
:
114 grub_env_set_net_property (name
, "rootpath", (const char *) ptr
,
118 case GRUB_NET_BOOTP_EXTENSIONS_PATH
:
119 grub_env_set_net_property (name
, "extensionspath", (const char *) ptr
,
123 /* If you need any other options please contact GRUB
131 #define OFFSET_OF(x, y) ((grub_size_t)((grub_uint8_t *)((y)->x) - (grub_uint8_t *)(y)))
133 struct grub_net_network_level_interface
*
134 grub_net_configure_by_dhcp_ack (const char *name
,
135 struct grub_net_card
*card
,
136 grub_net_interface_flags_t flags
,
137 const struct grub_net_bootp_packet
*bp
,
139 int is_def
, char **device
, char **path
)
141 grub_net_network_level_address_t addr
;
142 grub_net_link_level_address_t hwaddr
;
143 struct grub_net_network_level_interface
*inter
;
145 char server_ip
[sizeof ("xxx.xxx.xxx.xxx")];
147 addr
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
148 addr
.ipv4
= bp
->your_ip
;
155 grub_memcpy (hwaddr
.mac
, bp
->mac_addr
,
156 bp
->hw_len
< sizeof (hwaddr
.mac
) ? bp
->hw_len
157 : sizeof (hwaddr
.mac
));
158 hwaddr
.type
= GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
;
160 inter
= grub_net_add_addr (name
, card
, &addr
, &hwaddr
, flags
);
165 /* This is likely based on misunderstanding. gateway_ip refers to
166 address of BOOTP relay and should not be used after BOOTP transaction
168 See RFC1542, 3.4 Interpretation of the 'giaddr' field
172 grub_net_network_level_netaddress_t target
;
173 grub_net_network_level_address_t gw
;
176 target
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
177 target
.ipv4
.base
= bp
->server_ip
;
178 target
.ipv4
.masksize
= 32;
179 gw
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
180 gw
.ipv4
= bp
->gateway_ip
;
181 rname
= grub_xasprintf ("%s:gw", name
);
183 grub_net_add_route_gw (rname
, target
, gw
);
186 target
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
187 target
.ipv4
.base
= bp
->gateway_ip
;
188 target
.ipv4
.masksize
= 32;
189 grub_net_add_route (name
, target
, inter
);
193 if (size
> OFFSET_OF (boot_file
, bp
))
194 grub_env_set_net_property (name
, "boot_file", bp
->boot_file
,
195 sizeof (bp
->boot_file
));
198 grub_snprintf (server_ip
, sizeof (server_ip
), "%d.%d.%d.%d",
199 ((grub_uint8_t
*) &bp
->server_ip
)[0],
200 ((grub_uint8_t
*) &bp
->server_ip
)[1],
201 ((grub_uint8_t
*) &bp
->server_ip
)[2],
202 ((grub_uint8_t
*) &bp
->server_ip
)[3]);
203 grub_env_set_net_property (name
, "next_server", server_ip
, sizeof (server_ip
));
208 grub_net_default_server
= 0;
209 if (is_def
&& !grub_net_default_server
&& bp
->server_ip
)
211 grub_net_default_server
= grub_strdup (server_ip
);
217 grub_env_set ("net_default_interface", name
);
218 grub_env_export ("net_default_interface");
221 if (device
&& !*device
&& bp
->server_ip
)
223 *device
= grub_xasprintf ("tftp,%s", server_ip
);
226 if (size
> OFFSET_OF (server_name
, bp
)
227 && bp
->server_name
[0])
229 grub_env_set_net_property (name
, "dhcp_server_name", bp
->server_name
,
230 sizeof (bp
->server_name
));
231 if (is_def
&& !grub_net_default_server
)
233 grub_net_default_server
= grub_strdup (bp
->server_name
);
236 if (device
&& !*device
)
238 *device
= grub_xasprintf ("tftp,%s", bp
->server_name
);
243 if (size
> OFFSET_OF (boot_file
, bp
) && path
)
245 *path
= grub_strndup (bp
->boot_file
, sizeof (bp
->boot_file
));
250 slash
= grub_strrchr (*path
, '/');
257 if (size
> OFFSET_OF (vendor
, bp
))
258 parse_dhcp_vendor (name
, &bp
->vendor
, size
- OFFSET_OF (vendor
, bp
), &mask
);
259 grub_net_add_ipv4_local (inter
, mask
);
261 inter
->dhcp_ack
= grub_malloc (size
);
264 grub_memcpy (inter
->dhcp_ack
, bp
, size
);
265 inter
->dhcp_acklen
= size
;
268 grub_errno
= GRUB_ERR_NONE
;
274 grub_net_process_dhcp (struct grub_net_buff
*nb
,
275 struct grub_net_card
*card
)
278 struct grub_net_network_level_interface
*inf
;
280 name
= grub_xasprintf ("%s:dhcp", card
->name
);
286 grub_net_configure_by_dhcp_ack (name
, card
,
287 0, (const struct grub_net_bootp_packet
*) nb
->data
,
288 (nb
->tail
- nb
->data
), 0, 0, 0);
294 FOR_NET_NETWORK_LEVEL_INTERFACES(inf
)
295 if (grub_memcmp (inf
->name
, card
->name
, grub_strlen (card
->name
)) == 0
296 && grub_memcmp (inf
->name
+ grub_strlen (card
->name
),
297 ":dhcp_tmp", sizeof (":dhcp_tmp") - 1) == 0)
299 grub_net_network_level_interface_unregister (inf
);
306 hexdigit (grub_uint8_t val
)
310 return val
+ 'a' - 10;
314 grub_cmd_dhcpopt (struct grub_command
*cmd
__attribute__ ((unused
)),
315 int argc
, char **args
)
317 struct grub_net_network_level_interface
*inter
;
320 grub_uint8_t taglength
;
323 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
324 N_("four arguments expected"));
326 FOR_NET_NETWORK_LEVEL_INTERFACES (inter
)
327 if (grub_strcmp (inter
->name
, args
[1]) == 0)
331 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
332 N_("unrecognised network interface `%s'"), args
[1]);
334 if (!inter
->dhcp_ack
)
335 return grub_error (GRUB_ERR_IO
, N_("no DHCP info found"));
337 if (inter
->dhcp_acklen
<= OFFSET_OF (vendor
, inter
->dhcp_ack
))
338 return grub_error (GRUB_ERR_IO
, N_("no DHCP options found"));
340 num
= grub_strtoul (args
[2], 0, 0);
344 ptr
= inter
->dhcp_ack
->vendor
;
346 if (ptr
[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0
347 || ptr
[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1
348 || ptr
[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2
349 || ptr
[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3
)
350 return grub_error (GRUB_ERR_IO
, N_("no DHCP options found"));
351 ptr
= ptr
+ sizeof (grub_uint32_t
);
354 grub_uint8_t tagtype
;
356 if (ptr
>= ((grub_uint8_t
*) inter
->dhcp_ack
) + inter
->dhcp_acklen
)
357 return grub_error (GRUB_ERR_IO
, N_("no DHCP option %d found"), num
);
367 return grub_error (GRUB_ERR_IO
, N_("no DHCP option %d found"), num
);
376 if (grub_strcmp (args
[3], "string") == 0)
378 grub_err_t err
= GRUB_ERR_NONE
;
379 char *val
= grub_malloc (taglength
+ 1);
382 grub_memcpy (val
, ptr
, taglength
);
384 if (args
[0][0] == '-' && args
[0][1] == 0)
385 grub_printf ("%s\n", val
);
387 err
= grub_env_set (args
[0], val
);
392 if (grub_strcmp (args
[3], "number") == 0)
394 grub_uint64_t val
= 0;
396 for (i
= 0; i
< taglength
; i
++)
397 val
= (val
<< 8) | ptr
[i
];
398 if (args
[0][0] == '-' && args
[0][1] == 0)
399 grub_printf ("%llu\n", (unsigned long long) val
);
403 grub_snprintf (valn
, sizeof (valn
), "%lld\n", (unsigned long long) val
);
404 return grub_env_set (args
[0], valn
);
406 return GRUB_ERR_NONE
;
409 if (grub_strcmp (args
[3], "hex") == 0)
411 grub_err_t err
= GRUB_ERR_NONE
;
412 char *val
= grub_malloc (2 * taglength
+ 1);
416 for (i
= 0; i
< taglength
; i
++)
418 val
[2 * i
] = hexdigit (ptr
[i
] >> 4);
419 val
[2 * i
+ 1] = hexdigit (ptr
[i
] & 0xf);
421 val
[2 * taglength
] = 0;
422 if (args
[0][0] == '-' && args
[0][1] == 0)
423 grub_printf ("%s\n", val
);
425 err
= grub_env_set (args
[0], val
);
430 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
431 N_("unrecognised DHCP option format specification `%s'"),
435 /* FIXME: allow to specify mac address. */
437 grub_cmd_bootp (struct grub_command
*cmd
__attribute__ ((unused
)),
438 int argc
, char **args
)
440 struct grub_net_card
*card
;
441 struct grub_net_network_level_interface
*ifaces
;
442 grub_size_t ncards
= 0;
449 if (argc
> 0 && grub_strcmp (card
->name
, args
[0]) != 0)
455 return grub_error (GRUB_ERR_NET_NO_CARD
, N_("no network card found"));
457 ifaces
= grub_zalloc (ncards
* sizeof (ifaces
[0]));
464 if (argc
> 0 && grub_strcmp (card
->name
, args
[0]) != 0)
466 ifaces
[j
].card
= card
;
467 ifaces
[j
].next
= &ifaces
[j
+1];
469 ifaces
[j
].prev
= &ifaces
[j
-1].next
;
470 ifaces
[j
].name
= grub_xasprintf ("%s:dhcp_tmp", card
->name
);
475 for (i
= 0; i
< j
; i
++)
476 grub_free (ifaces
[i
].name
);
480 ifaces
[j
].address
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV
;
481 grub_memcpy (&ifaces
[j
].hwaddress
, &card
->default_address
,
482 sizeof (ifaces
[j
].hwaddress
));
485 ifaces
[ncards
- 1].next
= grub_net_network_level_interfaces
;
486 if (grub_net_network_level_interfaces
)
487 grub_net_network_level_interfaces
->prev
= & ifaces
[ncards
- 1].next
;
488 grub_net_network_level_interfaces
= &ifaces
[0];
489 ifaces
[0].prev
= &grub_net_network_level_interfaces
;
490 for (interval
= 200; interval
< 10000; interval
*= 2)
493 for (j
= 0; j
< ncards
; j
++)
495 struct grub_net_bootp_packet
*pack
;
496 struct grub_datetime date
;
498 struct grub_net_buff
*nb
;
500 grub_net_network_level_address_t target
;
501 grub_net_link_level_address_t ll_target
;
505 nb
= grub_netbuff_alloc (sizeof (*pack
) + 64 + 128);
508 grub_netbuff_free (nb
);
511 err
= grub_netbuff_reserve (nb
, sizeof (*pack
) + 64 + 128);
514 grub_netbuff_free (nb
);
517 err
= grub_netbuff_push (nb
, sizeof (*pack
) + 64);
520 grub_netbuff_free (nb
);
523 pack
= (void *) nb
->data
;
525 grub_memset (pack
, 0, sizeof (*pack
) + 64);
529 err
= grub_get_datetime (&date
);
530 if (err
|| !grub_datetime2unixtime (&date
, &t
))
532 grub_errno
= GRUB_ERR_NONE
;
535 pack
->ident
= grub_cpu_to_be32 (t
);
536 pack
->seconds
= grub_cpu_to_be16 (t
);
538 grub_memcpy (&pack
->mac_addr
, &ifaces
[j
].hwaddress
.mac
, 6);
540 grub_netbuff_push (nb
, sizeof (*udph
));
542 udph
= (struct udphdr
*) nb
->data
;
543 udph
->src
= grub_cpu_to_be16_compile_time (68);
544 udph
->dst
= grub_cpu_to_be16_compile_time (67);
546 udph
->len
= grub_cpu_to_be16 (nb
->tail
- nb
->data
);
547 target
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
548 target
.ipv4
= 0xffffffff;
549 err
= grub_net_link_layer_resolve (&ifaces
[j
], &target
, &ll_target
);
553 udph
->chksum
= grub_net_ip_transport_checksum (nb
, GRUB_NET_IP_UDP
,
557 err
= grub_net_send_ip_packet (&ifaces
[j
], &target
, &ll_target
, nb
,
559 grub_netbuff_free (nb
);
565 grub_net_poll_cards (interval
, 0);
569 for (j
= 0; j
< ncards
; j
++)
571 grub_free (ifaces
[j
].name
);
575 grub_net_network_level_interface_unregister (&ifaces
[j
]);
576 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
,
577 N_("couldn't autoconfigure %s"),
578 ifaces
[j
].card
->name
);
585 static grub_command_t cmd_getdhcp
, cmd_bootp
;
588 grub_bootp_init (void)
590 cmd_bootp
= grub_register_command ("net_bootp", grub_cmd_bootp
,
592 N_("perform a bootp autoconfiguration"));
593 cmd_getdhcp
= grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt
,
594 N_("VAR INTERFACE NUMBER DESCRIPTION"),
595 N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value."));
599 grub_bootp_fini (void)
601 grub_unregister_command (cmd_getdhcp
);
602 grub_unregister_command (cmd_bootp
);