aboutsummaryrefslogtreecommitdiff
path: root/src/net
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2014-07-30 18:11:20 +0100
committerMichael Brown <mcb30@ipxe.org>2014-07-30 18:22:09 +0100
commit98d09a1e0372226bdea46f7dc8ce7f0cae98f08c (patch)
treee530ade6bf7cda0565eddb67cfa250635c22697b /src/net
parent057eb9e496b4d6e04864df48f3855f014da53aeb (diff)
downloadipxe-98d09a1e0372226bdea46f7dc8ce7f0cae98f08c.zip
ipxe-98d09a1e0372226bdea46f7dc8ce7f0cae98f08c.tar.gz
ipxe-98d09a1e0372226bdea46f7dc8ce7f0cae98f08c.tar.bz2
[netdevice] Avoid registering duplicate network devices
Reject network devices which appear to be duplicates of those already available via a different underlying hardware device. On a Xen PV-HVM system, this allows us to filter out the emulated PCI NICs (which would otherwise appear alongside the netfront NICs). Note that we cannot use the Xen facility to "unplug" the emulated PCI NICs, since there is no guarantee that the OS we subsequently load will have a native netfront driver. We permit devices with the same MAC address if they are attached to the same underlying hardware device (e.g. VLAN devices). Inspired-by: Marin Hannache <git@mareo.fr> Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/net')
-rw-r--r--src/net/netdevice.c45
1 files changed, 40 insertions, 5 deletions
diff --git a/src/net/netdevice.c b/src/net/netdevice.c
index 2350256..a802085 100644
--- a/src/net/netdevice.c
+++ b/src/net/netdevice.c
@@ -602,9 +602,27 @@ struct net_device * alloc_netdev ( size_t priv_len ) {
int register_netdev ( struct net_device *netdev ) {
struct ll_protocol *ll_protocol = netdev->ll_protocol;
struct net_driver *driver;
+ struct net_device *duplicate;
uint32_t seed;
int rc;
+ /* Set initial link-layer address, if not already set */
+ if ( ! netdev_has_ll_addr ( netdev ) ) {
+ ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
+ }
+
+ /* Reject network devices that are already available via a
+ * different hardware device.
+ */
+ duplicate = find_netdev_by_ll_addr ( ll_protocol, netdev->ll_addr );
+ if ( duplicate && ( duplicate->dev != netdev->dev ) ) {
+ DBGC ( netdev, "NETDEV rejecting duplicate (phys %s) of %s "
+ "(phys %s)\n", netdev->dev->name, duplicate->name,
+ duplicate->dev->name );
+ rc = -EEXIST;
+ goto err_duplicate;
+ }
+
/* Record device index and create device name */
netdev->index = netdev_index++;
if ( netdev->name[0] == '\0' ) {
@@ -612,11 +630,6 @@ int register_netdev ( struct net_device *netdev ) {
netdev->index );
}
- /* Set initial link-layer address, if not already set */
- if ( ! netdev_has_ll_addr ( netdev ) ) {
- ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
- }
-
/* Use least significant bits of the link-layer address to
* improve the randomness of the (non-cryptographic) random
* number generator.
@@ -660,6 +673,7 @@ int register_netdev ( struct net_device *netdev ) {
clear_settings ( netdev_settings ( netdev ) );
unregister_settings ( netdev_settings ( netdev ) );
err_register_settings:
+ err_duplicate:
return rc;
}
@@ -853,6 +867,27 @@ struct net_device * find_netdev_by_location ( unsigned int bus_type,
}
/**
+ * Get network device by link-layer address
+ *
+ * @v ll_protocol Link-layer protocol
+ * @v ll_addr Link-layer address
+ * @ret netdev Network device, or NULL
+ */
+struct net_device * find_netdev_by_ll_addr ( struct ll_protocol *ll_protocol,
+ const void *ll_addr ) {
+ struct net_device *netdev;
+
+ list_for_each_entry ( netdev, &net_devices, list ) {
+ if ( ( netdev->ll_protocol == ll_protocol ) &&
+ ( memcmp ( netdev->ll_addr, ll_addr,
+ ll_protocol->ll_addr_len ) == 0 ) )
+ return netdev;
+ }
+
+ return NULL;
+}
+
+/**
* Get most recently opened network device
*
* @ret netdev Most recently opened network device, or NULL