Fix netboot fucntionality to use the parameters specified.
authorChandra Seetharaman <sekharan@us.ibm.com>
Fri, 9 Jan 2009 13:57:44 +0000 (05:57 -0800)
committerTony Breeds <tony@bakeyournoodle.com>
Thu, 5 Mar 2009 00:07:23 +0000 (11:07 +1100)
Currently, yaboot works properly when there is a tftp boot server serving
the broadcast requests sent in the network.

If the user specifies siaddr, ciaddr, and other arguments in the command
line, it is not handled appropriately.

This patch changes that behavior and make yaboot work properly in both cases.

The semantics specified in section 4.1 of
http://playground.sun.com/1275/practice/obp-tftp/tftp1_0.pdf is followed.
([bootp,]siaddr,filename,ciaddr,giaddr,bootp-retries,tftp-retries)

Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
---

include/file.h
second/file.c
second/fs_of.c
second/yaboot.c

index 3434388f43ead6876d9ee0db0cf982ef9a4c1c18..ca76a52238559f62028a60abc290f2fa3acd00ee 100644 (file)
@@ -39,7 +39,13 @@ 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*   addl_params;    /* copy all additional parameters */
 };
 
 struct boot_file_t {
index 0082eae4c5abea524c766daa00162364d1bf2b01..e5135995a74e33fb73ebec5e318b8baa71c5f033 100644 (file)
 
 extern char bootdevice[];
 
-static char *netdev_path_to_filename(const char *path)
+/*
+ * 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 *tmp, *args, *filename;
-     size_t len;
-
-     DEBUG_F("path = %s\n", path);
+     char *ret = *dest;
 
-     if (!path)
+     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 arguments provided in the imagepath and fill it in result.
+ * Returns 1 on success, 0 on failure.
+ */
+static int
+extract_args_from_netdev_path(char *imagepath, struct boot_fspec_t *result)
+{
+     char *tmp, *args, *str, *start;
+
+     DEBUG_F("imagepath = %s\n", imagepath);
+
+     if (!imagepath)
+         return 1;
+
+     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 +106,42 @@ static char *netdev_path_to_filename(const char *path)
      if (tmp && tmp > args)
          args = tmp + strlen("rarp");
 
-     args = strchr(args, ',');
-     if (!args)
-         return NULL;
-
-     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.
-      */
-     args++;
-     if (*tmp != ':') {
+     if (args != start) /* we read some parameters, so go past the next comma(,) */
          args = strchr(args, ',');
-         if (!args)
-              return NULL;
-         args++;
-     }
-
-     /* filename may be empty; e.g. enet:192.168.1.1,,192.168.1.2 */
-     if (*args == ',') {
-         DEBUG_F("null filename\n");
-         return NULL;
-     }
+     if (!args)
+         return 1;
 
-     /* Now see whether there are more args following the filename. */
-     tmp = strchr(args, ',');
-     if (!tmp)
-         len = strlen(args) + 1;
-     else
-         len = tmp - args + 1;
+     str = malloc(strlen(args) + 1); /*long enough to hold all strings */
+     if (!str)
+         return 0;
 
-     filename = malloc(len);
-     if (!filename)
-         return NULL;
+     if (args[-1] != ':')
+         args++; /* If comma(,) is not immediately followed by ':' then go past the , */
 
-     strncpy(filename, args, len);
-     filename[len - 1] = '\0';
+     /*
+      * read the arguments in order: siaddr,filename,ciaddr,giaddr,
+      * bootp-retries,tftp-retries,addl_prameters
+      */
+     result->siaddr = scopy(&str, &args);
+     result->file = scopy(&str, &args);
+     result->ciaddr = scopy(&str, &args);
+     result->giaddr = scopy(&str, &args);
+     result->bootp_retries = scopy(&str, &args);
+     result->tftp_retries = scopy(&str, &args);
+     if (*args) {
+         result->addl_params = strdup(args);
+         if (!result->addl_params)
+               return 0;
+     }
 
-     DEBUG_F("filename = %s\n", filename);
-     return filename;
+     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);
+     return 1;
 }
 
 static char *netdev_path_to_dev(const char *path)
@@ -163,6 +188,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 +208,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,9 +279,10 @@ 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_args_from_netdev_path(ipath, result) == 0)
+                  return 0;
+         } else
               result->file = strdup(ipath);
 
          if (!defdev)
index 4e61d7d23d446cc9ede24e6f0eadab97a6ca98c1..ecc0366dae5c62ccf017ceac2f9e1aab69d40819 100644 (file)
@@ -135,23 +135,36 @@ 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;
 
      DEBUG_ENTER;
      DEBUG_OPEN;
 
-     strncpy(buffer, fspec->dev, 768);
      if (fspec->file && strlen(fspec->file)) {
-         strcat(buffer, ",");
          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>;\n",
+               fspec->siaddr, filename, fspec->ciaddr, fspec->giaddr);
+     strncpy(buffer, fspec->dev, 768);
+     strcat(buffer, fspec->siaddr);
+     strcat(buffer, ",");
+     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->addl_params);
+
      DEBUG_F("Opening: \"%s\"\n", buffer);
 
      file->of_device = prom_open(buffer);
index 3db7b4fe03f04b42c67adb703748246dcb37a066..8a74d7a5de89c1749738dbe775356655968362b0 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;
@@ -988,6 +989,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 +1011,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 +1022,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);