Fix broken blksize negotiation, fix broken seek and change a way net device is filled n i386-pc

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-07-02 17:58:23 +02:00
parent cae730b452
commit 6708faafde
8 changed files with 105 additions and 44 deletions

View file

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

View file

@ -45,9 +45,10 @@ struct mem_region
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;
@ -55,7 +56,8 @@ grub_machine_get_bootlocation (char **device,
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;
}

View file

@ -28,6 +28,7 @@
#include <grub/machine/pxe.h>
#include <grub/machine/int.h>
#include <grub/machine/memory.h>
#include <grub/machine/kernel.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -45,6 +46,22 @@ struct grub_pxe_undi_open
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;
@ -259,7 +276,7 @@ struct grub_net_card grub_pxe_card =
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,
@ -269,17 +286,11 @@ grub_pxe_unload (void)
}
}
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;
@ -289,9 +300,41 @@ GRUB_MOD_INIT(pxe)
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;
@ -303,11 +346,11 @@ GRUB_MOD_INIT(pxe)
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 ();
}

View file

@ -664,6 +664,7 @@ grub_net_open_real (const char *name)
else
ret->server = NULL;
ret->fs = &grub_net_fs;
ret->offset = 0;
return ret;
}
}
@ -784,7 +785,7 @@ grub_net_poll_cards (unsigned time)
/* 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;
@ -802,6 +803,7 @@ grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len)
amount = len;
len -= amount;
total += amount;
file->device->net->offset += amount;
if (buf)
{
grub_memcpy (ptr, nb->data, amount);
@ -829,28 +831,40 @@ grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len)
return total;
}
/* Read from the packets list*/
static grub_err_t
grub_net_seek_real (struct grub_file *file, grub_off_t offset)
{
grub_net_socket_t sock = file->device->net->socket;
struct grub_net_buff *nb;
grub_size_t len = offset - file->offset;
grub_size_t len = offset - file->device->net->offset;
if (!len)
return GRUB_ERR_NONE;
/* We cant seek backwards past the current packet. */
if (file->offset > offset)
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)))
@ -1384,7 +1398,6 @@ GRUB_MOD_INIT(net)
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;
}
@ -1400,6 +1413,5 @@ GRUB_MOD_FINI(net)
grub_unregister_command (cmd_getdhcp);
grub_fs_unregister (&grub_net_fs);
grub_net_open = NULL;
grub_file_net_seek = NULL;
grub_grubnet_fini = NULL;
}

View file

@ -11,6 +11,13 @@
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)
{
@ -85,9 +92,9 @@ 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)
@ -110,11 +117,11 @@ tftp_receive (grub_net_socket_t sock, struct grub_net_buff *nb)
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)
@ -122,6 +129,11 @@ tftp_receive (grub_net_socket_t sock, struct grub_net_buff *nb)
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++;
@ -139,12 +151,12 @@ tftp_receive (grub_net_socket_t sock, struct grub_net_buff *nb)
{
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;
}

View file

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

View file

@ -242,11 +242,11 @@ typedef struct grub_net
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

View file

@ -43,12 +43,6 @@
/* * 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;