diff -purN yaboot-1.3.14.orig/include/file.h yaboot-1.3.14/include/file.h --- yaboot-1.3.14.orig/include/file.h 2009-10-15 11:39:01.112642471 +1100 +++ yaboot-1.3.14/include/file.h 2009-10-15 15:29:04.692654961 +1100 @@ -45,6 +45,7 @@ struct boot_fspec_t { 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 */ diff -purN yaboot-1.3.14.orig/include/prom.h yaboot-1.3.14/include/prom.h --- yaboot-1.3.14.orig/include/prom.h 2009-10-15 15:23:39.796944672 +1100 +++ yaboot-1.3.14/include/prom.h 2009-10-15 15:29:04.692654961 +1100 @@ -153,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 -purN yaboot-1.3.14.orig/second/cfg.c yaboot-1.3.14/second/cfg.c --- yaboot-1.3.14.orig/second/cfg.c 2009-10-15 15:23:39.798647660 +1100 +++ yaboot-1.3.14/second/cfg.c 2009-10-15 15:29:04.693668247 +1100 @@ -597,6 +597,9 @@ int cfg_set_default_by_mac (char *mac_ad char * label = NULL; int haslabel = 0; + if (mac_addr == NULL) + return 0; + /* check if there is an image label equal to mac_addr */ for (tmp = images; tmp; tmp = tmp->next) { label = cfg_get_strg_i (tmp->table, "label"); diff -purN yaboot-1.3.14.orig/second/file.c yaboot-1.3.14/second/file.c --- yaboot-1.3.14.orig/second/file.c 2009-10-15 15:23:39.802647442 +1100 +++ yaboot-1.3.14/second/file.c 2009-10-15 15:29:04.694645423 +1100 @@ -51,6 +51,42 @@ ipv4_to_str(__u32 ip) return buf; } +/* FIXME: COMMENT */ +static char * is_valid_ip_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. @@ -130,12 +166,13 @@ extract_ipv4_args(char *imagepath, struc * read the arguments in order: siaddr,filename,ciaddr,giaddr, * bootp-retries,tftp-retries,addl_prameters */ - result->siaddr = scopy(&str, &args); + result->siaddr = is_valid_ip_str(scopy(&str, &args)); result->file = scopy(&str, &args); - result->ciaddr = scopy(&str, &args); - result->giaddr = scopy(&str, &args); + result->ciaddr = is_valid_ip_str(scopy(&str, &args)); + result->giaddr = is_valid_ip_str(scopy(&str, &args)); result->bootp_retries = scopy(&str, &args); result->tftp_retries = scopy(&str, &args); + result->subnetmask = scopy(&str, &args); if (*args) { result->addl_params = strdup(args); if (!result->addl_params) @@ -144,6 +181,82 @@ extract_ipv4_args(char *imagepath, struc return 1; } +/* 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 + +/* + * FIXME: COMMENT + */ +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; + } + + i += DHCP_COOKIE_SIZE; + + /* 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; + + if (tag == DHCP_PAD) + continue; + + 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); + } + /* FIXME: do we need to grok the subnet mask? */ + 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. @@ -170,16 +283,18 @@ extract_netinfo_args(struct boot_fspec_t if (packet->ciaddr == 0 && packet->yiaddr != 0) packet->ciaddr = packet->yiaddr; - if ((result->siaddr == NULL || *(result->siaddr) == NULL) + if ((result->siaddr == NULL || *(result->siaddr) == '\x0') && packet->siaddr != 0) result->siaddr = ipv4_to_str(packet->siaddr); - if ((result->ciaddr == NULL || *(result->ciaddr) == NULL) + if ((result->ciaddr == NULL || *(result->ciaddr) == '\x0') && packet->ciaddr != 0) result->ciaddr = ipv4_to_str(packet->ciaddr); - if ((result->giaddr == NULL || *(result->giaddr) == NULL) + 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 diff -purN yaboot-1.3.14.orig/second/fs_of.c yaboot-1.3.14/second/fs_of.c --- yaboot-1.3.14.orig/second/fs_of.c 2009-10-15 15:23:39.805647069 +1100 +++ yaboot-1.3.14/second/fs_of.c 2009-10-15 15:29:04.695645439 +1100 @@ -137,6 +137,7 @@ of_net_open(struct boot_file_t* file, static char buffer[1024]; char *filename = NULL; char *p; + int new_tftp; DEBUG_ENTER; DEBUG_OPEN; @@ -148,34 +149,47 @@ of_net_open(struct boot_file_t* file, *p = '\\'; } - DEBUG_F("siaddr <%s>; filename <%s>; ciaddr <%s>; giaddr <%s>; ipv6 <%d>\n", - fspec->siaddr, filename, fspec->ciaddr, fspec->giaddr, fspec->is_ipv6); + 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 (fspec->is_ipv6) strcat(buffer, TOK_IPV6 ","); - /* If we didn't get a ':' include one */ - if (fspec->dev[strlen(fspec->dev)-1] != ':') + else if (fspec->dev[strlen(fspec->dev)-1] != ':') strcat(buffer, ":"); - 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); - /* If /packages/cas exists the we have a "new skool" tftp */ - if (prom_finddevice("/packages/cas") != PROM_INVALID_HANDLE) { + /* 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 { - DEBUG_F("No \"/packages/cas\" using simple args\n") + strcat(buffer, ","); + strcat(buffer, filename); } DEBUG_F("Opening: \"%s\"\n", buffer); diff -purN yaboot-1.3.14.orig/second/prom.c yaboot-1.3.14/second/prom.c --- yaboot-1.3.14.orig/second/prom.c 2009-10-15 15:23:39.806647224 +1100 +++ yaboot-1.3.14/second/prom.c 2009-10-15 15:29:04.696645314 +1100 @@ -685,6 +685,10 @@ struct bootp_packet * prom_get_netinfo ( 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])) @@ -709,7 +713,7 @@ struct bootp_packet * prom_get_netinfo ( 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 -purN yaboot-1.3.14.orig/second/yaboot.c yaboot-1.3.14/second/yaboot.c --- yaboot-1.3.14.orig/second/yaboot.c 2009-10-15 15:23:39.809646432 +1100 +++ yaboot-1.3.14/second/yaboot.c 2009-10-15 15:29:04.697642396 +1100 @@ -471,6 +471,10 @@ static int load_my_config_file(struct bo int minlen; packet = prom_get_netinfo(); + if (packet == NULL) { + prom_printf("Failed to get netinfo data\n"); + return 0; + } /* * First, try to match on mac address with the hardware type