extern struct net_device * find_netdev_by_index ( unsigned int index );
extern struct net_device * find_netdev_by_location ( unsigned int bus_type,
unsigned int location );
+extern struct net_device *
+find_netdev_by_ll_addr ( struct ll_protocol *ll_protocol, const void *ll_addr );
extern struct net_device * last_opened_netdev ( void );
extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
struct net_protocol *net_protocol, const void *ll_dest,
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' ) {
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.
clear_settings ( netdev_settings ( netdev ) );
unregister_settings ( netdev_settings ( netdev ) );
err_register_settings:
+ err_duplicate:
return rc;
}
return NULL;
}
+/**
+ * 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
*