]> git.proxmox.com Git - grub2.git/commitdiff
Fix broken blksize negotiation, fix broken seek and change a way net device is filled...
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 2 Jul 2011 15:58:23 +0000 (17:58 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 2 Jul 2011 15:58:23 +0000 (17:58 +0200)
grub-core/kern/file.c
grub-core/kern/i386/pc/init.c
grub-core/net/drivers/i386/pc/pxe.c
grub-core/net/net.c
grub-core/net/tftp.c
include/grub/i386/pc/kernel.h
include/grub/net.h
include/grub/net/tftp.h

index 2407e72c5fb98603962e487bd8e10253d994f25d..f69ef6fd487a6309f2968b3c28bddba6448ba077 100644 (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;
     
index 3aedaf6d898a01aeb311ab543274d7b3e1f66e7b..24fe8fed9440f5acb45baab0bd631a765917cb3f 100644 (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;
     }
 
index 144df964c562c7d6b38ffbf49188de66ceb7bf8a..51f4023a6dd936d23f63c4eb2ac9cac00f2d59aa 100644 (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 ();
 }
index 2ecb709b97e5d3a0d94c1e4342b57ecdb62e56d2..a56860eed521a86b7a5808094546d091eb470fac 100644 (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;
 }
index 24f30eb7a95012dff4385b26bcfd23ddb3a623ac..b112f643ee32258879a4b574aac2fc406a7e4605 100644 (file)
 
 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;
            }
index 1de37a5d5d9167f7917ad2790bdd00b062af7ecc..dd50aa8338ed0456cbf5bbe386914199e95292d9 100644 (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 */
index 6aaf391d5a7af57c32fd893ba84554bf4c50a626..4948266250fa6e9dd81253eb279dc599b04060a8 100644 (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
index c67380817bea098bd8db45b19d118b4e6199de88..0d8cbd1dee6d7b82a5d1e19c5ab9732fb2fb4e39 100644 (file)
  /*  * 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;