From: Tony Breeds Date: Tue, 5 May 2009 06:14:20 +0000 (+1000) Subject: Add parseing for Vendor options aka DHCP options. X-Git-Tag: yaboot-1.3.17-rc1~28^2~4 X-Git-Url: http://git.ozlabs.org/?p=yaboot.git;a=commitdiff_plain;h=f91756b6306e4da8aef013c8b375b32c2c0c3a2f Add parseing for Vendor options aka DHCP options. If we have DHCP options process them. Signed-off-by: Tony Breeds --- diff --git a/include/prom.h b/include/prom.h index eacee77..e0397ec 100644 --- a/include/prom.h +++ b/include/prom.h @@ -152,7 +152,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 5d5ccbd..0ad981b 100644 --- a/second/file.c +++ b/second/file.c @@ -144,6 +144,78 @@ extract_ipv4_args(char *imagepath, struct boot_fspec_t *result) 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 + +/* + * 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; + } + + 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; jgiaddr == 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 +242,18 @@ extract_netinfo_args(struct boot_fspec_t *result) 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 --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; }