Network infrastructure.

The ARP protocol was made by Paulo Pinatti <ppinatti@br.ibm.com>

	* include/grub/net/arp.h: New file.
	* include/grub/net/device.h: Likewise.
	* include/grub/net/ethernet.h: Likewise.
	* include/grub/net/ip.h: Likewise.
	* include/grub/net/netbuff.h: Likewise.
	* include/grub/net/tftp.h: Likewise.
	* include/grub/net/udp.h: Likewise.
	* include/grub/ieee1275/ofnet.h: Likewise.
	* include/grub/emu/export.h: Likewise.
	* include/grub/net.h: Likewise.
	* grub-core/net/arp.c: Likewise.
	* grub-core/net/ethernet.c: Likewise.
	* grub-core/net/ip.c: Likewise.
	* grub-core/net/udp.c: Likewise.
	* grub-core/net/tftp.c: Likewise.
	* grub-core/net/netbuff.c: Likewise.
	* grub-core/net/net.c: Likewise.
	* grub-core/net/drivers/emu/emunet.c: Likewise.
	* grub-core/net/drivers/ieee1275/ofnet.c: Likewise.
	* grub-core/Makefile.am (KERNEL_HEADER_FILES): Add net.h, ofnet.h and
	export.h.
	* grub-core/Makefile.core.def (net): New module.
	(tftp): Likewise.
	(ofnet): Likewise.
	(emunet): Likewise.
	* grub-core/commands/ls.c (grub_ls_list_devices) [!GRUB_UTIL]: List
	network protocols.
	* grub-core/kern/device.c (grub_net_open) : New variable.
	(grub_device_open): Handle network device.
	(grub_device_close): Likewise.
	* grub-core/kern/file.c (grub_file_net_seek) : New variable.
	(grub_grubnet_fini): Likewise.
	(grub_file_seek): Seek in network device.
	* grub-core/kern/fs.c (grub_fs_probe): Handle network devices.
	* grub-core/kern/ieee1275/init.c (grub_machine_set_prefix): Handle
	network root.
	(grub_machine_fini): Call grub_grubnet_fini.
	* grub-core/kern/ieee1275/openfw.c (grub_ieee1275_parse_args): Handle
	network.
	(grub_ieee1275_get_aliasdevname): New function.
	* grub-core/loader/i386/multiboot_mbi.c (grub_multiboot_get_mbi_size):
	Add unofficial Solaris network info.
	(grub_multiboot_make_mbi): Likewise.
	* grub-core/fs/i386/pc/pxe.c: Moved from here ...
	* grub-core/net/i386/pc/pxe.c: ...here. Adapted for new design.
	* include/grub/device.h (grub_fs): Removed.
	* include/grub/err.h (grub_err_t): Add network-related values.
	* include/grub/i386/pc/pxe.h: Removed bootp parts.
	* include/grub/ieee1275/ieee1275.h (grub_ofnetcard_data): New struct.
	(grub_ieee1275_get_aliasdevname): New proto.
	* include/grub/net.h: Rewritten.

	Also-By: Paulo Pinatti <ppinatti@br.ibm.com>

	Also-By: Vladimir Serbinenko <phcoder@gmail.com>
This commit is contained in:
Manoel Rebelo Abranches 2011-06-24 22:16:05 +02:00 committed by Vladimir 'phcoder' Serbinenko
commit 90162423e9
35 changed files with 3447 additions and 399 deletions

View file

@ -1,3 +1,61 @@
2011-06-24 Vladimir Serbinenko <phcoder@gmail.com>
2011-06-24 Manoel Rebelo Abranches <mrabran@gmail.com>
Network infrastructure.
The ARP protocol was made by Paulo Pinatti <ppinatti@br.ibm.com>
* include/grub/net/arp.h: New file.
* include/grub/net/device.h: Likewise.
* include/grub/net/ethernet.h: Likewise.
* include/grub/net/ip.h: Likewise.
* include/grub/net/netbuff.h: Likewise.
* include/grub/net/tftp.h: Likewise.
* include/grub/net/udp.h: Likewise.
* include/grub/ieee1275/ofnet.h: Likewise.
* include/grub/emu/export.h: Likewise.
* include/grub/net.h: Likewise.
* grub-core/net/arp.c: Likewise.
* grub-core/net/ethernet.c: Likewise.
* grub-core/net/ip.c: Likewise.
* grub-core/net/udp.c: Likewise.
* grub-core/net/tftp.c: Likewise.
* grub-core/net/netbuff.c: Likewise.
* grub-core/net/net.c: Likewise.
* grub-core/net/drivers/emu/emunet.c: Likewise.
* grub-core/net/drivers/ieee1275/ofnet.c: Likewise.
* grub-core/Makefile.am (KERNEL_HEADER_FILES): Add net.h, ofnet.h and
export.h.
* grub-core/Makefile.core.def (net): New module.
(tftp): Likewise.
(ofnet): Likewise.
(emunet): Likewise.
* grub-core/commands/ls.c (grub_ls_list_devices) [!GRUB_UTIL]: List
network protocols.
* grub-core/kern/device.c (grub_net_open) : New variable.
(grub_device_open): Handle network device.
(grub_device_close): Likewise.
* grub-core/kern/file.c (grub_file_net_seek) : New variable.
(grub_grubnet_fini): Likewise.
(grub_file_seek): Seek in network device.
* grub-core/kern/fs.c (grub_fs_probe): Handle network devices.
* grub-core/kern/ieee1275/init.c (grub_machine_set_prefix): Handle
network root.
(grub_machine_fini): Call grub_grubnet_fini.
* grub-core/kern/ieee1275/openfw.c (grub_ieee1275_parse_args): Handle
network.
(grub_ieee1275_get_aliasdevname): New function.
* grub-core/loader/i386/multiboot_mbi.c (grub_multiboot_get_mbi_size):
Add unofficial Solaris network info.
(grub_multiboot_make_mbi): Likewise.
* grub-core/fs/i386/pc/pxe.c: Moved from here ...
* grub-core/net/i386/pc/pxe.c: ...here. Adapted for new design.
* include/grub/device.h (grub_fs): Removed.
* include/grub/err.h (grub_err_t): Add network-related values.
* include/grub/i386/pc/pxe.h: Removed bootp parts.
* include/grub/ieee1275/ieee1275.h (grub_ofnetcard_data): New struct.
(grub_ieee1275_get_aliasdevname): New proto.
* include/grub/net.h: Rewritten.
2011-06-24 Vladimir Serbinenko <phcoder@gmail.com> 2011-06-24 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/disk/raid.c (insert_array): Ensure uniqueness of readable * grub-core/disk/raid.c (insert_array): Ensure uniqueness of readable

View file

@ -79,6 +79,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/net.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h
@ -112,6 +113,7 @@ endif
if COND_i386_ieee1275 if COND_i386_ieee1275
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h 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/terminfo.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
@ -171,6 +173,7 @@ endif
if COND_powerpc_ieee1275 if COND_powerpc_ieee1275
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h 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/terminfo.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
@ -178,6 +181,7 @@ endif
if COND_sparc64_ieee1275 if COND_sparc64_ieee1275
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h 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/sparc64/ieee1275/ieee1275.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.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/extcmd.h
@ -187,6 +191,7 @@ endif
if COND_emu if COND_emu
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/datetime.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/datetime.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/misc.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/misc.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/export.h
if COND_GRUB_EMU_SDL if COND_GRUB_EMU_SDL
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sdl.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sdl.h
endif endif

View file

@ -1100,7 +1100,7 @@ module = {
module = { module = {
name = pxe; name = pxe;
i386_pc = fs/i386/pc/pxe.c; i386_pc = net/i386/pc/pxe.c;
enable = i386_pc; enable = i386_pc;
}; };
@ -1571,6 +1571,33 @@ module = {
common = hook/datehook.c; common = hook/datehook.c;
}; };
module = {
name = net;
common = net/net.c;
common = net/ip.c;
common = net/udp.c;
common = net/ethernet.c;
common = net/arp.c;
common = net/netbuff.c;
};
module = {
name = tftp;
common = net/tftp.c;
};
module = {
name = ofnet;
ieee1275 = net/drivers/ieee1275/ofnet.c;
enable = ieee1275;
};
module = {
name = emunet;
emu = net/drivers/emu/emunet.c;
enable = emu;
};
module = { module = {
name = legacycfg; name = legacycfg;
common = commands/legacycfg.c; common = commands/legacycfg.c;

View file

@ -31,6 +31,7 @@
#include <grub/extcmd.h> #include <grub/extcmd.h>
#include <grub/datetime.h> #include <grub/datetime.h>
#include <grub/i18n.h> #include <grub/i18n.h>
#include <grub/net.h>
GRUB_MOD_LICENSE ("GPLv3+"); GRUB_MOD_LICENSE ("GPLv3+");
@ -60,6 +61,22 @@ grub_ls_list_devices (int longlist)
grub_device_iterate (grub_ls_print_devices); grub_device_iterate (grub_ls_print_devices);
grub_xputs ("\n"); grub_xputs ("\n");
#ifndef GRUB_UTIL
{
grub_net_app_level_t proto;
int first = 1;
FOR_NET_APP_LEVEL (proto)
{
if (first)
grub_puts_ (N_ ("Network protocols:"));
first = 0;
grub_printf ("%s ", proto->name);
}
grub_xputs ("\n");
}
#endif
grub_refresh (); grub_refresh ();
return 0; return 0;

View file

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

View file

@ -26,6 +26,8 @@
#include <grub/env.h> #include <grub/env.h>
#include <grub/partition.h> #include <grub/partition.h>
grub_net_t (*grub_net_open) (const char *name) = NULL;
grub_device_t grub_device_t
grub_device_open (const char *name) grub_device_open (const char *name)
{ {
@ -46,14 +48,18 @@ grub_device_open (const char *name)
if (! dev) if (! dev)
goto fail; goto fail;
dev->net = NULL;
/* Try to open a disk. */ /* Try to open a disk. */
disk = grub_disk_open (name); dev->disk = grub_disk_open (name);
if (! disk) if (dev->disk)
goto fail; return dev;
if (grub_net_open && grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
dev->disk = disk; {
dev->net = 0; /* FIXME */ grub_errno = GRUB_ERR_NONE;
dev->net = grub_net_open (name);
}
if (dev->net)
return dev; return dev;
fail: fail:
@ -71,6 +77,12 @@ grub_device_close (grub_device_t device)
if (device->disk) if (device->disk)
grub_disk_close (device->disk); grub_disk_close (device->disk);
if (device->net)
{
grub_free (device->net->name);
grub_free (device->net);
}
grub_free (device); grub_free (device);
return grub_errno; return grub_errno;

View file

@ -20,10 +20,14 @@
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/err.h> #include <grub/err.h>
#include <grub/file.h> #include <grub/file.h>
#include <grub/net.h>
#include <grub/mm.h> #include <grub/mm.h>
#include <grub/fs.h> #include <grub/fs.h>
#include <grub/device.h> #include <grub/device.h>
grub_err_t (*grub_file_net_seek) (struct grub_file *file, grub_off_t offset) = NULL;
void (*EXPORT_VAR (grub_grubnet_fini)) (void);
grub_file_filter_t grub_file_filters_all[GRUB_FILE_FILTER_MAX]; grub_file_filter_t grub_file_filters_all[GRUB_FILE_FILTER_MAX];
grub_file_filter_t grub_file_filters_enabled[GRUB_FILE_FILTER_MAX]; grub_file_filter_t grub_file_filters_enabled[GRUB_FILE_FILTER_MAX];
@ -148,7 +152,6 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len)
if (len == 0) if (len == 0)
return 0; return 0;
res = (file->fs->read) (file, buf, len); res = (file->fs->read) (file, buf, len);
if (res > 0) if (res > 0)
file->offset += res; file->offset += res;
@ -180,7 +183,11 @@ grub_file_seek (grub_file_t file, grub_off_t offset)
return -1; return -1;
} }
if (file->device->net && grub_file_net_seek)
grub_file_net_seek (file, offset);
old = file->offset; old = file->offset;
file->offset = offset; file->offset = offset;
return old; return old;
} }

View file

@ -94,7 +94,7 @@ grub_fs_probe (grub_device_t device)
count--; count--;
} }
} }
else if (device->net->fs) else if (device->net && device->net->fs)
return device->net->fs; return device->net->fs;
grub_error (GRUB_ERR_UNKNOWN_FS, "unknown filesystem"); grub_error (GRUB_ERR_UNKNOWN_FS, "unknown filesystem");

View file

@ -31,6 +31,8 @@
#include <grub/ieee1275/console.h> #include <grub/ieee1275/console.h>
#include <grub/ieee1275/ofdisk.h> #include <grub/ieee1275/ofdisk.h>
#include <grub/ieee1275/ieee1275.h> #include <grub/ieee1275/ieee1275.h>
#include <grub/ieee1275/ofnet.h>
#include <grub/net.h>
#include <grub/offsets.h> #include <grub/offsets.h>
#include <grub/memory.h> #include <grub/memory.h>
@ -74,6 +76,21 @@ grub_machine_set_prefix (void)
char bootpath[64]; /* XXX check length */ char bootpath[64]; /* XXX check length */
char *filename; char *filename;
char *prefix; 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]) if (grub_prefix[0])
{ {
@ -247,6 +264,8 @@ grub_machine_init (void)
void void
grub_machine_fini (void) grub_machine_fini (void)
{ {
if (grub_grubnet_fini)
grub_grubnet_fini ();
grub_ofdisk_fini (); grub_ofdisk_fini ();
grub_console_fini (); grub_console_fini ();
} }

View file

@ -22,11 +22,16 @@
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/mm.h> #include <grub/mm.h>
#include <grub/ieee1275/ieee1275.h> #include <grub/ieee1275/ieee1275.h>
#include <grub/ieee1275/ofnet.h>
#include <grub/net.h>
#include <grub/net/tftp.h>
grub_bootp_t (*grub_getbootp) (void);
enum grub_ieee1275_parse_type enum grub_ieee1275_parse_type
{ {
GRUB_PARSE_FILENAME, GRUB_PARSE_FILENAME,
GRUB_PARSE_PARTITION, GRUB_PARSE_PARTITION,
GRUB_PARSE_DEVICE
}; };
/* Walk children of 'devpath', calling hook for each. */ /* Walk children of 'devpath', calling hook for each. */
@ -366,12 +371,14 @@ grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype)
ret = grub_strndup (args, (grub_size_t)(comma - args)); ret = grub_strndup (args, (grub_size_t)(comma - args));
} }
} }
else if (!grub_strcmp ("network", type))
{
if (ptype == GRUB_PARSE_DEVICE)
ret = grub_strdup(device);
}
else else
{ {
/* XXX Handle net devices by configuring & registering a grub_net_dev
here, then return its name?
Example path: "net:<server ip>,<file name>,<client ip>,<gateway
ip>,<bootp retries>,<tftp retries>". */
grub_printf ("Unsupported type %s for device %s\n", type, device); grub_printf ("Unsupported type %s for device %s\n", type, device);
} }
@ -381,6 +388,12 @@ fail:
return ret; return ret;
} }
char *
grub_ieee1275_get_aliasdevname (const char *path)
{
return grub_ieee1275_parse_args (path, GRUB_PARSE_DEVICE);
}
char * char *
grub_ieee1275_get_filename (const char *path) grub_ieee1275_get_filename (const char *path)
{ {
@ -467,3 +480,4 @@ grub_ieee1275_canonicalise_devname (const char *path)
grub_free (buf); grub_free (buf);
return NULL; return NULL;
} }

View file

@ -33,6 +33,7 @@
#include <grub/relocator.h> #include <grub/relocator.h>
#include <grub/video.h> #include <grub/video.h>
#include <grub/file.h> #include <grub/file.h>
#include <grub/net.h>
/* The bits in the required part of flags field we don't support. */ /* The bits in the required part of flags field we don't support. */
#define UNSUPPORTED_FLAGS 0x0000fff8 #define UNSUPPORTED_FLAGS 0x0000fff8
@ -194,7 +195,10 @@ grub_multiboot_load (grub_file_t file)
static grub_size_t static grub_size_t
grub_multiboot_get_mbi_size (void) grub_multiboot_get_mbi_size (void)
{ {
return sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4) grub_size_t ret;
struct grub_net_network_level_interface *net;
ret = sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4)
+ modcnt * sizeof (struct multiboot_mod_list) + total_modcmd + modcnt * sizeof (struct multiboot_mod_list) + total_modcmd
+ ALIGN_UP (sizeof(PACKAGE_STRING), 4) + ALIGN_UP (sizeof(PACKAGE_STRING), 4)
+ grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry) + grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry)
@ -205,6 +209,15 @@ grub_multiboot_get_mbi_size (void)
+ sizeof (struct grub_vbe_mode_info_block) + sizeof (struct grub_vbe_mode_info_block)
#endif #endif
+ ALIGN_UP (sizeof (struct multiboot_apm_info), 4); + ALIGN_UP (sizeof (struct multiboot_apm_info), 4);
FOR_NET_NETWORK_LEVEL_INTERFACES(net)
if (net->dhcp_ack)
{
ret += net->dhcp_acklen;
break;
}
return ret;
} }
/* Fill previously allocated Multiboot mmap. */ /* Fill previously allocated Multiboot mmap. */
@ -530,6 +543,20 @@ grub_multiboot_make_mbi (grub_uint32_t *target)
mbi->flags |= MULTIBOOT_INFO_BOOTDEV; mbi->flags |= MULTIBOOT_INFO_BOOTDEV;
} }
{
struct grub_net_network_level_interface *net;
FOR_NET_NETWORK_LEVEL_INTERFACES(net)
if (net->dhcp_ack)
{
grub_memcpy (ptrorig, net->dhcp_ack, net->dhcp_acklen);
mbi->drives_addr = ptrdest;
mbi->drives_length = net->dhcp_acklen;
ptrorig += net->dhcp_acklen;
ptrdest += net->dhcp_acklen;
break;
}
}
if (elf_sec_num) if (elf_sec_num)
{ {
mbi->u.elf_sec.addr = ptrdest; mbi->u.elf_sec.addr = ptrdest;

166
grub-core/net/arp.c Normal file
View file

@ -0,0 +1,166 @@
#include <grub/net/arp.h>
#include <grub/net/netbuff.h>
#include <grub/mm.h>
#include <grub/net.h>
#include <grub/net/ethernet.h>
#include <grub/net/ip.h>
#include <grub/time.h>
static struct arp_entry arp_table[10];
static grub_int8_t new_table_entry = -1;
static void
arp_init_table (void)
{
grub_memset (arp_table, 0, sizeof (arp_table));
new_table_entry = 0;
}
static struct arp_entry *
arp_find_entry (const grub_net_network_level_address_t *proto)
{
unsigned i;
for (i = 0; i < ARRAY_SIZE (arp_table); i++)
{
if (arp_table[i].avail == 1 &&
arp_table[i].nl_address.ipv4 == proto->ipv4)
return &(arp_table[i]);
}
return NULL;
}
grub_err_t
grub_net_arp_resolve (struct grub_net_network_level_interface *inf,
const grub_net_network_level_address_t *proto_addr,
grub_net_link_level_address_t *hw_addr)
{
struct arp_entry *entry;
struct grub_net_buff nb;
struct arphdr *arp_header;
grub_net_link_level_address_t target_hw_addr;
char *aux, arp_data[128];
grub_err_t err;
int i;
if (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
&& proto_addr->ipv4 == 0xffffffff)
{
hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
grub_memset (hw_addr->mac, -1, 6);
return GRUB_ERR_NONE;
}
/* Check cache table. */
entry = arp_find_entry (proto_addr);
if (entry)
{
*hw_addr = entry->ll_address;
return GRUB_ERR_NONE;
}
/* Build a request packet. */
nb.head = arp_data;
nb.end = arp_data + sizeof (arp_data);
grub_netbuff_clear (&nb);
grub_netbuff_reserve (&nb, 128);
err = grub_netbuff_push (&nb, sizeof (*arp_header) + 2 * (6 + 4));
if (err)
return err;
arp_header = (struct arphdr *) nb.data;
arp_header->hrd = grub_cpu_to_be16 (GRUB_NET_ARPHRD_ETHERNET);
arp_header->pro = grub_cpu_to_be16 (GRUB_NET_ETHERTYPE_IP);
/* FIXME Add support to ipv6 address. */
arp_header->hln = 6;
arp_header->pln = 4;
arp_header->op = grub_cpu_to_be16 (ARP_REQUEST);
aux = (char *) arp_header + sizeof (*arp_header);
/* Sender hardware address. */
grub_memcpy (aux, &inf->hwaddress.mac, 6);
aux += 6;
/* Sender protocol address */
grub_memcpy (aux, &inf->address.ipv4, 4);
aux += 4;
/* Target hardware address */
for (i = 0; i < 6; i++)
aux[i] = 0x00;
aux += 6;
/* Target protocol address */
grub_memcpy (aux, &proto_addr->ipv4, 4);
grub_memset (&target_hw_addr.mac, 0xff, 6);
send_ethernet_packet (inf, &nb, target_hw_addr, GRUB_NET_ETHERTYPE_ARP);
for (i = 0; i < 3; i++)
{
entry = arp_find_entry (proto_addr);
if (entry)
{
grub_memcpy (hw_addr, &entry->ll_address, sizeof (*hw_addr));
return GRUB_ERR_NONE;
}
grub_net_poll_cards (200);
}
return grub_error (GRUB_ERR_TIMEOUT, "timeout: could not resolve hardware address");
}
grub_err_t
grub_net_arp_receive (struct grub_net_buff *nb)
{
struct arphdr *arp_header = (struct arphdr *) nb->data;
struct arp_entry *entry;
grub_uint8_t *sender_hardware_address, *sender_protocol_address;
grub_uint8_t *target_hardware_address, *target_protocol_address;
grub_net_network_level_address_t hwaddress;
struct grub_net_network_level_interface *inf;
sender_hardware_address =
(grub_uint8_t *) arp_header + sizeof (*arp_header);
sender_protocol_address = sender_hardware_address + arp_header->hln;
target_hardware_address = sender_protocol_address + arp_header->pln;
target_protocol_address = target_hardware_address + arp_header->hln;
grub_memcpy (&hwaddress.ipv4, sender_protocol_address, 4);
/* Check if the sender is in the cache table. */
entry = arp_find_entry (&hwaddress);
/* Update sender hardware address. */
if (entry)
grub_memcpy (entry->ll_address.mac, sender_hardware_address, 6);
else
{
/* Add sender to cache table. */
if (new_table_entry == -1)
arp_init_table ();
entry = &(arp_table[new_table_entry]);
entry->avail = 1;
grub_memcpy (&entry->nl_address.ipv4, sender_protocol_address, 4);
grub_memcpy (entry->ll_address.mac, sender_hardware_address, 6);
new_table_entry++;
if (new_table_entry == ARRAY_SIZE (arp_table))
new_table_entry = 0;
}
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
{
/* Am I the protocol address target? */
if (grub_memcmp (target_protocol_address, &inf->address.ipv4, 6) == 0
&& grub_be_to_cpu16 (arp_header->op) == ARP_REQUEST)
{
grub_net_link_level_address_t aux;
/* Swap hardware fields */
grub_memcpy (target_hardware_address, sender_hardware_address,
arp_header->hln);
grub_memcpy (sender_hardware_address, inf->hwaddress.mac, 6);
grub_memcpy (aux.mac, sender_protocol_address, 6);
grub_memcpy (sender_protocol_address, target_protocol_address,
arp_header->pln);
grub_memcpy (target_protocol_address, aux.mac, arp_header->pln);
/* Change operation to REPLY and send packet */
arp_header->op = grub_be_to_cpu16 (ARP_REPLY);
grub_memcpy (aux.mac, target_hardware_address, 6);
send_ethernet_packet (inf, nb, aux, GRUB_NET_ETHERTYPE_ARP);
}
}
return GRUB_ERR_NONE;
}

View file

@ -0,0 +1,86 @@
#include <grub/dl.h>
#include <grub/net/netbuff.h>
#include <sys/socket.h>
#include <grub/net.h>
#include <sys/types.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <grub/term.h>
static int fd;
static grub_err_t
send_card_buffer (const struct grub_net_card *dev __attribute__ ((unused)),
struct grub_net_buff *pack)
{
ssize_t actual;
actual = write (fd, pack->data, pack->tail - pack->data);
if (actual < 0)
return grub_error (GRUB_ERR_IO, "couldn't send packets");
return GRUB_ERR_NONE;
}
static grub_ssize_t
get_card_packet (const struct grub_net_card *dev __attribute__ ((unused)),
struct grub_net_buff *pack)
{
ssize_t actual;
grub_netbuff_clear (pack);
actual = read (fd, pack->data, 1500);
if (actual < 0)
return -1;
grub_netbuff_put (pack, actual);
return actual;
}
static struct grub_net_card_driver emudriver =
{
.name = "emu",
.send = send_card_buffer,
.recv = get_card_packet
};
static struct grub_net_card emucard =
{
.name = "emu0",
.driver = &emudriver,
.default_address = {
.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET,
{.mac = {0, 1, 2, 3, 4, 5}}
},
.flags = 0
};
GRUB_MOD_INIT(emunet)
{
struct ifreq ifr;
fd = open ("/dev/net/tun", O_RDWR | O_NONBLOCK);
if (fd < 0)
return;
grub_memset (&ifr, 0, sizeof (ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
if (ioctl (fd, TUNSETIFF, &ifr) < 0)
{
close (fd);
fd = -1;
return;
}
grub_net_card_register (&emucard);
}
GRUB_MOD_FINI(emunet)
{
if (fd >= 0)
{
close (fd);
grub_net_card_unregister (&emucard);
}
}

View file

@ -0,0 +1,237 @@
#include <grub/net/netbuff.h>
#include <grub/ieee1275/ofnet.h>
#include <grub/ieee1275/ieee1275.h>
#include <grub/dl.h>
#include <grub/net.h>
#include <grub/time.h>
GRUB_MOD_LICENSE ("GPLv3+");
static grub_err_t
card_open (struct grub_net_card *dev)
{
int status;
struct grub_ofnetcard_data *data = dev->data;
char path[grub_strlen (data->path) +
grub_strlen (":speed=auto,duplex=auto,1.1.1.1,dummy,1.1.1.1,1.1.1.1,5,5,1.1.1.1,512") + 1];
/* The full string will prevent a bootp packet to be sent. Just put some valid ip in there. */
grub_snprintf (path, sizeof (path), "%s%s", data->path,
":speed=auto,duplex=auto,1.1.1.1,dummy,1.1.1.1,1.1.1.1,5,5,1.1.1.1,512");
status = grub_ieee1275_open (path, &(data->handle));
if (status)
return grub_error (GRUB_ERR_IO, "Couldn't open network card.");
return GRUB_ERR_NONE;
}
static grub_err_t
card_close (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
send_card_buffer (struct grub_net_card *dev, struct grub_net_buff *pack)
{
int actual;
int status;
struct grub_ofnetcard_data *data = dev->data;
status = grub_ieee1275_write (data->handle, pack->data,
pack->tail - pack->data, &actual);
if (status)
return grub_error (GRUB_ERR_IO, "Couldn't send network packet.");
return GRUB_ERR_NONE;
}
static grub_ssize_t
get_card_packet (struct grub_net_card *dev, struct grub_net_buff *nb)
{
int actual, rc;
struct grub_ofnetcard_data *data = dev->data;
grub_uint64_t start_time;
grub_netbuff_clear (nb);
start_time = grub_get_time_ms ();
do
rc = grub_ieee1275_read (data->handle, nb->data, data->mtu, &actual);
while ((actual <= 0 || rc < 0) && (grub_get_time_ms () - start_time < 200));
if (actual)
{
grub_netbuff_put (nb, actual);
return actual;
}
return -1;
}
static struct grub_net_card_driver ofdriver =
{
.name = "ofnet",
.init = card_open,
.fini = card_close,
.send = send_card_buffer,
.recv = get_card_packet
};
static const struct
{
char *name;
int offset;
}
bootp_response_properties[] =
{
{ .name = "bootp-response", .offset = 0},
{ .name = "dhcp-response", .offset = 0},
{ .name = "bootpreply-packet", .offset = 0x2a},
};
static grub_bootp_t
grub_getbootp_real (void)
{
grub_bootp_t packet = grub_malloc (sizeof *packet);
char *bootp_response;
grub_ssize_t size;
unsigned int i;
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 NULL;
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;
grub_memcpy (packet, bootp_response + bootp_response_properties[i].offset, sizeof (*packet));
grub_free (bootp_response);
return packet;
}
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"))
{
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);
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.");
if (grub_ieee1275_get_property
(devhandle, "mac-address", &(lla.mac), 6, 0))
return grub_error (GRUB_ERR_IO, "Couldn't retrieve mac address.");
lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
card->default_address = lla;
card->driver = NULL;
card->data = ofdata;
card->flags = 0;
card->name = grub_xasprintf ("eth%d", i++);
grub_net_card_register (card);
return 0;
}
return 0;
}
/* Look at all nodes for devices of the type network. */
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_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;
}

78
grub-core/net/ethernet.c Normal file
View file

@ -0,0 +1,78 @@
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/net/ethernet.h>
#include <grub/net/ip.h>
#include <grub/net/arp.h>
#include <grub/net/netbuff.h>
#include <grub/net.h>
#include <grub/time.h>
#include <grub/net/arp.h>
grub_err_t
send_ethernet_packet (struct grub_net_network_level_interface *inf,
struct grub_net_buff *nb,
grub_net_link_level_address_t target_addr,
grub_uint16_t ethertype)
{
struct etherhdr *eth;
grub_err_t err;
err = grub_netbuff_push (nb, sizeof (*eth));
if (err)
return err;
eth = (struct etherhdr *) nb->data;
grub_memcpy (eth->dst, target_addr.mac, 6);
grub_memcpy (eth->src, inf->hwaddress.mac, 6);
eth->type = grub_cpu_to_be16 (ethertype);
return inf->card->driver->send (inf->card, nb);
}
grub_err_t
grub_net_recv_ethernet_packet (struct grub_net_buff * nb,
const struct grub_net_card * card)
{
struct etherhdr *eth;
struct llchdr *llch;
struct snaphdr *snaph;
grub_uint16_t type;
grub_net_link_level_address_t hwaddress;
grub_err_t err;
eth = (struct etherhdr *) nb->data;
type = grub_be_to_cpu16 (eth->type);
err = grub_netbuff_pull (nb, sizeof (*eth));
if (err)
return err;
if (type <= 1500)
{
llch = (struct llchdr *) nb->data;
type = llch->dsap & LLCADDRMASK;
if (llch->dsap == 0xaa && llch->ssap == 0xaa && llch->ctrl == 0x3)
{
err = grub_netbuff_pull (nb, sizeof (*llch));
if (err)
return err;
snaph = (struct snaphdr *) nb->data;
type = snaph->type;
}
}
hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
grub_memcpy (hwaddress.mac, eth->dst, sizeof (hwaddress.mac));
/* ARP packet. */
if (type == GRUB_NET_ETHERTYPE_ARP)
{
grub_net_arp_receive (nb);
grub_netbuff_free (nb);
}
/* IP packet. */
if (type == GRUB_NET_ETHERTYPE_IP)
grub_net_recv_ip_packets (nb, card, &hwaddress);
return GRUB_ERR_NONE;
}

View file

@ -18,9 +18,8 @@
*/ */
#include <grub/dl.h> #include <grub/dl.h>
#include <grub/fs.h> #include <grub/net.h>
#include <grub/mm.h> #include <grub/mm.h>
#include <grub/disk.h>
#include <grub/file.h> #include <grub/file.h>
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/bufio.h> #include <grub/bufio.h>
@ -30,35 +29,29 @@
#include <grub/machine/int.h> #include <grub/machine/int.h>
#include <grub/machine/memory.h> #include <grub/machine/memory.h>
GRUB_MOD_LICENSE ("GPLv3+");
#define SEGMENT(x) ((x) >> 4) #define SEGMENT(x) ((x) >> 4)
#define OFFSET(x) ((x) & 0xF) #define OFFSET(x) ((x) & 0xF)
#define SEGOFS(x) ((SEGMENT(x) << 16) + OFFSET(x)) #define SEGOFS(x) ((SEGMENT(x) << 16) + OFFSET(x))
#define LINEAR(x) (void *) (((x >> 16) << 4) + (x & 0xFFFF)) #define LINEAR(x) (void *) (((x >> 16) << 4) + (x & 0xFFFF))
struct grub_pxe_disk_data
{
grub_uint32_t server_ip;
grub_uint32_t gateway_ip;
};
struct grub_pxe_bangpxe *grub_pxe_pxenv; struct grub_pxe_bangpxe *grub_pxe_pxenv;
static grub_uint32_t grub_pxe_your_ip;
static grub_uint32_t grub_pxe_default_server_ip; static grub_uint32_t grub_pxe_default_server_ip;
#if 0
static grub_uint32_t grub_pxe_default_gateway_ip; static grub_uint32_t grub_pxe_default_gateway_ip;
#endif
static unsigned grub_pxe_blksize = GRUB_PXE_MIN_BLKSIZE; static unsigned grub_pxe_blksize = GRUB_PXE_MIN_BLKSIZE;
static grub_uint32_t pxe_rm_entry = 0;
static grub_file_t curr_file = 0; static grub_file_t curr_file = 0;
struct grub_pxe_data struct grub_pxe_data
{ {
grub_uint32_t packet_number; grub_uint32_t packet_number;
grub_uint32_t block_size; grub_uint32_t block_size;
grub_uint32_t server_ip;
grub_uint32_t gateway_ip;
char filename[0]; char filename[0];
}; };
static grub_uint32_t pxe_rm_entry = 0;
static struct grub_pxe_bangpxe * static struct grub_pxe_bangpxe *
grub_pxe_scan (void) grub_pxe_scan (void)
@ -103,132 +96,13 @@ grub_pxe_scan (void)
return bangpxe; return bangpxe;
} }
static int
grub_pxe_iterate (int (*hook) (const char *name))
{
if (hook ("pxe"))
return 1;
return 0;
}
static grub_err_t static grub_err_t
parse_ip (const char *val, grub_uint32_t *ip, const char **rest) grub_pxefs_dir (grub_device_t device __attribute__ ((unused)),
{
grub_uint32_t newip = 0;
unsigned long t;
int i;
const char *ptr = val;
for (i = 0; i < 4; i++)
{
t = grub_strtoul (ptr, (char **) &ptr, 0);
if (grub_errno)
return grub_errno;
if (t & ~0xff)
return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP.");
newip >>= 8;
newip |= (t << 24);
if (i != 3 && *ptr != '.')
return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP.");
ptr++;
}
*ip = newip;
if (rest)
*rest = ptr - 1;
return 0;
}
static grub_err_t
grub_pxe_open (const char *name, grub_disk_t disk)
{
struct grub_pxe_disk_data *data;
if (grub_strcmp (name, "pxe") != 0
&& grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) != 0)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a pxe disk");
data = grub_malloc (sizeof (*data));
if (!data)
return grub_errno;
if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
{
const char *ptr;
grub_err_t err;
ptr = name + sizeof ("pxe:") - 1;
err = parse_ip (ptr, &(data->server_ip), &ptr);
if (err)
return err;
if (*ptr == ':')
{
err = parse_ip (ptr + 1, &(data->gateway_ip), 0);
if (err)
return err;
}
else
data->gateway_ip = grub_pxe_default_gateway_ip;
}
else
{
data->server_ip = grub_pxe_default_server_ip;
data->gateway_ip = grub_pxe_default_gateway_ip;
}
disk->total_sectors = 0;
disk->id = (unsigned long) data;
disk->data = data;
return GRUB_ERR_NONE;
}
static void
grub_pxe_close (grub_disk_t disk)
{
grub_free (disk->data);
}
static grub_err_t
grub_pxe_read (grub_disk_t disk __attribute((unused)),
grub_disk_addr_t sector __attribute((unused)),
grub_size_t size __attribute((unused)),
char *buf __attribute((unused)))
{
return GRUB_ERR_OUT_OF_RANGE;
}
static grub_err_t
grub_pxe_write (grub_disk_t disk __attribute((unused)),
grub_disk_addr_t sector __attribute((unused)),
grub_size_t size __attribute((unused)),
const char *buf __attribute((unused)))
{
return GRUB_ERR_OUT_OF_RANGE;
}
static struct grub_disk_dev grub_pxe_dev =
{
.name = "pxe",
.id = GRUB_DISK_DEVICE_PXE_ID,
.iterate = grub_pxe_iterate,
.open = grub_pxe_open,
.close = grub_pxe_close,
.read = grub_pxe_read,
.write = grub_pxe_write,
.next = 0
};
static grub_err_t
grub_pxefs_dir (grub_device_t device,
const char *path __attribute__ ((unused)), const char *path __attribute__ ((unused)),
int (*hook) (const char *filename, int (*hook) (const char *filename,
const struct grub_dirhook_info *info) const struct grub_dirhook_info *info)
__attribute__ ((unused))) __attribute__ ((unused)))
{ {
if (device->disk->dev->id != GRUB_DISK_DEVICE_PXE_ID)
return grub_error (GRUB_ERR_BAD_FS, "not a pxe disk");
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
@ -241,11 +115,45 @@ grub_pxefs_open (struct grub_file *file, const char *name)
struct grub_pxenv_tftp_open c2; struct grub_pxenv_tftp_open c2;
} c; } c;
struct grub_pxe_data *data; struct grub_pxe_data *data;
struct grub_pxe_disk_data *disk_data = file->device->disk->data;
grub_file_t file_int, bufio; grub_file_t file_int, bufio;
if (file->device->disk->dev->id != GRUB_DISK_DEVICE_PXE_ID) data = grub_zalloc (sizeof (*data) + grub_strlen (name) + 1);
return grub_error (GRUB_ERR_BAD_FS, "not a pxe disk"); 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) if (curr_file != 0)
{ {
@ -253,12 +161,15 @@ grub_pxefs_open (struct grub_file *file, const char *name)
curr_file = 0; curr_file = 0;
} }
c.c1.server_ip = disk_data->server_ip; c.c1.server_ip = data->server_ip;
c.c1.gateway_ip = disk_data->gateway_ip; c.c1.gateway_ip = data->gateway_ip;
grub_strcpy ((char *)&c.c1.filename[0], name); grub_strcpy ((char *)&c.c1.filename[0], name);
grub_pxe_call (GRUB_PXENV_TFTP_GET_FSIZE, &c.c1, pxe_rm_entry); grub_pxe_call (GRUB_PXENV_TFTP_GET_FSIZE, &c.c1, pxe_rm_entry);
if (c.c1.status) if (c.c1.status)
{
grub_free (data);
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
}
file->size = c.c1.file_size; file->size = c.c1.file_size;
@ -266,11 +177,10 @@ grub_pxefs_open (struct grub_file *file, const char *name)
c.c2.packet_size = grub_pxe_blksize; c.c2.packet_size = grub_pxe_blksize;
grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &c.c2, pxe_rm_entry); grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &c.c2, pxe_rm_entry);
if (c.c2.status) if (c.c2.status)
{
grub_free (data);
return grub_error (GRUB_ERR_BAD_FS, "open fails"); return grub_error (GRUB_ERR_BAD_FS, "open fails");
}
data = grub_zalloc (sizeof (struct grub_pxe_data) + grub_strlen (name) + 1);
if (! data)
return grub_errno;
data->block_size = c.c2.packet_size; data->block_size = c.c2.packet_size;
grub_strcpy (data->filename, name); grub_strcpy (data->filename, name);
@ -305,7 +215,6 @@ grub_pxefs_read (grub_file_t file, char *buf, grub_size_t len)
{ {
struct grub_pxenv_tftp_read c; struct grub_pxenv_tftp_read c;
struct grub_pxe_data *data; struct grub_pxe_data *data;
struct grub_pxe_disk_data *disk_data = file->device->disk->data;
grub_uint32_t pn; grub_uint32_t pn;
grub_uint64_t r; grub_uint64_t r;
@ -326,8 +235,8 @@ grub_pxefs_read (grub_file_t file, char *buf, grub_size_t len)
if (curr_file != 0) if (curr_file != 0)
grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &o, pxe_rm_entry); grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &o, pxe_rm_entry);
o.server_ip = disk_data->server_ip; o.server_ip = data->server_ip;
o.gateway_ip = disk_data->gateway_ip; o.gateway_ip = data->gateway_ip;
grub_strcpy ((char *)&o.filename[0], data->filename); grub_strcpy ((char *)&o.filename[0], data->filename);
o.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT); o.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT);
o.packet_size = data->block_size; o.packet_size = data->block_size;
@ -386,7 +295,7 @@ grub_pxefs_label (grub_device_t device __attribute ((unused)),
static struct grub_fs grub_pxefs_fs = static struct grub_fs grub_pxefs_fs =
{ {
.name = "pxefs", .name = "pxe",
.dir = grub_pxefs_dir, .dir = grub_pxefs_dir,
.open = grub_pxefs_open, .open = grub_pxefs_open,
.read = grub_pxefs_read, .read = grub_pxefs_read,
@ -395,134 +304,31 @@ static struct grub_fs grub_pxefs_fs =
.next = 0 .next = 0
}; };
static char * static grub_ssize_t
grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)), grub_pxe_recv (struct grub_net_card *dev __attribute__ ((unused)),
const char *val __attribute__ ((unused))) struct grub_net_buff *buf __attribute__ ((unused)))
{ {
return NULL; return 0;
} }
static void static grub_err_t
set_mac_env (grub_uint8_t *mac_addr, grub_size_t mac_len) grub_pxe_send (struct grub_net_card *dev __attribute__ ((unused)),
struct grub_net_buff *buf __attribute__ ((unused)))
{ {
char buf[(sizeof ("XX:") - 1) * mac_len + 1]; return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "not implemented");
char *ptr = buf;
unsigned i;
for (i = 0; i < mac_len; i++)
{
grub_snprintf (ptr, sizeof (buf) - (ptr - buf),
"%02x:", mac_addr[i] & 0xff);
ptr += (sizeof ("XX:") - 1);
}
if (mac_len)
*(ptr - 1) = 0;
else
buf[0] = 0;
grub_env_set ("net_pxe_mac", buf);
/* XXX: Is it possible to change MAC in PXE? */
grub_register_variable_hook ("net_pxe_mac", 0, grub_env_write_readonly);
grub_env_export ("net_pxe_mac");
} }
static void struct grub_net_card_driver grub_pxe_card_driver =
set_env_limn_ro (const char *varname, char *value, grub_size_t len)
{ {
char c; .send = grub_pxe_send,
c = value[len]; .recv = grub_pxe_recv
value[len] = 0; };
grub_env_set (varname, value);
value[len] = c;
grub_register_variable_hook (varname, 0, grub_env_write_readonly);
grub_env_export (varname);
}
static void struct grub_net_card grub_pxe_card =
parse_dhcp_vendor (void *vend, int limit)
{ {
grub_uint8_t *ptr, *ptr0; .driver = &grub_pxe_card_driver,
.name = "pxe"
ptr = ptr0 = vend; };
if (grub_be_to_cpu32 (*(grub_uint32_t *) ptr) != 0x63825363)
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 ("net_pxe_hostname", (char *) ptr, taglength);
break;
case 15:
set_env_limn_ro ("net_pxe_domain", (char *) ptr, taglength);
break;
case 17:
set_env_limn_ro ("net_pxe_rootpath", (char *) ptr, taglength);
break;
case 18:
set_env_limn_ro ("net_pxe_extensionspath", (char *) ptr, taglength);
break;
/* If you need any other options please contact GRUB
development team. */
}
ptr += taglength;
}
}
static void
grub_pxe_detect (void)
{
struct grub_pxe_bangpxe *pxenv;
struct grub_pxenv_get_cached_info ci;
struct grub_pxenv_boot_player *bp;
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_your_ip = bp->your_ip;
grub_pxe_default_server_ip = bp->server_ip;
grub_pxe_default_gateway_ip = bp->gateway_ip;
set_mac_env (bp->mac_addr, bp->hw_len < sizeof (bp->mac_addr) ? bp->hw_len
: sizeof (bp->mac_addr));
set_env_limn_ro ("net_pxe_boot_file", (char *) bp->boot_file,
sizeof (bp->boot_file));
set_env_limn_ro ("net_pxe_dhcp_server_name", (char *) bp->server_name,
sizeof (bp->server_name));
parse_dhcp_vendor (&bp->vendor, sizeof (bp->vendor));
grub_pxe_pxenv = pxenv;
}
void void
grub_pxe_unload (void) grub_pxe_unload (void)
@ -530,8 +336,7 @@ grub_pxe_unload (void)
if (grub_pxe_pxenv) if (grub_pxe_pxenv)
{ {
grub_fs_unregister (&grub_pxefs_fs); grub_fs_unregister (&grub_pxefs_fs);
grub_disk_dev_unregister (&grub_pxe_dev); grub_net_card_unregister (&grub_pxe_card);
grub_pxe_pxenv = 0; grub_pxe_pxenv = 0;
} }
} }
@ -539,10 +344,12 @@ grub_pxe_unload (void)
static void static void
set_ip_env (char *varname, grub_uint32_t ip) set_ip_env (char *varname, grub_uint32_t ip)
{ {
char buf[sizeof ("XXX.XXX.XXX.XXX")]; 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_snprintf (buf, sizeof (buf), "%d.%d.%d.%d", (ip & 0xff), grub_net_addr_to_str (&addr, buf);
(ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff);
grub_env_set (varname, buf); grub_env_set (varname, buf);
} }
@ -551,19 +358,21 @@ write_ip_env (grub_uint32_t *ip, const char *val)
{ {
char *buf; char *buf;
grub_err_t err; grub_err_t err;
grub_uint32_t newip; grub_net_network_level_address_t addr;
err = parse_ip (val, &newip, 0); err = grub_net_resolve_address (val, &addr);
if (err) if (err)
return 0; return 0;
if (addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
return NULL;
/* Normalize the IP. */ /* Normalize the IP. */
buf = grub_xasprintf ("%d.%d.%d.%d", (newip & 0xff), (newip >> 8) & 0xff, buf = grub_malloc (GRUB_NET_MAX_STR_ADDR_LEN);
(newip >> 16) & 0xff, (newip >> 24) & 0xff);
if (!buf) if (!buf)
return 0; return 0;
grub_net_addr_to_str (&addr, buf);
*ip = newip; *ip = addr.ipv4;
return buf; return buf;
} }
@ -576,6 +385,7 @@ grub_env_write_pxe_default_server (struct grub_env_var *var
return write_ip_env (&grub_pxe_default_server_ip, val); return write_ip_env (&grub_pxe_default_server_ip, val);
} }
#if 0
static char * static char *
grub_env_write_pxe_default_gateway (struct grub_env_var *var grub_env_write_pxe_default_gateway (struct grub_env_var *var
__attribute__ ((unused)), __attribute__ ((unused)),
@ -583,6 +393,7 @@ grub_env_write_pxe_default_gateway (struct grub_env_var *var
{ {
return write_ip_env (&grub_pxe_default_gateway_ip, val); return write_ip_env (&grub_pxe_default_gateway_ip, val);
} }
#endif
static char * static char *
grub_env_write_pxe_blocksize (struct grub_env_var *var __attribute__ ((unused)), grub_env_write_pxe_blocksize (struct grub_env_var *var __attribute__ ((unused)),
@ -609,42 +420,60 @@ grub_env_write_pxe_blocksize (struct grub_env_var *var __attribute__ ((unused)),
return buf; return buf;
} }
GRUB_MOD_INIT(pxe) GRUB_MOD_INIT(pxe)
{ {
grub_pxe_detect (); struct grub_pxe_bangpxe *pxenv;
if (grub_pxe_pxenv) struct grub_pxenv_get_cached_info ci;
{ struct grub_net_bootp_ack *bp;
char *buf; 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); buf = grub_xasprintf ("%d", grub_pxe_blksize);
if (buf) if (buf)
grub_env_set ("pxe_blksize", buf); grub_env_set ("pxe_blksize", buf);
grub_free (buf); grub_free (buf);
set_ip_env ("pxe_default_server", grub_pxe_default_server_ip);
set_ip_env ("pxe_default_gateway", grub_pxe_default_gateway_ip);
set_ip_env ("net_pxe_ip", grub_pxe_your_ip);
grub_register_variable_hook ("pxe_default_server", 0,
grub_env_write_pxe_default_server);
grub_register_variable_hook ("pxe_default_gateway", 0,
grub_env_write_pxe_default_gateway);
/* XXX: Is it possible to change IP in PXE? */
grub_register_variable_hook ("net_pxe_ip", 0,
grub_env_write_readonly);
grub_register_variable_hook ("pxe_blksize", 0, grub_register_variable_hook ("pxe_blksize", 0,
grub_env_write_pxe_blocksize); grub_env_write_pxe_blocksize);
grub_env_export ("pxe_default_server"); grub_memcpy (grub_pxe_card.default_address.mac, bp->mac_addr,
grub_env_export ("pxe_default_gateway"); bp->hw_len < sizeof (grub_pxe_card.default_address.mac)
grub_env_export ("net_pxe_ip"); ? bp->hw_len : sizeof (grub_pxe_card.default_address.mac));
grub_env_export ("pxe_blksize"); grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
grub_disk_dev_register (&grub_pxe_dev);
grub_fs_register (&grub_pxefs_fs); 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_MOD_FINI(pxe)

118
grub-core/net/ip.c Normal file
View file

@ -0,0 +1,118 @@
#include <grub/net/ip.h>
#include <grub/misc.h>
#include <grub/net/arp.h>
#include <grub/net/udp.h>
#include <grub/net/ethernet.h>
#include <grub/net.h>
#include <grub/net/netbuff.h>
#include <grub/mm.h>
grub_uint16_t
ipchksum (void *ipv, int len)
{
grub_uint16_t *ip = (grub_uint16_t *) ipv;
grub_uint32_t sum = 0;
len >>= 1;
while (len--)
{
sum += grub_be_to_cpu16 (*(ip++));
if (sum > 0xFFFF)
sum -= 0xFFFF;
}
return grub_cpu_to_be16 ((~sum) & 0x0000FFFF);
}
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)
{
struct iphdr *iph;
static int id = 0x2400;
grub_net_link_level_address_t ll_target_addr;
grub_err_t err;
grub_netbuff_push (nb, sizeof (*iph));
iph = (struct iphdr *) nb->data;
iph->verhdrlen = ((4 << 4) | 5);
iph->service = 0;
iph->len = grub_cpu_to_be16 (nb->tail - nb->data);
iph->ident = grub_cpu_to_be16 (++id);
iph->frags = 0;
iph->ttl = 0xff;
iph->protocol = 0x11;
iph->src = inf->address.ipv4;
iph->dest = target->ipv4;
iph->chksum = 0;
iph->chksum = ipchksum ((void *) nb->data, sizeof (*iph));
/* Determine link layer target address via ARP. */
err = grub_net_arp_resolve (inf, target, &ll_target_addr);
if (err)
return err;
return send_ethernet_packet (inf, nb, ll_target_addr,
GRUB_NET_ETHERTYPE_IP);
}
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)
{
struct iphdr *iph = (struct iphdr *) nb->data;
grub_err_t err;
struct grub_net_network_level_interface *inf;
err = grub_netbuff_pull (nb, sizeof (*iph));
if (err)
return err;
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
{
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;
}
if (!inf)
{
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
if (inf->card == card
&& inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_PROMISC
&& 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;
}
switch (iph->protocol)
{
case IP_UDP:
return grub_net_recv_udp_packet (nb, inf);
break;
default:
grub_netbuff_free (nb);
break;
}
return GRUB_ERR_NONE;
}

1312
grub-core/net/net.c Normal file

File diff suppressed because it is too large Load diff

106
grub-core/net/netbuff.c Normal file
View file

@ -0,0 +1,106 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/net/netbuff.h>
grub_err_t
grub_netbuff_put (struct grub_net_buff *nb, grub_size_t len)
{
nb->tail += len;
if (nb->tail > nb->end)
return grub_error (GRUB_ERR_OUT_OF_RANGE, "put out of the packet range.");
return GRUB_ERR_NONE;
}
grub_err_t
grub_netbuff_unput (struct grub_net_buff *nb, grub_size_t len)
{
nb->tail -= len;
if (nb->tail < nb->head)
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"unput out of the packet range.");
return GRUB_ERR_NONE;
}
grub_err_t
grub_netbuff_push (struct grub_net_buff *nb, grub_size_t len)
{
nb->data -= len;
if (nb->data < nb->head)
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"push out of the packet range.");
return GRUB_ERR_NONE;
}
grub_err_t
grub_netbuff_pull (struct grub_net_buff *nb, grub_size_t len)
{
nb->data += len;
if (nb->data > nb->end)
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"pull out of the packet range.");
return GRUB_ERR_NONE;
}
grub_err_t
grub_netbuff_reserve (struct grub_net_buff *nb, grub_size_t len)
{
nb->data += len;
nb->tail += len;
if ((nb->tail > nb->end) || (nb->data > nb->end))
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"reserve out of the packet range.");
return GRUB_ERR_NONE;
}
struct grub_net_buff *
grub_netbuff_alloc (grub_size_t len)
{
struct grub_net_buff *nb;
void *data;
if (len < NETBUFFMINLEN)
len = NETBUFFMINLEN;
len = ALIGN_UP (len, NETBUFF_ALIGN);
data = grub_memalign (NETBUFF_ALIGN, len + sizeof (*nb));
if (!data)
return NULL;
nb = (struct grub_net_buff *) ((grub_uint8_t *) data + len);
nb->head = nb->data = nb->tail = data;
nb->end = (char *) nb;
return nb;
}
grub_err_t
grub_netbuff_free (struct grub_net_buff *nb)
{
grub_free (nb->head);
return GRUB_ERR_NONE;
}
grub_err_t
grub_netbuff_clear (struct grub_net_buff *nb)
{
nb->data = nb->tail = nb->head;
return GRUB_ERR_NONE;
}

195
grub-core/net/tftp.c Normal file
View file

@ -0,0 +1,195 @@
#include <grub/misc.h>
#include <grub/net/tftp.h>
#include <grub/net/udp.h>
#include <grub/net/ip.h>
#include <grub/net/ethernet.h>
#include <grub/net/netbuff.h>
#include <grub/net.h>
#include <grub/mm.h>
#include <grub/dl.h>
#include <grub/file.h>
GRUB_MOD_LICENSE ("GPLv3+");
static grub_err_t
tftp_open (struct grub_file *file, const char *filename)
{
struct tftphdr *tftph;
char *rrq;
int i;
int rrqlen;
int hdrlen;
char open_data[1500];
struct grub_net_buff nb;
tftp_data_t data;
grub_err_t err;
data = grub_malloc (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)
return err;
tftph = (struct tftphdr *) nb.data;
rrq = (char *) tftph->u.rrq;
rrqlen = 0;
tftph->opcode = grub_cpu_to_be16 (TFTP_RRQ);
grub_strcpy (rrq, filename);
rrqlen += grub_strlen (filename) + 1;
rrq += grub_strlen (filename) + 1;
grub_strcpy (rrq, "octet");
rrqlen += grub_strlen ("octet") + 1;
rrq += grub_strlen ("octet") + 1;
grub_strcpy (rrq, "blksize");
rrqlen += grub_strlen ("blksize") + 1;
rrq += grub_strlen ("blksize") + 1;
grub_strcpy (rrq, "1024");
rrqlen += grub_strlen ("1024") + 1;
rrq += grub_strlen ("1024") + 1;
grub_strcpy (rrq, "tsize");
rrqlen += grub_strlen ("tsize") + 1;
rrq += grub_strlen ("tsize") + 1;
grub_strcpy (rrq, "0");
rrqlen += grub_strlen ("0") + 1;
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);
if (err)
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)
break;
/* Retry. */
/*err = grub_net_send_udp_packet (file->device->net->socket, &nb);
if (err)
return err; */
}
if (file->device->net->socket->status == 0)
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)
{
struct tftphdr *tftph;
char nbdata[128];
tftp_data_t data = sock->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:
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);
break;
case TFTP_ERROR:
grub_netbuff_clear (nb);
return grub_error (GRUB_ERR_IO, (char *) tftph->u.err.errmsg);
break;
}
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);
return GRUB_ERR_NONE;
}
static struct grub_net_app_protocol grub_tftp_protocol =
{
.name = "tftp",
.open = tftp_open,
.read = tftp_receive,
.close = tftp_close
};
GRUB_MOD_INIT (tftp)
{
grub_net_app_level_register (&grub_tftp_protocol);
}
GRUB_MOD_FINI (tftp)
{
grub_net_app_level_unregister (&grub_tftp_protocol);
}

61
grub-core/net/udp.c Normal file
View file

@ -0,0 +1,61 @@
#include <grub/net.h>
#include <grub/net/udp.h>
#include <grub/net/ip.h>
#include <grub/net/netbuff.h>
#include <grub/time.h>
grub_err_t
grub_net_send_udp_packet (const grub_net_socket_t socket,
struct grub_net_buff *nb)
{
struct udphdr *udph;
grub_err_t err;
err = grub_netbuff_push (nb, sizeof (*udph));
if (err)
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);
/* 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);
}
grub_err_t
grub_net_recv_udp_packet (struct grub_net_buff * nb,
struct grub_net_network_level_interface * inf)
{
struct udphdr *udph;
grub_net_socket_t sock;
udph = (struct udphdr *) nb->data;
grub_netbuff_pull (nb, sizeof (*udph));
FOR_NET_SOCKETS (sock)
{
if (grub_be_to_cpu16 (udph->dst) == sock->in_port
&& inf == sock->inf && sock->app)
{
if (sock->status == 0)
sock->out_port = grub_be_to_cpu16 (udph->src);
/* 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);
return GRUB_ERR_NONE;
}
}
if (grub_be_to_cpu16 (udph->dst) == 68)
grub_net_process_dhcp (nb, inf->card);
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
}

View file

@ -25,7 +25,6 @@
struct grub_disk; struct grub_disk;
struct grub_net; struct grub_net;
struct grub_fs;
struct grub_device struct grub_device
{ {

View file

@ -0,0 +1,6 @@
void EXPORT_FUNC (open64) (void);
void EXPORT_FUNC (close) (void);
void EXPORT_FUNC (read) (void);
void EXPORT_FUNC (write) (void);
void EXPORT_FUNC (ioctl) (void);

View file

@ -56,6 +56,10 @@ typedef enum
GRUB_ERR_IO, GRUB_ERR_IO,
GRUB_ERR_ACCESS_DENIED, GRUB_ERR_ACCESS_DENIED,
GRUB_ERR_EXTRACTOR, GRUB_ERR_EXTRACTOR,
GRUB_ERR_NET_BAD_ADDRESS,
GRUB_ERR_NET_ROUTE_LOOP,
GRUB_ERR_NET_NO_ROUTE,
GRUB_ERR_WAIT,
GRUB_ERR_BUG GRUB_ERR_BUG
} }
grub_err_t; grub_err_t;

View file

@ -152,9 +152,9 @@
#define GRUB_PXE_BOOTP_BCAST 0x8000 #define GRUB_PXE_BOOTP_BCAST 0x8000
#if 1 #if 1
#define GRUB_PXE_BOOTP_DHCPVEND 1024 /* DHCP extended vendor field size. */ #define GRUB_PXE_BOOTP_SIZE (1024 + 236) /* DHCP extended vendor field size. */
#else #else
#define GRUB_PXE_BOOTP_DHCPVEND 312 /* DHCP standard vendor field size. */ #define GRUB_PXE_BOOTP_SIZE (312 + 236) /* DHCP standard vendor field size. */
#endif #endif
#define GRUB_PXE_MIN_BLKSIZE 512 #define GRUB_PXE_MIN_BLKSIZE 512
@ -162,8 +162,6 @@
#define GRUB_PXE_TFTP_PORT 69 #define GRUB_PXE_TFTP_PORT 69
#define GRUB_PXE_VM_RFC1048 0x63825363L
#define GRUB_PXE_ERR_LEN 0xFFFFFFFF #define GRUB_PXE_ERR_LEN 0xFFFFFFFF
#ifndef ASM_FILE #ifndef ASM_FILE
@ -214,38 +212,6 @@ struct grub_pxenv_get_cached_info
grub_uint16_t buffer_limit; grub_uint16_t buffer_limit;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define GRUB_PXE_MAC_ADDR_LEN 16
typedef grub_uint8_t grub_pxe_mac_addr_t[GRUB_PXE_MAC_ADDR_LEN];
struct grub_pxenv_boot_player
{
grub_uint8_t opcode;
grub_uint8_t hw_type; /* hardware type. */
grub_uint8_t hw_len; /* hardware addr len. */
grub_uint8_t gate_hops; /* zero it. */
grub_uint32_t ident; /* random number chosen by client. */
grub_uint16_t seconds; /* seconds since did initial bootstrap. */
grub_uint16_t flags;
grub_uint32_t client_ip;
grub_uint32_t your_ip;
grub_uint32_t server_ip;
grub_uint32_t gateway_ip;
grub_pxe_mac_addr_t mac_addr;
grub_uint8_t server_name[64];
grub_uint8_t boot_file[128];
union
{
grub_uint8_t d[GRUB_PXE_BOOTP_DHCPVEND]; /* raw array of vendor/dhcp options. */
struct
{
grub_uint32_t magic; /* DHCP magic cookie. */
grub_uint32_t flags; /* bootp flags/opcodes. */
grub_uint8_t padding[56];
} v;
} vendor;
} __attribute__ ((packed));
struct grub_pxenv_tftp_open struct grub_pxenv_tftp_open
{ {
grub_uint16_t status; grub_uint16_t status;

View file

@ -24,7 +24,6 @@
#include <grub/types.h> #include <grub/types.h>
#include <grub/machine/ieee1275.h> #include <grub/machine/ieee1275.h>
/* Maps a device alias to a pathname. */
struct grub_ieee1275_devalias struct grub_ieee1275_devalias
{ {
char *name; char *name;
@ -65,6 +64,14 @@ struct grub_ieee1275_common_hdr
typedef grub_uint32_t grub_ieee1275_ihandle_t; typedef grub_uint32_t grub_ieee1275_ihandle_t;
typedef grub_uint32_t grub_ieee1275_phandle_t; typedef grub_uint32_t grub_ieee1275_phandle_t;
struct grub_ofnetcard_data
{
char *path;
grub_ieee1275_ihandle_t handle;
grub_uint32_t mtu;
};
/* Maps a device alias to a pathname. */
extern grub_ieee1275_phandle_t EXPORT_VAR(grub_ieee1275_chosen); extern grub_ieee1275_phandle_t EXPORT_VAR(grub_ieee1275_chosen);
extern grub_ieee1275_ihandle_t EXPORT_VAR(grub_ieee1275_mmu); extern grub_ieee1275_ihandle_t EXPORT_VAR(grub_ieee1275_mmu);
extern int (* EXPORT_VAR(grub_ieee1275_entry_fn)) (void *); extern int (* EXPORT_VAR(grub_ieee1275_entry_fn)) (void *);
@ -191,11 +198,10 @@ EXPORT_FUNC(grub_ieee1275_map) (grub_addr_t phys, grub_addr_t virt,
char *EXPORT_FUNC(grub_ieee1275_encode_devname) (const char *path); char *EXPORT_FUNC(grub_ieee1275_encode_devname) (const char *path);
char *EXPORT_FUNC(grub_ieee1275_get_filename) (const char *path); char *EXPORT_FUNC(grub_ieee1275_get_filename) (const char *path);
int EXPORT_FUNC(grub_ieee1275_devices_iterate) (int (*hook) int EXPORT_FUNC(grub_ieee1275_devices_iterate) (int (*hook)
(struct grub_ieee1275_devalias * (struct grub_ieee1275_devalias *
alias)); 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_canonicalise_devname) (const char *path);
#endif /* ! GRUB_IEEE1275_HEADER */ #endif /* ! GRUB_IEEE1275_HEADER */

View file

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

View file

@ -1,6 +1,6 @@
/* /*
* GRUB -- GRand Unified Bootloader * GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2007 Free Software Foundation, Inc. * Copyright (C) 2010 Free Software Foundation, Inc.
* *
* GRUB is free software: you can redistribute it and/or modify * GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -19,54 +19,437 @@
#ifndef GRUB_NET_HEADER #ifndef GRUB_NET_HEADER
#define GRUB_NET_HEADER 1 #define GRUB_NET_HEADER 1
#include <grub/symbol.h>
#include <grub/err.h>
#include <grub/types.h> #include <grub/types.h>
#include <grub/err.h>
#include <grub/list.h>
#include <grub/fs.h>
#include <grub/file.h>
#include <grub/mm.h>
#include <grub/net/netbuff.h>
struct grub_net; typedef enum grub_link_level_protocol_id
struct grub_net_dev
{ {
/* The device name. */ GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
const char *name; } grub_link_level_protocol_id_t;
/* FIXME: Just a template. */ typedef struct grub_net_link_level_address
int (*probe) (struct grub_net *net, const void *addr); {
void (*reset) (struct grub_net *net); grub_link_level_protocol_id_t type;
int (*poll) (struct grub_net *net); union
void (*transmit) (struct grub_net *net, const void *destip, {
unsigned srcsock, unsigned destsock, const void *packet); grub_uint8_t mac[6];
void (*disable) (struct grub_net *net);
/* The next net device. */
struct grub_net_dev *next;
}; };
typedef struct grub_net_dev *grub_net_dev_t; } grub_net_link_level_address_t;
struct grub_fs; typedef enum grub_net_interface_flags
struct grub_net
{ {
/* The net name. */ GRUB_NET_INTERFACE_HWADDRESS_IMMUTABLE = 1,
const char *name; GRUB_NET_INTERFACE_ADDRESS_IMMUTABLE = 2,
GRUB_NET_INTERFACE_PERMANENT = 4
} grub_net_interface_flags_t;
/* The underlying disk device. */ typedef enum grub_net_card_flags
grub_net_dev_t dev; {
GRUB_NET_CARD_HWADDRESS_IMMUTABLE = 1,
GRUB_NET_CARD_NO_MANUAL_INTERFACES = 2
} grub_net_card_flags_t;
/* The binding filesystem. */ struct grub_net_card;
struct grub_fs *fs;
/* FIXME: More data would be required, such as an IP address, a mask, struct grub_net_card_driver
a gateway, etc. */ {
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 (*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);
};
/* Device-specific data. */ 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;
struct grub_net_packet *prev;
struct grub_net_packets *up;
struct grub_net_buff *nb;
} grub_net_packet_t;
typedef struct grub_net_packets
{
grub_net_packet_t *first;
grub_net_packet_t *last;
} grub_net_packets_t;
struct grub_net_card
{
struct grub_net_card *next;
char *name;
struct grub_net_card_driver *driver;
grub_net_link_level_address_t default_address;
grub_net_card_flags_t flags;
union
{
void *data;
int data_num;
};
};
struct grub_net_network_level_interface;
typedef enum grub_network_level_protocol_id
{
GRUB_NET_NETWORK_LEVEL_PROTOCOL_PROMISC,
GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
} grub_network_level_protocol_id_t;
typedef struct grub_net_network_level_address
{
grub_network_level_protocol_id_t type;
union
{
grub_uint32_t ipv4;
};
} grub_net_network_level_address_t;
typedef struct grub_net_network_level_netaddress
{
grub_network_level_protocol_id_t type;
union
{
struct {
grub_uint32_t base;
int masksize;
} ipv4;
};
} grub_net_network_level_netaddress_t;
#define FOR_PACKETS(cont,var) for (var = (cont).first; var; var = var->next)
static inline grub_err_t
grub_net_put_packet (grub_net_packets_t *pkts, struct grub_net_buff *nb)
{
struct grub_net_packet *n;
n = grub_malloc (sizeof (*n));
if (!n)
return grub_errno;
n->nb = nb;
n->next = NULL;
n->prev = NULL;
n->up = pkts;
if (pkts->first)
{
pkts->last->next = n;
pkts->last = n;
n->prev = pkts->last;
}
else
pkts->first = pkts->last = n;
return GRUB_ERR_NONE;
}
static inline void
grub_net_remove_packet (grub_net_packet_t *pkt)
{
if (pkt->prev)
pkt->prev->next = pkt->next;
else
pkt->up->first = pkt->next;
if (pkt->next)
pkt->next->prev = pkt->prev;
else
pkt->up->last = pkt->prev;
grub_free (pkt);
}
typedef struct grub_net_app_protocol *grub_net_app_level_t;
typedef struct grub_net_socket *grub_net_socket_t;
struct grub_net_app_protocol
{
struct grub_net_app_protocol *next;
char *name;
grub_err_t (*dir) (grub_device_t device, const char *path,
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; void *data;
}; };
typedef struct grub_net *grub_net_t;
/* FIXME: How to abstract networks? More consideration is necessary. */ extern struct grub_net_socket *grub_net_sockets;
/* Note: Networks are very different from disks, because networks must static inline void
be initialized before used, and the status is persistent. */ grub_net_socket_register (grub_net_socket_t sock)
{
grub_list_push (GRUB_AS_LIST_P (&grub_net_sockets),
GRUB_AS_LIST (sock));
}
static inline void
grub_net_socket_unregister (grub_net_socket_t sock)
{
grub_list_remove (GRUB_AS_LIST_P (&grub_net_sockets),
GRUB_AS_LIST (sock));
}
#define FOR_NET_SOCKETS(var) for (var = grub_net_sockets; var; var = var->next)
typedef struct grub_net
{
char *name;
grub_net_app_level_t protocol;
grub_net_socket_t socket;
grub_fs_t fs;
} *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;
grub_net_network_level_address_t address;
grub_net_link_level_address_t hwaddress;
grub_net_interface_flags_t flags;
struct grub_net_bootp_packet *dhcp_ack;
grub_size_t dhcp_acklen;
void *data;
};
struct grub_net_session;
struct grub_net_session_level_protocol
{
void (*close) (struct grub_net_session *session);
grub_ssize_t (*recv) (struct grub_net_session *session, void *buf,
grub_size_t size);
grub_err_t (*send) (struct grub_net_session *session, void *buf,
grub_size_t size);
};
struct grub_net_session
{
struct grub_net_session_level_protocol *protocol;
void *data;
};
static inline void
grub_net_session_close (struct grub_net_session *session)
{
session->protocol->close (session);
}
static inline grub_err_t
grub_net_session_send (struct grub_net_session *session, void *buf,
grub_size_t size)
{
return session->protocol->send (session, buf, size);
}
static inline grub_ssize_t
grub_net_session_recv (struct grub_net_session *session, void *buf,
grub_size_t size)
{
return session->protocol->recv (session, buf, size);
}
struct grub_net_network_level_interface *
grub_net_add_addr (const char *name,
const 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);
extern struct grub_net_network_level_interface *grub_net_network_level_interfaces;
extern grub_net_app_level_t grub_net_app_level_list;
#ifndef GRUB_LST_GENERATOR
static inline void
grub_net_app_level_register (grub_net_app_level_t proto)
{
grub_list_push (GRUB_AS_LIST_P (&grub_net_app_level_list),
GRUB_AS_LIST (proto));
}
#endif
static inline void
grub_net_app_level_unregister (grub_net_app_level_t proto)
{
grub_list_remove (GRUB_AS_LIST_P (&grub_net_app_level_list),
GRUB_AS_LIST (proto));
}
#define FOR_NET_APP_LEVEL(var) FOR_LIST_ELEMENTS((var), \
(grub_net_app_level_list))
extern struct grub_net_card *grub_net_cards;
static inline void
grub_net_card_register (struct grub_net_card *card)
{
grub_list_push (GRUB_AS_LIST_P (&grub_net_cards),
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));
}
#define FOR_NET_CARDS(var) for (var = grub_net_cards; var; var = var->next)
struct grub_net_session *
grub_net_open_tcp (char *address, grub_uint16_t port);
grub_err_t
grub_net_resolve_address (const char *name,
grub_net_network_level_address_t *addr);
grub_err_t
grub_net_resolve_net_address (const char *name,
grub_net_network_level_netaddress_t *addr);
grub_err_t
grub_net_route_address (grub_net_network_level_address_t addr,
grub_net_network_level_address_t *gateway,
struct grub_net_network_level_interface **interf);
grub_err_t
grub_net_add_route (const char *name,
grub_net_network_level_netaddress_t target,
struct grub_net_network_level_interface *inter);
grub_err_t
grub_net_add_route_gw (const char *name,
grub_net_network_level_netaddress_t target,
grub_net_network_level_address_t gw);
#define GRUB_NET_BOOTP_MAC_ADDR_LEN 16
typedef grub_uint8_t grub_net_bootp_mac_addr_t[GRUB_NET_BOOTP_MAC_ADDR_LEN];
struct grub_net_bootp_packet
{
grub_uint8_t opcode;
grub_uint8_t hw_type; /* hardware type. */
grub_uint8_t hw_len; /* hardware addr len. */
grub_uint8_t gate_hops; /* zero it. */
grub_uint32_t ident; /* random number chosen by client. */
grub_uint16_t seconds; /* seconds since did initial bootstrap. */
grub_uint16_t flags;
grub_uint32_t client_ip;
grub_uint32_t your_ip;
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];
grub_uint8_t vendor[0];
} __attribute__ ((packed));
#define GRUB_NET_BOOTP_RFC1048_MAGIC 0x63825363L
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);
void
grub_net_process_dhcp (struct grub_net_buff *nb,
const struct grub_net_card *card);
int
grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a,
const grub_net_link_level_address_t *b);
/*
Currently suppoerted adresses:
IPv4: XXX.XXX.XXX.XXX
*/
#define GRUB_NET_MAX_STR_ADDR_LEN sizeof ("XXX.XXX.XXX.XXX")
void
grub_net_addr_to_str (const grub_net_network_level_address_t *target,
char *buf);
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)
void
grub_net_poll_cards (unsigned time);
#endif /* ! GRUB_NET_HEADER */ #endif /* ! GRUB_NET_HEADER */

36
include/grub/net/arp.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef GRUB_NET_ARP_HEADER
#define GRUB_NET_ARP_HEADER 1
#include <grub/misc.h>
#include <grub/net.h>
enum
{
/* IANA ARP constant to define hardware type as ethernet. */
GRUB_NET_ARPHRD_ETHERNET = 1
};
/* ARP header operation codes */
#define ARP_REQUEST 1
#define ARP_REPLY 2
struct arp_entry {
int avail;
grub_net_network_level_address_t nl_address;
grub_net_link_level_address_t ll_address;
};
struct arphdr {
grub_uint16_t hrd;
grub_uint16_t pro;
grub_uint8_t hln;
grub_uint8_t pln;
grub_uint16_t op;
} __attribute__ ((packed));
extern grub_err_t grub_net_arp_receive(struct grub_net_buff *nb);
extern grub_err_t grub_net_arp_resolve(struct grub_net_network_level_interface *inf,
const grub_net_network_level_address_t *addr,
grub_net_link_level_address_t *hw_addr);
#endif

View file

View file

@ -0,0 +1,45 @@
#ifndef GRUB_NET_ETHERNET_HEADER
#define GRUB_NET_ETHERNET_HEADER 1
#include <grub/types.h>
#include <grub/net.h>
#define LLCADDRMASK 0x7f
struct etherhdr
{
grub_uint8_t dst[6];
grub_uint8_t src[6];
grub_uint16_t type;
} __attribute__ ((packed));
struct llchdr
{
grub_uint8_t dsap;
grub_uint8_t ssap;
grub_uint8_t ctrl;
} __attribute__ ((packed));
struct snaphdr
{
grub_uint8_t oui[3];
grub_uint16_t type;
} __attribute__ ((packed));
/* IANA Ethertype */
enum
{
GRUB_NET_ETHERTYPE_IP = 0x0800,
GRUB_NET_ETHERTYPE_ARP = 0x0806
};
grub_err_t
send_ethernet_packet (struct grub_net_network_level_interface *inf,
struct grub_net_buff *nb,
grub_net_link_level_address_t target_addr,
grub_uint16_t ethertype);
grub_err_t
grub_net_recv_ethernet_packet (struct grub_net_buff *nb,
const struct grub_net_card *card);
#endif

35
include/grub/net/ip.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef GRUB_NET_IP_HEADER
#define GRUB_NET_IP_HEADER 1
#include <grub/misc.h>
struct iphdr {
grub_uint8_t verhdrlen;
grub_uint8_t service;
grub_uint16_t len;
grub_uint16_t ident;
grub_uint16_t frags;
grub_uint8_t ttl;
grub_uint8_t protocol;
grub_uint16_t chksum;
grub_uint32_t src;
grub_uint32_t dest;
} __attribute__ ((packed)) ;
struct ip6hdr
{
grub_uint8_t version:4, priority:4;
grub_uint8_t flow_lbl[3];
grub_uint16_t payload_len;
grub_uint8_t nexthdr;
grub_uint8_t hop_limit;
grub_uint8_t saddr[16];
grub_uint8_t daddr[16];
} __attribute__ ((packed));
#define IP_UDP 0x11 /* UDP protocol */
#define IP_BROADCAST 0xFFFFFFFF
grub_uint16_t ipchksum(void *ipv, int len);
void ipv4_ini(void);
void ipv4_fini(void);
#endif

View file

@ -0,0 +1,30 @@
#ifndef GRUB_NETBUFF_HEADER
#define GRUB_NETBUFF_HEADER
#include <grub/misc.h>
#define NETBUFF_ALIGN 2048
#define NETBUFFMINLEN 64
struct grub_net_buff
{
/*Pointer to the start of the buffer*/
char *head;
/*Pointer to the data */
char *data;
/*Pointer to the tail */
char *tail;
/*Pointer to the end of the buffer*/
char *end;
};
grub_err_t grub_netbuff_put (struct grub_net_buff *net_buff ,grub_size_t len);
grub_err_t grub_netbuff_unput (struct grub_net_buff *net_buff ,grub_size_t len);
grub_err_t grub_netbuff_push (struct grub_net_buff *net_buff ,grub_size_t len);
grub_err_t grub_netbuff_pull (struct grub_net_buff *net_buff ,grub_size_t len);
grub_err_t grub_netbuff_reserve (struct grub_net_buff *net_buff ,grub_size_t len);
grub_err_t grub_netbuff_clear (struct grub_net_buff *net_buff);
struct grub_net_buff * grub_netbuff_alloc ( grub_size_t len );
grub_err_t grub_netbuff_free (struct grub_net_buff *net_buff);
#endif

74
include/grub/net/tftp.h Normal file
View file

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

24
include/grub/net/udp.h Normal file
View file

@ -0,0 +1,24 @@
#ifndef GRUB_NET_UDP_HEADER
#define GRUB_NET_UDP_HEADER 1
#include <grub/types.h>
#include <grub/net.h>
struct udphdr
{
grub_uint16_t src;
grub_uint16_t dst;
grub_uint16_t len;
grub_uint16_t chksum;
} __attribute__ ((packed));
grub_err_t
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