# SPDX-License-Identifier: BSD-3-Clause import array import struct import fcntl import socket from .utils import Util ETHTOOL_GPERMADDR = 0x00000020 SIOCETHTOOL = 0x8946 MAX_ADDR_LEN = 32 IFNAMESIZ = 16 def get_perm_addr(ifname): """ Return the Permanent address value for the specified interface using the ETHTOOL_GPERMADDR ioctl command. Please for further documentation, see: https://github.com/torvalds/linux/blob/master/include/uapi/linux/ethtool.h#L734 https://github.com/torvalds/linux/blob/master/include/uapi/linux/ethtool.h#L1388 https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/tree/ethtool.c#n4172 """ try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sockfd = sock.fileno() ifname = ifname.encode("utf-8") if len(ifname) > IFNAMESIZ: return None ecmd = array.array( "B", struct.pack( "II%is" % MAX_ADDR_LEN, ETHTOOL_GPERMADDR, MAX_ADDR_LEN, b"\x00" * MAX_ADDR_LEN, ), ) ifreq = struct.pack("%isP" % IFNAMESIZ, ifname, ecmd.buffer_info()[0]) fcntl.ioctl(sockfd, SIOCETHTOOL, ifreq) try: res = ecmd.tobytes() except AttributeError: # tobytes() is not available in python2 res = ecmd.tostring() _, size, perm_addr = struct.unpack("II%is" % MAX_ADDR_LEN, res) perm_addr = Util.mac_ntoa(perm_addr[:size]) except IOError: perm_addr = None finally: sock.close() return perm_addr