diff -r f859d567f94e -r 42b62867574d master/ethernet.c --- a/master/ethernet.c Fri Jan 22 10:11:58 2016 +0100 +++ b/master/ethernet.c Fri Jan 22 13:09:43 2016 +0100 @@ -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,65 @@ 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 +273,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: @@ -266,7 +349,8 @@ current_size = remaining_size; last_fragment = 1; } else { - current_size = ((eoe->slave->configured_tx_mailbox_size - 10) / 32) * 32; + current_size = + ((eoe->slave->configured_tx_mailbox_size - 10) / 32) * 32; last_fragment = 0; }