blob: 22cb130e73a08953b80d206eed89d5b28e7185e7 [file] [log] [blame]
developer2a209692023-08-14 20:23:42 +08001let libubus = require("ubus");
2import { open, readfile } from "fs";
3import { wdev_create, wdev_remove, is_equal, vlist_new } from "common";
4
5let ubus = libubus.connect();
6
7wpas.data.config = {};
8
9function iface_stop(iface)
10{
11 let ifname = iface.config.iface;
12
13 wpas.remove_iface(ifname);
14 wdev_remove(ifname);
15 iface.running = false;
16}
17
18function iface_start(phy, iface)
19{
20 if (iface.running)
21 return;
22
23 let ifname = iface.config.iface;
24
25 wdev_remove(ifname);
26 let ret = wdev_create(phy, ifname, iface.config);
27 if (ret)
28 wpas.printf(`Failed to create device ${ifname}: ${ret}`);
29 wpas.add_iface(iface.config);
30 iface.running = true;
31}
32
33function iface_cb(new_if, old_if)
34{
35 if (old_if && new_if && is_equal(old_if.config, new_if.config)) {
36 new_if.running = old_if.running;
37 return;
38 }
39
40 if (old_if && old_if.running)
41 iface_stop(old_if);
42}
43
44function prepare_config(config)
45{
46 config.config_data = readfile(config.config);
47
48 return { config: config };
49}
50
51function set_config(phy_name, config_list)
52{
53 let phy = wpas.data.config[phy_name];
54
55 if (!phy) {
56 phy = vlist_new(iface_cb, false);
57 wpas.data.config[phy_name] = phy;
58 }
59
60 let values = [];
61 for (let config in config_list)
62 push(values, [ config.iface, prepare_config(config) ]);
63
64 phy.update(values);
65}
66
67function start_pending(phy_name)
68{
69 let phy = wpas.data.config[phy_name];
70
71 for (let ifname in phy.data)
72 iface_start(phy_name, phy.data[ifname]);
73}
74
75let main_obj = {
76 config_set: {
77 args: {
78 phy: "",
79 config: [],
80 defer: true,
81 },
82 call: function(req) {
83 if (!req.args.phy)
84 return libubus.STATUS_INVALID_ARGUMENT;
85
86 try {
87 if (req.args.config)
88 set_config(req.args.phy, req.args.config);
89
90 if (!req.args.defer)
91 start_pending(req.args.phy);
92 } catch (e) {
93 wpas.printf(`Error loading config: ${e}\n${e.stacktrace[0].context}`);
94 return libubus.STATUS_INVALID_ARGUMENT;
95 }
96
97 return {
98 pid: wpas.getpid()
99 };
100 }
101 },
102 config_add: {
103 args: {
104 driver: "",
105 iface: "",
106 bridge: "",
107 hostapd_ctrl: "",
108 ctrl: "",
109 config: "",
110 },
111 call: function(req) {
112 if (!req.args.iface || !req.args.config)
113 return libubus.STATUS_INVALID_ARGUMENT;
114
115 if (wpas.add_iface(req.args) < 0)
116 return libubus.STATUS_INVALID_ARGUMENT;
117
118 return {
119 pid: wpas.getpid()
120 };
121 }
122 },
123 config_remove: {
124 args: {
125 iface: ""
126 },
127 call: function(req) {
128 if (!req.args.iface)
129 return libubus.STATUS_INVALID_ARGUMENT;
130
131 wpas.remove_iface(req.args.iface);
132 return 0;
133 }
134 },
135};
136
137wpas.data.ubus = ubus;
138wpas.data.obj = ubus.publish("wpa_supplicant", main_obj);
139
140function iface_event(type, name, data) {
141 let ubus = wpas.data.ubus;
142
143 data ??= {};
144 data.name = name;
145 wpas.data.obj.notify(`iface.${type}`, data, null, null, null, -1);
146 ubus.call("service", "event", { type: `wpa_supplicant.${name}.${type}`, data: {} });
147}
148
149return {
150 shutdown: function() {
151 for (let phy in wpas.data.config)
152 set_config(phy, []);
153 wpas.ubus.disconnect();
154 },
155 iface_add: function(name, obj) {
156 iface_event("add", name);
157 },
158 iface_remove: function(name, obj) {
159 iface_event("remove", name);
160 }
161};