master/ethernet.c
changeset 2625 e25af8bd3957
parent 2593 e2388daebfbc
child 2626 713058b68b43
--- a/master/ethernet.c	Sun Jun 01 18:07:47 2014 +1200
+++ b/master/ethernet.c	Tue Apr 14 10:12:55 2015 -0400
@@ -79,6 +79,7 @@
 int ec_eoedev_stop(struct net_device *);
 int ec_eoedev_tx(struct sk_buff *, struct net_device *);
 struct net_device_stats *ec_eoedev_stats(struct net_device *);
+static int ec_eoedev_set_mac(struct net_device *netdev, void *p);
 
 /*****************************************************************************/
 
@@ -90,11 +91,34 @@
     .ndo_stop = ec_eoedev_stop,
     .ndo_start_xmit = ec_eoedev_tx,
     .ndo_get_stats = ec_eoedev_stats,
+    .ndo_set_mac_address = ec_eoedev_set_mac,
 };
 #endif
 
 /*****************************************************************************/
 
+/**
+ * ec_eoedev_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int
+ec_eoedev_set_mac(struct net_device *netdev, void *p)
+{
+   struct sockaddr *addr = p;
+
+   if (!is_valid_ether_addr(addr->sa_data))
+      return -EADDRNOTAVAIL;
+
+   memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+
+   return 0;
+}
+
+/*****************************************************************************/
+
 /** EoE constructor.
  *
  * Initializes the EoE handler, creates a net_device and registers it.
@@ -107,9 +131,13 @@
         )
 {
     ec_eoe_t **priv;
-    int i, ret = 0;
+    int ret = 0;
     char name[EC_DATAGRAM_NAME_SIZE];
 
+    struct net_device *dev;
+    unsigned char lo_mac[ETH_ALEN] = {0};
+    unsigned int use_master_mac = 0;
+
     eoe->slave = slave;
 
     ec_datagram_init(&eoe->datagram);
@@ -165,8 +193,53 @@
     eoe->dev->get_stats = ec_eoedev_stats;
 #endif
 
-    for (i = 0; i < ETH_ALEN; i++)
-        eoe->dev->dev_addr[i] = i | (i << 4);
+    // First check if the MAC address assigned to the master is globally unique
+    if ((slave->master->devices[EC_DEVICE_MAIN].dev->dev_addr[0] & 0x02) != 0x02) {
+        // The master MAC is unique and the NIC part can be used for the EoE interface MAC
+        use_master_mac = 1;
+    }
+    else {
+        // The master MAC is not unique, so we check for unique MAC in other interfaces
+        dev = first_net_device(&init_net);
+        while (dev) {
+            // Check if globally unique MAC address
+            if (dev->addr_len == ETH_ALEN) {
+                if (memcmp(dev->dev_addr, lo_mac, ETH_ALEN) != 0) {
+                    if ((dev->dev_addr[0] & 0x02) != 0x02) {
+                        // The first globally unique MAC address has been identified
+                        break;
+                    }
+                }
+            }
+            dev = next_net_device(dev);
+        }
+        if (eoe->dev->addr_len == ETH_ALEN) {
+            if (dev) {
+                // A unique MAC were identified in one of the other network interfaces
+                // and the NIC part can be used for the EoE interface MAC.
+                EC_SLAVE_INFO(slave, "%s MAC address derived from NIC part of %s MAC address",
+                    eoe->dev->name, dev->name);
+                eoe->dev->dev_addr[1] = dev->dev_addr[3];
+                eoe->dev->dev_addr[2] = dev->dev_addr[4];
+                eoe->dev->dev_addr[3] = dev->dev_addr[5];
+            }
+            else {
+                use_master_mac = 1;
+            }
+        }
+    }
+    if (eoe->dev->addr_len == ETH_ALEN) {
+        if (use_master_mac) {
+            EC_SLAVE_INFO(slave, "%s MAC address derived from NIC part of %s MAC address",
+                eoe->dev->name, slave->master->devices[EC_DEVICE_MAIN].dev->name);
+            eoe->dev->dev_addr[1] = slave->master->devices[EC_DEVICE_MAIN].dev->dev_addr[3];
+            eoe->dev->dev_addr[2] = slave->master->devices[EC_DEVICE_MAIN].dev->dev_addr[4];
+            eoe->dev->dev_addr[3] = slave->master->devices[EC_DEVICE_MAIN].dev->dev_addr[5];
+        }
+        eoe->dev->dev_addr[0] = 0x02;
+        eoe->dev->dev_addr[4] = (uint8_t)(slave->ring_position >> 8);
+        eoe->dev->dev_addr[5] = (uint8_t)(slave->ring_position);
+    }
 
     // initialize private data
     priv = netdev_priv(eoe->dev);
@@ -188,8 +261,6 @@
         goto out_free;
     }
 
-    // make the last address octet unique
-    eoe->dev->dev_addr[ETH_ALEN - 1] = (uint8_t) eoe->dev->ifindex;
     return 0;
 
  out_free: