Merge commit 'origin/mdc-working'
authorMichael Brown <mcb30@etherboot.org>
Wed, 21 Nov 2007 15:35:08 +0000 (15:35 +0000)
committerMichael Brown <mcb30@etherboot.org>
Wed, 21 Nov 2007 15:35:08 +0000 (15:35 +0000)
src/arch/i386/firmware/pcbios/smbios.c
src/arch/i386/include/bits/uuid.h [new file with mode: 0644]
src/arch/i386/include/smbios.h
src/arch/i386/prefix/romprefix.S
src/core/uuid.c [new file with mode: 0644]
src/include/gpxe/dhcp.h
src/include/gpxe/uuid.h [new file with mode: 0644]
src/net/dhcpopts.c
src/net/udp/dhcp.c
src/usr/dhcpmgmt.c
src/util/parserom.pl

index bafcafc..d8be6f8 100644 (file)
@@ -20,6 +20,8 @@
 #include <string.h>
 #include <stdio.h>
 #include <errno.h>
+#include <gpxe/uaccess.h>
+#include <gpxe/uuid.h>
 #include <realmode.h>
 #include <pnpbios.h>
 #include <smbios.h>
  *
  */
 
-/** Signature for an SMBIOS structure */
+/** Signature for SMBIOS entry point */
 #define SMBIOS_SIGNATURE \
         ( ( '_' << 0 ) + ( 'S' << 8 ) + ( 'M' << 16 ) + ( '_' << 24 ) )
 
-/** SMBIOS entry point */
+/**
+ * SMBIOS entry point
+ *
+ * This is the single table which describes the list of SMBIOS
+ * structures.  It is located by scanning through the BIOS segment.
+ */
 struct smbios_entry {
        /** Signature
         *
@@ -69,31 +76,44 @@ struct smbios_entry {
        uint8_t bcd_revision;
 } __attribute__ (( packed ));
 
-/** An SMBIOS structure */
+/**
+ * SMBIOS entry point descriptor
+ *
+ * This contains the information from the SMBIOS entry point that we
+ * care about.
+ */
 struct smbios {
-       /** Type */
-       uint8_t type;
-       /** Length */
-       uint8_t length;
-       /** Handle */
-       uint16_t handle;
-} __attribute__ (( packed ));
+       /** Start of SMBIOS structures */
+       userptr_t address;
+       /** Length of SMBIOS structures */ 
+       size_t length;
+       /** Number of SMBIOS structures */
+       unsigned int count;
+};
 
-struct smbios_system_information {
-       struct smbios header;
-       uint8_t manufacturer;
-       uint8_t product;
-       uint8_t version;
-       uint8_t serial;
-} __attribute__ (( packed ));
+/**
+ * SMBIOS strings descriptor
+ *
+ * This is returned as part of the search for an SMBIOS structure, and
+ * contains the information needed for extracting the strings within
+ * the "unformatted" portion of the structure.
+ */
+struct smbios_strings {
+       /** Start of strings data */
+       userptr_t data;
+       /** Length of strings data */
+       size_t length;
+};
 
 /**
  * Find SMBIOS
  *
- * @v emtry            SMBIOS entry point to fill in
- * @ret rc             Return status code
+ * @ret smbios         SMBIOS entry point descriptor, or NULL if not found
  */
-static int find_smbios_entry ( struct smbios_entry *entry ) {
+static struct smbios * find_smbios ( void ) {
+       static struct smbios smbios = {
+               .address = UNULL,
+       };
        union {
                struct smbios_entry entry;
                uint8_t bytes[256]; /* 256 is maximum length possible */
@@ -101,7 +121,11 @@ static int find_smbios_entry ( struct smbios_entry *entry ) {
        unsigned int offset;
        size_t len;
        unsigned int i;
-       uint8_t sum = 0;
+       uint8_t sum;
+
+       /* Return cached result if available */
+       if ( smbios.address != UNULL )
+               return &smbios;
 
        /* Try to find SMBIOS */
        for ( offset = 0 ; offset < 0x10000 ; offset += 0x10 ) {
@@ -115,7 +139,7 @@ static int find_smbios_entry ( struct smbios_entry *entry ) {
                /* Read whole header and verify checksum */
                len = u.entry.length;
                copy_from_real ( &u.bytes, BIOS_SEG, offset, len );
-               for ( i = 0 ; i < len ; i++ ) {
+               for ( i = 0 , sum = 0 ; i < len ; i++ ) {
                        sum += u.bytes[i];
                }
                if ( sum != 0 ) {
@@ -127,72 +151,105 @@ static int find_smbios_entry ( struct smbios_entry *entry ) {
                /* Fill result structure */
                DBG ( "Found SMBIOS entry point at %04x:%04x\n",
                      BIOS_SEG, offset );
-               memcpy ( entry, &u.entry, sizeof ( *entry ) );
-               return 0;
+               smbios.address = phys_to_user ( u.entry.smbios_address );
+               smbios.length = u.entry.smbios_length;
+               smbios.count = u.entry.smbios_count;
+               return &smbios;
        }
 
        DBG ( "No SMBIOS found\n" );
-       return -ENOENT;
+       return NULL;
+}
+
+/**
+ * Find SMBIOS strings terminator
+ *
+ * @v smbios           SMBIOS entry point descriptor
+ * @v offset           Offset to start of strings
+ * @ret offset         Offset to strings terminator, or 0 if not found
+ */
+static size_t find_strings_terminator ( struct smbios *smbios,
+                                       size_t offset ) {
+       size_t max_offset = ( smbios->length - 2 );
+       uint16_t nulnul;
+
+       for ( ; offset <= max_offset ; offset++ ) {
+               copy_from_user ( &nulnul, smbios->address, offset, 2 );
+               if ( nulnul == 0 )
+                       return ( offset + 1 );
+       }
+       return 0;
 }
 
 /**
  * Find specific structure type within SMBIOS
  *
- * @v entry            SMBIOS entry point
- * @v type             Structure type
- * @v data             SMBIOS structure buffer to fill in
+ * @v type             Structure type to search for
+ * @v structure                Buffer to fill in with structure
+ * @v length           Length of buffer
+ * @v strings          Strings descriptor to fill in, or NULL
  * @ret rc             Return status code
- *
- * The buffer must be at least @c entry->max bytes in size.
  */
-static int find_smbios ( struct smbios_entry *entry, unsigned int type,
-                        void *data ) {
-       struct smbios *smbios = data;
-       userptr_t smbios_address = phys_to_user ( entry->smbios_address );
+int find_smbios_structure ( unsigned int type, void *structure,
+                           size_t length, struct smbios_strings *strings ) {
+       struct smbios *smbios;
+       struct smbios_header header;
+       struct smbios_strings temp_strings;
        unsigned int count = 0;
        size_t offset = 0;
-       size_t frag_len;
-       void *end;
-
-       while ( ( offset < entry->smbios_length ) &&
-               ( count < entry->smbios_count ) ) {
-               /* Read next SMBIOS structure */
-               frag_len = ( entry->smbios_length - offset );
-               if ( frag_len > entry->max )
-                       frag_len = entry->max;
-               copy_from_user ( data, smbios_address, offset, frag_len );
-
-               /* Sanity protection; ensure the last two bytes of the
-                * buffer are 0x00,0x00, just so that a terminator
-                * exists somewhere.  Also ensure that this lies
-                * outside the formatted area.
-                */
-               *( ( uint16_t * ) ( data + entry->max - 2 ) ) = 0;
-               if ( smbios->length > ( entry->max - 2 ) ) {
-                       DBG ( "Invalid SMBIOS structure length %zd\n",
-                             smbios->length );
+       size_t strings_offset;
+       size_t terminator_offset;
+
+       /* Locate SMBIOS entry point */
+       if ( ! ( smbios = find_smbios() ) )
+               return -ENOENT;
+
+       /* Ensure that we have a usable strings descriptor buffer */
+       if ( ! strings )
+               strings = &temp_strings;
+
+       /* Scan through list of structures */
+       while ( ( ( offset + sizeof ( header ) ) < smbios->length ) &&
+               ( count < smbios->count ) ) {
+
+               /* Read next SMBIOS structure header */
+               copy_from_user ( &header, smbios->address, offset,
+                                sizeof ( header ) );
+
+               /* Determine start and extent of strings block */
+               strings_offset = ( offset + header.length );
+               if ( strings_offset > smbios->length ) {
+                       DBG ( "SMBIOS structure at offset %zx with length "
+                             "%zx extends beyond SMBIOS\n", offset,
+                             header.length );
+                       return -ENOENT;
+               }
+               terminator_offset =
+                       find_strings_terminator ( smbios, strings_offset );
+               if ( ! terminator_offset ) {
+                       DBG ( "SMBIOS structure at offset %zx has "
+                             "unterminated strings section\n", offset );
                        return -ENOENT;
                }
+               strings->data = userptr_add ( smbios->address,
+                                             strings_offset );
+               strings->length = ( terminator_offset - strings_offset );
 
-               DBG ( "Found SMBIOS structure type %d at offset %zx\n",
-                     smbios->type, offset );
+               DBG ( "SMBIOS structure at offset %zx has type %d, "
+                     "length %zx, strings length %zx\n",
+                     offset, header.type, header.length, strings->length );
 
                /* If this is the structure we want, return */
-               if ( smbios->type == type )
+               if ( header.type == type ) {
+                       if ( length > header.length )
+                               length = header.length;
+                       copy_from_user ( structure, smbios->address,
+                                        offset, length );
                        return 0;
-
-               /* Find end of record.  This will always exist, thanks
-                * to our sanity check above.
-                */
-               for ( end = ( data + smbios->length ) ;
-                     end < ( data + entry->max ) ; end++ ) {
-                       if ( *( ( uint16_t * ) end ) == 0 ) {
-                               end += 2;
-                               break;
-                       }
                }
 
-               offset += ( end - data );
+               /* Move to next SMBIOS structure */
+               offset = ( terminator_offset + 1 );
                count++;
        }
 
@@ -203,56 +260,64 @@ static int find_smbios ( struct smbios_entry *entry, unsigned int type,
 /**
  * Find indexed string within SMBIOS structure
  *
- * @v data             SMBIOS structure
+ * @v strings          SMBIOS strings descriptor
  * @v index            String index
- * @ret string         String, or NULL
+ * @v buffer           Buffer for string
+ * @v length           Length of string buffer
+ * @ret rc             Return status code
  */
-static const char * find_smbios_string ( void *data, unsigned int index ) {
-       struct smbios *smbios = data;
-       const char *string;
-       size_t len;
+int find_smbios_string ( struct smbios_strings *strings, unsigned int index,
+                        char *buffer, size_t length ) {
+       size_t offset = 0;
+       size_t string_len;
 
+       /* Zero buffer.  This ensures that a valid NUL terminator is
+        * always present (unless length==0).
+        */
+       memset ( buffer, 0, length );
+          
+       /* String numbers start at 1 (0 is used to indicate "no string") */
        if ( ! index )
-               return NULL;
-
-       string = ( data + smbios->length );
-       while ( --index ) {
-               /* Move to next string */
-               len = strlen ( string );
-               if ( len == 0 ) {
-                       /* Reached premature end of string table */
-                       DBG ( "SMBIOS string index %d not found\n", index );
-                       return NULL;
+               return 0;
+
+       while ( offset < strings->length ) {
+               /* Get string length.  This is known safe, since the
+                * smbios_strings struct is constructed so as to
+                * always end on a string boundary.
+                */
+               string_len = strlen_user ( strings->data, offset );
+               if ( --index == 0 ) {
+                       /* Copy string, truncating as necessary. */
+                       if ( string_len >= length )
+                               string_len = ( length - 1 );
+                       copy_from_user ( buffer, strings->data,
+                                        offset, string_len );
+                       return 0;
                }
-               string += ( len + 1 );
+               offset += ( string_len + 1 );
        }
-       return string;
+
+       DBG ( "SMBIOS string index %d not found\n", index );
+       return -ENOENT;
 }
 
 /**
- * Find SMBIOS serial number
+ * Get UUID from SMBIOS
  *
- * @v data             Buffer to fill
- * @v len              Length of buffer
+ * @v uuid             UUID to fill in
+ * @ret rc             Return status code
  */
-int find_smbios_serial ( void *data, size_t len ) {
-       struct smbios_entry entry;
-       const char *string;
+int smbios_get_uuid ( union uuid *uuid ) {
+       struct smbios_system_information sysinfo;
        int rc;
 
-       if ( ( rc = find_smbios_entry ( &entry ) ) != 0 )
+       if ( ( rc = find_smbios_structure ( SMBIOS_TYPE_SYSTEM_INFORMATION,
+                                           &sysinfo, sizeof ( sysinfo ),
+                                           NULL ) ) != 0 )
                return rc;
 
-       char buffer[entry.max];
-       if ( ( rc = find_smbios ( &entry, 1, buffer ) ) != 0 )
-               return rc;
-
-       struct smbios_system_information *sysinfo = ( void * ) buffer;
-       string = find_smbios_string ( buffer, sysinfo->serial );
-       if ( ! string )
-               return -ENOENT;
+       memcpy ( uuid, sysinfo.uuid, sizeof ( *uuid ) );
+       DBG ( "SMBIOS found UUID %s\n", uuid_ntoa ( uuid ) );
 
-       DBG ( "Found serial number \"%s\"\n", string );
-       snprintf ( data, len, "%s", string );
        return 0;
 }
diff --git a/src/arch/i386/include/bits/uuid.h b/src/arch/i386/include/bits/uuid.h
new file mode 100644 (file)
index 0000000..0cbd320
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _I386_UUID_H
+#define _I386_UUID_H
+
+#include <smbios.h>
+
+static inline int get_uuid ( union uuid *uuid ) {
+       return smbios_get_uuid ( uuid );
+}
+
+#endif /* _I386_UUID_H */
index 5b35ade..821eda1 100644 (file)
@@ -6,6 +6,46 @@
  * System Management BIOS
  */
 
-extern int find_smbios_serial ( void *data, size_t len );
+#include <stdint.h>
+
+/** An SMBIOS structure header */
+struct smbios_header {
+       /** Type */
+       uint8_t type;
+       /** Length */
+       uint8_t length;
+       /** Handle */
+       uint16_t handle;
+} __attribute__ (( packed ));
+
+/** SMBIOS system information structure */
+struct smbios_system_information {
+       /** SMBIOS structure header */
+       struct smbios_header header;
+       /** Manufacturer string */
+       uint8_t manufacturer;
+       /** Product string */
+       uint8_t product;
+       /** Version string */
+       uint8_t version;
+       /** Serial number string */
+       uint8_t serial;
+       /** UUID */
+       uint8_t uuid[16];
+       /** Wake-up type */
+       uint8_t wakeup;
+} __attribute__ (( packed ));
+
+/** SMBIOS system information structure type */
+#define SMBIOS_TYPE_SYSTEM_INFORMATION 1
+
+struct smbios_strings;
+extern int find_smbios_structure ( unsigned int type,
+                                  void *structure, size_t length,
+                                  struct smbios_strings *strings );
+extern int find_smbios_string ( struct smbios_strings *strings,
+                               unsigned int index,
+                               char *buffer, size_t length );
+extern int smbios_get_uuid ( union uuid *uuid );
 
 #endif /* _SMBIOS_H */
index 593b5d8..167641c 100644 (file)
@@ -82,7 +82,7 @@ mfgstr:
        .asciz  "http://etherboot.org"
        .size mfgstr, . - mfgstr
 prodstr:
-       .asciz  "Etherboot"
+       .asciz  "gPXE"
        .size prodstr, . - prodstr
        
 undiheader:
@@ -131,10 +131,10 @@ notpnp:
        .size init_vector, . - init_vector
 
 ispnp_message:
-       .asciz  "Etherboot detected PnP BIOS\r\n"
+       .asciz  "gPXE detected PnP BIOS\r\n"
        .size ispnp_message, . - ispnp_message
 notpnp_message:
-       .asciz  "Etherboot detected non-PnP BIOS\r\n"
+       .asciz  "gPXE detected non-PnP BIOS\r\n"
        .size notpnp_message, . - notpnp_message
 
 /* Boot execution vector
@@ -173,7 +173,7 @@ exec_vector:
        .previous
 
 exec_message:
-       .asciz  "Etherboot starting boot\r\n"
+       .asciz  "gPXE starting boot\r\n"
        .size exec_message, . - exec_message
 
 /* UNDI loader
diff --git a/src/core/uuid.c b/src/core/uuid.c
new file mode 100644 (file)
index 0000000..dae26c1
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <byteswap.h>
+#include <gpxe/uuid.h>
+
+/** @file
+ *
+ * Universally unique IDs
+ *
+ */
+
+/**
+ * Convert UUID to printable string
+ *
+ * @v uuid             UUID
+ * @ret string         UUID in canonical form
+ */
+char * uuid_ntoa ( union uuid *uuid ) {
+       static char buf[37]; /* "00000000-0000-0000-0000-000000000000" */
+
+       sprintf ( buf, "%08lx-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+                 le32_to_cpu ( uuid->canonical.a ),
+                 le16_to_cpu ( uuid->canonical.b ),
+                 le16_to_cpu ( uuid->canonical.c ),
+                 be16_to_cpu ( uuid->canonical.d ),
+                 uuid->canonical.e[0], uuid->canonical.e[1],
+                 uuid->canonical.e[2], uuid->canonical.e[3],
+                 uuid->canonical.e[4], uuid->canonical.e[5] );
+       return buf;
+}
index 18baa86..60d2ccf 100644 (file)
@@ -135,6 +135,15 @@ struct job_interface;
  */
 #define DHCP_BOOTFILE_NAME 67
 
+/** Client system architecture */
+#define DHCP_CLIENT_ARCHITECTURE 93
+
+/** Client network device interface */
+#define DHCP_CLIENT_NDI 94
+
+/** UUID client identifier */
+#define DHCP_CLIENT_UUID 97
+
 /** Etherboot-specific encapsulated options
  *
  * This encapsulated options field is used to contain all options
@@ -503,6 +512,8 @@ dhcpopt_put ( struct dhcp_option_block *options ) {
        ref_put ( &options->refcnt );
 }
 
+extern struct list_head dhcp_option_blocks;
+
 extern unsigned long dhcp_num_option ( struct dhcp_option *option );
 extern void dhcp_ipv4_option ( struct dhcp_option *option,
                               struct in_addr *inp );
diff --git a/src/include/gpxe/uuid.h b/src/include/gpxe/uuid.h
new file mode 100644 (file)
index 0000000..a62735c
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef _GPXE_UUID_H
+#define _GPXE_UUID_H
+
+/** @file
+ *
+ * Universally unique IDs
+ */
+
+#include <stdint.h>
+
+union uuid;
+#include <bits/uuid.h>
+
+/** A universally unique ID */
+union uuid {
+       /** Canonical form (00000000-0000-0000-0000-000000000000) */
+       struct {
+               /** 8 hex digits, little-endian */
+               uint32_t a;
+               /** 2 hex digits, little-endian */
+               uint16_t b;
+               /** 2 hex digits, little-endian */
+               uint16_t c;
+               /** 2 hex digits, big-endian */
+               uint16_t d;
+               /** 12 hex digits, big-endian */
+               uint8_t e[6];
+       } canonical;
+       uint8_t raw[16];
+};
+
+extern char * uuid_ntoa ( union uuid *uuid );
+
+#endif /* _GPXE_UUID_H */
index c713909..d1837be 100644 (file)
@@ -35,7 +35,7 @@
  */
 
 /** List of registered DHCP option blocks */
-static LIST_HEAD ( option_blocks );
+LIST_HEAD ( dhcp_option_blocks );
 
 /** Registered DHCP option applicators */
 static struct dhcp_option_applicator dhcp_option_applicators[0]
@@ -259,7 +259,7 @@ struct dhcp_option * find_dhcp_option ( struct dhcp_option_block *options,
        if ( options ) {
                return find_dhcp_option_with_encap ( options, tag, NULL );
        } else {
-               list_for_each_entry ( options, &option_blocks, list ) {
+               list_for_each_entry ( options, &dhcp_option_blocks, list ) {
                        if ( ( option = find_dhcp_option ( options, tag ) ) )
                                return option;
                }
@@ -283,7 +283,7 @@ void register_dhcp_options ( struct dhcp_option_block *options ) {
              options, options->priority );
 
        /* Insert after any existing blocks which have a higher priority */
-       list_for_each_entry ( existing, &option_blocks, list ) {
+       list_for_each_entry ( existing, &dhcp_option_blocks, list ) {
                if ( options->priority > existing->priority )
                        break;
        }
index 8e34ccb..3080445 100644 (file)
@@ -31,6 +31,7 @@
 #include <gpxe/retry.h>
 #include <gpxe/tcpip.h>
 #include <gpxe/ip.h>
+#include <gpxe/uuid.h>
 #include <gpxe/dhcp.h>
 
 /** @file
@@ -60,13 +61,17 @@ static const uint8_t dhcp_op[] = {
 static uint8_t dhcp_request_options_data[] = {
        DHCP_MAX_MESSAGE_SIZE, DHCP_WORD ( ETH_MAX_MTU ),
        DHCP_VENDOR_CLASS_ID,
-       DHCP_STRING (  'E', 't', 'h', 'e', 'r', 'b', 'o', 'o', 't' ),
+       DHCP_STRING (  'P', 'X', 'E', 'C', 'l', 'i', 'e', 'n', 't', ':',
+                      'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '0', ':',
+                      'U', 'N', 'D', 'I', ':', '0', '0', '2', '0', '0', '1' ),
+       DHCP_CLIENT_ARCHITECTURE, DHCP_WORD ( 0 ),
+       DHCP_CLIENT_NDI, DHCP_OPTION ( 1 /* UNDI */ , 2, 1 /* v2.1 */ ),
        DHCP_PARAMETER_REQUEST_LIST,
-       DHCP_OPTION ( DHCP_SUBNET_MASK, DHCP_ROUTERS, DHCP_DNS_SERVERS, DHCP_LOG_SERVERS,
-                     DHCP_HOST_NAME, DHCP_DOMAIN_NAME, DHCP_ROOT_PATH,
-                     DHCP_VENDOR_ENCAP, DHCP_TFTP_SERVER_NAME,
-                     DHCP_BOOTFILE_NAME, DHCP_EB_ENCAP,
-                     DHCP_ISCSI_INITIATOR_IQN ),
+       DHCP_OPTION ( DHCP_SUBNET_MASK, DHCP_ROUTERS, DHCP_DNS_SERVERS,
+                     DHCP_LOG_SERVERS, DHCP_HOST_NAME, DHCP_DOMAIN_NAME,
+                     DHCP_ROOT_PATH, DHCP_VENDOR_ENCAP, DHCP_VENDOR_CLASS_ID,
+                     DHCP_TFTP_SERVER_NAME, DHCP_BOOTFILE_NAME,
+                     DHCP_EB_ENCAP, DHCP_ISCSI_INITIATOR_IQN ),
        DHCP_END
 };
 
@@ -511,6 +516,16 @@ struct dhcp_client_id {
        uint8_t ll_addr[MAX_LL_ADDR_LEN];
 } __attribute__ (( packed ));
 
+/** DHCP client UUID */
+struct dhcp_client_uuid {
+       /** Identifier type */
+       uint8_t type;
+       /** UUID */
+       union uuid uuid;
+} __attribute__ (( packed ));
+
+#define DHCP_CLIENT_UUID_TYPE 0
+
 /**
  * Create DHCP request
  *
@@ -529,6 +544,7 @@ int create_dhcp_request ( struct net_device *netdev, int msgtype,
        struct device_description *desc = &netdev->dev->desc;
        struct dhcp_netdev_desc dhcp_desc;
        struct dhcp_client_id client_id;
+       struct dhcp_client_uuid client_uuid;
        size_t dhcp_features_len;
        size_t ll_addr_len;
        int rc;
@@ -604,6 +620,18 @@ int create_dhcp_request ( struct net_device *netdev, int msgtype,
                return rc;
        }
 
+       /* Add client UUID, if we have one.  Required for PXE. */
+       client_uuid.type = DHCP_CLIENT_UUID_TYPE;
+       if ( ( rc = get_uuid ( &client_uuid.uuid ) ) == 0 ) {
+               if ( ( rc = set_dhcp_packet_option ( dhcppkt,
+                                          DHCP_CLIENT_UUID, &client_uuid,
+                                          sizeof ( client_uuid ) ) ) != 0 ) {
+                       DBG ( "DHCP could not set client UUID: %s\n",
+                             strerror ( rc ) );
+                       return rc;
+               }
+       }
+
        return 0;
 }
 
@@ -978,14 +1006,18 @@ int dhcp_configure_netdev ( struct net_device *netdev,
        struct in_addr gateway = { INADDR_NONE };
        int rc;
 
-       /* Clear any existing routing table entry */
-       del_ipv4_address ( netdev );
-
        /* Retrieve IP address configuration */
        find_dhcp_ipv4_option ( options, DHCP_EB_YIADDR, &address );
        find_dhcp_ipv4_option ( options, DHCP_SUBNET_MASK, &netmask );
        find_dhcp_ipv4_option ( options, DHCP_ROUTERS, &gateway );
 
+       /* Do nothing unless we have at least an IP address to use */
+       if ( ! address.s_addr )
+               return 0;
+
+       /* Clear any existing routing table entry */
+       del_ipv4_address ( netdev );
+
        /* Set up new IP address configuration */
        if ( ( rc = add_ipv4_address ( netdev, address, netmask,
                                       gateway ) ) != 0 ) {
index bd05c5e..0c6b458 100644 (file)
  *
  */
 
-static struct dhcp_option_block *dhcp_options = NULL;
-
 static int dhcp_success ( struct net_device *netdev,
                          struct dhcp_option_block *options ) {
-       dhcp_options = dhcpopt_get ( options );
+       DBGC ( options, "DHCP client registering options %p\n", options );
        register_dhcp_options ( options );
        return dhcp_configure_netdev ( netdev, options );
 }
 
 int dhcp ( struct net_device *netdev ) {
+       struct dhcp_option_block *options;
+       struct dhcp_option_block *tmp;
        int rc;
 
        /* Check we can open the interface first */
        if ( ( rc = ifopen ( netdev ) ) != 0 )
                return rc;
 
-       /* Unregister any previously acquired options */
-       if ( dhcp_options ) {
-               unregister_dhcp_options ( dhcp_options );
-               dhcpopt_put ( dhcp_options );
-               dhcp_options = NULL;
+       /* Unregister any option blocks acquired via DHCP */
+       list_for_each_entry_safe ( options, tmp, &dhcp_option_blocks, list ) {
+               /* Skip static option blocks (e.g. from NVS) */
+               if ( find_dhcp_option ( options, DHCP_MESSAGE_TYPE ) ) {
+                       DBGC ( options, "DHCP client unregistering options "
+                              "%p\n", options );
+                       unregister_dhcp_options ( options );
+               }
        }
 
        /* Perform DHCP */
index 56bb944..ace8ec9 100644 (file)
@@ -32,8 +32,8 @@ sub rom {
   print "DRIVER_$image = $driver_name\n";
   print "ROM_TYPE_$image = $type\n";
   print "ROM_DESCRIPTION_$image = \"$desc\"\n";
-  print "PCI_VENDOR_$image = $vendor\n" if $vendor;
-  print "PCI_DEVICE_$image = $device\n" if $device;
+  print "PCI_VENDOR_$image = 0x$vendor\n" if $vendor;
+  print "PCI_DEVICE_$image = 0x$device\n" if $device;
   print "ROMS += $image\n";
   print "ROMS_$driver_name += $image\n";
 }
@@ -42,13 +42,14 @@ while ( <DRV> ) {
   next unless /(PCI|ISA)_ROM\s*\(/;
 
   if ( /^\s*PCI_ROM\s*\(
-         \s*(0x[0-9A-Fa-f]{4})\s*, # PCI vendor
-         \s*(0x[0-9A-Fa-f]{4})\s*, # PCI device
+         \s*0x([0-9A-Fa-f]{4})\s*, # PCI vendor
+         \s*0x([0-9A-Fa-f]{4})\s*, # PCI device
          \s*\"([^\"]*)\"\s*,      # Image
          \s*\"([^\"]*)\"\s*       # Description
        \)/x ) {
     ( my $vendor, my $device, my $image, my $desc ) = ( lc $1, lc $2, $3, $4 );
     rom ( "pci", $image, $desc, $vendor, $device );
+    rom ( "pci", lc "pci_${vendor}_${device}", $desc, $vendor, $device );
   } elsif ( /^\s*ISA_ROM\s*\(
              \s*\"([^\"]*)\"\s*,  # Image
              \s*\"([^\"]*)\"\s*   # Description