'use strict';
+'require fs';
+'require ui';
'require rpc';
'require uci';
'require form';
'require tools.widgets as widgets';
function count_changes(section_id) {
- var changes = L.ui.changes.changes, n = 0;
+ var changes = ui.changes.changes, n = 0;
if (!L.isObject(changes))
return n;
channel = radioNet.getChannel(),
disabled = (radioNet.get('disabled') == '1' || uci.get('wireless', radioNet.getWifiDeviceName(), 'disabled') == '1'),
is_assoc = (bssid && bssid != '00:00:00:00:00:00' && channel && mode != 'Unknown' && !disabled),
+ is_mesh = (radioNet.getMode() == 'mesh'),
changecount = count_changes(radioNet.getName()),
status_text = null;
if (changecount)
status_text = E('a', {
href: '#',
- click: L.bind(L.ui.changes.displayChanges, L.ui.changes)
+ click: L.bind(ui.changes.displayChanges, ui.changes)
}, _('Interface has %d pending changes').format(changecount));
else if (!is_assoc)
status_text = E('em', disabled ? _('Wireless is disabled') : _('Wireless is not associated'));
return L.itemlist(E('div'), [
- _('SSID'), radioNet.getSSID() || '?',
+ is_mesh ? _('Mesh ID') : _('SSID'), (is_mesh ? radioNet.getMeshID() : radioNet.getSSID()) || '?',
_('Mode'), mode,
_('BSSID'), (!changecount && is_assoc) ? bssid : null,
_('Encryption'), (!changecount && is_assoc) ? radioNet.getActiveEncryption() || _('None') : null,
}
return map.save().then(function() {
- L.ui.changes.apply()
+ ui.changes.apply()
});
}
'11a': L.hasSystemFeature('hostapd', 'acs') ? [ 'auto', 'auto', true ] : []
};
- for (var i = 0; Array.isArray(data[1]) && i < data[1].length; i++)
+ for (var i = 0; i < data[1].length; i++)
this.channels[(data[1][i].mhz > 2484) ? '11a' : '11g'].push(
data[1][i].channel,
'%d (%d Mhz)'.format(data[1][i].channel, data[1][i].mhz),
if (vals[i+2])
sel.add(E('option', { value: vals[i+0] }, [ vals[i+1] ]));
- if (!isNaN(vals.selected))
+ if (vals && !isNaN(vals.selected))
sel.selectedIndex = vals.selected;
sel.parentNode.style.display = (sel.options.length <= 1) ? 'none' : '';
},
renderWidget: function(section_id, option_index, cfgvalue) {
- var typeClass = this.keylist.length ? form.ListValue : form.Value;
+ var typeClass = (this.keylist && this.keylist.length) ? form.ListValue : form.Value;
return typeClass.prototype.renderWidget.apply(this, [section_id, option_index, cfgvalue]);
}
});
btns[2].disabled = busy;
}
- var table = document.querySelector('wifi_assoclist_table'),
+ var table = document.querySelector('#wifi_assoclist_table'),
hosts = data[0],
trows = [];
ipv4 = hosts.getIPAddrByMACAddr(bss.mac),
ipv6 = hosts.getIP6AddrByMACAddr(bss.mac);
- trows.push([
+ var hint;
+
+ if (name && ipv4 && ipv6)
+ hint = '%s (%s, %s)'.format(name, ipv4, ipv6);
+ else if (name && (ipv4 || ipv6))
+ hint = '%s (%s)'.format(name, ipv4 || ipv6);
+ else
+ hint = name || ipv4 || ipv6 || '?';
+
+ var row = [
E('span', { 'class': 'ifacebadge' }, [
E('img', {
'src': L.resource('icons/wifi%s.png').format(bss.network.isUp() ? '' : '_disabled'),
E('small', '(%s)'.format(bss.network.getIfname()))
]),
bss.mac,
- name ? '%s (%s)'.format(name, ipv4 || ipv6 || '?') : ipv4 || ipv6 || '?',
+ hint,
render_signal_badge(Math.min((bss.signal + 110) / 70 * 100, 100), bss.signal, bss.noise),
E('span', {}, [
E('span', format_wifirate(bss.rx)),
E('br'),
E('span', format_wifirate(bss.tx))
])
- ]);
+ ];
+
+ if (bss.network.isClientDisconnectSupported()) {
+ if (table.firstElementChild.childNodes.length < 6)
+ table.firstElementChild.appendChild(E('div', { 'class': 'th nowrap right'}, [ _('Disconnect') ]));
+
+ row.push(E('button', {
+ 'class': 'cbi-button cbi-button-remove',
+ 'click': L.bind(function(net, mac, ev) {
+ L.dom.parent(ev.currentTarget, '.tr').style.opacity = 0.5;
+ ev.currentTarget.classList.add('spinning');
+ ev.currentTarget.disabled = true;
+ ev.currentTarget.blur();
+
+ net.disconnectClient(mac, true, 5, 60000);
+ }, this, bss.network, bss.mac)
+ }, [ _('Disconnect') ]));
+ }
+ else {
+ row.push('-');
+ }
+
+ trows.push(row);
}
- cbi_update_table('#wifi_assoclist_table', trows, E('em', _('No information available')));
+ cbi_update_table(table, trows, E('em', _('No information available')));
var stat = document.querySelector('.cbi-modal [data-name="_wifistat_modal"] .ifacebadge.large');
}
return Promise.all(tasks)
- .then(L.bind(L.ui.changes.init, L.ui.changes))
- .then(L.bind(L.ui.changes.apply, L.ui.changes));
+ .then(L.bind(ui.changes.init, ui.changes))
+ .then(L.bind(ui.changes.apply, ui.changes));
},
renderMigration: function() {
- L.ui.showModal(_('Wireless configuration migration'), [
+ ui.showModal(_('Wireless configuration migration'), [
E('p', _('The existing wireless configuration needs to be changed for LuCI to function properly.')),
E('p', _('Upon pressing "Continue", anonymous "wifi-iface" sections will be assigned with a name in the form <em>wifinet#</em> and the network will be restarted to apply the updated configuration.')),
E('div', { 'class': 'right' },
E('button', {
'class': 'btn cbi-button-action important',
- 'click': L.ui.createHandlerFn(this, 'handleMigration')
+ 'click': ui.createHandlerFn(this, 'handleMigration')
}, _('Continue')))
]);
},
E('button', {
'class': 'cbi-button cbi-button-neutral',
'title': _('Restart radio interface'),
- 'click': L.ui.createHandlerFn(this, radio_restart, section_id)
+ 'click': ui.createHandlerFn(this, radio_restart, section_id)
}, _('Restart')),
E('button', {
'class': 'cbi-button cbi-button-action important',
'title': _('Find and join network'),
- 'click': L.ui.createHandlerFn(this, 'handleScan', inst)
+ 'click': ui.createHandlerFn(this, 'handleScan', inst)
}, _('Scan')),
E('button', {
'class': 'cbi-button cbi-button-add',
'title': _('Provide new network'),
- 'click': L.ui.createHandlerFn(this, 'handleAdd', inst)
+ 'click': ui.createHandlerFn(this, 'handleAdd', inst)
}, _('Add'))
];
}
E('button', {
'class': 'cbi-button cbi-button-neutral enable-disable',
'title': isDisabled ? _('Enable this network') : _('Disable this network'),
- 'click': L.ui.createHandlerFn(this, network_updown, section_id, this.map)
+ 'click': ui.createHandlerFn(this, network_updown, section_id, this.map)
}, isDisabled ? _('Enable') : _('Disable')),
E('button', {
'class': 'cbi-button cbi-button-action important',
'title': _('Edit this network'),
- 'click': L.ui.createHandlerFn(this, 'renderMoreOptionsModal', section_id)
+ 'click': ui.createHandlerFn(this, 'renderMoreOptionsModal', section_id)
}, _('Edit')),
E('button', {
'class': 'cbi-button cbi-button-negative remove',
'title': _('Delete this network'),
- 'click': L.ui.createHandlerFn(this, 'handleRemove', section_id)
+ 'click': ui.createHandlerFn(this, 'handleRemove', section_id)
}, _('Remove'))
];
}
ss.tab('general', _('General Setup'));
ss.tab('advanced', _('Advanced Settings'));
- var isDisabled = (radioNet.get('disabled') == '1');
+ var isDisabled = (radioNet.get('disabled') == '1' ||
+ uci.get('wireless', radioNet.getWifiDeviceName(), 'disabled') == 1);
o = ss.taboption('general', form.DummyValue, '_wifistat_modal', _('Status'));
o.cfgvalue = L.bind(function(radioNet) {
o = ss.taboption('general', form.Button, '_toggle', isDisabled ? _('Wireless network is disabled') : _('Wireless network is enabled'));
o.inputstyle = isDisabled ? 'apply' : 'reset';
o.inputtitle = isDisabled ? _('Enable') : _('Disable');
- o.onclick = L.ui.createHandlerFn(s, network_updown, s.section, s.map);
+ o.onclick = ui.createHandlerFn(s, network_updown, s.section, s.map);
o = ss.taboption('general', CBIWifiFrequencyValue, '_freq', '<br />' + _('Operating frequency'));
o.ucisection = s.section;
o.depends({ mode: 'ap-wds', encryption: 'sae-mixed' });
if (L.hasSystemFeature('hostapd', 'cli') && L.hasSystemFeature('wpasupplicant')) {
- o = ss.taboption('encryption', form.Flag, 'wps_pushbutton', _('Enable WPS pushbutton, requires WPA(2)-PSK'))
+ o = ss.taboption('encryption', form.Flag, 'wps_pushbutton', _('Enable WPS pushbutton, requires WPA(2)-PSK/WPA3-SAE'))
o.enabled = '1';
o.disabled = '0';
o.default = o.disabled;
o.depends('encryption', 'psk');
o.depends('encryption', 'psk2');
o.depends('encryption', 'psk-mixed');
+ o.depends('encryption', 'sae');
+ o.depends('encryption', 'sae-mixed');
}
}
}
cbi_update_table(table, [], E('em', { class: 'spinning' }, _('Starting wireless scan...')));
- var md = L.ui.showModal(_('Join Network: Wireless Scan'), [
+ var md = ui.showModal(_('Join Network: Wireless Scan'), [
table,
E('div', { 'class': 'right' },
E('button', {
md.style.maxHeight = '';
}
- L.ui.hideModal();
+ ui.hideModal();
L.Poll.remove(this.pollFn);
this.pollFn = null;
var section_id = null;
return this.map.save(function() {
+ var wifi_sections = uci.sections('wireless', 'wifi-iface');
+
if (replopt.formvalue('_new_') == '1') {
- var sections = uci.sections('wireless', 'wifi-iface');
+ for (var i = 0; i < wifi_sections.length; i++)
+ if (wifi_sections[i].device == radioDev.getName())
+ uci.remove('wireless', wifi_sections[i]['.name']);
+ }
+
+ if (uci.get('wireless', radioDev.getName(), 'disabled') == '1') {
+ for (var i = 0; i < wifi_sections.length; i++)
+ if (wifi_sections[i].device == radioDev.getName())
+ uci.set('wireless', wifi_sections[i]['.name'], 'disabled', '1');
- for (var i = 0; i < sections.length; i++)
- if (sections[i].device == radioDev.getName())
- uci.remove('wireless', sections[i]['.name']);
+ uci.unset('wireless', radioDev.getName(), 'disabled');
}
- section_id = next_free_sid(uci.sections('wifi-iface').length);
+ section_id = next_free_sid(wifi_sections.length);
uci.add('wireless', 'wifi-iface', section_id);
uci.set('wireless', section_id, 'device', radioDev.getName());
zone.default = 'wan';
return m2.render().then(L.bind(function(nodes) {
- L.ui.showModal(_('Joining Network: %q').replace(/%q/, '"%h"'.format(bss.ssid)), [
+ ui.showModal(_('Joining Network: %q').replace(/%q/, '"%h"'.format(bss.ssid)), [
nodes,
E('div', { 'class': 'right' }, [
E('button', {
'class': 'btn',
- 'click': L.ui.hideModal
+ 'click': ui.hideModal
}, _('Cancel')), ' ',
E('button', {
'class': 'cbi-button cbi-button-positive important',
- 'click': L.ui.createHandlerFn(this, 'handleJoinConfirm', radioDev, bss, m2)
+ 'click': ui.createHandlerFn(this, 'handleJoinConfirm', radioDev, bss, m2)
}, _('Submit'))
])
], 'cbi-modal').querySelector('[id="%s"] input[class][type]'.format((passphrase || name).cbid('_new_'))).focus();
if (dsc.getAttribute('restart') == '') {
dsc.setAttribute('restart', '1');
- tasks.push(L.Request.post(
- L.url('admin/network/wireless_reconnect', section_ids[i]),
- 'token=' + L.env.token,
- { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
- ).catch(function() {}));
+ tasks.push(fs.exec('/sbin/wifi', ['up', section_ids[i]]).catch(function(e) {
+ ui.addNotification(null, E('p', e.message));
+ }));
}
else if (dsc.getAttribute('restart') == '1') {
dsc.removeAttribute('restart');
E('div', { 'class': 'tr table-titles' }, [
E('div', { 'class': 'th nowrap' }, _('Network')),
E('div', { 'class': 'th hide-xs' }, _('MAC-Address')),
- E('div', { 'class': 'th nowrap' }, _('Host')),
+ E('div', { 'class': 'th' }, _('Host')),
E('div', { 'class': 'th nowrap' }, _('Signal / Noise')),
E('div', { 'class': 'th nowrap' }, _('RX Rate / TX Rate'))
])