wdev.uc 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. #!/usr/bin/env ucode
  2. 'use strict';
  3. import { vlist_new, is_equal, 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_name = shift(ARGV);
  8. let command = shift(ARGV);
  9. let phy, 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. phydev.wdev_add(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 [ "basic-rates", "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(phydev, config)
  77. {
  78. phydev.for_each_wdev((wdev) => {
  79. if (config[wdev])
  80. return;
  81. if (trim(readfile(`/sys/class/net/${wdev}/operstate`)) == "down")
  82. config[wdev] = {};
  83. });
  84. }
  85. function usage()
  86. {
  87. warn(`Usage: ${basename(sourcepath())} <phy> <command> [<arguments>]
  88. Commands:
  89. set_config <config> [<device]...] - set phy configuration
  90. get_macaddr <id> - get phy MAC address for vif index <id>
  91. `);
  92. exit(1);
  93. }
  94. const commands = {
  95. set_config: function(args) {
  96. let statefile = `/var/run/wdev-${phy_name}.json`;
  97. let new_config = shift(args);
  98. for (let dev in ARGV)
  99. keep_devices[dev] = true;
  100. if (!new_config)
  101. usage();
  102. new_config = json(new_config);
  103. if (!new_config) {
  104. warn("Invalid configuration\n");
  105. exit(1);
  106. }
  107. let old_config = readfile(statefile);
  108. if (old_config)
  109. old_config = json(old_config);
  110. let config = vlist_new(iface_cb);
  111. if (type(old_config) == "object")
  112. config.data = old_config;
  113. add_existing(phydev, config.data);
  114. add_ifname(config.data);
  115. drop_inactive(config.data);
  116. let ubus = libubus.connect();
  117. let data = ubus.call("hostapd", "config_get_macaddr_list", { phy: phydev.name, radio: phydev.radio ?? -1 });
  118. let macaddr_list = [];
  119. if (type(data) == "object" && data.macaddr)
  120. macaddr_list = data.macaddr;
  121. ubus.disconnect();
  122. phydev.macaddr_init(macaddr_list);
  123. add_ifname(new_config);
  124. config.update(new_config);
  125. drop_inactive(config.data);
  126. delete_ifname(config.data);
  127. writefile(statefile, sprintf("%J", config.data));
  128. },
  129. get_macaddr: function(args) {
  130. let data = {};
  131. for (let arg in args) {
  132. arg = split(arg, "=", 2);
  133. data[arg[0]] = arg[1];
  134. }
  135. let macaddr = phydev.macaddr_generate(data);
  136. if (!macaddr) {
  137. warn(`Could not get MAC address for phy ${phy_name}\n`);
  138. exit(1);
  139. }
  140. print(macaddr + "\n");
  141. },
  142. };
  143. if (!phy_name || !command | !commands[command])
  144. usage();
  145. let phy_split = split(phy_name, ":");
  146. phydev = phy_open(phy_split[0], phy_split[1]);
  147. phy = phydev.phy;
  148. if (!phydev) {
  149. warn(`PHY ${phy_name} does not exist\n`);
  150. exit(1);
  151. }
  152. commands[command](ARGV);