#include <grub/fs.h>
#include <grub/device.h>
-grub_err_t (*grub_file_net_seek) (struct grub_file *file, grub_off_t offset) = NULL;
void (*EXPORT_VAR (grub_grubnet_fini)) (void);
grub_file_filter_t grub_file_filters_all[GRUB_FILE_FILTER_MAX];
return -1;
}
- if (file->device->net && grub_file_net_seek)
- grub_file_net_seek (file, offset);
-
old = file->offset;
file->offset = offset;
static struct mem_region mem_regions[MAX_REGIONS];
static int num_regions;
+void (*grub_pc_net_config) (char **device, char **path);
+
void
-grub_machine_get_bootlocation (char **device,
- char **path __attribute__ ((unused)))
+grub_machine_get_bootlocation (char **device, char **path)
{
char *ptr;
partition number encoded at the install time. */
if (grub_boot_drive == GRUB_BOOT_MACHINE_PXE_DL)
{
- *device = grub_strdup ("pxe");
+ if (grub_pc_net_config)
+ grub_pc_net_config (device, path);
return;
}
#include <grub/machine/pxe.h>
#include <grub/machine/int.h>
#include <grub/machine/memory.h>
+#include <grub/machine/kernel.h>
GRUB_MOD_LICENSE ("GPLv3+");
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;
void
grub_pxe_unload (void)
{
- if (grub_pxe_pxenv)
+ if (pxe_rm_entry)
{
grub_pxe_call (GRUB_PXENV_UNDI_CLOSE,
(void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR,
}
}
-GRUB_MOD_INIT(pxe)
+static void
+grub_pc_net_config_real (char **device, char **path)
{
- struct grub_pxe_bangpxe *pxenv;
- struct grub_pxenv_get_cached_info ci;
struct grub_net_bootp_packet *bp;
- struct grub_pxe_undi_open *ou;
-
- pxenv = grub_pxe_scan ();
- if (! pxenv)
- return;
-
+ struct grub_pxenv_get_cached_info ci;
ci.packet_type = GRUB_PXENV_PACKET_TYPE_DHCP_ACK;
ci.buffer = 0;
ci.buffer_size = 0;
bp = LINEAR (ci.buffer);
- 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_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_open *ou;
+ 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;
ou = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
return;
grub_net_card_register (&grub_pxe_card);
- grub_net_configure_by_dhcp_ack ("pxe", &grub_pxe_card, 0,
- bp, GRUB_PXE_BOOTP_SIZE);
+ grub_pc_net_config = grub_pc_net_config_real;
}
GRUB_MOD_FINI(pxe)
{
+ grub_pc_net_config = 0;
grub_pxe_unload ();
}
else
ret->server = NULL;
ret->fs = &grub_net_fs;
+ ret->offset = 0;
return ret;
}
}
/* 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;
struct grub_net_buff *nb;
amount = len;
len -= amount;
total += amount;
+ file->device->net->offset += amount;
if (buf)
{
grub_memcpy (ptr, nb->data, amount);
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)
+ if (file->device->net->offset > offset)
{
nb = sock->packs.first->nb;
- return grub_netbuff_push (nb, file->offset - offset);
+ return grub_netbuff_push (nb, file->device->net->offset - offset);
}
- grub_net_fs_read (file, NULL, len);
+ grub_net_fs_read_real (file, NULL, len);
return GRUB_ERR_NONE;
}
+static grub_ssize_t
+grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len)
+{
+ if (file->offset != file->device->net->offset)
+ {
+ grub_err_t err;
+ err = grub_net_seek_real (file, file->offset);
+ if (err)
+ return err;
+ }
+ return grub_net_fs_read_real (file, buf, len);
+}
+
static char *
grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
const char *val __attribute__ ((unused)))
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;
}
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_MOD_LICENSE ("GPLv3+");
+typedef struct tftp_data
+{
+ grub_uint64_t file_size;
+ grub_uint64_t block;
+ grub_uint32_t block_size;
+} *tftp_data_t;
+
static grub_err_t
tftp_open (struct grub_file *file, const char *filename)
{
if (file->device->net->socket->status != 0)
break;
/* Retry. */
- /*err = grub_net_send_udp_packet (file->device->net->socket, &nb);
- if (err)
- return err; */
+ err = grub_net_send_udp_packet (file->device->net->socket, &nb);
+ if (err)
+ return err;
}
if (file->device->net->socket->status == 0)
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 = 512;
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++;
unsigned size = nb->tail - nb->data;
- if (size < 1024)
+ if (size < data->block_size)
sock->status = 2;
/* Prevent garbage in broken cards. */
- if (size > 1024)
+ if (size > data->block_size)
{
- err = grub_netbuff_unput (nb, size - 1024);
+ err = grub_netbuff_unput (nb, size - data->block_size);
if (err)
return err;
}
/* 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 */
char *server;
grub_net_app_level_t protocol;
grub_net_socket_t socket;
+ grub_off_t offset;
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
/* * 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;