• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/netifd/examples/wireless-device.uc

  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