Update DHCP to use data-xfer interface (not yet tested).
authorMichael Brown <mcb30@etherboot.org>
Wed, 27 Jun 2007 22:20:36 +0000 (23:20 +0100)
committerMichael Brown <mcb30@etherboot.org>
Wed, 27 Jun 2007 22:20:36 +0000 (23:20 +0100)
src/core/nvo.c
src/include/gpxe/dhcp.h
src/include/gpxe/xfer.h
src/net/dhcpopts.c
src/net/udp.c
src/net/udp/dhcp.c
src/tests/dhcptest.c
src/usr/dhcpmgmt.c

index 14ed4e1..8c6c9c0 100644 (file)
@@ -194,7 +194,7 @@ int nvo_register ( struct nvo_block *nvo ) {
        return 0;
        
  err:
-       free_dhcp_options ( nvo->options );
+       dhcpopt_put ( nvo->options );
        nvo->options = NULL;
        return rc;
 }
@@ -208,7 +208,7 @@ void nvo_unregister ( struct nvo_block *nvo ) {
 
        if ( nvo->options ) {
                unregister_dhcp_options ( nvo->options );
-               free_dhcp_options ( nvo->options );
+               dhcpopt_put ( nvo->options );
                nvo->options = NULL;
        }
 
index 16609ba..1f68742 100644 (file)
 #include <stdint.h>
 #include <gpxe/list.h>
 #include <gpxe/in.h>
-#include <gpxe/udp.h>
-#include <gpxe/async.h>
-#include <gpxe/retry.h>
+#include <gpxe/refcnt.h>
+
+struct net_device;
+struct job_interface;
 
 /** BOOTP/DHCP server port */
 #define BOOTPS_PORT 67
@@ -312,6 +313,8 @@ struct dhcp_option {
 
 /** A DHCP options block */
 struct dhcp_option_block {
+       /** Reference counter */
+       struct refcnt refcnt;
        /** List of option blocks */
        struct list_head list;
        /** Option block raw data */
@@ -413,6 +416,13 @@ struct dhcphdr {
 /** DHCP magic cookie */
 #define DHCP_MAGIC_COOKIE 0x63825363UL
 
+/** DHCP minimum packet length
+ *
+ * This is the mandated minimum packet length that a DHCP participant
+ * must be prepared to receive.
+ */
+#define DHCP_MIN_LEN 552
+
 /** DHCP packet option block fill order
  *
  * This is the order in which option blocks are filled when
@@ -448,30 +458,27 @@ struct dhcp_packet {
        struct dhcp_option_block options[NUM_OPT_BLOCKS];
 };
 
-struct udp_connection {};
-
-/** A DHCP session */
-struct dhcp_session {
-       /** UDP connection for this session */
-       struct udp_connection udp;
-
-       /** Network device being configured */
-       struct net_device *netdev;
-
-       /** Options obtained from server */
-       struct dhcp_option_block *options;
+/**
+ * Get reference to DHCP options block
+ *
+ * @v options          DHCP options block
+ * @ret options                DHCP options block
+ */
+static inline __attribute__ (( always_inline )) struct dhcp_option_block *
+dhcpopt_get ( struct dhcp_option_block *options ) {
+       ref_get ( &options->refcnt );
+       return options;
+}
 
-       /** State of the session
-        *
-        * This is a value for the @c DHCP_MESSAGE_TYPE option
-        * (e.g. @c DHCPDISCOVER).
-        */
-       int state;
-       /** Asynchronous operation for this DHCP session */
-       struct async async;
-       /** Retransmission timer */
-       struct retry_timer timer;
-};
+/**
+ * Drop reference to DHCP options block
+ *
+ * @v options          DHCP options block
+ */
+static inline __attribute__ (( always_inline )) void
+dhcpopt_put ( struct dhcp_option_block *options ) {
+       ref_put ( &options->refcnt );
+}
 
 extern unsigned long dhcp_num_option ( struct dhcp_option *option );
 extern void dhcp_ipv4_option ( struct dhcp_option *option,
@@ -485,7 +492,6 @@ extern void unregister_dhcp_options ( struct dhcp_option_block *options );
 extern void init_dhcp_options ( struct dhcp_option_block *options,
                                void *data, size_t max_len );
 extern struct dhcp_option_block * alloc_dhcp_options ( size_t max_len );
-extern void free_dhcp_options ( struct dhcp_option_block *options );
 extern struct dhcp_option *
 set_dhcp_option ( struct dhcp_option_block *options, unsigned int tag,
                  const void *data, size_t len );
@@ -506,6 +512,7 @@ extern int create_dhcp_packet ( struct net_device *netdev, uint8_t msgtype,
                                struct dhcp_packet *dhcppkt );
 extern int copy_dhcp_packet_options ( struct dhcp_packet *dhcppkt,
                                      struct dhcp_option_block *options );
-extern int start_dhcp ( struct dhcp_session *dhcp, struct async *parent );
+extern int start_dhcp ( struct job_interface *job, struct net_device *netdev,
+                       int (*register_options) ( struct dhcp_option_block * ));
 
 #endif /* _GPXE_DHCP_H */
index 0224613..55c5b17 100644 (file)
@@ -115,6 +115,8 @@ struct xfer_metadata {
        struct sockaddr *src;
        /** Destination socket address, or NULL */
        struct sockaddr *dest;
+       /** Network device, or NULL */
+       struct net_device *netdev;
 };
 
 /** Basis positions for seek() events */
index b2a2266..bb97731 100644 (file)
@@ -280,6 +280,7 @@ void register_dhcp_options ( struct dhcp_option_block *options ) {
                if ( options->priority > existing->priority )
                        break;
        }
+       dhcpopt_get ( options );
        list_add_tail ( &options->list, &existing->list );
 }
 
@@ -290,6 +291,7 @@ void register_dhcp_options ( struct dhcp_option_block *options ) {
  */
 void unregister_dhcp_options ( struct dhcp_option_block *options ) {
        list_del ( &options->list );
+       dhcpopt_put ( options );
 }
 
 /**
@@ -337,15 +339,6 @@ struct dhcp_option_block * alloc_dhcp_options ( size_t max_len ) {
        return options;
 }
 
-/**
- * Free DHCP options block
- *
- * @v options          DHCP option block
- */
-void free_dhcp_options ( struct dhcp_option_block *options ) {
-       free ( options );
-}
-
 /**
  * Resize a DHCP option
  *
index 404dd72..c99a3eb 100644 (file)
@@ -183,17 +183,16 @@ static void udp_close ( struct udp_connection *udp, int rc ) {
  * @v iobuf            I/O buffer
  * @v src_port         Source port, or 0 to use default
  * @v dest             Destination address, or NULL to use default
+ * @v netdev           Network device, or NULL to use default
  * @ret rc             Return status code
  */
 static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
-                   unsigned int src_port, struct sockaddr_tcpip *dest ) {
+                   unsigned int src_port, struct sockaddr_tcpip *dest,
+                   struct net_device *netdev ) {
                struct udp_header *udphdr;
-       struct net_device *netdev = NULL;
        size_t len;
        int rc;
 
-#warning "netdev?"
-
        /* Check we can accommodate the header */
        if ( ( rc = iob_ensure_headroom ( iobuf, UDP_MAX_HLEN ) ) != 0 ) {
                free_iob ( iobuf );
@@ -394,6 +393,7 @@ static int udp_xfer_deliver_iob ( struct xfer_interface *xfer,
                container_of ( xfer, struct udp_connection, xfer );
        struct sockaddr_tcpip *src;
        struct sockaddr_tcpip *dest = NULL;
+       struct net_device *netdev = NULL;
        unsigned int src_port = 0;
 
        /* Apply xfer metadata */
@@ -402,10 +402,11 @@ static int udp_xfer_deliver_iob ( struct xfer_interface *xfer,
                if ( src )
                        src_port = src->st_port;
                dest = ( struct sockaddr_tcpip * ) meta->dest;
+               netdev = meta->netdev;
        }
 
        /* Transmit data, if possible */
-       udp_tx ( udp, iobuf, src_port, dest );
+       udp_tx ( udp, iobuf, src_port, dest, netdev );
 
        return 0;
 }
index 4ecb17b..e5a95b3 100644 (file)
  */
 
 #include <string.h>
+#include <stdlib.h>
 #include <errno.h>
 #include <assert.h>
 #include <byteswap.h>
 #include <gpxe/if_ether.h>
 #include <gpxe/netdevice.h>
-#include <gpxe/udp.h>
+#include <gpxe/xfer.h>
+#include <gpxe/open.h>
+#include <gpxe/job.h>
+#include <gpxe/retry.h>
 #include <gpxe/dhcp.h>
 
 /** @file
@@ -387,7 +391,6 @@ static void merge_dhcp_field ( struct dhcp_option_block *options,
 /**
  * Parse DHCP packet and construct DHCP options block
  *
- * @v dhcp             DHCP session
  * @v dhcphdr          DHCP packet
  * @v len              Length of DHCP packet
  * @ret options                DHCP options block, or NULL
@@ -407,8 +410,7 @@ static void merge_dhcp_field ( struct dhcp_option_block *options,
  * options block; it is the responsibility of the caller to eventually
  * free this memory.
  */
-static struct dhcp_option_block * dhcp_parse ( struct dhcp_session *dhcp,
-                                              struct dhcphdr *dhcphdr,
+static struct dhcp_option_block * dhcp_parse ( const struct dhcphdr *dhcphdr,
                                               size_t len ) {
        struct dhcp_option_block *options;
        size_t options_len;
@@ -443,8 +445,8 @@ static struct dhcp_option_block * dhcp_parse ( struct dhcp_session *dhcp,
        /* Allocate empty options block of required size */
        options = alloc_dhcp_options ( options_len );
        if ( ! options ) {
-               DBGC ( dhcp, "DHCP %p could not allocate %d-byte option "
-                      "block\n", dhcp, options_len );
+               DBG ( "DHCP could not allocate %d-byte option block\n",
+                     options_len );
                return NULL;
        }
        
@@ -488,12 +490,45 @@ static struct dhcp_option_block * dhcp_parse ( struct dhcp_session *dhcp,
  *
  */
 
-static inline struct dhcp_session *
-udp_to_dhcp ( struct udp_connection *conn ) {
-       return container_of ( conn, struct dhcp_session, udp );
-}
+/** A DHCP session */
+struct dhcp_session {
+       /** Reference counter */
+       struct refcnt refcnt;
+       /** Job control interface */
+       struct job_interface job;
+       /** Data transfer interface */
+       struct xfer_interface xfer;
+
+       /** Network device being configured */
+       struct net_device *netdev;
+       /** Option block registration routine */
+       int ( * register_options ) ( struct dhcp_option_block *options );
+
+       /** State of the session
+        *
+        * This is a value for the @c DHCP_MESSAGE_TYPE option
+        * (e.g. @c DHCPDISCOVER).
+        */
+       int state;
+       /** Options obtained from server */
+       struct dhcp_option_block *options;
+       /** Retransmission timer */
+       struct retry_timer timer;
+};
+
+/**
+ * Free DHCP session
+ *
+ * @v refcnt           Reference counter
+ */
+static void dhcp_free ( struct refcnt *refcnt ) {
+       struct dhcp_session *dhcp =
+               container_of ( refcnt, struct dhcp_session, refcnt );
 
-#if 0
+       netdev_put ( dhcp->netdev );
+       dhcpopt_put ( dhcp->options );
+       free ( dhcp );
+}
 
 /**
  * Mark DHCP session as complete
@@ -501,50 +536,38 @@ udp_to_dhcp ( struct udp_connection *conn ) {
  * @v dhcp             DHCP session
  * @v rc               Return status code
  */
-static void dhcp_done ( struct dhcp_session *dhcp, int rc ) {
+static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) {
 
-       /* Free up options if we failed */
-       if ( rc != 0 ) {
-               if ( dhcp->options ) {
-                       free_dhcp_options ( dhcp->options );
-                       dhcp->options = NULL;
-               }
-       }
+       /* Block futher incoming messages */
+       job_nullify ( &dhcp->job );
+       xfer_nullify ( &dhcp->xfer );
 
        /* Stop retry timer */
        stop_timer ( &dhcp->timer );
 
-       /* Close UDP connection */
-       udp_close ( &dhcp->udp );
-
-       /* Mark async operation as complete */
-       async_done ( &dhcp->async, rc );
+       /* Free resources and close interfaces */
+       xfer_close ( &dhcp->xfer, rc );
+       job_done ( &dhcp->job, rc );
 }
 
-/** Address for transmitting DHCP requests */
-static union {
-       struct sockaddr_tcpip st;
-       struct sockaddr_in sin;
-} sa_dhcp_server = {
-       .sin = {
-               .sin_family = AF_INET,
-               .sin_addr.s_addr = INADDR_BROADCAST,
-               .sin_port = htons ( BOOTPS_PORT ),
-       },
-};
+/****************************************************************************
+ *
+ * Data transfer interface
+ *
+ */
 
 /**
  * Transmit DHCP request
  *
- * @v conn             UDP connection
- * @v buf              Temporary data buffer
- * @v len              Length of temporary data buffer
+ * @v dhcp             DHCP session
  * @ret rc             Return status code
  */
-static int dhcp_senddata ( struct udp_connection *conn,
-                          void *buf, size_t len ) {
-       struct dhcp_session *dhcp = udp_to_dhcp ( conn );
+static int dhcp_send_request ( struct dhcp_session *dhcp ) {
+       struct xfer_metadata meta = {
+               .netdev = dhcp->netdev,
+       };
        struct dhcp_packet dhcppkt;
+       struct io_buffer *iobuf;
        int rc;
        
        DBGC ( dhcp, "DHCP %p transmitting %s\n",
@@ -553,12 +576,23 @@ static int dhcp_senddata ( struct udp_connection *conn,
        assert ( ( dhcp->state == DHCPDISCOVER ) ||
                 ( dhcp->state == DHCPREQUEST ) );
 
+       /* Start retry timer.  Do this first so that failures to
+        * transmit will be retried.
+        */
+       start_timer ( &dhcp->timer );
+
+       /* Allocate buffer for packet */
+       iobuf = xfer_alloc_iob ( &dhcp->xfer, DHCP_MIN_LEN );
+       if ( ! iobuf )
+               return -ENOMEM;
+
        /* Create DHCP packet in temporary buffer */
-       if ( ( rc = create_dhcp_packet ( dhcp->netdev, dhcp->state, buf, len,
+       if ( ( rc = create_dhcp_packet ( dhcp->netdev, dhcp->state,
+                                        iobuf->data, iob_tailroom ( iobuf ),
                                         &dhcppkt ) ) != 0 ) {
                DBGC ( dhcp, "DHCP %p could not create DHCP packet: %s\n",
                       dhcp, strerror ( rc ) );
-               return rc;
+               goto done;
        }
 
        /* Copy in options common to all requests */
@@ -566,7 +600,7 @@ static int dhcp_senddata ( struct udp_connection *conn,
                                               &dhcp_request_options ) ) != 0){
                DBGC ( dhcp, "DHCP %p could not set common DHCP options: %s\n",
                       dhcp, strerror ( rc ) );
-               return rc;
+               goto done;
        }
 
        /* Copy any required options from previous server repsonse */
@@ -576,36 +610,30 @@ static int dhcp_senddata ( struct udp_connection *conn,
                                            DHCP_SERVER_IDENTIFIER ) ) != 0 ) {
                        DBGC ( dhcp, "DHCP %p could not set server identifier "
                               "option: %s\n", dhcp, strerror ( rc ) );
-                       return rc;
+                       goto done;
                }
                if ( ( rc = copy_dhcp_packet_option ( &dhcppkt, dhcp->options,
                                            DHCP_EB_YIADDR,
                                            DHCP_REQUESTED_ADDRESS ) ) != 0 ) {
                        DBGC ( dhcp, "DHCP %p could not set requested address "
                               "option: %s\n", dhcp, strerror ( rc ) );
-                       return rc;
+                       goto done;
                }
        }
 
        /* Transmit the packet */
-       if ( ( rc = udp_sendto_via ( conn, &sa_dhcp_server.st, dhcp->netdev,
-                                    dhcppkt.dhcphdr, dhcppkt.len ) ) != 0 ) {
+       iob_put ( iobuf, dhcppkt.len );
+       rc = xfer_deliver_iob_meta ( &dhcp->xfer, iobuf, &meta );
+       iobuf = NULL;
+       if ( rc != 0 ) {
                DBGC ( dhcp, "DHCP %p could not transmit UDP packet: %s\n",
                       dhcp, strerror ( rc ) );
-               return rc;
+               goto done;
        }
 
-       return 0;
-}
-
-/**
- * Transmit DHCP request
- *
- * @v dhcp             DHCP session
- */
-static void dhcp_send_request ( struct dhcp_session *dhcp ) {
-       start_timer ( &dhcp->timer );
-       udp_senddata ( &dhcp->udp );
+ done:
+       free_iob ( iobuf );
+       return rc;
 }
 
 /**
@@ -619,7 +647,7 @@ static void dhcp_timer_expired ( struct retry_timer *timer, int fail ) {
                container_of ( timer, struct dhcp_session, timer );
 
        if ( fail ) {
-               dhcp_done ( dhcp, -ETIMEDOUT );
+               dhcp_finished ( dhcp, -ETIMEDOUT );
        } else {
                dhcp_send_request ( dhcp );
        }
@@ -628,17 +656,17 @@ static void dhcp_timer_expired ( struct retry_timer *timer, int fail ) {
 /**
  * Receive new data
  *
- * @v udp              UDP connection
+ * @v xfer             Data transfer interface
+ * @v iobuf            I/O buffer
  * @v data             Received data
  * @v len              Length of received data
- * @v st_src           Partially-filled source address
- * @v st_dest          Partially-filled destination address
+ * @ret rc             Return status code
  */
-static int dhcp_newdata ( struct udp_connection *conn, void *data, size_t len,
-                         struct sockaddr_tcpip *st_src __unused,
-                         struct sockaddr_tcpip *st_dest __unused ) {
-       struct dhcp_session *dhcp = udp_to_dhcp ( conn );
-       struct dhcphdr *dhcphdr = data;
+static int dhcp_deliver_raw ( struct xfer_interface *xfer,
+                             const void *data, size_t len ) {
+       struct dhcp_session *dhcp =
+               container_of ( xfer, struct dhcp_session, xfer );
+       const struct dhcphdr *dhcphdr = data;
        struct dhcp_option_block *options;
        unsigned int msgtype;
 
@@ -651,7 +679,7 @@ static int dhcp_newdata ( struct udp_connection *conn, void *data, size_t len,
        };
 
        /* Parse packet and create options structure */
-       options = dhcp_parse ( dhcp, dhcphdr, len );
+       options = dhcp_parse ( dhcphdr, len );
        if ( ! options ) {
                DBGC ( dhcp, "DHCP %p could not parse DHCP packet\n", dhcp );
                return -EINVAL;
@@ -682,58 +710,120 @@ static int dhcp_newdata ( struct udp_connection *conn, void *data, size_t len,
        /* Stop timer and update stored options */
        stop_timer ( &dhcp->timer );
        if ( dhcp->options )
-               free_dhcp_options ( dhcp->options );
+               dhcpopt_put ( dhcp->options );
        dhcp->options = options;
 
        /* Transmit next packet, or terminate session */
        if ( dhcp->state < DHCPACK ) {
                dhcp_send_request ( dhcp );
        } else {
-               dhcp_done ( dhcp, 0 );
+               dhcp->register_options ( dhcp->options );
+               dhcp_finished ( dhcp, 0 );
        }
        return 0;
 
  out_discard:
-       free_dhcp_options ( options );
+       dhcpopt_put ( options );
        return 0;
 }
 
-/** DHCP UDP operations */
-static struct udp_operations dhcp_udp_operations = {
-       .senddata       = dhcp_senddata,
-       .newdata        = dhcp_newdata,
+/** DHCP data transfer interface operations */
+static struct xfer_interface_operations dhcp_xfer_operations = {
+       .close          = ignore_xfer_close,
+       .vredirect      = xfer_vopen,
+       .request        = ignore_xfer_request,
+       .seek           = ignore_xfer_seek,
+       .deliver_iob    = xfer_deliver_as_raw,
+       .deliver_raw    = dhcp_deliver_raw,
 };
 
+/****************************************************************************
+ *
+ * Job control interface
+ *
+ */
+
 /**
- * Initiate DHCP on a network interface
+ * Handle kill() event received via job control interface
  *
- * @v dhcp             DHCP session
- * @v parent           Parent asynchronous operation
+ * @v job              DHCP job control interface
+ */
+static void dhcp_job_kill ( struct job_interface *job ) {
+       struct dhcp_session *dhcp =
+               container_of ( job, struct dhcp_session, job );
+
+       /* Terminate DHCP session */
+       dhcp_finished ( dhcp, -ECANCELED );
+}
+
+/** DHCP job control interface operations */
+static struct job_interface_operations dhcp_job_operations = {
+       .start          = ignore_job_start,
+       .done           = ignore_job_done,
+       .kill           = dhcp_job_kill,
+       .progress       = ignore_job_progress,
+};
+
+/****************************************************************************
+ *
+ * Instantiator
+ *
+ */
+
+/**
+ * Start DHCP on a network device
+ *
+ * @v job              Job control interface
+ * @v netdev           Network device
+ * @v register_options DHCP option block registration routine
  * @ret rc             Return status code
  *
- * If the DHCP operation completes successfully, the
- * dhcp_session::options field will be filled in with the resulting
- * options block.  The caller takes responsibility for eventually
- * calling free_dhcp_options().
+ * Starts DHCP on the specified network device.  If successful, the @c
+ * register_options() routine will be called with the acquired
+ * options.
  */
-int start_dhcp ( struct dhcp_session *dhcp, struct async *parent ) {
+int start_dhcp ( struct job_interface *job, struct net_device *netdev,
+                int ( * register_options ) ( struct dhcp_option_block * ) ) {
+       static struct sockaddr_in server = {
+               .sin_family = AF_INET,
+               .sin_addr.s_addr = INADDR_BROADCAST,
+               .sin_port = htons ( BOOTPS_PORT ),
+       };
+       static struct sockaddr_in client = {
+               .sin_family = AF_INET,
+               .sin_port = htons ( BOOTPC_PORT ),
+       };
+       struct dhcp_session *dhcp;
        int rc;
 
-       /* Initialise DHCP session */
-       dhcp->udp.udp_op = &dhcp_udp_operations;
+       /* Allocate and initialise structure */
+       dhcp = malloc ( sizeof ( *dhcp ) );
+       if ( ! dhcp )
+               return -ENOMEM;
+       memset ( dhcp, 0, sizeof ( *dhcp ) );
+       dhcp->refcnt.free = dhcp_free;
+       job_init ( &dhcp->job, &dhcp_job_operations, &dhcp->refcnt );
+       xfer_init ( &dhcp->xfer, &dhcp_xfer_operations, &dhcp->refcnt );
+       dhcp->netdev = netdev_get ( netdev );
+       dhcp->register_options = register_options;
        dhcp->timer.expired = dhcp_timer_expired;
-       dhcp->state = DHCPDISCOVER;
 
-       /* Bind to local port */
-       if ( ( rc = udp_open ( &dhcp->udp, htons ( BOOTPC_PORT ) ) ) != 0 )
-               return rc;
+       /* Instantiate child objects and attach to our interfaces */
+       if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM,
+                                      ( struct sockaddr * ) &server,
+                                      ( struct sockaddr * ) &client ) ) != 0 )
+               goto err;
 
-       /* Proof of concept: just send a single DHCPDISCOVER */
-       dhcp_send_request ( dhcp );
+       /* Start timer to initiate initial DHCPREQUEST */
+       start_timer ( &dhcp->timer );
 
-       async_init ( &dhcp->async, &default_async_operations, parent );
+       /* Attach parent interface, mortalise self, and return */
+       job_plug_plug ( &dhcp->job, job );
+       ref_put ( &dhcp->refcnt );
        return 0;
-}
 
-
-#endif
+ err:
+       dhcp_finished ( dhcp, rc );
+       ref_put ( &dhcp->refcnt );
+       return rc;
+}
index 7e4bedb..dad2ecf 100644 (file)
@@ -261,7 +261,7 @@ int test_dhcp ( struct net_device *netdev ) {
  out:
        /* Unregister and free DHCP options */
        unregister_dhcp_options ( dhcp.options );
-       free_dhcp_options ( dhcp.options );
+       dhcpopt_put ( dhcp.options );
  out_no_options:
  out_no_del_ipv4:
        return rc;
index 926cd74..45c7e1e 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <string.h>
 #include <stdio.h>
+#include <errno.h>
 #include <byteswap.h>
 #include <gpxe/in.h>
 #include <gpxe/ip.h>
  *
  */
 
+int dhcp ( struct net_device *netdev ) {
+       return -ENOTSUP;
+}
+
+#if 0
+
 /* Avoid dragging in dns.o */
 struct sockaddr_tcpip nameserver;
 
@@ -63,7 +70,7 @@ int dhcp ( struct net_device *netdev ) {
        /* Free up any previously-acquired options */
        if ( dhcp_options ) {
                unregister_dhcp_options ( dhcp_options );
-               free_dhcp_options ( dhcp_options );
+               dhcpopt_put ( dhcp_options );
                dhcp_options = NULL;
        }
 
@@ -108,3 +115,5 @@ int dhcp ( struct net_device *netdev ) {
 
        return 0;
 }
+
+#endif