1 'use strict'; 2 3 import * as libubus from "ubus"; 4 import { realpath } from "fs"; 5 import { 6 handler_load, handler_attributes, 7 parse_attribute_list, parse_bool, parse_array, 8 TYPE_ARRAY, TYPE_STRING, TYPE_INT, TYPE_BOOL 9 } from "./utils.uc"; 10 import * as wdev from "./wireless-device.uc"; 11 12 let ubus = netifd.ubus; 13 let wireless = netifd.wireless = { 14 handlers: {}, 15 devices: {}, 16 path: realpath(netifd.main_path + "/wireless"), 17 }; 18 19 function update_config(new_devices) 20 { 21 for (let name, dev in wireless.devices) 22 if (!new_devices[name]) 23 dev.destroy(); 24 25 for (let name, dev in new_devices) { 26 let cur_dev = wireless.devices[name]; 27 if (cur_dev) { 28 cur_dev.update(dev); 29 continue; 30 } 31 32 let handler = wireless.handlers[dev.config.type]; 33 cur_dev = wdev.new(dev, handler.script); 34 if (!cur_dev) 35 continue; 36 37 wireless.devices[name] = cur_dev; 38 } 39 } 40 41 function config_init(uci) 42 { 43 let config = uci.get_all("wireless"); 44 45 let handlers = {}; 46 let devices = {}; 47 let vifs = {}; 48 let mlo_device; 49 50 let sections = { 51 device: {}, 52 iface: {}, 53 vlan: {}, 54 station: {}, 55 }; 56 let radio_idx = {}; 57 58 for (let name, data in config) { 59 let type = data[".type"]; 60 if (parse_bool(data.disabled) && type != "wifi-device") 61 continue; 62 63 if (substr(type, 0, 5) != "wifi-") 64 continue; 65 66 let list = sections[substr(type, 5)]; 67 if (list) 68 list[name] = data; 69 70 if (type == "wifi-iface" && parse_bool(data.mlo)) 71 mlo_device = true; 72 } 73 74 if (mlo_device) { 75 devices[wdev.mlo_name] = { 76 name: wdev.mlo_name, 77 config: { 78 type: "mac80211", 79 }, 80 vif: [], 81 }; 82 handlers[wdev.mlo_name] = wireless.handlers.mac80211; 83 } 84 85 for (let name, data in sections.device) { 86 if (!data.type) 87 continue; 88 89 let handler = wireless.handlers[data.type]; 90 if (!handler) 91 continue; 92 93 if (data.radio != null) 94 radio_idx[name] = +data.radio; 95 96 let config = parse_attribute_list(data, handler.device); 97 devices[name] = { 98 name, 99 config, 100 101 vif: [], 102 }; 103 handlers[name] = handler; 104 } 105 106 for (let name, data in sections.iface) { 107 let dev_names = parse_array(data.device); 108 let mlo_vif = parse_bool(data.mlo); 109 let radios = map(dev_names, (v) => radio_idx[v]); 110 radios = filter(radios, (v) => v != null); 111 let radio_config = map(dev_names, (v) => devices[v].config); 112 if (mlo_vif) 113 dev_names = [ wdev.mlo_name, ...dev_names ]; 114 for (let dev_name in dev_names) { 115 let dev = devices[dev_name]; 116 if (!dev) 117 continue; 118 119 let handler = handlers[dev_name]; 120 if (!handler) 121 continue; 122 123 let config = parse_attribute_list(data, handler.iface); 124 if (mlo_vif) 125 if (dev_name == wdev.mlo_name) 126 config.radio_config = radio_config; 127 else 128 config.mode = "link"; 129 config.radios = radios; 130 131 let vif = { 132 name, config, 133 device: dev_name, 134 135 vlan: [], 136 sta: [], 137 }; 138 push(dev.vif, vif); 139 140 vifs[name] ??= []; 141 push(vifs[name], vif); 142 } 143 } 144 145 for (let name, data in sections.vlan) { 146 if (!data.iface || !vifs[data.iface]) 147 continue; 148 149 for (let vif in vifs[data.iface]) { 150 let dev = devices[vif.device]; 151 let handler = handlers[vif.device]; 152 if (!dev || !handler) 153 continue; 154 155 let config = parse_attribute_list(data, handler.vlan); 156 157 let vlan = { 158 name, 159 config 160 }; 161 push(vif.vlan, vlan); 162 } 163 } 164 165 for (let name, data in sections.station) { 166 if (!data.iface || !vifs[data.iface]) 167 continue; 168 169 for (let vif in vifs[data.iface]) { 170 let dev = devices[vif.device]; 171 let handler = handlers[vif.device]; 172 if (!dev || !handler) 173 continue; 174 175 let config = parse_attribute_list(data, handler.station); 176 177 let sta = { 178 name, 179 config 180 }; 181 push(vif.sta, sta); 182 } 183 } 184 185 let udata = ubus.call({ 186 object: "service", 187 method: "get_data", 188 data: { 189 type: "wifi-device" 190 }, 191 }); 192 for (let svcname, svc in udata) { 193 for (let insname, ins in svc) { 194 for (let typename, data in ins) { 195 for (let radio, config in data) { 196 if (type(config) != "object") 197 continue; 198 199 let dev = devices[radio]; 200 if (dev) { 201 dev.config = { ...dev.config, ...config }; 202 continue; 203 } 204 205 let handler = wireless.handlers[config.type]; 206 if (!handler) 207 continue; 208 209 dev = devices[radio] = { 210 name, 211 config, 212 213 vif: [], 214 }; 215 handlers[radio] = handler; 216 } 217 } 218 } 219 } 220 221 222 udata = ubus.call({ 223 object: "service", 224 method: "get_data", 225 data: { 226 type: "wifi-iface" 227 }, 228 }); 229 230 for (let svcname, svc in udata) { 231 for (let insname, ins in svc) { 232 for (let typename, data in ins) { 233 for (let radio, vifs in data) { 234 if (type(vifs) != "object") 235 continue; 236 237 for (let name, vif in vifs) { 238 let devs = vif.device; 239 if (type(devs) != "array") 240 devs = [ devs ]; 241 let config = vif.config; 242 if (!config) 243 continue; 244 for (let device in devs) { 245 let dev = devices[device]; 246 if (!dev) 247 continue; 248 249 let vif_data = { 250 name, device, config, 251 vlan: [], 252 sta: [] 253 }; 254 if (vif.vlans) 255 vif_data.vlans = vif.vlans; 256 if (vif.stations) 257 vif_data.sta = vif.stations; 258 vifs[name] ??= []; 259 push(vifs[name], vif_data); 260 push(dev.vif, vif_data); 261 } 262 } 263 } 264 } 265 } 266 } 267 268 update_config(devices); 269 } 270 271 function config_start() 272 { 273 for (let name, dev in wireless.devices) 274 if (dev.autostart) 275 dev.start(); 276 277 } 278 279 function check_interfaces() 280 { 281 for (let name, dev in wireless.devices) 282 if (dev.autostart) 283 dev.check(); 284 } 285 286 function hotplug(ifname, add) 287 { 288 for (let name, dev in wireless.devices) 289 if (dev.autostart) 290 dev.hotplug(ifname, add); 291 } 292 293 const network_config_attr = { 294 network: TYPE_ARRAY, 295 network_vlan: TYPE_ARRAY, 296 bridge_isolate: TYPE_BOOL, 297 isolate: TYPE_BOOL, 298 proxy_arp: TYPE_BOOL, 299 multicast_to_unicast: TYPE_BOOL, 300 }; 301 302 const default_config_attr = { 303 device: { 304 disabled: TYPE_BOOL, 305 type: TYPE_STRING, 306 }, 307 iface: { 308 ...network_config_attr, 309 device: TYPE_STRING, 310 mode: TYPE_STRING, 311 }, 312 station: { 313 iface: TYPE_STRING, 314 315 mac: TYPE_STRING, 316 key: TYPE_STRING, 317 vid: TYPE_STRING, 318 }, 319 vlan: { 320 ...network_config_attr, 321 iface: TYPE_STRING, 322 name: TYPE_STRING, 323 vid: TYPE_STRING, 324 }, 325 }; 326 327 const wdev_args = { 328 device: "" 329 }; 330 331 function wdev_call(req, cb) 332 { 333 let dev = req.args.device; 334 if (dev) { 335 dev = wireless.devices[dev]; 336 if (!dev) 337 return libubus.STATUS_NOT_FOUND; 338 339 return cb(dev); 340 } 341 342 for (let name, dev in wireless.devices) { 343 if (name == wdev.mlo_name) 344 continue; 345 cb(dev); 346 } 347 348 return 0; 349 } 350 351 function attr_validate(attr_type, validate) 352 { 353 if (validate) 354 return validate; 355 switch (attr_type) { 356 case TYPE_STRING: 357 return "string"; 358 case TYPE_ARRAY: 359 return "list(string)"; 360 case TYPE_INT: 361 return "uinteger"; 362 case TYPE_BOOL: 363 return "bool"; 364 } 365 } 366 367 function get_validate_info(ret, handler) 368 { 369 for (let kind in default_config_attr) { 370 let cur = ret[kind == "iface" ? "interface" : kind] = {}; 371 let validate = handler[kind + "_validate"]; 372 373 for (let attr, attr_type in handler[kind]) { 374 let val = attr_validate(attr_type, validate[attr]); 375 if (val != null) 376 cur[attr] = val; 377 } 378 } 379 380 return ret; 381 } 382 383 const ubus_obj = { 384 up: { 385 args: wdev_args, 386 call: function(req) { 387 let mlo_dev = wireless.devices[wdev.mlo_name]; 388 if (mlo_dev) 389 mlo_dev.start(); 390 391 return wdev_call(req, (dev) => { 392 dev.start(); 393 return 0; 394 }); 395 } 396 }, 397 down: { 398 args: wdev_args, 399 call: function(req) { 400 let mlo_dev = wireless.devices[wdev.mlo_name]; 401 if (mlo_dev) 402 mlo_dev.config_change = true; 403 404 return wdev_call(req, (dev) => { 405 dev.stop(); 406 return 0; 407 }); 408 } 409 }, 410 reconf: { 411 args: wdev_args, 412 call: function(req) { 413 let mlo_dev = wireless.devices[wdev.mlo_name]; 414 if (mlo_dev) 415 mlo_dev.update(); 416 417 return wdev_call(req, (dev) => { 418 dev.update(); 419 return 0; 420 }); 421 } 422 }, 423 status: { 424 args: wdev_args, 425 call: function(req) { 426 let ret = {}; 427 let err = wdev_call(req, (dev) => { 428 ret[dev.data.name] = dev.status(); 429 return 0; 430 }); 431 if (err != 0) 432 return err; 433 434 return ret; 435 } 436 }, 437 notify: { 438 args: { 439 ...wdev_args, 440 command: 0, 441 interface: "", 442 vlan: "", 443 data: {}, 444 }, 445 call: function(req) { 446 let dev = req.args.device; 447 if (!dev) 448 return libubus.STATUS_INVALID_ARGUMENT; 449 450 dev = wireless.devices[dev]; 451 if (!dev) 452 return libubus.STATUS_NOT_FOUND; 453 454 return dev.notify(req); 455 } 456 }, 457 get_validate: { 458 args: wdev_args, 459 call: function(req) { 460 let ret = {}; 461 let err = wdev_call(req, (dev) => { 462 let dev_type = dev.data.config.type; 463 let cur = ret[dev.data.name] = {}; 464 get_validate_info(cur, wireless.handlers[dev_type]); 465 return 0; 466 }); 467 if (err != 0) 468 return err; 469 470 return ret; 471 } 472 }, 473 }; 474 475 476 handler_load(wireless.path, (script, data) => { 477 if (!data.name) 478 return; 479 480 let handler = wireless.handlers[data.name] = { 481 script, 482 }; 483 for (let kind, attr in default_config_attr) { 484 let validate = handler[kind + "_validate"] = {}; 485 handler[kind] = handler_attributes(data[kind], attr, validate); 486 } 487 }); 488 489 wireless.obj = ubus.publish("network.wireless", ubus_obj); 490 491 return { 492 hotplug, 493 config_init, 494 config_start, 495 check_interfaces, 496 };
This page was automatically generated by LXR 0.3.1. • OpenWrt