Eoe mac address now derived from unique mac.
authorKnud Baastrup <kba@deif.com>
Tue, 14 Apr 2015 10:12:55 -0400
changeset 2625 e25af8bd3957
parent 2624 ecef88726fc3
child 2626 713058b68b43
Eoe mac address now derived from unique mac.
The EoE MAC address is now derived from the NIC part of the first global
unique MAC address of the linked list of available network interfaces or
otherwise the MAC address used by the EtherCAT master. The EoE MAC address
will get the format 02:NIC:NIC:NIC:RP:RP where NIC comes from the unique MAC
address (if available) and RP is the ring position of the EoE slave.
master/ethernet.c
--- 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: