]> git.ozlabs.org Git - yaboot.git/commitdiff
Merge branch 'netboot'
authorTony Breeds <tony@bakeyournoodle.com>
Fri, 16 Jul 2010 04:56:12 +0000 (14:56 +1000)
committerTony Breeds <tony@bakeyournoodle.com>
Fri, 16 Jul 2010 04:56:12 +0000 (14:56 +1000)
13 files changed:
include/debug.h
include/file.h
include/fs.h
include/prom.h
second/file.c
second/fs.c
second/fs_ext2.c
second/fs_iso.c
second/fs_of.c
second/fs_reiserfs.c
second/fs_xfs.c
second/prom.c
second/yaboot.c

index 47a9cce84ef82dcb098dc081f2800d90b8dc3cf7..dcac25a88acfd20d54e32508d7a53aded28eee08 100644 (file)
@@ -32,8 +32,8 @@
     prom_printf( fmt, ## args );\
 }
 # define DEBUG_OPEN DEBUG_F( "dev=%s, part=0x%p (%d), file_name=%s\n",\
-                             dev_name, part, part ? part->part_number : -1,\
-                             file_name)
+                             fspec->dev, part, part ? part->part_number : -1,\
+                             fspec->file)
 # define DEBUG_SLEEP prom_sleep(3)
 #else
 #define DEBUG_ENTER
index b6b9fe51236e90063eb3d13f775495e8efc04191..b2d9c63a71d9082f499382c877fdb3ee074883d5 100644 (file)
@@ -39,7 +39,19 @@ struct boot_file_t;
 struct boot_fspec_t {
        char*   dev;            /* OF device path */
        int     part;           /* Partition number or -1 */
+       char*   siaddr;         /* Server address */
        char*   file;           /* File path */
+       char*   ciaddr;         /* Client address */
+       char*   giaddr;         /* Gateway address */
+       char*   bootp_retries;  /* Bootp retries */
+       char*   tftp_retries;   /* TFTP retries */
+       char*   subnetmask;     /* Subnet mask */
+       char*   addl_params;    /* copy all additional parameters */
+
+       /* Following fields are used only in ipv6 format */
+       int     is_ipv6;        /* is ipv6 specified ? */
+       char*   dhcpv6;         /* dhcpv6 string */
+       char*   blksize;        /* blksize string */
 };
 
 struct boot_file_t {
@@ -63,7 +75,7 @@ struct boot_file_t {
 };
 
 extern int
-open_file(const struct boot_fspec_t*   spec,
+open_file(struct boot_fspec_t* spec,
          struct boot_file_t*           file);
 
 extern int
index d960fea61918c80526f97d707f589647241bb8ff..1ff7986af5c9343d8dadb7de55005c2704d06511 100644 (file)
 #include "file.h"
 
 int fserrorno;
+struct boot_fspec_t;
 
 struct fs_t {
        const char* name;
 
        int (*open)(    struct boot_file_t*     file,
-                       const char*             dev_name,
                        struct partition_t*     part,
-                       const char*             file_name);
+                       struct boot_fspec_t*    fspec);
 
        int (*read)(    struct boot_file_t*     file,
                        unsigned int            size,
@@ -49,7 +49,7 @@ struct fs_t {
 extern const struct fs_t *fs_of;
 extern const struct fs_t *fs_of_netboot;
 
-const struct fs_t *fs_open(struct boot_file_t *file, const char *dev_name,
-                         struct partition_t *part, const char *file_name);
+const struct fs_t *fs_open(struct boot_file_t *file,
+                         struct partition_t *part, struct boot_fspec_t *fspec);
 
 #endif
index eacee7708c1f9300e87b7cca8db84f01aad0d00a..a512f2be5a4d1db15a144dfc3e256ce81eb0bc93 100644 (file)
@@ -37,6 +37,7 @@ typedef void *phandle;
 #define PROM_INVALID_HANDLE    ((prom_handle)-1UL)
 #define BOOTDEVSZ               (2048) /* iscsi args can be in excess of 1040 bytes */
 #define TOK_ISCSI               "iscsi"
+#define TOK_IPV6                "ipv6"
 #define PROM_CLAIM_MAX_ADDR    0x8000000
 #define BOOTLASTSZ             1024
 #define FW_NBR_REBOOTSZ                4
@@ -152,7 +153,7 @@ struct bootp_packet {
      unsigned char chaddr[16];
      unsigned char sname[64];
      unsigned char file[128];
-     /* vendor options go here if we need them */
+     unsigned char options[]; /* vendor options */
 };
 
 struct bootp_packet * prom_get_netinfo (void);
index 4054dd18ca24a3746990f3c19bc527a4ee7bfab7..81d91a9f6c6341511238d03439cdd8be46ed9ac3 100644 (file)
 
 extern char bootdevice[];
 
-static char *netdev_path_to_filename(const char *path)
+/* Convert __u32 into std, dotted quad string, leaks like a sive :( */
+static char *
+ipv4_to_str(__u32 ip)
 {
-     char *tmp, *args, *filename;
-     size_t len;
+     char *buf = malloc(sizeof("000.000.000.000"));
 
-     DEBUG_F("path = %s\n", path);
+     sprintf(buf,"%u.%u.%u.%u",
+             (ip & 0xff000000) >> 24, (ip & 0x00ff0000) >> 16,
+             (ip & 0x0000ff00) >>  8, (ip & 0x000000ff));
 
-     if (!path)
+     return buf;
+}
+
+/* Ensure the string arg is a plausible IPv4 address */
+static char * is_valid_ipv4_str(char *str)
+{
+     int i;
+     long tmp;
+     __u32 ip = 0;
+     char *ptr=str, *endptr;
+
+     if (str == NULL)
+          return NULL;
+
+     for (i=0; i<4; i++, ptr = ++endptr) {
+          tmp = strtol(ptr, &endptr, 10);
+          if ((tmp & 0xff) != tmp)
+               return NULL;
+
+          /* If we reach the end of the string but we're not in the 4th octet
+           * we have an invalid IP */
+          if (*endptr == '\x0' && i!=3)
+               return NULL;
+
+          /* If we have anything other than a NULL or '.' we have an invlaid
+           * IP */
+          if (*endptr != '\x0' && *endptr != '.')
+               return NULL;
+
+          ip += (tmp << (24-(i*8)));
+     }
+
+     if (ip == 0 || ip == ~0u)
+          return NULL;
+
+     return str;
+}
+
+
+/*
+ * Copy the string from source to dest till newline or comma(,) is seen
+ * in the source.
+ * Move source and dest pointers respectively.
+ * Returns pointer to the start of the string that has just been copied.
+ */
+static char *
+scopy(char **dest, char **source)
+{
+     char *ret = *dest;
+
+     if (!**source)
          return NULL;
 
-     args = strrchr(path, ':');
+     while (**source != ',' && **source != '\0')
+         *(*dest)++ = *(*source)++;
+     if (**source != '\0')
+         *(*source)++;
+     **dest = '\0';
+     *(*dest)++;
+     return ret;
+}
+
+/*
+ * Extract all the ipv4 arguments from the bootpath provided and fill result
+ * Returns 1 on success, 0 on failure.
+ */
+static int
+extract_ipv4_args(char *imagepath, struct boot_fspec_t *result)
+{
+     char *tmp, *args, *str, *start;
+
+     args = strrchr(imagepath, ':');
      if (!args)
-         return NULL;
+         return 1;
+
+     start = args; /* used to see if we read any optional parameters */
 
      /* The obp-tftp device arguments should be at the end of
       * the argument list.  Skip over any extra arguments (promiscuous,
@@ -77,46 +150,240 @@ static char *netdev_path_to_filename(const char *path)
      if (tmp && tmp > args)
          args = tmp + strlen("rarp");
 
-     args = strchr(args, ',');
+     if (args != start) /* we read some parameters, so go past the next comma(,) */
+         args = strchr(args, ',');
      if (!args)
-         return NULL;
+         return 1;
+
+     str = malloc(strlen(args) + 1); /*long enough to hold all strings */
+     if (!str)
+         return 0;
 
-     tmp = args;
-     tmp--;
-     /* If the preceding character is ':' then there were no
-      * non-obp-tftp arguments and we know we're right up to the
-      * filename.  Otherwise, we must advance args once more.
+     if (args[-1] != ':')
+         args++; /* If comma(,) is not immediately followed by ':' then go past the , */
+
+     /*
+      * read the arguments in order: siaddr,filename,ciaddr,giaddr,
+      * bootp-retries,tftp-retries,addl_prameters
       */
-     args++;
-     if (*tmp != ':') {
-         args = strchr(args, ',');
-         if (!args)
-              return NULL;
-         args++;
+     result->siaddr = is_valid_ipv4_str(scopy(&str, &args));
+     result->file = scopy(&str, &args);
+     result->ciaddr = is_valid_ipv4_str(scopy(&str, &args));
+     result->giaddr = is_valid_ipv4_str(scopy(&str, &args));
+     result->bootp_retries = scopy(&str, &args);
+     result->tftp_retries = scopy(&str, &args);
+     result->subnetmask = is_valid_ipv4_str(scopy(&str, &args));
+     if (*args) {
+         result->addl_params = strdup(args);
+         if (!result->addl_params)
+               return 0;
      }
+     return 1;
+}
 
-     /* filename may be empty; e.g. enet:192.168.1.1,,192.168.1.2 */
-     if (*args == ',') {
-         DEBUG_F("null filename\n");
-         return NULL;
+/* DHCP options */
+enum dhcp_options {
+     DHCP_PAD = 0,
+     DHCP_NETMASK = 1,
+     DHCP_ROUTERS = 3,
+     DHCP_DNS = 6,
+     DHCP_END = 255,
+};
+
+#define DHCP_COOKIE        0x63825363
+#define DHCP_COOKIE_SIZE   4
+
+/*
+ * Process the bootp reply packet's vendor extensions.
+ * Vendor extensions are detailed in: http://www.faqs.org/rfcs/rfc1084.html
+ */
+static void
+extract_vendor_options(struct bootp_packet *packet, struct boot_fspec_t *result)
+{
+     int i = 0;
+     __u32 cookie;
+     __u8 *options = &packet->options[0];
+
+     memcpy(&cookie, &options[i], DHCP_COOKIE_SIZE);
+
+     if (cookie != DHCP_COOKIE) {
+          prom_printf("EEEK! cookie is fubar got %08x expected %08x\n",
+                      cookie, DHCP_COOKIE);
+          return;
      }
 
-     /* Now see whether there are more args following the filename. */
-     tmp = strchr(args, ',');
-     if (!tmp)
-         len = strlen(args) + 1;
-     else
-         len = tmp - args + 1;
+     i += DHCP_COOKIE_SIZE;
 
-     filename = malloc(len);
-     if (!filename)
-         return NULL;
+     /* FIXME: It may be possible to run off the end of a packet here /if/
+      *         it's malformed. :( */
+     while (options[i] != DHCP_END) {
+          __u8 tag = options[i++], len;
+          __u32 value;
 
-     strncpy(filename, args, len);
-     filename[len - 1] = '\0';
+          if (tag == DHCP_PAD)
+               continue;
 
-     DEBUG_F("filename = %s\n", filename);
-     return filename;
+          len = options[i++];
+          memcpy(&value, &options[i], len);
+
+#if DEBUG
+{
+     DEBUG_F("tag=%2d, len=%2d, data=", tag, len);
+     int j;
+     for (j=0; j<len; j++)
+          prom_printf("%02x", options[i+j]);
+     prom_printf("\n");
+}
+#endif
+
+          switch (tag) {
+               case DHCP_NETMASK:
+                    if ((result->subnetmask == NULL ||
+                         *(result->subnetmask) == '\x0') && value != 0) {
+                         result->subnetmask = ipv4_to_str(value);
+                         DEBUG_F("Storing %s as subnetmask from options\n",
+                                 result->subnetmask);
+                    }
+                    break;
+               case DHCP_ROUTERS:
+                    if ((result->giaddr == NULL || *(result->giaddr) == '\x0')
+                        && value != 0) {
+                         result->giaddr = ipv4_to_str(value);
+                         DEBUG_F("Storing %s as gateway from options\n",
+                                 result->giaddr);
+                    }
+                    break;
+               }
+          i += len;
+     }
+}
+
+/*
+ * Check netinfo for ipv4 parameters and add them to the fspec iff the
+ * fspec has no existing value.
+ *
+ * Returns 1 on success, 0 on failure.
+ */
+static int
+extract_netinfo_args(struct boot_fspec_t *result)
+{
+     struct bootp_packet *packet;
+
+     /* Check to see if we can get the [scyg]iaddr fields from netinfo */
+     packet = prom_get_netinfo();
+     if (!packet)
+          return 0;
+
+     DEBUG_F("We have a boot packet\n");
+     DEBUG_F(" siaddr = <%x>\n", packet->siaddr);
+     DEBUG_F(" ciaddr = <%x>\n", packet->ciaddr);
+     DEBUG_F(" yiaddr = <%x>\n", packet->yiaddr);
+     DEBUG_F(" giaddr = <%x>\n", packet->giaddr);
+
+     /* Try to fallback to yiaddr if ciaddr is empty. Broken? */
+     if (packet->ciaddr == 0 && packet->yiaddr != 0)
+          packet->ciaddr = packet->yiaddr;
+
+     if ((result->siaddr == NULL || *(result->siaddr) == '\x0')
+         && packet->siaddr != 0)
+          result->siaddr = ipv4_to_str(packet->siaddr);
+     if ((result->ciaddr == NULL || *(result->ciaddr) == '\x0')
+         && packet->ciaddr != 0)
+          result->ciaddr = ipv4_to_str(packet->ciaddr);
+     if ((result->giaddr == NULL || *(result->giaddr) == '\x0')
+         && packet->giaddr != 0)
+          result->giaddr = ipv4_to_str(packet->giaddr);
+
+     extract_vendor_options(packet, result);
+
+     /* FIXME: Yck! if we /still/ do not have a gateway then "cheat" and use
+      *        the server.  This will be okay if the client and server are on
+      *        the same IP network, if not then lets hope the server does ICMP
+      *        redirections */
+     if (result->giaddr == NULL) {
+          result->giaddr = ipv4_to_str(packet->siaddr);
+          DEBUG_F("Forcing giaddr to siaddr <%s>\n", result->giaddr);
+     }
+
+     return 1;
+}
+
+/*
+ * Extract all the ipv6 arguments from the bootpath provided and fill result
+ * Syntax: ipv6,[dhcpv6[=diaddr,]]ciaddr=c_iaddr,giaddr=g_iaddr,siaddr=s_iaddr,
+ *      filename=file_name,tftp-retries=tftp_retries,blksize=block_size
+ * Returns 1 on success, 0 on failure.
+ */
+static int
+extract_ipv6_args(char *imagepath, struct boot_fspec_t *result)
+{
+     char *str, *tmp;
+     int total_len;
+
+     result->is_ipv6 = 1;
+
+     /* Just allocate the max required size */
+     total_len = strlen(imagepath) + 1;
+     str = malloc(total_len);
+     if (!str)
+       return 0;
+
+     if ((tmp = strstr(imagepath, "dhcpv6=")) != NULL)
+       result->dhcpv6 = scopy(&str, &tmp);
+
+     if ((tmp = strstr(imagepath, "ciaddr=")) != NULL)
+       result->ciaddr = scopy(&str, &tmp);
+
+     if ((tmp = strstr(imagepath, "giaddr=")) != NULL)
+       result->giaddr = scopy(&str, &tmp);
+
+     if ((tmp = strstr(imagepath, "siaddr=")) != NULL)
+       result->siaddr = scopy(&str, &tmp);
+
+     if ((tmp = strstr(imagepath, "filename=")) != NULL)
+       result->file = scopy(&str, &tmp);
+
+     if ((tmp = strstr(imagepath, "tftp-retries=")) != NULL)
+       result->tftp_retries = scopy(&str, &tmp);
+
+     if ((tmp = strstr(imagepath, "blksize=")) != NULL)
+       result->blksize = scopy(&str, &tmp);
+
+     return 1;
+}
+
+/*
+ * Extract all the arguments provided in the imagepath and fill it in result.
+ * Returns 1 on success, 0 on failure.
+ */
+static int
+extract_netboot_args(char *imagepath, struct boot_fspec_t *result)
+{
+     int ret;
+
+     DEBUG_F("imagepath = %s\n", imagepath);
+
+     if (!imagepath)
+         return 1;
+
+     if (strstr(imagepath, TOK_IPV6))
+         ret = extract_ipv6_args(imagepath, result);
+     else
+         ret = extract_ipv4_args(imagepath, result);
+     ret |= extract_netinfo_args(result);
+
+     DEBUG_F("ipv6 = <%d>\n", result->is_ipv6);
+     DEBUG_F("siaddr = <%s>\n", result->siaddr);
+     DEBUG_F("file = <%s>\n", result->file);
+     DEBUG_F("ciaddr = <%s>\n", result->ciaddr);
+     DEBUG_F("giaddr = <%s>\n", result->giaddr);
+     DEBUG_F("bootp_retries = <%s>\n", result->bootp_retries);
+     DEBUG_F("tftp_retries = <%s>\n", result->tftp_retries);
+     DEBUG_F("addl_params = <%s>\n", result->addl_params);
+     DEBUG_F("dhcpv6 = <%s>\n", result->dhcpv6);
+     DEBUG_F("blksize = <%s>\n", result->blksize);
+
+     return ret;
 }
 
 static char *netdev_path_to_dev(const char *path)
@@ -163,6 +430,10 @@ static char *netdev_path_to_dev(const char *path)
     - enet:,/tftpboot/vmlinux
     - enet:bootp
     - enet:0
+    - arguments for obp-tftp open as specified in section 4.1 of
+      http://playground.sun.com/1275/practice/obp-tftp/tftp1_0.pdf
+      [bootp,]siaddr,filename,ciaddr,giaddr,bootp-retries,tftp-retries
+      ex: enet:bootp,10.0.0.11,bootme,10.0.0.12,10.0.0.1,5,5
    Supported only if defdevice == NULL
     - disc
     - any other device path lacking a :
@@ -179,6 +450,9 @@ parse_device_path(char *imagepath, char *defdevice, int defpart,
      char *defdev = NULL;
      int device_kind = -1;
 
+     DEBUG_F("imagepath = %s; defdevice %s; defpart %d, deffile %s\n",
+               imagepath, defdevice, defpart, deffile);
+
      result->dev = NULL;
      result->part = -1;
      result->file = NULL;
@@ -247,10 +521,14 @@ parse_device_path(char *imagepath, char *defdevice, int defpart,
      }
 
      if (device_kind == FILE_DEVICE_NET) {
-         if (strchr(ipath, ':'))
-              result->file = netdev_path_to_filename(ipath);
-         else
+         if (strchr(ipath, ':')) {
+              if (extract_netboot_args(ipath, result) == 0)
+                  return 0;
+         } else {
+               /* If we didn't get a ':' then look only in netinfo */
+              extract_netinfo_args(result);
               result->file = strdup(ipath);
+          }
 
          if (!defdev)
               result->dev = netdev_path_to_dev(ipath);
@@ -287,15 +565,14 @@ parse_device_path(char *imagepath, char *defdevice, int defpart,
 
 static int
 file_block_open(       struct boot_file_t*     file,
-                       const char*             dev_name,
-                       const char*             file_name,
+                       struct boot_fspec_t*    fspec,
                        int                     partition)
 {
      struct partition_t*       parts;
      struct partition_t*       p;
      struct partition_t*       found;
 
-     parts = partitions_lookup(dev_name);
+     parts = partitions_lookup(fspec->dev);
      found = NULL;
 
 #if DEBUG
@@ -308,7 +585,7 @@ file_block_open(    struct boot_file_t*     file,
          DEBUG_F("number: %02d, start: 0x%08lx, length: 0x%08lx\n",
                  p->part_number, p->part_start, p->part_size );
          if (partition == -1) {
-              file->fs = fs_open( file, dev_name, p, file_name );
+              file->fs = fs_open( file, p, fspec );
               if (file->fs == NULL || fserrorno != FILE_ERR_OK)
                    continue;
               else {
@@ -328,7 +605,7 @@ file_block_open(    struct boot_file_t*     file,
       * cases, let OF figure out a default partition.
       */
      DEBUG_F( "Using OF defaults.. (found = %p)\n", found );
-     file->fs = fs_open( file, dev_name, found, file_name );
+     file->fs = fs_open( file, found, fspec );
 
 done:
      if (parts)
@@ -338,12 +615,10 @@ done:
 }
 
 static int
-file_net_open( struct boot_file_t*     file,
-               const char*             dev_name,
-               const char*             file_name)
+file_net_open(struct boot_file_t* file, struct boot_fspec_t *fspec)
 {
      file->fs = fs_of_netboot;
-     return fs_of_netboot->open(file, dev_name, NULL, file_name);
+     return fs_of_netboot->open(file, NULL, fspec);
 }
 
 static int
@@ -380,7 +655,7 @@ static struct fs_t fs_default =
 };
 
 
-int open_file(const struct boot_fspec_t* spec, struct boot_file_t* file)
+int open_file(struct boot_fspec_t* spec, struct boot_file_t* file)
 {
      int result;
 
@@ -399,10 +674,10 @@ int open_file(const struct boot_fspec_t* spec, struct boot_file_t* file)
      switch(file->device_kind) {
      case FILE_DEVICE_BLOCK:
          DEBUG_F("device is a block device\n");
-         return file_block_open(file, spec->dev, spec->file, spec->part);
+         return file_block_open(file, spec, spec->part);
      case FILE_DEVICE_NET:
          DEBUG_F("device is a network device\n");
-         return file_net_open(file, spec->dev, spec->file);
+         return file_net_open(file, spec);
      }
      return 0;
 }
index 2ae70669eb7652fd1c9f1b142f0c0a7e622aca55..b748bed3e2d8401fc195ebae9f3fe80809609bd9 100644 (file)
@@ -56,12 +56,12 @@ const struct fs_t *fs_of = &of_filesystem;              /* needed by ISO9660 */
 const struct fs_t *fs_of_netboot = &of_net_filesystem;  /* needed by file.c */
 
 const struct fs_t *
-fs_open(struct boot_file_t *file, const char *dev_name,
-       struct partition_t *part, const char *file_name)
+fs_open(struct boot_file_t *file,
+       struct partition_t *part, struct boot_fspec_t *fspec)
 {
      const struct fs_t **fs;
      for (fs = block_filesystems; *fs; fs++)
-         if ((fserrorno = (*fs)->open(file, dev_name, part, file_name)) != FILE_ERR_BAD_FSYS)
+         if ((fserrorno = (*fs)->open(file, part, fspec)) != FILE_ERR_BAD_FSYS)
               break;
 
      return *fs;
index 67571f28fadda668e967cde6e263a2ce37dda0a8..d24450d5c92b5b0105a7597907b54ef2ee2f2fc5 100644 (file)
@@ -46,9 +46,8 @@ typedef int FILE;
 #include "ext2fs/ext2fs.h"
 
 static int ext2_open(  struct boot_file_t*     file,
-                       const char*             dev_name,
                        struct partition_t*     part,
-                       const char*             file_name);
+                       struct boot_fspec_t*    fspec);
 static int ext2_read(  struct boot_file_t*     file,
                        unsigned int            size,
                        void*                   buffer);
@@ -123,14 +122,15 @@ void com_err (const char *a, long i, const char *fmt,...)
 
 static int
 ext2_open(     struct boot_file_t*     file,
-               const char*             dev_name,
                struct partition_t*     part,
-               const char*             file_name)
+               struct boot_fspec_t*    fspec)
 {
      int result = 0;
      int error = FILE_ERR_NOTFOUND;
      static char buffer[1024];
      int ofopened = 0;
+     char *dev_name = fspec->dev;
+     char *file_name = fspec->file;
 
      DEBUG_ENTER;
      DEBUG_OPEN;
index 303790f27bded5f97d8dd34b0d2a6a38ed367396..33d43b3e86d1fdaef162b8deb410e51578c19203 100644 (file)
@@ -29,9 +29,8 @@
 #include "errors.h"
 
 static int iso_open(   struct boot_file_t*     file,
-                       const char*             dev_name,
                        struct partition_t*     part,
-                       const char*             file_name);
+                       struct boot_fspec_t*    fspec);
 static int iso_read(   struct boot_file_t*     file,
                        unsigned int            size,
                        void*                   buffer);
@@ -50,9 +49,8 @@ struct fs_t iso_filesystem =
 
 static int
 iso_open(      struct boot_file_t*     file,
-               const char*             dev_name,
                struct partition_t*     part,
-               const char*             file_name)
+               struct boot_fspec_t*    fspec)
 {
      return FILE_ERR_BAD_FSYS;
 }
index 95c131d684bec7722a87b4fe60b238353ee6f20f..bd481e43ed66007b2430f63348a029e519bf1d75 100644 (file)
 #include "debug.h"
 
 #define LOAD_BUFFER_POS                0x1000000
-#define LOAD_BUFFER_SIZE       0x1000000
+#define LOAD_BUFFER_SIZE       0x1800000
 
-static int of_open(struct boot_file_t* file, const char* dev_name,
-                  struct partition_t* part, const char* file_name);
+static int of_open(struct boot_file_t* file,
+                  struct partition_t* part, struct boot_fspec_t* fspec);
 static int of_read(struct boot_file_t* file, unsigned int size, void* buffer);
 static int of_seek(struct boot_file_t* file, unsigned int newpos);
 static int of_close(struct boot_file_t* file);
 
 
-static int of_net_open(struct boot_file_t* file, const char* dev_name,
-                      struct partition_t* part, const char* file_name);
+static int of_net_open(struct boot_file_t* file,
+                      struct partition_t* part, struct boot_fspec_t* fspec);
 static int of_net_read(struct boot_file_t* file, unsigned int size, void* buffer);
 static int of_net_seek(struct boot_file_t* file, unsigned int newpos);
 
@@ -79,8 +79,8 @@ struct fs_t of_net_filesystem =
 };
 
 static int
-of_open(struct boot_file_t* file, const char* dev_name,
-       struct partition_t* part, const char* file_name)
+of_open(struct boot_file_t* file,
+       struct partition_t* part, struct boot_fspec_t* fspec)
 {
      static char       buffer[1024];
      char               *filename;
@@ -89,7 +89,7 @@ of_open(struct boot_file_t* file, const char* dev_name,
      DEBUG_ENTER;
      DEBUG_OPEN;
 
-     strncpy(buffer, dev_name, 768);
+     strncpy(buffer, fspec->dev, 768);
      strcat(buffer, ":");
      if (part) {
           if (part->sys_ind == LINUX_RAID) {
@@ -101,10 +101,10 @@ of_open(struct boot_file_t* file, const char* dev_name,
          sprintf(pn, "%02d", part->part_number);
          strcat(buffer, pn);
      }
-     if (file_name && strlen(file_name)) {
+     if (fspec->file && strlen(fspec->file)) {
          if (part)
               strcat(buffer, ",");
-         filename = strdup(file_name);
+         filename = strdup(fspec->file);
          for (p = filename; *p; p++)
               if (*p == '/')
                    *p = '\\';
@@ -131,25 +131,64 @@ of_open(struct boot_file_t* file, const char* dev_name,
 }
 
 static int
-of_net_open(struct boot_file_t* file, const char* dev_name,
-           struct partition_t* part, const char* file_name)
+of_net_open(struct boot_file_t* file,
+           struct partition_t* part, struct boot_fspec_t* fspec)
 {
      static char       buffer[1024];
-     char               *filename;
+     char               *filename = NULL;
      char               *p;
+     int                new_tftp;
 
      DEBUG_ENTER;
      DEBUG_OPEN;
 
-     strncpy(buffer, dev_name, 768);
-     if (file_name && strlen(file_name)) {
-         strcat(buffer, ",");
-         filename = strdup(file_name);
+     if (fspec->file && strlen(fspec->file)) {
+         filename = strdup(fspec->file);
          for (p = filename; *p; p++)
               if (*p == '/')
                    *p = '\\';
-         strcat(buffer, filename);
-         free(filename);
+     }
+
+     DEBUG_F("siaddr <%s>; filename <%s>; ciaddr <%s>; giaddr <%s>;"
+             " ipv6 <%d>\n",
+             fspec->siaddr, filename, fspec->ciaddr, fspec->giaddr,
+             fspec->is_ipv6);
+
+     strncpy(buffer, fspec->dev, 768);
+     /* If we didn't get a ':' include one */
+     if (fspec->dev[strlen(fspec->dev)-1] != ':')
+          strcat(buffer, ":");
+
+     /* If /packages/cas exists the we have a "new skool" tftp.
+      * This means that siaddr is the tftp server and that we can add
+      * {tftp,bootp}_retrys, subnet mask and tftp block size to the load
+      * method */
+     new_tftp = (prom_finddevice("/packages/cas") != PROM_INVALID_HANDLE);
+     DEBUG_F("Using %s tftp style\n", (new_tftp? "new": "old"));
+
+     if (new_tftp) {
+          strcat(buffer, fspec->siaddr);
+          strcat(buffer, ",");
+
+          if (fspec->is_ipv6 && (strstr(filename, "filename=") == NULL))
+               strcat(buffer, "filename=");
+
+          strcat(buffer, filename);
+          strcat(buffer, ",");
+          strcat(buffer, fspec->ciaddr);
+          strcat(buffer, ",");
+          strcat(buffer, fspec->giaddr);
+          strcat(buffer, ",");
+          strcat(buffer, fspec->bootp_retries);
+          strcat(buffer, ",");
+          strcat(buffer, fspec->tftp_retries);
+          strcat(buffer, ",");
+          strcat(buffer, fspec->subnetmask);
+          strcat(buffer, ",");
+          strcat(buffer, fspec->addl_params);
+     } else {
+          strcat(buffer, ",");
+          strcat(buffer, filename);
      }
 
      DEBUG_F("Opening: \"%s\"\n", buffer);
index 238f523e843c848246522e064be08a402c4b6794..4b83a7aa1c26070f072574258a26626f520053d6 100644 (file)
@@ -33,8 +33,8 @@
 #include "reiserfs/reiserfs.h"
 
 /* Exported in struct fs_t */
-static int reiserfs_open( struct boot_file_t *file, const char *dev_name,
-                         struct partition_t *part, const char *file_name );
+static int reiserfs_open( struct boot_file_t *file, struct partition_t *part,
+                         struct boot_fspec_t *fspec);
 static int reiserfs_read( struct boot_file_t *file, unsigned int size,
 
                          void *buffer );
@@ -63,10 +63,12 @@ int errnum;
 
 
 static int
-reiserfs_open( struct boot_file_t *file, const char *dev_name,
-               struct partition_t *part, const char *file_name )
+reiserfs_open( struct boot_file_t *file, struct partition_t *part,
+               struct boot_fspec_t *fspec)
 {
      static char buffer[1024];
+     char *dev_name = fspec->dev;
+     char *file_name = fspec->file;
 
      DEBUG_ENTER;
      DEBUG_OPEN;
@@ -74,7 +76,7 @@ reiserfs_open( struct boot_file_t *file, const char *dev_name,
      memset( INFO, 0, sizeof(struct reiserfs_state) );
      INFO->file = file;
 
-     if (part)
+     if (fspec->part)
      {
          DEBUG_F( "Determining offset for partition %d\n", part->part_number );
          INFO->partition_offset = ((uint64_t)part->part_start) * part->blocksize;
index 04d6cf3a4db03943a444636abec51c27bc26c6d7..e27d857a7d23b87ada047d7376cc8fc614b6ad36 100644 (file)
@@ -39,8 +39,8 @@ int xfs_read_data (char *buf, int len);
 int xfs_dir (char *dirname);
 
 /* Exported in struct fs_t */
-static int xfs_open(struct boot_file_t *file, const char *dev_name,
-                   struct partition_t *part, const char *file_name);
+static int xfs_open(struct boot_file_t *file,
+                   struct partition_t *part, struct boot_fspec_t *fspec);
 static int xfs_read(struct boot_file_t *file, unsigned int size, void *buffer);
 static int xfs_seek(struct boot_file_t *file, unsigned int newpos);
 static int xfs_close(struct boot_file_t *file);
@@ -59,8 +59,8 @@ uint64_t partition_offset;
 int errnum;
 
 static int
-xfs_open(struct boot_file_t *file, const char *dev_name,
-        struct partition_t *part, const char *file_name)
+xfs_open(struct boot_file_t *file,
+        struct partition_t *part, struct boot_fspec_t *fspec)
 {
        static char buffer[1024];
 
@@ -78,11 +78,11 @@ xfs_open(struct boot_file_t *file, const char *dev_name,
        else
                partition_offset = 0;
 
-       strncpy(buffer, dev_name, 1020);
+       strncpy(buffer, fspec->dev, 1020);
        if (_machine != _MACH_bplan)
                strcat(buffer, ":0");  /* 0 is full disk in (non-buggy) OF */
        DEBUG_F("Trying to open dev_name=%s; filename=%s; partition offset=%Lu\n",
-               buffer, file_name, partition_offset);
+               buffer, fspec->file, partition_offset);
        file->of_device = prom_open(buffer);
 
        if (file->of_device == PROM_INVALID_HANDLE || file->of_device == NULL)
@@ -105,8 +105,8 @@ xfs_open(struct boot_file_t *file, const char *dev_name,
                return FILE_ERR_BAD_FSYS;
        }
 
-       DEBUG_F("Attempting to open %s\n", file_name);
-       strcpy(buffer, file_name); /* xfs_dir modifies argument */
+       DEBUG_F("Attempting to open %s\n", fspec->file);
+       strcpy(buffer, fspec->file); /* xfs_dir modifies argument */
        if(!xfs_dir(buffer))
        {
                DEBUG_F("xfs_dir() failed. errnum = %d\n", errnum);
@@ -116,7 +116,7 @@ xfs_open(struct boot_file_t *file, const char *dev_name,
                return errnum;
        }
 
-       DEBUG_F("Successfully opened %s\n", file_name);
+       DEBUG_F("Successfully opened %s\n", fspec->file);
 
        DEBUG_LEAVE(FILE_ERR_OK);
        return FILE_ERR_OK;
index 4ad727761b47a58f2a6b47869df912dd3de04df4..d48ede52b071025e12a5514f8e604d89c5e9e400 100644 (file)
@@ -683,6 +683,10 @@ struct bootp_packet * prom_get_netinfo (void)
      void *bootp_response = NULL;
      char *propname;
      struct bootp_packet *packet;
+     /* struct bootp_packet contains a VLA, so sizeof won't work.
+        the VLA /must/ be the last field in the structure so use it's
+        offset as a good estimate of the packet size */
+     size_t packet_size = offsetof(struct bootp_packet, options);
      int i = 0, size, offset = 0;
      prom_handle chosen;
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
@@ -707,7 +711,7 @@ struct bootp_packet * prom_get_netinfo (void)
      if (size <= 0)
          return NULL;
 
-     if (sizeof(*packet) > size - offset) {
+     if (packet_size > size - offset) {
          prom_printf("Malformed %s property?\n", propname);
          return NULL;
      }
index e91b6c7bf5efa0943da4e606866ed020480cba7a..5df07608dacb297eda7352fa03c55013ec3d2f64 100644 (file)
@@ -300,6 +300,7 @@ void print_message_file(char *filename)
          }
 
      strncpy(msgpath, filename, sizeof(msgpath));
+     msgfile = boot; /* Copy all the original paramters */
      if (!parse_device_path(msgpath, defdev, defpart, "/etc/yaboot.msg", &msgfile)) {
          prom_printf("%s: Unable to parse\n", msgpath);
          goto done;
@@ -470,6 +471,8 @@ static int load_my_config_file(struct boot_fspec_t *orig_fspec)
      int minlen;
 
      packet = prom_get_netinfo();
+     if (!packet)
+          goto out;
 
      /*
       * First, try to match on mac address with the hardware type
@@ -988,6 +991,7 @@ int get_params(struct boot_param_t* params)
      if (!label && password)
          check_password ("To boot a custom image you must enter the password.");
 
+     params->kernel = boot; /* Copy all the original paramters */
      if (!parse_device_path(imagepath, defdevice, defpart,
                            "/vmlinux", &params->kernel)) {
          prom_printf("%s: Unable to parse\n", imagepath);
@@ -1009,6 +1013,7 @@ int get_params(struct boot_param_t* params)
                strncpy(initrdpath, p, 1024);
 
               DEBUG_F("Parsing initrd path <%s>\n", initrdpath);
+              params->rd = boot; /* Copy all the original paramters */
               if (!parse_device_path(initrdpath, defdevice, defpart,
                                      "/root.bin", &params->rd)) {
                    prom_printf("%s: Unable to parse\n", imagepath);
@@ -1019,6 +1024,7 @@ int get_params(struct boot_param_t* params)
          if (p && *p) {
               DEBUG_F("Parsing sysmap path <%s>\n", p);
               strncpy(sysmappath, p, 1024);
+              params->sysmap = boot; /* Copy all the original paramters */
               if (!parse_device_path(sysmappath, defdevice, defpart,
                                      "/boot/System.map", &params->sysmap)) {
                    prom_printf("%s: Unable to parse\n", imagepath);