From 8e64db245a2d402dc89fa1f68a3789203815b238 Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Thu, 5 Mar 2009 15:04:47 +1100 Subject: [PATCH 1/1] Enhance the parseing of IPv4 information. Pull information out of the bootp-reply (or similar) property. This successfully netboots in a wider variety of OF "boot" lines. Signed-off-by: Tony Breeds --- second/file.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++--- second/fs_of.c | 21 ++++++++++----- second/yaboot.c | 2 ++ 3 files changed, 86 insertions(+), 9 deletions(-) diff --git a/second/file.c b/second/file.c index 875cad8..5d5ccbd 100644 --- a/second/file.c +++ b/second/file.c @@ -38,6 +38,19 @@ extern char bootdevice[]; +/* Convert __u32 into std, dotted quad string, leaks like a sive :( */ +static char * +ipv4_to_str(__u32 ip) +{ + char *buf = malloc(sizeof("000.000.000.000")); + + sprintf(buf,"%u.%u.%u.%u", + (ip & 0xff000000) >> 24, (ip & 0x00ff0000) >> 16, + (ip & 0x0000ff00) >> 8, (ip & 0x000000ff)); + + return buf; +} + /* * Copy the string from source to dest till newline or comma(,) is seen * in the source. @@ -131,12 +144,60 @@ extract_ipv4_args(char *imagepath, struct boot_fspec_t *result) return 1; } +/* + * 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) == NULL) + && packet->siaddr != 0) + result->siaddr = ipv4_to_str(packet->siaddr); + if ((result->ciaddr == NULL || *(result->ciaddr) == NULL) + && packet->ciaddr != 0) + result->ciaddr = ipv4_to_str(packet->ciaddr); + if ((result->giaddr == NULL || *(result->giaddr) == NULL) + && packet->giaddr != 0) + result->giaddr = ipv4_to_str(packet->giaddr); + + /* 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 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) +extract_netboot_args(char *imagepath, struct boot_fspec_t *result) { int ret; @@ -146,6 +207,7 @@ extract_args_from_netdev_path(char *imagepath, struct boot_fspec_t *result) return 1; ret = extract_ipv4_args(imagepath, result); + ret |= extract_netinfo_args(result); DEBUG_F("siaddr = <%s>\n", result->siaddr); DEBUG_F("file = <%s>\n", result->file); @@ -154,6 +216,7 @@ extract_args_from_netdev_path(char *imagepath, struct boot_fspec_t *result) 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 ret; } @@ -293,10 +356,13 @@ parse_device_path(char *imagepath, char *defdevice, int defpart, if (device_kind == FILE_DEVICE_NET) { if (strchr(ipath, ':')) { - if (extract_args_from_netdev_path(ipath, result) == 0) + if (extract_netboot_args(ipath, result) == 0) return 0; - } else + } 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); diff --git a/second/fs_of.c b/second/fs_of.c index ecc0366..5c7dd9b 100644 --- a/second/fs_of.c +++ b/second/fs_of.c @@ -151,6 +151,9 @@ of_net_open(struct boot_file_t* file, DEBUG_F("siaddr <%s>; filename <%s>; ciaddr <%s>; giaddr <%s>;\n", fspec->siaddr, filename, fspec->ciaddr, fspec->giaddr); strncpy(buffer, fspec->dev, 768); + /* If we didn't get a ':' include one */ + if (fspec->dev[strlen(fspec->dev)-1] != ':') + strcat(buffer, ":"); strcat(buffer, fspec->siaddr); strcat(buffer, ","); strcat(buffer, filename); @@ -158,12 +161,18 @@ of_net_open(struct boot_file_t* file, 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); + + /* If /packages/cas exists the we have a "new skool" tftp */ + if (prom_finddevice("/packages/cas") != PROM_INVALID_HANDLE) { + strcat(buffer, ","); + strcat(buffer, fspec->bootp_retries); + strcat(buffer, ","); + strcat(buffer, fspec->tftp_retries); + strcat(buffer, ","); + strcat(buffer, fspec->addl_params); + } else { + DEBUG_F("No \"/packages/cas\" using simple args\n") + } DEBUG_F("Opening: \"%s\"\n", buffer); diff --git a/second/yaboot.c b/second/yaboot.c index 8a74d7a..66f288b 100644 --- a/second/yaboot.c +++ b/second/yaboot.c @@ -471,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 -- 2.39.2