hostapd: rework reload support and MAC address handling
[openwrt/staging/dangole.git] / package / network / services / hostapd / files / common.uc
index f37804c8c6ec5678dbc8d50a3a572cd0999ed79e..ccffe3eb4362199aabdb5655a5e85e9d54be746d 100644 (file)
@@ -1,6 +1,6 @@
 import * as nl80211 from "nl80211";
 import * as rtnl from "rtnl";
-import { readfile } from "fs";
+import { readfile, glob, basename, readlink } from "fs";
 
 const iftypes = {
        ap: nl80211.const.NL80211_IFTYPE_AP,
@@ -109,71 +109,139 @@ function macaddr_join(addr)
        return join(":", map(addr, (val) => sprintf("%02x", val)));
 }
 
-function wdev_generate_macaddr(phy, data)
+function wdev_macaddr(wdev)
 {
-       let idx = int(data.id ?? 0);
-       let mbssid = int(data.mbssid ?? 0) > 0;
-       let num_global = int(data.num_global ?? 1);
-       let use_global = !mbssid && idx < num_global;
+       return trim(readfile(`/sys/class/net/${wdev}/address`));
+}
 
-       let base_addr = phy_sysfs_file(phy, "macaddress");
-       if (!base_addr)
-               return null;
+const phy_proto = {
+       macaddr_init: function(used, options) {
+               this.macaddr_options = options ?? {};
+               this.macaddr_list = {};
 
-       if (!idx && !mbssid)
-               return base_addr;
+               if (type(used) == "object")
+                       for (let addr in used)
+                               this.macaddr_list[addr] = used[addr];
+               else
+                       for (let addr in used)
+                               this.macaddr_list[addr] = -1;
 
-       let base_mask = phy_sysfs_file(phy, "address_mask");
-       if (!base_mask)
-               return null;
+               this.for_each_wdev((wdev) => {
+                       let macaddr = wdev_macaddr(wdev);
+                       this.macaddr_list[macaddr] ??= -1;
+               });
 
-       if (base_mask == "00:00:00:00:00:00" && idx >= num_global) {
-               let addrs = split(phy_sysfs_file(phy, "addresses"), "\n");
+               return this.macaddr_list;
+       },
 
-               if (idx < length(addrs))
-                       return addrs[idx];
+       macaddr_generate: function(data) {
+               let phy = this.name;
+               let idx = int(data.id ?? 0);
+               let mbssid = int(data.mbssid ?? 0) > 0;
+               let num_global = int(data.num_global ?? 1);
+               let use_global = !mbssid && idx < num_global;
 
-               base_mask = "ff:ff:ff:ff:ff:ff";
-       }
+               let base_addr = phy_sysfs_file(phy, "macaddress");
+               if (!base_addr)
+                       return null;
+
+               if (!idx && !mbssid)
+                       return base_addr;
+
+               let base_mask = phy_sysfs_file(phy, "address_mask");
+               if (!base_mask)
+                       return null;
+
+               if (base_mask == "00:00:00:00:00:00" && idx >= num_global) {
+                       let addrs = split(phy_sysfs_file(phy, "addresses"), "\n");
+
+                       if (idx < length(addrs))
+                               return addrs[idx];
+
+                       base_mask = "ff:ff:ff:ff:ff:ff";
+               }
+
+               let addr = macaddr_split(base_addr);
+               let mask = macaddr_split(base_mask);
+               let type;
 
-       let addr = macaddr_split(base_addr);
-       let mask = macaddr_split(base_mask);
-       let type;
-
-       if (mbssid)
-               type = "b5";
-       else if (use_global)
-               type = "add";
-       else if (mask[0] > 0)
-               type = "b1";
-       else if (mask[5] < 0xff)
-               type = "b5";
-       else
-               type = "add";
-
-       switch (type) {
-       case "b1":
-               if (!(addr[0] & 2))
-                       idx--;
-               addr[0] |= 2;
-               addr[0] ^= idx << 2;
-               break;
-       case "b5":
                if (mbssid)
+                       type = "b5";
+               else if (use_global)
+                       type = "add";
+               else if (mask[0] > 0)
+                       type = "b1";
+               else if (mask[5] < 0xff)
+                       type = "b5";
+               else
+                       type = "add";
+
+               switch (type) {
+               case "b1":
+                       if (!(addr[0] & 2))
+                               idx--;
                        addr[0] |= 2;
-               addr[5] ^= idx;
-               break;
-       default:
-               for (let i = 5; i > 0; i--) {
-                       addr[i] += idx;
-                       if (addr[i] < 256)
-                               break;
-                       addr[i] %= 256;
+                       addr[0] ^= idx << 2;
+                       break;
+               case "b5":
+                       if (mbssid)
+                               addr[0] |= 2;
+                       addr[5] ^= idx;
+                       break;
+               default:
+                       for (let i = 5; i > 0; i--) {
+                               addr[i] += idx;
+                               if (addr[i] < 256)
+                                       break;
+                               addr[i] %= 256;
+                       }
+                       break;
+               }
+
+               return macaddr_join(addr);
+       },
+
+       macaddr_next: function(val) {
+               let data = this.macaddr_options ?? {};
+               let list = this.macaddr_list;
+
+               for (let i = 0; i < 32; i++) {
+                       data.id = i;
+
+                       let mac = this.macaddr_generate(data);
+                       if (!mac)
+                               return null;
+
+                       if (list[mac] != null)
+                               continue;
+
+                       list[mac] = val != null ? val : -1;
+                       return mac;
+               }
+       },
+
+       for_each_wdev: function(cb) {
+               let wdevs = glob(`/sys/class/ieee80211/${this.name}/device/net/*`);
+               wdevs = map(wdevs, (arg) => basename(arg));
+               for (let wdev in wdevs) {
+                       if (basename(readlink(`/sys/class/net/${wdev}/phy80211`)) != this.name)
+                               continue;
+
+                       cb(wdev);
                }
-               break;
        }
+};
 
-       return macaddr_join(addr);
+function phy_open(phy)
+{
+       let phyidx = readfile(`/sys/class/ieee80211/${phy}/index`);
+       if (!phyidx)
+               return null;
+
+       return proto({
+               name: phy,
+               idx: int(phyidx)
+       }, phy_proto);
 }
 
 const vlist_proto = {
@@ -247,4 +315,4 @@ function vlist_new(cb) {
                }, vlist_proto);
 }
 
-export { wdev_remove, wdev_create, wdev_generate_macaddr, is_equal, vlist_new, phy_is_fullmac };
+export { wdev_remove, wdev_create, is_equal, vlist_new, phy_is_fullmac, phy_open };