wireless-device.uc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. 'use strict';
  2. import * as ubus from "ubus";
  3. import * as uloop from "uloop";
  4. import { is_equal } from "./utils.uc";
  5. import { access } from "fs";
  6. const NOTIFY_CMD_UP = 0;
  7. const NOTIFY_CMD_SET_DATA = 1;
  8. const NOTIFY_CMD_PROCESS_ADD = 2;
  9. const NOTIFY_CMD_SET_RETRY = 4;
  10. const DEFAULT_RETRY = 3;
  11. const DEFAULT_SCRIPT_TIMEOUT = 30 * 1000;
  12. let wdev_cur;
  13. let wdev_handler = {};
  14. let wdev_script_task, wdev_script_timeout;
  15. let handler_timer;
  16. function wireless_config_done()
  17. {
  18. ubus.call({
  19. object: "wpa_supplicant",
  20. method: "mld_start",
  21. return: "ignore",
  22. data: { },
  23. });
  24. ubus.call({
  25. object: "service",
  26. method: "event",
  27. return: "ignore",
  28. data: {
  29. type: "netifd.wireless.done",
  30. data: {},
  31. },
  32. });
  33. }
  34. function delete_wdev(name)
  35. {
  36. delete netifd.wireless.devices[name];
  37. gc();
  38. }
  39. function handle_link(dev, data, up)
  40. {
  41. let config = data.config;
  42. let bridge_isolate;
  43. let ap = false;
  44. if (dev == data.ifname)
  45. ap = data.type == "vlan" ||
  46. (data.type == "vif" && config.mode == "ap");
  47. let dev_data = {
  48. external: 2,
  49. check_vlan: false,
  50. isolate: !!config.bridge_isolate,
  51. wireless: true,
  52. wireless_ap: ap,
  53. };
  54. if (ap && config.multicast_to_unicast != null)
  55. dev_data.multicast_to_unicast = config.multicast_to_unicast;
  56. if (data.type == "vif" && config.mode == "ap") {
  57. dev_data.wireless_proxyarp = !!config.proxy_arp;
  58. dev_data.wireless_isolate = !!config.isolate;
  59. }
  60. if (up)
  61. netifd.device_set(dev, dev_data);
  62. for (let net in config.network)
  63. netifd.interface_handle_link({
  64. name: net,
  65. ifname: dev,
  66. vlan: config.network_vlan,
  67. link_ext: true,
  68. up,
  69. });
  70. }
  71. function wdev_config_init(wdev)
  72. {
  73. let data = wdev.data;
  74. let config = data.config;
  75. let interfaces = {};
  76. let vif_idx = 0;
  77. for (let vif in data.vif) {
  78. let vlan_idx = 0, sta_idx = 0;
  79. let vlans = {}, stas = {};
  80. if (wdev.disabled_vifs[vif.name])
  81. continue;
  82. for (let vlan in vif.vlan) {
  83. let vlan_name = sprintf("%02d", ++vlan_idx);
  84. let cur_vlan = vlans[vlan_name] = {
  85. name: vlan.name,
  86. config: vlan.config,
  87. };
  88. if (wdev.disabled_vifs[vif.name])
  89. continue;
  90. for (let net in vlan.config.network)
  91. if (netifd.interface_get_bridge(net, cur_vlan))
  92. break;
  93. }
  94. for (let sta in vif.sta) {
  95. let sta_name = sprintf("%02d", ++sta_idx);
  96. stas[sta_name] = {
  97. name: sta.name,
  98. config: sta.config,
  99. };
  100. }
  101. let vif_name = sprintf("%02d", ++vif_idx);
  102. let iface = interfaces[vif_name] = {
  103. name: vif.name,
  104. config: vif.config,
  105. vlans, stas,
  106. };
  107. for (let net in vif.config.network)
  108. if (netifd.interface_get_bridge(net, iface))
  109. break;
  110. }
  111. wdev.handler_config = {
  112. config,
  113. interfaces,
  114. };
  115. let prev = wdev.handler_data;
  116. wdev.handler_data = {};
  117. if (prev && prev[wdev.name])
  118. wdev.handler_data[wdev.name] = prev[wdev.name];
  119. }
  120. function wdev_setup_cb(wdev)
  121. {
  122. if (wdev.state != "setup")
  123. return;
  124. if (wdev.retry > 0)
  125. wdev.retry--;
  126. else
  127. wdev.retry_setup_failed = true;
  128. wdev.teardown();
  129. }
  130. function wdev_teardown_cb(wdev)
  131. {
  132. for (let section, data in wdev.handler_data) {
  133. if (data.ifname)
  134. handle_link(data.ifname, data, false);
  135. }
  136. wdev.handler_data = {};
  137. wdev.state = "down";
  138. if (wdev.delete) {
  139. delete_wdev(wdev.data.name);
  140. return;
  141. }
  142. wdev.setup();
  143. }
  144. function run_handler_cb(wdev, cb)
  145. {
  146. if (wdev != wdev_cur.wdev)
  147. return;
  148. wdev.dbg("complete " + wdev_cur.op);
  149. if (wdev_script_timeout)
  150. wdev_script_timeout.cancel();
  151. wdev_script_timeout = null;
  152. wdev_script_task = null;
  153. wdev_cur = null;
  154. handler_timer.set(1);
  155. cb(wdev);
  156. }
  157. function run_handler_timeout(wdev, cb)
  158. {
  159. wdev_script_task.cancel();
  160. run_handler_cb(wdev, cb);
  161. }
  162. function handler_sort_fn(a, b)
  163. {
  164. return wdev_handler[a].time - wdev_handler[b].time
  165. }
  166. function __run_next_handler_name()
  167. {
  168. return sort(keys(wdev_handler), handler_sort_fn)[0];
  169. }
  170. function __run_next_handler()
  171. {
  172. let name = __run_next_handler_name();
  173. if (!name)
  174. return;
  175. wdev_cur = wdev_handler[name];
  176. delete wdev_handler[name];
  177. let wdev = wdev_cur.wdev;
  178. let op = wdev_cur.op;
  179. let cb = wdev_cur.cb;
  180. wdev.dbg("run " + op);
  181. wdev.handler_config.data = wdev.handler_data[wdev.name] ?? {};
  182. wdev_script_task = netifd.process({
  183. cb: () => run_handler_cb(wdev, cb),
  184. dir: netifd.wireless.path,
  185. argv: [ './' + wdev.script, wdev.data.config.type, op, wdev.name, "" + wdev.handler_config ],
  186. log_prefix: wdev.name,
  187. });
  188. if (!wdev_script_task)
  189. return run_handler_cb(wdev, cb);
  190. wdev_script_timeout = uloop.timer(DEFAULT_SCRIPT_TIMEOUT,
  191. () => run_handler_timeout(wdev, cb)
  192. );
  193. }
  194. function run_next_handler()
  195. {
  196. while (!wdev_cur && length(wdev_handler) > 0)
  197. __run_next_handler();
  198. if (!wdev_cur && !length(wdev_handler))
  199. wireless_config_done();
  200. }
  201. function run_handler(wdev, op, cb)
  202. {
  203. wdev.dbg("queue " + op);
  204. wdev_handler[wdev.name] = {
  205. op, wdev, cb,
  206. time: time()
  207. };
  208. run_next_handler();
  209. }
  210. function wdev_proc_reset(wdev)
  211. {
  212. if (wdev.proc_timer) {
  213. wdev.proc_timer.cancel();
  214. delete wdev.proc_timer;
  215. }
  216. wdev.procs = [];
  217. }
  218. function __wdev_proc_check(wdev, proc)
  219. {
  220. if (netifd.process_check(proc.pid, proc.exe))
  221. return;
  222. wdev.dbg(`process ${proc.exe}(${proc.pid}) no longer active`);
  223. wdev.teardown();
  224. return true;
  225. }
  226. function wdev_proc_check(wdev)
  227. {
  228. for (let proc in wdev.procs)
  229. if (__wdev_proc_check(wdev, proc))
  230. break;
  231. }
  232. function wdev_proc_add(wdev, data)
  233. {
  234. if (!data.pid || !data.exe)
  235. return;
  236. push(wdev.procs, data);
  237. if (!wdev.proc_timer)
  238. wdev.proc_timer = uloop.interval(1000, () => wdev_proc_check(wdev));
  239. }
  240. function setup()
  241. {
  242. if (this.state != "up" && this.state != "down")
  243. return;
  244. this.dbg("setup, state=" + this.state);
  245. if (!this.autostart || this.retry_setup_failed)
  246. return;
  247. wdev_proc_reset(this);
  248. delete this.config_change;
  249. this.state = "setup";
  250. run_handler(this, "setup", wdev_setup_cb);
  251. }
  252. function teardown()
  253. {
  254. delete this.cancel_setup;
  255. this.dbg("teardown, state=" + this.state);
  256. if (this.state == "teardown" || this.state == "down")
  257. return;
  258. wdev_proc_reset(this);
  259. this.state = "teardown";
  260. run_handler(this, "teardown", wdev_teardown_cb);
  261. }
  262. function wdev_update_disabled_vifs(wdev)
  263. {
  264. let cache = wdev.ifindex_cache;
  265. let prev_disabled = wdev.disabled_vifs;
  266. let disabled = wdev.disabled_vifs = {};
  267. let changed;
  268. let vifs = [];
  269. for (let vif in wdev.data.vif)
  270. push(vifs, vif, ...vif.vlan);
  271. for (let vif in vifs) {
  272. let enabled, ifindex;
  273. for (let net in vif.config.network) {
  274. let state = netifd.interface_get_enabled(net);
  275. if (!state)
  276. continue;
  277. if (state.enabled)
  278. enabled = true;
  279. else if (enabled == null)
  280. enabled = false;
  281. if (state.ifindex)
  282. ifindex = state.ifindex;
  283. }
  284. let name = vif.name;
  285. if (enabled == false)
  286. disabled[wdev] = true;
  287. else if (ifindex != cache[name])
  288. changed = true;
  289. if (ifindex)
  290. cache[name] = ifindex;
  291. else
  292. delete cache[name];
  293. }
  294. if (changed || !is_equal(prev_disabled, disabled))
  295. wdev.config_change = true;
  296. return wdev.config_change;
  297. }
  298. function wdev_reset(wdev)
  299. {
  300. wdev.retry = DEFAULT_RETRY;
  301. delete wdev.retry_setup_failed;
  302. }
  303. function update(data)
  304. {
  305. if (is_equal(this.data, data))
  306. return;
  307. if (data) {
  308. this.data = data;
  309. this.ifindex_cache = {};
  310. delete this.retry_setup_failed;
  311. delete this.delete;
  312. }
  313. wdev_reset(this);
  314. this.config_change = true;
  315. this.check();
  316. }
  317. function start()
  318. {
  319. if (this.delete)
  320. return;
  321. this.dbg("start, state=" + this.state);
  322. this.autostart = true;
  323. wdev_reset(this);
  324. if (this.state != "down")
  325. return;
  326. if (wdev_update_disabled_vifs(this))
  327. wdev_config_init(this);
  328. this.setup();
  329. }
  330. function retry_setup()
  331. {
  332. if (this.delete)
  333. return;
  334. if (this.state != "down" || !this.autostart)
  335. return;
  336. this.start();
  337. }
  338. function stop()
  339. {
  340. this.dbg("stop, state=" + this.state);
  341. this.autostart = false;
  342. switch (this.state) {
  343. case "setup":
  344. this.cancel_setup = true;
  345. break;
  346. case "up":
  347. this.teardown();
  348. break;
  349. }
  350. }
  351. function check()
  352. {
  353. if (!wdev_update_disabled_vifs(this))
  354. return;
  355. wdev_config_init(this);
  356. this.setup();
  357. }
  358. function wdev_mark_up(wdev)
  359. {
  360. wdev.dbg("mark up, state=" + wdev.state);
  361. if (wdev.state != "setup")
  362. return;
  363. if (wdev.config_change) {
  364. wdev.setup();
  365. return;
  366. }
  367. for (let section, data in wdev.handler_data) {
  368. if (data.ifname)
  369. handle_link(data.ifname, data, true);
  370. }
  371. wdev.state = "up";
  372. return 0;
  373. }
  374. function wdev_set_data(wdev, vif, vlan, data)
  375. {
  376. let config = wdev.handler_config;
  377. let cur = wdev;
  378. let cur_type = "device";
  379. if (!config)
  380. return ubus.STATUS_INVALID_ARGUMENT;
  381. if (vif) {
  382. cur = vif = config.interfaces[vif];
  383. if (!vif)
  384. return ubus.STATUS_NOT_FOUND;
  385. cur_type = "vif";
  386. }
  387. if (vlan) {
  388. if (!vif)
  389. return ubus.STATUS_INVALID_ARGUMENT;
  390. cur = vlan = vif.vlans[vlan];
  391. if (!vlan)
  392. return ubus.STATUS_NOT_FOUND;
  393. cur_type = "vlan";
  394. }
  395. let key = cur.name;
  396. if (cur_type == "vlan")
  397. key = vif.name + "/" + vlan.name;
  398. wdev.handler_data[key] = {
  399. ...cur,
  400. ...data,
  401. type: cur_type,
  402. config: cur.config,
  403. };
  404. return 0;
  405. }
  406. function notify(req)
  407. {
  408. let vif = req.args.interface;
  409. let vlan = req.args.vlan;
  410. let data = req.args.data;
  411. switch (req.args.command) {
  412. case NOTIFY_CMD_UP:
  413. if (vif || vlan || this.state != "setup")
  414. return ubus.STATUS_INVALID_ARGUMENT;
  415. return wdev_mark_up(this);
  416. case NOTIFY_CMD_SET_DATA:
  417. return wdev_set_data(this, vif, vlan, data);
  418. case NOTIFY_CMD_PROCESS_ADD:
  419. if (this.state != "setup" && this.state != "up")
  420. return 0;
  421. wdev_proc_add(this, data);
  422. return 0;
  423. case NOTIFY_CMD_SET_RETRY:
  424. if (data.retry != null)
  425. this.retry = data.retry;
  426. else
  427. this.retry = DEFAULT_RETRY;
  428. return 0;
  429. default:
  430. return ubus.STATUS_INVALID_ARGUMENT;
  431. }
  432. }
  433. function hotplug(name, add)
  434. {
  435. let dev = name;
  436. let m = match(name, /(.+)\.sta.+/);
  437. if (m)
  438. name = m[1];
  439. for (let section, data in this.handler_data) {
  440. if (data.ifname != name ||
  441. data.type != "vif" && data.type != "vlan")
  442. continue;
  443. handle_link(dev, data, add);
  444. }
  445. }
  446. function get_status_data(wdev, vif, parent_vif)
  447. {
  448. let key = vif.name;
  449. if (parent_vif)
  450. key = parent_vif.name + "/" + vif.name;
  451. let hdata = wdev.handler_data[key];
  452. let data = {
  453. section: vif.name,
  454. config: vif.config
  455. };
  456. if (hdata && hdata.ifname)
  457. data.ifname = hdata.ifname;
  458. return data;
  459. }
  460. function get_status_vlans(wdev, vif)
  461. {
  462. let vlans = [];
  463. for (let vlan in vif.vlan)
  464. push(vlans, get_status_data(wdev, vlan, vif));
  465. return vlans;
  466. }
  467. function get_status_stations(wdev, vif)
  468. {
  469. let vlans = [];
  470. for (let vlan in vif.sta)
  471. push(vlans, get_status_data(wdev, vlan));
  472. return vlans;
  473. }
  474. function status()
  475. {
  476. let interfaces = [];
  477. for (let vif in this.data.vif) {
  478. let vlans = get_status_vlans(this, vif);
  479. let stations = get_status_stations(this, vif);
  480. let data = get_status_data(this, vif);
  481. push(interfaces, {
  482. ...data,
  483. vlans, stations
  484. });
  485. }
  486. return {
  487. up: this.state == "up",
  488. pending: this.state == "setup" || this.state == "teardown",
  489. autostart: this.autostart,
  490. disabled: !!this.data.config.disabled,
  491. retry_setup_failed: !!this.retry_setup_failed,
  492. config: this.data.config,
  493. interfaces
  494. };
  495. }
  496. function destroy()
  497. {
  498. this.dbg("destroy");
  499. this.autostart = false;
  500. this.delete = true;
  501. if (this.state != "down") {
  502. this.stop();
  503. return;
  504. }
  505. delete_wdev(this.data.name);
  506. }
  507. function dbg(msg)
  508. {
  509. netifd.log(netifd.L_DEBUG, `wireless: ${this.name}: ${msg}\n`);
  510. }
  511. const wdev_proto = {
  512. update,
  513. destroy,
  514. retry_setup,
  515. start,
  516. stop,
  517. setup,
  518. status,
  519. teardown,
  520. check,
  521. notify,
  522. hotplug,
  523. dbg,
  524. };
  525. export function new(data, script, driver)
  526. {
  527. let wdev = {
  528. name: data.name,
  529. script, data,
  530. procs: [],
  531. vifs: {},
  532. disabled_vifs: {},
  533. ifindex_cache: {},
  534. autostart: true,
  535. state: "down",
  536. };
  537. wdev_update_disabled_vifs(wdev);
  538. wdev_config_init(wdev);
  539. handler_timer = uloop.timer(1, run_next_handler);
  540. return proto(wdev, wdev_proto);
  541. };