diff --git a/ChangeLog b/ChangeLog index 06b71a246..110a980f0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,194 @@ +2011-07-06 Vladimir Serbinenko + + 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 * grub-core/kern/i386/qemu/mmap.c (grub_machine_mmap_init): Use new diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 28a143413..3a085eb2c 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -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 diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 807f5b357..7bceaa98f 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -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; diff --git a/grub-core/commands/i386/pc/pxecmd.c b/grub-core/commands/i386/pc/pxecmd.c deleted file mode 100644 index dffa15a3a..000000000 --- a/grub-core/commands/i386/pc/pxecmd.c +++ /dev/null @@ -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 . - */ - -#include -#include -#include -#include -#include -#include - -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); -} diff --git a/grub-core/commands/probe.c b/grub-core/commands/probe.c index 7ed2a4e51..ce1e9aac0 100644 --- a/grub-core/commands/probe.c +++ b/grub-core/commands/probe.c @@ -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) diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c index 35602513e..07f0f6859 100644 --- a/grub-core/disk/efi/efidisk.c +++ b/grub-core/disk/efi/efidisk.c @@ -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; } diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c index 0a935d5c2..7868b14b1 100644 --- a/grub-core/disk/ieee1275/ofdisk.c +++ b/grub-core/disk/ieee1275/ofdisk.c @@ -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 diff --git a/grub-core/kern/device.c b/grub-core/kern/device.c index 45bcd8210..c998d4d4b 100644 --- a/grub-core/kern/device.c +++ b/grub-core/kern/device.c @@ -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); } diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c index 5f214e378..1841bf1f5 100644 --- a/grub-core/kern/dl.c +++ b/grub-core/kern/dl.c @@ -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; diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c index c95058733..d0994a940 100644 --- a/grub-core/kern/efi/efi.c +++ b/grub-core/kern/efi/efi.c @@ -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; +} diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c index 1b0a872b4..4dfb06284 100644 --- a/grub-core/kern/efi/init.c +++ b/grub-core/kern/efi/init.c @@ -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 diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c index 0a7645992..2092d03cb 100644 --- a/grub-core/kern/emu/main.c +++ b/grub-core/kern/emu/main.c @@ -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) diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c index 2407e72c5..f69ef6fd4 100644 --- a/grub-core/kern/file.c +++ b/grub-core/kern/file.c @@ -25,7 +25,6 @@ #include #include -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; diff --git a/grub-core/kern/i386/coreboot/init.c b/grub-core/kern/i386/coreboot/init.c index 434b9b5a8..ebbea2523 100644 --- a/grub-core/kern/i386/coreboot/init.c +++ b/grub-core/kern/i386/coreboot/init.c @@ -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 diff --git a/grub-core/kern/i386/efi/init.c b/grub-core/kern/i386/efi/init.c index f73f828c6..6bd8f3e87 100644 --- a/grub-core/kern/i386/efi/init.c +++ b/grub-core/kern/i386/efi/init.c @@ -39,9 +39,3 @@ grub_machine_fini (void) { grub_efi_fini (); } - -void -grub_machine_set_prefix (void) -{ - grub_efi_set_prefix (); -} diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c index d8c337bde..24fe8fed9 100644 --- a/grub-core/kern/i386/pc/init.c +++ b/grub-core/kern/i386/pc/init.c @@ -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) { diff --git a/grub-core/kern/ia64/efi/init.c b/grub-core/kern/ia64/efi/init.c index 6bb4219ac..e2fa58090 100644 --- a/grub-core/kern/ia64/efi/init.c +++ b/grub-core/kern/ia64/efi/init.c @@ -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) { diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c index 2fbe809b2..9e80757f4 100644 --- a/grub-core/kern/ieee1275/cmain.c +++ b/grub-core/kern/ieee1275/cmain.c @@ -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); diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c index 3c55096a4..81b06c88e 100644 --- a/grub-core/kern/ieee1275/init.c +++ b/grub-core/kern/ieee1275/init.c @@ -31,10 +31,12 @@ #include #include #include -#include #include #include #include +#ifdef __sparc__ +#include +#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 (); } diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c index db4bec90a..4e705a4d8 100644 --- a/grub-core/kern/ieee1275/openfw.c +++ b/grub-core/kern/ieee1275/openfw.c @@ -22,16 +22,14 @@ #include #include #include -#include #include -#include -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) { diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c index 447f0ae33..0cec93d89 100644 --- a/grub-core/kern/main.c +++ b/grub-core/kern/main.c @@ -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"); diff --git a/grub-core/kern/mips/init.c b/grub-core/kern/mips/init.c index bfa08f56a..353f679e6 100644 --- a/grub-core/kern/mips/init.c +++ b/grub-core/kern/mips/init.c @@ -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); } diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c index d54f3f240..ee4d58d81 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -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); diff --git a/grub-core/kern/sparc64/ieee1275/init.c b/grub-core/kern/sparc64/ieee1275/init.c deleted file mode 100644 index 72ee1f136..000000000 --- a/grub-core/kern/sparc64/ieee1275/init.c +++ /dev/null @@ -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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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 (); -} diff --git a/grub-core/kern/term.c b/grub-core/kern/term.c index 7b3593161..d7c65dd82 100644 --- a/grub-core/kern/term.c +++ b/grub-core/kern/term.c @@ -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); diff --git a/grub-core/kern/x86_64/efi/callwrap.S b/grub-core/kern/x86_64/efi/callwrap.S index aae267872..cc2c8aa05 100644 --- a/grub-core/kern/x86_64/efi/callwrap.S +++ b/grub-core/kern/x86_64/efi/callwrap.S @@ -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 diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c index fecde3282..d726f2c3a 100644 --- a/grub-core/net/arp.c +++ b/grub-core/net/arp.c @@ -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; diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c new file mode 100644 index 000000000..84bdc04d7 --- /dev/null +++ b/grub-core/net/bootp.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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); +} diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c new file mode 100644 index 000000000..5c6aac608 --- /dev/null +++ b/grub-core/net/drivers/efi/efinet.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include + +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); +} + diff --git a/grub-core/net/drivers/i386/pc/pxe.c b/grub-core/net/drivers/i386/pc/pxe.c new file mode 100644 index 000000000..cd598ea72 --- /dev/null +++ b/grub-core/net/drivers/i386/pc/pxe.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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, ®s); + + 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); +} diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c index b5bb03dc8..20d45ee3d 100644 --- a/grub-core/net/drivers/ieee1275/ofnet.c +++ b/grub-core/net/drivers/ieee1275/ofnet.c @@ -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 . + */ + #include -#include #include #include #include @@ -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; } diff --git a/grub-core/net/ethernet.c b/grub-core/net/ethernet.c index 863e659a8..acd33bcf6 100644 --- a/grub-core/net/ethernet.c +++ b/grub-core/net/ethernet.c @@ -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 . + */ + #include #include #include @@ -8,6 +26,28 @@ #include #include +#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; } diff --git a/grub-core/net/i386/pc/pxe.c b/grub-core/net/i386/pc/pxe.c deleted file mode 100644 index a23104bad..000000000 --- a/grub-core/net/i386/pc/pxe.c +++ /dev/null @@ -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 . - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#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, ®s); - - 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 (); -} diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c index 776937a6e..642a67f18 100644 --- a/grub-core/net/ip.c +++ b/grub-core/net/ip.c @@ -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 . + */ + #include #include #include @@ -7,8 +25,32 @@ #include #include +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; diff --git a/grub-core/net/net.c b/grub-core/net/net.c index 5c7d00991..0f8a60413 100644 --- a/grub-core/net/net.c +++ b/grub-core/net/net.c @@ -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 . */ -#include #include #include #include @@ -28,10 +27,14 @@ #include #include #include -#include +#include +#include +#include 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; } diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c index d0ed7c43a..be1534021 100644 --- a/grub-core/net/tftp.c +++ b/grub-core/net/tftp.c @@ -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 . + */ + #include -#include #include #include #include @@ -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 }; diff --git a/grub-core/net/udp.c b/grub-core/net/udp.c index 95134c0cf..47a67a967 100644 --- a/grub-core/net/udp.c +++ b/grub-core/net/udp.c @@ -4,6 +4,46 @@ #include #include +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; } diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h index ded03a1b3..b20baa015 100644 --- a/include/grub/efi/api.h +++ b/include/grub/efi/api.h @@ -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, diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h index e9c57dd11..e98f99507 100644 --- a/include/grub/efi/efi.h +++ b/include/grub/efi/efi.h @@ -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); diff --git a/include/grub/i386/pc/kernel.h b/include/grub/i386/pc/kernel.h index 1de37a5d5..dd50aa833 100644 --- a/include/grub/i386/pc/kernel.h +++ b/include/grub/i386/pc/kernel.h @@ -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 */ diff --git a/include/grub/i386/pc/pxe.h b/include/grub/i386/pc/pxe.h index 781b53df5..376a18962 100644 --- a/include/grub/i386/pc/pxe.h +++ b/include/grub/i386/pc/pxe.h @@ -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 */ diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h index 87294610d..81590ee4b 100644 --- a/include/grub/ieee1275/ieee1275.h +++ b/include/grub/ieee1275/ieee1275.h @@ -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 */ diff --git a/include/grub/ieee1275/ofnet.h b/include/grub/ieee1275/ofnet.h deleted file mode 100644 index c7284df38..000000000 --- a/include/grub/ieee1275/ofnet.h +++ /dev/null @@ -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 . - */ - -#ifndef GRUB_OFNET_HEADER -#define GRUB_OFNET_HEADER 1 - -#include -#include -#include - -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 */ diff --git a/include/grub/kernel.h b/include/grub/kernel.h index 2ecc73df4..aef585668 100644 --- a/include/grub/kernel.h +++ b/include/grub/kernel.h @@ -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 diff --git a/include/grub/net.h b/include/grub/net.h index 068ccec41..45d08f3f5 100644 --- a/include/grub/net.h +++ b/include/grub/net.h @@ -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 +#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 */ diff --git a/include/grub/net/device.h b/include/grub/net/device.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/include/grub/net/ethernet.h b/include/grub/net/ethernet.h index a841dc12c..a68aafd96 100644 --- a/include/grub/net/ethernet.h +++ b/include/grub/net/ethernet.h @@ -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 . + */ + #ifndef GRUB_NET_ETHERNET_HEADER #define GRUB_NET_ETHERNET_HEADER 1 #include #include -#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, diff --git a/include/grub/net/ip.h b/include/grub/net/ip.h index cb8481a7d..9bed1e19c 100644 --- a/include/grub/net/ip.h +++ b/include/grub/net/ip.h @@ -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 . + */ + #ifndef GRUB_NET_IP_HEADER #define GRUB_NET_IP_HEADER 1 #include +#include -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 diff --git a/include/grub/net/tftp.h b/include/grub/net/tftp.h deleted file mode 100644 index c67380817..000000000 --- a/include/grub/net/tftp.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef GRUB_NET_TFTP_HEADER -#define GRUB_NET_TFTP_HEADER 1 - -#include -#include -#include - -/* 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 diff --git a/include/grub/net/udp.h b/include/grub/net/udp.h index eacf3325c..5aacf8abb 100644 --- a/include/grub/net/udp.h +++ b/include/grub/net/udp.h @@ -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 diff --git a/include/grub/offsets.h b/include/grub/offsets.h index af724096d..e8170fcbe 100644 --- a/include/grub/offsets.h +++ b/include/grub/offsets.h @@ -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 diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c index 002696d07..b05507242 100644 --- a/util/grub-mkimage.c +++ b/util/grub-mkimage.c @@ -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); diff --git a/util/grub-mknetdir.in b/util/grub-mknetdir.in index 61a7ec3ad..52598a8c9 100644 --- a/util/grub-mknetdir.in +++ b/util/grub-mknetdir.in @@ -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