From 00a1f000b192f277e52b1d2ac63b2a066a9814a3 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 20 Jul 2006 02:49:59 +0000 Subject: [PATCH] Added dhcp_ipv4_option() and friends. Added test code to configure the interface for IPv4 after DHCP. --- src/include/gpxe/dhcp.h | 7 ++++++ src/net/dhcpopts.c | 55 +++++++++++++++++++++++++++++++++++++++++ src/tests/dhcptest.c | 41 +++++++++++++++++++++++++++++- 3 files changed, 102 insertions(+), 1 deletion(-) diff --git a/src/include/gpxe/dhcp.h b/src/include/gpxe/dhcp.h index 1dbb290e..115ce2be 100644 --- a/src/include/gpxe/dhcp.h +++ b/src/include/gpxe/dhcp.h @@ -250,6 +250,7 @@ struct dhcp_option { uint8_t byte; uint16_t word; uint32_t dword; + struct in_addr in; uint8_t bytes[0]; } data; } __attribute__ (( packed )); @@ -429,6 +430,8 @@ struct dhcp_session { }; extern unsigned long dhcp_num_option ( struct dhcp_option *option ); +extern void dhcp_ipv4_option ( struct dhcp_option *option, + struct in_addr *inp ); extern struct dhcp_option * find_dhcp_option ( struct dhcp_option_block *options, unsigned int tag ); extern void register_dhcp_options ( struct dhcp_option_block *options ); @@ -444,6 +447,10 @@ extern struct dhcp_option * find_global_dhcp_option ( unsigned int tag ); extern unsigned long find_dhcp_num_option ( struct dhcp_option_block *options, unsigned int tag ); extern unsigned long find_global_dhcp_num_option ( unsigned int tag ); +extern void find_dhcp_ipv4_option ( struct dhcp_option_block *options, + unsigned int tag, struct in_addr *inp ); +extern void find_global_dhcp_ipv4_option ( unsigned int tag, + struct in_addr *inp ); extern void delete_dhcp_option ( struct dhcp_option_block *options, unsigned int tag ); diff --git a/src/net/dhcpopts.c b/src/net/dhcpopts.c index 4f67f846..ebd6de75 100644 --- a/src/net/dhcpopts.c +++ b/src/net/dhcpopts.c @@ -24,6 +24,7 @@ #include #include #include +#include #include /** @file @@ -85,6 +86,21 @@ unsigned long dhcp_num_option ( struct dhcp_option *option ) { return value; } +/** + * Obtain value of an IPv4-address DHCP option + * + * @v option DHCP option, or NULL + * @v inp IPv4 address to fill in + * + * Parses the IPv4 address value from a DHCP option, if present. It + * is permitted to call dhcp_ipv4_option() with @c option set to NULL; + * in this case the address will be set to 0.0.0.0. + */ +void dhcp_ipv4_option ( struct dhcp_option *option, struct in_addr *inp ) { + if ( option ) + *inp = option->data.in; +} + /** * Calculate length of a normal DHCP option * @@ -460,6 +476,45 @@ unsigned long find_global_dhcp_num_option ( unsigned int tag ) { return dhcp_num_option ( find_global_dhcp_option ( tag ) ); } +/** + * Find DHCP IPv4-address option, and return its value + * + * @v options DHCP options block + * @v tag DHCP option tag to search for + * @v inp IPv4 address to fill in + * @ret value Numerical value of the option, or 0 if not found + * + * This function exists merely as a notational shorthand for a call to + * find_dhcp_option() followed by a call to dhcp_ipv4_option(). It is + * not possible to distinguish between the cases "option not found" + * and "option has a value of 0.0.0.0" using this function; if this + * matters to you then issue the two constituent calls directly and + * check that find_dhcp_option() returns a non-NULL value. + */ +void find_dhcp_ipv4_option ( struct dhcp_option_block *options, + unsigned int tag, struct in_addr *inp ) { + dhcp_ipv4_option ( find_dhcp_option ( options, tag ), inp ); +} + +/** + * Find DHCP IPv4-address option, and return its value + * + * @v options DHCP options block + * @v tag DHCP option tag to search for + * @v inp IPv4 address to fill in + * @ret value Numerical value of the option, or 0 if not found + * + * This function exists merely as a notational shorthand for a call to + * find_dhcp_option() followed by a call to dhcp_ipv4_option(). It is + * not possible to distinguish between the cases "option not found" + * and "option has a value of 0.0.0.0" using this function; if this + * matters to you then issue the two constituent calls directly and + * check that find_dhcp_option() returns a non-NULL value. + */ +void find_global_dhcp_ipv4_option ( unsigned int tag, struct in_addr *inp ) { + dhcp_ipv4_option ( find_global_dhcp_option ( tag ), inp ); +} + /** * Delete DHCP option * diff --git a/src/tests/dhcptest.c b/src/tests/dhcptest.c index d35e02c2..b61535f2 100644 --- a/src/tests/dhcptest.c +++ b/src/tests/dhcptest.c @@ -1,10 +1,49 @@ #include +#include +#include +#include #include int test_dhcp ( struct net_device *netdev ) { struct dhcp_session dhcp; + struct in_addr address = { htonl ( 0 ) }; + struct in_addr netmask = { htonl ( 0 ) }; + struct in_addr gateway = { INADDR_NONE }; + int rc; + /* Bring IP interface up with address 0.0.0.0 */ + if ( ( rc = add_ipv4_address ( netdev, address, netmask, + gateway ) ) != 0 ) + goto out_no_del_ipv4; + + /* Issue DHCP request */ memset ( &dhcp, 0, sizeof ( dhcp ) ); dhcp.netdev = netdev; - return async_wait ( start_dhcp ( &dhcp ) ); + if ( ( rc = async_wait ( start_dhcp ( &dhcp ) ) ) != 0 ) + goto out_no_options; + + /* Retrieve IP address configuration */ + find_dhcp_ipv4_option ( dhcp.options, DHCP_EB_YIADDR, &address ); + find_dhcp_ipv4_option ( dhcp.options, DHCP_SUBNET_MASK, &netmask ); + find_dhcp_ipv4_option ( dhcp.options, DHCP_ROUTERS, &gateway ); + + /* Remove old IP address configuration */ + del_ipv4_address ( netdev ); + + /* Set up new IP address configuration */ + if ( ( rc = add_ipv4_address ( netdev, address, netmask, + gateway ) ) != 0 ) + goto out_no_del_ipv4; + + printf ( "IP %s", inet_ntoa ( address ) ); + printf ( " netmask %s", inet_ntoa ( netmask ) ); + printf ( " gateway %s\n", inet_ntoa ( gateway ) ); + + /* Free DHCP options */ + free_dhcp_options ( dhcp.options ); + out_no_options: + /* Take down IP interface */ + del_ipv4_address ( netdev ); + out_no_del_ipv4: + return rc; }