summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/net/netdev_settings.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/ipxe/src/net/netdev_settings.c')
-rw-r--r--qemu/roms/ipxe/src/net/netdev_settings.c348
1 files changed, 348 insertions, 0 deletions
diff --git a/qemu/roms/ipxe/src/net/netdev_settings.c b/qemu/roms/ipxe/src/net/netdev_settings.c
new file mode 100644
index 000000000..b3b2e68d8
--- /dev/null
+++ b/qemu/roms/ipxe/src/net/netdev_settings.c
@@ -0,0 +1,348 @@
+/*
+ * 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, mac ) = {
+ .name = "mac",
+ .description = "MAC address",
+ .type = &setting_type_hex,
+};
+const struct setting bustype_setting __setting ( SETTING_NETDEV, bustype ) = {
+ .name = "bustype",
+ .description = "Bus type",
+ .type = &setting_type_string,
+};
+const struct setting busloc_setting __setting ( SETTING_NETDEV, busloc ) = {
+ .name = "busloc",
+ .description = "Bus location",
+ .type = &setting_type_uint32,
+};
+const struct setting busid_setting __setting ( SETTING_NETDEV, busid ) = {
+ .name = "busid",
+ .description = "Bus ID",
+ .type = &setting_type_hex,
+};
+const struct setting chip_setting __setting ( SETTING_NETDEV, chip ) = {
+ .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,
+};