All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Vladimir 'φ-coder/phcoder' Serbinenko" <phcoder@gmail.com>
To: The development of GRUB 2 <grub-devel@gnu.org>
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	[thread overview]
Message-ID: <4B2E7A49.5070901@gmail.com> (raw)


[-- Attachment #1.1: Type: text/plain, Size: 90 bytes --]

Any other DHCP options needed?

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


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: pxeenv.diff --]
[-- Type: text/x-diff; name="pxeenv.diff", Size: 16279 bytes --]

=== 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  <phcoder@gmail.com>
+
+	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 #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 293 bytes --]

             reply	other threads:[~2009-12-20 19:26 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-12-20 19:26 Vladimir 'φ-coder/phcoder' Serbinenko [this message]
2009-12-24 21:45 ` [PATCH] Add support for (pxe[:server_ip[:gateway_ip]]) and export pxe parameteres into grub environment Robert Millan
2009-12-24 22:14   ` Seth Goldberg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4B2E7A49.5070901@gmail.com \
    --to=phcoder@gmail.com \
    --cc=grub-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.