blob: 9ece3b1af2ea1b545a8cf07031770e96d75887be [file] [log] [blame]
developerf0fd7052023-08-14 20:23:42 +08001import * as nl80211 from "nl80211";
2import * as rtnl from "rtnl";
3import { readfile } from "fs";
4
5const iftypes = {
6 ap: nl80211.const.NL80211_IFTYPE_AP,
7 mesh: nl80211.const.NL80211_IFTYPE_MESH_POINT,
8 sta: nl80211.const.NL80211_IFTYPE_STATION,
9 adhoc: nl80211.const.NL80211_IFTYPE_ADHOC,
10 monitor: nl80211.const.NL80211_IFTYPE_MONITOR,
11};
12
13function wdev_remove(name)
14{
15 nl80211.request(nl80211.const.NL80211_CMD_DEL_INTERFACE, 0, { dev: name });
16}
17
18function __phy_is_fullmac(phyidx)
19{
20 let data = nl80211.request(nl80211.const.NL80211_CMD_GET_WIPHY, 0, { wiphy: phyidx });
21
22 return !data.software_iftypes.ap_vlan;
23}
24
25function phy_is_fullmac(phy)
26{
27 let phyidx = int(trim(readfile(`/sys/class/ieee80211/${phy}/index`)));
28
29 return __phy_is_fullmac(phyidx);
30}
31
32function find_reusable_wdev(phyidx)
33{
34 if (!__phy_is_fullmac(phyidx))
35 return null;
36
37 let data = nl80211.request(
38 nl80211.const.NL80211_CMD_GET_INTERFACE,
39 nl80211.const.NLM_F_DUMP,
40 { wiphy: phyidx });
41 for (let res in data)
42 if (trim(readfile(`/sys/class/net/${res.ifname}/operstate`)) == "down")
43 return res.ifname;
44 return null;
45}
46
47function wdev_create(phy, name, data)
48{
49 let phyidx = int(readfile(`/sys/class/ieee80211/${phy}/index`));
50
51 wdev_remove(name);
52
53 if (!iftypes[data.mode])
54 return `Invalid mode: ${data.mode}`;
55
56 let req = {
57 wiphy: phyidx,
58 ifname: name,
59 iftype: iftypes[data.mode],
60 };
61
62 if (data["4addr"])
63 req["4addr"] = data["4addr"];
64 if (data.macaddr)
65 req.mac = data.macaddr;
66
67 nl80211.error();
68
69 let reuse_ifname = find_reusable_wdev(phyidx);
70 if (reuse_ifname &&
71 (reuse_ifname == name ||
72 rtnl.request(rtnl.const.RTM_SETLINK, 0, { dev: reuse_ifname, ifname: name}) != false))
73 nl80211.request(
74 nl80211.const.NL80211_CMD_SET_INTERFACE, 0, {
75 wiphy: phyidx,
76 dev: name,
77 iftype: iftypes[data.mode],
78 });
79 else
80 nl80211.request(
81 nl80211.const.NL80211_CMD_NEW_INTERFACE,
82 nl80211.const.NLM_F_CREATE,
83 req);
84
85 let error = nl80211.error();
86 if (error)
87 return error;
88
89 if (data.powersave != null) {
90 nl80211.request(nl80211.const.NL80211_CMD_SET_POWER_SAVE, 0,
91 { dev: name, ps_state: data.powersave ? 1 : 0});
92 }
93
94 return null;
95}
96
97const vlist_proto = {
98 update: function(values, arg) {
99 let data = this.data;
100 let cb = this.cb;
101 let seq = { };
102 let new_data = {};
103 let old_data = {};
104
105 this.data = new_data;
106
107 if (type(values) == "object") {
108 for (let key in values) {
109 old_data[key] = data[key];
110 new_data[key] = values[key];
111 delete data[key];
112 }
113 } else {
114 for (let val in values) {
115 let cur_key = val[0];
116 let cur_obj = val[1];
117
118 old_data[cur_key] = data[cur_key];
119 new_data[cur_key] = val[1];
120 delete data[cur_key];
121 }
122 }
123
124 for (let key in data) {
125 cb(null, data[key], arg);
126 delete data[key];
127 }
128 for (let key in new_data)
129 cb(new_data[key], old_data[key], arg);
130 }
131};
132
133function is_equal(val1, val2) {
134 let t1 = type(val1);
135
136 if (t1 != type(val2))
137 return false;
138
139 if (t1 == "array") {
140 if (length(val1) != length(val2))
141 return false;
142
143 for (let i = 0; i < length(val1); i++)
144 if (!is_equal(val1[i], val2[i]))
145 return false;
146
147 return true;
148 } else if (t1 == "object") {
149 for (let key in val1)
150 if (!is_equal(val1[key], val2[key]))
151 return false;
152 for (let key in val2)
153 if (!val1[key])
154 return false;
155 return true;
156 } else {
157 return val1 == val2;
158 }
159}
160
161function vlist_new(cb) {
162 return proto({
163 cb: cb,
164 data: {}
165 }, vlist_proto);
166}
167
168export { wdev_remove, wdev_create, is_equal, vlist_new, phy_is_fullmac };