grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Add support for (pxe[:server_ip[:gateway_ip]]) and export pxe pa


From: Vladimir 'φ-coder/phcoder' Serbinenko
Subject: [PATCH] Add support for (pxe[:server_ip[:gateway_ip]]) and export pxe parameteres into grub environment
Date: Sun, 20 Dec 2009 20:26:01 +0100
User-agent: Mozilla-Thunderbird 2.0.0.22 (X11/20091109)

Any other DHCP options needed?

-- 
Regards
Vladimir 'φ-coder/phcoder' Serbinenko

=== added file 'ChangeLog.pxeenv'
--- ChangeLog.pxeenv    1970-01-01 00:00:00 +0000
+++ ChangeLog.pxeenv    2009-12-20 19:23:11 +0000
@@ -0,0 +1,36 @@
+2009-12-19  Vladimir Serbinenko  <address@hidden>
+
+       Support for (pxe[:server[:gateway]]) syntax and
+       use environment variable for PXE.
+
+       * commands/i386/pc/pxecmd.c (options): Removed.
+       (print_ip): Removed.
+       (grub_cmd_pxe): Removed
+       (grub_cmd_pxe_unload): New function.
+       * fs/i386/pc/pxe.c (grub_pxe_disk_data): New structure.
+       (grub_pxe_your_ip): Made static.
+       (grub_pxe_default_server_ip): Likewise.
+       (grub_pxe_default_gateway_ip): Likewise.
+       (grub_pxe_blksize): Likewise.
+       (parse_ip): New function.
+       (grub_pxe_open): Support server and gateway specification.
+       (grub_pxe_close): Free disk->data.
+       (grub_pxefs_open): Use disk->data.
+       (grub_pxefs_read): Likewise.
+       (grub_env_write_readonly): New function.
+       (set_mac_env): Likewise.
+       (set_env_limn_ro): Likewise.
+       (parse_dhcp_vendor): Likewise.
+       (grub_pxe_detect): Set the environment variables.
+       (set_ip_env): New function.
+       (write_ip_env): Likewise.
+       (grub_env_write_pxe_default_server): Likewise.
+       (grub_env_write_pxe_default_gateway): Likewise.
+       (grub_env_write_pxe_blocksize): Likewise.
+       (GRUB_MOD_INIT(pxe)): Set environment variables.
+       * include/grub/i386/pc/pxe.h (grub_pxe_mac_addr): Rename to ...
+       (grub_pxe_mac_addr_t): ... this. All users updated.
+       (grub_pxe_your_ip): Removed.
+       (grub_pxe_server_ip): Likewise.
+       (grub_pxe_gateway_ip): Likewise.
+       (grub_pxe_blksize): Likewise.

=== modified file 'commands/i386/pc/pxecmd.c'
--- commands/i386/pc/pxecmd.c   2009-05-04 03:49:08 +0000
+++ commands/i386/pc/pxecmd.c   2009-12-20 19:05:53 +0000
@@ -1,7 +1,7 @@
 /* pxe.c - command to control the pxe driver  */
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *  Copyright (C) 2008,2009  Free Software Foundation, Inc.
  *
  *  GRUB is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -21,79 +21,31 @@
 #include <grub/err.h>
 #include <grub/misc.h>
 #include <grub/machine/pxe.h>
-#include <grub/extcmd.h>
-
-static const struct grub_arg_option options[] =
-{
-    {"info", 'i', 0, "show PXE information.", 0, 0},
-    {"bsize", 'b', 0, "set PXE block size", 0, ARG_TYPE_INT},
-    {"unload", 'u', 0, "unload PXE stack.", 0, 0},
-    {0, 0, 0, 0, 0, 0}
-  };
-
-static void
-print_ip (grub_uint32_t ip)
-{
-  int i;
-
-  for (i = 0; i < 3; i++)
-    {
-      grub_printf ("%d.", ip & 0xFF);
-      ip >>= 8;
-    }
-  grub_printf ("%d", ip);
-}
+#include <grub/command.h>
 
 static grub_err_t
-grub_cmd_pxe (grub_extcmd_t cmd, int argc __attribute__ ((unused)),
-             char **args __attribute__ ((unused)))
+grub_cmd_pxe_unload (grub_command_t cmd __attribute__ ((unused)),
+                    int argc __attribute__ ((unused)),
+                    char **args __attribute__ ((unused)))
 {
-  struct grub_arg_list *state = cmd->state;
-
   if (! grub_pxe_pxenv)
     return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no pxe environment");
 
-  if (state[1].set)
-    {
-      int size;
-
-      size = grub_strtoul (state[1].arg, 0, 0);
-      if (size < GRUB_PXE_MIN_BLKSIZE)
-        size = GRUB_PXE_MIN_BLKSIZE;
-      else if (size > GRUB_PXE_MAX_BLKSIZE)
-        size = GRUB_PXE_MAX_BLKSIZE;
-
-      grub_pxe_blksize = size;
-    }
-
-  if (state[0].set)
-    {
-      grub_printf ("blksize : %d\n", grub_pxe_blksize);
-      grub_printf ("client ip  : ");
-      print_ip (grub_pxe_your_ip);
-      grub_printf ("\nserver ip  : ");
-      print_ip (grub_pxe_server_ip);
-      grub_printf ("\ngateway ip : ");
-      print_ip (grub_pxe_gateway_ip);
-      grub_printf ("\n");
-    }
-
-  if (state[2].set)
-    grub_pxe_unload ();
+  grub_pxe_unload ();
 
   return 0;
 }
 
-static grub_extcmd_t cmd;
+static grub_command_t cmd;
 
 GRUB_MOD_INIT(pxecmd)
 {
-  cmd = grub_register_extcmd ("pxe", grub_cmd_pxe, GRUB_COMMAND_FLAG_BOTH,
-                             "pxe [-i|-b|-u]",
-                             "Command to control the PXE device.", options);
+  cmd = grub_register_command ("pxe_unload", grub_cmd_pxe_unload,
+                              "pxe_unload",
+                              "Unload PXE environment.");
 }
 
 GRUB_MOD_FINI(pxecmd)
 {
-  grub_unregister_extcmd (cmd);
+  grub_unregister_command (cmd);
 }

=== modified file 'fs/i386/pc/pxe.c'
--- fs/i386/pc/pxe.c    2009-12-20 13:09:16 +0000
+++ fs/i386/pc/pxe.c    2009-12-20 19:05:53 +0000
@@ -1,7 +1,7 @@
 /* pxe.c - Driver to provide access to the pxe filesystem  */
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *  Copyright (C) 2008,2009  Free Software Foundation, Inc.
  *
  *  GRUB is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@
 #include <grub/file.h>
 #include <grub/misc.h>
 #include <grub/bufio.h>
+#include <grub/env.h>
 
 #include <grub/machine/pxe.h>
 #include <grub/machine/memory.h>
@@ -33,11 +34,17 @@
 #define SEGOFS(x)      ((SEGMENT(x) << 16) + OFFSET(x))
 #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_pxenv *grub_pxe_pxenv;
-grub_uint32_t grub_pxe_your_ip;
-grub_uint32_t grub_pxe_server_ip;
-grub_uint32_t grub_pxe_gateway_ip;
-int grub_pxe_blksize = GRUB_PXE_MIN_BLKSIZE;
+static grub_uint32_t grub_pxe_your_ip;
+static grub_uint32_t grub_pxe_default_server_ip;
+static grub_uint32_t grub_pxe_default_gateway_ip;
+static unsigned grub_pxe_blksize = GRUB_PXE_MIN_BLKSIZE;
 
 static grub_file_t curr_file = 0;
 
@@ -57,23 +64,82 @@ grub_pxe_iterate (int (*hook) (const cha
 }
 
 static grub_err_t
+parse_ip (const char *val, grub_uint32_t *ip, const char **rest)
+{
+  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)
 {
-  if (grub_strcmp (name, "pxe"))
-      return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a pxe 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->server_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) "pxe";
+  disk->id = (unsigned long) data;
 
   disk->has_partitions = 0;
-  disk->data = 0;
+  disk->data = data;
 
   return GRUB_ERR_NONE;
 }
 
 static void
-grub_pxe_close (grub_disk_t disk __attribute((unused)))
+grub_pxe_close (grub_disk_t disk)
 {
+  grub_free (disk->data);
 }
 
 static grub_err_t
@@ -125,6 +191,7 @@ grub_pxefs_open (struct grub_file *file,
       struct grub_pxenv_tftp_open c2;
     } c;
   struct grub_pxe_data *data;
+  struct grub_pxe_disk_data *disk_data = file->device->disk->data;
   grub_file_t file_int, bufio;
 
   if (curr_file != 0)
@@ -133,8 +200,8 @@ grub_pxefs_open (struct grub_file *file,
       curr_file = 0;
     }
 
-  c.c1.server_ip = grub_pxe_server_ip;
-  c.c1.gateway_ip = grub_pxe_gateway_ip;
+  c.c1.server_ip = disk_data->server_ip;
+  c.c1.gateway_ip = disk_data->gateway_ip;
   grub_strcpy ((char *)&c.c1.filename[0], name);
   grub_pxe_call (GRUB_PXENV_TFTP_GET_FSIZE, &c.c1);
   if (c.c1.status)
@@ -184,6 +251,7 @@ grub_pxefs_read (grub_file_t file, char 
 {
   struct grub_pxenv_tftp_read c;
   struct grub_pxe_data *data;
+  struct grub_pxe_disk_data *disk_data = file->device->disk->data;
   grub_uint32_t pn, r;
 
   data = file->data;
@@ -203,8 +271,8 @@ grub_pxefs_read (grub_file_t file, char 
       if (curr_file != 0)
         grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &o);
 
-      o.server_ip = grub_pxe_server_ip;
-      o.gateway_ip = grub_pxe_gateway_ip;
+      o.server_ip = disk_data->server_ip;
+      o.gateway_ip = disk_data->gateway_ip;
       grub_strcpy ((char *)&o.filename[0], data->filename);
       o.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT);
       o.packet_size = grub_pxe_blksize;
@@ -272,6 +340,99 @@ static struct grub_fs grub_pxefs_fs =
     .next = 0
   };
 
+static char *
+grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
+                        const char *val __attribute__ ((unused)))
+{
+  return NULL;
+}
+
+static void
+set_mac_env (grub_uint8_t *mac_addr, grub_size_t mac_len)
+{
+  char buf[(sizeof ("XX:") - 1) * mac_len + 1];
+  char *ptr = buf;
+  unsigned i;
+
+  for (i = 0; i < mac_len; i++)
+    {
+      grub_sprintf (ptr, "%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);
+}
+
+static void
+set_env_limn_ro (const char *varname, char *value, grub_size_t len)
+{
+  char c;
+  c = value[len];
+  value[len] = 0;
+  grub_env_set (varname, value);
+  value[len] = c;
+  grub_register_variable_hook (varname, 0, grub_env_write_readonly);
+}
+
+static void
+parse_dhcp_vendor (void *vend, int limit)
+{
+  grub_uint8_t *ptr, *ptr0;
+
+  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
+            developpement team.  */
+       }
+
+      ptr += taglength;
+    }
+}
+
 static void
 grub_pxe_detect (void)
 {
@@ -293,9 +454,15 @@ grub_pxe_detect (void)
   bp = LINEAR (ci.buffer);
 
   grub_pxe_your_ip = bp->your_ip;
-  grub_pxe_server_ip = bp->server_ip;
-  grub_pxe_gateway_ip = bp->gateway_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;
 }
 
@@ -311,11 +478,110 @@ grub_pxe_unload (void)
     }
 }
 
+static void
+set_ip_env (char *varname, grub_uint32_t ip)
+{
+  char buf[sizeof ("XXX.XXX.XXX.XXX")];
+
+  grub_sprintf (buf, "%d.%d.%d.%d", (ip & 0xff),
+               (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff);
+  grub_env_set (varname, buf);
+}
+
+static char *
+write_ip_env (grub_uint32_t *ip, const char *val)
+{
+  char *buf;
+  grub_err_t err;
+  grub_uint32_t newip;
+  
+  err = parse_ip (val, &newip, 0);
+  if (err)
+    return 0;
+
+  /* Normalize the IP.  */
+  buf = grub_malloc (sizeof ("XXX.XXX.XXX.XXX"));
+  if (!buf)
+    return 0;
+
+  *ip = newip;
+
+  grub_sprintf (buf, "%d.%d.%d.%d", (newip & 0xff), (newip >> 8) & 0xff,
+               (newip >> 16) & 0xff, (newip >> 24) & 0xff);
+
+  return buf; 
+}
+
+static char *
+grub_env_write_pxe_default_server (struct grub_env_var *var 
+                                  __attribute__ ((unused)),
+                                  const char *val)
+{
+  return write_ip_env (&grub_pxe_default_server_ip, val);
+}
+
+static char *
+grub_env_write_pxe_default_gateway (struct grub_env_var *var
+                                   __attribute__ ((unused)),
+                                   const char *val)
+{
+  return write_ip_env (&grub_pxe_default_gateway_ip, val);
+}
+
+static char *
+grub_env_write_pxe_blocksize (struct grub_env_var *var __attribute__ 
((unused)),
+                             const char *val)
+{
+  unsigned size;
+  char *buf;
+
+  size = grub_strtoul (val, 0, 0);
+  if (grub_errno)
+    return 0;
+
+  if (size < GRUB_PXE_MIN_BLKSIZE)
+    size = GRUB_PXE_MIN_BLKSIZE;
+  else if (size > GRUB_PXE_MAX_BLKSIZE)
+    size = GRUB_PXE_MAX_BLKSIZE;
+  
+  buf = grub_malloc (sizeof ("XXXXXX XXXXXX"));
+  if (!buf)
+    return 0;
+
+  grub_sprintf (buf, "%d", size);
+  grub_pxe_blksize = size;
+  
+  return buf;
+}
+
+
 GRUB_MOD_INIT(pxe)
 {
   grub_pxe_detect ();
   if (grub_pxe_pxenv)
     {
+      char *buf;
+
+      buf = grub_malloc (sizeof ("XXXXXX XXXXXX"));
+      if (buf)
+       {
+         grub_sprintf (buf, "%d", grub_pxe_blksize);
+         grub_env_set ("net_pxe_blksize", 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 ("net_pxe_default_server", 0,
+                                  grub_env_write_pxe_default_server);
+      grub_register_variable_hook ("net_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 ("net_pxe_blksize", 0,
+                                  grub_env_write_pxe_blocksize);
       grub_disk_dev_register (&grub_pxe_dev);
       grub_fs_register (&grub_pxefs_fs);
     }

=== modified file 'include/grub/i386/pc/pxe.h'
--- include/grub/i386/pc/pxe.h  2008-08-05 15:15:59 +0000
+++ include/grub/i386/pc/pxe.h  2009-12-20 19:05:53 +0000
@@ -201,7 +201,7 @@ struct grub_pxenv_get_cached_info
 
 #define GRUB_PXE_MAC_ADDR_LEN  16
 
-typedef grub_uint8_t grub_pxe_mac_addr[GRUB_PXE_MAC_ADDR_LEN];
+typedef grub_uint8_t grub_pxe_mac_addr_t[GRUB_PXE_MAC_ADDR_LEN];
 
 struct grub_pxenv_boot_player
 {
@@ -216,7 +216,7 @@ struct grub_pxenv_boot_player
   grub_uint32_t your_ip;
   grub_uint32_t        server_ip;
   grub_uint32_t        gateway_ip;
-  grub_pxe_mac_addr mac_addr;
+  grub_pxe_mac_addr_t mac_addr;
   grub_uint8_t server_name[64];
   grub_uint8_t boot_file[128];
   union
@@ -306,10 +306,6 @@ struct grub_pxenv * EXPORT_FUNC(grub_pxe
 int EXPORT_FUNC(grub_pxe_call) (int func, void * data);
 
 extern struct grub_pxenv *grub_pxe_pxenv;
-extern grub_uint32_t grub_pxe_your_ip;
-extern grub_uint32_t grub_pxe_server_ip;
-extern grub_uint32_t grub_pxe_gateway_ip;
-extern int grub_pxe_blksize;
 
 void grub_pxe_unload (void);
 

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]