diff -r ecef88726fc3 -r e25af8bd3957 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: