1 'use strict'; 2 import * as libubus from "ubus"; 3 import * as uloop from "uloop"; 4 import { is_equal } from "./utils.uc"; 5 import { access } from "fs"; 6 7 const NOTIFY_CMD_UP = 0; 8 const NOTIFY_CMD_SET_DATA = 1; 9 const NOTIFY_CMD_PROCESS_ADD = 2; 10 const NOTIFY_CMD_SET_RETRY = 4; 11 12 const DEFAULT_RETRY = 3; 13 const DEFAULT_SCRIPT_TIMEOUT = 30 * 1000; 14 15 export const mlo_name = "#mlo"; 16 17 let mlo_wdev; 18 let wdev_cur; 19 let wdev_handler = {}; 20 let wdev_script_task, wdev_script_timeout; 21 let handler_timer; 22 23 function delete_wdev(name) 24 { 25 delete netifd.wireless.devices[name]; 26 gc(); 27 } 28 29 function handle_link(dev, data, up) 30 { 31 let config = data.config; 32 let bridge_isolate; 33 let ap = false; 34 if (dev == data.ifname) 35 ap = data.type == "vlan" || 36 (data.type == "vif" && config.mode == "ap"); 37 38 let dev_data = { 39 external: 2, 40 check_vlan: false, 41 isolate: !!config.bridge_isolate, 42 wireless: true, 43 wireless_ap: ap, 44 }; 45 46 if (ap && config.multicast_to_unicast != null) 47 dev_data.multicast_to_unicast = config.multicast_to_unicast; 48 49 if (data.type == "vif" && config.mode == "ap") { 50 dev_data.wireless_proxyarp = !!config.proxy_arp; 51 dev_data.wireless_isolate = !!config.isolate; 52 } 53 54 if (up) 55 netifd.device_set(dev, dev_data); 56 57 for (let net in config.network) 58 netifd.interface_handle_link({ 59 name: net, 60 ifname: dev, 61 vlan: config.network_vlan, 62 link_ext: true, 63 up, 64 }); 65 } 66 67 function wdev_mlo_fixup(config) 68 { 69 if (!mlo_wdev) 70 return; 71 72 for (let name, iface in config.interfaces) { 73 let config = iface.config; 74 75 if (config.mode != "link") 76 continue; 77 78 let mlo_config = mlo_wdev.handler_data[iface.name]; 79 if (mlo_config && mlo_config.ifname) 80 config.ifname = mlo_config.ifname; 81 } 82 } 83 84 function wdev_config_init(wdev) 85 { 86 let data = wdev.data; 87 let config = data.config; 88 let interfaces = {}; 89 90 let vif_idx = 0; 91 for (let vif in data.vif) { 92 let vlan_idx = 0, sta_idx = 0; 93 let vlans = {}, stas = {}; 94 95 if (wdev.disabled_vifs[vif.name]) 96 continue; 97 for (let vlan in vif.vlan) { 98 let vlan_name = sprintf("%02d", ++vlan_idx); 99 let cur_vlan = vlans[vlan_name] = { 100 name: vlan.name, 101 config: vlan.config, 102 }; 103 104 if (wdev.disabled_vifs[vif.name]) 105 continue; 106 for (let net in vlan.config.network) 107 if (netifd.interface_get_bridge(net, cur_vlan)) 108 break; 109 } 110 111 for (let sta in vif.sta) { 112 let sta_name = sprintf("%02d", ++sta_idx); 113 stas[sta_name] = { 114 name: sta.name, 115 config: sta.config, 116 }; 117 } 118 119 let vif_name = sprintf("%02d", ++vif_idx); 120 let iface = interfaces[vif_name] = { 121 name: vif.name, 122 config: vif.config, 123 vlans, stas, 124 }; 125 126 for (let net in vif.config.network) 127 if (netifd.interface_get_bridge(net, iface)) 128 break; 129 } 130 131 wdev.handler_config = { 132 config, 133 interfaces, 134 }; 135 136 let prev = wdev.handler_data; 137 wdev.handler_data = {}; 138 139 if (prev && prev[wdev.name]) 140 wdev.handler_data[wdev.name] = prev[wdev.name]; 141 } 142 143 function wdev_setup_cb(wdev) 144 { 145 if (wdev.state != "setup") 146 return; 147 148 if (wdev.retry > 0) 149 wdev.retry--; 150 else 151 wdev.retry_setup_failed = true; 152 153 wdev.teardown(); 154 } 155 156 function wdev_teardown_cb(wdev) 157 { 158 for (let section, data in wdev.handler_data) { 159 if (data.ifname) 160 handle_link(data.ifname, data, false); 161 } 162 163 wdev.handler_data = {}; 164 wdev.state = "down"; 165 166 if (wdev.delete) { 167 delete_wdev(wdev.data.name); 168 return; 169 } 170 171 wdev.setup(); 172 } 173 174 function run_handler_cb(wdev, cb) 175 { 176 if (wdev != wdev_cur.wdev) 177 return; 178 179 wdev.dbg("complete " + wdev_cur.op); 180 if (wdev_script_timeout) 181 wdev_script_timeout.cancel(); 182 wdev_script_timeout = null; 183 wdev_script_task = null; 184 wdev_cur = null; 185 handler_timer.set(1); 186 cb(wdev); 187 } 188 189 function run_handler_timeout(wdev, cb) 190 { 191 wdev_script_task.cancel(); 192 run_handler_cb(wdev, cb); 193 } 194 195 function handler_sort_fn(a, b) 196 { 197 return wdev_handler[a].time - wdev_handler[b].time 198 } 199 200 function __run_next_handler_name() 201 { 202 if (wdev_handler[mlo_name]) 203 return mlo_name; 204 205 return sort(keys(wdev_handler), handler_sort_fn)[0]; 206 } 207 208 function __run_next_handler() 209 { 210 let name = __run_next_handler_name(); 211 if (!name) 212 return; 213 214 wdev_cur = wdev_handler[name]; 215 delete wdev_handler[name]; 216 217 let wdev = wdev_cur.wdev; 218 let op = wdev_cur.op; 219 let cb = wdev_cur.cb; 220 221 wdev.dbg("run " + op); 222 if (name != mlo_name) 223 wdev_mlo_fixup(wdev.handler_config); 224 wdev.handler_config.data = wdev.handler_data[wdev.name]; 225 wdev_script_task = netifd.process({ 226 cb: () => run_handler_cb(wdev, cb), 227 dir: netifd.wireless.path, 228 argv: [ './' + wdev.script, wdev.data.config.type, op, wdev.name, "" + wdev.handler_config ], 229 log_prefix: wdev.name, 230 }); 231 232 if (!wdev_script_task) 233 return run_handler_cb(wdev, cb); 234 235 wdev_script_timeout = uloop.timer(DEFAULT_SCRIPT_TIMEOUT, 236 () => run_handler_timeout(wdev, cb) 237 ); 238 } 239 240 function run_next_handler() 241 { 242 while (!wdev_cur && length(wdev_handler) > 0) 243 __run_next_handler(); 244 } 245 246 function run_handler(wdev, op, cb) 247 { 248 wdev.dbg("queue " + op); 249 wdev_handler[wdev.name] = { 250 op, wdev, cb, 251 time: time() 252 }; 253 254 run_next_handler(); 255 } 256 257 function wdev_proc_reset(wdev) 258 { 259 if (wdev.proc_timer) { 260 wdev.proc_timer.cancel(); 261 delete wdev.proc_timer; 262 } 263 264 wdev.procs = []; 265 } 266 267 function __wdev_proc_check(wdev, proc) 268 { 269 if (netifd.process_check(proc.pid, proc.exe)) 270 return; 271 272 wdev.dbg(`process ${proc.exe}(${proc.pid}) no longer active`); 273 wdev.teardown(); 274 return true; 275 } 276 277 function wdev_proc_check(wdev) 278 { 279 for (let proc in wdev.procs) 280 if (__wdev_proc_check(wdev, proc)) 281 break; 282 } 283 284 function wdev_proc_add(wdev, data) 285 { 286 if (!data.pid || !data.exe) 287 return; 288 289 push(wdev.procs, data); 290 291 if (!wdev.proc_timer) 292 wdev.proc_timer = uloop.interval(1000, () => wdev_proc_check(wdev)); 293 } 294 295 296 function setup() 297 { 298 if (this.state != "up" && this.state != "down") 299 return; 300 301 this.dbg("setup, state=" + this.state); 302 if (!this.autostart || this.retry_setup_failed || this.data.config.disabled) 303 return; 304 305 wdev_proc_reset(this); 306 delete this.config_change; 307 this.state = "setup"; 308 run_handler(this, "setup", wdev_setup_cb); 309 } 310 311 function teardown() 312 { 313 delete this.cancel_setup; 314 315 this.dbg("teardown, state=" + this.state); 316 if (this.state == "teardown" || this.state == "down") 317 return; 318 319 wdev_proc_reset(this); 320 this.state = "teardown"; 321 run_handler(this, "teardown", wdev_teardown_cb); 322 } 323 324 function wdev_update_disabled_vifs(wdev) 325 { 326 let cache = wdev.ifindex_cache; 327 let prev_disabled = wdev.disabled_vifs; 328 let disabled = wdev.disabled_vifs = {}; 329 let changed; 330 331 let vifs = []; 332 for (let vif in wdev.data.vif) 333 push(vifs, vif, ...vif.vlan); 334 335 for (let vif in vifs) { 336 let enabled, ifindex; 337 338 for (let net in vif.config.network) { 339 let state = netifd.interface_get_enabled(net); 340 if (!state) 341 continue; 342 343 if (state.enabled) 344 enabled = true; 345 else if (enabled == null) 346 enabled = false; 347 if (state.ifindex) 348 ifindex = state.ifindex; 349 } 350 351 let name = vif.name; 352 if (enabled == false) 353 disabled[wdev] = true; 354 else if (ifindex != cache[name]) 355 changed = true; 356 357 if (ifindex) 358 cache[name] = ifindex; 359 else 360 delete cache[name]; 361 } 362 363 if (changed || !is_equal(prev_disabled, disabled)) 364 wdev.config_change = true; 365 366 return wdev.config_change; 367 } 368 369 function wdev_reset(wdev) 370 { 371 wdev.retry = DEFAULT_RETRY; 372 delete wdev.retry_setup_failed; 373 } 374 375 function update(data) 376 { 377 if (is_equal(this.data, data)) 378 return; 379 380 if (data) { 381 this.data = data; 382 this.ifindex_cache = {}; 383 delete this.retry_setup_failed; 384 delete this.delete; 385 } 386 387 wdev_reset(this); 388 this.config_change = true; 389 this.check(); 390 } 391 392 function start() 393 { 394 if (this.delete) 395 return; 396 397 this.dbg("start, state=" + this.state); 398 this.autostart = true; 399 if (this.data.config.disabled) 400 return; 401 402 wdev_reset(this); 403 404 if (this.state != "down") 405 return; 406 407 if (wdev_update_disabled_vifs(this)) 408 wdev_config_init(this); 409 this.setup(); 410 } 411 412 function stop() 413 { 414 this.dbg("stop, state=" + this.state); 415 this.autostart = false; 416 417 switch (this.state) { 418 case "setup": 419 this.cancel_setup = true; 420 break; 421 case "up": 422 this.teardown(); 423 break; 424 } 425 } 426 427 function check() 428 { 429 if (!wdev_update_disabled_vifs(this)) 430 return; 431 432 wdev_config_init(this); 433 if (this.data.config.disabled) 434 this.teardown(); 435 else 436 this.setup(); 437 } 438 439 function wdev_mark_up(wdev) 440 { 441 wdev.dbg("mark up, state=" + wdev.state); 442 if (wdev.state != "setup") 443 return; 444 445 if (wdev.name == mlo_name) 446 mlo_wdev = wdev; 447 448 if (wdev.config_change) { 449 wdev.setup(); 450 return; 451 } 452 453 for (let section, data in wdev.handler_data) { 454 if (data.ifname) 455 handle_link(data.ifname, data, true); 456 } 457 wdev.state = "up"; 458 459 return 0; 460 } 461 462 function wdev_set_data(wdev, vif, vlan, data) 463 { 464 let config = wdev.handler_config; 465 let cur = wdev; 466 let cur_type = "device"; 467 if (!config) 468 return libubus.STATUS_INVALID_ARGUMENT; 469 470 if (vif) { 471 cur = vif = config.interfaces[vif]; 472 if (!vif) 473 return libubus.STATUS_NOT_FOUND; 474 cur_type = "vif"; 475 } 476 477 if (vlan) { 478 if (!vif) 479 return libubus.STATUS_INVALID_ARGUMENT; 480 481 cur = vlan = vif.vlans[vlan]; 482 if (!vlan) 483 return libubus.STATUS_NOT_FOUND; 484 485 cur_type = "vlan"; 486 } 487 488 wdev.handler_data[cur.name] = { 489 ...cur, 490 ...data, 491 type: cur_type, 492 config: cur.config, 493 }; 494 495 return 0; 496 } 497 498 function notify(req) 499 { 500 let vif = req.args.interface; 501 let vlan = req.args.vlan; 502 let data = req.args.data; 503 504 switch (req.args.command) { 505 case NOTIFY_CMD_UP: 506 if (vif || vlan || this.state != "setup") 507 return libubus.STATUS_INVALID_ARGUMENT; 508 509 return wdev_mark_up(this); 510 case NOTIFY_CMD_SET_DATA: 511 return wdev_set_data(this, vif, vlan, data); 512 case NOTIFY_CMD_PROCESS_ADD: 513 if (this.state != "setup" && this.state != "up") 514 return 0; 515 516 wdev_proc_add(this, data); 517 return 0; 518 case NOTIFY_CMD_SET_RETRY: 519 if (data.retry != null) 520 this.retry = data.retry; 521 else 522 this.retry = DEFAULT_RETRY; 523 return 0; 524 default: 525 return libubus.STATUS_INVALID_ARGUMENT; 526 } 527 } 528 529 function hotplug(name, add) 530 { 531 let dev = name; 532 let m = match(name, /(.+)\.sta.+/); 533 if (m) 534 name = m[1]; 535 536 for (let section, data in this.handler_data) { 537 if (data.ifname != name || 538 data.type != "vif" && data.type != "vlan") 539 continue; 540 541 handle_link(dev, data, add); 542 } 543 } 544 545 function get_status_data(wdev, vif) 546 { 547 let hdata = wdev.handler_data[vif.name]; 548 let data = { 549 section: vif.name, 550 config: vif.config 551 }; 552 if (hdata && hdata.ifname) 553 data.ifname = hdata.ifname; 554 return data; 555 } 556 557 function get_status_vlans(wdev, vif) 558 { 559 let vlans = []; 560 for (let vlan in vif.vlan) 561 push(vlans, get_status_data(wdev, vlan)); 562 return vlans; 563 } 564 565 function get_status_stations(wdev, vif) 566 { 567 let vlans = []; 568 for (let vlan in vif.sta) 569 push(vlans, get_status_data(wdev, vlan)); 570 return vlans; 571 } 572 573 function status() 574 { 575 let interfaces = []; 576 for (let vif in this.data.vif) { 577 let vlans = get_status_vlans(this, vif); 578 let stations = get_status_stations(this, vif); 579 let data = get_status_data(this, vif); 580 push(interfaces, { 581 ...data, 582 vlans, stations 583 }); 584 } 585 return { 586 up: this.state == "up", 587 pending: this.state == "setup" || this.state == "teardown", 588 autostart: this.autostart, 589 disabled: !!this.data.config.disabled, 590 retry_setup_failed: !!this.retry_setup_failed, 591 config: this.data.config, 592 interfaces 593 }; 594 } 595 596 function destroy() 597 { 598 this.dbg("destroy"); 599 this.autostart = false; 600 this.delete = true; 601 if (this.state != "down") { 602 this.stop(); 603 return; 604 } 605 606 delete_wdev(this.data.name); 607 } 608 609 function dbg(msg) 610 { 611 netifd.log(netifd.L_DEBUG, `wireless: ${this.name}: ${msg}\n`); 612 } 613 614 const wdev_proto = { 615 update, 616 destroy, 617 start, 618 stop, 619 setup, 620 status, 621 teardown, 622 check, 623 notify, 624 hotplug, 625 dbg, 626 }; 627 628 export function new(data, script, driver) 629 { 630 let wdev = { 631 name: data.name, 632 script, data, 633 procs: [], 634 vifs: {}, 635 disabled_vifs: {}, 636 ifindex_cache: {}, 637 638 autostart: true, 639 state: "down", 640 }; 641 wdev_update_disabled_vifs(wdev); 642 wdev_config_init(wdev); 643 handler_timer = uloop.timer(1, run_next_handler); 644 return proto(wdev, wdev_proto); 645 };
This page was automatically generated by LXR 0.3.1. • OpenWrt