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 grub_env_write_readonly (struct grub_env_var
*var
__attribute__ ((unused
)),
30 const char *val
__attribute__ ((unused
)))
36 set_env_limn_ro (const char *intername
, const char *suffix
,
37 char *value
, grub_size_t len
)
40 char varname
[sizeof ("net_") + grub_strlen (intername
) + sizeof ("_")
41 + grub_strlen (suffix
)];
43 grub_snprintf (varname
, sizeof (varname
), "net_%s_%s", intername
, suffix
);
44 for (ptr
= varname
; *ptr
; ptr
++)
49 grub_env_set (varname
, value
);
51 grub_register_variable_hook (varname
, 0, grub_env_write_readonly
);
55 parse_dhcp_vendor (const char *name
, void *vend
, int limit
, int *mask
)
57 grub_uint8_t
*ptr
, *ptr0
;
61 if (ptr
[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0
62 || ptr
[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1
63 || ptr
[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2
64 || ptr
[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3
)
66 ptr
= ptr
+ sizeof (grub_uint32_t
);
67 while (ptr
- ptr0
< limit
)
70 grub_uint8_t taglength
;
75 if (tagtype
== GRUB_NET_BOOTP_PAD
)
79 if (tagtype
== GRUB_NET_BOOTP_END
)
86 case GRUB_NET_BOOTP_NETMASK
:
90 for (i
= 0; i
< 32; i
++)
91 if (!(ptr
[i
/ 8] & (1 << (7 - (i
% 8)))))
97 case GRUB_NET_BOOTP_ROUTER
:
100 grub_net_network_level_netaddress_t target
;
101 grub_net_network_level_address_t gw
;
102 char rname
[grub_strlen (name
) + sizeof (":default")];
104 target
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
105 target
.ipv4
.base
= 0;
106 target
.ipv4
.masksize
= 0;
107 gw
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
108 grub_memcpy (&gw
.ipv4
, ptr
, sizeof (gw
.ipv4
));
109 grub_snprintf (rname
, sizeof (rname
), "%s:default", name
);
110 grub_net_add_route_gw (rname
, target
, gw
);
113 case GRUB_NET_BOOTP_DNS
:
116 for (i
= 0; i
< taglength
/ 4; i
++)
118 struct grub_net_network_level_address s
;
119 s
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
120 s
.ipv4
= grub_get_unaligned32 (ptr
);
121 grub_net_add_dns_server (&s
);
126 case GRUB_NET_BOOTP_HOSTNAME
:
127 set_env_limn_ro (name
, "hostname", (char *) ptr
, taglength
);
130 case GRUB_NET_BOOTP_DOMAIN
:
131 set_env_limn_ro (name
, "domain", (char *) ptr
, taglength
);
134 case GRUB_NET_BOOTP_ROOT_PATH
:
135 set_env_limn_ro (name
, "rootpath", (char *) ptr
, taglength
);
138 case GRUB_NET_BOOTP_EXTENSIONS_PATH
:
139 set_env_limn_ro (name
, "extensionspath", (char *) ptr
, taglength
);
142 /* If you need any other options please contact GRUB
143 developpement team. */
150 #define OFFSET_OF(x, y) ((grub_uint8_t *)((y)->x) - (grub_uint8_t *)(y))
152 struct grub_net_network_level_interface
*
153 grub_net_configure_by_dhcp_ack (const char *name
,
154 struct grub_net_card
*card
,
155 grub_net_interface_flags_t flags
,
156 const struct grub_net_bootp_packet
*bp
,
158 int is_def
, char **device
, char **path
)
160 grub_net_network_level_address_t addr
;
161 grub_net_link_level_address_t hwaddr
;
162 struct grub_net_network_level_interface
*inter
;
165 addr
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
166 addr
.ipv4
= bp
->your_ip
;
173 grub_memcpy (hwaddr
.mac
, bp
->mac_addr
,
174 bp
->hw_len
< sizeof (hwaddr
.mac
) ? bp
->hw_len
175 : sizeof (hwaddr
.mac
));
176 hwaddr
.type
= GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
;
178 inter
= grub_net_add_addr (name
, card
, &addr
, &hwaddr
, flags
);
181 grub_net_network_level_netaddress_t target
;
182 grub_net_network_level_address_t gw
;
183 char rname
[grub_strlen (name
) + sizeof (":gw")];
185 target
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
186 target
.ipv4
.base
= bp
->server_ip
;
187 target
.ipv4
.masksize
= 32;
188 gw
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
189 gw
.ipv4
= bp
->gateway_ip
;
190 grub_snprintf (rname
, sizeof (rname
), "%s:gw", name
);
191 grub_net_add_route_gw (rname
, target
, gw
);
193 if (bp
->gateway_ip
|| bp
->server_ip
)
195 grub_net_network_level_netaddress_t target
;
196 target
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
197 target
.ipv4
.base
= bp
->gateway_ip
? bp
->gateway_ip
: bp
->server_ip
;
198 target
.ipv4
.masksize
= 32;
199 grub_net_add_route (name
, target
, inter
);
202 if (size
> OFFSET_OF (boot_file
, bp
))
203 set_env_limn_ro (name
, "boot_file", (char *) bp
->boot_file
,
204 sizeof (bp
->boot_file
));
206 grub_net_default_server
= 0;
207 if (size
> OFFSET_OF (server_name
, bp
)
208 && bp
->server_name
[0])
210 set_env_limn_ro (name
, "dhcp_server_name", (char *) bp
->server_name
,
211 sizeof (bp
->server_name
));
212 if (is_def
&& !grub_net_default_server
)
214 grub_net_default_server
= grub_strdup (bp
->server_name
);
217 if (device
&& !*device
)
219 *device
= grub_xasprintf ("tftp,%s", bp
->server_name
);
223 if (is_def
&& !grub_net_default_server
)
225 grub_net_default_server
= grub_xasprintf ("%d.%d.%d.%d",
226 ((grub_uint8_t
*) &bp
->server_ip
)[0],
227 ((grub_uint8_t
*) &bp
->server_ip
)[1],
228 ((grub_uint8_t
*) &bp
->server_ip
)[2],
229 ((grub_uint8_t
*) &bp
->server_ip
)[3]);
233 if (device
&& !*device
)
235 *device
= grub_xasprintf ("tftp,%d.%d.%d.%d",
236 ((grub_uint8_t
*) &bp
->server_ip
)[0],
237 ((grub_uint8_t
*) &bp
->server_ip
)[1],
238 ((grub_uint8_t
*) &bp
->server_ip
)[2],
239 ((grub_uint8_t
*) &bp
->server_ip
)[3]);
242 if (size
> OFFSET_OF (boot_file
, bp
) && path
)
244 *path
= grub_strndup (bp
->boot_file
, sizeof (bp
->boot_file
));
249 slash
= grub_strrchr (*path
, '/');
256 if (size
> OFFSET_OF (vendor
, bp
))
257 parse_dhcp_vendor (name
, &bp
->vendor
, size
- OFFSET_OF (vendor
, bp
), &mask
);
258 grub_net_add_ipv4_local (inter
, mask
);
260 inter
->dhcp_ack
= grub_malloc (size
);
263 grub_memcpy (inter
->dhcp_ack
, bp
, size
);
264 inter
->dhcp_acklen
= size
;
267 grub_errno
= GRUB_ERR_NONE
;
273 grub_net_process_dhcp (struct grub_net_buff
*nb
,
274 struct grub_net_card
*card
)
277 struct grub_net_network_level_interface
*inf
;
279 name
= grub_xasprintf ("%s:dhcp", card
->name
);
285 grub_net_configure_by_dhcp_ack (name
, card
,
286 0, (const struct grub_net_bootp_packet
*) nb
->data
,
287 (nb
->tail
- nb
->data
), 0, 0, 0);
293 FOR_NET_NETWORK_LEVEL_INTERFACES(inf
)
294 if (grub_memcmp (inf
->name
, card
->name
, grub_strlen (card
->name
)) == 0
295 && grub_memcmp (inf
->name
+ grub_strlen (card
->name
),
296 ":dhcp_tmp", sizeof (":dhcp_tmp") - 1) == 0)
298 grub_net_network_level_interface_unregister (inf
);
305 hexdigit (grub_uint8_t val
)
309 return val
+ 'a' - 10;
313 grub_cmd_dhcpopt (struct grub_command
*cmd
__attribute__ ((unused
)),
314 int argc
, char **args
)
316 struct grub_net_network_level_interface
*inter
;
319 grub_uint8_t taglength
;
322 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
323 N_("four arguments expected"));
325 FOR_NET_NETWORK_LEVEL_INTERFACES (inter
)
326 if (grub_strcmp (inter
->name
, args
[1]) == 0)
330 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
331 N_("unrecognised network interface `%s'"), args
[1]);
333 if (!inter
->dhcp_ack
)
334 return grub_error (GRUB_ERR_IO
, N_("no DHCP info found"));
336 if (inter
->dhcp_acklen
<= OFFSET_OF (vendor
, inter
->dhcp_ack
))
337 return grub_error (GRUB_ERR_IO
, N_("no DHCP options found"));
339 num
= grub_strtoul (args
[2], 0, 0);
343 ptr
= inter
->dhcp_ack
->vendor
;
345 if (ptr
[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0
346 || ptr
[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1
347 || ptr
[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2
348 || ptr
[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3
)
349 return grub_error (GRUB_ERR_IO
, N_("no DHCP options found"));
350 ptr
= ptr
+ sizeof (grub_uint32_t
);
353 grub_uint8_t tagtype
;
355 if (ptr
>= ((grub_uint8_t
*) inter
->dhcp_ack
) + inter
->dhcp_acklen
)
356 return grub_error (GRUB_ERR_IO
, N_("no DHCP option %d found"), num
);
366 return grub_error (GRUB_ERR_IO
, N_("no DHCP option %d found"), num
);
375 if (grub_strcmp (args
[3], "string") == 0)
377 char *val
= grub_malloc (taglength
+ 1);
380 grub_memcpy (val
, ptr
, taglength
);
382 if (args
[0][0] == '-' && args
[0][1] == 0)
383 grub_printf ("%s\n", val
);
385 return grub_env_set (args
[0], val
);
386 return GRUB_ERR_NONE
;
389 if (grub_strcmp (args
[3], "number") == 0)
391 grub_uint64_t val
= 0;
393 for (i
= 0; i
< taglength
; i
++)
394 val
= (val
<< 8) | ptr
[i
];
395 if (args
[0][0] == '-' && args
[0][1] == 0)
396 grub_printf ("%llu\n", (unsigned long long) val
);
400 grub_printf (valn
, sizeof (valn
), "%lld\n", (unsigned long long) val
);
401 return grub_env_set (args
[0], valn
);
403 return GRUB_ERR_NONE
;
406 if (grub_strcmp (args
[3], "hex") == 0)
408 char *val
= grub_malloc (2 * taglength
+ 1);
412 for (i
= 0; i
< taglength
; i
++)
414 val
[2 * i
] = hexdigit (ptr
[i
] >> 4);
415 val
[2 * i
+ 1] = hexdigit (ptr
[i
] & 0xf);
417 val
[2 * taglength
] = 0;
418 if (args
[0][0] == '-' && args
[0][1] == 0)
419 grub_printf ("%s\n", val
);
421 return grub_env_set (args
[0], val
);
422 return GRUB_ERR_NONE
;
425 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
426 N_("unrecognised DHCP option format specification `%s'"),
430 /* FIXME: allow to specify mac address. */
432 grub_cmd_bootp (struct grub_command
*cmd
__attribute__ ((unused
)),
433 int argc
, char **args
)
435 struct grub_net_card
*card
;
436 struct grub_net_network_level_interface
*ifaces
;
437 grub_size_t ncards
= 0;
444 if (argc
> 0 && grub_strcmp (card
->name
, args
[0]) != 0)
449 ifaces
= grub_zalloc (ncards
* sizeof (ifaces
[0]));
456 if (argc
> 0 && grub_strcmp (card
->name
, args
[0]) != 0)
458 ifaces
[j
].card
= card
;
459 ifaces
[j
].next
= &ifaces
[j
+1];
461 ifaces
[j
].prev
= &ifaces
[j
-1].next
;
462 ifaces
[j
].name
= grub_xasprintf ("%s:dhcp_tmp", card
->name
);
467 for (i
= 0; i
< j
; i
++)
468 grub_free (ifaces
[i
].name
);
472 ifaces
[j
].address
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV
;
473 grub_memcpy (&ifaces
[j
].hwaddress
, &card
->default_address
,
474 sizeof (ifaces
[j
].hwaddress
));
477 ifaces
[ncards
- 1].next
= grub_net_network_level_interfaces
;
478 if (grub_net_network_level_interfaces
)
479 grub_net_network_level_interfaces
->prev
= & ifaces
[ncards
- 1].next
;
480 grub_net_network_level_interfaces
= &ifaces
[0];
481 ifaces
[0].prev
= &grub_net_network_level_interfaces
;
482 for (interval
= 200; interval
< 10000; interval
*= 2)
485 for (j
= 0; j
< ncards
; j
++)
487 struct grub_net_bootp_packet
*pack
;
488 struct grub_datetime date
;
490 struct grub_net_buff
*nb
;
492 grub_net_network_level_address_t target
;
493 grub_net_link_level_address_t ll_target
;
497 nb
= grub_netbuff_alloc (sizeof (*pack
));
500 grub_netbuff_free (nb
);
503 err
= grub_netbuff_reserve (nb
, sizeof (*pack
) + 64 + 128);
506 grub_netbuff_free (nb
);
509 err
= grub_netbuff_push (nb
, sizeof (*pack
) + 64);
512 grub_netbuff_free (nb
);
515 pack
= (void *) nb
->data
;
517 grub_memset (pack
, 0, sizeof (*pack
) + 64);
521 err
= grub_get_datetime (&date
);
522 if (err
|| !grub_datetime2unixtime (&date
, &t
))
524 grub_errno
= GRUB_ERR_NONE
;
527 pack
->ident
= grub_cpu_to_be32 (t
);
528 pack
->seconds
= grub_cpu_to_be16 (t
);
530 grub_memcpy (&pack
->mac_addr
, &ifaces
[j
].hwaddress
.mac
, 6);
532 grub_netbuff_push (nb
, sizeof (*udph
));
534 udph
= (struct udphdr
*) nb
->data
;
535 udph
->src
= grub_cpu_to_be16 (68);
536 udph
->dst
= grub_cpu_to_be16 (67);
538 udph
->len
= grub_cpu_to_be16 (nb
->tail
- nb
->data
);
539 target
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
540 target
.ipv4
= 0xffffffff;
541 err
= grub_net_link_layer_resolve (&ifaces
[j
], &target
, &ll_target
);
545 udph
->chksum
= grub_net_ip_transport_checksum (nb
, GRUB_NET_IP_UDP
,
549 err
= grub_net_send_ip_packet (&ifaces
[j
], &target
, &ll_target
, nb
,
551 grub_netbuff_free (nb
);
557 grub_net_poll_cards (interval
, 0);
561 for (j
= 0; j
< ncards
; j
++)
563 grub_free (ifaces
[j
].name
);
567 grub_net_network_level_interface_unregister (&ifaces
[j
]);
568 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
,
569 N_("couldn't autoconfigure %s"),
570 ifaces
[j
].card
->name
);
577 static grub_command_t cmd_getdhcp
, cmd_bootp
;
580 grub_bootp_init (void)
582 cmd_bootp
= grub_register_command ("net_bootp", grub_cmd_bootp
,
584 N_("perform a bootp autoconfiguration"));
585 cmd_getdhcp
= grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt
,
586 N_("VAR INTERFACE NUMBER DESCRIPTION"),
587 N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value."));
591 grub_bootp_fini (void)
593 grub_unregister_command (cmd_getdhcp
);
594 grub_unregister_command (cmd_bootp
);