[driver] Add support for the AoE boot firmware table (aBFT)

Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
This commit is contained in:
Michael Brown 2010-09-13 04:52:31 +01:00
parent 43a46e10ba
commit e604684e55
7 changed files with 491 additions and 251 deletions

63
src/driver/abft.c Normal file
View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2010 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:4100) /* unreferenced formal parameter */
#include <ntddk.h>
#include <ntstrsafe.h>
#include "sanbootconf.h"
#include "nic.h"
#include "abft.h"
/**
* Do nothing with NIC
*
* @v pdo Physical device object
* @v netcfginstanceid Interface name within registry
* @v opaque iBFT NIC structure
* @ret ntstatus NT status
*/
static NTSTATUS abft_dummy ( PDEVICE_OBJECT pdo,
LPCWSTR netcfginstanceid,
PVOID opaque ) {
return STATUS_SUCCESS;
}
/**
* Parse aBFT
*
* @v acpi ACPI description header
*/
VOID parse_abft ( PACPI_DESCRIPTION_HEADER acpi ) {
PABFT_TABLE abft = ( PABFT_TABLE ) acpi;
NTSTATUS status;
/* Dump structure information */
DbgPrint ( "Found aBFT target e%d.%d\n", abft->shelf, abft->slot );
DbgPrint ( "Found aBFT NIC %02x:%02x:%02x:%02x:%02x:%02x\n",
abft->mac[0], abft->mac[1], abft->mac[2],
abft->mac[3], abft->mac[4], abft->mac[5] );
/* Check for existence of NIC */
status = find_nic ( abft->mac, abft_dummy, NULL );
if ( NT_SUCCESS ( status ) ) {
DbgPrint ( "Successfully identified aBFT NIC\n" );
} else {
DbgPrint ( "Could not identify aBFT NIC\n" );
}
}

58
src/driver/abft.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef _ABFT_H
#define _ABFT_H
/*
* Copyright (C) 2010 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.
*/
/** @file
*
* AoE boot firmware table
*
* The working draft specification for the SRP boot firmware table can
* be found at
*
* http://www.etherboot.org/wiki/aoe/abft
*
*/
#include "acpi.h"
/** AoE Boot Firmware Table signature */
#define ABFT_SIG "aBFT"
/**
* AoE Boot Firmware Table (aBFT)
*/
#pragma pack(1)
typedef struct _ABFT_TABLE {
/** ACPI header */
ACPI_DESCRIPTION_HEADER acpi;
/** AoE shelf */
USHORT shelf;
/** AoE slot */
UCHAR slot;
/** Reserved */
UCHAR reserved_a;
/** MAC address */
UCHAR mac[6];
} ABFT_TABLE, *PABFT_TABLE;
#pragma pack()
extern VOID parse_abft ( PACPI_DESCRIPTION_HEADER acpi );
#endif /* _ABFT_H */

View File

@ -16,18 +16,14 @@
* 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:4100) /* unreferenced formal parameter */
#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 "nic.h"
#include "ibft.h"
/**
@ -123,153 +119,6 @@ static VOID parse_ibft_initiator ( PIBFT_TABLE ibft,
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
*
@ -322,15 +171,18 @@ static NTSTATUS store_ipv4_parameter_multi_sz ( HANDLE reg_key,
/**
* Store TCP/IP parameters in registry
*
* @v nic iBFT NIC structure
* @v pdo Physical device object
* @v netcfginstanceid Interface name within registry
* @v opaque iBFT NIC structure
* @ret ntstatus NT status
*/
static NTSTATUS store_tcpip_parameters ( PIBFT_NIC nic,
LPCWSTR netcfginstanceid ) {
static NTSTATUS store_tcpip_parameters ( PDEVICE_OBJECT pdo,
LPCWSTR netcfginstanceid,
PVOID opaque ) {
LPCWSTR key_name_prefix = ( L"\\Registry\\Machine\\SYSTEM\\"
L"CurrentControlSet\\Services\\"
L"Tcpip\\Parameters\\Interfaces\\" );
PIBFT_NIC nic = opaque;
LPWSTR key_name;
SIZE_T key_name_len;
HANDLE reg_key;
@ -365,7 +217,8 @@ static NTSTATUS store_tcpip_parameters ( PIBFT_NIC nic,
goto err_reg_store;
/* Store subnet mask */
subnet_mask = RtlUlongByteSwap ( 0xffffffffUL << ( 32 - nic->subnet_mask_prefix ) );
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 ) )
@ -396,79 +249,6 @@ static NTSTATUS store_tcpip_parameters ( PIBFT_NIC nic,
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
*
@ -477,9 +257,6 @@ static NTSTATUS try_configure_nic ( PIBFT_NIC nic, PUNICODE_STRING name ) {
*/
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 */
@ -511,24 +288,15 @@ static VOID parse_ibft_nic ( PIBFT_TABLE ibft, PIBFT_NIC nic ) {
( ( 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;
/* Try to configure NIC */
status = find_nic ( nic->mac_address, store_tcpip_parameters, nic );
if ( NT_SUCCESS ( status ) ) {
DbgPrint ( "Successfully configured iBFT NIC %d\n",
header->index );
} else {
DbgPrint ( "Could not configure iBFT NIC %d: %x\n",
header->index, status );
}
/* 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 );
}
/**

310
src/driver/nic.c Normal file
View File

@ -0,0 +1,310 @@
/*
* 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 */
#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 "nic.h"
/**
* 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;
}
/**
* Try processing NIC
*
* @v mac MAC address
* @v name NDIS device name
* @v process Processing function
* @v opaque Argument to processing function
* @ret found NIC found
* @ret ntstatus NT status
*/
static NTSTATUS try_nic ( PUCHAR mac, PUNICODE_STRING name,
NTSTATUS ( *process ) ( PDEVICE_OBJECT pdo,
LPWSTR netcfginstanceid,
PVOID opaque ),
PVOID opaque,
PBOOLEAN found ) {
BOOLEAN must_disable;
PFILE_OBJECT file;
PDEVICE_OBJECT device;
UCHAR this_mac[6];
PDEVICE_OBJECT pdo;
LPWSTR netcfginstanceid;
NTSTATUS status;
/* Mark as not yet found */
*found = FALSE;
/* 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, this_mac,
sizeof ( this_mac ) );
if ( ! NT_SUCCESS ( status ) )
goto err_fetch_mac;
if ( memcmp ( mac, this_mac, sizeof ( this_mac ) ) != 0 )
goto err_compare_mac;
DbgPrint ( "NIC %02x:%02x:%02x:%02x:%02x:%02x is interface \"%wZ\"\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], name );
*found = TRUE;
/* Get matching PDO */
status = fetch_pdo ( name, device, &pdo );
if ( ! NT_SUCCESS ( status ) )
goto err_fetch_pdo;
DbgPrint ( "NIC %02x:%02x:%02x:%02x:%02x:%02x is PDO %p\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], pdo );
/* Get NetCfgInstanceId */
status = fetch_netcfginstanceid ( pdo, &netcfginstanceid );
if ( ! NT_SUCCESS ( status ) )
goto err_fetch_netcfginstanceid;
DbgPrint ( "NIC %02x:%02x:%02x:%02x:%02x:%02x is NetCfgInstanceId "
"\"%S\"\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
netcfginstanceid );
/* Store registry values */
status = process ( pdo, netcfginstanceid, opaque );
if ( ! NT_SUCCESS ( status ) )
goto err_process;
err_process:
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;
}
/**
* Try processing NIC
*
* @v mac MAC address
* @v process Processing function
* @v opaque Argument to processing function
* @ret ntstatus NT status
*/
NTSTATUS find_nic ( PUCHAR mac,
NTSTATUS ( *process ) ( PDEVICE_OBJECT pdo,
LPWSTR netcfginstanceid,
PVOID opaque ),
PVOID opaque ) {
PWSTR symlinks;
PWSTR symlink;
UNICODE_STRING u_symlink;
BOOLEAN found;
NTSTATUS status;
/* 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 status;
}
/* Look for a matching NIC */
for ( symlink = symlinks ;
RtlInitUnicodeString ( &u_symlink, symlink ) , *symlink ;
symlink += ( ( u_symlink.Length / sizeof ( *symlink ) ) + 1 ) ) {
status = try_nic ( mac, &u_symlink, process, opaque, &found );
if ( found )
goto done;
}
status = STATUS_NO_SUCH_FILE;
done:
/* Free object list */
ExFreePool ( symlinks );
return status;
}

28
src/driver/nic.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef _NIC_H
#define _NIC_H
/*
* 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.
*/
extern NTSTATUS find_nic ( PUCHAR mac,
NTSTATUS ( *process ) ( PDEVICE_OBJECT pdo,
LPWSTR netcfginstanceid,
PVOID opaque ),
PVOID opaque );
#endif /* _NIC_H */

View File

@ -24,6 +24,7 @@
#include "acpi.h"
#include "ibft.h"
#include "sbft.h"
#include "abft.h"
/** Maximum time to wait for system disk, in seconds */
#define SANBOOTCONF_MAX_WAIT 120
@ -32,6 +33,8 @@
typedef struct _SANBOOTCONF_PRIV {
/* Copy of iBFT, if any */
PACPI_DESCRIPTION_HEADER ibft;
/* Copy of aBFT, if any */
PACPI_DESCRIPTION_HEADER abft;
/* Copy of sBFT, if any */
PACPI_DESCRIPTION_HEADER sbft;
} SANBOOTCONF_PRIV, *PSANBOOTCONF_PRIV;
@ -45,6 +48,11 @@ DEFINE_GUID ( GUID_SANBOOTCONF_CLASS, 0x8a2f8602, 0x8f0b, 0x4138,
CTL_CODE ( FILE_DEVICE_UNKNOWN, 0x0001, METHOD_BUFFERED, \
FILE_READ_ACCESS )
/** IoControl code to retrieve aBFT */
#define IOCTL_SANBOOTCONF_ABFT \
CTL_CODE ( FILE_DEVICE_UNKNOWN, 0x0861, METHOD_BUFFERED, \
FILE_READ_ACCESS )
/** IoControl code to retrieve sBFT */
#define IOCTL_SANBOOTCONF_SBFT \
CTL_CODE ( FILE_DEVICE_UNKNOWN, 0x0873, METHOD_BUFFERED, \
@ -122,6 +130,10 @@ static NTSTATUS sanbootconf_iocontrol_irp ( PDEVICE_OBJECT device, PIRP irp ) {
status = fetch_acpi_table_copy ( IBFT_SIG, priv->ibft,
buf, len );
break;
case IOCTL_SANBOOTCONF_ABFT:
status = fetch_acpi_table_copy ( ABFT_SIG, priv->abft,
buf, len );
break;
case IOCTL_SANBOOTCONF_SBFT:
status = fetch_acpi_table_copy ( SBFT_SIG, priv->sbft,
buf, len );
@ -479,6 +491,7 @@ NTSTATUS DriverEntry ( IN PDRIVER_OBJECT DriverObject,
/* Look for boot firmware tables*/
found_san =
( try_find_acpi_table ( IBFT_SIG, parse_ibft, &priv->ibft ) |
try_find_acpi_table ( ABFT_SIG, parse_abft, &priv->abft ) |
try_find_acpi_table ( SBFT_SIG, parse_sbft, &priv->sbft ) );
/* Wait for system disk, if booting from SAN */

View 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 acpi.c ibft.c sbft.c
SOURCES = sanbootconf.c registry.c acpi.c nic.c ibft.c abft.c sbft.c