wdev.uc 5.0 KB

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