luci-base: add 11ax HW / HT modes
[project/luci.git] / modules / luci-base / htdocs / luci-static / resources / network.js
index 856421cd319960fccc0b943fa81f4e011633bdb0..e78892cbdb5d97712d8d0b6db332da41b33983ee 100644 (file)
@@ -387,9 +387,11 @@ function initNetworkState(refresh) {
                                        stats:    dev.stats,
                                        macaddr:  dev.mac,
                                        type:     dev.type,
+                                       devtype:  dev.devtype,
                                        mtu:      dev.mtu,
                                        qlen:     dev.qlen,
                                        wireless: dev.wireless,
+                                       parent:   dev.parent,
                                        ipaddrs:  [],
                                        ip6addrs: []
                                };
@@ -430,6 +432,16 @@ function initNetworkState(refresh) {
                                s.isBridge[name] = true;
                        }
 
+                       for (var name in luci_devs) {
+                               var dev = luci_devs[name];
+
+                               if (!dev.parent || dev.devtype != 'dsa')
+                                       continue;
+
+                               s.isSwitch[dev.parent] = true;
+                               s.isSwitch[name] = true;
+                       }
+
                        if (L.isObject(board_json.switch)) {
                                for (var switchname in board_json.switch) {
                                        var layout = board_json.switch[switchname],
@@ -1209,6 +1221,59 @@ Network = baseclass.extend(/** @lends LuCI.network.prototype */ {
                                }
                        }
 
+                       /* find bridge VLAN devices */
+                       var uciBridgeVLANs = uci.sections('network', 'bridge-vlan');
+                       for (var i = 0; i < uciBridgeVLANs.length; i++) {
+                               var basedev = uciBridgeVLANs[i].device,
+                                   local = uciBridgeVLANs[i].local,
+                                   alias = uciBridgeVLANs[i].alias,
+                                   vid = +uciBridgeVLANs[i].vlan,
+                                   ports = L.toArray(uciBridgeVLANs[i].ports);
+
+                               if (local == '0')
+                                       continue;
+
+                               if (isNaN(vid) || vid < 0 || vid > 4095)
+                                       continue;
+
+                               var vlandev = '%s.%s'.format(basedev, alias || vid);
+
+                               _state.isBridge[basedev] = true;
+
+                               if (!_state.bridges.hasOwnProperty(basedev))
+                                       _state.bridges[basedev] = {
+                                               name:    basedev,
+                                               ifnames: []
+                                       };
+
+                               if (!devices.hasOwnProperty(vlandev))
+                                       devices[vlandev] = this.instantiateDevice(vlandev);
+
+                               ports.forEach(function(port_name) {
+                                       var m = port_name.match(/^([^:]+)(?::[ut*]+)?$/),
+                                           p = m ? m[1] : null;
+
+                                       if (!p)
+                                               return;
+
+                                       if (_state.bridges[basedev].ifnames.filter(function(sd) { return sd.name == p }).length)
+                                               return;
+
+                                       _state.netdevs[p] = _state.netdevs[p] || {
+                                               name: p,
+                                               ipaddrs: [],
+                                               ip6addrs: [],
+                                               type: 1,
+                                               devtype: 'ethernet',
+                                               stats: {},
+                                               flags: {}
+                                       };
+
+                                       _state.bridges[basedev].ifnames.push(_state.netdevs[p]);
+                                       _state.netdevs[p].bridge = _state.bridges[basedev];
+                               });
+                       }
+
                        /* find wireless interfaces */
                        var uciWifiIfaces = uci.sections('wireless', 'wifi-iface'),
                            networkCount = {};
@@ -1453,6 +1518,18 @@ Network = baseclass.extend(/** @lends LuCI.network.prototype */ {
                                }
                        }
 
+                       rv.sort(function(a, b) {
+                               if (a.metric != b.metric)
+                                       return (a.metric - b.metric);
+
+                               if (a.interface < b.interface)
+                                       return -1;
+                               else if (a.interface > b.interface)
+                                       return 1;
+
+                               return 0;
+                       });
+
                        return rv;
                }, this));
        },
@@ -2726,7 +2803,7 @@ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ {
                }
 
                this.ifname  = this.ifname || ifname;
-               this.dev     = _state.netdevs[this.ifname];
+               this.dev     = Object.assign({}, _state.netdevs[this.ifname]);
                this.network = network;
        },
 
@@ -2797,7 +2874,7 @@ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ {
        },
 
        /**
-        * Get the type of the device..
+        * Get the type of the device.
         *
         * @returns {string}
         * Returns a string describing the type of the network device:
@@ -2812,15 +2889,15 @@ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ {
        getType: function() {
                if (this.ifname != null && this.ifname.charAt(0) == '@')
                        return 'alias';
-               else if (this.wif != null || isWifiIfname(this.ifname))
+               else if (this.dev.devtype == 'wlan' || this.wif != null || isWifiIfname(this.ifname))
                        return 'wifi';
-               else if (_state.isBridge[this.ifname])
+               else if (this.dev.devtype == 'bridge' || _state.isBridge[this.ifname])
                        return 'bridge';
                else if (_state.isTunnel[this.ifname])
                        return 'tunnel';
-               else if (this.ifname.indexOf('.') > -1)
+               else if (this.dev.devtype == 'vlan' || this.ifname.indexOf('.') > -1)
                        return 'vlan';
-               else if (_state.isSwitch[this.ifname])
+               else if (this.dev.devtype == 'dsa' || _state.isSwitch[this.ifname])
                        return 'switch';
                else
                        return 'ethernet';
@@ -2877,7 +2954,8 @@ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ {
                        return _('Bridge');
 
                case 'switch':
-                       return _('Ethernet Switch');
+                       return (_state.netdevs[this.ifname] && _state.netdevs[this.ifname].devtype == 'dsa')
+                               ? _('Switch port') : _('Ethernet Switch');
 
                case 'vlan':
                        return (_state.isSwitch[this.ifname] ? _('Switch VLAN') : _('Software VLAN'));
@@ -3064,6 +3142,22 @@ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ {
         */
        getWifiNetwork: function() {
                return (this.wif != null ? this.wif : null);
+       },
+
+       /**
+        * Get the logical parent device of this device.
+        *
+        * In case of DSA switch ports, the parent device will be the DSA switch
+        * device itself, for VLAN devices, the parent refers to the base device
+        * etc.
+        *
+        * @returns {null|LuCI.network.Device}
+        * Returns a `Network.Device` instance representing the parent device or
+        * `null` when this device has no parent, as it is the case for e.g.
+        * ordinary ethernet interfaces.
+        */
+       getParent: function() {
+               return this.dev.parent ? Network.prototype.instantiateDevice(this.dev.parent) : null;
        }
 });
 
@@ -3173,6 +3267,7 @@ WifiDevice = baseclass.extend(/** @lends LuCI.network.WifiDevice.prototype */ {
         *  - `g` - Legacy 802.11g mode, 2.4 GHz, up to 54 Mbit/s
         *  - `n` - IEEE 802.11n mode, 2.4 or 5 GHz, up to 600 Mbit/s
         *  - `ac` - IEEE 802.11ac mode, 5 GHz, up to 6770 Mbit/s
+        *  - `ax` - IEEE 802.11ax mode, 2.4 or 5 GHz
         */
        getHWModes: function() {
                var hwmodes = this.ubus('dev', 'iwinfo', 'hwmodes');
@@ -3194,6 +3289,10 @@ WifiDevice = baseclass.extend(/** @lends LuCI.network.WifiDevice.prototype */ {
         *  - `VHT40` - applicable to IEEE 802.11ac, 40 MHz wide channels
         *  - `VHT80` - applicable to IEEE 802.11ac, 80 MHz wide channels
         *  - `VHT160` - applicable to IEEE 802.11ac, 160 MHz wide channels
+        *  - `HE20` - applicable to IEEE 802.11ax, 20 MHz wide channels
+        *  - `HE40` - applicable to IEEE 802.11ax, 40 MHz wide channels
+        *  - `HE80` - applicable to IEEE 802.11ax, 80 MHz wide channels
+        *  - `HE160` - applicable to IEEE 802.11ax, 160 MHz wide channels
         */
        getHTModes: function() {
                var htmodes = this.ubus('dev', 'iwinfo', 'htmodes');
@@ -3570,6 +3669,24 @@ WifiNetwork = baseclass.extend(/** @lends LuCI.network.WifiNetwork.prototype */
                return ifname;
        },
 
+       /**
+        * Get the Linux VLAN network device names.
+        *
+        * @returns {string[]}
+        * Returns the current Linux VLAN network device name as resolved
+        * from `ubus` runtime information or empty array if this network
+        * has no associated VLAN network devices.
+        */
+       getVlanIfnames: function() {
+               var vlans = L.toArray(this.ubus('net', 'vlans')),
+                   ifnames = [];
+
+               for (var i = 0; i < vlans.length; i++)
+                       ifnames.push(vlans[i]['ifname']);
+
+               return ifnames;
+       },
+
        /**
         * Get the name of the corresponding wifi radio device.
         *
@@ -3870,6 +3987,17 @@ WifiNetwork = baseclass.extend(/** @lends LuCI.network.WifiNetwork.prototype */
         * @property {number} [nss]
         * Specifies the number of spatial streams used by the transmission.
         * Only applicable to VHT rates.
+        *
+        * @property {boolean} [he]
+        * Specifies whether this rate is an HE (IEEE 802.11ax) rate.
+        *
+        * @property {number} [he_gi]
+        * Specifies whether the guard interval used for the transmission.
+        * Only applicable to HE rates.
+        *
+        * @property {number} [he_dcm]
+        * Specifies whether dual concurrent modulation is used for the transmission.
+        * Only applicable to HE rates.
         */
 
        /**
@@ -3880,7 +4008,15 @@ WifiNetwork = baseclass.extend(/** @lends LuCI.network.WifiNetwork.prototype */
         * with this network.
         */
        getAssocList: function() {
-               return callIwinfoAssoclist(this.getIfname());
+               var tasks = [];
+               var ifnames = [ this.getIfname() ].concat(this.getVlanIfnames());
+
+               for (var i = 0; i < ifnames.length; i++)
+                       tasks.push(callIwinfoAssoclist(ifnames[i]));
+
+               return Promise.all(tasks).then(function(values) {
+                       return Array.prototype.concat.apply([], values);
+               });
        },
 
        /**