wifi-scripts: create the wlan object in board_data if not present
[openwrt/staging/jow.git] / package / network / config / wifi-scripts / files / usr / share / hostap / wifi-detect.uc
1 #!/usr/bin/env ucode
2 'use strict';
3 import { readfile, writefile, realpath, glob, basename, unlink, open, rename } from "fs";
4 import { is_equal } from "/usr/share/hostap/common.uc";
5 let nl = require("nl80211");
6
7 let board_file = "/etc/board.json";
8 let prev_board_data = json(readfile(board_file));
9 let board_data = json(readfile(board_file));
10
11 function phy_idx(name) {
12 return +rtrim(readfile(`/sys/class/ieee80211/${name}/index`));
13 }
14
15 function phy_path(name) {
16 let devpath = realpath(`/sys/class/ieee80211/${name}/device`);
17
18 devpath = replace(devpath, /^\/sys\/devices\//, "");
19 if (match(devpath, /^platform\/.*\/pci/))
20 devpath = replace(devpath, /^platform\//, "");
21 let dev_phys = map(glob(`/sys/class/ieee80211/${name}/device/ieee80211/*`), basename);
22 sort(dev_phys, (a, b) => phy_idx(a) - phy_idx(b));
23
24 let ofs = index(dev_phys, name);
25 if (ofs > 0)
26 devpath += `+${ofs}`;
27
28 return devpath;
29 }
30
31 function cleanup() {
32 let wlan = board_data.wlan;
33
34 for (let name in wlan)
35 if (substr(name, 0, 3) == "phy")
36 delete wlan[name];
37 else
38 delete wlan[name].info;
39 }
40
41 function wiphy_get_entry(phy, path) {
42 board_data.wlan ??= {};
43
44 let wlan = board_data.wlan;
45 for (let name in wlan)
46 if (wlan[name].path == path)
47 return wlan[name];
48
49 wlan[phy] = {
50 path: path
51 };
52
53 return wlan[phy];
54 }
55
56 function wiphy_detect() {
57 let phys = nl.request(nl.const.NL80211_CMD_GET_WIPHY, nl.const.NLM_F_DUMP, { split_wiphy_dump: true });
58 if (!phys)
59 return;
60
61 for (let phy in phys) {
62 let name = phy.wiphy_name;
63 let path = phy_path(name);
64 let info = {
65 antenna_rx: phy.wiphy_antenna_avail_rx,
66 antenna_tx: phy.wiphy_antenna_avail_tx,
67 bands: {},
68 };
69
70 let bands = info.bands;
71 for (let band in phy.wiphy_bands) {
72 if (!band || !band.freqs)
73 continue;
74 let freq = band.freqs[0].freq;
75 let band_info = {};
76 let band_name;
77 if (freq > 50000)
78 band_name = "60G";
79 else if (freq > 5900)
80 band_name = "6G";
81 else if (freq > 4000)
82 band_name = "5G";
83 else
84 band_name = "2G";
85 bands[band_name] = band_info;
86 if (band.ht_capa > 0)
87 band_info.ht = true;
88 if (band.vht_capa > 0)
89 band_info.vht = true;
90 let he_phy_cap = 0;
91
92 for (let ift in band.iftype_data) {
93 if (!ift.he_cap_phy)
94 continue;
95
96 band_info.he = true;
97 he_phy_cap |= ift.he_cap_phy[0];
98 /* TODO: EHT */
99 }
100
101 if (band_name != "2G" &&
102 (he_phy_cap & 0x18) || ((band.vht_capa >> 2) & 0x3))
103 band_info.max_width = 160;
104 else if (band_name != "2G" &&
105 (he_phy_cap & 4) || band.vht_capa > 0)
106 band_info.max_width = 80;
107 else if ((band.ht_capa & 0x2) || (he_phy_cap & 0x2))
108 band_info.max_width = 40;
109 else
110 band_info.max_width = 20;
111
112 let modes = band_info.modes = [ "NOHT" ];
113 if (band_info.ht)
114 push(modes, "HT20");
115 if (band_info.vht)
116 push(modes, "VHT20");
117 if (band_info.he)
118 push(modes, "HE20");
119 if (band.ht_capa & 0x2) {
120 push(modes, "HT40");
121 if (band_info.vht)
122 push(modes, "VHT40")
123 }
124 if (he_phy_cap & 0x2)
125 push(modes, "HE40");
126
127 if (band_name == "2G")
128 continue;
129 if (band_info.vht)
130 push(modes, "VHT80");
131 if (he_phy_cap & 4)
132 push(modes, "HE80");
133 if ((band.vht_capa >> 2) & 0x3)
134 push(modes, "VHT160");
135 if (he_phy_cap & 0x18)
136 push(modes, "HE160");
137 }
138
139 let entry = wiphy_get_entry(name, path);
140 entry.info = info;
141 }
142 }
143
144 cleanup();
145 wiphy_detect();
146 if (!is_equal(prev_board_data, board_data)) {
147 let new_file = board_file + ".new";
148 unlink(new_file);
149 let f = open(new_file, "wx");
150 if (!f)
151 exit(1);
152 f.write(sprintf("%.J\n", board_data));
153 f.close();
154 rename(new_file, board_file);
155 }