wdev.uc 4.1 KB

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