[driver] Split out iSCSI-specific code to ibft.c
authorMichael Brown <mcb30@etherboot.org>
Thu, 22 Oct 2009 22:43:20 +0000 (23:43 +0100)
committerMichael Brown <mcb30@etherboot.org>
Thu, 22 Oct 2009 22:43:20 +0000 (23:43 +0100)
driver/acpi.c [new file with mode: 0644]
driver/acpi.h
driver/ibft.c [new file with mode: 0644]
driver/ibft.h
driver/sanbootconf.c
driver/sources

diff --git a/driver/acpi.c b/driver/acpi.c
new file mode 100644 (file)
index 0000000..97fcf9a
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2008 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 <ntddk.h>
+#include "sanbootconf.h"
+#include "acpi.h"
+
+/** Start of region to scan in base memory */
+#define BASEMEM_START 0x80000
+
+/** End of region to scan in base memory */
+#define BASEMEM_END 0xa0000
+
+/** Length of region to scan in base memory */
+#define BASEMEM_LEN ( BASEMEM_END - BASEMEM_START )
+
+/**
+ * Calculate byte checksum
+ *
+ * @v data             Region to checksum
+ * @v len              Length of region
+ * @ret checksum       Byte checksum
+ */
+static UCHAR byte_sum ( PUCHAR data, ULONG len ) {
+       UCHAR checksum = 0;
+       ULONG offset;
+
+       for ( offset = 0 ; offset < len ; offset++ )
+               checksum = ( ( UCHAR ) ( checksum + data[offset] ) );
+
+       return checksum;
+}
+
+/**
+ * Search for ACPI table in base memory
+ *
+ * @v signature                Table signature
+ * @ret table_copy     Copy of table, or NULL
+ *
+ * The returned table is allocated using ExAllocatePool().
+ */
+NTSTATUS find_acpi_table ( PCHAR signature,
+                          PACPI_DESCRIPTION_HEADER *table_copy ) {
+       PHYSICAL_ADDRESS basemem_phy;
+       PUCHAR basemem;
+       ULONG offset;
+       PACPI_DESCRIPTION_HEADER table;
+       NTSTATUS status;
+
+       /* Map base memory */
+       basemem_phy.QuadPart = BASEMEM_START;
+       basemem = MmMapIoSpace ( basemem_phy, BASEMEM_LEN, MmNonCached );
+       if ( ! basemem ) {
+               DbgPrint ( "Could not map base memory\n" );
+               status = STATUS_UNSUCCESSFUL;
+               goto err_mmmapiospace;
+       }
+
+       /* Scan for table */
+       status = STATUS_NO_SUCH_FILE;
+       for ( offset = 0 ; offset < BASEMEM_LEN ; offset += 16 ) {
+               table = ( ( PACPI_DESCRIPTION_HEADER ) ( basemem + offset ) );
+               if ( memcmp ( table->signature, signature,
+                             sizeof ( table->signature ) ) != 0 )
+                       continue;
+               if ( ( offset + table->length ) > BASEMEM_LEN )
+                       continue;
+               if ( byte_sum ( ( ( PUCHAR ) table ), table->length ) != 0 )
+                       continue;
+               DbgPrint ( "Found ACPI table \"%.4s\" at %05x OEM ID "
+                          "\"%.6s\" OEM table ID \"%.8s\"\n", signature,
+                          ( BASEMEM_START + offset ), table->oem_id,
+                          table->oem_table_id );
+               /* Create copy of table */
+               *table_copy = ExAllocatePoolWithTag ( NonPagedPool,
+                                                     table->length,
+                                                     SANBOOTCONF_POOL_TAG );
+               if ( ! *table_copy ) {
+                       DbgPrint ( "Could not allocate table copy\n" );
+                       status = STATUS_NO_MEMORY;
+                       goto err_exallocatepoolwithtag;
+               }
+               RtlCopyMemory ( *table_copy, table, table->length );
+               status = STATUS_SUCCESS;
+               break;
+       }
+
+ err_exallocatepoolwithtag:
+       MmUnmapIoSpace ( basemem, BASEMEM_LEN );
+ err_mmmapiospace:
+       return status;
+}
index d6ab831..d879d15 100644 (file)
@@ -36,4 +36,7 @@ typedef struct _ACPI_DESCRIPTION_HEADER {
 } ACPI_DESCRIPTION_HEADER, *PACPI_DESCRIPTION_HEADER;
 #pragma pack()
 
+extern NTSTATUS find_acpi_table ( PCHAR signature,
+                                 PACPI_DESCRIPTION_HEADER *table_copy );
+
 #endif /* _ACPI_H */
diff --git a/driver/ibft.c b/driver/ibft.c
new file mode 100644 (file)
index 0000000..cc90019
--- /dev/null
@@ -0,0 +1,621 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#pragma warning(disable:4201)  /* nameless struct/union warning */
+#pragma warning(disable:4214)  /* non-int bitfield warning */
+#pragma warning(disable:4327)  /* indirection alignment mismatch */
+
+#include <ntddk.h>
+#include <initguid.h>
+#include <ntstrsafe.h>
+#include <ndis.h>
+#include <ndisguid.h>
+#include <ntddndis.h>
+#include "sanbootconf.h"
+#include "registry.h"
+#include "ibft.h"
+
+/**
+ * Convert IPv4 address to string
+ *
+ * @v ipaddr           IP address
+ * @ret ipaddr         IP address string
+ *
+ * This function returns a static buffer.
+ */
+static LPSTR inet_ntoa ( ULONG ipaddr ) {
+       static CHAR buf[16];
+
+       RtlStringCbPrintfA ( buf, sizeof ( buf ), "%d.%d.%d.%d",
+                            ( ( ipaddr >> 0  ) & 0xff ),
+                            ( ( ipaddr >> 8  ) & 0xff ),
+                            ( ( ipaddr >> 16 ) & 0xff ),
+                            ( ( ipaddr >> 24 ) & 0xff ) );
+       return buf;
+}
+
+/**
+ * Check to see if iBFT string exists
+ *
+ * @v string           iBFT string
+ * @ret exists         String exists
+ */
+static BOOLEAN ibft_string_exists ( PIBFT_STRING string ) {
+       return ( ( BOOLEAN ) ( string->offset != 0 ) );
+}
+
+/**
+ * Read iBFT string
+ *
+ * @v ibft             iBFT
+ * @v string           iBFT string
+ * @ret string         Standard C string
+ */
+static LPSTR ibft_string ( PIBFT_TABLE ibft, PIBFT_STRING string ) {
+       if ( string->offset ) {
+               return ( ( ( PCHAR ) ibft ) + string->offset );
+       } else {
+               return "";
+       }
+}
+
+/**
+ * Check to see if iBFT IP address exists
+ *
+ * @v ipaddr           IP address
+ * @ret exists         IP address exists
+ */
+static BOOLEAN ibft_ipaddr_exists ( PIBFT_IPADDR ipaddr ) {
+       return ( ( BOOLEAN ) ( ipaddr->in != 0 ) );
+}
+
+/**
+ * Convert iBFT IP address to string
+ *
+ * @v ipaddr           IP address
+ * @ret ipaddr         IP address string
+ *
+ * This function returns a static buffer, as per inet_ntoa().
+ */
+static LPSTR ibft_ipaddr ( PIBFT_IPADDR ipaddr ) {
+       return inet_ntoa ( ipaddr->in );
+}
+
+/**
+ * Parse iBFT initiator structure
+ *
+ * @v ibft             iBFT
+ * @v initiator                Initiator structure
+ */
+static VOID parse_ibft_initiator ( PIBFT_TABLE ibft,
+                                  PIBFT_INITIATOR initiator ) {
+       PIBFT_HEADER header = &initiator->header;
+
+       /* Dump structure information */
+       DbgPrint ( "Found iBFT Initiator %d:\n", header->index );
+       DbgPrint ( "  Flags = %#02x%s%s\n", header->flags,
+                  ( header->flags & IBFT_FL_INITIATOR_BLOCK_VALID
+                    ? ", valid" : "" ),
+                  ( header->flags & IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED
+                    ? ", boot selected" : "" ) );
+       if ( ! ( header->flags & IBFT_FL_INITIATOR_BLOCK_VALID ) )
+               return;
+       DbgPrint ( "  iSNS = %s\n", ibft_ipaddr ( &initiator->isns_server ) );
+       DbgPrint ( "  SLP = %s\n", ibft_ipaddr ( &initiator->slp_server ) );
+       DbgPrint ( "  Radius = %s", ibft_ipaddr ( &initiator->radius[0] ) );
+       DbgPrint ( ", %s\n", ibft_ipaddr ( &initiator->radius[1] ) );
+       DbgPrint ( "  Name = %s\n",
+                  ibft_string ( ibft, &initiator->initiator_name ) );
+}
+
+/**
+ * Fetch NIC MAC address
+ *
+ * @v name             NDIS device name
+ * @v device           NDIS device object
+ * @v file             NDIS file object
+ * @v mac              MAC address buffer
+ * @v mac_len          MAC address buffer length
+ * @ret ntstatus       NT status
+ */
+static NTSTATUS fetch_mac ( PUNICODE_STRING name, PDEVICE_OBJECT device,
+                           PFILE_OBJECT file, PUCHAR mac, ULONG mac_len ) {
+       KEVENT event;
+       ULONG in_buf;
+       IO_STATUS_BLOCK io_status;
+       PIRP irp;
+       PIO_STACK_LOCATION io_stack;
+       ULONG i;
+       NTSTATUS status;
+
+       /* Construct IRP to query MAC address */
+       KeInitializeEvent ( &event, NotificationEvent, FALSE );
+       in_buf = OID_802_3_CURRENT_ADDRESS;
+       irp = IoBuildDeviceIoControlRequest ( IOCTL_NDIS_QUERY_GLOBAL_STATS,
+                                             device, &in_buf,
+                                             sizeof ( in_buf ), mac, mac_len,
+                                             FALSE, &event, &io_status );
+       if ( ! irp ) {
+               DbgPrint ( "Could not build IRP to retrieve MAC for \"%wZ\"\n",
+                          name );
+               return STATUS_UNSUCCESSFUL;
+       }
+       io_stack = IoGetNextIrpStackLocation( irp );
+       io_stack->FileObject = file;
+
+       /* Issue IRP */
+       status = IoCallDriver ( device, irp );
+       if ( status == STATUS_PENDING ) {
+               status = KeWaitForSingleObject ( &event, Executive, KernelMode,
+                                                FALSE, NULL );
+       }
+       if ( NT_SUCCESS ( status ) )
+               status = io_status.Status;
+       if ( ! NT_SUCCESS ( status ) ) {
+               DbgPrint ( "IRP failed to retrieve MAC for \"%wZ\": %x\n",
+                          name, status );
+               return status;
+       }
+
+       /* Dump MAC address */
+       DbgPrint ( "Found NIC with MAC address" );
+       for ( i = 0 ; i < mac_len ; i++ )
+               DbgPrint ( "%c%02x", ( i ? ':' : ' ' ), mac[i] );
+       DbgPrint ( " at \"%wZ\"\n", name );
+
+       return STATUS_SUCCESS;
+}
+
+/**
+ * Fetch NIC PDO
+ *
+ * @v name             NDIS device name
+ * @v device           NDIS device object
+ * @v pdo              Associated physical device object
+ * @ret ntstatus       NT status
+ */
+static NTSTATUS fetch_pdo ( PUNICODE_STRING name, PDEVICE_OBJECT device,
+                           PDEVICE_OBJECT *pdo ) {
+       KEVENT event;
+       IO_STATUS_BLOCK io_status;
+       PIRP irp;
+       PIO_STACK_LOCATION io_stack;
+       PDEVICE_RELATIONS relations;
+       NTSTATUS status;
+
+       /* Construct IRP to query MAC address */
+       KeInitializeEvent ( &event, NotificationEvent, FALSE );
+       irp = IoBuildSynchronousFsdRequest ( IRP_MJ_PNP, device, NULL, 0, NULL,
+                                            &event, &io_status );
+       if ( ! irp ) {
+               DbgPrint ( "Could not build IRP to retrieve PDO for \"%wZ\"\n",
+                          name );
+               return STATUS_UNSUCCESSFUL;
+       }
+       io_stack = IoGetNextIrpStackLocation( irp );
+       io_stack->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
+       io_stack->Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
+
+       /* Issue IRP */
+       status = IoCallDriver ( device, irp );
+       if ( status == STATUS_PENDING ) {
+               status = KeWaitForSingleObject ( &event, Executive, KernelMode,
+                                                FALSE, NULL );
+       }
+       if ( NT_SUCCESS ( status ) )
+               status = io_status.Status;
+       if ( ! NT_SUCCESS ( status ) ) {
+               DbgPrint ( "IRP failed to retrieve PDO for \"%wZ\": %x\n",
+                          name, status );
+               return status;
+       }
+
+       /* Extract PDO */
+       relations = ( ( PDEVICE_RELATIONS ) io_status.Information );
+       *pdo = relations->Objects[0];
+
+       /* Free the relations list allocated by the IRP */
+       ExFreePool ( relations );
+
+       return STATUS_SUCCESS;
+}
+
+/**
+ * Fetch NetCfgInstanceId registry value
+ *
+ * @v pdo              Physical device object
+ * @v netcfginstanceid Value to allocate and fill in
+ * @ret ntstatus       NT status
+ *
+ * The caller must eventually free the allocated value.
+ */
+static NTSTATUS fetch_netcfginstanceid ( PDEVICE_OBJECT pdo,
+                                        LPWSTR *netcfginstanceid ) {
+       HANDLE reg_key;
+       NTSTATUS status;
+
+       /* Open driver registry key */
+       status = IoOpenDeviceRegistryKey ( pdo, PLUGPLAY_REGKEY_DRIVER,
+                                          KEY_READ, &reg_key );
+       if ( ! NT_SUCCESS ( status ) ) {
+               DbgPrint ( "Could not open driver registry key for PDO %p: "
+                          "%x\n", pdo, status );
+               goto err_ioopendeviceregistrykey;
+       }
+
+       /* Read NetCfgInstanceId value */
+       status = fetch_reg_sz ( reg_key, L"NetCfgInstanceId",
+                               netcfginstanceid );
+       if ( ! NT_SUCCESS ( status ) )
+               goto err_fetch_reg_wstr;
+
+ err_fetch_reg_wstr:
+       ZwClose ( reg_key );
+ err_ioopendeviceregistrykey:
+       return status;
+}
+
+/**
+ * Store IPv4 parameter into a string registry value
+ *
+ * @v reg_key          Registry key
+ * @v value_name       Registry value name
+ * @v ipaddr           IPv4 address
+ * @ret ntstatus       NT status
+ */
+static NTSTATUS store_ipv4_parameter_sz ( HANDLE reg_key, LPCWSTR value_name,
+                                         ULONG ipaddr ) {
+       WCHAR buf[16];
+       LPWSTR value;
+
+       if ( ipaddr ) {
+               RtlStringCbPrintfW ( buf, sizeof ( buf ),
+                                    L"%S", inet_ntoa ( ipaddr ) );
+               value = buf;
+       } else {
+               value = L"";
+       }
+
+       return reg_store_sz ( reg_key, value_name, value );
+}
+
+/**
+ * Store IPv4 parameter into a multi-string registry value
+ *
+ * @v reg_key          Registry key
+ * @v value_name       Registry value name
+ * @v ipaddr           IPv4 address
+ * @ret ntstatus       NT status
+ */
+static NTSTATUS store_ipv4_parameter_multi_sz ( HANDLE reg_key,
+                                               LPCWSTR value_name,
+                                               ULONG ipaddr ) {
+       WCHAR buf[16];
+       LPWSTR value;
+
+       if ( ipaddr ) {
+               RtlStringCbPrintfW ( buf, sizeof ( buf ),
+                                    L"%S", inet_ntoa ( ipaddr ) );
+               value = buf;
+       } else {
+               value = NULL;
+       }
+
+       return reg_store_multi_sz ( reg_key, value_name, value, NULL );
+}
+
+/**
+ * Store TCP/IP parameters in registry
+ *
+ * @v nic              iBFT NIC structure
+ * @v netcfginstanceid Interface name within registry
+ * @ret ntstatus       NT status
+ */
+static NTSTATUS store_tcpip_parameters ( PIBFT_NIC nic,
+                                        LPCWSTR netcfginstanceid ) {
+       LPCWSTR key_name_prefix = ( L"\\Registry\\Machine\\SYSTEM\\"
+                                   L"CurrentControlSet\\Services\\"
+                                   L"Tcpip\\Parameters\\Interfaces\\" );
+       LPWSTR key_name;
+       SIZE_T key_name_len;
+       HANDLE reg_key;
+       ULONG subnet_mask;
+       NTSTATUS status;
+
+       /* Allocate key name */
+       key_name_len = ( ( wcslen ( key_name_prefix ) +
+                          wcslen ( netcfginstanceid ) + 1 ) *
+                        sizeof ( key_name[0] ) );
+       key_name = ExAllocatePoolWithTag ( NonPagedPool, key_name_len,
+                                          SANBOOTCONF_POOL_TAG );
+       if ( ! key_name ) {
+               DbgPrint ( "Could not allocate TCP/IP key name\n" );
+               status = STATUS_UNSUCCESSFUL;
+               goto err_exallocatepoolwithtag;
+       }
+
+       /* Construct key name */
+       RtlStringCbCopyW ( key_name, key_name_len, key_name_prefix );
+       RtlStringCbCatW ( key_name, key_name_len, netcfginstanceid );
+
+       /* Open key */
+       status = reg_open ( key_name, &reg_key );
+       if ( ! NT_SUCCESS ( status ) )
+               goto err_reg_open;
+
+       /* Store IP address */
+       status = store_ipv4_parameter_multi_sz ( reg_key, L"IPAddress",
+                                                nic->ip_address.in );
+       if ( ! NT_SUCCESS ( status ) )
+               goto err_reg_store;
+
+       /* Store subnet mask */
+       subnet_mask = RtlUlongByteSwap ( 0xffffffffUL << ( 32 - nic->subnet_mask_prefix ) );
+       status = store_ipv4_parameter_multi_sz ( reg_key, L"SubnetMask",
+                                                subnet_mask );
+       if ( ! NT_SUCCESS ( status ) )
+               goto err_reg_store;
+
+       /* Store default gateway */
+       status = store_ipv4_parameter_multi_sz ( reg_key, L"DefaultGateway",
+                                                nic->gateway.in );
+       if ( ! NT_SUCCESS ( status ) )
+               goto err_reg_store;
+
+       /* Store DNS servers */
+       status = store_ipv4_parameter_sz ( reg_key, L"NameServer",
+                                          nic->dns[0].in );
+       if ( ! NT_SUCCESS ( status ) )
+               goto err_reg_store;
+
+       /* Disable DHCP */
+       status = reg_store_dword ( reg_key, L"EnableDHCP", 0 );
+       if ( ! NT_SUCCESS ( status ) )
+               goto err_reg_store;
+
+ err_reg_store:
+       reg_close ( reg_key );
+ err_reg_open:
+       ExFreePool ( key_name );
+ err_exallocatepoolwithtag:
+       return status;
+}
+
+/**
+ * Try to configure NIC from iBFT NIC structure
+ *
+ * @v nic              iBFT NIC structure
+ * @v name             NDIS device name
+ * @ret ntstatus       NT status
+ */
+static NTSTATUS try_configure_nic ( PIBFT_NIC nic, PUNICODE_STRING name ) {
+       BOOLEAN must_disable;
+       PFILE_OBJECT file;
+       PDEVICE_OBJECT device;
+       UCHAR mac[6];
+       PDEVICE_OBJECT pdo;
+       LPWSTR netcfginstanceid;
+       NTSTATUS status;
+
+       /* Enable interface if not already done */
+       status = IoSetDeviceInterfaceState ( name, TRUE );
+       must_disable = ( NT_SUCCESS ( status ) ? TRUE : FALSE );
+
+       /* Get device and file object pointers */
+       status = IoGetDeviceObjectPointer ( name, FILE_ALL_ACCESS, &file,
+                                           &device );
+       if ( ! NT_SUCCESS ( status ) ) {
+               /* Not an error, apparently; IoGetDeviceInterfaces()
+                * seems to return a whole load of interfaces that
+                * aren't attached to any objects.
+                */
+               goto err_iogetdeviceobjectpointer;
+       }
+
+       /* See if NIC matches */
+       status = fetch_mac ( name, device, file, mac, sizeof ( mac ) );
+       if ( ! NT_SUCCESS ( status ) )
+               goto err_fetch_mac;
+       if ( memcmp ( nic->mac_address, mac, sizeof ( mac ) ) != 0 )
+               goto err_compare_mac;
+       DbgPrint ( "iBFT NIC %d is interface \"%wZ\"\n",
+                  nic->header.index, name );
+
+       /* Get matching PDO */
+       status = fetch_pdo ( name, device, &pdo );
+       if ( ! NT_SUCCESS ( status ) )
+               goto err_fetch_pdo;
+       DbgPrint ( "iBFT NIC %d is PDO %p\n", nic->header.index, pdo );
+
+       /* Get NetCfgInstanceId */
+       status = fetch_netcfginstanceid ( pdo, &netcfginstanceid );
+       if ( ! NT_SUCCESS ( status ) )
+               goto err_fetch_netcfginstanceid;
+       DbgPrint ( "iBFT NIC %d is NetCfgInstanceId \"%S\"\n",
+                  nic->header.index, netcfginstanceid );
+
+       /* Store registry values */
+       status = store_tcpip_parameters ( nic, netcfginstanceid );
+       if ( ! NT_SUCCESS ( status ) )
+               goto err_store_tcpip_parameters;
+
+ err_store_tcpip_parameters:
+       ExFreePool ( netcfginstanceid );
+ err_fetch_netcfginstanceid:
+ err_fetch_pdo:
+ err_compare_mac:
+ err_fetch_mac:
+       /* Drop object reference */
+       ObDereferenceObject ( file );
+ err_iogetdeviceobjectpointer:
+       /* Disable interface if we had to enable it */
+       if ( must_disable )
+               IoSetDeviceInterfaceState ( name, FALSE );
+       return status;
+}
+
+/**
+ * Parse iBFT NIC structure
+ *
+ * @v ibft             iBFT
+ * @v nic              NIC structure
+ */
+static VOID parse_ibft_nic ( PIBFT_TABLE ibft, PIBFT_NIC nic ) {
+       PIBFT_HEADER header = &nic->header;
+       PWSTR symlinks;
+       PWSTR symlink;
+       UNICODE_STRING u_symlink;
+       NTSTATUS status;
+
+       /* Dump structure information */
+       DbgPrint ( "Found iBFT NIC %d:\n", header->index );
+       DbgPrint ( "  Flags = %#02x%s%s\n", header->flags,
+                  ( header->flags & IBFT_FL_NIC_BLOCK_VALID
+                    ? ", valid" : "" ),
+                  ( header->flags & IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED
+                    ? ", boot selected" : "" ),
+                  ( header->flags & IBFT_FL_NIC_GLOBAL
+                    ? ", global address" : ", link local address" ) );
+       if ( ! ( header->flags & IBFT_FL_NIC_BLOCK_VALID ) )
+               return;
+       DbgPrint ( "  IP = %s/%d\n", ibft_ipaddr ( &nic->ip_address ),
+                  nic->subnet_mask_prefix );
+       DbgPrint ( "  Origin = %d\n", nic->origin );
+       DbgPrint ( "  Gateway = %s\n", ibft_ipaddr ( &nic->gateway ) );
+       DbgPrint ( "  DNS = %s", ibft_ipaddr ( &nic->dns[0] ) );
+       DbgPrint ( ", %s\n", ibft_ipaddr ( &nic->dns[1] ) );
+       DbgPrint ( "  DHCP = %s\n", ibft_ipaddr ( &nic->dhcp ) );
+       DbgPrint ( "  VLAN = %04x\n", nic->vlan );
+       DbgPrint ( "  MAC = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                  nic->mac_address[0], nic->mac_address[1],
+                  nic->mac_address[2], nic->mac_address[3],
+                  nic->mac_address[4], nic->mac_address[5] );
+       DbgPrint ( "  PCI = %02x:%02x.%x\n",
+                  ( ( nic->pci_bus_dev_func >> 8 ) & 0xff ),
+                  ( ( nic->pci_bus_dev_func >> 3 ) & 0x1f ),
+                  ( ( nic->pci_bus_dev_func >> 0 ) & 0x07 ) );
+       DbgPrint ( "  Hostname = %s\n", ibft_string ( ibft, &nic->hostname ) );
+
+       /* Get list of all objects providing GUID_NDIS_LAN_CLASS interface */
+       status = IoGetDeviceInterfaces ( &GUID_NDIS_LAN_CLASS, NULL,
+                                        DEVICE_INTERFACE_INCLUDE_NONACTIVE,
+                                        &symlinks );
+       if ( ! NT_SUCCESS ( status ) ) {
+               DbgPrint ( "Could not fetch NIC list: %x\n", status );
+               return;
+       }
+
+       /* Configure any matching NICs */
+       for ( symlink = symlinks ;
+             RtlInitUnicodeString ( &u_symlink, symlink ) , *symlink ;
+             symlink += ( ( u_symlink.Length / sizeof ( *symlink ) ) + 1 ) ) {
+               try_configure_nic ( nic, &u_symlink );
+       }
+
+       /* Free object list */
+       ExFreePool ( symlinks );
+}
+
+/**
+ * Parse iBFT target structure
+ *
+ * @v ibft             iBFT
+ * @v target           Target structure
+ */
+static VOID parse_ibft_target ( PIBFT_TABLE ibft, PIBFT_TARGET target ) {
+       PIBFT_HEADER header = &target->header;
+
+       /* Dump structure information */
+       DbgPrint ( "Found iBFT target %d:\n", header->index );
+       DbgPrint ( "  Flags = %#02x%s%s\n", header->flags,
+                  ( header->flags & IBFT_FL_TARGET_BLOCK_VALID
+                    ? ", valid" : "" ),
+                  ( header->flags & IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED
+                    ? ", boot selected" : "" ),
+                  ( header->flags & IBFT_FL_TARGET_USE_CHAP
+                    ? ", Radius CHAP" : "" ),
+                  ( header->flags & IBFT_FL_TARGET_USE_RCHAP
+                    ? ", Radius rCHAP" : "" ) );
+       if ( ! ( header->flags & IBFT_FL_TARGET_BLOCK_VALID ) )
+               return;
+       DbgPrint ( "  IP = %s\n",
+                  ibft_ipaddr ( &target->ip_address ) );
+       DbgPrint ( "  Port = %d\n", target->socket );
+       DbgPrint ( "  LUN = %04x-%04x-%04x-%04x\n",
+                  ( ( target->boot_lun >> 48 ) & 0xffff ),
+                  ( ( target->boot_lun >> 32 ) & 0xffff ),
+                  ( ( target->boot_lun >> 16 ) & 0xffff ),
+                  ( ( target->boot_lun >> 0  ) & 0xffff ) );
+       DbgPrint ( "  CHAP type = %d (%s)\n", target->chap_type,
+                  ( ( target->chap_type == IBFT_CHAP_NONE ) ? "None" :
+                    ( ( target->chap_type == IBFT_CHAP_ONE_WAY ) ? "One-way" :
+                      ( ( target->chap_type == IBFT_CHAP_MUTUAL ) ? "Mutual" :
+                        "Unknown" ) ) ) );
+       DbgPrint ( "  NIC = %d\n", target->nic_association );
+       DbgPrint ( "  Name = %s\n",
+                  ibft_string ( ibft, &target->target_name ) );
+       DbgPrint ( "  CHAP name = %s\n",
+                  ibft_string ( ibft, &target->chap_name ) );
+       DbgPrint ( "  CHAP secret = %s\n",
+                  ( ibft_string_exists ( &target->chap_secret ) ?
+                    "<omitted>" : "" ) );
+       DbgPrint ( "  Reverse CHAP name = %s\n",
+                  ibft_string ( ibft, &target->reverse_chap_name ) );
+       DbgPrint ( "  Reverse CHAP secret = %s\n",
+                  ( ibft_string_exists ( &target->reverse_chap_secret ) ?
+                    "<omitted>" : "" ) );
+}
+
+/**
+ * Parse iBFT
+ *
+ * @v ibft             iBFT
+ */
+VOID parse_ibft ( PIBFT_TABLE ibft ) {
+       PIBFT_CONTROL control = &ibft->control;
+       PUSHORT offset;
+       PIBFT_HEADER header;
+
+       /* Scan through all entries in the Control structure */
+       for ( offset = &control->extensions ;
+             ( ( PUCHAR ) offset ) <
+                     ( ( ( PUCHAR ) control ) + control->header.length ) ;
+             offset++ ) {
+               if ( ! *offset )
+                       continue;
+               header = ( ( PIBFT_HEADER ) ( ( ( PUCHAR ) ibft ) + *offset ));
+               switch ( header->structure_id ) {
+               case IBFT_STRUCTURE_ID_INITIATOR :
+                       parse_ibft_initiator ( ibft,
+                                              ( ( PIBFT_INITIATOR ) header ));
+                       break;
+               case IBFT_STRUCTURE_ID_NIC :
+                       parse_ibft_nic ( ibft, ( ( PIBFT_NIC ) header ) );
+                       break;
+               case IBFT_STRUCTURE_ID_TARGET :
+                       parse_ibft_target ( ibft,
+                                           ( ( PIBFT_TARGET ) header ) );
+                       break;
+               default :
+                       DbgPrint ( "Ignoring unknown iBFT structure ID %d "
+                                  "index %d\n", header->structure_id,
+                                  header->index );
+                       break;
+               }
+       }
+}
index ec493fd..162d51c 100644 (file)
@@ -266,4 +266,6 @@ typedef struct _IBFT_TABLE {
 } IBFT_TABLE, *PIBFT_TABLE;
 #pragma pack()
 
+extern VOID parse_ibft ( PIBFT_TABLE ibft );
+
 #endif /* _IBFT_H */
index a634b19..97cbd7a 100644 (file)
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#pragma warning(disable:4201)  /* nameless struct/union warning */
-#pragma warning(disable:4214)  /* non-int bitfield warning */
-#pragma warning(disable:4327)  /* indirection alignment mismatch */
-
 #include <ntddk.h>
-#include <ntstrsafe.h>
 #include <initguid.h>
-#include <ndis.h>
-#include <ndisguid.h>
-#include <ntddndis.h>
 #include <wdmsec.h>
-#include <iscsicfg.h>
 #include "sanbootconf.h"
+#include "acpi.h"
 #include "ibft.h"
-#include "registry.h"
-
-/** Start of region to scan in base memory */
-#define BASEMEM_START 0x80000
-
-/** End of region to scan in base memory */
-#define BASEMEM_END 0xa0000
-
-/** Length of region to scan in base memory */
-#define BASEMEM_LEN ( BASEMEM_END - BASEMEM_START )
-
-/** IoControl code to retrieve iSCSI boot data */
-#define IOCTL_ISCSIBOOT CTL_CODE ( FILE_DEVICE_UNKNOWN, 1, METHOD_BUFFERED, \
-                                  FILE_READ_ACCESS )
 
 /** Device private data */
-typedef struct _ISCSIBOOT_PRIV {
+typedef struct _SANBOOTCONF_PRIV {
        /* Copy of iBFT */
        PIBFT_TABLE ibft;
-} ISCSIBOOT_PRIV, *PISCSIBOOT_PRIV;
+} SANBOOTCONF_PRIV, *PSANBOOTCONF_PRIV;
 
 /** Unique GUID for IoCreateDeviceSecure() */
-DEFINE_GUID ( GUID_ISCSIBOOT_CLASS, 0x8a2f8602, 0x8f0b, 0x4138,
+DEFINE_GUID ( GUID_SANBOOTCONF_CLASS, 0x8a2f8602, 0x8f0b, 0x4138,
              0x8e, 0x16, 0x51, 0x9a, 0x59, 0xf3, 0x07, 0xca );
 
-/** iSCSI boot device name */
-static const WCHAR iscsiboot_device_name[] = L"\\Device\\iSCSIBoot";
-
-/** iSCSI boot device symlink name */
-static const WCHAR iscsiboot_device_symlink[] = L"\\DosDevices\\iSCSIBoot";
-
-/**
- * Calculate byte checksum
- *
- * @v data             Region to checksum
- * @v len              Length of region
- * @ret checksum       Byte checksum
- */
-static UCHAR byte_sum ( PUCHAR data, ULONG len ) {
-       UCHAR checksum = 0;
-       ULONG offset;
-
-       for ( offset = 0 ; offset < len ; offset++ )
-               checksum = ( ( UCHAR ) ( checksum + data[offset] ) );
-
-       return checksum;
-}
-
-/**
- * Convert IPv4 address to string
- *
- * @v ipaddr           IP address
- * @ret ipaddr         IP address string
- *
- * This function returns a static buffer.
- */
-static LPSTR inet_ntoa ( ULONG ipaddr ) {
-       static CHAR buf[16];
-
-       RtlStringCbPrintfA ( buf, sizeof ( buf ), "%d.%d.%d.%d",
-                            ( ( ipaddr >> 0  ) & 0xff ),
-                            ( ( ipaddr >> 8  ) & 0xff ),
-                            ( ( ipaddr >> 16 ) & 0xff ),
-                            ( ( ipaddr >> 24 ) & 0xff ) );
-       return buf;
-}
-
-/**
- * Search for iBFT
- *
- * @v start            Region in which to start searching
- * @v len              Length of region
- * @ret ibft_copy      Copy of iBFT, or NULL
- *
- * The returned iBFT is allocated using ExAllocatePool().
- */
-static NTSTATUS find_ibft ( PIBFT_TABLE *ibft_copy ) {
-       PHYSICAL_ADDRESS basemem_phy;
-       PUCHAR basemem;
-       ULONG offset;
-       PIBFT_TABLE ibft;
-       NTSTATUS status;
-
-       /* Map base memory */
-       basemem_phy.QuadPart = BASEMEM_START;
-       basemem = MmMapIoSpace ( basemem_phy, BASEMEM_LEN, MmNonCached );
-       if ( ! basemem ) {
-               DbgPrint ( "Could not map base memory\n" );
-               status = STATUS_UNSUCCESSFUL;
-               goto err_mmmapiospace;
-       }
-
-       /* Scan for iBFT */
-       status = STATUS_NO_SUCH_FILE;
-       for ( offset = 0 ; offset < BASEMEM_LEN ; offset += 16 ) {
-               ibft = ( ( PIBFT_TABLE ) ( basemem + offset ) );
-               if ( memcmp ( ibft->acpi.signature, IBFT_SIG,
-                             sizeof ( ibft->acpi.signature ) ) != 0 )
-                       continue;
-               if ( ( offset + ibft->acpi.length ) > BASEMEM_LEN )
-                       continue;
-               if ( byte_sum ( ( ( PUCHAR ) ibft ), ibft->acpi.length ) != 0 )
-                       continue;
-               DbgPrint ( "Found iBFT at %05x OEM ID \"%.6s\" OEM table ID "
-                          "\"%.8s\"\n", ( BASEMEM_START + offset ),
-                          ibft->acpi.oem_id, ibft->acpi.oem_table_id );
-               /* Create copy of iBFT */
-               *ibft_copy = ExAllocatePoolWithTag ( NonPagedPool,
-                                                    ibft->acpi.length,
-                                                    SANBOOTCONF_POOL_TAG );
-               if ( ! *ibft_copy ) {
-                       DbgPrint ( "Could not allocate iBFT copy\n" );
-                       status = STATUS_NO_MEMORY;
-                       goto err_exallocatepoolwithtag;
-               }
-               RtlCopyMemory ( *ibft_copy, ibft, ibft->acpi.length );
-               status = STATUS_SUCCESS;
-               break;
-       }
+/** IoControl code to retrieve iBFT */
+#define IOCTL_SANBOOTCONF_IBFT \
+       CTL_CODE ( FILE_DEVICE_UNKNOWN, 1, METHOD_BUFFERED, FILE_READ_ACCESS )
 
- err_exallocatepoolwithtag:
-       MmUnmapIoSpace ( basemem, BASEMEM_LEN );
- err_mmmapiospace:
-       return status;
-}
+/** Device name */
+static const WCHAR sanbootconf_device_name[] = L"\\Device\\sanbootconf";
 
-/**
- * Check to see if iBFT string exists
- *
- * @v string           iBFT string
- * @ret exists         String exists
- */
-static BOOLEAN ibft_string_exists ( PIBFT_STRING string ) {
-       return ( ( BOOLEAN ) ( string->offset != 0 ) );
-}
-
-/**
- * Read iBFT string
- *
- * @v ibft             iBFT
- * @v string           iBFT string
- * @ret string         Standard C string
- */
-static LPSTR ibft_string ( PIBFT_TABLE ibft, PIBFT_STRING string ) {
-       if ( string->offset ) {
-               return ( ( ( PCHAR ) ibft ) + string->offset );
-       } else {
-               return "";
-       }
-}
-
-/**
- * Check to see if iBFT IP address exists
- *
- * @v ipaddr           IP address
- * @ret exists         IP address exists
- */
-static BOOLEAN ibft_ipaddr_exists ( PIBFT_IPADDR ipaddr ) {
-       return ( ( BOOLEAN ) ( ipaddr->in != 0 ) );
-}
-
-/**
- * Convert iBFT IP address to string
- *
- * @v ipaddr           IP address
- * @ret ipaddr         IP address string
- *
- * This function returns a static buffer, as per inet_ntoa().
- */
-static LPSTR ibft_ipaddr ( PIBFT_IPADDR ipaddr ) {
-       return inet_ntoa ( ipaddr->in );
-}
-
-/**
- * Parse iBFT initiator structure
- *
- * @v ibft             iBFT
- * @v initiator                Initiator structure
- */
-static VOID parse_ibft_initiator ( PIBFT_TABLE ibft,
-                                  PIBFT_INITIATOR initiator ) {
-       PIBFT_HEADER header = &initiator->header;
-
-       /* Dump structure information */
-       DbgPrint ( "Found iBFT Initiator %d:\n", header->index );
-       DbgPrint ( "  Flags = %#02x%s%s\n", header->flags,
-                  ( header->flags & IBFT_FL_INITIATOR_BLOCK_VALID
-                    ? ", valid" : "" ),
-                  ( header->flags & IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED
-                    ? ", boot selected" : "" ) );
-       if ( ! ( header->flags & IBFT_FL_INITIATOR_BLOCK_VALID ) )
-               return;
-       DbgPrint ( "  iSNS = %s\n", ibft_ipaddr ( &initiator->isns_server ) );
-       DbgPrint ( "  SLP = %s\n", ibft_ipaddr ( &initiator->slp_server ) );
-       DbgPrint ( "  Radius = %s", ibft_ipaddr ( &initiator->radius[0] ) );
-       DbgPrint ( ", %s\n", ibft_ipaddr ( &initiator->radius[1] ) );
-       DbgPrint ( "  Name = %s\n",
-                  ibft_string ( ibft, &initiator->initiator_name ) );
-}
-
-/**
- * Fetch NIC MAC address
- *
- * @v name             NDIS device name
- * @v device           NDIS device object
- * @v file             NDIS file object
- * @v mac              MAC address buffer
- * @v mac_len          MAC address buffer length
- * @ret ntstatus       NT status
- */
-static NTSTATUS fetch_mac ( PUNICODE_STRING name, PDEVICE_OBJECT device,
-                           PFILE_OBJECT file, PUCHAR mac, ULONG mac_len ) {
-       KEVENT event;
-       ULONG in_buf;
-       IO_STATUS_BLOCK io_status;
-       PIRP irp;
-       PIO_STACK_LOCATION io_stack;
-       ULONG i;
-       NTSTATUS status;
-
-       /* Construct IRP to query MAC address */
-       KeInitializeEvent ( &event, NotificationEvent, FALSE );
-       in_buf = OID_802_3_CURRENT_ADDRESS;
-       irp = IoBuildDeviceIoControlRequest ( IOCTL_NDIS_QUERY_GLOBAL_STATS,
-                                             device, &in_buf,
-                                             sizeof ( in_buf ), mac, mac_len,
-                                             FALSE, &event, &io_status );
-       if ( ! irp ) {
-               DbgPrint ( "Could not build IRP to retrieve MAC for \"%wZ\"\n",
-                          name );
-               return STATUS_UNSUCCESSFUL;
-       }
-       io_stack = IoGetNextIrpStackLocation( irp );
-       io_stack->FileObject = file;
-
-       /* Issue IRP */
-       status = IoCallDriver ( device, irp );
-       if ( status == STATUS_PENDING ) {
-               status = KeWaitForSingleObject ( &event, Executive, KernelMode,
-                                                FALSE, NULL );
-       }
-       if ( NT_SUCCESS ( status ) )
-               status = io_status.Status;
-       if ( ! NT_SUCCESS ( status ) ) {
-               DbgPrint ( "IRP failed to retrieve MAC for \"%wZ\": %x\n",
-                          name, status );
-               return status;
-       }
-
-       /* Dump MAC address */
-       DbgPrint ( "Found NIC with MAC address" );
-       for ( i = 0 ; i < mac_len ; i++ )
-               DbgPrint ( "%c%02x", ( i ? ':' : ' ' ), mac[i] );
-       DbgPrint ( " at \"%wZ\"\n", name );
-
-       return STATUS_SUCCESS;
-}
-
-/**
- * Fetch NIC PDO
- *
- * @v name             NDIS device name
- * @v device           NDIS device object
- * @v pdo              Associated physical device object
- * @ret ntstatus       NT status
- */
-static NTSTATUS fetch_pdo ( PUNICODE_STRING name, PDEVICE_OBJECT device,
-                           PDEVICE_OBJECT *pdo ) {
-       KEVENT event;
-       IO_STATUS_BLOCK io_status;
-       PIRP irp;
-       PIO_STACK_LOCATION io_stack;
-       PDEVICE_RELATIONS relations;
-       NTSTATUS status;
-
-       /* Construct IRP to query MAC address */
-       KeInitializeEvent ( &event, NotificationEvent, FALSE );
-       irp = IoBuildSynchronousFsdRequest ( IRP_MJ_PNP, device, NULL, 0, NULL,
-                                            &event, &io_status );
-       if ( ! irp ) {
-               DbgPrint ( "Could not build IRP to retrieve PDO for \"%wZ\"\n",
-                          name );
-               return STATUS_UNSUCCESSFUL;
-       }
-       io_stack = IoGetNextIrpStackLocation( irp );
-       io_stack->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
-       io_stack->Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
-
-       /* Issue IRP */
-       status = IoCallDriver ( device, irp );
-       if ( status == STATUS_PENDING ) {
-               status = KeWaitForSingleObject ( &event, Executive, KernelMode,
-                                                FALSE, NULL );
-       }
-       if ( NT_SUCCESS ( status ) )
-               status = io_status.Status;
-       if ( ! NT_SUCCESS ( status ) ) {
-               DbgPrint ( "IRP failed to retrieve PDO for \"%wZ\": %x\n",
-                          name, status );
-               return status;
-       }
-
-       /* Extract PDO */
-       relations = ( ( PDEVICE_RELATIONS ) io_status.Information );
-       *pdo = relations->Objects[0];
-
-       /* Free the relations list allocated by the IRP */
-       ExFreePool ( relations );
-
-       return STATUS_SUCCESS;
-}
-
-/**
- * Fetch NetCfgInstanceId registry value
- *
- * @v pdo              Physical device object
- * @v netcfginstanceid Value to allocate and fill in
- * @ret ntstatus       NT status
- *
- * The caller must eventually free the allocated value.
- */
-static NTSTATUS fetch_netcfginstanceid ( PDEVICE_OBJECT pdo,
-                                        LPWSTR *netcfginstanceid ) {
-       HANDLE reg_key;
-       NTSTATUS status;
-
-       /* Open driver registry key */
-       status = IoOpenDeviceRegistryKey ( pdo, PLUGPLAY_REGKEY_DRIVER,
-                                          KEY_READ, &reg_key );
-       if ( ! NT_SUCCESS ( status ) ) {
-               DbgPrint ( "Could not open driver registry key for PDO %p: "
-                          "%x\n", pdo, status );
-               goto err_ioopendeviceregistrykey;
-       }
-
-       /* Read NetCfgInstanceId value */
-       status = fetch_reg_sz ( reg_key, L"NetCfgInstanceId",
-                               netcfginstanceid );
-       if ( ! NT_SUCCESS ( status ) )
-               goto err_fetch_reg_wstr;
-
- err_fetch_reg_wstr:
-       ZwClose ( reg_key );
- err_ioopendeviceregistrykey:
-       return status;
-}
-
-/**
- * Store IPv4 parameter into a string registry value
- *
- * @v reg_key          Registry key
- * @v value_name       Registry value name
- * @v ipaddr           IPv4 address
- * @ret ntstatus       NT status
- */
-static NTSTATUS store_ipv4_parameter_sz ( HANDLE reg_key, LPCWSTR value_name,
-                                         ULONG ipaddr ) {
-       WCHAR buf[16];
-       LPWSTR value;
-
-       if ( ipaddr ) {
-               RtlStringCbPrintfW ( buf, sizeof ( buf ),
-                                    L"%S", inet_ntoa ( ipaddr ) );
-               value = buf;
-       } else {
-               value = L"";
-       }
-
-       return reg_store_sz ( reg_key, value_name, value );
-}
-
-/**
- * Store IPv4 parameter into a multi-string registry value
- *
- * @v reg_key          Registry key
- * @v value_name       Registry value name
- * @v ipaddr           IPv4 address
- * @ret ntstatus       NT status
- */
-static NTSTATUS store_ipv4_parameter_multi_sz ( HANDLE reg_key,
-                                               LPCWSTR value_name,
-                                               ULONG ipaddr ) {
-       WCHAR buf[16];
-       LPWSTR value;
-
-       if ( ipaddr ) {
-               RtlStringCbPrintfW ( buf, sizeof ( buf ),
-                                    L"%S", inet_ntoa ( ipaddr ) );
-               value = buf;
-       } else {
-               value = NULL;
-       }
-
-       return reg_store_multi_sz ( reg_key, value_name, value, NULL );
-}
-
-/**
- * Store TCP/IP parameters in registry
- *
- * @v nic              iBFT NIC structure
- * @v netcfginstanceid Interface name within registry
- * @ret ntstatus       NT status
- */
-static NTSTATUS store_tcpip_parameters ( PIBFT_NIC nic,
-                                        LPCWSTR netcfginstanceid ) {
-       LPCWSTR key_name_prefix = ( L"\\Registry\\Machine\\SYSTEM\\"
-                                   L"CurrentControlSet\\Services\\"
-                                   L"Tcpip\\Parameters\\Interfaces\\" );
-       LPWSTR key_name;
-       SIZE_T key_name_len;
-       HANDLE reg_key;
-       ULONG subnet_mask;
-       NTSTATUS status;
-
-       /* Allocate key name */
-       key_name_len = ( ( wcslen ( key_name_prefix ) +
-                          wcslen ( netcfginstanceid ) + 1 ) *
-                        sizeof ( key_name[0] ) );
-       key_name = ExAllocatePoolWithTag ( NonPagedPool, key_name_len,
-                                          SANBOOTCONF_POOL_TAG );
-       if ( ! key_name ) {
-               DbgPrint ( "Could not allocate TCP/IP key name\n" );
-               status = STATUS_UNSUCCESSFUL;
-               goto err_exallocatepoolwithtag;
-       }
-
-       /* Construct key name */
-       RtlStringCbCopyW ( key_name, key_name_len, key_name_prefix );
-       RtlStringCbCatW ( key_name, key_name_len, netcfginstanceid );
-
-       /* Open key */
-       status = reg_open ( key_name, &reg_key );
-       if ( ! NT_SUCCESS ( status ) )
-               goto err_reg_open;
-
-       /* Store IP address */
-       status = store_ipv4_parameter_multi_sz ( reg_key, L"IPAddress",
-                                                nic->ip_address.in );
-       if ( ! NT_SUCCESS ( status ) )
-               goto err_reg_store;
-
-       /* Store subnet mask */
-       subnet_mask = RtlUlongByteSwap ( 0xffffffffUL << ( 32 - nic->subnet_mask_prefix ) );
-       status = store_ipv4_parameter_multi_sz ( reg_key, L"SubnetMask",
-                                                subnet_mask );
-       if ( ! NT_SUCCESS ( status ) )
-               goto err_reg_store;
-
-       /* Store default gateway */
-       status = store_ipv4_parameter_multi_sz ( reg_key, L"DefaultGateway",
-                                                nic->gateway.in );
-       if ( ! NT_SUCCESS ( status ) )
-               goto err_reg_store;
-
-       /* Store DNS servers */
-       status = store_ipv4_parameter_sz ( reg_key, L"NameServer",
-                                          nic->dns[0].in );
-       if ( ! NT_SUCCESS ( status ) )
-               goto err_reg_store;
-
-       /* Disable DHCP */
-       status = reg_store_dword ( reg_key, L"EnableDHCP", 0 );
-       if ( ! NT_SUCCESS ( status ) )
-               goto err_reg_store;
-
- err_reg_store:
-       reg_close ( reg_key );
- err_reg_open:
-       ExFreePool ( key_name );
- err_exallocatepoolwithtag:
-       return status;
-}
-
-/**
- * Try to configure NIC from iBFT NIC structure
- *
- * @v nic              iBFT NIC structure
- * @v name             NDIS device name
- * @ret ntstatus       NT status
- */
-static NTSTATUS try_configure_nic ( PIBFT_NIC nic, PUNICODE_STRING name ) {
-       BOOLEAN must_disable;
-       PFILE_OBJECT file;
-       PDEVICE_OBJECT device;
-       UCHAR mac[6];
-       PDEVICE_OBJECT pdo;
-       LPWSTR netcfginstanceid;
-       NTSTATUS status;
-
-       /* Enable interface if not already done */
-       status = IoSetDeviceInterfaceState ( name, TRUE );
-       must_disable = ( NT_SUCCESS ( status ) ? TRUE : FALSE );
-
-       /* Get device and file object pointers */
-       status = IoGetDeviceObjectPointer ( name, FILE_ALL_ACCESS, &file,
-                                           &device );
-       if ( ! NT_SUCCESS ( status ) ) {
-               /* Not an error, apparently; IoGetDeviceInterfaces()
-                * seems to return a whole load of interfaces that
-                * aren't attached to any objects.
-                */
-               goto err_iogetdeviceobjectpointer;
-       }
-
-       /* See if NIC matches */
-       status = fetch_mac ( name, device, file, mac, sizeof ( mac ) );
-       if ( ! NT_SUCCESS ( status ) )
-               goto err_fetch_mac;
-       if ( memcmp ( nic->mac_address, mac, sizeof ( mac ) ) != 0 )
-               goto err_compare_mac;
-       DbgPrint ( "iBFT NIC %d is interface \"%wZ\"\n",
-                  nic->header.index, name );
-
-       /* Get matching PDO */
-       status = fetch_pdo ( name, device, &pdo );
-       if ( ! NT_SUCCESS ( status ) )
-               goto err_fetch_pdo;
-       DbgPrint ( "iBFT NIC %d is PDO %p\n", nic->header.index, pdo );
-
-       /* Get NetCfgInstanceId */
-       status = fetch_netcfginstanceid ( pdo, &netcfginstanceid );
-       if ( ! NT_SUCCESS ( status ) )
-               goto err_fetch_netcfginstanceid;
-       DbgPrint ( "iBFT NIC %d is NetCfgInstanceId \"%S\"\n",
-                  nic->header.index, netcfginstanceid );
-
-       /* Store registry values */
-       status = store_tcpip_parameters ( nic, netcfginstanceid );
-       if ( ! NT_SUCCESS ( status ) )
-               goto err_store_tcpip_parameters;
-
- err_store_tcpip_parameters:
-       ExFreePool ( netcfginstanceid );
- err_fetch_netcfginstanceid:
- err_fetch_pdo:
- err_compare_mac:
- err_fetch_mac:
-       /* Drop object reference */
-       ObDereferenceObject ( file );
- err_iogetdeviceobjectpointer:
-       /* Disable interface if we had to enable it */
-       if ( must_disable )
-               IoSetDeviceInterfaceState ( name, FALSE );
-       return status;
-}
-
-/**
- * Parse iBFT NIC structure
- *
- * @v ibft             iBFT
- * @v nic              NIC structure
- */
-static VOID parse_ibft_nic ( PIBFT_TABLE ibft, PIBFT_NIC nic ) {
-       PIBFT_HEADER header = &nic->header;
-       PWSTR symlinks;
-       PWSTR symlink;
-       UNICODE_STRING u_symlink;
-       NTSTATUS status;
-
-       /* Dump structure information */
-       DbgPrint ( "Found iBFT NIC %d:\n", header->index );
-       DbgPrint ( "  Flags = %#02x%s%s\n", header->flags,
-                  ( header->flags & IBFT_FL_NIC_BLOCK_VALID
-                    ? ", valid" : "" ),
-                  ( header->flags & IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED
-                    ? ", boot selected" : "" ),
-                  ( header->flags & IBFT_FL_NIC_GLOBAL
-                    ? ", global address" : ", link local address" ) );
-       if ( ! ( header->flags & IBFT_FL_NIC_BLOCK_VALID ) )
-               return;
-       DbgPrint ( "  IP = %s/%d\n", ibft_ipaddr ( &nic->ip_address ),
-                  nic->subnet_mask_prefix );
-       DbgPrint ( "  Origin = %d\n", nic->origin );
-       DbgPrint ( "  Gateway = %s\n", ibft_ipaddr ( &nic->gateway ) );
-       DbgPrint ( "  DNS = %s", ibft_ipaddr ( &nic->dns[0] ) );
-       DbgPrint ( ", %s\n", ibft_ipaddr ( &nic->dns[1] ) );
-       DbgPrint ( "  DHCP = %s\n", ibft_ipaddr ( &nic->dhcp ) );
-       DbgPrint ( "  VLAN = %04x\n", nic->vlan );
-       DbgPrint ( "  MAC = %02x:%02x:%02x:%02x:%02x:%02x\n",
-                  nic->mac_address[0], nic->mac_address[1],
-                  nic->mac_address[2], nic->mac_address[3],
-                  nic->mac_address[4], nic->mac_address[5] );
-       DbgPrint ( "  PCI = %02x:%02x.%x\n",
-                  ( ( nic->pci_bus_dev_func >> 8 ) & 0xff ),
-                  ( ( nic->pci_bus_dev_func >> 3 ) & 0x1f ),
-                  ( ( nic->pci_bus_dev_func >> 0 ) & 0x07 ) );
-       DbgPrint ( "  Hostname = %s\n", ibft_string ( ibft, &nic->hostname ) );
-
-       /* Get list of all objects providing GUID_NDIS_LAN_CLASS interface */
-       status = IoGetDeviceInterfaces ( &GUID_NDIS_LAN_CLASS, NULL,
-                                        DEVICE_INTERFACE_INCLUDE_NONACTIVE,
-                                        &symlinks );
-       if ( ! NT_SUCCESS ( status ) ) {
-               DbgPrint ( "Could not fetch NIC list: %x\n", status );
-               return;
-       }
-
-       /* Configure any matching NICs */
-       for ( symlink = symlinks ;
-             RtlInitUnicodeString ( &u_symlink, symlink ) , *symlink ;
-             symlink += ( ( u_symlink.Length / sizeof ( *symlink ) ) + 1 ) ) {
-               try_configure_nic ( nic, &u_symlink );
-       }
-
-       /* Free object list */
-       ExFreePool ( symlinks );
-}
-
-/**
- * Parse iBFT target structure
- *
- * @v ibft             iBFT
- * @v target           Target structure
- */
-static VOID parse_ibft_target ( PIBFT_TABLE ibft, PIBFT_TARGET target ) {
-       PIBFT_HEADER header = &target->header;
-
-       /* Dump structure information */
-       DbgPrint ( "Found iBFT target %d:\n", header->index );
-       DbgPrint ( "  Flags = %#02x%s%s\n", header->flags,
-                  ( header->flags & IBFT_FL_TARGET_BLOCK_VALID
-                    ? ", valid" : "" ),
-                  ( header->flags & IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED
-                    ? ", boot selected" : "" ),
-                  ( header->flags & IBFT_FL_TARGET_USE_CHAP
-                    ? ", Radius CHAP" : "" ),
-                  ( header->flags & IBFT_FL_TARGET_USE_RCHAP
-                    ? ", Radius rCHAP" : "" ) );
-       if ( ! ( header->flags & IBFT_FL_TARGET_BLOCK_VALID ) )
-               return;
-       DbgPrint ( "  IP = %s\n",
-                  ibft_ipaddr ( &target->ip_address ) );
-       DbgPrint ( "  Port = %d\n", target->socket );
-       DbgPrint ( "  LUN = %04x-%04x-%04x-%04x\n",
-                  ( ( target->boot_lun >> 48 ) & 0xffff ),
-                  ( ( target->boot_lun >> 32 ) & 0xffff ),
-                  ( ( target->boot_lun >> 16 ) & 0xffff ),
-                  ( ( target->boot_lun >> 0  ) & 0xffff ) );
-       DbgPrint ( "  CHAP type = %d (%s)\n", target->chap_type,
-                  ( ( target->chap_type == IBFT_CHAP_NONE ) ? "None" :
-                    ( ( target->chap_type == IBFT_CHAP_ONE_WAY ) ? "One-way" :
-                      ( ( target->chap_type == IBFT_CHAP_MUTUAL ) ? "Mutual" :
-                        "Unknown" ) ) ) );
-       DbgPrint ( "  NIC = %d\n", target->nic_association );
-       DbgPrint ( "  Name = %s\n",
-                  ibft_string ( ibft, &target->target_name ) );
-       DbgPrint ( "  CHAP name = %s\n",
-                  ibft_string ( ibft, &target->chap_name ) );
-       DbgPrint ( "  CHAP secret = %s\n",
-                  ( ibft_string_exists ( &target->chap_secret ) ?
-                    "<omitted>" : "" ) );
-       DbgPrint ( "  Reverse CHAP name = %s\n",
-                  ibft_string ( ibft, &target->reverse_chap_name ) );
-       DbgPrint ( "  Reverse CHAP secret = %s\n",
-                  ( ibft_string_exists ( &target->reverse_chap_secret ) ?
-                    "<omitted>" : "" ) );
-}
-
-/**
- * Parse iBFT
- *
- * @v ibft             iBFT
- */
-static VOID parse_ibft ( PIBFT_TABLE ibft ) {
-       PIBFT_CONTROL control = &ibft->control;
-       PUSHORT offset;
-       PIBFT_HEADER header;
-
-       /* Scan through all entries in the Control structure */
-       for ( offset = &control->extensions ;
-             ( ( PUCHAR ) offset ) <
-                     ( ( ( PUCHAR ) control ) + control->header.length ) ;
-             offset++ ) {
-               if ( ! *offset )
-                       continue;
-               header = ( ( PIBFT_HEADER ) ( ( ( PUCHAR ) ibft ) + *offset ));
-               switch ( header->structure_id ) {
-               case IBFT_STRUCTURE_ID_INITIATOR :
-                       parse_ibft_initiator ( ibft,
-                                              ( ( PIBFT_INITIATOR ) header ));
-                       break;
-               case IBFT_STRUCTURE_ID_NIC :
-                       parse_ibft_nic ( ibft, ( ( PIBFT_NIC ) header ) );
-                       break;
-               case IBFT_STRUCTURE_ID_TARGET :
-                       parse_ibft_target ( ibft,
-                                           ( ( PIBFT_TARGET ) header ) );
-                       break;
-               default :
-                       DbgPrint ( "Ignoring unknown iBFT structure ID %d "
-                                  "index %d\n", header->structure_id,
-                                  header->index );
-                       break;
-               }
-       }
-}
+/** Device symlinks */
+static const PWCHAR sanbootconf_device_symlink[] = {
+       L"\\Device\\iSCSIBoot",
+       L"\\DosDevices\\iSCSIBoot",
+};
 
 /**
  * Dummy IRP handler
@@ -734,7 +53,7 @@ static VOID parse_ibft ( PIBFT_TABLE ibft ) {
  * @v irp              IRP
  * @ret ntstatus       NT status
  */
-static NTSTATUS iscsiboot_dummy_irp ( PDEVICE_OBJECT device, PIRP irp ) {
+static NTSTATUS sanbootconf_dummy_irp ( PDEVICE_OBJECT device, PIRP irp ) {
 
        irp->IoStatus.Status = STATUS_SUCCESS;
        irp->IoStatus.Information = 0;
@@ -751,16 +70,15 @@ static NTSTATUS iscsiboot_dummy_irp ( PDEVICE_OBJECT device, PIRP irp ) {
  * @v irp              IRP
  * @ret ntstatus       NT status
  */
-static NTSTATUS iscsiboot_iocontrol_irp ( PDEVICE_OBJECT device, PIRP irp ) {
+static NTSTATUS sanbootconf_iocontrol_irp ( PDEVICE_OBJECT device, PIRP irp ) {
        PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation ( irp );
-       PISCSIBOOT_PRIV priv = device->DeviceExtension;
-       ULONG len;
+       PSANBOOTCONF_PRIV priv = device->DeviceExtension;
+       ULONG len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
        NTSTATUS status;
 
        switch ( irpsp->Parameters.DeviceIoControl.IoControlCode ) {
-       case IOCTL_ISCSIBOOT:
-               DbgPrint ( "iSCSI boot parameters requested\n" );
-               len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
+       case IOCTL_SANBOOTCONF_IBFT:
+               DbgPrint ( "iBFT requested\n" );
                if ( len > priv->ibft->acpi.length )
                        len = priv->ibft->acpi.length;
                RtlCopyMemory ( irp->AssociatedIrp.SystemBuffer,
@@ -781,42 +99,45 @@ static NTSTATUS iscsiboot_iocontrol_irp ( PDEVICE_OBJECT device, PIRP irp ) {
 }
 
 /**
- * Create device object and symlink
+ * Create device object and symlinks
  *
  * @v driver           Driver object
  * @ret ntstatus       NT status
  */
-static NTSTATUS create_iscsiboot_device ( PDRIVER_OBJECT driver,
-                                         PIBFT_TABLE ibft ) {
+static NTSTATUS create_sanbootconf_device ( PDRIVER_OBJECT driver,
+                                           PDEVICE_OBJECT *device ) {
        UNICODE_STRING u_device_name;
        UNICODE_STRING u_device_symlink;
-       PISCSIBOOT_PRIV priv;
-       PDEVICE_OBJECT device;
+       unsigned int i;
        NTSTATUS status;
 
        /* Create device */
-       RtlInitUnicodeString ( &u_device_name, iscsiboot_device_name );
-       status = IoCreateDeviceSecure ( driver, sizeof ( *priv ),
+       RtlInitUnicodeString ( &u_device_name, sanbootconf_device_name );
+       status = IoCreateDeviceSecure ( driver, sizeof ( SANBOOTCONF_PRIV ),
                                        &u_device_name, FILE_DEVICE_UNKNOWN,
                                        FILE_DEVICE_SECURE_OPEN, FALSE,
                                        &SDDL_DEVOBJ_SYS_ALL_ADM_ALL,
-                                       &GUID_ISCSIBOOT_CLASS, &device );
+                                       &GUID_SANBOOTCONF_CLASS, device );
        if ( ! NT_SUCCESS ( status ) ) {
                DbgPrint ( "Could not create device \"%S\": %x\n",
-                          iscsiboot_device_name, status );
+                          sanbootconf_device_name, status );
                return status;
        }
-       priv = device->DeviceExtension;
-       priv->ibft = ibft;
-       device->Flags &= ~DO_DEVICE_INITIALIZING;
-
-       /* Create device symlink */
-       RtlInitUnicodeString ( &u_device_symlink, iscsiboot_device_symlink );
-       status = IoCreateSymbolicLink ( &u_device_symlink, &u_device_name );
-       if ( ! NT_SUCCESS ( status ) ) {
-               DbgPrint ( "Could not create device symlink \"%S\": %x\n",
-                          iscsiboot_device_symlink, status );
-               return status;
+       (*device)->Flags &= ~DO_DEVICE_INITIALIZING;
+
+       /* Create device symlinks */
+       for ( i = 0 ; i < ( sizeof ( sanbootconf_device_symlink ) /
+                           sizeof ( sanbootconf_device_symlink[0] ) ) ; i++ ){
+               RtlInitUnicodeString ( &u_device_symlink,
+                                      sanbootconf_device_symlink[i] );
+               status = IoCreateSymbolicLink ( &u_device_symlink,
+                                               &u_device_name );
+               if ( ! NT_SUCCESS ( status ) ) {
+                       DbgPrint ( "Could not create device symlink \"%S\": "
+                                  "%x\n", sanbootconf_device_symlink[i],
+                                  status );
+                       return status;
+               }
        }
 
        return STATUS_SUCCESS;
@@ -831,39 +152,40 @@ static NTSTATUS create_iscsiboot_device ( PDRIVER_OBJECT driver,
  */
 NTSTATUS DriverEntry ( IN PDRIVER_OBJECT DriverObject,
                       IN PUNICODE_STRING RegistryPath ) {
-       PIBFT_TABLE ibft;
+       PDEVICE_OBJECT device;
+       PSANBOOTCONF_PRIV priv;
+       PACPI_DESCRIPTION_HEADER table;
        NTSTATUS status;
 
        DbgPrint ( "SAN Boot Configuration Driver initialising\n" );
 
-       /* Scan for iBFT */
-       status = find_ibft ( &ibft );
-       if ( ! NT_SUCCESS ( status ) ) {
-               DbgPrint ( "No iBFT found\n" );
-               /* Lack of an iBFT is not necessarily an error */
-               status = STATUS_SUCCESS;
-               goto err_no_ibft;
-       }
-
-       /* Parse iBFT */
-       parse_ibft ( ibft );
-
        /* Hook in driver methods */
-       DriverObject->MajorFunction[IRP_MJ_CREATE] = iscsiboot_dummy_irp;
-       DriverObject->MajorFunction[IRP_MJ_CLOSE] = iscsiboot_dummy_irp;
-       DriverObject->MajorFunction[IRP_MJ_CLEANUP] = iscsiboot_dummy_irp;
+       DriverObject->MajorFunction[IRP_MJ_CREATE] = sanbootconf_dummy_irp;
+       DriverObject->MajorFunction[IRP_MJ_CLOSE] = sanbootconf_dummy_irp;
+       DriverObject->MajorFunction[IRP_MJ_CLEANUP] = sanbootconf_dummy_irp;
        DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
-               iscsiboot_iocontrol_irp;
+               sanbootconf_iocontrol_irp;
 
        /* Create device object */
-       status = create_iscsiboot_device ( DriverObject, ibft );
+       status = create_sanbootconf_device ( DriverObject, &device );
        if ( ! NT_SUCCESS ( status ) )
-               goto err_create_iscsiboot_device;
+               goto err_create_sanbootconf_device;
+       priv = device->DeviceExtension;
+
+       /* Look for an iBFT */
+       status = find_acpi_table ( IBFT_SIG, &table );
+       if ( NT_SUCCESS ( status ) ) {
+               priv->ibft = ( ( PIBFT_TABLE ) table );
+               parse_ibft ( priv->ibft );
+       } else {
+               /* Lack of an iBFT is not necessarily an error */
+               DbgPrint ( "No iBFT found\n" );
+               status = STATUS_SUCCESS;
+       }
 
        DbgPrint ( "SAN Boot Configuration Driver initialisation complete\n" );
 
- err_create_iscsiboot_device:
- err_no_ibft:
+ err_create_sanbootconf_device:
        ( VOID ) RegistryPath;
        return status;
 }
index 7de5aeb..6367621 100644 (file)
@@ -8,4 +8,4 @@ TARGETLIBS = $(DDK_LIB_PATH)\ndis.lib $(DDK_LIB_PATH)\ntstrsafe.lib $(DDK_LIB_PA
 
 MSC_WARNING_LEVEL = /W4 /Wp64 /WX
 
-SOURCES = sanbootconf.c registry.c
+SOURCES = sanbootconf.c registry.c acpi.c ibft.c