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 target
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
194 target
.ipv4
.base
= bp
->gateway_ip
;
195 target
.ipv4
.masksize
= 32;
196 grub_net_add_route (name
, target
, inter
);
199 if (size
> OFFSET_OF (boot_file
, bp
))
200 set_env_limn_ro (name
, "boot_file", (char *) bp
->boot_file
,
201 sizeof (bp
->boot_file
));
203 grub_net_default_server
= 0;
204 if (is_def
&& !grub_net_default_server
&& bp
->server_ip
)
206 grub_net_default_server
= grub_xasprintf ("%d.%d.%d.%d",
207 ((grub_uint8_t
*) &bp
->server_ip
)[0],
208 ((grub_uint8_t
*) &bp
->server_ip
)[1],
209 ((grub_uint8_t
*) &bp
->server_ip
)[2],
210 ((grub_uint8_t
*) &bp
->server_ip
)[3]);
214 if (device
&& !*device
&& bp
->server_ip
)
216 *device
= grub_xasprintf ("tftp,%d.%d.%d.%d",
217 ((grub_uint8_t
*) &bp
->server_ip
)[0],
218 ((grub_uint8_t
*) &bp
->server_ip
)[1],
219 ((grub_uint8_t
*) &bp
->server_ip
)[2],
220 ((grub_uint8_t
*) &bp
->server_ip
)[3]);
223 if (size
> OFFSET_OF (server_name
, bp
)
224 && bp
->server_name
[0])
226 set_env_limn_ro (name
, "dhcp_server_name", (char *) bp
->server_name
,
227 sizeof (bp
->server_name
));
228 if (is_def
&& !grub_net_default_server
)
230 grub_net_default_server
= grub_strdup (bp
->server_name
);
233 if (device
&& !*device
)
235 *device
= grub_xasprintf ("tftp,%s", bp
->server_name
);
240 if (size
> OFFSET_OF (boot_file
, bp
) && path
)
242 *path
= grub_strndup (bp
->boot_file
, sizeof (bp
->boot_file
));
247 slash
= grub_strrchr (*path
, '/');
254 if (size
> OFFSET_OF (vendor
, bp
))
255 parse_dhcp_vendor (name
, &bp
->vendor
, size
- OFFSET_OF (vendor
, bp
), &mask
);
256 grub_net_add_ipv4_local (inter
, mask
);
258 inter
->dhcp_ack
= grub_malloc (size
);
261 grub_memcpy (inter
->dhcp_ack
, bp
, size
);
262 inter
->dhcp_acklen
= size
;
265 grub_errno
= GRUB_ERR_NONE
;
271 grub_net_process_dhcp (struct grub_net_buff
*nb
,
272 struct grub_net_card
*card
)
275 struct grub_net_network_level_interface
*inf
;
277 name
= grub_xasprintf ("%s:dhcp", card
->name
);
283 grub_net_configure_by_dhcp_ack (name
, card
,
284 0, (const struct grub_net_bootp_packet
*) nb
->data
,
285 (nb
->tail
- nb
->data
), 0, 0, 0);
291 FOR_NET_NETWORK_LEVEL_INTERFACES(inf
)
292 if (grub_memcmp (inf
->name
, card
->name
, grub_strlen (card
->name
)) == 0
293 && grub_memcmp (inf
->name
+ grub_strlen (card
->name
),
294 ":dhcp_tmp", sizeof (":dhcp_tmp") - 1) == 0)
296 grub_net_network_level_interface_unregister (inf
);
303 hexdigit (grub_uint8_t val
)
307 return val
+ 'a' - 10;
311 grub_cmd_dhcpopt (struct grub_command
*cmd
__attribute__ ((unused
)),
312 int argc
, char **args
)
314 struct grub_net_network_level_interface
*inter
;
317 grub_uint8_t taglength
;
320 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
321 N_("four arguments expected"));
323 FOR_NET_NETWORK_LEVEL_INTERFACES (inter
)
324 if (grub_strcmp (inter
->name
, args
[1]) == 0)
328 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
329 N_("unrecognised network interface `%s'"), args
[1]);
331 if (!inter
->dhcp_ack
)
332 return grub_error (GRUB_ERR_IO
, N_("no DHCP info found"));
334 if (inter
->dhcp_acklen
<= OFFSET_OF (vendor
, inter
->dhcp_ack
))
335 return grub_error (GRUB_ERR_IO
, N_("no DHCP options found"));
337 num
= grub_strtoul (args
[2], 0, 0);
341 ptr
= inter
->dhcp_ack
->vendor
;
343 if (ptr
[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0
344 || ptr
[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1
345 || ptr
[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2
346 || ptr
[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3
)
347 return grub_error (GRUB_ERR_IO
, N_("no DHCP options found"));
348 ptr
= ptr
+ sizeof (grub_uint32_t
);
351 grub_uint8_t tagtype
;
353 if (ptr
>= ((grub_uint8_t
*) inter
->dhcp_ack
) + inter
->dhcp_acklen
)
354 return grub_error (GRUB_ERR_IO
, N_("no DHCP option %d found"), num
);
364 return grub_error (GRUB_ERR_IO
, N_("no DHCP option %d found"), num
);
373 if (grub_strcmp (args
[3], "string") == 0)
375 char *val
= grub_malloc (taglength
+ 1);
378 grub_memcpy (val
, ptr
, taglength
);
380 if (args
[0][0] == '-' && args
[0][1] == 0)
381 grub_printf ("%s\n", val
);
383 return grub_env_set (args
[0], val
);
384 return GRUB_ERR_NONE
;
387 if (grub_strcmp (args
[3], "number") == 0)
389 grub_uint64_t val
= 0;
391 for (i
= 0; i
< taglength
; i
++)
392 val
= (val
<< 8) | ptr
[i
];
393 if (args
[0][0] == '-' && args
[0][1] == 0)
394 grub_printf ("%llu\n", (unsigned long long) val
);
398 grub_printf (valn
, sizeof (valn
), "%lld\n", (unsigned long long) val
);
399 return grub_env_set (args
[0], valn
);
401 return GRUB_ERR_NONE
;
404 if (grub_strcmp (args
[3], "hex") == 0)
406 char *val
= grub_malloc (2 * taglength
+ 1);
410 for (i
= 0; i
< taglength
; i
++)
412 val
[2 * i
] = hexdigit (ptr
[i
] >> 4);
413 val
[2 * i
+ 1] = hexdigit (ptr
[i
] & 0xf);
415 val
[2 * taglength
] = 0;
416 if (args
[0][0] == '-' && args
[0][1] == 0)
417 grub_printf ("%s\n", val
);
419 return grub_env_set (args
[0], val
);
420 return GRUB_ERR_NONE
;
423 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
424 N_("unrecognised DHCP option format specification `%s'"),
428 /* FIXME: allow to specify mac address. */
430 grub_cmd_bootp (struct grub_command
*cmd
__attribute__ ((unused
)),
431 int argc
, char **args
)
433 struct grub_net_card
*card
;
434 struct grub_net_network_level_interface
*ifaces
;
435 grub_size_t ncards
= 0;
442 if (argc
> 0 && grub_strcmp (card
->name
, args
[0]) != 0)
447 ifaces
= grub_zalloc (ncards
* sizeof (ifaces
[0]));
454 if (argc
> 0 && grub_strcmp (card
->name
, args
[0]) != 0)
456 ifaces
[j
].card
= card
;
457 ifaces
[j
].next
= &ifaces
[j
+1];
459 ifaces
[j
].prev
= &ifaces
[j
-1].next
;
460 ifaces
[j
].name
= grub_xasprintf ("%s:dhcp_tmp", card
->name
);
465 for (i
= 0; i
< j
; i
++)
466 grub_free (ifaces
[i
].name
);
470 ifaces
[j
].address
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV
;
471 grub_memcpy (&ifaces
[j
].hwaddress
, &card
->default_address
,
472 sizeof (ifaces
[j
].hwaddress
));
475 ifaces
[ncards
- 1].next
= grub_net_network_level_interfaces
;
476 if (grub_net_network_level_interfaces
)
477 grub_net_network_level_interfaces
->prev
= & ifaces
[ncards
- 1].next
;
478 grub_net_network_level_interfaces
= &ifaces
[0];
479 ifaces
[0].prev
= &grub_net_network_level_interfaces
;
480 for (interval
= 200; interval
< 10000; interval
*= 2)
483 for (j
= 0; j
< ncards
; j
++)
485 struct grub_net_bootp_packet
*pack
;
486 struct grub_datetime date
;
488 struct grub_net_buff
*nb
;
490 grub_net_network_level_address_t target
;
491 grub_net_link_level_address_t ll_target
;
495 nb
= grub_netbuff_alloc (sizeof (*pack
) + 64 + 128);
498 grub_netbuff_free (nb
);
501 err
= grub_netbuff_reserve (nb
, sizeof (*pack
) + 64 + 128);
504 grub_netbuff_free (nb
);
507 err
= grub_netbuff_push (nb
, sizeof (*pack
) + 64);
510 grub_netbuff_free (nb
);
513 pack
= (void *) nb
->data
;
515 grub_memset (pack
, 0, sizeof (*pack
) + 64);
519 err
= grub_get_datetime (&date
);
520 if (err
|| !grub_datetime2unixtime (&date
, &t
))
522 grub_errno
= GRUB_ERR_NONE
;
525 pack
->ident
= grub_cpu_to_be32 (t
);
526 pack
->seconds
= grub_cpu_to_be16 (t
);
528 grub_memcpy (&pack
->mac_addr
, &ifaces
[j
].hwaddress
.mac
, 6);
530 grub_netbuff_push (nb
, sizeof (*udph
));
532 udph
= (struct udphdr
*) nb
->data
;
533 udph
->src
= grub_cpu_to_be16 (68);
534 udph
->dst
= grub_cpu_to_be16 (67);
536 udph
->len
= grub_cpu_to_be16 (nb
->tail
- nb
->data
);
537 target
.type
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
;
538 target
.ipv4
= 0xffffffff;
539 err
= grub_net_link_layer_resolve (&ifaces
[j
], &target
, &ll_target
);
543 udph
->chksum
= grub_net_ip_transport_checksum (nb
, GRUB_NET_IP_UDP
,
547 err
= grub_net_send_ip_packet (&ifaces
[j
], &target
, &ll_target
, nb
,
549 grub_netbuff_free (nb
);
555 grub_net_poll_cards (interval
, 0);
559 for (j
= 0; j
< ncards
; j
++)
561 grub_free (ifaces
[j
].name
);
565 grub_net_network_level_interface_unregister (&ifaces
[j
]);
566 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
,
567 N_("couldn't autoconfigure %s"),
568 ifaces
[j
].card
->name
);
575 static grub_command_t cmd_getdhcp
, cmd_bootp
;
578 grub_bootp_init (void)
580 cmd_bootp
= grub_register_command ("net_bootp", grub_cmd_bootp
,
582 N_("perform a bootp autoconfiguration"));
583 cmd_getdhcp
= grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt
,
584 N_("VAR INTERFACE NUMBER DESCRIPTION"),
585 N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value."));
589 grub_bootp_fini (void)
591 grub_unregister_command (cmd_getdhcp
);
592 grub_unregister_command (cmd_bootp
);