wdev.uc 4.1 KB

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