From: Tony Breeds Date: Thu, 22 Oct 2009 05:17:10 +0000 (+1100) Subject: Merge branch 'birecs' into devel X-Git-Tag: yaboot-1.3.17-rc1~26^2~2 X-Git-Url: http://git.ozlabs.org/?p=yaboot.git;a=commitdiff_plain;h=9a83909ef3d17b0ea205d32b6aa07ac6bea7260c;hp=fac08a190a9d932020b6f9275783aba2bd0902c4 Merge branch 'birecs' into devel --- diff --git a/include/debug.h b/include/debug.h index 47a9cce..dcac25a 100644 --- a/include/debug.h +++ b/include/debug.h @@ -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 diff --git a/include/file.h b/include/file.h index b6b9fe5..b2d9c63 100644 --- a/include/file.h +++ b/include/file.h @@ -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 diff --git a/include/fs.h b/include/fs.h index d960fea..1ff7986 100644 --- a/include/fs.h +++ b/include/fs.h @@ -27,14 +27,14 @@ #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 diff --git a/include/prom.h b/include/prom.h index eacee77..a512f2b 100644 --- a/include/prom.h +++ b/include/prom.h @@ -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); diff --git a/second/file.c b/second/file.c index 4054dd1..81d91a9 100644 --- a/second/file.c +++ b/second/file.c @@ -38,19 +38,92 @@ 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; jsubnetmask == 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; } diff --git a/second/fs.c b/second/fs.c index 2ae7066..b748bed 100644 --- a/second/fs.c +++ b/second/fs.c @@ -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; diff --git a/second/fs_ext2.c b/second/fs_ext2.c index 67571f2..d24450d 100644 --- a/second/fs_ext2.c +++ b/second/fs_ext2.c @@ -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; diff --git a/second/fs_iso.c b/second/fs_iso.c index 303790f..33d43b3 100644 --- a/second/fs_iso.c +++ b/second/fs_iso.c @@ -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; } diff --git a/second/fs_of.c b/second/fs_of.c index 95c131d..bd481e4 100644 --- a/second/fs_of.c +++ b/second/fs_of.c @@ -45,17 +45,17 @@ #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); diff --git a/second/fs_reiserfs.c b/second/fs_reiserfs.c index 238f523..4b83a7a 100644 --- a/second/fs_reiserfs.c +++ b/second/fs_reiserfs.c @@ -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; diff --git a/second/fs_xfs.c b/second/fs_xfs.c index 04d6cf3..e27d857 100644 --- a/second/fs_xfs.c +++ b/second/fs_xfs.c @@ -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; diff --git a/second/prom.c b/second/prom.c index 4ad7277..d48ede5 100644 --- a/second/prom.c +++ b/second/prom.c @@ -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; } diff --git a/second/yaboot.c b/second/yaboot.c index e91b6c7..5df0760 100644 --- a/second/yaboot.c +++ b/second/yaboot.c @@ -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", ¶ms->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", ¶ms->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", ¶ms->sysmap)) { prom_printf("%s: Unable to parse\n", imagepath);