mirror of
https://github.com/ipxe/sanbootconf.git
synced 2025-05-09 01:21:13 +08:00
[driver] Add support for the AoE boot firmware table (aBFT)
Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
This commit is contained in:
parent
43a46e10ba
commit
e604684e55
63
src/driver/abft.c
Normal file
63
src/driver/abft.c
Normal 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
58
src/driver/abft.h
Normal 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 */
|
@ -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, ®_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
310
src/driver/nic.c
Normal 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, ®_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
28
src/driver/nic.h
Normal 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 */
|
@ -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 */
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user