2
0
mirror of https://github.com/xcat2/xNBA.git synced 2025-07-30 00:02:42 +00:00
Files
xNBA/src/net/netdev_settings.c
Michael Brown 22001cb206 [settings] Explicitly separate the concept of a completed fetched setting
The fetch_setting() family of functions may currently modify the
definition of the specified setting (e.g. to add missing type
information).  Clean up this interface by requiring callers to provide
an explicit buffer to contain the completed definition of the fetched
setting, if required.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2013-12-05 00:37:02 +00:00

349 lines
9.5 KiB
C

/*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <string.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/dhcp.h>
#include <ipxe/dhcpopts.h>
#include <ipxe/settings.h>
#include <ipxe/device.h>
#include <ipxe/netdevice.h>
#include <ipxe/init.h>
/** @file
*
* Network device configuration settings
*
*/
/** Network device predefined settings */
const struct setting mac_setting __setting ( SETTING_NETDEV ) = {
.name = "mac",
.description = "MAC address",
.type = &setting_type_hex,
};
const struct setting bustype_setting __setting ( SETTING_NETDEV ) = {
.name = "bustype",
.description = "Bus type",
.type = &setting_type_string,
};
const struct setting busloc_setting __setting ( SETTING_NETDEV ) = {
.name = "busloc",
.description = "Bus location",
.type = &setting_type_uint32,
};
const struct setting busid_setting __setting ( SETTING_NETDEV ) = {
.name = "busid",
.description = "Bus ID",
.type = &setting_type_hex,
};
const struct setting chip_setting __setting ( SETTING_NETDEV ) = {
.name = "chip",
.description = "Chip",
.type = &setting_type_string,
};
/**
* Store MAC address setting
*
* @v netdev Network device
* @v data Setting data, or NULL to clear setting
* @v len Length of setting data
* @ret rc Return status code
*/
static int netdev_store_mac ( struct net_device *netdev,
const void *data, size_t len ) {
struct ll_protocol *ll_protocol = netdev->ll_protocol;
/* Record new MAC address */
if ( data ) {
if ( len != netdev->ll_protocol->ll_addr_len )
return -EINVAL;
memcpy ( netdev->ll_addr, data, len );
} else {
/* Reset MAC address if clearing setting */
ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
}
return 0;
}
/**
* Fetch MAC address setting
*
* @v netdev Network device
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int netdev_fetch_mac ( struct net_device *netdev, void *data,
size_t len ) {
if ( len > netdev->ll_protocol->ll_addr_len )
len = netdev->ll_protocol->ll_addr_len;
memcpy ( data, netdev->ll_addr, len );
return netdev->ll_protocol->ll_addr_len;
}
/**
* Fetch bus type setting
*
* @v netdev Network device
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int netdev_fetch_bustype ( struct net_device *netdev, void *data,
size_t len ) {
static const char *bustypes[] = {
[BUS_TYPE_PCI] = "PCI",
[BUS_TYPE_ISAPNP] = "ISAPNP",
[BUS_TYPE_EISA] = "EISA",
[BUS_TYPE_MCA] = "MCA",
[BUS_TYPE_ISA] = "ISA",
[BUS_TYPE_TAP] = "TAP",
};
struct device_description *desc = &netdev->dev->desc;
const char *bustype;
assert ( desc->bus_type < ( sizeof ( bustypes ) /
sizeof ( bustypes[0] ) ) );
bustype = bustypes[desc->bus_type];
assert ( bustype != NULL );
strncpy ( data, bustype, len );
return strlen ( bustype );
}
/**
* Fetch bus location setting
*
* @v netdev Network device
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int netdev_fetch_busloc ( struct net_device *netdev, void *data,
size_t len ) {
struct device_description *desc = &netdev->dev->desc;
uint32_t busloc;
busloc = cpu_to_be32 ( desc->location );
if ( len > sizeof ( busloc ) )
len = sizeof ( busloc );
memcpy ( data, &busloc, len );
return sizeof ( busloc );
}
/**
* Fetch bus ID setting
*
* @v netdev Network device
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int netdev_fetch_busid ( struct net_device *netdev, void *data,
size_t len ) {
struct device_description *desc = &netdev->dev->desc;
struct dhcp_netdev_desc dhcp_desc;
dhcp_desc.type = desc->bus_type;
dhcp_desc.vendor = htons ( desc->vendor );
dhcp_desc.device = htons ( desc->device );
if ( len > sizeof ( dhcp_desc ) )
len = sizeof ( dhcp_desc );
memcpy ( data, &dhcp_desc, len );
return sizeof ( dhcp_desc );
}
/**
* Fetch chip setting
*
* @v netdev Network device
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int netdev_fetch_chip ( struct net_device *netdev, void *data,
size_t len ) {
const char *chip = netdev->dev->driver_name;
strncpy ( data, chip, len );
return strlen ( chip );
}
/** A network device setting operation */
struct netdev_setting_operation {
/** Setting */
const struct setting *setting;
/** Store setting (or NULL if not supported)
*
* @v netdev Network device
* @v data Setting data, or NULL to clear setting
* @v len Length of setting data
* @ret rc Return status code
*/
int ( * store ) ( struct net_device *netdev, const void *data,
size_t len );
/** Fetch setting
*
* @v netdev Network device
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
int ( * fetch ) ( struct net_device *netdev, void *data, size_t len );
};
/** Network device settings */
static struct netdev_setting_operation netdev_setting_operations[] = {
{ &mac_setting, netdev_store_mac, netdev_fetch_mac },
{ &bustype_setting, NULL, netdev_fetch_bustype },
{ &busloc_setting, NULL, netdev_fetch_busloc },
{ &busid_setting, NULL, netdev_fetch_busid },
{ &chip_setting, NULL, netdev_fetch_chip },
};
/**
* Store value of network device setting
*
* @v settings Settings block
* @v setting Setting to store
* @v data Setting data, or NULL to clear setting
* @v len Length of setting data
* @ret rc Return status code
*/
static int netdev_store ( struct settings *settings,
const struct setting *setting,
const void *data, size_t len ) {
struct net_device *netdev = container_of ( settings, struct net_device,
settings.settings );
struct netdev_setting_operation *op;
unsigned int i;
/* Handle network device-specific settings */
for ( i = 0 ; i < ( sizeof ( netdev_setting_operations ) /
sizeof ( netdev_setting_operations[0] ) ) ; i++ ) {
op = &netdev_setting_operations[i];
if ( setting_cmp ( setting, op->setting ) == 0 ) {
if ( op->store ) {
return op->store ( netdev, data, len );
} else {
return -ENOTSUP;
}
}
}
return generic_settings_store ( settings, setting, data, len );
}
/**
* Fetch value of network device setting
*
* @v settings Settings block
* @v setting Setting to fetch
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int netdev_fetch ( struct settings *settings, struct setting *setting,
void *data, size_t len ) {
struct net_device *netdev = container_of ( settings, struct net_device,
settings.settings );
struct netdev_setting_operation *op;
unsigned int i;
/* Handle network device-specific settings */
for ( i = 0 ; i < ( sizeof ( netdev_setting_operations ) /
sizeof ( netdev_setting_operations[0] ) ) ; i++ ) {
op = &netdev_setting_operations[i];
if ( setting_cmp ( setting, op->setting ) == 0 )
return op->fetch ( netdev, data, len );
}
return generic_settings_fetch ( settings, setting, data, len );
}
/**
* Clear network device settings
*
* @v settings Settings block
*/
static void netdev_clear ( struct settings *settings ) {
generic_settings_clear ( settings );
}
/** Network device configuration settings operations */
struct settings_operations netdev_settings_operations = {
.store = netdev_store,
.fetch = netdev_fetch,
.clear = netdev_clear,
};
/**
* Redirect "netX" settings block
*
* @v settings Settings block
* @ret settings Underlying settings block
*/
static struct settings * netdev_redirect ( struct settings *settings ) {
struct net_device *netdev;
/* Redirect to most recently opened network device */
netdev = last_opened_netdev();
if ( netdev ) {
return netdev_settings ( netdev );
} else {
return settings;
}
}
/** "netX" settings operations */
static struct settings_operations netdev_redirect_settings_operations = {
.redirect = netdev_redirect,
};
/** "netX" settings */
static struct settings netdev_redirect_settings = {
.refcnt = NULL,
.siblings = LIST_HEAD_INIT ( netdev_redirect_settings.siblings ),
.children = LIST_HEAD_INIT ( netdev_redirect_settings.children ),
.op = &netdev_redirect_settings_operations,
};
/** Initialise "netX" settings */
static void netdev_redirect_settings_init ( void ) {
int rc;
if ( ( rc = register_settings ( &netdev_redirect_settings, NULL,
"netX" ) ) != 0 ) {
DBG ( "Could not register netX settings: %s\n",
strerror ( rc ) );
return;
}
}
/** "netX" settings initialiser */
struct init_fn netdev_redirect_settings_init_fn __init_fn ( INIT_LATE ) = {
.initialise = netdev_redirect_settings_init,
};