blob: c70b0b3afe9d3e5bfff4a36c8cdcf040c6cb0116 [file] [log] [blame]
developere92ee3c2023-10-25 17:01:28 +08001let libubus = require("ubus");
2import { open, readfile } from "fs";
developer70180b02023-11-14 17:01:47 +08003import { wdev_create, wdev_set_mesh_params, wdev_remove, is_equal, wdev_set_up, vlist_new, phy_open } from "common";
developere92ee3c2023-10-25 17:01:28 +08004
5let ubus = libubus.connect();
6
7wpas.data.config = {};
8wpas.data.iface_phy = {};
9wpas.data.macaddr_list = {};
10
11function iface_stop(iface)
12{
13 let ifname = iface.config.iface;
14
15 if (!iface.running)
16 return;
17
18 delete wpas.data.iface_phy[ifname];
19 wpas.remove_iface(ifname);
20 wdev_remove(ifname);
21 iface.running = false;
22}
23
24function iface_start(phydev, iface, macaddr_list)
25{
26 let phy = phydev.name;
27
28 if (iface.running)
29 return;
30
31 let ifname = iface.config.iface;
32 let wdev_config = {};
33 for (let field in iface.config)
34 wdev_config[field] = iface.config[field];
35 if (!wdev_config.macaddr)
36 wdev_config.macaddr = phydev.macaddr_next();
37
38 wpas.data.iface_phy[ifname] = phy;
39 wdev_remove(ifname);
developer66e89bc2024-04-23 14:50:01 +080040 let ret = wdev_create("phy0", ifname, wdev_config);
developere92ee3c2023-10-25 17:01:28 +080041 if (ret)
42 wpas.printf(`Failed to create device ${ifname}: ${ret}`);
developer70180b02023-11-14 17:01:47 +080043 wdev_set_up(ifname, true);
developere92ee3c2023-10-25 17:01:28 +080044 wpas.add_iface(iface.config);
45 iface.running = true;
46}
47
48function iface_cb(new_if, old_if)
49{
50 if (old_if && new_if && is_equal(old_if.config, new_if.config)) {
51 new_if.running = old_if.running;
52 return;
53 }
54
55 if (new_if && old_if)
56 wpas.printf(`Update configuration for interface ${old_if.config.iface}`);
57 else if (old_if)
58 wpas.printf(`Remove interface ${old_if.config.iface}`);
59
60 if (old_if)
61 iface_stop(old_if);
62}
63
64function prepare_config(config)
65{
66 config.config_data = readfile(config.config);
67
68 return { config: config };
69}
70
developerd0c89452024-10-11 16:53:27 +080071function set_config(phy_name, num_global_macaddr, config_list)
developere92ee3c2023-10-25 17:01:28 +080072{
73 let phy = wpas.data.config[phy_name];
74
75 if (!phy) {
76 phy = vlist_new(iface_cb, false);
77 wpas.data.config[phy_name] = phy;
78 }
79
developerd0c89452024-10-11 16:53:27 +080080 phy.num_global_macaddr = num_global_macaddr;
81
developere92ee3c2023-10-25 17:01:28 +080082 let values = [];
83 for (let config in config_list)
84 push(values, [ config.iface, prepare_config(config) ]);
85
86 phy.update(values);
87}
88
89function start_pending(phy_name)
90{
91 let phy = wpas.data.config[phy_name];
92 let ubus = wpas.data.ubus;
93
94 if (!phy || !phy.data)
95 return;
96
97 let phydev = phy_open(phy_name);
98 if (!phydev) {
99 wpas.printf(`Could not open phy ${phy_name}`);
100 return;
101 }
102
103 let macaddr_list = wpas.data.macaddr_list[phy_name];
developerd0c89452024-10-11 16:53:27 +0800104 phydev.macaddr_init(macaddr_list, { num_global: phy.num_global_macaddr });
developere92ee3c2023-10-25 17:01:28 +0800105
106 for (let ifname in phy.data)
107 iface_start(phydev, phy.data[ifname]);
108}
109
110let main_obj = {
111 phy_set_state: {
112 args: {
113 phy: "",
114 stop: true,
115 },
116 call: function(req) {
117 if (!req.args.phy || req.args.stop == null)
118 return libubus.STATUS_INVALID_ARGUMENT;
119
120 let phy = wpas.data.config[req.args.phy];
121 if (!phy)
122 return libubus.STATUS_NOT_FOUND;
123
124 try {
125 if (req.args.stop) {
126 for (let ifname in phy.data)
127 iface_stop(phy.data[ifname]);
128 } else {
129 start_pending(req.args.phy);
130 }
131 } catch (e) {
132 wpas.printf(`Error chaging state: ${e}\n${e.stacktrace[0].context}`);
133 return libubus.STATUS_INVALID_ARGUMENT;
134 }
135 return 0;
136 }
137 },
138 phy_set_macaddr_list: {
139 args: {
140 phy: "",
141 macaddr: [],
142 },
143 call: function(req) {
144 let phy = req.args.phy;
145 if (!phy)
146 return libubus.STATUS_INVALID_ARGUMENT;
147
148 wpas.data.macaddr_list[phy] = req.args.macaddr;
149 return 0;
150 }
151 },
152 phy_status: {
153 args: {
154 phy: ""
155 },
156 call: function(req) {
157 if (!req.args.phy)
158 return libubus.STATUS_INVALID_ARGUMENT;
159
160 let phy = wpas.data.config[req.args.phy];
161 if (!phy)
162 return libubus.STATUS_NOT_FOUND;
163
164 for (let ifname in phy.data) {
165 try {
166 let iface = wpas.interfaces[ifname];
167 if (!iface)
168 continue;
169
170 let status = iface.status();
171 if (!status)
172 continue;
173
174 if (status.state == "INTERFACE_DISABLED")
175 continue;
176
177 status.ifname = ifname;
178 return status;
179 } catch (e) {
180 continue;
181 }
182 }
183
184 return libubus.STATUS_NOT_FOUND;
185 }
186 },
187 config_set: {
188 args: {
189 phy: "",
developerd0c89452024-10-11 16:53:27 +0800190 num_global_macaddr: 0,
developere92ee3c2023-10-25 17:01:28 +0800191 config: [],
192 defer: true,
193 },
194 call: function(req) {
195 if (!req.args.phy)
196 return libubus.STATUS_INVALID_ARGUMENT;
197
198 wpas.printf(`Set new config for phy ${req.args.phy}`);
199 try {
200 if (req.args.config)
developerd0c89452024-10-11 16:53:27 +0800201 set_config(req.args.phy, req.args.num_global_macaddr, req.args.config);
developere92ee3c2023-10-25 17:01:28 +0800202
203 if (!req.args.defer)
204 start_pending(req.args.phy);
205 } catch (e) {
206 wpas.printf(`Error loading config: ${e}\n${e.stacktrace[0].context}`);
207 return libubus.STATUS_INVALID_ARGUMENT;
208 }
209
210 return {
211 pid: wpas.getpid()
212 };
213 }
214 },
215 config_add: {
216 args: {
217 driver: "",
218 iface: "",
219 bridge: "",
220 hostapd_ctrl: "",
221 ctrl: "",
222 config: "",
223 },
224 call: function(req) {
225 if (!req.args.iface || !req.args.config)
226 return libubus.STATUS_INVALID_ARGUMENT;
227
228 if (wpas.add_iface(req.args) < 0)
229 return libubus.STATUS_INVALID_ARGUMENT;
230
231 return {
232 pid: wpas.getpid()
233 };
234 }
235 },
236 config_remove: {
237 args: {
238 iface: ""
239 },
240 call: function(req) {
241 if (!req.args.iface)
242 return libubus.STATUS_INVALID_ARGUMENT;
243
244 wpas.remove_iface(req.args.iface);
245 return 0;
246 }
247 },
248};
249
250wpas.data.ubus = ubus;
251wpas.data.obj = ubus.publish("wpa_supplicant", main_obj);
developerab5e7752023-12-21 16:18:59 +0800252wpas.udebug_set("wpa_supplicant", wpas.data.ubus);
developere92ee3c2023-10-25 17:01:28 +0800253
254function iface_event(type, name, data) {
255 let ubus = wpas.data.ubus;
256
257 data ??= {};
258 data.name = name;
259 wpas.data.obj.notify(`iface.${type}`, data, null, null, null, -1);
260 ubus.call("service", "event", { type: `wpa_supplicant.${name}.${type}`, data: {} });
261}
262
developer66e89bc2024-04-23 14:50:01 +0800263function iface_hostapd_notify(phy, ifname, iface, state, link_id)
developere92ee3c2023-10-25 17:01:28 +0800264{
265 let ubus = wpas.data.ubus;
developere92ee3c2023-10-25 17:01:28 +0800266 let msg = { phy: phy };
267
developerab5e7752023-12-21 16:18:59 +0800268 wpas.printf(`ucode: mtk: wpa_s in state ${state} notifies hostapd`);
developere92ee3c2023-10-25 17:01:28 +0800269 switch (state) {
270 case "DISCONNECTED":
271 case "AUTHENTICATING":
272 case "SCANNING":
273 msg.up = false;
274 break;
275 case "INTERFACE_DISABLED":
276 case "INACTIVE":
277 msg.up = true;
278 break;
279 case "COMPLETED":
developer66e89bc2024-04-23 14:50:01 +0800280 let status = iface.status(link_id);
developere92ee3c2023-10-25 17:01:28 +0800281 msg.up = true;
282 msg.frequency = status.frequency;
283 msg.sec_chan_offset = status.sec_chan_offset;
developerab5e7752023-12-21 16:18:59 +0800284 msg.ch_width = status.ch_width;
285 msg.bw320_offset = status.bw320_offset;
developer66e89bc2024-04-23 14:50:01 +0800286 msg.band_idx = status.band_idx;
developerd0c89452024-10-11 16:53:27 +0800287 msg.punct_bitmap = status.punct_bitmap;
developere92ee3c2023-10-25 17:01:28 +0800288 break;
289 default:
290 return;
291 }
292
293 ubus.call("hostapd", "apsta_state", msg);
294}
295
296function iface_channel_switch(phy, ifname, iface, info)
297{
298 let msg = {
299 phy: phy,
300 up: true,
301 csa: true,
302 csa_count: info.csa_count ? info.csa_count - 1 : 0,
303 frequency: info.frequency,
developerab5e7752023-12-21 16:18:59 +0800304 ch_width: info.ch_width,
305 bw320_offset: info.bw320_offset,
developera20cdc22024-05-31 18:57:31 +0800306 band_idx: info.band_idx,
developere92ee3c2023-10-25 17:01:28 +0800307 sec_chan_offset: info.sec_chan_offset,
developer05f3b2b2024-08-19 19:17:34 +0800308 punct_bitmap: info.punct_bitmap,
developere92ee3c2023-10-25 17:01:28 +0800309 };
310 ubus.call("hostapd", "apsta_state", msg);
311}
312
313return {
314 shutdown: function() {
315 for (let phy in wpas.data.config)
316 set_config(phy, []);
317 wpas.ubus.disconnect();
318 },
319 iface_add: function(name, obj) {
320 iface_event("add", name);
321 },
322 iface_remove: function(name, obj) {
323 iface_event("remove", name);
324 },
325 state: function(ifname, iface, state) {
326 let phy = wpas.data.iface_phy[ifname];
developer66e89bc2024-04-23 14:50:01 +0800327 let ret = iface.get_valid_links();
328 let link_id = 0, valid_links = ret.valid_links;
developere92ee3c2023-10-25 17:01:28 +0800329 if (!phy) {
330 wpas.printf(`no PHY for ifname ${ifname}`);
331 return;
332 }
333
developer66e89bc2024-04-23 14:50:01 +0800334 if (valid_links) {
335 while (valid_links) {
336 if (valid_links & 1)
337 iface_hostapd_notify(phy, ifname, iface, state, link_id);
338
339 link_id++;
340 valid_links >>= 1;
341 }
342 } else {
343 iface_hostapd_notify(phy, ifname, iface, state, -1);
344 }
developer70180b02023-11-14 17:01:47 +0800345
346 if (state != "COMPLETED")
347 return;
348
349 let phy_data = wpas.data.config[phy];
350 if (!phy_data)
351 return;
352
353 let iface_data = phy_data.data[ifname];
354 if (!iface_data)
355 return;
356
357 let wdev_config = iface_data.config;
358 if (!wdev_config || wdev_config.mode != "mesh")
359 return;
360
361 wdev_set_mesh_params(ifname, wdev_config);
developere92ee3c2023-10-25 17:01:28 +0800362 },
363 event: function(ifname, iface, ev, info) {
364 let phy = wpas.data.iface_phy[ifname];
365 if (!phy) {
366 wpas.printf(`no PHY for ifname ${ifname}`);
367 return;
368 }
369
developera20cdc22024-05-31 18:57:31 +0800370 if (ev == "CH_SWITCH_STARTED" || ev == "LINK_CH_SWITCH_STARTED")
developere92ee3c2023-10-25 17:01:28 +0800371 iface_channel_switch(phy, ifname, iface, info);
372 }
373};