From 2afe34efec2e446ffe2b8b9d57eff564faf7da63 Mon Sep 17 00:00:00 2001
From: Matthias Schiffer <mschiffer@universe-factory.net>
Date: Wed, 20 Jul 2016 18:42:56 +0200
Subject: [PATCH] Use MAC addresses provided by WLAN drivers by default

Some drivers (mt76) don't support arbitrary MAC addresses. Use the
addresses provided by the driver (avoiding the primary address) by default,
but fall back to our has-based scheme when the driver doesn't provide
(enough) addresses.
---
 .../upgrade/320-gluon-client-bridge-wireless  |  2 +-
 .../luasrc/usr/lib/lua/gluon/util.lua         | 65 ++++++++++++++++++-
 .../300-gluon-mesh-batman-adv-core-wan        |  3 +-
 .../320-gluon-mesh-batman-adv-core-wireless   |  4 +-
 ...340-gluon-mesh-batman-adv-core-mesh-on-lan |  2 +-
 .../lib/gluon/upgrade/400-mesh-vpn-fastd      |  2 +-
 6 files changed, 70 insertions(+), 8 deletions(-)

diff --git a/package/gluon-client-bridge/luasrc/lib/gluon/upgrade/320-gluon-client-bridge-wireless b/package/gluon-client-bridge/luasrc/lib/gluon/upgrade/320-gluon-client-bridge-wireless
index 2f07f2b91..16b9db930 100755
--- a/package/gluon-client-bridge/luasrc/lib/gluon/upgrade/320-gluon-client-bridge-wireless
+++ b/package/gluon-client-bridge/luasrc/lib/gluon/upgrade/320-gluon-client-bridge-wireless
@@ -25,7 +25,7 @@ local function configure_client(config, radio, index, suffix)
     return
   end
 
-  macaddr = util.generate_mac(3*(index-1))
+  macaddr = util.get_wlan_mac(radio, index, 1)
   if not macaddr then
     return
   end
diff --git a/package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua b/package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua
index 76e3a8282..b9e81b1fe 100644
--- a/package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua
+++ b/package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua
@@ -23,6 +23,7 @@ local function escape_args(ret, arg0, ...)
 end
 
 
+local io = io
 local os = os
 local string = string
 local tonumber = tonumber
@@ -34,6 +35,8 @@ local hash = require 'hash'
 local sysconfig = require 'gluon.sysconfig'
 local site = require 'gluon.site_config'
 local uci = require('luci.model.uci').cursor()
+local lutil = require 'luci.util'
+local fs = require 'nixio.fs'
 
 
 module 'gluon.util'
@@ -71,6 +74,45 @@ function node_id()
   return string.gsub(sysconfig.primary_mac, ':', '')
 end
 
+
+local function find_phy_by_path(path)
+  for phy in fs.glob('/sys/devices/' .. path .. '/ieee80211/phy*') do
+    return phy:match('([^/]+)$')
+  end
+end
+
+local function find_phy_by_macaddr(macaddr)
+  local addr = macaddr:lower()
+  for file in fs.glob('/sys/class/ieee80211/*/macaddress') do
+    if lutil.trim(fs.readfile(file)) == addr then
+      return file:match('([^/]+)/macaddress$')
+    end
+  end
+end
+
+local function find_phy(radio)
+  local config = uci:get_all('wireless', radio)
+
+  if not config or config.type ~= 'mac80211' then
+    return nil
+  elseif config.path then
+    return find_phy_by_path(config.path)
+  elseif config.macaddr then
+    return find_phy_by_macaddr(config.macaddr)
+  else
+    return nil
+  end
+end
+
+local function get_addresses(radio)
+  local phy = find_phy(radio)
+  if not phy then
+    return function() end
+  end
+
+  return io.lines('/sys/class/ieee80211/' .. phy .. '/addresses')
+end
+
 -- Generates a (hopefully) unique MAC address
 -- The parameter defines the ID to add to the mac addr
 --
@@ -83,7 +125,7 @@ end
 -- 5: ibss1
 -- 6: mesh-on-lan
 -- 7: unused
-function generate_mac(i)
+local function generate_mac(i)
   if i > 7 or i < 0 then return nil end -- max allowed id (0b111)
 
   local hashed = string.sub(hash.md5(sysconfig.primary_mac), 0, 12)
@@ -105,6 +147,27 @@ function generate_mac(i)
   return string.format('%02x:%s:%s:%s:%s:%02x', m1, m2, m3, m4, m5, m6)
 end
 
+function get_mac(index)
+  return generate_mac(3*(index-1))
+end
+
+function get_wlan_mac(radio, index, vif)
+  local primary = sysconfig.primary_mac:lower()
+
+  local i = 1
+  for addr in get_addresses(radio) do
+    if addr:lower() ~= primary then
+      if i == vif then
+        return addr
+      end
+
+      i = i + 1
+    end
+  end
+
+  return generate_mac(3*(index-1) + (vif-1))
+end
+
 -- Iterate over all radios defined in UCI calling
 -- f(radio, index, site.wifiX) for each radio found while passing
 --  site.wifi24 for 2.4 GHz devices and site.wifi5 for 5 GHz ones.
diff --git a/package/gluon-mesh-batman-adv-core/luasrc/lib/gluon/upgrade/300-gluon-mesh-batman-adv-core-wan b/package/gluon-mesh-batman-adv-core/luasrc/lib/gluon/upgrade/300-gluon-mesh-batman-adv-core-wan
index be96c012b..eafadb712 100755
--- a/package/gluon-mesh-batman-adv-core/luasrc/lib/gluon/upgrade/300-gluon-mesh-batman-adv-core-wan
+++ b/package/gluon-mesh-batman-adv-core/luasrc/lib/gluon/upgrade/300-gluon-mesh-batman-adv-core-wan
@@ -5,6 +5,5 @@ local uci = require('luci.model.uci').cursor()
 
 
 -- fix up duplicate mac addresses (for mesh-on-WAN)
-uci:set('network', 'wan', 'macaddr', util.generate_mac(3))
+uci:set('network', 'wan', 'macaddr', util.get_mac(2))
 uci:save('network')
-
diff --git a/package/gluon-mesh-batman-adv-core/luasrc/lib/gluon/upgrade/320-gluon-mesh-batman-adv-core-wireless b/package/gluon-mesh-batman-adv-core/luasrc/lib/gluon/upgrade/320-gluon-mesh-batman-adv-core-wireless
index bcf1ca0e2..e11d118ab 100755
--- a/package/gluon-mesh-batman-adv-core/luasrc/lib/gluon/upgrade/320-gluon-mesh-batman-adv-core-wireless
+++ b/package/gluon-mesh-batman-adv-core/luasrc/lib/gluon/upgrade/320-gluon-mesh-batman-adv-core-wireless
@@ -33,7 +33,7 @@ local function configure_ibss(config, radio, index, suffix, disabled)
     return
   end
 
-  macaddr = util.generate_mac(3*(index-1)+2)
+  macaddr = util.get_wlan_mac(radio, index, 3)
   if not macaddr then
     return
   end
@@ -88,7 +88,7 @@ local function configure_mesh(config, radio, index, suffix, disabled)
     return
   end
 
-  macaddr = util.generate_mac(3*(index-1)+1)
+  macaddr = util.get_wlan_mac(radio, index, 2)
   if not macaddr then
     return
   end
diff --git a/package/gluon-mesh-batman-adv-core/luasrc/lib/gluon/upgrade/340-gluon-mesh-batman-adv-core-mesh-on-lan b/package/gluon-mesh-batman-adv-core/luasrc/lib/gluon/upgrade/340-gluon-mesh-batman-adv-core-mesh-on-lan
index 99ca42132..2cc0d9896 100755
--- a/package/gluon-mesh-batman-adv-core/luasrc/lib/gluon/upgrade/340-gluon-mesh-batman-adv-core-mesh-on-lan
+++ b/package/gluon-mesh-batman-adv-core/luasrc/lib/gluon/upgrade/340-gluon-mesh-batman-adv-core-mesh-on-lan
@@ -18,7 +18,7 @@ uci:section('network', 'interface', 'mesh_lan', {
   proto   = 'batadv',
   mesh    = 'bat0',
   mesh_no_rebroadcast = '1',
-  macaddr = util.generate_mac(6),
+  macaddr = util.get_mac(3),
 })
 
 if uci:get('network', 'mesh_lan', 'auto') == nil then
diff --git a/package/gluon-mesh-vpn-fastd/luasrc/lib/gluon/upgrade/400-mesh-vpn-fastd b/package/gluon-mesh-vpn-fastd/luasrc/lib/gluon/upgrade/400-mesh-vpn-fastd
index 77f2e6f29..6f2095f2f 100755
--- a/package/gluon-mesh-vpn-fastd/luasrc/lib/gluon/upgrade/400-mesh-vpn-fastd
+++ b/package/gluon-mesh-vpn-fastd/luasrc/lib/gluon/upgrade/400-mesh-vpn-fastd
@@ -127,7 +127,7 @@ uci:section('network', 'interface', 'mesh_vpn',
 		  proto = 'batadv',
 		  mesh = 'bat0',
 		  mesh_no_rebroadcast = 1,
-		  macaddr = util.generate_mac(0),
+		  macaddr = util.get_mac(1),
 	  }
 )
 
-- 
GitLab