8db245cdb7330bed2f5a5052bc836d8b49a1a0cd
[openwrt/staging/jow.git] / package / network / services / hostapd / files / wdev.uc
1 #!/usr/bin/env ucode
2 'use strict';
3 import { vlist_new, is_equal, wdev_create, wdev_remove, wdev_generate_macaddr } from "/usr/share/hostap/common.uc";
4 import { readfile, writefile, basename, readlink, glob } from "fs";
5
6 let keep_devices = {};
7 let phy = shift(ARGV);
8
9 const mesh_params = [
10 "mesh_retry_timeout", "mesh_confirm_timeout", "mesh_holding_timeout", "mesh_max_peer_links",
11 "mesh_max_retries", "mesh_ttl", "mesh_element_ttl", "mesh_hwmp_max_preq_retries",
12 "mesh_path_refresh_time", "mesh_min_discovery_timeout", "mesh_hwmp_active_path_timeout",
13 "mesh_hwmp_preq_min_interval", "mesh_hwmp_net_diameter_traversal_time", "mesh_hwmp_rootmode",
14 "mesh_hwmp_rann_interval", "mesh_gate_announcements", "mesh_sync_offset_max_neighor",
15 "mesh_rssi_threshold", "mesh_hwmp_active_path_to_root_timeout", "mesh_hwmp_root_interval",
16 "mesh_hwmp_confirmation_interval", "mesh_awake_window", "mesh_plink_timeout",
17 "mesh_auto_open_plinks", "mesh_fwding", "mesh_power_mode"
18 ];
19
20 function iface_stop(wdev)
21 {
22 if (keep_devices[wdev.ifname])
23 return;
24
25 wdev_remove(wdev.ifname);
26 }
27
28 function iface_start(wdev)
29 {
30 let ifname = wdev.ifname;
31
32 if (readfile(`/sys/class/net/${ifname}/ifindex`)) {
33 system([ "ip", "link", "set", "dev", ifname, "down" ]);
34 wdev_remove(ifname);
35 }
36 wdev_create(phy, ifname, wdev);
37 system([ "ip", "link", "set", "dev", ifname, "up" ]);
38 if (wdev.freq)
39 system(`iw dev ${ifname} set freq ${wdev.freq} ${wdev.htmode}`);
40 if (wdev.mode == "adhoc") {
41 let cmd = ["iw", "dev", ifname, "ibss", "join", wdev.ssid, wdev.freq, wdev.htmode, "fixed-freq" ];
42 if (wdev.bssid)
43 push(cmd, wdev.bssid);
44 for (let key in [ "beacon-interval", "basic-rates", "mcast-rate", "keys" ])
45 if (wdev[key])
46 push(cmd, key, wdev[key]);
47 system(cmd);
48 } else if (wdev.mode == "mesh") {
49 let cmd = [ "iw", "dev", ifname, "mesh", "join", wdev.ssid, "freq", wdev.freq, wdev.htmode ];
50 for (let key in [ "mcast-rate", "beacon-interval" ])
51 if (wdev[key])
52 push(cmd, key, wdev[key]);
53 system(cmd);
54
55 cmd = ["iw", "dev", ifname, "set", "mesh_param" ];
56 let len = length(cmd);
57
58 for (let param in mesh_params)
59 if (wdev[param])
60 push(cmd, param, wdev[param]);
61
62 if (len == length(cmd))
63 return;
64
65 system(cmd);
66 }
67
68 }
69
70 function iface_cb(new_if, old_if)
71 {
72 if (old_if && new_if && is_equal(old_if, new_if))
73 return;
74
75 if (old_if)
76 iface_stop(old_if);
77 if (new_if)
78 iface_start(new_if);
79 }
80
81 function drop_inactive(config)
82 {
83 for (let key in config) {
84 if (!readfile(`/sys/class/net/${key}/ifindex`))
85 delete config[key];
86 }
87 }
88
89 function add_ifname(config)
90 {
91 for (let key in config)
92 config[key].ifname = key;
93 }
94
95 function delete_ifname(config)
96 {
97 for (let key in config)
98 delete config[key].ifname;
99 }
100
101 function add_existing(phy, config)
102 {
103 let wdevs = glob(`/sys/class/ieee80211/${phy}/device/net/*`);
104 wdevs = map(wdevs, (arg) => basename(arg));
105 for (let wdev in wdevs) {
106 if (config[wdev])
107 continue;
108
109 if (basename(readlink(`/sys/class/net/${wdev}/phy80211`)) != phy)
110 continue;
111
112 if (trim(readfile(`/sys/class/net/${wdev}/operstate`)) == "down")
113 config[wdev] = {};
114 }
115 }
116
117 function usage()
118 {
119 warn(`Usage: ${basename(sourcepath())} <phy> <command> [<arguments>]
120
121 Commands:
122 set_config <config> [<device]...] - set phy configuration
123 get_macaddr <id> - get phy MAC address for vif index <id>
124 `);
125 exit(1);
126 }
127
128 const commands = {
129 set_config: function(args) {
130 let statefile = `/var/run/wdev-${phy}.json`;
131
132 let new_config = shift(args);
133 for (let dev in ARGV)
134 keep_devices[dev] = true;
135
136 if (!new_config)
137 usage();
138
139 new_config = json(new_config);
140 if (!new_config) {
141 warn("Invalid configuration\n");
142 exit(1);
143 }
144
145 let old_config = readfile(statefile);
146 if (old_config)
147 old_config = json(old_config);
148
149 let config = vlist_new(iface_cb);
150 if (type(old_config) == "object")
151 config.data = old_config;
152
153 add_existing(phy, config.data);
154 add_ifname(config.data);
155 drop_inactive(config.data);
156
157 add_ifname(new_config);
158 config.update(new_config);
159
160 drop_inactive(config.data);
161 delete_ifname(config.data);
162 writefile(statefile, sprintf("%J", config.data));
163 },
164 get_macaddr: function(args) {
165 let data = {};
166
167 for (let arg in args) {
168 arg = split(arg, "=", 2);
169 data[arg[0]] = arg[1];
170 }
171
172 let macaddr = wdev_generate_macaddr(phy, data);
173 if (!macaddr) {
174 warn(`Could not get MAC address for phy ${phy}\n`);
175 exit(1);
176 }
177
178 print(macaddr + "\n");
179 },
180 };
181
182 let command = shift(ARGV);
183
184 if (!phy || !command | !commands[command])
185 usage();
186
187 if (!readfile(`/sys/class/ieee80211/${phy}/index`)) {
188 warn(`PHY ${phy} does not exist\n`);
189 exit(1);
190 }
191
192 commands[command](ARGV);