Unify sparc init with other ieee1275.

* grub-core/Makefile.core.def (kernel): Use kern/ieee1275/init.c
	instead of kern/sparc64/ieee1275/init.c.
	* grub-core/kern/ieee1275/cmain.c (grub_ieee1275_find_options)
	[__sparc__]: Set GRUB_IEEE1275_FLAG_NO_PARTITION_0.
	* grub-core/kern/ieee1275/init.c [__sparc__]: Include
	grub/machine/kernel.h.
	(grub_ieee1275_original_stack) [__sparc__]: New variable.
	(grub_claim_heap) [__sparc__]: Use sparc version.
	(grub_machine_init): Moved args parsing to
	(grub_parse_cmdline): ...this.
	* grub-core/kern/sparc64/ieee1275/init.c: Removed.
	* include/grub/offsets.h (GRUB_KERNEL_SPARC64_IEEE1275_MOD_GAP):
	New definition.
	(GRUB_KERNEL_SPARC64_IEEE1275_MOD_ALIGN): Likewise.

	Move BOOTP to separate file.

	* grub-core/Makefile.core.def (net): Add net/bootp.c.
	* grub-core/net/net.c: Move all BOOTP functions to
	* grub-core/net/bootp.c: ... here.

	Use frame interface on PXE.

	* grub-core/Makefile.core.def (pxecmd): Removed.
	(pxe): Use net/drivers/i386/pc/pxe.c rather than net/i386/pc/pxe.c.
	* grub-core/commands/i386/pc/pxecmd.c: Removed.
	* grub-core/i386/pc/pxe.c: Moved from here ...
	* grub-core/net/i386/pc/pxe.c: ... here. Rewritten.
	* grub-core/net/net.c (grub_net_open_real): Handle old pxe syntax.
	* include/grub/i386/pc/pxe.h (grub_pxe_unload): Removed.

	EFI network support.

	* grub-core/Makefile.core.def (efinet): New module.
	* grub-core/disk/efi/efidisk.c (compare_device_paths): Moved from
	here...
	* grub-core/kern/efi/efi.c (grub_efi_compare_device_paths): ... here.
	All users updated.
	* grub-core/kern/efi/init.c (grub_efi_net_config): New variable.
	(grub_machine_get_bootlocation): Call grub_efi_net_config if needed.
	* grub-core/kern/x86_64/efi/callwrap.S (efi_wrap_7): New function.
	* grub-core/net/drivers/efi/efinet.c: New file.
	* include/grub/efi/efi.h (grub_efi_compare_device_paths): New proto.
	(grub_efi_net_config): New extern var.

	Various cleanups and bugfixes.

	* grub-core/disk/efi/efidisk.c (grub_efidisk_open): Fix off-by-one
	error.
	(grub_efidisk_get_device_name): Unify similar codepaths. Accept whole
	disk declared as partition.
	* grub-core/disk/ieee1275/ofdisk.c (grub_ofdisk_open): Fix memory
	leak on failure.
	* grub-core/kern/dl.c (grub_dl_load_file): Fix memory leak.
	* grub-core/kern/mm.c (grub_debug_malloc): Don't use unsupported %zx.
	(grub_debug_zalloc): Likewise.
	(grub_debug_realloc): Likewise.
	(grub_debug_memalign): Likewise.
	* grub-core/net/arp.c (grub_net_arp_receive): IPv4 is 4-byte wide.
	Check that target is IPv4.
	* grub-core/net/drivers/ieee1275/ofnet.c (grub_ofnet_findcards): Use
	local-mac-address as fallback.
	* grub-core/net/ethernet.c (grub_net_recv_ethernet_packet): Prevent
	memory leak.
	* grub-core/net/ip.c (ipchksum): Rename to ...
	(grub_net_ip_chksum): ... this. All users updated.
	(grub_net_recv_ip_packets): Special handling for DHCP.
	* util/grub-mkimage.c (generate_image): Zero-out aout header.

	Unify prefix handling

	* grub-core/kern/efi/init.c (grub_efi_set_prefix): Revamped into ...
	(grub_machine_get_bootlocation): ... this.
	* grub-core/kern/emu/main.c (grub_machine_set_prefix): Revamped into ...
	(grub_machine_get_bootlocation): ... this.
	(grub_prefix): New variable.
	(prefix): Removed.
	(root_dev): New variable.
	(dir): Likewise.
	(main): Use new variables.
	* grub-core/kern/i386/coreboot/init.c (grub_machine_set_prefix):
	Revamped into ...
	(grub_machine_get_bootlocation): ... this.
	* grub-core/kern/i386/efi/init.c (grub_machine_set_prefix): Removed.
	* grub-core/kern/i386/pc/init.c (make_install_device): Revamped into ...
	(grub_machine_get_bootlocation): ... this.
	(grub_machine_set_prefix): Removed.
	* grub-core/kern/ia64/efi/init.c (grub_machine_set_prefix): Removed.
	* grub-core/kern/ieee1275/init.c (grub_machine_set_prefix):
	Revamped into ...
	(grub_machine_get_bootlocation): ... this.
	* grub-core/kern/main.c (grub_set_root_dev): Revamped into ...
	(grub_set_prefix_and_root): ... this. All users updated.
	* grub-core/kern/mips/init.c (grub_machine_set_prefix):
	Revamped into ...
	(grub_machine_get_bootlocation): ... this.
	* include/grub/kernel.h (grub_machine_set_prefix): Removed.
	(grub_machine_get_bootlocation): New proto.
	* include/grub/i386/pc/kernel.h (grub_pc_net_config): New var.

	Less intrusive and more reliable seek on network implementation.

	* grub-core/kern/file.c (grub_file_net_seek): Removed.
	(grub_file_seek): Don't call grub_file_net_seek.
	* grub-core/net/net.c (grub_net_fs_read): Renamed to ...
	(grub_net_fs_read_real): .. this.
	(grub_net_seek_real): Use net->offset.
	(grub_net_fs_read): Seek if necessary.

	Unify IEEE1275 netwotk config with the other platforms.

	* grub-core/kern/ieee1275/init.c (grub_ieee1275_net_config):
	New variable.
	(grub_machine_get_bootlocation): Support network.
	* grub-core/kern/ieee1275/openfw.c (grub_ieee1275_parse_args):
	Support type and device parsing.
	(grub_ieee1275_get_device_type): New function.
	* grub-core/net/drivers/ieee1275/ofnet.c (grub_getbootp_real): Revamped
	into ...
	(grub_ieee1275_net_config_real): ... this.
	(grub_ofnet_probecards): Removed.
	* grub-core/Makefile.am (KERNEL_HEADER_FILES): Remove ofnet.h.
	* include/grub/ieee1275/ofnet.h: Removed.
	* include/grub/ieee1275/ieee1275.h (grub_ieee1275_net_config): NEw
	extern var.
	(grub_ieee1275_get_device_type): New function.

	Unify network device closing across platforms and make more robust.

	* grub-core/kern/ieee1275/init.c (grub_machine_fini): Don't call
	grub_grubnet_fini.
	* grub-core/net/ethernet.c (send_ethernet_packet): Open card if it isn't
	already.
	* grub-core/net/net.c (grub_net_network_level_interface_register):
	Update num_ifaces.
	(grub_net_card_unregister): Close all interfaces.
	(receive_packets): Don't poll if no iterfaces are registered.
	Open if necessary.
	(grub_net_fini_hw): New function.
	(grub_net_restore_hw): Likewise.
	(fini_hnd): New variable.
	(GRUB_MOD_INIT): Register preboot hook.
	(GRUB_MOD_FINI): Run and unregister preboot hook.

	Poll network cards when idle.

	* grub-core/kern/term.c (grub_net_poll_cards_idle): New variable.
	(grub_checkkey): Call grub_net_poll_cards_idle if it's not NULL.
	* grub-core/net/net.c (receive_packets): Save last poll time.
	(grub_net_poll_cards_idle_real): New function.
	(GRUB_MOD_INIT): Register grub_net_poll_cards_idle.
	(GRUB_MOD_FINI): Unregister grub_net_poll_cards_idle.
	* include/grub/kernel.h (grub_poll_cards_idle): New extern variable.

	Rename ofnet interfaces.

	* grub-core/net/drivers/ieee1275/ofnet.c (find_alias): New function.
	(grub_ofnet_findcards): Use ofnet_%s names.

	* util/grub-mknetdir.in: Support for EFI and IEEE1275.

	Cleanup socket opening.

	* grub-core/net/net.c (grub_net_fs_open): Rewritten.
	(grub_net_fs_close): Likewise.
	(grub_net_fs_read_real): Use eof member.
	* include/grub/net/udp.h (+grub_net_udp_open): New proto.
	(+grub_net_udp_close): New inline function.

	* include/grub/net/tftp.h: Moved to the top of ...
	* grub-core/net/tftp.c: ... here.
	* include/grub/net/ip.h: Moved mostly to the top of ...
	* grub-core/net/ip.c: ... here.
	* include/grub/net/ethernet.h: Moved mostly to the top of ...
	* grub-core/net/ethernet.c: ... here.

	* grub-core/kern/device.c (grub_device_close): Free device->net->server.

	* grub-core/commands/probe.c (grub_cmd_probe): Use protocol name for
	FS name.

	* include/grub/net/ip.h (ipv4_ini): Removed.
	(ipv4_fini): Likewise.

	* include/grub/net/ip.h (grub_net_recv_ip_packets): New proto.
	(grub_net_send_ip_packets): Likewise.
This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-07-06 20:05:26 +02:00
commit abee94edf9
53 changed files with 2820 additions and 2174 deletions

191
ChangeLog
View file

@ -1,3 +1,194 @@
2011-07-06 Vladimir Serbinenko <phcoder@gmail.com>
Unify sparc init with other ieee1275.
* grub-core/Makefile.core.def (kernel): Use kern/ieee1275/init.c
instead of kern/sparc64/ieee1275/init.c.
* grub-core/kern/ieee1275/cmain.c (grub_ieee1275_find_options)
[__sparc__]: Set GRUB_IEEE1275_FLAG_NO_PARTITION_0.
* grub-core/kern/ieee1275/init.c [__sparc__]: Include
grub/machine/kernel.h.
(grub_ieee1275_original_stack) [__sparc__]: New variable.
(grub_claim_heap) [__sparc__]: Use sparc version.
(grub_machine_init): Moved args parsing to
(grub_parse_cmdline): ...this.
* grub-core/kern/sparc64/ieee1275/init.c: Removed.
* include/grub/offsets.h (GRUB_KERNEL_SPARC64_IEEE1275_MOD_GAP):
New definition.
(GRUB_KERNEL_SPARC64_IEEE1275_MOD_ALIGN): Likewise.
Move BOOTP to separate file.
* grub-core/Makefile.core.def (net): Add net/bootp.c.
* grub-core/net/net.c: Move all BOOTP functions to
* grub-core/net/bootp.c: ... here.
Use frame interface on PXE.
* grub-core/Makefile.core.def (pxecmd): Removed.
(pxe): Use net/drivers/i386/pc/pxe.c rather than net/i386/pc/pxe.c.
* grub-core/commands/i386/pc/pxecmd.c: Removed.
* grub-core/i386/pc/pxe.c: Moved from here ...
* grub-core/net/i386/pc/pxe.c: ... here. Rewritten.
* grub-core/net/net.c (grub_net_open_real): Handle old pxe syntax.
* include/grub/i386/pc/pxe.h (grub_pxe_unload): Removed.
EFI network support.
* grub-core/Makefile.core.def (efinet): New module.
* grub-core/disk/efi/efidisk.c (compare_device_paths): Moved from
here...
* grub-core/kern/efi/efi.c (grub_efi_compare_device_paths): ... here.
All users updated.
* grub-core/kern/efi/init.c (grub_efi_net_config): New variable.
(grub_machine_get_bootlocation): Call grub_efi_net_config if needed.
* grub-core/kern/x86_64/efi/callwrap.S (efi_wrap_7): New function.
* grub-core/net/drivers/efi/efinet.c: New file.
* include/grub/efi/efi.h (grub_efi_compare_device_paths): New proto.
(grub_efi_net_config): New extern var.
Various cleanups and bugfixes.
* grub-core/disk/efi/efidisk.c (grub_efidisk_open): Fix off-by-one
error.
(grub_efidisk_get_device_name): Unify similar codepaths. Accept whole
disk declared as partition.
* grub-core/disk/ieee1275/ofdisk.c (grub_ofdisk_open): Fix memory
leak on failure.
* grub-core/kern/dl.c (grub_dl_load_file): Fix memory leak.
* grub-core/kern/mm.c (grub_debug_malloc): Don't use unsupported %zx.
(grub_debug_zalloc): Likewise.
(grub_debug_realloc): Likewise.
(grub_debug_memalign): Likewise.
* grub-core/net/arp.c (grub_net_arp_receive): IPv4 is 4-byte wide.
Check that target is IPv4.
* grub-core/net/drivers/ieee1275/ofnet.c (grub_ofnet_findcards): Use
local-mac-address as fallback.
* grub-core/net/ethernet.c (grub_net_recv_ethernet_packet): Prevent
memory leak.
* grub-core/net/ip.c (ipchksum): Rename to ...
(grub_net_ip_chksum): ... this. All users updated.
(grub_net_recv_ip_packets): Special handling for DHCP.
* util/grub-mkimage.c (generate_image): Zero-out aout header.
Unify prefix handling
* grub-core/kern/efi/init.c (grub_efi_set_prefix): Revamped into ...
(grub_machine_get_bootlocation): ... this.
* grub-core/kern/emu/main.c (grub_machine_set_prefix): Revamped into ...
(grub_machine_get_bootlocation): ... this.
(grub_prefix): New variable.
(prefix): Removed.
(root_dev): New variable.
(dir): Likewise.
(main): Use new variables.
* grub-core/kern/i386/coreboot/init.c (grub_machine_set_prefix):
Revamped into ...
(grub_machine_get_bootlocation): ... this.
* grub-core/kern/i386/efi/init.c (grub_machine_set_prefix): Removed.
* grub-core/kern/i386/pc/init.c (make_install_device): Revamped into ...
(grub_machine_get_bootlocation): ... this.
(grub_machine_set_prefix): Removed.
* grub-core/kern/ia64/efi/init.c (grub_machine_set_prefix): Removed.
* grub-core/kern/ieee1275/init.c (grub_machine_set_prefix):
Revamped into ...
(grub_machine_get_bootlocation): ... this.
* grub-core/kern/main.c (grub_set_root_dev): Revamped into ...
(grub_set_prefix_and_root): ... this. All users updated.
* grub-core/kern/mips/init.c (grub_machine_set_prefix):
Revamped into ...
(grub_machine_get_bootlocation): ... this.
* include/grub/kernel.h (grub_machine_set_prefix): Removed.
(grub_machine_get_bootlocation): New proto.
* include/grub/i386/pc/kernel.h (grub_pc_net_config): New var.
Less intrusive and more reliable seek on network implementation.
* grub-core/kern/file.c (grub_file_net_seek): Removed.
(grub_file_seek): Don't call grub_file_net_seek.
* grub-core/net/net.c (grub_net_fs_read): Renamed to ...
(grub_net_fs_read_real): .. this.
(grub_net_seek_real): Use net->offset.
(grub_net_fs_read): Seek if necessary.
Unify IEEE1275 netwotk config with the other platforms.
* grub-core/kern/ieee1275/init.c (grub_ieee1275_net_config):
New variable.
(grub_machine_get_bootlocation): Support network.
* grub-core/kern/ieee1275/openfw.c (grub_ieee1275_parse_args):
Support type and device parsing.
(grub_ieee1275_get_device_type): New function.
* grub-core/net/drivers/ieee1275/ofnet.c (grub_getbootp_real): Revamped
into ...
(grub_ieee1275_net_config_real): ... this.
(grub_ofnet_probecards): Removed.
* grub-core/Makefile.am (KERNEL_HEADER_FILES): Remove ofnet.h.
* include/grub/ieee1275/ofnet.h: Removed.
* include/grub/ieee1275/ieee1275.h (grub_ieee1275_net_config): NEw
extern var.
(grub_ieee1275_get_device_type): New function.
Unify network device closing across platforms and make more robust.
* grub-core/kern/ieee1275/init.c (grub_machine_fini): Don't call
grub_grubnet_fini.
* grub-core/net/ethernet.c (send_ethernet_packet): Open card if it isn't
already.
* grub-core/net/net.c (grub_net_network_level_interface_register):
Update num_ifaces.
(grub_net_card_unregister): Close all interfaces.
(receive_packets): Don't poll if no iterfaces are registered.
Open if necessary.
(grub_net_fini_hw): New function.
(grub_net_restore_hw): Likewise.
(fini_hnd): New variable.
(GRUB_MOD_INIT): Register preboot hook.
(GRUB_MOD_FINI): Run and unregister preboot hook.
Poll network cards when idle.
* grub-core/kern/term.c (grub_net_poll_cards_idle): New variable.
(grub_checkkey): Call grub_net_poll_cards_idle if it's not NULL.
* grub-core/net/net.c (receive_packets): Save last poll time.
(grub_net_poll_cards_idle_real): New function.
(GRUB_MOD_INIT): Register grub_net_poll_cards_idle.
(GRUB_MOD_FINI): Unregister grub_net_poll_cards_idle.
* include/grub/kernel.h (grub_poll_cards_idle): New extern variable.
Rename ofnet interfaces.
* grub-core/net/drivers/ieee1275/ofnet.c (find_alias): New function.
(grub_ofnet_findcards): Use ofnet_%s names.
* util/grub-mknetdir.in: Support for EFI and IEEE1275.
Cleanup socket opening.
* grub-core/net/net.c (grub_net_fs_open): Rewritten.
(grub_net_fs_close): Likewise.
(grub_net_fs_read_real): Use eof member.
* include/grub/net/udp.h (+grub_net_udp_open): New proto.
(+grub_net_udp_close): New inline function.
* include/grub/net/tftp.h: Moved to the top of ...
* grub-core/net/tftp.c: ... here.
* include/grub/net/ip.h: Moved mostly to the top of ...
* grub-core/net/ip.c: ... here.
* include/grub/net/ethernet.h: Moved mostly to the top of ...
* grub-core/net/ethernet.c: ... here.
* grub-core/kern/device.c (grub_device_close): Free device->net->server.
* grub-core/commands/probe.c (grub_cmd_probe): Use protocol name for
FS name.
* include/grub/net/ip.h (ipv4_ini): Removed.
(ipv4_fini): Likewise.
* include/grub/net/ip.h (grub_net_recv_ip_packets): New proto.
(grub_net_send_ip_packets): Likewise.
2011-07-05 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/kern/i386/qemu/mmap.c (grub_machine_mmap_init): Use new

View file

@ -115,7 +115,6 @@ endif
if COND_i386_ieee1275
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ofnet.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
@ -188,7 +187,6 @@ endif
if COND_powerpc_ieee1275
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ofnet.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
@ -196,7 +194,6 @@ endif
if COND_sparc64_ieee1275
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ofnet.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sparc64/ieee1275/ieee1275.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h

View file

@ -102,6 +102,7 @@ kernel = {
ieee1275 = kern/ieee1275/mmap.c;
ieee1275 = kern/ieee1275/openfw.c;
ieee1275 = term/ieee1275/ofconsole.c;
ieee1275 = kern/ieee1275/init.c;
terminfoinkernel = term/terminfo.c;
terminfoinkernel = term/tparm.c;
@ -153,8 +154,6 @@ kernel = {
i386_multiboot = kern/i386/multiboot_mmap.c;
i386_multiboot = kern/i386/tsc.c;
i386_ieee1275 = kern/ieee1275/init.c;
mips = kern/mips/cache.S;
mips = kern/mips/dl.c;
mips = kern/mips/init.c;
@ -184,14 +183,12 @@ kernel = {
extra_dist = video/sm712_init.c;
mips_loongson = commands/keylayouts.c;
powerpc_ieee1275 = kern/ieee1275/init.c;
powerpc_ieee1275 = kern/powerpc/cache.S;
powerpc_ieee1275 = kern/powerpc/dl.c;
sparc64_ieee1275 = kern/sparc64/cache.S;
sparc64_ieee1275 = kern/sparc64/dl.c;
sparc64_ieee1275 = kern/sparc64/ieee1275/ieee1275.c;
sparc64_ieee1275 = kern/sparc64/ieee1275/init.c;
emu = disk/host.c;
emu = gnulib/progname.c;
@ -722,12 +719,6 @@ module = {
common = commands/probe.c;
};
module = {
name = pxecmd;
i386_pc = commands/i386/pc/pxecmd.c;
enable = i386_pc;
};
module = {
name = read;
common = commands/read.c;
@ -1105,7 +1096,7 @@ module = {
module = {
name = pxe;
i386_pc = net/i386/pc/pxe.c;
i386_pc = net/drivers/i386/pc/pxe.c;
enable = i386_pc;
};
@ -1588,6 +1579,7 @@ module = {
module = {
name = net;
common = net/net.c;
common = net/bootp.c;
common = net/ip.c;
common = net/udp.c;
common = net/ethernet.c;
@ -1602,10 +1594,16 @@ module = {
module = {
name = ofnet;
ieee1275 = net/drivers/ieee1275/ofnet.c;
common = net/drivers/ieee1275/ofnet.c;
enable = ieee1275;
};
module = {
name = efinet;
common = net/drivers/efi/efinet.c;
enable = efi;
};
module = {
name = emunet;
emu = net/drivers/emu/emunet.c;

View file

@ -1,54 +0,0 @@
/* pxe.c - command to control the pxe driver */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/dl.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/machine/pxe.h>
#include <grub/command.h>
#include <grub/i18n.h>
GRUB_MOD_LICENSE ("GPLv3+");
static grub_err_t
grub_cmd_pxe_unload (grub_command_t cmd __attribute__ ((unused)),
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
if (! grub_pxe_pxenv)
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no pxe environment");
grub_pxe_unload ();
return 0;
}
static grub_command_t cmd;
GRUB_MOD_INIT(pxecmd)
{
cmd = grub_register_command ("pxe_unload", grub_cmd_pxe_unload,
0,
N_("Unload PXE environment."));
}
GRUB_MOD_FINI(pxecmd)
{
grub_unregister_command (cmd);
}

View file

@ -74,7 +74,7 @@ grub_cmd_probe (grub_extcmd_context_t ctxt, int argc, char **args)
{
const char *val = "none";
if (dev->net)
val = dev->net->name;
val = dev->net->protocol->name;
if (dev->disk)
val = dev->disk->dev->name;
if (state[0].set)

View file

@ -84,54 +84,6 @@ find_last_device_path (const grub_efi_device_path_t *dp)
return p;
}
/* Compare device paths. */
static int
compare_device_paths (const grub_efi_device_path_t *dp1,
const grub_efi_device_path_t *dp2)
{
if (! dp1 || ! dp2)
/* Return non-zero. */
return 1;
while (1)
{
grub_efi_uint8_t type1, type2;
grub_efi_uint8_t subtype1, subtype2;
grub_efi_uint16_t len1, len2;
int ret;
type1 = GRUB_EFI_DEVICE_PATH_TYPE (dp1);
type2 = GRUB_EFI_DEVICE_PATH_TYPE (dp2);
if (type1 != type2)
return (int) type2 - (int) type1;
subtype1 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp1);
subtype2 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp2);
if (subtype1 != subtype2)
return (int) subtype1 - (int) subtype2;
len1 = GRUB_EFI_DEVICE_PATH_LENGTH (dp1);
len2 = GRUB_EFI_DEVICE_PATH_LENGTH (dp2);
if (len1 != len2)
return (int) len1 - (int) len2;
ret = grub_memcmp (dp1, dp2, len1);
if (ret != 0)
return ret;
if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1))
break;
dp1 = (grub_efi_device_path_t *) ((char *) dp1 + len1);
dp2 = (grub_efi_device_path_t *) ((char *) dp2 + len2);
}
return 0;
}
static struct grub_efidisk_data *
make_devices (void)
{
@ -214,7 +166,7 @@ find_parent_device (struct grub_efidisk_data *devices,
if (parent == d)
continue;
if (compare_device_paths (parent->device_path, dp) == 0)
if (grub_efi_compare_device_paths (parent->device_path, dp) == 0)
{
/* Found. */
if (! parent->last_device_path)
@ -249,7 +201,7 @@ iterate_child_devices (struct grub_efidisk_data *devices,
ldp->length[0] = sizeof (*ldp);
ldp->length[1] = 0;
if (compare_device_paths (dp, d->device_path) == 0)
if (grub_efi_compare_device_paths (dp, d->device_path) == 0)
if (hook (p))
{
grub_free (dp);
@ -273,11 +225,11 @@ add_device (struct grub_efidisk_data **devices, struct grub_efidisk_data *d)
{
int ret;
ret = compare_device_paths (find_last_device_path ((*p)->device_path),
find_last_device_path (d->device_path));
ret = grub_efi_compare_device_paths (find_last_device_path ((*p)->device_path),
find_last_device_path (d->device_path));
if (ret == 0)
ret = compare_device_paths ((*p)->device_path,
d->device_path);
ret = grub_efi_compare_device_paths ((*p)->device_path,
d->device_path);
if (ret == 0)
return;
else if (ret > 0)
@ -530,7 +482,7 @@ grub_efidisk_open (const char *name, struct grub_disk *disk)
and total sectors should be replaced with total blocks. */
grub_dprintf ("efidisk", "m = %p, last block = %llx, block size = %x\n",
m, (unsigned long long) m->last_block, m->block_size);
disk->total_sectors = m->last_block;
disk->total_sectors = m->last_block + 1;
if (m->block_size & (m->block_size - 1) || !m->block_size)
return grub_error (GRUB_ERR_IO, "invalid sector size %d",
m->block_size);
@ -706,7 +658,35 @@ grub_efidisk_get_device_handle (grub_disk_t disk)
char *
grub_efidisk_get_device_name (grub_efi_handle_t *handle)
{
grub_efi_device_path_t *dp, *ldp;
grub_efi_device_path_t *dp, *ldp, *sdp;
/* This is a hard disk partition. */
grub_disk_t parent = 0;
auto int find_parent_disk (const char *name);
/* Find the disk which is the parent of a given hard disk partition. */
int find_parent_disk (const char *name)
{
grub_disk_t disk;
disk = grub_disk_open (name);
if (! disk)
return 1;
if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID)
{
struct grub_efidisk_data *d;
d = disk->data;
if (grub_efi_compare_device_paths (d->device_path, sdp) == 0)
{
parent = disk;
return 1;
}
}
grub_disk_close (disk);
return 0;
}
dp = grub_efi_get_device_path (handle);
if (! dp)
@ -720,40 +700,12 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle)
&& (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp)
== GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE))
{
/* This is a hard disk partition. */
grub_disk_t parent = 0;
grub_partition_t tpart = NULL;
char *device_name;
grub_efi_device_path_t *dup_dp, *dup_ldp;
grub_efi_hard_drive_device_path_t hd;
auto int find_parent_disk (const char *name);
auto int find_partition (grub_disk_t disk, const grub_partition_t part);
/* Find the disk which is the parent of a given hard disk partition. */
int find_parent_disk (const char *name)
{
grub_disk_t disk;
disk = grub_disk_open (name);
if (! disk)
return 1;
if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID)
{
struct grub_efidisk_data *d;
d = disk->data;
if (compare_device_paths (d->device_path, dup_dp) == 0)
{
parent = disk;
return 1;
}
}
grub_disk_close (disk);
return 0;
}
/* Find the identical partition. */
int find_partition (grub_disk_t disk __attribute__ ((unused)),
const grub_partition_t part)
@ -780,6 +732,8 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle)
dup_ldp->length[0] = sizeof (*dup_ldp);
dup_ldp->length[1] = 0;
sdp = dup_dp;
grub_efidisk_iterate (find_parent_disk);
grub_free (dup_dp);
@ -788,19 +742,27 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle)
/* Find a partition which matches the hard drive device path. */
grub_memcpy (&hd, ldp, sizeof (hd));
grub_partition_iterate (parent, find_partition);
if (! tpart)
if (hd.partition_start == 0
&& hd.partition_size == grub_disk_get_size (parent))
{
grub_disk_close (parent);
return 0;
device_name = grub_strdup (parent->name);
}
else
{
char *partition_name;
{
char *partition_name = grub_partition_get_name (tpart);
device_name = grub_xasprintf ("%s,%s", parent->name, partition_name);
grub_free (partition_name);
}
grub_partition_iterate (parent, find_partition);
if (! tpart)
{
grub_disk_close (parent);
return 0;
}
partition_name = grub_partition_get_name (tpart);
device_name = grub_xasprintf ("%s,%s", parent->name, partition_name);
grub_free (partition_name);
}
grub_disk_close (parent);
return device_name;
@ -808,36 +770,15 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle)
else
{
/* This should be an entire disk. */
auto int find_disk (const char *name);
char *device_name = 0;
int find_disk (const char *name)
{
grub_disk_t disk;
sdp = dp;
disk = grub_disk_open (name);
if (! disk)
return 1;
if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID)
{
struct grub_efidisk_data *d;
d = disk->data;
if (compare_device_paths (d->device_path, dp) == 0)
{
device_name = grub_strdup (disk->name);
grub_disk_close (disk);
return 1;
}
}
grub_disk_close (disk);
return 0;
}
grub_efidisk_iterate (find_disk);
grub_efidisk_iterate (find_parent_disk);
if (!parent)
return NULL;
device_name = grub_strdup (parent->name);
grub_disk_close (parent);
return device_name;
}

View file

@ -243,14 +243,24 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
grub_dprintf ("disk", "Opening `%s'.\n", devpath);
if (grub_ieee1275_finddevice (devpath, &dev))
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read device properties");
{
grub_free (devpath);
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
"can't read device properties");
}
if (grub_ieee1275_get_property (dev, "device_type", prop, sizeof (prop),
&actual))
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read the device type");
{
grub_free (devpath);
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read the device type");
}
if (grub_strcmp (prop, "block"))
return grub_error (GRUB_ERR_BAD_DEVICE, "not a block device");
{
grub_free (devpath);
return grub_error (GRUB_ERR_BAD_DEVICE, "not a block device");
}
/* XXX: There is no property to read the number of blocks. There
should be a property `#blocks', but it is not there. Perhaps it

View file

@ -79,7 +79,7 @@ grub_device_close (grub_device_t device)
if (device->net)
{
grub_free (device->net->name);
grub_free (device->net->server);
grub_free (device->net);
}

View file

@ -688,11 +688,9 @@ grub_dl_load_file (const char *filename)
grub_file_close (file);
mod = grub_dl_load_core (core, size);
grub_free (core);
if (! mod)
{
grub_free (core);
return 0;
}
return 0;
mod->ref_count--;
return mod;

View file

@ -746,3 +746,51 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
dp = (grub_efi_device_path_t *) ((char *) dp + len);
}
}
/* Compare device paths. */
int
grub_efi_compare_device_paths (const grub_efi_device_path_t *dp1,
const grub_efi_device_path_t *dp2)
{
if (! dp1 || ! dp2)
/* Return non-zero. */
return 1;
while (1)
{
grub_efi_uint8_t type1, type2;
grub_efi_uint8_t subtype1, subtype2;
grub_efi_uint16_t len1, len2;
int ret;
type1 = GRUB_EFI_DEVICE_PATH_TYPE (dp1);
type2 = GRUB_EFI_DEVICE_PATH_TYPE (dp2);
if (type1 != type2)
return (int) type2 - (int) type1;
subtype1 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp1);
subtype2 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp2);
if (subtype1 != subtype2)
return (int) subtype1 - (int) subtype2;
len1 = GRUB_EFI_DEVICE_PATH_LENGTH (dp1);
len2 = GRUB_EFI_DEVICE_PATH_LENGTH (dp2);
if (len1 != len2)
return (int) len1 - (int) len2;
ret = grub_memcmp (dp1, dp2, len1);
if (ret != 0)
return ret;
if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1))
break;
dp1 = (grub_efi_device_path_t *) ((char *) dp1 + len1);
dp2 = (grub_efi_device_path_t *) ((char *) dp2 + len2);
}
return 0;
}

View file

@ -42,84 +42,28 @@ grub_efi_init (void)
grub_efidisk_init ();
}
void (*grub_efi_net_config) (grub_efi_handle_t hnd,
char **device,
char **path);
void
grub_efi_set_prefix (void)
grub_machine_get_bootlocation (char **device, char **path)
{
grub_efi_loaded_image_t *image = NULL;
char *device = NULL;
char *path = NULL;
char *p;
{
char *pptr = NULL;
if (grub_prefix[0] == '(')
{
pptr = grub_strrchr (grub_prefix, ')');
if (pptr)
{
device = grub_strndup (grub_prefix + 1, pptr - grub_prefix - 1);
pptr++;
}
}
if (!pptr)
pptr = grub_prefix;
if (pptr[0])
path = grub_strdup (pptr);
}
image = grub_efi_get_loaded_image (grub_efi_image_handle);
if (!image)
return;
*device = grub_efidisk_get_device_name (image->device_handle);
*path = grub_efi_get_filename (image->file_path);
if (!*device && grub_efi_net_config)
grub_efi_net_config (image->device_handle, device, path);
if ((!device || device[0] == ',' || !device[0]) || !path)
image = grub_efi_get_loaded_image (grub_efi_image_handle);
if (image)
{
if (!device)
device = grub_efidisk_get_device_name (image->device_handle);
else if (device[0] == ',' || !device[0])
{
/* We have a partition, but still need to fill in the drive. */
char *image_device, *comma, *new_device;
image_device = grub_efidisk_get_device_name (image->device_handle);
comma = grub_strchr (image_device, ',');
if (comma)
{
char *drive = grub_strndup (image_device, comma - image_device);
new_device = grub_xasprintf ("%s%s", drive, device);
grub_free (drive);
}
else
new_device = grub_xasprintf ("%s%s", image_device, device);
grub_free (image_device);
grub_free (device);
device = new_device;
}
}
if (image && !path)
{
char *p;
path = grub_efi_get_filename (image->file_path);
/* Get the directory. */
p = grub_strrchr (path, '/');
if (p)
*p = '\0';
}
if (device && path)
{
char *prefix;
prefix = grub_xasprintf ("(%s)%s", device, path);
if (prefix)
{
grub_env_set ("prefix", prefix);
grub_free (prefix);
}
}
grub_free (device);
grub_free (path);
/* Get the directory. */
p = grub_strrchr (*path, '/');
if (p)
*p = '\0';
}
void

View file

@ -49,7 +49,7 @@
static jmp_buf main_env;
/* Store the prefix specified by an argument. */
static char *prefix = NULL;
static char *root_dev = NULL, *dir = NULL;
int grub_no_autoload;
@ -71,11 +71,10 @@ grub_machine_init (void)
}
void
grub_machine_set_prefix (void)
grub_machine_get_bootlocation (char **device, char **path)
{
grub_env_set ("prefix", prefix);
free (prefix);
prefix = 0;
*device = root_dev;
*path = dir;
}
void
@ -84,6 +83,8 @@ grub_machine_fini (void)
grub_console_fini ();
}
char grub_prefix[64] = "";
static struct option options[] =
@ -132,22 +133,24 @@ void grub_emu_init (void);
int
main (int argc, char *argv[])
{
char *root_dev = 0;
char *dir = DEFAULT_DIRECTORY;
char *dev_map = DEFAULT_DEVICE_MAP;
volatile int hold = 0;
int opt;
set_program_name (argv[0]);
dir = xstrdup (DEFAULT_DIRECTORY);
while ((opt = getopt_long (argc, argv, "r:d:m:vH:hV", options, 0)) != -1)
switch (opt)
{
case 'r':
root_dev = optarg;
free (root_dev);
root_dev = xstrdup (optarg);
break;
case 'd':
dir = optarg;
free (dir);
dir = xstrdup (optarg);
break;
case 'm':
dev_map = optarg;
@ -219,9 +222,6 @@ main (int argc, char *argv[])
dir = xstrdup (dir);
else
dir = grub_make_system_path_relative_to_its_root (dir);
prefix = xmalloc (strlen (root_dev) + 2 + strlen (dir) + 1);
sprintf (prefix, "(%s)%s", root_dev, dir);
free (dir);
/* Start GRUB! */
if (setjmp (main_env) == 0)

View file

@ -25,7 +25,6 @@
#include <grub/fs.h>
#include <grub/device.h>
grub_err_t (*grub_file_net_seek) (struct grub_file *file, grub_off_t offset) = NULL;
void (*EXPORT_VAR (grub_grubnet_fini)) (void);
grub_file_filter_t grub_file_filters_all[GRUB_FILE_FILTER_MAX];
@ -183,9 +182,6 @@ grub_file_seek (grub_file_t file, grub_off_t offset)
return -1;
}
if (file->device->net && grub_file_net_seek)
grub_file_net_seek (file, offset);
old = file->offset;
file->offset = offset;

View file

@ -107,10 +107,9 @@ grub_machine_init (void)
}
void
grub_machine_set_prefix (void)
grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
char **path __attribute__ ((unused)))
{
/* Initialize the prefix. */
grub_env_set ("prefix", grub_prefix);
}
void

View file

@ -39,9 +39,3 @@ grub_machine_fini (void)
{
grub_efi_fini ();
}
void
grub_machine_set_prefix (void)
{
grub_efi_set_prefix ();
}

View file

@ -45,52 +45,41 @@ struct mem_region
static struct mem_region mem_regions[MAX_REGIONS];
static int num_regions;
static char *
make_install_device (void)
void (*grub_pc_net_config) (char **device, char **path);
void
grub_machine_get_bootlocation (char **device, char **path)
{
char *ptr;
/* No hardcoded root partition - make it from the boot drive and the
partition number encoded at the install time. */
if (grub_boot_drive == GRUB_BOOT_MACHINE_PXE_DL)
{
if (grub_pc_net_config)
grub_pc_net_config (device, path);
return;
}
/* XXX: This should be enough. */
char dev[100], *ptr = dev;
#define DEV_SIZE 100
*device = grub_malloc (DEV_SIZE);
ptr = *device;
grub_snprintf (*device, DEV_SIZE,
"%cd%u", (grub_boot_drive & 0x80) ? 'h' : 'f',
grub_boot_drive & 0x7f);
ptr += grub_strlen (ptr);
if (grub_prefix[0] != '(')
{
/* No hardcoded root partition - make it from the boot drive and the
partition number encoded at the install time. */
if (grub_boot_drive == GRUB_BOOT_MACHINE_PXE_DL)
{
grub_strcpy (dev, "(pxe");
ptr += sizeof ("(pxe") - 1;
}
else
{
grub_snprintf (dev, sizeof (dev),
"(%cd%u", (grub_boot_drive & 0x80) ? 'h' : 'f',
grub_boot_drive & 0x7f);
ptr += grub_strlen (ptr);
if (grub_install_dos_part >= 0)
grub_snprintf (ptr, DEV_SIZE - (ptr - *device),
",%u", grub_install_dos_part + 1);
ptr += grub_strlen (ptr);
if (grub_install_dos_part >= 0)
grub_snprintf (ptr, sizeof (dev) - (ptr - dev),
",%u", grub_install_dos_part + 1);
ptr += grub_strlen (ptr);
if (grub_install_bsd_part >= 0)
grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ",%u",
grub_install_bsd_part + 1);
ptr += grub_strlen (ptr);
}
grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ")%s", grub_prefix);
grub_strcpy (grub_prefix, dev);
}
else if (grub_prefix[1] == ',' || grub_prefix[1] == ')')
{
/* We have a prefix, but still need to fill in the boot drive. */
grub_snprintf (dev, sizeof (dev),
"(%cd%u%s", (grub_boot_drive & 0x80) ? 'h' : 'f',
grub_boot_drive & 0x7f, grub_prefix + 1);
grub_strcpy (grub_prefix, dev);
}
return grub_prefix;
if (grub_install_bsd_part >= 0)
grub_snprintf (ptr, DEV_SIZE - (ptr - *device), ",%u",
grub_install_bsd_part + 1);
ptr += grub_strlen (ptr);
*ptr = 0;
}
/* Add a memory region. */
@ -211,13 +200,6 @@ grub_machine_init (void)
grub_tsc_init ();
}
void
grub_machine_set_prefix (void)
{
/* Initialize the prefix. */
grub_env_set ("prefix", make_install_device ());
}
void
grub_machine_fini (void)
{

View file

@ -40,12 +40,6 @@ grub_machine_fini (void)
grub_efi_fini ();
}
void
grub_machine_set_prefix (void)
{
grub_efi_set_prefix ();
}
void
grub_arch_sync_caches (void *address, grub_size_t len)
{

View file

@ -60,6 +60,10 @@ grub_ieee1275_find_options (void)
int is_olpc = 0;
int is_qemu = 0;
#ifdef __sparc__
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0);
#endif
grub_ieee1275_finddevice ("/", &root);
grub_ieee1275_finddevice ("/options", &options);
grub_ieee1275_finddevice ("/openprom", &openprom);

View file

@ -31,10 +31,12 @@
#include <grub/ieee1275/console.h>
#include <grub/ieee1275/ofdisk.h>
#include <grub/ieee1275/ieee1275.h>
#include <grub/ieee1275/ofnet.h>
#include <grub/net.h>
#include <grub/offsets.h>
#include <grub/memory.h>
#ifdef __sparc__
#include <grub/machine/kernel.h>
#endif
/* The minimal heap size we can live with. */
#define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024)
@ -49,6 +51,10 @@
extern char _start[];
extern char _end[];
#ifdef __sparc__
grub_addr_t grub_ieee1275_original_stack;
#endif
void
grub_exit (void)
{
@ -70,52 +76,51 @@ grub_translate_ieee1275_path (char *filepath)
}
}
void (*grub_ieee1275_net_config) (const char *dev,
char **device,
char **path);
void
grub_machine_set_prefix (void)
grub_machine_get_bootlocation (char **device, char **path)
{
char bootpath[64]; /* XXX check length */
char *filename;
char *prefix;
grub_bootp_t bootp_pckt;
char addr[GRUB_NET_MAX_STR_ADDR_LEN];
/* Set the net prefix when possible. */
if (grub_getbootp && (bootp_pckt = grub_getbootp()))
{
grub_uint32_t n = bootp_pckt->siaddr;
grub_snprintf (addr, GRUB_NET_MAX_STR_ADDR_LEN, "%d.%d.%d.%d",
((n >> 24) & 0xff), ((n >> 16) & 0xff),
((n >> 8) & 0xff), ((n >> 0) & 0xff));
prefix = grub_xasprintf ("(tftp,%s)%s", addr,grub_prefix);
grub_env_set ("prefix", prefix);
grub_free (prefix);
return;
}
if (grub_prefix[0])
{
grub_env_set ("prefix", grub_prefix);
/* Prefix is hardcoded in the core image. */
return;
}
char *type;
if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath", &bootpath,
sizeof (bootpath), 0))
{
/* Should never happen. */
grub_printf ("/chosen/bootpath property missing!\n");
grub_env_set ("prefix", "");
return;
}
/* Transform an OF device path to a GRUB path. */
prefix = grub_ieee1275_encode_devname (bootpath);
type = grub_ieee1275_get_device_type (bootpath);
if (type && grub_strcmp (type, "network") == 0)
{
char *dev, *canon;
char *ptr;
dev = grub_ieee1275_get_aliasdevname (bootpath);
canon = grub_ieee1275_canonicalise_devname (dev);
ptr = canon + grub_strlen (canon) - 1;
while (ptr > canon && (*ptr == ',' || *ptr == ':'))
ptr--;
ptr++;
*ptr = 0;
if (grub_ieee1275_net_config)
grub_ieee1275_net_config (canon, device, path);
grub_free (dev);
grub_free (canon);
}
else
*device = grub_ieee1275_encode_devname (bootpath);
grub_free (type);
filename = grub_ieee1275_get_filename (bootpath);
if (filename)
{
char *newprefix;
char *lastslash = grub_strrchr (filename, '\\');
/* Truncate at last directory. */
@ -124,23 +129,22 @@ grub_machine_set_prefix (void)
*lastslash = '\0';
grub_translate_ieee1275_path (filename);
newprefix = grub_xasprintf ("%s%s", prefix, filename);
if (newprefix)
{
grub_free (prefix);
prefix = newprefix;
}
*path = filename;
}
}
grub_env_set ("prefix", prefix);
grub_free (filename);
grub_free (prefix);
}
/* Claim some available memory in the first /memory node. */
static void grub_claim_heap (void)
#ifdef __sparc__
static void
grub_claim_heap (void)
{
grub_mm_init_region ((void *) (grub_modules_get_end ()
+ GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000);
}
#else
static void
grub_claim_heap (void)
{
unsigned long total = 0;
@ -208,23 +212,14 @@ static void grub_claim_heap (void)
else
grub_machine_mmap_iterate (heap_init);
}
#endif
static grub_uint64_t ieee1275_get_time_ms (void);
void
grub_machine_init (void)
static void
grub_parse_cmdline (void)
{
char args[256];
grub_ssize_t actual;
char args[256];
grub_ieee1275_init ();
grub_console_init_early ();
grub_claim_heap ();
grub_console_init_lately ();
grub_ofdisk_init ();
/* Process commandline. */
if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootargs", &args,
sizeof args, &actual) == 0
&& actual > 1)
@ -257,6 +252,21 @@ grub_machine_init (void)
}
}
}
}
static grub_uint64_t ieee1275_get_time_ms (void);
void
grub_machine_init (void)
{
grub_ieee1275_init ();
grub_console_init_early ();
grub_claim_heap ();
grub_console_init_lately ();
grub_ofdisk_init ();
grub_parse_cmdline ();
grub_install_get_time_ms (ieee1275_get_time_ms);
}
@ -264,8 +274,6 @@ grub_machine_init (void)
void
grub_machine_fini (void)
{
if (grub_grubnet_fini)
grub_grubnet_fini ();
grub_ofdisk_fini ();
grub_console_fini ();
}

View file

@ -22,16 +22,14 @@
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/ieee1275/ieee1275.h>
#include <grub/ieee1275/ofnet.h>
#include <grub/net.h>
#include <grub/net/tftp.h>
grub_bootp_t (*grub_getbootp) (void);
enum grub_ieee1275_parse_type
{
GRUB_PARSE_FILENAME,
GRUB_PARSE_PARTITION,
GRUB_PARSE_DEVICE
GRUB_PARSE_DEVICE,
GRUB_PARSE_DEVICE_TYPE
};
/* Walk children of 'devpath', calling hook for each. */
@ -322,14 +320,9 @@ grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype)
{
char type[64]; /* XXX check size. */
char *device = grub_ieee1275_get_devname (path);
char *args = grub_ieee1275_get_devargs (path);
char *ret = 0;
grub_ieee1275_phandle_t dev;
if (!args)
/* Shouldn't happen. */
return 0;
/* We need to know what type of device it is in order to parse the full
file path properly. */
if (grub_ieee1275_finddevice (device, &dev))
@ -344,50 +337,86 @@ grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype)
goto fail;
}
if (!grub_strcmp ("block", type))
switch (ptype)
{
/* The syntax of the device arguments is defined in the CHRP and PReP
IEEE1275 bindings: "[partition][,[filename]]". */
char *comma = grub_strchr (args, ',');
case GRUB_PARSE_DEVICE:
ret = grub_strdup (device);
break;
case GRUB_PARSE_DEVICE_TYPE:
ret = grub_strdup (type);
break;
case GRUB_PARSE_FILENAME:
{
char *comma;
char *args;
if (ptype == GRUB_PARSE_FILENAME)
{
if (comma)
{
char *filepath = comma + 1;
if (grub_strcmp ("block", type) != 0)
goto unknown;
/* Make sure filepath has leading backslash. */
if (filepath[0] != '\\')
ret = grub_xasprintf ("\\%s", filepath);
else
ret = grub_strdup (filepath);
args = grub_ieee1275_get_devargs (path);
if (!args)
/* Shouldn't happen. */
return 0;
/* The syntax of the device arguments is defined in the CHRP and PReP
IEEE1275 bindings: "[partition][,[filename]]". */
comma = grub_strchr (args, ',');
if (comma)
{
char *filepath = comma + 1;
/* Make sure filepath has leading backslash. */
if (filepath[0] != '\\')
ret = grub_xasprintf ("\\%s", filepath);
else
ret = grub_strdup (filepath);
}
grub_free (args);
}
else if (ptype == GRUB_PARSE_PARTITION)
{
if (!comma)
ret = grub_strdup (args);
else
ret = grub_strndup (args, (grub_size_t)(comma - args));
}
}
break;
case GRUB_PARSE_PARTITION:
{
char *comma;
char *args;
else if (!grub_strcmp ("network", type))
{
if (ptype == GRUB_PARSE_DEVICE)
ret = grub_strdup(device);
}
else
{
if (grub_strcmp ("block", type) != 0)
goto unknown;
args = grub_ieee1275_get_devargs (path);
if (!args)
/* Shouldn't happen. */
return 0;
comma = grub_strchr (args, ',');
if (!comma)
ret = grub_strdup (args);
else
ret = grub_strndup (args, (grub_size_t)(comma - args));
/* Consistently provide numbered partitions to GRUB.
OpenBOOT traditionally uses alphabetical partition
specifiers. */
if (ret[0] >= 'a' && ret[0] <= 'z')
ret[0] = '1' + (ret[0] - 'a');
grub_free (args);
}
break;
default:
unknown:
grub_printf ("Unsupported type %s for device %s\n", type, device);
}
fail:
grub_free (device);
grub_free (args);
return ret;
}
char *
grub_ieee1275_get_device_type (const char *path)
{
return grub_ieee1275_parse_args (path, GRUB_PARSE_DEVICE_TYPE);
}
char *
grub_ieee1275_get_aliasdevname (const char *path)
{

View file

@ -129,27 +129,74 @@ grub_env_write_root (struct grub_env_var *var __attribute__ ((unused)),
return grub_strdup (val);
}
/* Set the root device according to the dl prefix. */
static void
grub_set_root_dev (void)
grub_set_prefix_and_root (void)
{
const char *prefix;
char *device = NULL;
char *path = NULL;
char *fwdevice = NULL;
char *fwpath = NULL;
grub_register_variable_hook ("root", 0, grub_env_write_root);
prefix = grub_env_get ("prefix");
{
char *pptr = NULL;
if (grub_prefix[0] == '(')
{
pptr = grub_strrchr (grub_prefix, ')');
if (pptr)
{
device = grub_strndup (grub_prefix + 1, pptr - grub_prefix - 1);
pptr++;
}
}
if (!pptr)
pptr = grub_prefix;
if (pptr[0])
path = grub_strdup (pptr);
}
if ((!device || device[0] == ',' || !device[0]) || !path)
grub_machine_get_bootlocation (&fwdevice, &fwpath);
if (prefix)
if (!device && fwdevice)
device = fwdevice;
else if (fwdevice && (device[0] == ',' || !device[0]))
{
char *dev;
/* We have a partition, but still need to fill in the drive. */
char *comma, *new_device;
dev = grub_file_get_device_name (prefix);
if (dev)
comma = grub_strchr (fwdevice, ',');
if (comma)
{
grub_env_set ("root", dev);
grub_free (dev);
char *drive = grub_strndup (fwdevice, comma - fwdevice);
new_device = grub_xasprintf ("%s%s", drive, device);
grub_free (drive);
}
else
new_device = grub_xasprintf ("%s%s", fwdevice, device);
grub_free (fwdevice);
grub_free (device);
device = new_device;
}
if (fwpath && !path)
path = fwpath;
if (device)
{
char *prefix;
prefix = grub_xasprintf ("(%s)%s", device, path ? : "");
if (prefix)
{
grub_env_set ("prefix", prefix);
grub_free (prefix);
}
grub_env_set ("root", device);
}
grub_free (device);
grub_free (path);
grub_print_error ();
}
/* Load the normal mode module and execute the normal mode if possible. */
@ -187,8 +234,7 @@ grub_main (void)
/* It is better to set the root device as soon as possible,
for convenience. */
grub_machine_set_prefix ();
grub_set_root_dev ();
grub_set_prefix_and_root ();
grub_env_export ("root");
grub_env_export ("prefix");

View file

@ -38,7 +38,7 @@ grub_get_rtc (void)
}
void
grub_machine_set_prefix (void)
grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
char **path __attribute__ ((unused)))
{
grub_env_set ("prefix", grub_prefix);
}

View file

@ -515,7 +515,7 @@ grub_debug_malloc (const char *file, int line, grub_size_t size)
void *ptr;
if (grub_mm_debug)
grub_printf ("%s:%d: malloc (0x%zx) = ", file, line, size);
grub_printf ("%s:%d: malloc (0x%" PRIxGRUB_SIZE ") = ", file, line, size);
ptr = grub_malloc (size);
if (grub_mm_debug)
grub_printf ("%p\n", ptr);
@ -528,7 +528,7 @@ grub_debug_zalloc (const char *file, int line, grub_size_t size)
void *ptr;
if (grub_mm_debug)
grub_printf ("%s:%d: zalloc (0x%zx) = ", file, line, size);
grub_printf ("%s:%d: zalloc (0x%" PRIxGRUB_SIZE ") = ", file, line, size);
ptr = grub_zalloc (size);
if (grub_mm_debug)
grub_printf ("%p\n", ptr);
@ -547,7 +547,7 @@ void *
grub_debug_realloc (const char *file, int line, void *ptr, grub_size_t size)
{
if (grub_mm_debug)
grub_printf ("%s:%d: realloc (%p, 0x%zx) = ", file, line, ptr, size);
grub_printf ("%s:%d: realloc (%p, 0x%" PRIxGRUB_SIZE ") = ", file, line, ptr, size);
ptr = grub_realloc (ptr, size);
if (grub_mm_debug)
grub_printf ("%p\n", ptr);
@ -561,8 +561,8 @@ grub_debug_memalign (const char *file, int line, grub_size_t align,
void *ptr;
if (grub_mm_debug)
grub_printf ("%s:%d: memalign (0x%zx, 0x%zx) = ",
file, line, align, size);
grub_printf ("%s:%d: memalign (0x%" PRIxGRUB_SIZE ", 0x%" PRIxGRUB_SIZE
") = ", file, line, align, size);
ptr = grub_memalign (align, size);
if (grub_mm_debug)
grub_printf ("%p\n", ptr);

View file

@ -1,174 +0,0 @@
/* init.c -- Initialize GRUB on SPARC64. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/kernel.h>
#include <grub/mm.h>
#include <grub/env.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/time.h>
#include <grub/machine/boot.h>
#include <grub/ieee1275/console.h>
#include <grub/machine/kernel.h>
#include <grub/machine/time.h>
#include <grub/ieee1275/ofdisk.h>
#include <grub/ieee1275/ieee1275.h>
grub_addr_t grub_ieee1275_original_stack;
void
grub_exit (void)
{
grub_ieee1275_exit ();
}
static grub_uint64_t
ieee1275_get_time_ms (void)
{
grub_uint32_t msecs = 0;
grub_ieee1275_milliseconds (&msecs);
return msecs;
}
grub_uint32_t
grub_get_rtc (void)
{
return ieee1275_get_time_ms ();
}
grub_addr_t
grub_arch_modules_addr (void)
{
extern char _end[];
return (grub_addr_t) _end;
}
void
grub_machine_set_prefix (void)
{
if (grub_prefix[0] != '(')
{
char bootpath[IEEE1275_MAX_PATH_LEN];
char *prefix, *path, *colon;
grub_ssize_t actual;
if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath",
&bootpath, sizeof (bootpath), &actual))
{
/* Should never happen. */
grub_printf ("/chosen/bootpath property missing!\n");
grub_env_set ("prefix", "");
return;
}
/* Transform an OF device path to a GRUB path. */
colon = grub_strchr (bootpath, ':');
if (colon)
{
char *part = colon + 1;
/* Consistently provide numbered partitions to GRUB.
OpenBOOT traditionally uses alphabetical partition
specifiers. */
if (part[0] >= 'a' && part[0] <= 'z')
part[0] = '1' + (part[0] - 'a');
}
prefix = grub_ieee1275_encode_devname (bootpath);
path = grub_xasprintf("%s%s", prefix, grub_prefix);
grub_strcpy (grub_prefix, path);
grub_free (path);
grub_free (prefix);
}
grub_env_set ("prefix", grub_prefix);
}
static void
grub_heap_init (void)
{
grub_mm_init_region ((void *) (grub_modules_get_end ()
+ GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000);
}
static void
grub_parse_cmdline (void)
{
grub_ssize_t actual;
char args[256];
if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootargs", &args,
sizeof args, &actual) == 0
&& actual > 1)
{
int i = 0;
while (i < actual)
{
char *command = &args[i];
char *end;
char *val;
end = grub_strchr (command, ';');
if (end == 0)
i = actual; /* No more commands after this one. */
else
{
*end = '\0';
i += end - command + 1;
while (grub_isspace(args[i]))
i++;
}
/* Process command. */
val = grub_strchr (command, '=');
if (val)
{
*val = '\0';
grub_env_set (command, val + 1);
}
}
}
}
void
grub_machine_init (void)
{
grub_ieee1275_init ();
grub_console_init_early ();
grub_heap_init ();
grub_console_init_lately ();
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0);
grub_ofdisk_init ();
grub_parse_cmdline ();
grub_install_get_time_ms (ieee1275_get_time_ms);
}
void
grub_machine_fini (void)
{
grub_ofdisk_fini ();
grub_console_fini ();
}

View file

@ -29,6 +29,7 @@ struct grub_term_output *grub_term_outputs;
struct grub_term_input *grub_term_inputs;
void (*grub_term_poll_usb) (void) = NULL;
void (*grub_net_poll_cards_idle) (void) = NULL;
/* Put a Unicode character. */
static void
@ -91,6 +92,9 @@ grub_checkkey (void)
if (grub_term_poll_usb)
grub_term_poll_usb ();
if (grub_net_poll_cards_idle)
grub_net_poll_cards_idle ();
FOR_ACTIVE_TERM_INPUTS(term)
{
pending_key = term->getkey (term);

View file

@ -95,6 +95,20 @@ FUNCTION(efi_wrap_6)
addq $64, %rsp
ret
FUNCTION(efi_wrap_7)
subq $96, %rsp
mov 96+16(%rsp), %rax
mov %rax, 48(%rsp)
mov 96+8(%rsp), %rax
mov %rax, 40(%rsp)
mov %r9, 32(%rsp)
mov %r8, %r9
mov %rcx, %r8
mov %rsi, %rcx
call *%rdi
addq $96, %rsp
ret
FUNCTION(efi_wrap_10)
subq $96, %rsp
mov 96+40(%rsp), %rax

View file

@ -144,7 +144,8 @@ grub_net_arp_receive (struct grub_net_buff *nb)
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
{
/* Am I the protocol address target? */
if (grub_memcmp (target_protocol_address, &inf->address.ipv4, 6) == 0
if (inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
&& grub_memcmp (target_protocol_address, &inf->address.ipv4, 4) == 0
&& grub_be_to_cpu16 (arp_header->op) == ARP_REQUEST)
{
grub_net_link_level_address_t aux;

539
grub-core/net/bootp.c Normal file
View file

@ -0,0 +1,539 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/net.h>
#include <grub/env.h>
#include <grub/i18n.h>
#include <grub/command.h>
#include <grub/net/ip.h>
#include <grub/net/netbuff.h>
#include <grub/net/udp.h>
#include <grub/datetime.h>
static char *
grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
const char *val __attribute__ ((unused)))
{
return NULL;
}
static void
set_env_limn_ro (const char *intername, const char *suffix,
char *value, grub_size_t len)
{
char c;
char varname[sizeof ("net_") + grub_strlen (intername) + sizeof ("_")
+ grub_strlen (suffix)];
grub_snprintf (varname, sizeof (varname), "net_%s_%s", intername, suffix);
c = value[len];
value[len] = 0;
grub_env_set (varname, value);
value[len] = c;
grub_register_variable_hook (varname, 0, grub_env_write_readonly);
}
static void
parse_dhcp_vendor (const char *name, void *vend, int limit)
{
grub_uint8_t *ptr, *ptr0;
ptr = ptr0 = vend;
if (ptr[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0
|| ptr[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1
|| ptr[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2
|| ptr[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3)
return;
ptr = ptr + sizeof (grub_uint32_t);
while (ptr - ptr0 < limit)
{
grub_uint8_t tagtype;
grub_uint8_t taglength;
tagtype = *ptr++;
/* Pad tag. */
if (tagtype == 0)
continue;
/* End tag. */
if (tagtype == 0xff)
return;
taglength = *ptr++;
switch (tagtype)
{
case 12:
set_env_limn_ro (name, "hostname", (char *) ptr, taglength);
break;
case 15:
set_env_limn_ro (name, "domain", (char *) ptr, taglength);
break;
case 17:
set_env_limn_ro (name, "rootpath", (char *) ptr, taglength);
break;
case 18:
set_env_limn_ro (name, "extensionspath", (char *) ptr, taglength);
break;
/* If you need any other options please contact GRUB
developpement team. */
}
ptr += taglength;
}
}
#define OFFSET_OF(x, y) ((grub_uint8_t *)((y)->x) - (grub_uint8_t *)(y))
struct grub_net_network_level_interface *
grub_net_configure_by_dhcp_ack (const char *name,
struct grub_net_card *card,
grub_net_interface_flags_t flags,
const struct grub_net_bootp_packet *bp,
grub_size_t size,
int is_def, char **device, char **path)
{
grub_net_network_level_address_t addr;
grub_net_link_level_address_t hwaddr;
struct grub_net_network_level_interface *inter;
addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
addr.ipv4 = bp->your_ip;
if (device)
*device = 0;
if (path)
*path = 0;
grub_memcpy (hwaddr.mac, bp->mac_addr,
bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len
: sizeof (hwaddr.mac));
hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
inter = grub_net_add_addr (name, card, addr, hwaddr, flags);
{
grub_net_network_level_netaddress_t target;
grub_net_network_level_address_t gw;
char rname[grub_strlen (name) + sizeof ("_gw")];
target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
target.ipv4.base = bp->server_ip;
target.ipv4.masksize = 32;
gw.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
gw.ipv4 = bp->gateway_ip;
grub_snprintf (rname, sizeof (rname), "%s_gw", name);
grub_net_add_route_gw (rname, target, gw);
}
{
grub_net_network_level_netaddress_t target;
target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
target.ipv4.base = bp->gateway_ip;
target.ipv4.masksize = 32;
grub_net_add_route (name, target, inter);
}
if (size > OFFSET_OF (boot_file, bp))
set_env_limn_ro (name, "boot_file", (char *) bp->boot_file,
sizeof (bp->boot_file));
if (is_def)
grub_net_default_server = 0;
if (size > OFFSET_OF (server_name, bp)
&& bp->server_name[0])
{
set_env_limn_ro (name, "dhcp_server_name", (char *) bp->server_name,
sizeof (bp->server_name));
if (is_def && !grub_net_default_server)
{
grub_net_default_server = grub_strdup (bp->server_name);
grub_print_error ();
}
if (device && !*device)
{
*device = grub_xasprintf ("tftp,%s", bp->server_name);
grub_print_error ();
}
}
if (is_def && !grub_net_default_server)
{
grub_net_default_server = grub_xasprintf ("%d.%d.%d.%d",
((grub_uint8_t *) &bp->server_ip)[0],
((grub_uint8_t *) &bp->server_ip)[1],
((grub_uint8_t *) &bp->server_ip)[2],
((grub_uint8_t *) &bp->server_ip)[3]);
grub_print_error ();
}
if (device && !*device)
{
*device = grub_xasprintf ("tftp,%d.%d.%d.%d",
((grub_uint8_t *) &bp->server_ip)[0],
((grub_uint8_t *) &bp->server_ip)[1],
((grub_uint8_t *) &bp->server_ip)[2],
((grub_uint8_t *) &bp->server_ip)[3]);
grub_print_error ();
}
if (size > OFFSET_OF (boot_file, bp) && path)
{
*path = grub_strndup (bp->boot_file, sizeof (bp->boot_file));
grub_print_error ();
if (*path)
{
char *slash;
slash = grub_strrchr (*path, '/');
if (slash)
*slash = 0;
else
**path = 0;
}
}
if (size > OFFSET_OF (vendor, bp))
parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp));
inter->dhcp_ack = grub_malloc (size);
if (inter->dhcp_ack)
{
grub_memcpy (inter->dhcp_ack, bp, size);
inter->dhcp_acklen = size;
}
else
grub_errno = GRUB_ERR_NONE;
return inter;
}
void
grub_net_process_dhcp (struct grub_net_buff *nb,
struct grub_net_card *card)
{
char *name;
struct grub_net_network_level_interface *inf;
name = grub_xasprintf ("%s:dhcp", card->name);
if (!name)
{
grub_print_error ();
return;
}
grub_net_configure_by_dhcp_ack (name, card,
0, (const struct grub_net_bootp_packet *) nb->data,
(nb->tail - nb->data), 0, 0, 0);
grub_free (name);
if (grub_errno)
grub_print_error ();
else
{
FOR_NET_NETWORK_LEVEL_INTERFACES(inf)
if (grub_memcmp (inf->name, card->name, grub_strlen (card->name)) == 0
&& grub_memcmp (inf->name + grub_strlen (card->name),
":dhcp_tmp", sizeof (":dhcp_tmp") - 1) == 0)
{
grub_net_network_level_interface_unregister (inf);
break;
}
}
}
static char
hexdigit (grub_uint8_t val)
{
if (val < 10)
return val + '0';
return val + 'a' - 10;
}
static grub_err_t
grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)),
int argc, char **args)
{
struct grub_net_network_level_interface *inter;
int num;
grub_uint8_t *ptr;
grub_uint8_t taglength;
if (argc < 4)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "4 arguments expected");
FOR_NET_NETWORK_LEVEL_INTERFACES (inter)
if (grub_strcmp (inter->name, args[1]) == 0)
break;
if (!inter)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("unrecognised interface %s"), args[1]);
if (!inter->dhcp_ack)
return grub_error (GRUB_ERR_IO, N_("no DHCP info found"));
if (inter->dhcp_acklen <= OFFSET_OF (vendor, inter->dhcp_ack))
return grub_error (GRUB_ERR_IO, N_("no DHCP options found"));
num = grub_strtoul (args[2], 0, 0);
if (grub_errno)
return grub_errno;
ptr = inter->dhcp_ack->vendor;
if (ptr[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0
|| ptr[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1
|| ptr[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2
|| ptr[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3)
return grub_error (GRUB_ERR_IO, N_("no DHCP options found"));
ptr = ptr + sizeof (grub_uint32_t);
while (1)
{
grub_uint8_t tagtype;
if (ptr >= ((grub_uint8_t *) inter->dhcp_ack) + inter->dhcp_acklen)
return grub_error (GRUB_ERR_IO, N_("no DHCP option %d found"), num);
tagtype = *ptr++;
/* Pad tag. */
if (tagtype == 0)
continue;
/* End tag. */
if (tagtype == 0xff)
return grub_error (GRUB_ERR_IO, N_("no DHCP option %d found"), num);
taglength = *ptr++;
if (tagtype == num)
break;
ptr += taglength;
}
if (grub_strcmp (args[3], "string") == 0)
{
char *val = grub_malloc (taglength + 1);
if (!val)
return grub_errno;
grub_memcpy (val, ptr, taglength);
val[taglength] = 0;
if (args[0][0] == '-' && args[0][1] == 0)
grub_printf ("%s\n", val);
else
return grub_env_set (args[0], val);
return GRUB_ERR_NONE;
}
if (grub_strcmp (args[3], "number") == 0)
{
grub_uint64_t val = 0;
int i;
for (i = 0; i < taglength; i++)
val = (val << 8) | ptr[i];
if (args[0][0] == '-' && args[0][1] == 0)
grub_printf ("%llu\n", (unsigned long long) val);
else
{
char valn[64];
grub_printf (valn, sizeof (valn), "%lld\n", (unsigned long long) val);
return grub_env_set (args[0], valn);
}
return GRUB_ERR_NONE;
}
if (grub_strcmp (args[3], "hex") == 0)
{
char *val = grub_malloc (2 * taglength + 1);
int i;
if (!val)
return grub_errno;
for (i = 0; i < taglength; i++)
{
val[2 * i] = hexdigit (ptr[i] >> 4);
val[2 * i + 1] = hexdigit (ptr[i] & 0xf);
}
val[2 * taglength] = 0;
if (args[0][0] == '-' && args[0][1] == 0)
grub_printf ("%s\n", val);
else
return grub_env_set (args[0], val);
return GRUB_ERR_NONE;
}
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"unrecognised format specification %s", args[3]);
}
static grub_err_t
grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
int argc, char **args)
{
struct grub_net_card *card;
struct grub_net_network_level_interface *ifaces;
grub_size_t ncards = 0;
unsigned j = 0;
int interval;
grub_err_t err;
FOR_NET_CARDS (card)
{
if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
continue;
ncards++;
}
ifaces = grub_zalloc (ncards * sizeof (ifaces[0]));
if (!ifaces)
return grub_errno;
j = 0;
FOR_NET_CARDS (card)
{
if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
continue;
ifaces[j].card = card;
ifaces[j].next = &ifaces[j+1];
if (j)
ifaces[j].prev = &ifaces[j-1].next;
ifaces[j].name = grub_xasprintf ("%s:dhcp_tmp", card->name);
card->num_ifaces++;
if (!ifaces[j].name)
{
unsigned i;
for (i = 0; i < j; i++)
grub_free (ifaces[i].name);
grub_free (ifaces);
return grub_errno;
}
ifaces[j].address.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV;
grub_memcpy (&ifaces[j].hwaddress, &card->default_address,
sizeof (ifaces[j].hwaddress));
j++;
}
ifaces[ncards - 1].next = grub_net_network_level_interfaces;
if (grub_net_network_level_interfaces)
grub_net_network_level_interfaces->prev = & ifaces[ncards - 1].next;
grub_net_network_level_interfaces = &ifaces[0];
ifaces[0].prev = &grub_net_network_level_interfaces;
for (interval = 200; interval < 10000; interval *= 2)
{
int done = 0;
for (j = 0; j < ncards; j++)
{
struct grub_net_bootp_packet *pack;
struct grub_datetime date;
grub_int32_t t;
struct grub_net_buff *nb;
struct udphdr *udph;
grub_net_network_level_address_t target;
if (!ifaces[j].prev)
continue;
nb = grub_netbuff_alloc (sizeof (*pack));
if (!nb)
{
grub_netbuff_free (nb);
return grub_errno;
}
err = grub_netbuff_reserve (nb, sizeof (*pack) + 64 + 128);
if (err)
{
grub_netbuff_free (nb);
return err;
}
err = grub_netbuff_push (nb, sizeof (*pack) + 64);
if (err)
{
grub_netbuff_free (nb);
return err;
}
pack = (void *) nb->data;
done = 1;
grub_memset (pack, 0, sizeof (*pack) + 64);
pack->opcode = 1;
pack->hw_type = 1;
pack->hw_len = 6;
err = grub_get_datetime (&date);
if (err || !grub_datetime2unixtime (&date, &t))
{
grub_errno = GRUB_ERR_NONE;
t = 0;
}
pack->ident = grub_cpu_to_be32 (t);
pack->seconds = 0;//grub_cpu_to_be16 (t);
grub_memcpy (&pack->mac_addr, &ifaces[j].hwaddress.mac, 6);
grub_netbuff_push (nb, sizeof (*udph));
udph = (struct udphdr *) nb->data;
udph->src = grub_cpu_to_be16 (68);
udph->dst = grub_cpu_to_be16 (67);
udph->chksum = 0;
udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
target.ipv4 = 0xffffffff;
err = grub_net_send_ip_packet (&ifaces[j], &target, nb);
grub_netbuff_free (nb);
if (err)
return err;
}
if (!done)
break;
grub_net_poll_cards (interval);
}
err = GRUB_ERR_NONE;
for (j = 0; j < ncards; j++)
{
grub_free (ifaces[j].name);
if (!ifaces[j].prev)
continue;
grub_error_push ();
grub_net_network_level_interface_unregister (&ifaces[j]);
err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "couldn't configure %s",
ifaces[j].card->name);
}
grub_free (ifaces);
return err;
}
static grub_command_t cmd_dhcp, cmd_getdhcp, cmd_bootp;
void
grub_bootp_init (void)
{
cmd_bootp = grub_register_command ("net_bootp", grub_cmd_bootp,
"[CARD]",
N_("perform a bootp autoconfiguration"));
cmd_dhcp = grub_register_command ("net_dhcp", grub_cmd_bootp,
"[CARD]",
N_("perform a bootp autoconfiguration"));
cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt,
N_("VAR INTERFACE NUMBER DESCRIPTION"),
N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value."));
}
void
grub_bootp_fini (void)
{
grub_unregister_command (cmd_getdhcp);
grub_unregister_command (cmd_dhcp);
grub_unregister_command (cmd_bootp);
}

View file

@ -0,0 +1,201 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/net/netbuff.h>
#include <grub/dl.h>
#include <grub/net.h>
#include <grub/time.h>
#include <grub/efi/api.h>
#include <grub/efi/efi.h>
GRUB_MOD_LICENSE ("GPLv3+");
/* GUID. */
static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID;
static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID;
static grub_err_t
send_card_buffer (const struct grub_net_card *dev,
struct grub_net_buff *pack)
{
grub_efi_status_t st;
grub_efi_simple_network_t *net = dev->efi_net;
st = efi_call_7 (net->transmit, net, 0, (pack->tail - pack->data),
pack->data, NULL, NULL, NULL);
if (st != GRUB_EFI_SUCCESS)
return grub_error (GRUB_ERR_IO, "Couldn't send network packet.");
return GRUB_ERR_NONE;
}
static grub_ssize_t
get_card_packet (const struct grub_net_card *dev,
struct grub_net_buff *nb)
{
grub_efi_simple_network_t *net = dev->efi_net;
grub_err_t err;
grub_efi_status_t st;
grub_efi_uintn_t bufsize = 1500;
err = grub_netbuff_clear (nb);
if (err)
return -1;
err = grub_netbuff_put (nb, 1500);
if (err)
return -1;
st = efi_call_7 (net->receive, net, NULL, &bufsize,
nb->data, NULL, NULL, NULL);
if (st == GRUB_EFI_BUFFER_TOO_SMALL)
{
err = grub_netbuff_put (nb, bufsize - 1500);
if (err)
return -1;
st = efi_call_7 (net->receive, net, NULL, &bufsize,
nb->data, NULL, NULL, NULL);
}
if (st != GRUB_EFI_SUCCESS)
{
grub_netbuff_clear (nb);
return -1;
}
err = grub_netbuff_unput (nb, (nb->tail - nb->data) - bufsize);
if (err)
return -1;
return bufsize;
}
static struct grub_net_card_driver efidriver =
{
.name = "efinet",
.send = send_card_buffer,
.recv = get_card_packet
};
static void
grub_efinet_findcards (void)
{
grub_efi_uintn_t num_handles;
grub_efi_handle_t *handles;
grub_efi_handle_t *handle;
int i = 0;
/* Find handles which support the disk io interface. */
handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &net_io_guid,
0, &num_handles);
if (! handles)
return;
for (handle = handles; num_handles--; handle++)
{
grub_efi_simple_network_t *net;
struct grub_net_card *card;
net = grub_efi_open_protocol (*handle, &net_io_guid,
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (! net)
/* This should not happen... Why? */
continue;
if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
&& efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
continue;
if (net->mode->state == GRUB_EFI_NETWORK_STOPPED)
continue;
if (net->mode->state == GRUB_EFI_NETWORK_STARTED
&& efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS)
continue;
card = grub_zalloc (sizeof (struct grub_net_card));
if (!card)
{
grub_print_error ();
grub_free (handles);
return;
}
card->name = grub_xasprintf ("efinet%d", i++);
card->driver = &efidriver;
card->flags = 0;
card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
grub_memcpy (card->default_address.mac,
net->mode->current_address,
sizeof (card->default_address.mac));
card->efi_net = net;
card->efi_handle = *handle;
grub_net_card_register (card);
}
grub_free (handles);
}
static void
grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
char **path)
{
struct grub_net_card *card;
grub_efi_device_path_t *dp;
dp = grub_efi_get_device_path (hnd);
if (! dp)
return;
FOR_NET_CARDS (card)
{
grub_efi_device_path_t *cdp;
struct grub_efi_pxe *pxe;
struct grub_efi_pxe_mode *pxe_mode;
if (card->driver != &efidriver)
continue;
cdp = grub_efi_get_device_path (card->efi_handle);
if (! cdp)
continue;
if (grub_efi_compare_device_paths (dp, cdp) != 0)
continue;
pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (! pxe)
continue;
pxe_mode = pxe->mode;
grub_net_configure_by_dhcp_ack (card->name, card, 0,
(struct grub_net_bootp_packet *)
&pxe_mode->dhcp_ack,
sizeof (pxe_mode->dhcp_ack),
1, device, path);
return;
}
}
GRUB_MOD_INIT(efinet)
{
grub_efinet_findcards ();
grub_efi_net_config = grub_efi_net_config_real;
}
GRUB_MOD_FINI(efinet)
{
struct grub_net_card *card, *next;
FOR_NET_CARDS_SAFE (card, next)
if (card->driver == &efidriver)
grub_net_card_unregister (card);
}

View file

@ -0,0 +1,359 @@
/* pxe.c - Driver to provide access to the pxe filesystem */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008,2009,2011 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/dl.h>
#include <grub/net.h>
#include <grub/mm.h>
#include <grub/file.h>
#include <grub/misc.h>
#include <grub/env.h>
#include <grub/machine/pxe.h>
#include <grub/machine/int.h>
#include <grub/machine/memory.h>
#include <grub/machine/kernel.h>
GRUB_MOD_LICENSE ("GPLv3+");
#define SEGMENT(x) ((x) >> 4)
#define OFFSET(x) ((x) & 0xF)
#define SEGOFS(x) ((SEGMENT(x) << 16) + OFFSET(x))
#define LINEAR(x) (void *) ((((x) >> 16) << 4) + ((x) & 0xFFFF))
struct grub_pxe_undi_open
{
grub_uint16_t status;
grub_uint16_t open_flag;
grub_uint16_t pkt_filter;
grub_uint16_t mcast_count;
grub_uint8_t mcast[8][6];
} __attribute__ ((packed));
struct grub_pxe_undi_info
{
grub_uint16_t status;
grub_uint16_t base_io;
grub_uint16_t int_number;
grub_uint16_t mtu;
grub_uint16_t hwtype;
grub_uint16_t hwaddrlen;
grub_uint8_t current_addr[16];
grub_uint8_t permanent_addr[16];
grub_uint32_t romaddr;
grub_uint16_t rxbufct;
grub_uint16_t txbufct;
} __attribute__ ((packed));
struct grub_pxe_undi_isr
{
grub_uint16_t status;
grub_uint16_t func_flag;
grub_uint16_t buffer_len;
grub_uint16_t frame_len;
grub_uint16_t frame_hdr_len;
grub_uint32_t buffer;
grub_uint8_t prot_type;
grub_uint8_t pkt_type;
} __attribute__ ((packed));
enum
{
GRUB_PXE_ISR_IN_START = 1,
GRUB_PXE_ISR_IN_PROCESS,
GRUB_PXE_ISR_IN_GET_NEXT
};
enum
{
GRUB_PXE_ISR_OUT_OURS = 0,
GRUB_PXE_ISR_OUT_NOT_OURS = 1
};
enum
{
GRUB_PXE_ISR_OUT_DONE = 0,
GRUB_PXE_ISR_OUT_TRANSMIT = 2,
GRUB_PXE_ISR_OUT_RECEIVE = 3,
GRUB_PXE_ISR_OUT_BUSY = 4,
};
struct grub_pxe_undi_transmit
{
grub_uint16_t status;
grub_uint8_t protocol;
grub_uint8_t xmitflag;
grub_uint32_t dest;
grub_uint32_t tbd;
grub_uint32_t reserved[2];
} __attribute__ ((packed));
struct grub_pxe_undi_tbd
{
grub_uint16_t len;
grub_uint32_t buf;
grub_uint16_t blk_count;
struct
{
grub_uint8_t ptr_type;
grub_uint8_t reserved;
grub_uint16_t len;
grub_uint32_t ptr;
} blocks[8];
} __attribute__ ((packed));
struct grub_pxe_bangpxe *grub_pxe_pxenv;
static grub_uint32_t pxe_rm_entry = 0;
static struct grub_pxe_bangpxe *
grub_pxe_scan (void)
{
struct grub_bios_int_registers regs;
struct grub_pxenv *pxenv;
struct grub_pxe_bangpxe *bangpxe;
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
regs.ebx = 0;
regs.ecx = 0;
regs.eax = 0x5650;
regs.es = 0;
grub_bios_interrupt (0x1a, &regs);
if ((regs.eax & 0xffff) != 0x564e)
return NULL;
pxenv = (struct grub_pxenv *) ((regs.es << 4) + (regs.ebx & 0xffff));
if (grub_memcmp (pxenv->signature, GRUB_PXE_SIGNATURE,
sizeof (pxenv->signature))
!= 0)
return NULL;
if (pxenv->version < 0x201)
return NULL;
bangpxe = (void *) ((((pxenv->pxe_ptr & 0xffff0000) >> 16) << 4)
+ (pxenv->pxe_ptr & 0xffff));
if (!bangpxe)
return NULL;
if (grub_memcmp (bangpxe->signature, GRUB_PXE_BANGPXE_SIGNATURE,
sizeof (bangpxe->signature)) != 0)
return NULL;
pxe_rm_entry = bangpxe->rm_entry;
return bangpxe;
}
static grub_ssize_t
grub_pxe_recv (const struct grub_net_card *dev __attribute__ ((unused)),
struct grub_net_buff *buf)
{
struct grub_pxe_undi_isr *isr;
static int in_progress = 0;
char *ptr, *end;
int len;
isr = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
if (!in_progress)
{
grub_memset (isr, 0, sizeof (*isr));
isr->func_flag = GRUB_PXE_ISR_IN_START;
grub_pxe_call (GRUB_PXENV_UNDI_ISR, isr, pxe_rm_entry);
if (isr->status || isr->func_flag != GRUB_PXE_ISR_OUT_OURS)
{
in_progress = 0;
return -1;
}
grub_memset (isr, 0, sizeof (*isr));
isr->func_flag = GRUB_PXE_ISR_IN_PROCESS;
grub_pxe_call (GRUB_PXENV_UNDI_ISR, isr, pxe_rm_entry);
}
else
{
grub_memset (isr, 0, sizeof (*isr));
isr->func_flag = GRUB_PXE_ISR_IN_GET_NEXT;
grub_pxe_call (GRUB_PXENV_UNDI_ISR, isr, pxe_rm_entry);
}
while (isr->func_flag != GRUB_PXE_ISR_OUT_RECEIVE)
{
if (isr->status || isr->func_flag == GRUB_PXE_ISR_OUT_DONE)
{
in_progress = 0;
return -1;
}
grub_memset (isr, 0, sizeof (*isr));
isr->func_flag = GRUB_PXE_ISR_IN_GET_NEXT;
grub_pxe_call (GRUB_PXENV_UNDI_ISR, isr, pxe_rm_entry);
}
grub_netbuff_put (buf, isr->frame_len);
ptr = buf->data;
end = ptr + isr->frame_len;
len = isr->frame_len;
grub_memcpy (ptr, LINEAR (isr->buffer), isr->buffer_len);
ptr += isr->buffer_len;
while (ptr < end)
{
grub_memset (isr, 0, sizeof (*isr));
isr->func_flag = GRUB_PXE_ISR_IN_GET_NEXT;
grub_pxe_call (GRUB_PXENV_UNDI_ISR, isr, pxe_rm_entry);
if (isr->status || isr->func_flag != GRUB_PXE_ISR_OUT_RECEIVE)
{
in_progress = 1;
return -1;
}
grub_memcpy (ptr, LINEAR (isr->buffer), isr->buffer_len);
ptr += isr->buffer_len;
}
in_progress = 1;
return len;
}
static grub_err_t
grub_pxe_send (const struct grub_net_card *dev __attribute__ ((unused)),
struct grub_net_buff *pack)
{
struct grub_pxe_undi_transmit *trans;
struct grub_pxe_undi_tbd *tbd;
char *buf;
trans = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
grub_memset (trans, 0, sizeof (*trans));
tbd = (void *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + 128);
grub_memset (tbd, 0, sizeof (*tbd));
buf = (void *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + 256);
grub_memcpy (buf, pack->data, pack->tail - pack->data);
trans->tbd = SEGOFS ((grub_addr_t) tbd);
trans->protocol = 0;
tbd->len = pack->tail - pack->data;
tbd->buf = SEGOFS ((grub_addr_t) buf);
grub_pxe_call (GRUB_PXENV_UNDI_TRANSMIT, trans, pxe_rm_entry);
if (trans->status)
return grub_error (GRUB_ERR_IO, "PXE send failed (status 0x%x)",
trans->status);
return 0;
}
static void
grub_pxe_close (const struct grub_net_card *dev __attribute__ ((unused)))
{
if (pxe_rm_entry)
grub_pxe_call (GRUB_PXENV_UNDI_CLOSE,
(void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR,
pxe_rm_entry);
}
static grub_err_t
grub_pxe_open (const struct grub_net_card *dev __attribute__ ((unused)))
{
struct grub_pxe_undi_open *ou;
ou = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
grub_memset (ou, 0, sizeof (*ou));
ou->pkt_filter = 4;
grub_pxe_call (GRUB_PXENV_UNDI_OPEN, ou, pxe_rm_entry);
if (ou->status)
return grub_error (GRUB_ERR_IO, "can't open UNDI");
return GRUB_ERR_NONE;
}
struct grub_net_card_driver grub_pxe_card_driver =
{
.open = grub_pxe_open,
.close = grub_pxe_close,
.send = grub_pxe_send,
.recv = grub_pxe_recv
};
struct grub_net_card grub_pxe_card =
{
.driver = &grub_pxe_card_driver,
.name = "pxe"
};
static void
grub_pc_net_config_real (char **device, char **path)
{
struct grub_net_bootp_packet *bp;
struct grub_pxenv_get_cached_info ci;
ci.packet_type = GRUB_PXENV_PACKET_TYPE_DHCP_ACK;
ci.buffer = 0;
ci.buffer_size = 0;
grub_pxe_call (GRUB_PXENV_GET_CACHED_INFO, &ci, pxe_rm_entry);
if (ci.status)
return;
bp = LINEAR (ci.buffer);
grub_net_configure_by_dhcp_ack ("pxe", &grub_pxe_card, 0,
bp, GRUB_PXE_BOOTP_SIZE,
1, device, path);
}
GRUB_MOD_INIT(pxe)
{
struct grub_pxe_bangpxe *pxenv;
struct grub_pxe_undi_info *ui;
unsigned i;
pxenv = grub_pxe_scan ();
if (! pxenv)
return;
ui = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
grub_memset (ui, 0, sizeof (*ui));
grub_pxe_call (GRUB_PXENV_UNDI_GET_INFORMATION, ui, pxe_rm_entry);
grub_memcpy (grub_pxe_card.default_address.mac, ui->current_addr,
sizeof (grub_pxe_card.default_address.mac));
for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++)
if (grub_pxe_card.default_address.mac[i] != 0)
break;
if (i != sizeof (grub_pxe_card.default_address.mac))
{
for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++)
if (grub_pxe_card.default_address.mac[i] != 0xff)
break;
}
if (i == sizeof (grub_pxe_card.default_address.mac))
grub_memcpy (grub_pxe_card.default_address.mac, ui->permanent_addr,
sizeof (grub_pxe_card.default_address.mac));
grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
grub_net_card_register (&grub_pxe_card);
grub_pc_net_config = grub_pc_net_config_real;
}
GRUB_MOD_FINI(pxe)
{
grub_pc_net_config = 0;
grub_net_card_unregister (&grub_pxe_card);
}

View file

@ -1,5 +1,22 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/net/netbuff.h>
#include <grub/ieee1275/ofnet.h>
#include <grub/ieee1275/ieee1275.h>
#include <grub/dl.h>
#include <grub/net.h>
@ -7,8 +24,15 @@
GRUB_MOD_LICENSE ("GPLv3+");
struct grub_ofnetcard_data
{
char *path;
grub_ieee1275_ihandle_t handle;
grub_uint32_t mtu;
};
static grub_err_t
card_open (struct grub_net_card *dev)
card_open (const struct grub_net_card *dev)
{
int status;
struct grub_ofnetcard_data *data = dev->data;
@ -26,14 +50,13 @@ card_open (struct grub_net_card *dev)
return GRUB_ERR_NONE;
}
static grub_err_t
card_close (struct grub_net_card *dev)
static void
card_close (const struct grub_net_card *dev)
{
struct grub_ofnetcard_data *data = dev->data;
if (data->handle)
grub_ieee1275_close (data->handle);
return GRUB_ERR_NONE;
}
static grub_err_t
@ -75,8 +98,8 @@ get_card_packet (const struct grub_net_card *dev, struct grub_net_buff *nb)
static struct grub_net_card_driver ofdriver =
{
.name = "ofnet",
.init = card_open,
.fini = card_close,
.open = card_open,
.close = card_close,
.send = send_card_buffer,
.recv = get_card_packet
};
@ -94,51 +117,113 @@ bootp_response_properties[] =
{ .name = "bootpreply-packet", .offset = 0x2a},
};
static grub_bootp_t
grub_getbootp_real (void)
static void
grub_ieee1275_net_config_real (const char *devpath, char **device, char **path)
{
grub_bootp_t packet = grub_malloc (sizeof *packet);
char *bootp_response;
grub_ssize_t size;
unsigned int i;
struct grub_net_card *card;
for (i = 0; i < ARRAY_SIZE (bootp_response_properties); i++)
if (grub_ieee1275_get_property_length (grub_ieee1275_chosen,
bootp_response_properties[i].name,
&size) >= 0)
break;
/* FIXME: Check that it's the right card. */
FOR_NET_CARDS (card)
{
char *bootp_response;
char *cardpath;
char *canon;
if (size < 0)
return NULL;
grub_ssize_t size = -1;
unsigned int i;
bootp_response = grub_malloc (size);
if (grub_ieee1275_get_property (grub_ieee1275_chosen,
bootp_response_properties[i].name,
bootp_response, size, 0) < 0)
return NULL;
if (card->driver != &ofdriver)
continue;
grub_memcpy (packet, bootp_response + bootp_response_properties[i].offset, sizeof (*packet));
grub_free (bootp_response);
return packet;
cardpath = ((struct grub_ofnetcard_data *) card->data)->path;
canon = grub_ieee1275_canonicalise_devname (cardpath);
if (grub_strcmp (devpath, canon) != 0)
{
grub_free (canon);
continue;
}
grub_free (canon);
for (i = 0; i < ARRAY_SIZE (bootp_response_properties); i++)
if (grub_ieee1275_get_property_length (grub_ieee1275_chosen,
bootp_response_properties[i].name,
&size) >= 0)
break;
if (size < 0)
return;
bootp_response = grub_malloc (size);
if (!bootp_response)
{
grub_print_error ();
return;
}
if (grub_ieee1275_get_property (grub_ieee1275_chosen,
bootp_response_properties[i].name,
bootp_response, size, 0) < 0)
return;
grub_net_configure_by_dhcp_ack (card->name, card, 0,
(struct grub_net_bootp_packet *)
&bootp_response
+ bootp_response_properties[i].offset,
size - bootp_response_properties[i].offset,
1, device, path);
return;
}
}
static char *
find_alias (const char *fullname)
{
char *ret = NULL;
auto int find_alias_hook (struct grub_ieee1275_devalias *alias);
int find_alias_hook (struct grub_ieee1275_devalias *alias)
{
if (grub_strcmp (alias->path, fullname) == 0)
{
ret = grub_strdup (alias->name);
return 1;
}
return 0;
}
grub_devalias_iterate (find_alias_hook);
grub_errno = GRUB_ERR_NONE;
return ret;
}
static void
grub_ofnet_findcards (void)
{
struct grub_net_card *card;
grub_ieee1275_phandle_t devhandle;
grub_net_link_level_address_t lla;
int i = 0;
auto int search_net_devices (struct grub_ieee1275_devalias *alias);
int search_net_devices (struct grub_ieee1275_devalias *alias)
{
if (!grub_strcmp (alias->type, "network"))
{
struct grub_ofnetcard_data *ofdata;
struct grub_net_card *card;
grub_ieee1275_phandle_t devhandle;
grub_net_link_level_address_t lla;
char *shortname;
ofdata = grub_malloc (sizeof (struct grub_ofnetcard_data));
if (!ofdata)
{
grub_print_error ();
return 1;
}
card = grub_zalloc (sizeof (struct grub_net_card));
if (!card)
{
grub_free (ofdata);
grub_print_error ();
return 1;
}
card = grub_malloc (sizeof (struct grub_net_card));
struct grub_ofnetcard_data *ofdata =
grub_malloc (sizeof (struct grub_ofnetcard_data));
ofdata->path = grub_strdup (alias->path);
grub_ieee1275_finddevice (ofdata->path, &devhandle);
@ -146,11 +231,19 @@ grub_ofnet_findcards (void)
if (grub_ieee1275_get_integer_property
(devhandle, "max-frame-size", &(ofdata->mtu),
sizeof (ofdata->mtu), 0))
return grub_error (GRUB_ERR_IO, "Couldn't retrieve mtu size.");
{
ofdata->mtu = 1500;
}
if (grub_ieee1275_get_property
(devhandle, "mac-address", &(lla.mac), 6, 0))
return grub_error (GRUB_ERR_IO, "Couldn't retrieve mac address.");
if (grub_ieee1275_get_property (devhandle, "mac-address",
&(lla.mac), 6, 0)
&& grub_ieee1275_get_property (devhandle, "local-mac-address",
&(lla.mac), 6, 0))
{
grub_error (GRUB_ERR_IO, "Couldn't retrieve mac address.");
grub_print_error ();
return 0;
}
lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
card->default_address = lla;
@ -158,7 +251,12 @@ grub_ofnet_findcards (void)
card->driver = NULL;
card->data = ofdata;
card->flags = 0;
card->name = grub_xasprintf ("eth%d", i++);
shortname = find_alias (alias->path);
card->name = grub_xasprintf ("ofnet_%s", shortname ? : alias->path);
card->idle_poll_delay_ms = 1;
grub_free (shortname);
card->driver = &ofdriver;
grub_net_card_register (card);
return 0;
}
@ -169,69 +267,18 @@ grub_ofnet_findcards (void)
grub_ieee1275_devices_iterate (search_net_devices);
}
static void
grub_ofnet_probecards (void)
{
struct grub_net_card *card;
struct grub_net_card_driver *driver;
struct grub_net_network_level_interface *inter;
grub_bootp_t bootp_pckt;
grub_net_network_level_address_t addr;
grub_net_network_level_netaddress_t net;
bootp_pckt = grub_getbootp ();
/* Assign correspondent driver for each device. */
FOR_NET_CARDS (card)
{
FOR_NET_CARD_DRIVERS (driver)
{
if (driver->init (card) == GRUB_ERR_NONE)
{
card->driver = driver;
if (bootp_pckt
&& grub_memcmp (bootp_pckt->chaddr, card->default_address.mac, 6) == 0)
{
addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
addr.ipv4 = bootp_pckt->yiaddr;
grub_net_add_addr ("bootp_cli_addr", card, addr,
card->default_address, 0);
FOR_NET_NETWORK_LEVEL_INTERFACES (inter)
if (grub_strcmp (inter->name, "bootp_cli_addr") == 0)
break;
net.type = addr.type;
net.ipv4.base = addr.ipv4;
net.ipv4.masksize = 24;
grub_net_add_route ("bootp-router", net, inter);
}
break;
}
}
}
grub_free (bootp_pckt);
}
GRUB_MOD_INIT(ofnet)
{
struct grub_net_card *card;
grub_getbootp = grub_getbootp_real;
grub_net_card_driver_register (&ofdriver);
grub_ofnet_findcards ();
grub_ofnet_probecards ();
FOR_NET_CARDS (card)
if (card->driver == NULL)
grub_net_card_unregister (card);
grub_ieee1275_net_config = grub_ieee1275_net_config_real;
}
GRUB_MOD_FINI(ofnet)
{
struct grub_net_card *card;
FOR_NET_CARDS (card)
if (card->driver && !grub_strcmp (card->driver->name, "ofnet"))
{
card->driver->fini (card);
card->driver = NULL;
}
grub_net_card_driver_unregister (&ofdriver);
grub_getbootp = NULL;
struct grub_net_card *card, *next;
FOR_NET_CARDS_SAFE (card, next)
if (card->driver && grub_strcmp (card->driver->name, "ofnet") == 0)
grub_net_card_unregister (card);
grub_ieee1275_net_config = 0;
}

View file

@ -1,3 +1,21 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/net/ethernet.h>
@ -8,6 +26,28 @@
#include <grub/time.h>
#include <grub/net/arp.h>
#define LLCADDRMASK 0x7f
struct etherhdr
{
grub_uint8_t dst[6];
grub_uint8_t src[6];
grub_uint16_t type;
} __attribute__ ((packed));
struct llchdr
{
grub_uint8_t dsap;
grub_uint8_t ssap;
grub_uint8_t ctrl;
} __attribute__ ((packed));
struct snaphdr
{
grub_uint8_t oui[3];
grub_uint16_t type;
} __attribute__ ((packed));
grub_err_t
send_ethernet_packet (struct grub_net_network_level_interface *inf,
struct grub_net_buff *nb,
@ -25,7 +65,15 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
grub_memcpy (eth->src, inf->hwaddress.mac, 6);
eth->type = grub_cpu_to_be16 (ethertype);
if (!inf->card->opened)
{
err = GRUB_ERR_NONE;
if (inf->card->driver->open)
err = inf->card->driver->open (inf->card);
if (err)
return err;
inf->card->opened = 1;
}
return inf->card->driver->send (inf->card, nb);
}
@ -69,10 +117,14 @@ grub_net_recv_ethernet_packet (struct grub_net_buff * nb,
{
grub_net_arp_receive (nb);
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
}
/* IP packet. */
if (type == GRUB_NET_ETHERTYPE_IP)
grub_net_recv_ip_packets (nb, card, &hwaddress);
{
grub_net_recv_ip_packets (nb, card, &hwaddress);
return GRUB_ERR_NONE;
}
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
}

View file

@ -1,482 +0,0 @@
/* pxe.c - Driver to provide access to the pxe filesystem */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/dl.h>
#include <grub/net.h>
#include <grub/mm.h>
#include <grub/file.h>
#include <grub/misc.h>
#include <grub/bufio.h>
#include <grub/env.h>
#include <grub/machine/pxe.h>
#include <grub/machine/int.h>
#include <grub/machine/memory.h>
#define SEGMENT(x) ((x) >> 4)
#define OFFSET(x) ((x) & 0xF)
#define SEGOFS(x) ((SEGMENT(x) << 16) + OFFSET(x))
#define LINEAR(x) (void *) (((x >> 16) << 4) + (x & 0xFFFF))
struct grub_pxe_bangpxe *grub_pxe_pxenv;
static grub_uint32_t grub_pxe_default_server_ip;
#if 0
static grub_uint32_t grub_pxe_default_gateway_ip;
#endif
static unsigned grub_pxe_blksize = GRUB_PXE_MIN_BLKSIZE;
static grub_uint32_t pxe_rm_entry = 0;
static grub_file_t curr_file = 0;
struct grub_pxe_data
{
grub_uint32_t packet_number;
grub_uint32_t block_size;
grub_uint32_t server_ip;
grub_uint32_t gateway_ip;
char filename[0];
};
static struct grub_pxe_bangpxe *
grub_pxe_scan (void)
{
struct grub_bios_int_registers regs;
struct grub_pxenv *pxenv;
struct grub_pxe_bangpxe *bangpxe;
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
regs.ebx = 0;
regs.ecx = 0;
regs.eax = 0x5650;
regs.es = 0;
grub_bios_interrupt (0x1a, &regs);
if ((regs.eax & 0xffff) != 0x564e)
return NULL;
pxenv = (struct grub_pxenv *) ((regs.es << 4) + (regs.ebx & 0xffff));
if (grub_memcmp (pxenv->signature, GRUB_PXE_SIGNATURE,
sizeof (pxenv->signature))
!= 0)
return NULL;
if (pxenv->version < 0x201)
return NULL;
bangpxe = (void *) ((((pxenv->pxe_ptr & 0xffff0000) >> 16) << 4)
+ (pxenv->pxe_ptr & 0xffff));
if (!bangpxe)
return NULL;
if (grub_memcmp (bangpxe->signature, GRUB_PXE_BANGPXE_SIGNATURE,
sizeof (bangpxe->signature)) != 0)
return NULL;
pxe_rm_entry = bangpxe->rm_entry;
return bangpxe;
}
static grub_err_t
grub_pxefs_dir (grub_device_t device __attribute__ ((unused)),
const char *path __attribute__ ((unused)),
int (*hook) (const char *filename,
const struct grub_dirhook_info *info)
__attribute__ ((unused)))
{
return GRUB_ERR_NONE;
}
static grub_err_t
grub_pxefs_open (struct grub_file *file, const char *name)
{
union
{
struct grub_pxenv_tftp_get_fsize c1;
struct grub_pxenv_tftp_open c2;
} c;
struct grub_pxe_data *data;
grub_file_t file_int, bufio;
data = grub_zalloc (sizeof (*data) + grub_strlen (name) + 1);
if (!data)
return grub_errno;
{
grub_net_network_level_address_t addr;
grub_net_network_level_address_t gateway;
struct grub_net_network_level_interface *interf;
grub_err_t err;
if (grub_strncmp (file->device->net->name,
"pxe,", sizeof ("pxe,") - 1) == 0
|| grub_strncmp (file->device->net->name,
"pxe:", sizeof ("pxe:") - 1) == 0)
{
err = grub_net_resolve_address (file->device->net->name
+ sizeof ("pxe,") - 1, &addr);
if (err)
{
grub_free (data);
return err;
}
}
else
{
addr.ipv4 = grub_pxe_default_server_ip;
addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
}
err = grub_net_route_address (addr, &gateway, &interf);
if (err)
{
grub_free (data);
return err;
}
data->server_ip = addr.ipv4;
data->gateway_ip = gateway.ipv4;
}
if (curr_file != 0)
{
grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c.c2, pxe_rm_entry);
curr_file = 0;
}
c.c1.server_ip = data->server_ip;
c.c1.gateway_ip = data->gateway_ip;
grub_strcpy ((char *)&c.c1.filename[0], name);
grub_pxe_call (GRUB_PXENV_TFTP_GET_FSIZE, &c.c1, pxe_rm_entry);
if (c.c1.status)
{
grub_free (data);
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
}
file->size = c.c1.file_size;
c.c2.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT);
c.c2.packet_size = grub_pxe_blksize;
grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &c.c2, pxe_rm_entry);
if (c.c2.status)
{
grub_free (data);
return grub_error (GRUB_ERR_BAD_FS, "open fails");
}
data->block_size = c.c2.packet_size;
grub_strcpy (data->filename, name);
file_int = grub_malloc (sizeof (*file_int));
if (! file_int)
{
grub_free (data);
return grub_errno;
}
file->data = data;
file->not_easily_seekable = 1;
grub_memcpy (file_int, file, sizeof (struct grub_file));
curr_file = file_int;
bufio = grub_bufio_open (file_int, data->block_size);
if (! bufio)
{
grub_free (file_int);
grub_free (data);
return grub_errno;
}
grub_memcpy (file, bufio, sizeof (struct grub_file));
return GRUB_ERR_NONE;
}
static grub_ssize_t
grub_pxefs_read (grub_file_t file, char *buf, grub_size_t len)
{
struct grub_pxenv_tftp_read c;
struct grub_pxe_data *data;
grub_uint32_t pn;
grub_uint64_t r;
data = file->data;
pn = grub_divmod64 (file->offset, data->block_size, &r);
if (r)
{
grub_error (GRUB_ERR_BAD_FS,
"read access must be aligned to packet size");
return -1;
}
if ((curr_file != file) || (data->packet_number > pn))
{
struct grub_pxenv_tftp_open o;
if (curr_file != 0)
grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &o, pxe_rm_entry);
o.server_ip = data->server_ip;
o.gateway_ip = data->gateway_ip;
grub_strcpy ((char *)&o.filename[0], data->filename);
o.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT);
o.packet_size = data->block_size;
grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &o, pxe_rm_entry);
if (o.status)
{
grub_error (GRUB_ERR_BAD_FS, "open fails");
return -1;
}
data->block_size = o.packet_size;
data->packet_number = 0;
curr_file = file;
}
c.buffer = SEGOFS (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
while (pn >= data->packet_number)
{
c.buffer_size = data->block_size;
grub_pxe_call (GRUB_PXENV_TFTP_READ, &c, pxe_rm_entry);
if (c.status)
{
grub_error (GRUB_ERR_BAD_FS, "read fails");
return -1;
}
data->packet_number++;
}
grub_memcpy (buf, (char *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, len);
return len;
}
static grub_err_t
grub_pxefs_close (grub_file_t file)
{
struct grub_pxenv_tftp_close c;
if (curr_file == file)
{
grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c, pxe_rm_entry);
curr_file = 0;
}
grub_free (file->data);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_pxefs_label (grub_device_t device __attribute ((unused)),
char **label __attribute ((unused)))
{
*label = 0;
return GRUB_ERR_NONE;
}
static struct grub_fs grub_pxefs_fs =
{
.name = "pxe",
.dir = grub_pxefs_dir,
.open = grub_pxefs_open,
.read = grub_pxefs_read,
.close = grub_pxefs_close,
.label = grub_pxefs_label,
.next = 0
};
static grub_ssize_t
grub_pxe_recv (const struct grub_net_card *dev __attribute__ ((unused)),
struct grub_net_buff *buf __attribute__ ((unused)))
{
return 0;
}
static grub_err_t
grub_pxe_send (const struct grub_net_card *dev __attribute__ ((unused)),
struct grub_net_buff *buf __attribute__ ((unused)))
{
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "not implemented");
}
struct grub_net_card_driver grub_pxe_card_driver =
{
.send = grub_pxe_send,
.recv = grub_pxe_recv
};
struct grub_net_card grub_pxe_card =
{
.driver = &grub_pxe_card_driver,
.name = "pxe"
};
void
grub_pxe_unload (void)
{
if (grub_pxe_pxenv)
{
grub_fs_unregister (&grub_pxefs_fs);
grub_net_card_unregister (&grub_pxe_card);
grub_pxe_pxenv = 0;
}
}
static void
set_ip_env (char *varname, grub_uint32_t ip)
{
char buf[GRUB_NET_MAX_STR_ADDR_LEN];
grub_net_network_level_address_t addr;
addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
addr.ipv4 = ip;
grub_net_addr_to_str (&addr, buf);
grub_env_set (varname, buf);
}
static char *
write_ip_env (grub_uint32_t *ip, const char *val)
{
char *buf;
grub_err_t err;
grub_net_network_level_address_t addr;
err = grub_net_resolve_address (val, &addr);
if (err)
return 0;
if (addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
return NULL;
/* Normalize the IP. */
buf = grub_malloc (GRUB_NET_MAX_STR_ADDR_LEN);
if (!buf)
return 0;
grub_net_addr_to_str (&addr, buf);
*ip = addr.ipv4;
return buf;
}
static char *
grub_env_write_pxe_default_server (struct grub_env_var *var
__attribute__ ((unused)),
const char *val)
{
return write_ip_env (&grub_pxe_default_server_ip, val);
}
#if 0
static char *
grub_env_write_pxe_default_gateway (struct grub_env_var *var
__attribute__ ((unused)),
const char *val)
{
return write_ip_env (&grub_pxe_default_gateway_ip, val);
}
#endif
static char *
grub_env_write_pxe_blocksize (struct grub_env_var *var __attribute__ ((unused)),
const char *val)
{
unsigned size;
char *buf;
size = grub_strtoul (val, 0, 0);
if (grub_errno)
return 0;
if (size < GRUB_PXE_MIN_BLKSIZE)
size = GRUB_PXE_MIN_BLKSIZE;
else if (size > GRUB_PXE_MAX_BLKSIZE)
size = GRUB_PXE_MAX_BLKSIZE;
buf = grub_xasprintf ("%d", size);
if (!buf)
return 0;
grub_pxe_blksize = size;
return buf;
}
GRUB_MOD_INIT(pxe)
{
struct grub_pxe_bangpxe *pxenv;
struct grub_pxenv_get_cached_info ci;
struct grub_net_bootp_packet *bp;
char *buf;
pxenv = grub_pxe_scan ();
if (! pxenv)
return;
ci.packet_type = GRUB_PXENV_PACKET_TYPE_DHCP_ACK;
ci.buffer = 0;
ci.buffer_size = 0;
grub_pxe_call (GRUB_PXENV_GET_CACHED_INFO, &ci, pxe_rm_entry);
if (ci.status)
return;
bp = LINEAR (ci.buffer);
grub_pxe_default_server_ip = bp->server_ip;
grub_pxe_pxenv = pxenv;
set_ip_env ("pxe_default_server", grub_pxe_default_server_ip);
grub_register_variable_hook ("pxe_default_server", 0,
grub_env_write_pxe_default_server);
#if 0
grub_pxe_default_gateway_ip = bp->gateway_ip;
grub_register_variable_hook ("pxe_default_gateway", 0,
grub_env_write_pxe_default_gateway);
#endif
buf = grub_xasprintf ("%d", grub_pxe_blksize);
if (buf)
grub_env_set ("pxe_blksize", buf);
grub_free (buf);
grub_register_variable_hook ("pxe_blksize", 0,
grub_env_write_pxe_blocksize);
grub_memcpy (grub_pxe_card.default_address.mac, bp->mac_addr,
bp->hw_len < sizeof (grub_pxe_card.default_address.mac)
? bp->hw_len : sizeof (grub_pxe_card.default_address.mac));
grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
grub_fs_register (&grub_pxefs_fs);
grub_net_card_register (&grub_pxe_card);
grub_net_configure_by_dhcp_ack ("pxe", &grub_pxe_card,
GRUB_NET_INTERFACE_PERMANENT
| GRUB_NET_INTERFACE_ADDRESS_IMMUTABLE
| GRUB_NET_INTERFACE_HWADDRESS_IMMUTABLE,
bp, GRUB_PXE_BOOTP_SIZE);
}
GRUB_MOD_FINI(pxe)
{
grub_pxe_unload ();
}

View file

@ -1,3 +1,21 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/net/ip.h>
#include <grub/misc.h>
#include <grub/net/arp.h>
@ -7,8 +25,32 @@
#include <grub/net/netbuff.h>
#include <grub/mm.h>
struct iphdr {
grub_uint8_t verhdrlen;
grub_uint8_t service;
grub_uint16_t len;
grub_uint16_t ident;
grub_uint16_t frags;
grub_uint8_t ttl;
grub_uint8_t protocol;
grub_uint16_t chksum;
grub_uint32_t src;
grub_uint32_t dest;
} __attribute__ ((packed)) ;
struct ip6hdr
{
grub_uint8_t version:4, priority:4;
grub_uint8_t flow_lbl[3];
grub_uint16_t payload_len;
grub_uint8_t nexthdr;
grub_uint8_t hop_limit;
grub_uint8_t saddr[16];
grub_uint8_t daddr[16];
} __attribute__ ((packed));
grub_uint16_t
ipchksum (void *ipv, int len)
grub_net_ip_chksum (void *ipv, int len)
{
grub_uint16_t *ip = (grub_uint16_t *) ipv;
grub_uint32_t sum = 0;
@ -48,7 +90,7 @@ grub_net_send_ip_packet (struct grub_net_network_level_interface * inf,
iph->dest = target->ipv4;
iph->chksum = 0;
iph->chksum = ipchksum ((void *) nb->data, sizeof (*iph));
iph->chksum = grub_net_ip_chksum ((void *) nb->data, sizeof (*iph));
/* Determine link layer target address via ARP. */
err = grub_net_arp_resolve (inf, target, &ll_target_addr);
@ -65,50 +107,49 @@ grub_net_recv_ip_packets (struct grub_net_buff * nb,
{
struct iphdr *iph = (struct iphdr *) nb->data;
grub_err_t err;
struct grub_net_network_level_interface *inf;
struct grub_net_network_level_interface *inf = NULL;
err = grub_netbuff_pull (nb, sizeof (*iph));
if (err)
return err;
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
/* DHCP needs special treatment since we don't know IP yet. */
{
if (inf->card == card
&& inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
&& inf->address.ipv4 == iph->dest
&& grub_net_hwaddr_cmp (&inf->hwaddress, hwaddress) == 0)
break;
struct udphdr *udph;
udph = (struct udphdr *) nb->data;
if (iph->protocol == IP_UDP && grub_be_to_cpu16 (udph->dst) == 68)
{
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
if (inf->card == card
&& inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV
&& grub_net_hwaddr_cmp (&inf->hwaddress, hwaddress) == 0)
{
err = grub_netbuff_pull (nb, sizeof (*udph));
if (err)
return err;
grub_net_process_dhcp (nb, inf->card);
grub_netbuff_free (nb);
}
return GRUB_ERR_NONE;
}
}
if (!inf)
{
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
{
if (inf->card == card
&& inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_PROMISC
&& inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
&& inf->address.ipv4 == iph->dest
&& grub_net_hwaddr_cmp (&inf->hwaddress, hwaddress) == 0)
break;
}
if (!inf)
{
if (iph->protocol == IP_UDP
&& grub_net_hwaddr_cmp (&card->default_address, hwaddress) == 0)
{
struct udphdr *udph;
udph = (struct udphdr *) nb->data;
err = grub_netbuff_pull (nb, sizeof (*udph));
if (err)
return err;
if (grub_be_to_cpu16 (udph->dst) == 68)
grub_net_process_dhcp (nb, card);
}
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
break;
}
}
switch (iph->protocol)
{
case IP_UDP:
return grub_net_recv_udp_packet (nb, inf);
break;
default:
grub_netbuff_free (nb);
break;

View file

@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -16,7 +16,6 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/net/udp.h>
#include <grub/net.h>
#include <grub/net/netbuff.h>
#include <grub/time.h>
@ -28,10 +27,14 @@
#include <grub/command.h>
#include <grub/env.h>
#include <grub/net/ethernet.h>
#include <grub/datetime.h>
#include <grub/loader.h>
#include <grub/bufio.h>
#include <grub/kernel.h>
GRUB_MOD_LICENSE ("GPLv3+");
char *grub_net_default_server;
struct grub_net_route
{
struct grub_net_route *next;
@ -49,20 +52,27 @@ struct grub_net_route
struct grub_net_route *grub_net_routes = NULL;
struct grub_net_network_level_interface *grub_net_network_level_interfaces = NULL;
struct grub_net_card *grub_net_cards = NULL;
struct grub_net_card_driver *grub_net_card_drivers = NULL;
struct grub_net_network_level_protocol *grub_net_network_level_protocols = NULL;
static struct grub_fs grub_net_fs;
static inline void
grub_net_network_level_interface_unregister (struct grub_net_network_level_interface *inter)
void
grub_net_card_unregister (struct grub_net_card *card)
{
*inter->prev = inter->next;
if (inter->next)
inter->next->prev = inter->prev;
inter->next = 0;
inter->prev = 0;
struct grub_net_network_level_interface *inf, *next;
FOR_NET_NETWORK_LEVEL_INTERFACES_SAFE(inf, next)
if (inf->card == card)
grub_net_network_level_interface_unregister (inf);
if (card->opened)
{
if (card->driver->close)
card->driver->close (card);
card->opened = 0;
}
grub_list_remove (GRUB_AS_LIST_P (&grub_net_cards),
GRUB_AS_LIST (card));
}
static inline void
grub_net_route_register (struct grub_net_route *route)
{
@ -117,7 +127,7 @@ match_net (const grub_net_network_level_netaddress_t *net,
return 0;
switch (net->type)
{
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_PROMISC:
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
return 0;
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
{
@ -236,8 +246,8 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf)
{
switch (target->type)
{
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_PROMISC:
grub_strcpy (buf, "promisc");
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
grub_strcpy (buf, "temporary");
return;
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
{
@ -334,6 +344,7 @@ grub_net_network_level_interface_register (struct grub_net_network_level_interfa
grub_register_variable_hook (name, 0, addr_set_env);
}
inter->card->num_ifaces++;
inter->prev = &grub_net_network_level_interfaces;
inter->next = grub_net_network_level_interfaces;
if (inter->next)
@ -343,7 +354,7 @@ grub_net_network_level_interface_register (struct grub_net_network_level_interfa
struct grub_net_network_level_interface *
grub_net_add_addr (const char *name,
const struct grub_net_card *card,
struct grub_net_card *card,
grub_net_network_level_address_t addr,
grub_net_link_level_address_t hwaddress,
grub_net_interface_flags_t flags)
@ -519,8 +530,8 @@ print_net_address (const grub_net_network_level_netaddress_t *target)
{
switch (target->type)
{
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_PROMISC:
grub_printf ("promisc\n");
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
grub_printf ("temporary\n");
break;
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
{
@ -574,9 +585,10 @@ grub_cmd_listcards (struct grub_command *cmd __attribute__ ((unused)),
struct grub_net_card *card;
FOR_NET_CARDS(card)
{
grub_printf ("%s ", card->name);
char buf[MAX_STR_HWADDR_LEN];
hwaddr_to_str (&card->default_address, buf);
grub_printf ("%s %s\n", card->name, buf);
}
grub_printf ("\n");
return GRUB_ERR_NONE;
}
@ -603,27 +615,68 @@ struct grub_net_socket *grub_net_sockets;
static grub_net_t
grub_net_open_real (const char *name)
{
const char *comma = grub_strchr (name, ',');
grub_net_app_level_t proto;
const char *protname, *server;
grub_size_t protnamelen;
if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
{
protname = "tftp";
protnamelen = sizeof ("tftp") - 1;
server = name + sizeof ("pxe:") - 1;
}
else if (grub_strcmp (name, "pxe") == 0)
{
protname = "tftp";
protnamelen = sizeof ("tftp") - 1;
server = grub_net_default_server;
}
else
{
const char *comma;
comma = grub_strchr (name, ',');
if (comma)
{
protnamelen = comma - name;
server = comma + 1;
protname = name;
}
else
{
protnamelen = grub_strlen (name);
server = grub_net_default_server;
protname = name;
}
}
if (!server)
{
grub_error (GRUB_ERR_NET_BAD_ADDRESS, "no server");
return NULL;
}
if (!comma)
comma = name + grub_strlen (name);
FOR_NET_APP_LEVEL (proto)
{
if (comma - name == (grub_ssize_t) grub_strlen (proto->name)
&& grub_memcmp (proto->name, name, comma - name) == 0)
if (grub_memcmp (proto->name, protname, protnamelen) == 0
&& proto->name[protnamelen] == 0)
{
grub_net_t ret = grub_malloc (sizeof (*ret));
grub_net_t ret = grub_zalloc (sizeof (*ret));
if (!ret)
return NULL;
ret->protocol = proto;
ret->name = grub_strdup (name);
if (!ret->name)
if (server)
{
grub_free (ret);
return NULL;
ret->server = grub_strdup (server);
if (!ret->server)
{
grub_free (ret);
return NULL;
}
}
else
ret->server = NULL;
ret->fs = &grub_net_fs;
ret->offset = 0;
ret->eof = 0;
return ret;
}
}
@ -643,73 +696,69 @@ grub_net_fs_dir (grub_device_t device, const char *path __attribute__ ((unused))
}
static grub_err_t
grub_net_fs_open (struct grub_file *file, const char *name)
grub_net_fs_open (struct grub_file *file_out, const char *name)
{
grub_err_t err;
grub_net_network_level_address_t addr;
struct grub_net_network_level_interface *inf;
grub_net_network_level_address_t gateway;
grub_net_socket_t socket;
static int port = 25300;
const char *comma;
struct grub_file *file, *bufio;
comma = grub_strchr (file->device->net->name, ',');
if (!comma)
return grub_error (GRUB_ERR_NET_BAD_ADDRESS, "no separator");
file = grub_malloc (sizeof (*file));
if (!file)
return grub_errno;
err = grub_net_resolve_address (comma + 1, &addr);
if (err)
return err;
err = grub_net_route_address (addr, &gateway, &inf);
grub_memcpy (file, file_out, sizeof (struct grub_file));
file->device->net->packs.first = NULL;
file->device->net->packs.last = NULL;
file->device->net->name = grub_strdup (name);
if (!file->device->net->name)
return grub_errno;
err = file->device->net->protocol->open (file, name);
if (err)
return err;
bufio = grub_bufio_open (file, 32768);
if (! bufio)
{
file->device->net->protocol->close (file);
grub_free (file->device->net->name);
grub_free (file);
return grub_errno;
}
socket = (grub_net_socket_t) grub_malloc (sizeof (*socket));
if (socket == NULL)
return grub_errno;
socket->inf = inf;
socket->out_nla = addr;
socket->in_port = port++;
socket->status = 0;
socket->app = file->device->net->protocol;
socket->packs.first = NULL;
socket->packs.last = NULL;
file->device->net->socket = socket;
grub_net_socket_register (socket);
err = file->device->net->protocol->open (file,name);
if (err)
goto fail;
file->not_easily_seekable = 1;
grub_memcpy (file_out, bufio, sizeof (struct grub_file));
grub_free (bufio);
return GRUB_ERR_NONE;
fail:
grub_net_socket_unregister (socket);
grub_free (socket);
return err;
}
static grub_err_t
grub_net_fs_close (grub_file_t file)
{
grub_net_socket_t sock = file->device->net->socket;
while (sock->packs.first)
while (file->device->net->packs.first)
{
grub_netbuff_free (sock->packs.first->nb);
grub_net_remove_packet (sock->packs.first);
grub_netbuff_free (file->device->net->packs.first->nb);
grub_net_remove_packet (file->device->net->packs.first);
}
grub_net_socket_unregister (sock);
grub_free (sock);
file->device->net->protocol->close (file);
grub_free (file->device->net->name);
return GRUB_ERR_NONE;
}
static void
receive_packets (struct grub_net_card *card)
{
if (card->num_ifaces == 0)
return;
if (!card->opened)
{
grub_err_t err = GRUB_ERR_NONE;
if (card->driver->open)
err = card->driver->open (card);
if (err)
{
grub_errno = GRUB_ERR_NONE;
return;
}
card->opened = 1;
}
while (1)
{
/* Maybe should be better have a fixed number of packets for each card
@ -720,6 +769,7 @@ receive_packets (struct grub_net_card *card)
if (!nb)
{
grub_print_error ();
card->last_poll = grub_get_time_ms ();
return;
}
@ -727,6 +777,7 @@ receive_packets (struct grub_net_card *card)
if (actual < 0)
{
grub_netbuff_free (nb);
card->last_poll = grub_get_time_ms ();
break;
}
grub_net_recv_ethernet_packet (nb, card);
@ -747,13 +798,27 @@ grub_net_poll_cards (unsigned time)
}
}
static void
grub_net_poll_cards_idle_real (void)
{
struct grub_net_card *card;
FOR_NET_CARDS (card)
{
grub_uint64_t ctime = grub_get_time_ms ();
if (ctime < card->last_poll
|| ctime >= card->last_poll + card->idle_poll_delay_ms)
receive_packets (card);
}
}
/* Read from the packets list*/
static grub_ssize_t
grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len)
grub_net_fs_read_real (grub_file_t file, char *buf, grub_size_t len)
{
grub_net_socket_t sock = file->device->net->socket;
grub_net_t sock = file->device->net;
struct grub_net_buff *nb;
char *ptr = buf;
char *ptr = buf;
grub_size_t amount, total = 0;
int try = 0;
while (try <= 3)
@ -767,6 +832,7 @@ grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len)
amount = len;
len -= amount;
total += amount;
file->device->net->offset += amount;
if (buf)
{
grub_memcpy (ptr, nb->data, amount);
@ -783,7 +849,7 @@ grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len)
if (!len)
return total;
}
if (sock->status == 1)
if (!sock->eof)
{
try++;
grub_net_poll_cards (200);
@ -794,454 +860,49 @@ grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len)
return total;
}
/* Read from the packets list*/
static grub_err_t
grub_net_seek_real (struct grub_file *file, grub_off_t offset)
{
grub_net_socket_t sock = file->device->net->socket;
struct grub_net_buff *nb;
grub_size_t len = offset - file->offset;
grub_size_t len = offset - file->device->net->offset;
if (!len)
return GRUB_ERR_NONE;
/* We cant seek backwards past the current packet. */
if (file->offset > offset)
{
nb = sock->packs.first->nb;
return grub_netbuff_push (nb, file->offset - offset);
if (file->device->net->offset > offset)
{
grub_err_t err;
while (file->device->net->packs.first)
{
grub_netbuff_free (file->device->net->packs.first->nb);
grub_net_remove_packet (file->device->net->packs.first);
}
file->device->net->protocol->close (file);
file->device->net->packs.first = NULL;
file->device->net->packs.last = NULL;
file->device->net->offset = 0;
file->device->net->eof = 0;
err = file->device->net->protocol->open (file, file->device->net->name);
if (err)
return err;
len = offset;
}
grub_net_fs_read (file, NULL, len);
grub_net_fs_read_real (file, NULL, len);
return GRUB_ERR_NONE;
}
static char *
grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
const char *val __attribute__ ((unused)))
static grub_ssize_t
grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len)
{
return NULL;
}
static void
set_env_limn_ro (const char *intername, const char *suffix,
char *value, grub_size_t len)
{
char c;
char varname[sizeof ("net_") + grub_strlen (intername) + sizeof ("_")
+ grub_strlen (suffix)];
grub_snprintf (varname, sizeof (varname), "net_%s_%s", intername, suffix);
c = value[len];
value[len] = 0;
grub_env_set (varname, value);
value[len] = c;
grub_register_variable_hook (varname, 0, grub_env_write_readonly);
}
static void
parse_dhcp_vendor (const char *name, void *vend, int limit)
{
grub_uint8_t *ptr, *ptr0;
ptr = ptr0 = vend;
if (grub_be_to_cpu32 (*(grub_uint32_t *) ptr) != GRUB_NET_BOOTP_RFC1048_MAGIC)
return;
ptr = ptr + sizeof (grub_uint32_t);
while (ptr - ptr0 < limit)
if (file->offset != file->device->net->offset)
{
grub_uint8_t tagtype;
grub_uint8_t taglength;
tagtype = *ptr++;
/* Pad tag. */
if (tagtype == 0)
continue;
/* End tag. */
if (tagtype == 0xff)
return;
taglength = *ptr++;
switch (tagtype)
{
case 12:
set_env_limn_ro (name, "hostname", (char *) ptr, taglength);
break;
case 15:
set_env_limn_ro (name, "domain", (char *) ptr, taglength);
break;
case 17:
set_env_limn_ro (name, "rootpath", (char *) ptr, taglength);
break;
case 18:
set_env_limn_ro (name, "extensionspath", (char *) ptr, taglength);
break;
/* If you need any other options please contact GRUB
developpement team. */
}
ptr += taglength;
grub_err_t err;
err = grub_net_seek_real (file, file->offset);
if (err)
return err;
}
}
#define OFFSET_OF(x, y) ((grub_uint8_t *)((y)->x) - (grub_uint8_t *)(y))
struct grub_net_network_level_interface *
grub_net_configure_by_dhcp_ack (const char *name,
const struct grub_net_card *card,
grub_net_interface_flags_t flags,
const struct grub_net_bootp_packet *bp,
grub_size_t size)
{
grub_net_network_level_address_t addr;
grub_net_link_level_address_t hwaddr;
struct grub_net_network_level_interface *inter;
addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
addr.ipv4 = bp->your_ip;
grub_memcpy (hwaddr.mac, bp->mac_addr,
bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len
: sizeof (hwaddr.mac));
hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
inter = grub_net_add_addr (name, card, addr, hwaddr, flags);
if (bp->gateway_ip != bp->server_ip)
{
grub_net_network_level_netaddress_t target;
grub_net_network_level_address_t gw;
char rname[grub_strlen (name) + sizeof ("_gw")];
target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
target.ipv4.base = bp->server_ip;
target.ipv4.masksize = 32;
gw.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
gw.ipv4 = bp->gateway_ip;
grub_snprintf (rname, sizeof (rname), "%s_gw", name);
grub_net_add_route_gw (rname, target, gw);
}
{
grub_net_network_level_netaddress_t target;
target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
target.ipv4.base = bp->gateway_ip;
target.ipv4.masksize = 32;
grub_net_add_route (name, target, inter);
}
if (size > OFFSET_OF (boot_file, bp))
set_env_limn_ro (name, "boot_file", (char *) bp->boot_file,
sizeof (bp->boot_file));
if (size > OFFSET_OF (server_name, bp))
set_env_limn_ro (name, "dhcp_server_name", (char *) bp->server_name,
sizeof (bp->server_name));
if (size > OFFSET_OF (vendor, bp))
parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp));
inter->dhcp_ack = grub_malloc (size);
if (inter->dhcp_ack)
{
grub_memcpy (inter->dhcp_ack, bp, size);
inter->dhcp_acklen = size;
}
else
grub_errno = GRUB_ERR_NONE;
return inter;
}
void
grub_net_process_dhcp (struct grub_net_buff *nb,
const struct grub_net_card *card)
{
char *name;
struct grub_net_network_level_interface *inf;
name = grub_xasprintf ("%s:dhcp", card->name);
if (!name)
{
grub_print_error ();
return;
}
grub_net_configure_by_dhcp_ack (name, card,
0, (const struct grub_net_bootp_packet *) nb->data,
(nb->tail - nb->data));
grub_free (name);
if (grub_errno)
grub_print_error ();
else
{
FOR_NET_NETWORK_LEVEL_INTERFACES(inf)
if (grub_memcmp (inf->name, card->name, grub_strlen (card->name)) == 0
&& grub_memcmp (inf->name + grub_strlen (card->name),
":dhcp_tmp", sizeof (":dhcp_tmp") - 1) == 0)
{
grub_net_network_level_interface_unregister (inf);
break;
}
}
}
static char
hexdigit (grub_uint8_t val)
{
if (val < 10)
return val + '0';
return val + 'a' - 10;
}
static grub_err_t
grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)),
int argc, char **args)
{
struct grub_net_network_level_interface *inter;
int num;
grub_uint8_t *ptr;
grub_uint8_t taglength;
if (argc < 4)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "4 arguments expected");
FOR_NET_NETWORK_LEVEL_INTERFACES (inter)
if (grub_strcmp (inter->name, args[1]) == 0)
break;
if (!inter)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("unrecognised interface %s"), args[1]);
if (!inter->dhcp_ack)
return grub_error (GRUB_ERR_IO, N_("no DHCP info found"));
if (inter->dhcp_acklen <= OFFSET_OF (vendor, inter->dhcp_ack))
return grub_error (GRUB_ERR_IO, N_("no DHCP options found"));
num = grub_strtoul (args[2], 0, 0);
if (grub_errno)
return grub_errno;
ptr = inter->dhcp_ack->vendor;
if (grub_be_to_cpu32 (*(grub_uint32_t *) ptr)
!= GRUB_NET_BOOTP_RFC1048_MAGIC)
return grub_error (GRUB_ERR_IO, N_("no DHCP options found"));
ptr = ptr + sizeof (grub_uint32_t);
while (1)
{
grub_uint8_t tagtype;
if (ptr >= ((grub_uint8_t *) inter->dhcp_ack) + inter->dhcp_acklen)
return grub_error (GRUB_ERR_IO, N_("no DHCP option %d found"), num);
tagtype = *ptr++;
/* Pad tag. */
if (tagtype == 0)
continue;
/* End tag. */
if (tagtype == 0xff)
return grub_error (GRUB_ERR_IO, N_("no DHCP option %d found"), num);
taglength = *ptr++;
if (tagtype == num)
break;
ptr += taglength;
}
if (grub_strcmp (args[3], "string") == 0)
{
char *val = grub_malloc (taglength + 1);
if (!val)
return grub_errno;
grub_memcpy (val, ptr, taglength);
val[taglength] = 0;
if (args[0][0] == '-' && args[0][1] == 0)
grub_printf ("%s\n", val);
else
return grub_env_set (args[0], val);
return GRUB_ERR_NONE;
}
if (grub_strcmp (args[3], "number") == 0)
{
grub_uint64_t val = 0;
int i;
for (i = 0; i < taglength; i++)
val = (val << 8) | ptr[i];
if (args[0][0] == '-' && args[0][1] == 0)
grub_printf ("%llu\n", (unsigned long long) val);
else
{
char valn[64];
grub_printf (valn, sizeof (valn), "%lld\n", (unsigned long long) val);
return grub_env_set (args[0], valn);
}
return GRUB_ERR_NONE;
}
if (grub_strcmp (args[3], "hex") == 0)
{
char *val = grub_malloc (2 * taglength + 1);
int i;
if (!val)
return grub_errno;
for (i = 0; i < taglength; i++)
{
val[2 * i] = hexdigit (ptr[i] >> 4);
val[2 * i + 1] = hexdigit (ptr[i] & 0xf);
}
val[2 * taglength] = 0;
if (args[0][0] == '-' && args[0][1] == 0)
grub_printf ("%s\n", val);
else
return grub_env_set (args[0], val);
return GRUB_ERR_NONE;
}
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"unrecognised format specification %s", args[3]);
}
static grub_err_t
grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
int argc, char **args)
{
struct grub_net_card *card;
struct grub_net_network_level_interface *ifaces;
grub_size_t ncards = 0;
unsigned j = 0;
int interval;
grub_err_t err;
FOR_NET_CARDS (card)
{
if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
continue;
ncards++;
}
ifaces = grub_zalloc (ncards * sizeof (ifaces[0]));
if (!ifaces)
return grub_errno;
j = 0;
FOR_NET_CARDS (card)
{
if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
continue;
ifaces[j].card = card;
ifaces[j].next = &ifaces[j+1];
if (j)
ifaces[j].prev = &ifaces[j-1].next;
ifaces[j].name = grub_xasprintf ("%s:dhcp_tmp", card->name);
if (!ifaces[j].name)
{
unsigned i;
for (i = 0; i < j; i++)
grub_free (ifaces[i].name);
grub_free (ifaces);
return grub_errno;
}
ifaces[j].address.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_PROMISC;
grub_memcpy (&ifaces[j].hwaddress, &card->default_address,
sizeof (ifaces[j].hwaddress));
j++;
}
ifaces[ncards - 1].next = grub_net_network_level_interfaces;
if (grub_net_network_level_interfaces)
grub_net_network_level_interfaces->prev = & ifaces[ncards - 1].next;
grub_net_network_level_interfaces = &ifaces[0];
ifaces[0].prev = &grub_net_network_level_interfaces;
for (interval = 200; interval < 10000; interval *= 2)
{
int done = 0;
for (j = 0; j < ncards; j++)
{
struct grub_net_bootp_packet *pack;
struct grub_datetime date;
grub_int32_t t;
struct grub_net_buff *nb;
struct udphdr *udph;
grub_net_network_level_address_t target;
if (!ifaces[j].prev)
continue;
nb = grub_netbuff_alloc (sizeof (*pack));
if (!nb)
return grub_errno;
err = grub_netbuff_reserve (nb, sizeof (*pack) + 64 + 128);
if (err)
return err;
err = grub_netbuff_push (nb, sizeof (*pack) + 64);
if (err)
return err;
pack = (void *) nb->data;
done = 1;
grub_memset (pack, 0, sizeof (*pack) + 64);
pack->opcode = 1;
pack->hw_type = 1;
pack->hw_len = 6;
err = grub_get_datetime (&date);
if (err || !grub_datetime2unixtime (&date, &t))
{
grub_errno = GRUB_ERR_NONE;
t = 0;
}
pack->ident = grub_cpu_to_be32 (t);
pack->seconds = 0;//grub_cpu_to_be16 (t);
grub_memcpy (&pack->mac_addr, &ifaces[j].hwaddress.mac, 6);
grub_netbuff_push (nb, sizeof (*udph));
udph = (struct udphdr *) nb->data;
udph->src = grub_cpu_to_be16 (68);
udph->dst = grub_cpu_to_be16 (67);
udph->chksum = 0;
udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
target.ipv4 = 0xffffffff;
err = grub_net_send_ip_packet (&ifaces[j], &target, nb);
if (err)
return err;
}
if (!done)
break;
grub_net_poll_cards (interval);
}
err = GRUB_ERR_NONE;
for (j = 0; j < ncards; j++)
{
if (!ifaces[j].prev)
continue;
grub_error_push ();
grub_net_network_level_interface_unregister (&ifaces[j]);
err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "couldn't configure %s",
ifaces[j].card->name);
}
return err;
}
static void
grub_grubnet_fini_real (void)
{
struct grub_net_card *card;
FOR_NET_CARDS (card)
if (card->driver)
card->driver->fini (card);
return grub_net_fs_read_real (file, buf, len);
}
static struct grub_fs grub_net_fs =
@ -1255,9 +916,32 @@ static struct grub_fs grub_net_fs =
.uuid = NULL,
.mtime = NULL,
};
static grub_err_t
grub_net_fini_hw (int noreturn __attribute__ ((unused)))
{
struct grub_net_card *card;
FOR_NET_CARDS (card)
if (card->opened)
{
if (card->driver->close)
card->driver->close (card);
card->opened = 0;
}
return GRUB_ERR_NONE;
}
static grub_err_t
grub_net_restore_hw (void)
{
return GRUB_ERR_NONE;
}
static void *fini_hnd;
static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute;
static grub_command_t cmd_lsroutes, cmd_lscards, cmd_getdhcp, cmd_bootp;
static grub_command_t cmd_dhcp, cmd_lsaddr;
static grub_command_t cmd_lsroutes, cmd_lscards;
static grub_command_t cmd_lsaddr;
GRUB_MOD_INIT(net)
{
@ -1279,24 +963,19 @@ GRUB_MOD_INIT(net)
"", N_("list network cards"));
cmd_lsaddr = grub_register_command ("net_ls_addr", grub_cmd_listaddrs,
"", N_("list network addresses"));
cmd_bootp = grub_register_command ("net_bootp", grub_cmd_bootp,
"[CARD]",
N_("perform a bootp autoconfiguration"));
cmd_dhcp = grub_register_command ("net_dhcp", grub_cmd_bootp,
"[CARD]",
N_("perform a bootp autoconfiguration"));
cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt,
N_("VAR INTERFACE NUMBER DESCRIPTION"),
N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value."));
grub_bootp_init ();
grub_fs_register (&grub_net_fs);
grub_net_open = grub_net_open_real;
grub_file_net_seek = grub_net_seek_real;
grub_grubnet_fini = grub_grubnet_fini_real;
fini_hnd = grub_loader_register_preboot_hook (grub_net_fini_hw,
grub_net_restore_hw,
GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK);
grub_net_poll_cards_idle = grub_net_poll_cards_idle_real;
}
GRUB_MOD_FINI(net)
{
grub_bootp_fini ();
grub_unregister_command (cmd_addaddr);
grub_unregister_command (cmd_deladdr);
grub_unregister_command (cmd_addroute);
@ -1304,9 +983,9 @@ GRUB_MOD_FINI(net)
grub_unregister_command (cmd_lsroutes);
grub_unregister_command (cmd_lscards);
grub_unregister_command (cmd_lsaddr);
grub_unregister_command (cmd_getdhcp);
grub_fs_unregister (&grub_net_fs);
grub_net_open = NULL;
grub_file_net_seek = NULL;
grub_grubnet_fini = NULL;
grub_net_fini_hw (0);
grub_loader_unregister_preboot_hook (fini_hnd);
grub_net_poll_cards_idle = grub_net_poll_cards_idle_real;
}

View file

@ -1,5 +1,22 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/misc.h>
#include <grub/net/tftp.h>
#include <grub/net/udp.h>
#include <grub/net/ip.h>
#include <grub/net/ethernet.h>
@ -11,6 +28,180 @@
GRUB_MOD_LICENSE ("GPLv3+");
/* IP port for the MTFTP server used for Intel's PXE */
enum
{
MTFTP_SERVER_PORT = 75,
MTFTP_CLIENT_PORT = 76,
/* IP port for the TFTP server */
TFTP_SERVER_PORT = 69
};
enum
{
TFTP_DEFAULTSIZE_PACKET = 512,
TFTP_MAX_PACKET = 1432
};
enum
{
TFTP_CODE_EOF = 1,
TFTP_CODE_MORE = 2,
TFTP_CODE_ERROR = 3,
TFTP_CODE_BOOT = 4,
TFTP_CODE_CFG = 5
};
enum
{
TFTP_RRQ = 1,
TFTP_WRQ = 2,
TFTP_DATA = 3,
TFTP_ACK = 4,
TFTP_ERROR = 5,
TFTP_OACK = 6
};
enum
{
TFTP_EUNDEF = 0, /* not defined */
TFTP_ENOTFOUND = 1, /* file not found */
TFTP_EACCESS = 2, /* access violation */
TFTP_ENOSPACE = 3, /* disk full or allocation exceeded */
TFTP_EBADOP = 4, /* illegal TFTP operation */
TFTP_EBADID = 5, /* unknown transfer ID */
TFTP_EEXISTS = 6, /* file already exists */
TFTP_ENOUSER = 7 /* no such user */
};
struct tftphdr {
grub_uint16_t opcode;
union {
grub_int8_t rrq[TFTP_DEFAULTSIZE_PACKET];
struct {
grub_uint16_t block;
grub_int8_t download[TFTP_MAX_PACKET];
} data;
struct {
grub_uint16_t block;
} ack;
struct {
grub_uint16_t errcode;
grub_int8_t errmsg[TFTP_DEFAULTSIZE_PACKET];
} err;
struct {
grub_int8_t data[TFTP_DEFAULTSIZE_PACKET+2];
} oack;
} u;
} __attribute__ ((packed)) ;
typedef struct tftp_data
{
grub_uint64_t file_size;
grub_uint64_t block;
grub_uint32_t block_size;
int have_oack;
grub_net_socket_t sock;
} *tftp_data_t;
static grub_err_t
tftp_receive (grub_net_socket_t sock __attribute__ ((unused)),
struct grub_net_buff *nb,
void *f)
{
grub_file_t file = f;
struct tftphdr *tftph = (void *) nb->data;
char nbdata[512];
tftp_data_t data = file->data;
grub_err_t err;
char *ptr;
struct grub_net_buff nb_ack;
nb_ack.head = nbdata;
nb_ack.end = nbdata + sizeof (nbdata);
tftph = (struct tftphdr *) nb->data;
switch (grub_be_to_cpu16 (tftph->opcode))
{
case TFTP_OACK:
data->block_size = TFTP_DEFAULTSIZE_PACKET;
data->have_oack = 1;
for (ptr = nb->data + sizeof (tftph->opcode); ptr < nb->tail;)
{
if (grub_memcmp (ptr, "tsize\0", sizeof ("tsize\0") - 1) == 0)
{
data->file_size = grub_strtoul (ptr + sizeof ("tsize\0") - 1,
0, 0);
}
if (grub_memcmp (ptr, "blksize\0", sizeof ("blksize\0") - 1) == 0)
{
data->block_size = grub_strtoul (ptr + sizeof ("blksize\0") - 1,
0, 0);
}
while (ptr < nb->tail && *ptr)
ptr++;
ptr++;
}
data->block = 0;
grub_netbuff_free (nb);
break;
case TFTP_DATA:
err = grub_netbuff_pull (nb, sizeof (tftph->opcode) +
sizeof (tftph->u.data.block));
if (err)
return err;
if (grub_be_to_cpu16 (tftph->u.data.block) == data->block + 1)
{
unsigned size = nb->tail - nb->data;
data->block++;
if (size < data->block_size)
{
file->device->net->eof = 1;
}
/* Prevent garbage in broken cards. */
if (size > data->block_size)
{
err = grub_netbuff_unput (nb, size - data->block_size);
if (err)
return err;
}
/* If there is data, puts packet in socket list. */
if ((nb->tail - nb->data) > 0)
grub_net_put_packet (&file->device->net->packs, nb);
else
grub_netbuff_free (nb);
}
else
{
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
}
break;
case TFTP_ERROR:
grub_netbuff_free (nb);
return grub_error (GRUB_ERR_IO, (char *) tftph->u.err.errmsg);
}
grub_netbuff_clear (&nb_ack);
grub_netbuff_reserve (&nb_ack, 512);
err = grub_netbuff_push (&nb_ack, sizeof (tftph->opcode)
+ sizeof (tftph->u.ack.block));
if (err)
return err;
tftph = (struct tftphdr *) nb_ack.data;
tftph->opcode = grub_cpu_to_be16 (TFTP_ACK);
tftph->u.ack.block = grub_cpu_to_be16 (data->block);
err = grub_net_send_udp_packet (data->sock, &nb_ack);
if (file->device->net->eof)
{
grub_net_udp_close (data->sock);
data->sock = NULL;
}
return err;
}
static grub_err_t
tftp_open (struct grub_file *file, const char *filename)
{
@ -24,17 +215,17 @@ tftp_open (struct grub_file *file, const char *filename)
tftp_data_t data;
grub_err_t err;
data = grub_malloc (sizeof (*data));
data = grub_zalloc (sizeof (*data));
if (!data)
return grub_errno;
file->device->net->socket->data = (void *) data;
nb.head = open_data;
nb.end = open_data + sizeof (open_data);
grub_netbuff_clear (&nb);
grub_netbuff_reserve (&nb, 1500);
if ((err = grub_netbuff_push (&nb, sizeof (*tftph))) != GRUB_ERR_NONE)
err = grub_netbuff_push (&nb, sizeof (*tftph));
if (err)
return err;
tftph = (struct tftphdr *) nb.data;
@ -68,111 +259,86 @@ tftp_open (struct grub_file *file, const char *filename)
rrq += grub_strlen ("0") + 1;
hdrlen = sizeof (tftph->opcode) + rrqlen;
if ((err = grub_netbuff_unput (&nb, nb.tail - (nb.data + hdrlen))) != GRUB_ERR_NONE)
return err;
file->device->net->socket->out_port = TFTP_SERVER_PORT;
err = grub_net_send_udp_packet (file->device->net->socket, &nb);
err = grub_netbuff_unput (&nb, nb.tail - (nb.data + hdrlen));
if (err)
return err;
file->not_easily_seekable = 1;
file->data = data;
data->sock = grub_net_udp_open (file->device->net->server,
TFTP_SERVER_PORT, tftp_receive,
file);
if (!data->sock)
return grub_errno;
err = grub_net_send_udp_packet (data->sock, &nb);
if (err)
{
grub_net_udp_close (data->sock);
return err;
}
/* Receive OACK packet. */
for (i = 0; i < 3; i++)
{
grub_net_poll_cards (100);
if (grub_errno)
return grub_errno;
if (file->device->net->socket->status != 0)
if (data->have_oack)
break;
/* Retry. */
/*err = grub_net_send_udp_packet (file->device->net->socket, &nb);
if (err)
return err; */
err = grub_net_send_udp_packet (data->sock, &nb);
if (err)
{
grub_net_udp_close (data->sock);
return err;
}
}
if (file->device->net->socket->status == 0)
return grub_error (GRUB_ERR_TIMEOUT, "Time out opening tftp.");
if (!data->have_oack)
{
grub_net_udp_close (data->sock);
return grub_error (GRUB_ERR_TIMEOUT, "Time out opening tftp.");
}
file->size = data->file_size;
return GRUB_ERR_NONE;
}
static grub_err_t
tftp_receive (grub_net_socket_t sock, struct grub_net_buff *nb)
tftp_close (struct grub_file *file)
{
struct tftphdr *tftph;
char nbdata[128];
tftp_data_t data = sock->data;
grub_err_t err;
char *ptr;
struct grub_net_buff nb_ack;
tftp_data_t data = file->data;
nb_ack.head = nbdata;
nb_ack.end = nbdata + sizeof (nbdata);
tftph = (struct tftphdr *) nb->data;
switch (grub_be_to_cpu16 (tftph->opcode))
if (data->sock)
{
case TFTP_OACK:
for (ptr = nb->data + sizeof (tftph->opcode); ptr < nb->tail;)
{
if (grub_memcmp (ptr, "tsize\0", sizeof ("tsize\0") - 1) == 0)
{
data->file_size = grub_strtoul (ptr + sizeof ("tsize\0") - 1,
0, 0);
}
while (ptr < nb->tail && *ptr)
ptr++;
ptr++;
}
sock->status = 1;
data->block = 0;
grub_netbuff_clear (nb);
break;
case TFTP_DATA:
if ((err = grub_netbuff_pull (nb, sizeof (tftph->opcode) +
sizeof (tftph->u.data.block))) != GRUB_ERR_NONE)
return err;
if (grub_be_to_cpu16 (tftph->u.data.block) == data->block + 1)
{
data->block++;
unsigned size = nb->tail - nb->data;
if (size < 1024)
sock->status = 2;
/* Prevent garbage in broken cards. */
if (size > 1024)
if ((err = grub_netbuff_unput (nb, size - 1024)) != GRUB_ERR_NONE)
return err;
}
else
grub_netbuff_clear (nb);
char nbdata[512];
grub_err_t err;
struct grub_net_buff nb_err;
struct tftphdr *tftph;
break;
case TFTP_ERROR:
grub_netbuff_clear (nb);
return grub_error (GRUB_ERR_IO, (char *) tftph->u.err.errmsg);
break;
nb_err.head = nbdata;
nb_err.end = nbdata + sizeof (nbdata);
grub_netbuff_clear (&nb_err);
grub_netbuff_reserve (&nb_err, 512);
err = grub_netbuff_push (&nb_err, sizeof (tftph->opcode)
+ sizeof (tftph->u.err.errcode)
+ sizeof ("closed"));
if (!err)
{
tftph = (struct tftphdr *) nb_err.data;
tftph->opcode = grub_cpu_to_be16 (TFTP_ERROR);
tftph->u.err.errcode = grub_cpu_to_be16 (TFTP_EUNDEF);
grub_memcpy (tftph->u.err.errmsg, "closed", sizeof ("closed"));
err = grub_net_send_udp_packet (data->sock, &nb_err);
}
if (err)
grub_print_error ();
grub_net_udp_close (data->sock);
}
grub_netbuff_clear (&nb_ack);
grub_netbuff_reserve (&nb_ack, 128);
err = grub_netbuff_push (&nb_ack, sizeof (tftph->opcode)
+ sizeof (tftph->u.ack.block));
if (err)
return err;
tftph = (struct tftphdr *) nb_ack.data;
tftph->opcode = grub_cpu_to_be16 (TFTP_ACK);
tftph->u.ack.block = grub_cpu_to_be16 (data->block);
err = grub_net_send_udp_packet (sock, &nb_ack);
return err;
}
static grub_err_t
tftp_close (struct grub_file *file __attribute__ ((unused)))
{
grub_free (file->device->net->socket->data);
grub_free (data);
return GRUB_ERR_NONE;
}
@ -180,7 +346,6 @@ static struct grub_net_app_protocol grub_tftp_protocol =
{
.name = "tftp",
.open = tftp_open,
.read = tftp_receive,
.close = tftp_close
};

View file

@ -4,6 +4,46 @@
#include <grub/net/netbuff.h>
#include <grub/time.h>
grub_net_socket_t
grub_net_udp_open (char *server,
grub_uint16_t out_port,
grub_err_t (*recv_hook) (grub_net_socket_t sock,
struct grub_net_buff *nb,
void *data),
void *recv_hook_data)
{
grub_err_t err;
grub_net_network_level_address_t addr;
struct grub_net_network_level_interface *inf;
grub_net_network_level_address_t gateway;
grub_net_socket_t socket;
static int in_port = 25300;
err = grub_net_resolve_address (server, &addr);
if (err)
return NULL;
err = grub_net_route_address (addr, &gateway, &inf);
if (err)
return NULL;
socket = grub_zalloc (sizeof (*socket));
if (socket == NULL)
return NULL;
socket->x_out_port = out_port;
socket->x_inf = inf;
socket->x_out_nla = addr;
socket->x_in_port = in_port++;
socket->x_status = GRUB_NET_SOCKET_START;
socket->recv_hook = recv_hook;
socket->recv_hook_data = recv_hook_data;
grub_net_socket_register (socket);
return socket;
}
grub_err_t
grub_net_send_udp_packet (const grub_net_socket_t socket,
struct grub_net_buff *nb)
@ -16,14 +56,14 @@ grub_net_send_udp_packet (const grub_net_socket_t socket,
return err;
udph = (struct udphdr *) nb->data;
udph->src = grub_cpu_to_be16 (socket->in_port);
udph->dst = grub_cpu_to_be16 (socket->out_port);
udph->src = grub_cpu_to_be16 (socket->x_in_port);
udph->dst = grub_cpu_to_be16 (socket->x_out_port);
/* No chechksum. */
udph->chksum = 0;
udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
return grub_net_send_ip_packet (socket->inf, &(socket->out_nla), nb);
return grub_net_send_ip_packet (socket->x_inf, &(socket->x_out_nla), nb);
}
grub_err_t
@ -32,30 +72,28 @@ grub_net_recv_udp_packet (struct grub_net_buff * nb,
{
struct udphdr *udph;
grub_net_socket_t sock;
grub_err_t err;
udph = (struct udphdr *) nb->data;
grub_netbuff_pull (nb, sizeof (*udph));
err = grub_netbuff_pull (nb, sizeof (*udph));
if (err)
return err;
FOR_NET_SOCKETS (sock)
{
if (grub_be_to_cpu16 (udph->dst) == sock->in_port
&& inf == sock->inf && sock->app)
if (grub_be_to_cpu16 (udph->dst) == sock->x_in_port
&& inf == sock->x_inf && sock->recv_hook)
{
if (sock->status == 0)
sock->out_port = grub_be_to_cpu16 (udph->src);
if (sock->x_status == GRUB_NET_SOCKET_START)
{
sock->x_out_port = grub_be_to_cpu16 (udph->src);
sock->x_status = GRUB_NET_SOCKET_ESTABLISHED;
}
/* App protocol remove its own reader. */
sock->app->read (sock, nb);
/* If there is data, puts packet in socket list. */
if ((nb->tail - nb->data) > 0)
grub_net_put_packet (&sock->packs, nb);
else
grub_netbuff_free (nb);
sock->recv_hook (sock, nb, sock->recv_hook_data);
return GRUB_ERR_NONE;
}
}
if (grub_be_to_cpu16 (udph->dst) == 68)
grub_net_process_dhcp (nb, inf->card);
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
}

View file

@ -84,6 +84,16 @@
{ 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
}
#define GRUB_EFI_SIMPLE_NETWORK_GUID \
{ 0xa19832b9, 0xac25, 0x11d3, \
{ 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
}
#define GRUB_EFI_PXE_GUID \
{ 0x03c4e603, 0xac28, 0x11d3, \
{ 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
}
#define GRUB_EFI_DEVICE_PATH_GUID \
{ 0x09576e91, 0x6d3f, 0x11d2, \
{ 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
@ -1113,6 +1123,36 @@ struct grub_efi_simple_text_output_interface
};
typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output_interface_t;
typedef grub_uint8_t grub_efi_pxe_packet_t[1472];
typedef struct grub_efi_pxe_mode
{
grub_uint8_t unused[52];
grub_efi_pxe_packet_t dhcp_discover;
grub_efi_pxe_packet_t dhcp_ack;
grub_efi_pxe_packet_t proxy_offer;
grub_efi_pxe_packet_t pxe_discover;
grub_efi_pxe_packet_t pxe_reply;
} grub_efi_pxe_mode_t;
typedef struct grub_efi_pxe
{
grub_uint64_t rev;
void (*start) (void);
void (*stop) (void);
void (*dhcp) (void);
void (*discover) (void);
void (*mftp) (void);
void (*udpwrite) (void);
void (*udpread) (void);
void (*setipfilter) (void);
void (*arp) (void);
void (*setparams) (void);
void (*setstationip) (void);
void (*setpackets) (void);
struct grub_efi_pxe_mode *mode;
} grub_efi_pxe_t;
#define GRUB_EFI_BLACK 0x00
#define GRUB_EFI_BLUE 0x01
#define GRUB_EFI_GREEN 0x02
@ -1214,6 +1254,74 @@ struct grub_efi_block_io_media
};
typedef struct grub_efi_block_io_media grub_efi_block_io_media_t;
typedef grub_uint8_t grub_efi_mac_t[32];
struct grub_efi_simple_network_mode
{
grub_uint32_t state;
grub_uint32_t hwaddr_size;
grub_uint32_t media_header_size;
grub_uint32_t max_packet_size;
grub_uint32_t nvram_size;
grub_uint32_t nvram_access_size;
grub_uint32_t receive_filter_mask;
grub_uint32_t receive_filter_setting;
grub_uint32_t max_mcast_filter_count;
grub_uint32_t mcast_filter_count;
grub_efi_mac_t mcast_filter[16];
grub_efi_mac_t current_address;
grub_efi_mac_t broadcast_address;
grub_efi_mac_t permanent_address;
grub_uint8_t if_type;
grub_uint8_t mac_changeable;
grub_uint8_t multitx_supported;
grub_uint8_t media_present_supported;
grub_uint8_t media_present;
};
enum
{
GRUB_EFI_NETWORK_STOPPED,
GRUB_EFI_NETWORK_STARTED,
GRUB_EFI_NETWORK_INITIALIZED,
};
struct grub_efi_simple_network
{
grub_uint64_t revision;
grub_efi_status_t (*start) (struct grub_efi_simple_network *this);
void (*stop) (void);
grub_efi_status_t (*initialize) (struct grub_efi_simple_network *this,
grub_efi_uintn_t extra_rx,
grub_efi_uintn_t extra_tx);
void (*reset) (void);
void (*shutdown) (void);
void (*receive_filters) (void);
void (*station_address) (void);
void (*statistics) (void);
void (*mcastiptomac) (void);
void (*nvdata) (void);
void (*getstatus) (void);
grub_efi_status_t (*transmit) (struct grub_efi_simple_network *this,
grub_efi_uintn_t header_size,
grub_efi_uintn_t buffer_size,
void *buffer,
grub_efi_mac_t *src_addr,
grub_efi_mac_t *dest_addr,
grub_efi_uint16_t *protocol);
grub_efi_status_t (*receive) (struct grub_efi_simple_network *this,
grub_efi_uintn_t *header_size,
grub_efi_uintn_t *buffer_size,
void *buffer,
grub_efi_mac_t *src_addr,
grub_efi_mac_t *dest_addr,
grub_uint16_t *protocol);
void (*waitforpacket) (void);
struct grub_efi_simple_network_mode *mode;
};
typedef struct grub_efi_simple_network grub_efi_simple_network_t;
struct grub_efi_block_io
{
grub_efi_uint64_t revision;
@ -1243,6 +1351,7 @@ typedef struct grub_efi_block_io grub_efi_block_io_t;
#define efi_call_4(func, a, b, c, d) func(a, b, c, d)
#define efi_call_5(func, a, b, c, d, e) func(a, b, c, d, e)
#define efi_call_6(func, a, b, c, d, e, f) func(a, b, c, d, e, f)
#define efi_call_7(func, a, b, c, d, e, f, g) func(a, b, c, d, e, f, g)
#define efi_call_10(func, a, b, c, d, e, f, g, h, i, j) func(a, b, c, d, e, f, g, h, i, j)
#else
@ -1250,24 +1359,31 @@ typedef struct grub_efi_block_io grub_efi_block_io_t;
#define efi_call_0(func) \
efi_wrap_0(func)
#define efi_call_1(func, a) \
efi_wrap_1(func, (grub_uint64_t) a)
efi_wrap_1(func, (grub_uint64_t) (a))
#define efi_call_2(func, a, b) \
efi_wrap_2(func, (grub_uint64_t) a, (grub_uint64_t) b)
efi_wrap_2(func, (grub_uint64_t) (a), (grub_uint64_t) (b))
#define efi_call_3(func, a, b, c) \
efi_wrap_3(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c)
efi_wrap_3(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \
(grub_uint64_t) (c))
#define efi_call_4(func, a, b, c, d) \
efi_wrap_4(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, \
(grub_uint64_t) d)
efi_wrap_4(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \
(grub_uint64_t) (c), (grub_uint64_t) (d))
#define efi_call_5(func, a, b, c, d, e) \
efi_wrap_5(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, \
(grub_uint64_t) d, (grub_uint64_t) e)
efi_wrap_5(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \
(grub_uint64_t) (c), (grub_uint64_t) (d), (grub_uint64_t) (e))
#define efi_call_6(func, a, b, c, d, e, f) \
efi_wrap_6(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, \
(grub_uint64_t) d, (grub_uint64_t) e, (grub_uint64_t) f)
efi_wrap_6(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \
(grub_uint64_t) (c), (grub_uint64_t) (d), (grub_uint64_t) (e), \
(grub_uint64_t) (f))
#define efi_call_7(func, a, b, c, d, e, f, g) \
efi_wrap_7(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \
(grub_uint64_t) (c), (grub_uint64_t) (d), (grub_uint64_t) (e), \
(grub_uint64_t) (f), (grub_uint64_t) (g))
#define efi_call_10(func, a, b, c, d, e, f, g, h, i, j) \
efi_wrap_10(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, \
(grub_uint64_t) d, (grub_uint64_t) e, (grub_uint64_t) f, (grub_uint64_t) g, \
(grub_uint64_t) h, (grub_uint64_t) i, (grub_uint64_t) j)
efi_wrap_10(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \
(grub_uint64_t) (c), (grub_uint64_t) (d), (grub_uint64_t) (e), \
(grub_uint64_t) (f), (grub_uint64_t) (g), (grub_uint64_t) (h), \
(grub_uint64_t) (i), (grub_uint64_t) (j))
grub_uint64_t EXPORT_FUNC(efi_wrap_0) (void *func);
grub_uint64_t EXPORT_FUNC(efi_wrap_1) (void *func, grub_uint64_t arg1);
@ -1285,6 +1401,10 @@ grub_uint64_t EXPORT_FUNC(efi_wrap_6) (void *func, grub_uint64_t arg1,
grub_uint64_t arg2, grub_uint64_t arg3,
grub_uint64_t arg4, grub_uint64_t arg5,
grub_uint64_t arg6);
grub_uint64_t EXPORT_FUNC(efi_wrap_7) (void *func, grub_uint64_t arg1,
grub_uint64_t arg2, grub_uint64_t arg3,
grub_uint64_t arg4, grub_uint64_t arg5,
grub_uint64_t arg6, grub_uint64_t arg7);
grub_uint64_t EXPORT_FUNC(efi_wrap_10) (void *func, grub_uint64_t arg1,
grub_uint64_t arg2, grub_uint64_t arg3,
grub_uint64_t arg4, grub_uint64_t arg5,

View file

@ -62,6 +62,14 @@ grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memo
grub_efi_uint32_t descriptor_version,
grub_efi_memory_descriptor_t *virtual_map);
int
EXPORT_FUNC (grub_efi_compare_device_paths) (const grub_efi_device_path_t *dp1,
const grub_efi_device_path_t *dp2);
extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd,
char **device,
char **path);
void grub_efi_mm_init (void);
void grub_efi_mm_fini (void);
void grub_efi_init (void);

View file

@ -44,6 +44,8 @@ extern grub_int32_t grub_install_bsd_part;
/* The boot BIOS drive number. */
extern grub_uint8_t EXPORT_VAR(grub_boot_drive);
extern void (*EXPORT_VAR(grub_pc_net_config)) (char **device, char **path);
#endif /* ! ASM_FILE */
#endif /* ! KERNEL_MACHINE_HEADER */

View file

@ -287,8 +287,6 @@ int EXPORT_FUNC(grub_pxe_call) (int func, void * data, grub_uint32_t pxe_rm_entr
extern struct grub_pxe_bangpxe *grub_pxe_pxenv;
void grub_pxe_unload (void);
#endif
#endif /* GRUB_CPU_PXE_H */

View file

@ -64,12 +64,9 @@ struct grub_ieee1275_common_hdr
typedef grub_uint32_t grub_ieee1275_ihandle_t;
typedef grub_uint32_t grub_ieee1275_phandle_t;
struct grub_ofnetcard_data
{
char *path;
grub_ieee1275_ihandle_t handle;
grub_uint32_t mtu;
};
extern void (*EXPORT_VAR(grub_ieee1275_net_config)) (const char *dev,
char **device,
char **path);
/* Maps a device alias to a pathname. */
extern grub_ieee1275_phandle_t EXPORT_VAR(grub_ieee1275_chosen);
@ -203,5 +200,6 @@ int EXPORT_FUNC(grub_ieee1275_devices_iterate) (int (*hook)
alias));
char *EXPORT_FUNC(grub_ieee1275_get_aliasdevname) (const char *path);
char *EXPORT_FUNC(grub_ieee1275_canonicalise_devname) (const char *path);
char *EXPORT_FUNC(grub_ieee1275_get_device_type) (const char *path);
#endif /* ! GRUB_IEEE1275_HEADER */

View file

@ -1,66 +0,0 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2007 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_OFNET_HEADER
#define GRUB_OFNET_HEADER 1
#include <grub/symbol.h>
#include <grub/err.h>
#include <grub/types.h>
struct grub_ofnet
{
/* The net name. */
const char *name;
/* The OF device string. */
char *dev;
/*server ip*/
char *sip;
/*client ip*/
char *cip;
/*gateway*/
char *gat;
/**/
int type;
};
typedef struct grub_ofnet *grub_ofnet_t;
struct grub_bootp {
grub_uint8_t op; /* 1 = BOOTREQUEST, 2 = BOOTREPLY */
grub_uint8_t htype; /* Hardware address type. */
grub_uint8_t hlen; /* Hardware address length */
grub_uint8_t hops; /* Used by gateways in cross-gateway booting. */
grub_uint32_t xid; /* Transaction ID */
grub_uint16_t secs; /* Seconds elapsed. */
grub_uint16_t unused; /* Unused. */
grub_uint32_t ciaddr; /* Client IP address, */
grub_uint32_t yiaddr; /* Client IP address filled by server. */
grub_uint32_t siaddr; /* Server IP address. */
grub_uint32_t giaddr; /* Gateway IP address. */
unsigned char chaddr [16]; /* Client hardware address */
char sname [64]; /* Server name */
char file [128]; /* Boot filename */
unsigned char vend [64];
};
typedef struct grub_bootp* grub_bootp_t;
extern grub_bootp_t (*EXPORT_VAR (grub_getbootp)) (void);
#endif /* ! GRUB_NET_HEADER */

View file

@ -84,12 +84,16 @@ void grub_machine_init (void);
void EXPORT_FUNC(grub_machine_fini) (void);
/* The machine-specific prefix initialization. */
void grub_machine_set_prefix (void);
void
grub_machine_get_bootlocation (char **device, char **path);
/* Register all the exported symbols. This is automatically generated. */
void grub_register_exported_symbols (void);
#if ! defined (ASM_FILE) && !defined (GRUB_MACHINE_EMU)
extern void (*EXPORT_VAR(grub_net_poll_cards_idle)) (void);
#if ! defined (ASM_FILE)
extern char grub_prefix[];
#endif

View file

@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -60,32 +60,14 @@ struct grub_net_card_driver
{
struct grub_net_card_driver *next;
char *name;
grub_err_t (*init) (struct grub_net_card *dev);
grub_err_t (*fini) (struct grub_net_card *dev);
grub_err_t (*open) (const struct grub_net_card *dev);
void (*close) (const struct grub_net_card *dev);
grub_err_t (*send) (const struct grub_net_card *dev,
struct grub_net_buff *buf);
grub_ssize_t (*recv) (const struct grub_net_card *dev,
struct grub_net_buff *buf);
};
extern struct grub_net_card_driver *grub_net_card_drivers;
static inline void
grub_net_card_driver_register (struct grub_net_card_driver *driver)
{
grub_list_push (GRUB_AS_LIST_P (&grub_net_card_drivers),
GRUB_AS_LIST (driver));
}
static inline void
grub_net_card_driver_unregister (struct grub_net_card_driver *driver)
{
grub_list_remove (GRUB_AS_LIST_P (&grub_net_card_drivers),
GRUB_AS_LIST (driver));
}
#define FOR_NET_CARD_DRIVERS(var) for (var = grub_net_card_drivers; var; var = var->next)
typedef struct grub_net_packet
{
struct grub_net_packet *next;
@ -100,6 +82,10 @@ typedef struct grub_net_packets
grub_net_packet_t *last;
} grub_net_packets_t;
#ifdef GRUB_MACHINE_EFI
#include <grub/efi/api.h>
#endif
struct grub_net_card
{
struct grub_net_card *next;
@ -107,8 +93,19 @@ struct grub_net_card
struct grub_net_card_driver *driver;
grub_net_link_level_address_t default_address;
grub_net_card_flags_t flags;
int num_ifaces;
int opened;
unsigned idle_poll_delay_ms;
grub_uint64_t last_poll;
union
{
#ifdef GRUB_MACHINE_EFI
struct
{
struct grub_efi_simple_network *efi_net;
grub_efi_handle_t efi_handle;
};
#endif
void *data;
int data_num;
};
@ -118,7 +115,7 @@ struct grub_net_network_level_interface;
typedef enum grub_network_level_protocol_id
{
GRUB_NET_NETWORK_LEVEL_PROTOCOL_PROMISC,
GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV,
GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
} grub_network_level_protocol_id_t;
@ -196,22 +193,23 @@ struct grub_net_app_protocol
int (*hook) (const char *filename,
const struct grub_dirhook_info *info));
grub_err_t (*open) (struct grub_file *file, const char *filename);
grub_err_t (*read) (grub_net_socket_t sock, struct grub_net_buff *nb);
grub_err_t (*close) (struct grub_file *file);
grub_err_t (*label) (grub_device_t device, char **label);
};
struct grub_net_socket
{
struct grub_net_socket *next;
int status;
int in_port;
int out_port;
grub_net_app_level_t app;
grub_net_network_level_address_t out_nla;
struct grub_net_network_level_interface *inf;
grub_net_packets_t packs;
void *data;
enum { GRUB_NET_SOCKET_START,
GRUB_NET_SOCKET_ESTABLISHED,
GRUB_NET_SOCKET_CLOSED } x_status;
int x_in_port;
int x_out_port;
grub_err_t (*recv_hook) (grub_net_socket_t sock, struct grub_net_buff *nb,
void *recv);
void *recv_hook_data;
grub_net_network_level_address_t x_out_nla;
struct grub_net_network_level_interface *x_inf;
};
extern struct grub_net_socket *grub_net_sockets;
@ -234,22 +232,23 @@ grub_net_socket_unregister (grub_net_socket_t sock)
typedef struct grub_net
{
char *server;
char *name;
grub_net_app_level_t protocol;
grub_net_socket_t socket;
grub_net_packets_t packs;
grub_off_t offset;
grub_fs_t fs;
int eof;
} *grub_net_t;
extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name);
extern grub_err_t (*EXPORT_VAR (grub_file_net_seek)) (struct grub_file *file, grub_off_t offset);
extern void (*EXPORT_VAR (grub_grubnet_fini)) (void);
struct grub_net_network_level_interface
{
struct grub_net_network_level_interface *next;
struct grub_net_network_level_interface **prev;
char *name;
const struct grub_net_card *card;
struct grub_net_card *card;
grub_net_network_level_address_t address;
grub_net_link_level_address_t hwaddress;
grub_net_interface_flags_t flags;
@ -297,7 +296,7 @@ grub_net_session_recv (struct grub_net_session *session, void *buf,
struct grub_net_network_level_interface *
grub_net_add_addr (const char *name,
const struct grub_net_card *card,
struct grub_net_card *card,
grub_net_network_level_address_t addr,
grub_net_link_level_address_t hwaddress,
grub_net_interface_flags_t flags);
@ -334,14 +333,12 @@ grub_net_card_register (struct grub_net_card *card)
GRUB_AS_LIST (card));
}
static inline void
grub_net_card_unregister (struct grub_net_card *card)
{
grub_list_remove (GRUB_AS_LIST_P (&grub_net_cards),
GRUB_AS_LIST (card));
}
void
grub_net_card_unregister (struct grub_net_card *card);
#define FOR_NET_CARDS(var) for (var = grub_net_cards; var; var = var->next)
#define FOR_NET_CARDS_SAFE(var, next) for (var = grub_net_cards, next = var->next; var; var = next, next = var->next)
struct grub_net_session *
grub_net_open_tcp (char *address, grub_uint16_t port);
@ -389,23 +386,27 @@ struct grub_net_bootp_packet
grub_uint32_t server_ip;
grub_uint32_t gateway_ip;
grub_net_bootp_mac_addr_t mac_addr;
grub_uint8_t server_name[64];
grub_uint8_t boot_file[128];
char server_name[64];
char boot_file[128];
grub_uint8_t vendor[0];
} __attribute__ ((packed));
#define GRUB_NET_BOOTP_RFC1048_MAGIC 0x63825363L
#define GRUB_NET_BOOTP_RFC1048_MAGIC_0 0x63
#define GRUB_NET_BOOTP_RFC1048_MAGIC_1 0x82
#define GRUB_NET_BOOTP_RFC1048_MAGIC_2 0x53
#define GRUB_NET_BOOTP_RFC1048_MAGIC_3 0x63
struct grub_net_network_level_interface *
grub_net_configure_by_dhcp_ack (const char *name,
const struct grub_net_card *card,
struct grub_net_card *card,
grub_net_interface_flags_t flags,
const struct grub_net_bootp_packet *bp,
grub_size_t size);
grub_size_t size,
int is_def, char **device, char **path);
void
grub_net_process_dhcp (struct grub_net_buff *nb,
const struct grub_net_card *card);
struct grub_net_card *card);
int
grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a,
@ -425,31 +426,25 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target,
extern struct grub_net_network_level_interface *grub_net_network_level_interfaces;
#define FOR_NET_NETWORK_LEVEL_INTERFACES(var) for (var = grub_net_network_level_interfaces; var; var = var->next)
grub_err_t grub_net_send_link_layer (struct grub_net_network_level_interface *inf,
struct grub_net_buff *nb,
grub_net_link_level_address_t *target);
typedef int
(*grub_net_packet_handler_t) (struct grub_net_buff *nb,
struct grub_net_network_level_interface *inf);
grub_err_t grub_net_recv_link_layer (struct grub_net_network_level_interface *inf,
grub_net_packet_handler_t handler);
grub_err_t
grub_net_recv_ip_packets (struct grub_net_buff *nb,
const struct grub_net_card *card,
const grub_net_link_level_address_t *hwaddress);
grub_err_t
grub_net_send_ip_packet (struct grub_net_network_level_interface *inf,
const grub_net_network_level_address_t *target,
struct grub_net_buff *nb);
#define FOR_NET_NL_PACKETS(inf, var) FOR_PACKETS(inf->nl_pending, var)
#define FOR_NET_NETWORK_LEVEL_INTERFACES_SAFE(var,next) for (var = grub_net_network_level_interfaces, next = var->next; var; var = next, next = var->next)
void
grub_net_poll_cards (unsigned time);
void grub_bootp_init (void);
void grub_bootp_fini (void);
static inline void
grub_net_network_level_interface_unregister (struct grub_net_network_level_interface *inter)
{
inter->card->num_ifaces--;
*inter->prev = inter->next;
if (inter->next)
inter->next->prev = inter->prev;
inter->next = 0;
inter->prev = 0;
}
extern char *grub_net_default_server;
#endif /* ! GRUB_NET_HEADER */

View file

@ -1,30 +1,26 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_NET_ETHERNET_HEADER
#define GRUB_NET_ETHERNET_HEADER 1
#include <grub/types.h>
#include <grub/net.h>
#define LLCADDRMASK 0x7f
struct etherhdr
{
grub_uint8_t dst[6];
grub_uint8_t src[6];
grub_uint16_t type;
} __attribute__ ((packed));
struct llchdr
{
grub_uint8_t dsap;
grub_uint8_t ssap;
grub_uint8_t ctrl;
} __attribute__ ((packed));
struct snaphdr
{
grub_uint8_t oui[3];
grub_uint16_t type;
} __attribute__ ((packed));
/* IANA Ethertype */
enum
{
@ -32,7 +28,6 @@ enum
GRUB_NET_ETHERTYPE_ARP = 0x0806
};
grub_err_t
send_ethernet_packet (struct grub_net_network_level_interface *inf,
struct grub_net_buff *nb,

View file

@ -1,35 +1,42 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_NET_IP_HEADER
#define GRUB_NET_IP_HEADER 1
#include <grub/misc.h>
#include <grub/net.h>
struct iphdr {
grub_uint8_t verhdrlen;
grub_uint8_t service;
grub_uint16_t len;
grub_uint16_t ident;
grub_uint16_t frags;
grub_uint8_t ttl;
grub_uint8_t protocol;
grub_uint16_t chksum;
grub_uint32_t src;
grub_uint32_t dest;
} __attribute__ ((packed)) ;
struct ip6hdr
{
grub_uint8_t version:4, priority:4;
grub_uint8_t flow_lbl[3];
grub_uint16_t payload_len;
grub_uint8_t nexthdr;
grub_uint8_t hop_limit;
grub_uint8_t saddr[16];
grub_uint8_t daddr[16];
} __attribute__ ((packed));
#define IP_UDP 0x11 /* UDP protocol */
enum
{
IP_UDP = 0x11 /* UDP protocol */
};
#define IP_BROADCAST 0xFFFFFFFF
grub_uint16_t ipchksum(void *ipv, int len);
void ipv4_ini(void);
void ipv4_fini(void);
grub_uint16_t grub_net_ip_chksum(void *ipv, int len);
grub_err_t
grub_net_recv_ip_packets (struct grub_net_buff *nb,
const struct grub_net_card *card,
const grub_net_link_level_address_t *hwaddress);
grub_err_t
grub_net_send_ip_packet (struct grub_net_network_level_interface *inf,
const grub_net_network_level_address_t *target,
struct grub_net_buff *nb);
#endif

View file

@ -1,74 +0,0 @@
#ifndef GRUB_NET_TFTP_HEADER
#define GRUB_NET_TFTP_HEADER 1
#include <grub/misc.h>
#include <grub/net/ethernet.h>
#include <grub/net/udp.h>
/* IP port for the MTFTP server used for Intel's PXE */
#define MTFTP_SERVER_PORT 75
#define MTFTP_CLIENT_PORT 76
#define TFTP_DEFAULTSIZE_PACKET 512
#define TFTP_MAX_PACKET 1432
/* IP port for the TFTP server */
#define TFTP_SERVER_PORT 69
/* We define these based on what's in arpa/tftp.h. We just like our
* names better, cause they're clearer */
#define TFTP_RRQ 1
#define TFTP_WRQ 2
#define TFTP_DATA 3
#define TFTP_ACK 4
#define TFTP_ERROR 5
#define TFTP_OACK 6
#define TFTP_CODE_EOF 1
#define TFTP_CODE_MORE 2
#define TFTP_CODE_ERROR 3
#define TFTP_CODE_BOOT 4
#define TFTP_CODE_CFG 5
#define TFTP_EUNDEF 0 /* not defined */
#define TFTP_ENOTFOUND 1 /* file not found */
#define TFTP_EACCESS 2 /* access violation */
#define TFTP_ENOSPACE 3 /* disk full or allocation exceeded */
#define TFTP_EBADOP 4 /* illegal TFTP operation */
#define TFTP_EBADID 5 /* unknown transfer ID */
#define TFTP_EEXISTS 6 /* file already exists */
#define TFTP_ENOUSER 7 /* no such user */
/* * own here because this is cleaner, and maps to the same data layout.
* */
typedef struct tftp_data
{
int file_size;
int block;
} *tftp_data_t;
struct tftphdr {
grub_uint16_t opcode;
union {
grub_int8_t rrq[TFTP_DEFAULTSIZE_PACKET];
struct {
grub_uint16_t block;
grub_int8_t download[TFTP_MAX_PACKET];
} data;
struct {
grub_uint16_t block;
} ack;
struct {
grub_uint16_t errcode;
grub_int8_t errmsg[TFTP_DEFAULTSIZE_PACKET];
} err;
struct {
grub_int8_t data[TFTP_DEFAULTSIZE_PACKET+2];
} oack;
} u;
} __attribute__ ((packed)) ;
#endif

View file

@ -11,14 +11,28 @@ struct udphdr
grub_uint16_t chksum;
} __attribute__ ((packed));
grub_net_socket_t
grub_net_udp_open (char *server,
grub_uint16_t out_port,
grub_err_t (*recv_hook) (grub_net_socket_t sock,
struct grub_net_buff *nb,
void *data),
void *recv_hook_data);
static inline void
grub_net_udp_close (grub_net_socket_t sock)
{
grub_net_socket_unregister (sock);
grub_free (sock);
}
grub_err_t
grub_net_send_udp_packet (const grub_net_socket_t socket , struct grub_net_buff *nb);
grub_net_send_udp_packet (const grub_net_socket_t socket, struct grub_net_buff *nb);
grub_err_t
grub_net_recv_udp_packet (struct grub_net_buff *nb,
struct grub_net_network_level_interface *inf);
#define FOR_NET_UDP_PACKETS(inf, var) FOR_PACKETS(inf->udp_pending, var)
#endif

View file

@ -169,8 +169,10 @@
/* Non-zero value is only needed for PowerMacs. */
#define GRUB_KERNEL_I386_IEEE1275_MOD_GAP 0x0
#define GRUB_KERNEL_I386_COREBOOT_MOD_GAP 0x0
#define GRUB_KERNEL_SPARC64_IEEE1275_MOD_GAP 0x0
#define GRUB_KERNEL_POWERPC_IEEE1275_MOD_ALIGN 0x1000
#define GRUB_KERNEL_SPARC64_IEEE1275_MOD_ALIGN 0x1
#define GRUB_KERNEL_MIPS_LOONGSON_MOD_ALIGN 0x1
#define GRUB_KERNEL_MIPS_ARC_MOD_ALIGN 0x1

View file

@ -1323,6 +1323,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[],
aout_size = core_size + sizeof (*aout_head);
aout_img = xmalloc (aout_size);
aout_head = aout_img;
grub_memset (aout_head, 0, sizeof (*aout_head));
aout_head->a_midmag = grub_host_to_target32 ((AOUT_MID_SUN << 16)
| AOUT32_OMAGIC);
aout_head->a_text = grub_host_to_target32 (core_size);

View file

@ -45,6 +45,12 @@ debug=no
debug_image=
subdir=`echo /boot/grub | sed ${transform}`
pc_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-pc
ppc_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/powerpc-ieee1275
sparc_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/sparc64-ieee1275
i386_ieee1275_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-ieee1275
efi32_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-efi
efi64_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/x86_64-efi
itanium_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/ia64-efi
# Usage: usage
# Print the usage.
@ -196,11 +202,20 @@ process_input_dir ()
config_opt="-c ${grubdir}/load.cfg "
fi
prefix="/${subdir}/${platform}";
case "${platform}" in
i386-pc) mkimage_target=i386-pc-pxe;
netmodules="pxe";
prefix="(pxe)/${subdir}/${platform}";
ext=0 ;;
sparc64-ieee1275) mkimage_target=sparc64-ieee1275-aout;
netmodules="ofnet";
ext=img ;;
*-ieee1275) mkimage_target="${platform}";
netmodules="ofnet";
ext=elf ;;
*-efi) mkimage_target="${platform}";
netmodules="efinet";
ext=efi ;;
*) echo Unsupported platform ${platform};
exit 1;;
esac
@ -209,13 +224,31 @@ process_input_dir ()
source ${subdir}/grub.cfg
EOF
$grub_mkimage ${config_opt} -d "${input_dir}" -O ${mkimage_target} --output=${grubdir}/core.$ext --prefix=$prefix $modules $netmodules || exit 1
$grub_mkimage ${config_opt} -d "${input_dir}" -O ${mkimage_target} --output=${grubdir}/core.$ext --prefix=$prefix $modules $netmodules tftp || exit 1
echo "Netboot directory for ${platform} created. Configure your DHCP server to point to ${subdir}/${platform}/core.$ext"
}
if [ "${override_dir}" = "" ] ; then
if test -e "${pc_dir}" ; then
process_input_dir ${pc_dir} i386-pc
process_input_dir "${pc_dir}" i386-pc
fi
if test -e "${ppc_dir}" ; then
process_input_dir "${ppc_dir}" powerpc-ieee1275
fi
if test -e "${sparc_dir}" ; then
process_input_dir ${sparc_dir} sparc64-ieee1275
fi
if test -e "${i386_ieee1275_dir}" ; then
process_input_dir "${i386_ieee1275_dir}" i386-ieee1275
fi
if test -e "${efi32_dir}" ; then
process_input_dir "${efi32_dir}" i386-efi
fi
if test -e "${efi64_dir}" ; then
process_input_dir "${efi64_dir}" x86_64-efi
fi
if test -e "${itanium_dir}" ; then
process_input_dir "${itanium_dir}" ia64-efi
fi
else
source "${override_dir}"/modinfo.sh