2020-03-27 09:27:18 +00:00
'use strict' ;
2020-04-09 12:39:09 +00:00
'require view' ;
'require dom' ;
'require poll' ;
2020-03-27 09:27:18 +00:00
'require fs' ;
'require ui' ;
'require rpc' ;
'require uci' ;
'require form' ;
'require network' ;
'require firewall' ;
'require tools.widgets as widgets' ;
2020-05-20 08:46:25 +00:00
var isReadonlyView = ! L . hasViewPermission ( ) ;
2020-03-27 09:27:18 +00:00
function count _changes ( section _id ) {
var changes = ui . changes . changes , n = 0 ;
if ( ! L . isObject ( changes ) )
return n ;
if ( Array . isArray ( changes . wireless ) )
for ( var i = 0 ; i < changes . wireless . length ; i ++ )
n += ( changes . wireless [ i ] [ 1 ] == section _id ) ;
return n ;
}
function render _radio _badge ( radioDev ) {
return E ( 'span' , { 'class' : 'ifacebadge' } , [
E ( 'img' , { 'src' : L . resource ( 'icons/wifi%s.png' ) . format ( radioDev . isUp ( ) ? '' : '_disabled' ) } ) ,
' ' ,
radioDev . getName ( )
] ) ;
}
2020-04-09 12:39:09 +00:00
function render _signal _badge ( signalPercent , signalValue , noiseValue , wrap , mode ) {
2020-03-27 09:27:18 +00:00
var icon , title , value ;
if ( signalPercent < 0 )
icon = L . resource ( 'icons/signal-none.png' ) ;
else if ( signalPercent == 0 )
icon = L . resource ( 'icons/signal-0.png' ) ;
else if ( signalPercent < 25 )
icon = L . resource ( 'icons/signal-0-25.png' ) ;
else if ( signalPercent < 50 )
icon = L . resource ( 'icons/signal-25-50.png' ) ;
else if ( signalPercent < 75 )
icon = L . resource ( 'icons/signal-50-75.png' ) ;
else
icon = L . resource ( 'icons/signal-75-100.png' ) ;
2020-04-09 12:39:09 +00:00
if ( signalValue != null && signalValue != 0 ) {
if ( noiseValue != null && noiseValue != 0 ) {
value = '%d/%d\xa0%s' . format ( signalValue , noiseValue , _ ( 'dBm' ) ) ;
title = '%s: %d %s / %s: %d %s / %s %d' . format (
_ ( 'Signal' ) , signalValue , _ ( 'dBm' ) ,
_ ( 'Noise' ) , noiseValue , _ ( 'dBm' ) ,
_ ( 'SNR' ) , signalValue - noiseValue ) ;
}
else {
value = '%d\xa0%s' . format ( signalValue , _ ( 'dBm' ) ) ;
title = '%s: %d %s' . format ( _ ( 'Signal' ) , signalValue , _ ( 'dBm' ) ) ;
}
2020-03-27 09:27:18 +00:00
}
else if ( signalPercent > - 1 ) {
2020-04-09 12:39:09 +00:00
switch ( mode ) {
case 'ap' :
title = _ ( 'No client associated' ) ;
break ;
case 'sta' :
case 'adhoc' :
case 'mesh' :
title = _ ( 'Not associated' ) ;
break ;
default :
title = _ ( 'No RX signal' ) ;
}
if ( noiseValue != null && noiseValue != 0 ) {
value = '---/%d\x0a%s' . format ( noiseValue , _ ( 'dBm' ) ) ;
title = '%s / %s: %d %s' . format ( title , _ ( 'Noise' ) , noiseValue , _ ( 'dBm' ) ) ;
}
else {
value = '---\xa0%s' . format ( _ ( 'dBm' ) ) ;
}
2020-03-27 09:27:18 +00:00
}
else {
value = E ( 'em' , { } , E ( 'small' , { } , [ _ ( 'disabled' ) ] ) ) ;
title = _ ( 'Interface is disabled' ) ;
}
return E ( 'div' , {
'class' : wrap ? 'center' : 'ifacebadge' ,
'title' : title ,
'data-signal' : signalValue ,
'data-noise' : noiseValue
} , [
E ( 'img' , { 'src' : icon } ) ,
E ( 'span' , { } , [
wrap ? E ( 'br' ) : ' ' ,
value
] )
] ) ;
}
function render _network _badge ( radioNet ) {
2020-04-09 12:39:09 +00:00
return render _signal _badge (
radioNet . isUp ( ) ? radioNet . getSignalPercent ( ) : - 1 ,
radioNet . getSignal ( ) , radioNet . getNoise ( ) , false , radioNet . getMode ( ) ) ;
2020-03-27 09:27:18 +00:00
}
function render _radio _status ( radioDev , wifiNets ) {
var name = radioDev . getI18n ( ) . replace ( / Wireless Controller .+$/ , '' ) ,
node = E ( 'div' , [ E ( 'big' , { } , E ( 'strong' , { } , name ) ) , E ( 'div' ) ] ) ,
channel , frequency , bitrate ;
for ( var i = 0 ; i < wifiNets . length ; i ++ ) {
channel = channel || wifiNets [ i ] . getChannel ( ) ;
frequency = frequency || wifiNets [ i ] . getFrequency ( ) ;
bitrate = bitrate || wifiNets [ i ] . getBitRate ( ) ;
}
if ( radioDev . isUp ( ) )
L . itemlist ( node . lastElementChild , [
_ ( 'Channel' ) , '%s (%s %s)' . format ( channel || '?' , frequency || '?' , _ ( 'GHz' ) ) ,
_ ( 'Bitrate' ) , '%s %s' . format ( bitrate || '?' , _ ( 'Mbit/s' ) )
] , ' | ' ) ;
else
node . lastElementChild . appendChild ( E ( 'em' , _ ( 'Device is not active' ) ) ) ;
return node ;
}
function render _network _status ( radioNet ) {
var mode = radioNet . getActiveMode ( ) ,
bssid = radioNet . getActiveBSSID ( ) ,
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 ( 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' ) , [
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 ,
null , status _text
] , [ ' | ' , E ( 'br' ) ] ) ;
}
function render _modal _status ( node , radioNet ) {
var mode = radioNet . getActiveMode ( ) ,
noise = radioNet . getNoise ( ) ,
bssid = radioNet . getActiveBSSID ( ) ,
channel = radioNet . getChannel ( ) ,
disabled = ( radioNet . get ( 'disabled' ) == '1' ) ,
is _assoc = ( bssid && bssid != '00:00:00:00:00:00' && channel && mode != 'Unknown' && ! disabled ) ;
if ( node == null )
node = E ( 'span' , { 'class' : 'ifacebadge large' , 'data-network' : radioNet . getName ( ) } , [ E ( 'small' ) , E ( 'span' ) ] ) ;
2020-04-09 12:39:09 +00:00
dom . content ( node . firstElementChild , render _signal _badge (
disabled ? - 1 : radioNet . getSignalPercent ( ) ,
radioNet . getSignal ( ) , noise , true , radioNet . getMode ( ) ) ) ;
2020-03-27 09:27:18 +00:00
L . itemlist ( node . lastElementChild , [
_ ( 'Mode' ) , mode ,
_ ( 'SSID' ) , radioNet . getSSID ( ) || '?' ,
_ ( 'BSSID' ) , is _assoc ? bssid : null ,
_ ( 'Encryption' ) , is _assoc ? radioNet . getActiveEncryption ( ) || _ ( 'None' ) : null ,
_ ( 'Channel' ) , is _assoc ? '%d (%.3f %s)' . format ( radioNet . getChannel ( ) , radioNet . getFrequency ( ) || 0 , _ ( 'GHz' ) ) : null ,
_ ( 'Tx-Power' ) , is _assoc ? '%d %s' . format ( radioNet . getTXPower ( ) , _ ( 'dBm' ) ) : null ,
_ ( 'Signal' ) , is _assoc ? '%d %s' . format ( radioNet . getSignal ( ) , _ ( 'dBm' ) ) : null ,
_ ( 'Noise' ) , ( is _assoc && noise != null ) ? '%d %s' . format ( noise , _ ( 'dBm' ) ) : null ,
_ ( 'Bitrate' ) , is _assoc ? '%.1f %s' . format ( radioNet . getBitRate ( ) || 0 , _ ( 'Mbit/s' ) ) : null ,
_ ( 'Country' ) , is _assoc ? radioNet . getCountryCode ( ) : null
] , [ ' | ' , E ( 'br' ) , E ( 'br' ) , E ( 'br' ) , E ( 'br' ) , E ( 'br' ) , ' | ' , E ( 'br' ) , ' | ' ] ) ;
if ( ! is _assoc )
2020-04-09 12:39:09 +00:00
dom . append ( node . lastElementChild , E ( 'em' , disabled ? _ ( 'Wireless is disabled' ) : _ ( 'Wireless is not associated' ) ) ) ;
2020-03-27 09:27:18 +00:00
return node ;
}
function format _wifirate ( rate ) {
var s = '%.1f\xa0%s, %d\xa0%s' . format ( rate . rate / 1000 , _ ( 'Mbit/s' ) , rate . mhz , _ ( 'MHz' ) ) ,
ht = rate . ht , vht = rate . vht ,
mhz = rate . mhz , nss = rate . nss ,
2021-06-25 17:45:23 +00:00
mcs = rate . mcs , sgi = rate . short _gi ,
he = rate . he , he _gi = rate . he _gi ,
he _dcm = rate . he _dcm ;
2020-03-27 09:27:18 +00:00
if ( ht || vht ) {
if ( vht ) s += ', VHT-MCS\xa0%d' . format ( mcs ) ;
if ( nss ) s += ', VHT-NSS\xa0%d' . format ( nss ) ;
if ( ht ) s += ', MCS\xa0%s' . format ( mcs ) ;
if ( sgi ) s += ', ' + _ ( 'Short GI' ) . replace ( / /g , '\xa0' ) ;
}
2021-06-25 17:45:23 +00:00
if ( he ) {
s += ', HE-MCS\xa0%d' . format ( mcs ) ;
if ( nss ) s += ', HE-NSS\xa0%d' . format ( nss ) ;
if ( he _gi ) s += ', HE-GI\xa0%d' . format ( he _gi ) ;
if ( he _dcm ) s += ', HE-DCM\xa0%d' . format ( he _dcm ) ;
}
2020-03-27 09:27:18 +00:00
return s ;
}
function radio _restart ( id , ev ) {
var row = document . querySelector ( '.cbi-section-table-row[data-sid="%s"]' . format ( id ) ) ,
dsc = row . querySelector ( '[data-name="_stat"] > div' ) ,
btn = row . querySelector ( '.cbi-section-actions button' ) ;
btn . blur ( ) ;
btn . classList . add ( 'spinning' ) ;
btn . disabled = true ;
dsc . setAttribute ( 'restart' , '' ) ;
2020-04-09 12:39:09 +00:00
dom . content ( dsc , E ( 'em' , _ ( 'Device is restarting…' ) ) ) ;
2020-03-27 09:27:18 +00:00
}
function network _updown ( id , map , ev ) {
var radio = uci . get ( 'wireless' , id , 'device' ) ,
disabled = ( uci . get ( 'wireless' , id , 'disabled' ) == '1' ) ||
( uci . get ( 'wireless' , radio , 'disabled' ) == '1' ) ;
if ( disabled ) {
uci . unset ( 'wireless' , id , 'disabled' ) ;
uci . unset ( 'wireless' , radio , 'disabled' ) ;
}
else {
uci . set ( 'wireless' , id , 'disabled' , '1' ) ;
var all _networks _disabled = true ,
wifi _ifaces = uci . sections ( 'wireless' , 'wifi-iface' ) ;
for ( var i = 0 ; i < wifi _ifaces . length ; i ++ ) {
if ( wifi _ifaces [ i ] . device == radio && wifi _ifaces [ i ] . disabled != '1' ) {
all _networks _disabled = false ;
break ;
}
}
if ( all _networks _disabled )
uci . set ( 'wireless' , radio , 'disabled' , '1' ) ;
}
return map . save ( ) . then ( function ( ) {
ui . changes . apply ( )
} ) ;
}
function next _free _sid ( offset ) {
var sid = 'wifinet' + offset ;
while ( uci . get ( 'wireless' , sid ) )
sid = 'wifinet' + ( ++ offset ) ;
return sid ;
}
2020-04-09 12:39:09 +00:00
function add _dependency _permutations ( o , deps ) {
var res = null ;
for ( var key in deps ) {
if ( ! deps . hasOwnProperty ( key ) || ! Array . isArray ( deps [ key ] ) )
continue ;
var list = deps [ key ] ,
tmp = [ ] ;
for ( var j = 0 ; j < list . length ; j ++ ) {
for ( var k = 0 ; k < ( res ? res . length : 1 ) ; k ++ ) {
var item = ( res ? Object . assign ( { } , res [ k ] ) : { } ) ;
item [ key ] = list [ j ] ;
tmp . push ( item ) ;
}
}
res = tmp ;
}
for ( var i = 0 ; i < ( res ? res . length : 0 ) ; i ++ )
o . depends ( res [ i ] ) ;
}
2020-03-27 09:27:18 +00:00
var CBIWifiFrequencyValue = form . Value . extend ( {
callFrequencyList : rpc . declare ( {
object : 'iwinfo' ,
method : 'freqlist' ,
params : [ 'device' ] ,
expect : { results : [ ] }
} ) ,
load : function ( section _id ) {
return Promise . all ( [
network . getWifiDevice ( section _id ) ,
this . callFrequencyList ( section _id )
] ) . then ( L . bind ( function ( data ) {
this . channels = {
2021-06-25 17:45:23 +00:00
'2g' : L . hasSystemFeature ( 'hostapd' , 'acs' ) ? [ 'auto' , 'auto' , true ] : [ ] ,
'5g' : L . hasSystemFeature ( 'hostapd' , 'acs' ) ? [ 'auto' , 'auto' , true ] : [ ] ,
2023-11-27 15:37:15 +00:00
'6g' : L . hasSystemFeature ( 'hostapd' , 'acs' ) ? [ 'auto' , 'auto' , true ] : [ ] ,
2021-06-25 17:45:23 +00:00
'60g' : [ ]
2020-03-27 09:27:18 +00:00
} ;
2021-06-25 17:45:23 +00:00
for ( var i = 0 ; i < data [ 1 ] . length ; i ++ ) {
2023-11-27 15:37:15 +00:00
if ( ! data [ 1 ] [ i ] . band )
2021-06-25 17:45:23 +00:00
continue ;
2023-11-27 15:37:15 +00:00
var band = '%dg' . format ( data [ 1 ] [ i ] . band ) ;
2021-06-25 17:45:23 +00:00
this . channels [ band ] . push (
2020-03-27 09:27:18 +00:00
data [ 1 ] [ i ] . channel ,
'%d (%d Mhz)' . format ( data [ 1 ] [ i ] . channel , data [ 1 ] [ i ] . mhz ) ,
! data [ 1 ] [ i ] . restricted
) ;
2021-06-25 17:45:23 +00:00
}
2020-03-27 09:27:18 +00:00
var hwmodelist = L . toArray ( data [ 0 ] ? data [ 0 ] . getHWModes ( ) : null )
. reduce ( function ( o , v ) { o [ v ] = true ; return o } , { } ) ;
this . modes = [
2023-11-27 15:37:15 +00:00
'' , 'Legacy' , hwmodelist . a || hwmodelist . b || hwmodelist . g ,
2020-03-27 09:27:18 +00:00
'n' , 'N' , hwmodelist . n ,
2023-11-27 15:37:15 +00:00
'ac' , 'AC' , L . hasSystemFeature ( 'hostapd' , '11ac' ) && hwmodelist . ac ,
'ax' , 'AX' , L . hasSystemFeature ( 'hostapd' , '11ax' ) && hwmodelist . ax
2020-03-27 09:27:18 +00:00
] ;
var htmodelist = L . toArray ( data [ 0 ] ? data [ 0 ] . getHTModes ( ) : null )
. reduce ( function ( o , v ) { o [ v ] = true ; return o } , { } ) ;
this . htmodes = {
'' : [ '' , '-' , true ] ,
'n' : [
'HT20' , '20 MHz' , htmodelist . HT20 ,
'HT40' , '40 MHz' , htmodelist . HT40
] ,
'ac' : [
'VHT20' , '20 MHz' , htmodelist . VHT20 ,
'VHT40' , '40 MHz' , htmodelist . VHT40 ,
'VHT80' , '80 MHz' , htmodelist . VHT80 ,
'VHT160' , '160 MHz' , htmodelist . VHT160
2021-06-25 17:45:23 +00:00
] ,
'ax' : [
'HE20' , '20 MHz' , htmodelist . HE20 ,
'HE40' , '40 MHz' , htmodelist . HE40 ,
'HE80' , '80 MHz' , htmodelist . HE80 ,
'HE160' , '160 MHz' , htmodelist . HE160
2020-03-27 09:27:18 +00:00
]
} ;
this . bands = {
'' : [
2021-06-25 17:45:23 +00:00
'2g' , '2.4 GHz' , this . channels [ '2g' ] . length > 3 ,
2023-11-27 15:37:15 +00:00
'5g' , '5 GHz' , this . channels [ '5g' ] . length > 3 ,
'60g' , '60 GHz' , this . channels [ '60g' ] . length > 0
2020-03-27 09:27:18 +00:00
] ,
'n' : [
2021-06-25 17:45:23 +00:00
'2g' , '2.4 GHz' , this . channels [ '2g' ] . length > 3 ,
'5g' , '5 GHz' , this . channels [ '5g' ] . length > 3
2020-03-27 09:27:18 +00:00
] ,
'ac' : [
2021-06-25 17:45:23 +00:00
'5g' , '5 GHz' , true
] ,
'ax' : [
'2g' , '2.4 GHz' , this . channels [ '2g' ] . length > 3 ,
2023-11-27 15:37:15 +00:00
'5g' , '5 GHz' , this . channels [ '5g' ] . length > 3 ,
'6g' , '6 GHz' , this . channels [ '6g' ] . length > 3
2020-03-27 09:27:18 +00:00
]
} ;
} , this ) ) ;
} ,
setValues : function ( sel , vals ) {
if ( sel . vals )
sel . vals . selected = sel . selectedIndex ;
while ( sel . options [ 0 ] )
sel . remove ( 0 ) ;
for ( var i = 0 ; vals && i < vals . length ; i += 3 )
if ( vals [ i + 2 ] )
sel . add ( E ( 'option' , { value : vals [ i + 0 ] } , [ vals [ i + 1 ] ] ) ) ;
if ( vals && ! isNaN ( vals . selected ) )
sel . selectedIndex = vals . selected ;
sel . parentNode . style . display = ( sel . options . length <= 1 ) ? 'none' : '' ;
sel . vals = vals ;
} ,
toggleWifiMode : function ( elem ) {
this . toggleWifiHTMode ( elem ) ;
this . toggleWifiBand ( elem ) ;
} ,
toggleWifiHTMode : function ( elem ) {
var mode = elem . querySelector ( '.mode' ) ;
var bwdt = elem . querySelector ( '.htmode' ) ;
this . setValues ( bwdt , this . htmodes [ mode . value ] ) ;
} ,
toggleWifiBand : function ( elem ) {
var mode = elem . querySelector ( '.mode' ) ;
var band = elem . querySelector ( '.band' ) ;
this . setValues ( band , this . bands [ mode . value ] ) ;
this . toggleWifiChannel ( elem ) ;
2021-06-25 17:45:23 +00:00
this . map . checkDepends ( ) ;
2020-03-27 09:27:18 +00:00
} ,
toggleWifiChannel : function ( elem ) {
var band = elem . querySelector ( '.band' ) ;
var chan = elem . querySelector ( '.channel' ) ;
this . setValues ( chan , this . channels [ band . value ] ) ;
} ,
setInitialValues : function ( section _id , elem ) {
var mode = elem . querySelector ( '.mode' ) ,
band = elem . querySelector ( '.band' ) ,
chan = elem . querySelector ( '.channel' ) ,
bwdt = elem . querySelector ( '.htmode' ) ,
htval = uci . get ( 'wireless' , section _id , 'htmode' ) ,
hwval = uci . get ( 'wireless' , section _id , 'hwmode' ) ,
2021-06-25 17:45:23 +00:00
chval = uci . get ( 'wireless' , section _id , 'channel' ) ,
bandval = uci . get ( 'wireless' , section _id , 'band' ) ;
2020-03-27 09:27:18 +00:00
this . setValues ( mode , this . modes ) ;
2021-06-25 17:45:23 +00:00
if ( /HE20|HE40|HE80|HE160/ . test ( htval ) )
mode . value = 'ax' ;
else if ( /VHT20|VHT40|VHT80|VHT160/ . test ( htval ) )
2020-03-27 09:27:18 +00:00
mode . value = 'ac' ;
else if ( /HT20|HT40/ . test ( htval ) )
mode . value = 'n' ;
else
mode . value = '' ;
this . toggleWifiMode ( elem ) ;
2021-06-25 17:45:23 +00:00
if ( hwval != null ) {
this . useBandOption = false ;
if ( /a/ . test ( hwval ) )
band . value = '5g' ;
else
band . value = '2g' ;
}
else {
this . useBandOption = true ;
band . value = bandval ;
}
2020-03-27 09:27:18 +00:00
this . toggleWifiBand ( elem ) ;
bwdt . value = htval ;
2023-11-27 15:37:15 +00:00
chan . value = chval || ( chan . options [ 0 ] ? chan . options [ 0 ] . value : 'auto' ) ;
2020-03-27 09:27:18 +00:00
return elem ;
} ,
renderWidget : function ( section _id , option _index , cfgvalue ) {
var elem = E ( 'div' ) ;
2020-04-09 12:39:09 +00:00
dom . content ( elem , [
2020-03-27 09:27:18 +00:00
E ( 'label' , { 'style' : 'float:left; margin-right:3px' } , [
_ ( 'Mode' ) , E ( 'br' ) ,
E ( 'select' , {
'class' : 'mode' ,
'style' : 'width:auto' ,
2020-05-20 08:46:25 +00:00
'change' : L . bind ( this . toggleWifiMode , this , elem ) ,
'disabled' : ( this . disabled != null ) ? this . disabled : this . map . readonly
2020-03-27 09:27:18 +00:00
} )
] ) ,
E ( 'label' , { 'style' : 'float:left; margin-right:3px' } , [
_ ( 'Band' ) , E ( 'br' ) ,
E ( 'select' , {
'class' : 'band' ,
'style' : 'width:auto' ,
2020-05-20 08:46:25 +00:00
'change' : L . bind ( this . toggleWifiBand , this , elem ) ,
'disabled' : ( this . disabled != null ) ? this . disabled : this . map . readonly
2020-03-27 09:27:18 +00:00
} )
] ) ,
E ( 'label' , { 'style' : 'float:left; margin-right:3px' } , [
_ ( 'Channel' ) , E ( 'br' ) ,
E ( 'select' , {
'class' : 'channel' ,
2020-05-20 08:46:25 +00:00
'style' : 'width:auto' ,
2021-06-25 17:45:23 +00:00
'change' : L . bind ( this . map . checkDepends , this . map ) ,
2020-05-20 08:46:25 +00:00
'disabled' : ( this . disabled != null ) ? this . disabled : this . map . readonly
2020-03-27 09:27:18 +00:00
} )
] ) ,
E ( 'label' , { 'style' : 'float:left; margin-right:3px' } , [
_ ( 'Width' ) , E ( 'br' ) ,
E ( 'select' , {
'class' : 'htmode' ,
2020-05-20 08:46:25 +00:00
'style' : 'width:auto' ,
2021-06-25 17:45:23 +00:00
'change' : L . bind ( this . map . checkDepends , this . map ) ,
2020-05-20 08:46:25 +00:00
'disabled' : ( this . disabled != null ) ? this . disabled : this . map . readonly
2020-03-27 09:27:18 +00:00
} )
] ) ,
E ( 'br' , { 'style' : 'clear:left' } )
] ) ;
return this . setInitialValues ( section _id , elem ) ;
} ,
cfgvalue : function ( section _id ) {
return [
uci . get ( 'wireless' , section _id , 'htmode' ) ,
2021-06-25 17:45:23 +00:00
uci . get ( 'wireless' , section _id , 'hwmode' ) || uci . get ( 'wireless' , section _id , 'band' ) ,
2020-03-27 09:27:18 +00:00
uci . get ( 'wireless' , section _id , 'channel' )
] ;
} ,
formvalue : function ( section _id ) {
var node = this . map . findElement ( 'data-field' , this . cbid ( section _id ) ) ;
return [
node . querySelector ( '.htmode' ) . value ,
node . querySelector ( '.band' ) . value ,
node . querySelector ( '.channel' ) . value
] ;
} ,
write : function ( section _id , value ) {
uci . set ( 'wireless' , section _id , 'htmode' , value [ 0 ] || null ) ;
2021-06-25 17:45:23 +00:00
if ( this . useBandOption )
uci . set ( 'wireless' , section _id , 'band' , value [ 1 ] ) ;
else
uci . set ( 'wireless' , section _id , 'hwmode' , ( value [ 1 ] == '2g' ) ? '11g' : '11a' ) ;
2020-03-27 09:27:18 +00:00
uci . set ( 'wireless' , section _id , 'channel' , value [ 2 ] ) ;
}
} ) ;
var CBIWifiTxPowerValue = form . ListValue . extend ( {
callTxPowerList : rpc . declare ( {
object : 'iwinfo' ,
method : 'txpowerlist' ,
params : [ 'device' ] ,
expect : { results : [ ] }
} ) ,
load : function ( section _id ) {
return this . callTxPowerList ( section _id ) . then ( L . bind ( function ( pwrlist ) {
this . powerval = this . wifiNetwork ? this . wifiNetwork . getTXPower ( ) : null ;
this . poweroff = this . wifiNetwork ? this . wifiNetwork . getTXPowerOffset ( ) : null ;
this . value ( '' , _ ( 'driver default' ) ) ;
for ( var i = 0 ; i < pwrlist . length ; i ++ )
this . value ( pwrlist [ i ] . dbm , '%d dBm (%d mW)' . format ( pwrlist [ i ] . dbm , pwrlist [ i ] . mw ) ) ;
return form . ListValue . prototype . load . apply ( this , [ section _id ] ) ;
} , this ) ) ;
} ,
renderWidget : function ( section _id , option _index , cfgvalue ) {
var widget = form . ListValue . prototype . renderWidget . apply ( this , [ section _id , option _index , cfgvalue ] ) ;
widget . firstElementChild . style . width = 'auto' ;
2020-04-09 12:39:09 +00:00
dom . append ( widget , E ( 'span' , [
2020-03-27 09:27:18 +00:00
' - ' , _ ( 'Current power' ) , ': ' ,
E ( 'span' , [ this . powerval != null ? '%d dBm' . format ( this . powerval ) : E ( 'em' , _ ( 'unknown' ) ) ] ) ,
this . poweroff ? ' + %d dB offset = %s dBm' . format ( this . poweroff , this . powerval != null ? this . powerval + this . poweroff : '?' ) : ''
] ) ) ;
return widget ;
}
} ) ;
var CBIWifiCountryValue = form . Value . extend ( {
callCountryList : rpc . declare ( {
object : 'iwinfo' ,
method : 'countrylist' ,
params : [ 'device' ] ,
expect : { results : [ ] }
} ) ,
load : function ( section _id ) {
return this . callCountryList ( section _id ) . then ( L . bind ( function ( countrylist ) {
if ( Array . isArray ( countrylist ) && countrylist . length > 0 ) {
this . value ( '' , _ ( 'driver default' ) ) ;
for ( var i = 0 ; i < countrylist . length ; i ++ )
this . value ( countrylist [ i ] . iso3166 , '%s - %s' . format ( countrylist [ i ] . iso3166 , countrylist [ i ] . country ) ) ;
}
return form . Value . prototype . load . apply ( this , [ section _id ] ) ;
} , this ) ) ;
} ,
validate : function ( section _id , formvalue ) {
if ( formvalue != null && formvalue != '' && ! /^[A-Z0-9][A-Z0-9]$/ . test ( formvalue ) )
return _ ( 'Use ISO/IEC 3166 alpha2 country codes.' ) ;
return true ;
} ,
renderWidget : function ( section _id , option _index , cfgvalue ) {
var typeClass = ( this . keylist && this . keylist . length ) ? form . ListValue : form . Value ;
return typeClass . prototype . renderWidget . apply ( this , [ section _id , option _index , cfgvalue ] ) ;
}
} ) ;
2020-04-09 12:39:09 +00:00
return view . extend ( {
2020-03-27 09:27:18 +00:00
poll _status : function ( map , data ) {
var rows = map . querySelectorAll ( '.cbi-section-table-row[data-sid]' ) ;
for ( var i = 0 ; i < rows . length ; i ++ ) {
var section _id = rows [ i ] . getAttribute ( 'data-sid' ) ,
radioDev = data [ 1 ] . filter ( function ( d ) { return d . getName ( ) == section _id } ) [ 0 ] ,
radioNet = data [ 2 ] . filter ( function ( n ) { return n . getName ( ) == section _id } ) [ 0 ] ,
badge = rows [ i ] . querySelector ( '[data-name="_badge"] > div' ) ,
stat = rows [ i ] . querySelector ( '[data-name="_stat"]' ) ,
btns = rows [ i ] . querySelectorAll ( '.cbi-section-actions button' ) ,
busy = btns [ 0 ] . classList . contains ( 'spinning' ) || btns [ 1 ] . classList . contains ( 'spinning' ) || btns [ 2 ] . classList . contains ( 'spinning' ) ;
if ( radioDev ) {
2020-04-09 12:39:09 +00:00
dom . content ( badge , render _radio _badge ( radioDev ) ) ;
dom . content ( stat , render _radio _status ( radioDev , data [ 2 ] . filter ( function ( n ) { return n . getWifiDeviceName ( ) == radioDev . getName ( ) } ) ) ) ;
2020-03-27 09:27:18 +00:00
}
else {
2020-04-09 12:39:09 +00:00
dom . content ( badge , render _network _badge ( radioNet ) ) ;
dom . content ( stat , render _network _status ( radioNet ) ) ;
2020-03-27 09:27:18 +00:00
}
if ( stat . hasAttribute ( 'restart' ) )
2020-04-09 12:39:09 +00:00
dom . content ( stat , E ( 'em' , _ ( 'Device is restarting…' ) ) ) ;
2020-03-27 09:27:18 +00:00
2020-05-20 08:46:25 +00:00
btns [ 0 ] . disabled = isReadonlyView || busy ;
btns [ 1 ] . disabled = ( isReadonlyView && radioDev ) || busy ;
btns [ 2 ] . disabled = isReadonlyView || busy ;
2020-03-27 09:27:18 +00:00
}
var table = document . querySelector ( '#wifi_assoclist_table' ) ,
hosts = data [ 0 ] ,
trows = [ ] ;
for ( var i = 0 ; i < data [ 3 ] . length ; i ++ ) {
var bss = data [ 3 ] [ i ] ,
name = hosts . getHostnameByMACAddr ( bss . mac ) ,
ipv4 = hosts . getIPAddrByMACAddr ( bss . mac ) ,
ipv6 = hosts . getIP6AddrByMACAddr ( bss . mac ) ;
var hint ;
if ( name && ipv4 && ipv6 )
hint = '%s <span class="hide-xs">(%s, %s)</span>' . format ( name , ipv4 , ipv6 ) ;
else if ( name && ( ipv4 || ipv6 ) )
hint = '%s <span class="hide-xs">(%s)</span>' . format ( name , ipv4 || ipv6 ) ;
else
hint = name || ipv4 || ipv6 || '?' ;
var row = [
E ( 'span' , {
'class' : 'ifacebadge' ,
'data-ifname' : bss . network . getIfname ( ) ,
'data-ssid' : bss . network . getSSID ( )
} , [
E ( 'img' , {
'src' : L . resource ( 'icons/wifi%s.png' ) . format ( bss . network . isUp ( ) ? '' : '_disabled' ) ,
'title' : bss . radio . getI18n ( )
} ) ,
E ( 'span' , [
' %s ' . format ( bss . network . getShortName ( ) ) ,
E ( 'small' , '(%s)' . format ( bss . network . getIfname ( ) ) )
] )
] ) ,
bss . mac ,
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 )
2020-12-03 10:26:41 +00:00
table . firstElementChild . appendChild ( E ( 'th' , { 'class' : 'th cbi-section-actions' } ) ) ;
2020-03-27 09:27:18 +00:00
row . push ( E ( 'button' , {
'class' : 'cbi-button cbi-button-remove' ,
'click' : L . bind ( function ( net , mac , ev ) {
2020-04-09 12:39:09 +00:00
dom . parent ( ev . currentTarget , '.tr' ) . style . opacity = 0.5 ;
2020-03-27 09:27:18 +00:00
ev . currentTarget . classList . add ( 'spinning' ) ;
ev . currentTarget . disabled = true ;
ev . currentTarget . blur ( ) ;
net . disconnectClient ( mac , true , 5 , 60000 ) ;
2020-05-20 08:46:25 +00:00
} , this , bss . network , bss . mac ) ,
'disabled' : isReadonlyView || null
2020-03-27 09:27:18 +00:00
} , [ _ ( 'Disconnect' ) ] ) ) ;
}
else {
row . push ( '-' ) ;
}
trows . push ( row ) ;
}
cbi _update _table ( table , trows , E ( 'em' , _ ( 'No information available' ) ) ) ;
var stat = document . querySelector ( '.cbi-modal [data-name="_wifistat_modal"] .ifacebadge.large' ) ;
if ( stat )
render _modal _status ( stat , data [ 2 ] . filter ( function ( n ) { return n . getName ( ) == stat . getAttribute ( 'data-network' ) } ) [ 0 ] ) ;
return network . flushCache ( ) ;
} ,
load : function ( ) {
return Promise . all ( [
uci . changes ( ) ,
2023-11-27 15:37:15 +00:00
uci . load ( 'wireless' ) ,
uci . load ( 'system' )
2020-03-27 09:27:18 +00:00
] ) ;
} ,
checkAnonymousSections : function ( ) {
var wifiIfaces = uci . sections ( 'wireless' , 'wifi-iface' ) ;
for ( var i = 0 ; i < wifiIfaces . length ; i ++ )
if ( wifiIfaces [ i ] [ '.anonymous' ] )
return true ;
return false ;
} ,
callUciRename : rpc . declare ( {
object : 'uci' ,
method : 'rename' ,
params : [ 'config' , 'section' , 'name' ]
} ) ,
render : function ( ) {
if ( this . checkAnonymousSections ( ) )
return this . renderMigration ( ) ;
else
return this . renderOverview ( ) ;
} ,
handleMigration : function ( ev ) {
var wifiIfaces = uci . sections ( 'wireless' , 'wifi-iface' ) ,
id _offset = 0 ,
tasks = [ ] ;
for ( var i = 0 ; i < wifiIfaces . length ; i ++ ) {
if ( ! wifiIfaces [ i ] [ '.anonymous' ] )
continue ;
var new _name = next _free _sid ( id _offset ) ;
tasks . push ( this . callUciRename ( 'wireless' , wifiIfaces [ i ] [ '.name' ] , new _name ) ) ;
id _offset = + new _name . substring ( 7 ) + 1 ;
}
return Promise . all ( tasks )
. then ( L . bind ( ui . changes . init , ui . changes ) )
. then ( L . bind ( ui . changes . apply , ui . changes ) ) ;
} ,
renderMigration : function ( ) {
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' : ui . createHandlerFn ( this , 'handleMigration' )
} , _ ( 'Continue' ) ) )
] ) ;
} ,
renderOverview : function ( ) {
var m , s , o ;
m = new form . Map ( 'wireless' ) ;
m . chain ( 'network' ) ;
m . chain ( 'firewall' ) ;
s = m . section ( form . GridSection , 'wifi-device' , _ ( 'Wireless Overview' ) ) ;
s . anonymous = true ;
s . addremove = false ;
s . load = function ( ) {
return network . getWifiDevices ( ) . then ( L . bind ( function ( radios ) {
this . radios = radios . sort ( function ( a , b ) {
return a . getName ( ) > b . getName ( ) ;
} ) ;
var tasks = [ ] ;
for ( var i = 0 ; i < radios . length ; i ++ )
tasks . push ( radios [ i ] . getWifiNetworks ( ) ) ;
return Promise . all ( tasks ) ;
} , this ) ) . then ( L . bind ( function ( data ) {
this . wifis = [ ] ;
for ( var i = 0 ; i < data . length ; i ++ )
this . wifis . push . apply ( this . wifis , data [ i ] ) ;
} , this ) ) ;
} ;
s . cfgsections = function ( ) {
var rv = [ ] ;
for ( var i = 0 ; i < this . radios . length ; i ++ ) {
rv . push ( this . radios [ i ] . getName ( ) ) ;
for ( var j = 0 ; j < this . wifis . length ; j ++ )
if ( this . wifis [ j ] . getWifiDeviceName ( ) == this . radios [ i ] . getName ( ) )
rv . push ( this . wifis [ j ] . getName ( ) ) ;
}
return rv ;
} ;
s . modaltitle = function ( section _id ) {
var radioNet = this . wifis . filter ( function ( w ) { return w . getName ( ) == section _id } ) [ 0 ] ;
return radioNet ? radioNet . getI18n ( ) : _ ( 'Edit wireless network' ) ;
} ;
s . lookupRadioOrNetwork = function ( section _id ) {
var radioDev = this . radios . filter ( function ( r ) { return r . getName ( ) == section _id } ) [ 0 ] ;
if ( radioDev )
return radioDev ;
var radioNet = this . wifis . filter ( function ( w ) { return w . getName ( ) == section _id } ) [ 0 ] ;
if ( radioNet )
return radioNet ;
return null ;
} ;
s . renderRowActions = function ( section _id ) {
var inst = this . lookupRadioOrNetwork ( section _id ) , btns ;
if ( inst . getWifiNetworks ) {
btns = [
E ( 'button' , {
'class' : 'cbi-button cbi-button-neutral' ,
'title' : _ ( 'Restart radio interface' ) ,
'click' : ui . createHandlerFn ( this , radio _restart , section _id )
} , _ ( 'Restart' ) ) ,
E ( 'button' , {
'class' : 'cbi-button cbi-button-action important' ,
'title' : _ ( 'Find and join network' ) ,
'click' : ui . createHandlerFn ( this , 'handleScan' , inst )
} , _ ( 'Scan' ) ) ,
E ( 'button' , {
'class' : 'cbi-button cbi-button-add' ,
'title' : _ ( 'Provide new network' ) ,
'click' : ui . createHandlerFn ( this , 'handleAdd' , inst )
} , _ ( 'Add' ) )
] ;
}
else {
var isDisabled = ( inst . get ( 'disabled' ) == '1' ||
uci . get ( 'wireless' , inst . getWifiDeviceName ( ) , 'disabled' ) == '1' ) ;
btns = [
E ( 'button' , {
'class' : 'cbi-button cbi-button-neutral enable-disable' ,
'title' : isDisabled ? _ ( 'Enable this network' ) : _ ( 'Disable this network' ) ,
'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' : ui . createHandlerFn ( this , 'renderMoreOptionsModal' , section _id )
} , _ ( 'Edit' ) ) ,
E ( 'button' , {
'class' : 'cbi-button cbi-button-negative remove' ,
'title' : _ ( 'Delete this network' ) ,
'click' : ui . createHandlerFn ( this , 'handleRemove' , section _id )
} , _ ( 'Remove' ) )
] ;
}
2020-12-03 10:26:41 +00:00
return E ( 'td' , { 'class' : 'td middle cbi-section-actions' } , E ( 'div' , btns ) ) ;
2020-03-27 09:27:18 +00:00
} ;
s . addModalOptions = function ( s ) {
return network . getWifiNetwork ( s . section ) . then ( function ( radioNet ) {
var hwtype = uci . get ( 'wireless' , radioNet . getWifiDeviceName ( ) , 'type' ) ;
var o , ss ;
o = s . option ( form . SectionValue , '_device' , form . NamedSection , radioNet . getWifiDeviceName ( ) , 'wifi-device' , _ ( 'Device Configuration' ) ) ;
o . modalonly = true ;
ss = o . subsection ;
ss . tab ( 'general' , _ ( 'General Setup' ) ) ;
ss . tab ( 'advanced' , _ ( 'Advanced Settings' ) ) ;
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 ) {
return render _modal _status ( null , radioNet ) ;
} , this , radioNet ) ;
o . write = function ( ) { } ;
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 = ui . createHandlerFn ( s , network _updown , s . section , s . map ) ;
o = ss . taboption ( 'general' , CBIWifiFrequencyValue , '_freq' , '<br />' + _ ( 'Operating frequency' ) ) ;
o . ucisection = s . section ;
if ( hwtype == 'mac80211' ) {
2021-06-25 17:45:23 +00:00
o = ss . taboption ( 'general' , form . Flag , 'legacy_rates' , _ ( 'Allow legacy 802.11b rates' ) , _ ( 'Legacy or badly behaving devices may require legacy 802.11b rates to interoperate. Airtime efficiency may be significantly reduced where these are used. It is recommended to not allow 802.11b rates where possible.' ) ) ;
2023-11-27 15:37:15 +00:00
o . depends ( { '_freq' : '2g' , '!contains' : true } ) ;
2021-06-25 17:45:23 +00:00
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'general' , CBIWifiTxPowerValue , 'txpower' , _ ( 'Maximum transmit power' ) , _ ( 'Specifies the maximum transmit power the wireless radio may use. Depending on regulatory requirements and wireless usage, the actual transmit power may be reduced by the driver.' ) ) ;
o . wifiNetwork = radioNet ;
o = ss . taboption ( 'advanced' , CBIWifiCountryValue , 'country' , _ ( 'Country Code' ) ) ;
o . wifiNetwork = radioNet ;
2020-12-03 10:26:41 +00:00
o = ss . taboption ( 'advanced' , form . ListValue , 'cell_density' , _ ( 'Coverage cell density' ) , _ ( 'Configures data rates based on the coverage cell density. Normal configures basic rates to 6, 12, 24 Mbps if legacy 802.11b rates are not used else to 5.5, 11 Mbps. High configures basic rates to 12, 24 Mbps if legacy 802.11b rates are not used else to the 11 Mbps rate. Very High configures 24 Mbps as the basic rate. Supported rates lower than the minimum basic rate are not offered.' ) ) ;
o . value ( '0' , _ ( 'Disabled' ) ) ;
o . value ( '1' , _ ( 'Normal' ) ) ;
o . value ( '2' , _ ( 'High' ) ) ;
o . value ( '3' , _ ( 'Very High' ) ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'advanced' , form . Value , 'distance' , _ ( 'Distance Optimization' ) , _ ( 'Distance to farthest network member in meters.' ) ) ;
2020-05-20 08:46:25 +00:00
o . datatype = 'or(range(0,114750),"auto")' ;
2020-03-27 09:27:18 +00:00
o . placeholder = 'auto' ;
o = ss . taboption ( 'advanced' , form . Value , 'frag' , _ ( 'Fragmentation Threshold' ) ) ;
o . datatype = 'min(256)' ;
o . placeholder = _ ( 'off' ) ;
o = ss . taboption ( 'advanced' , form . Value , 'rts' , _ ( 'RTS/CTS Threshold' ) ) ;
o . datatype = 'uinteger' ;
o . placeholder = _ ( 'off' ) ;
o = ss . taboption ( 'advanced' , form . Flag , 'noscan' , _ ( 'Force 40MHz mode' ) , _ ( 'Always use 40MHz channels even if the secondary channel overlaps. Using this option does not comply with IEEE 802.11n-2009!' ) ) ;
o . rmempty = true ;
o = ss . taboption ( 'advanced' , form . Value , 'beacon_int' , _ ( 'Beacon Interval' ) ) ;
o . datatype = 'range(15,65535)' ;
o . placeholder = 100 ;
o . rmempty = true ;
}
o = s . option ( form . SectionValue , '_device' , form . NamedSection , radioNet . getName ( ) , 'wifi-iface' , _ ( 'Interface Configuration' ) ) ;
o . modalonly = true ;
ss = o . subsection ;
ss . tab ( 'general' , _ ( 'General Setup' ) ) ;
ss . tab ( 'encryption' , _ ( 'Wireless Security' ) ) ;
ss . tab ( 'macfilter' , _ ( 'MAC-Filter' ) ) ;
ss . tab ( 'advanced' , _ ( 'Advanced Settings' ) ) ;
2023-11-27 15:37:15 +00:00
ss . tab ( 'roaming' , _ ( 'WLAN roaming' ) , _ ( 'Settings for assisting wireless clients in roaming between multiple APs: 802.11r, 802.11k and 802.11v' ) ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'general' , form . ListValue , 'mode' , _ ( 'Mode' ) ) ;
o . value ( 'ap' , _ ( 'Access Point' ) ) ;
o . value ( 'sta' , _ ( 'Client' ) ) ;
o . value ( 'adhoc' , _ ( 'Ad-Hoc' ) ) ;
o = ss . taboption ( 'general' , form . Value , 'mesh_id' , _ ( 'Mesh Id' ) ) ;
o . depends ( 'mode' , 'mesh' ) ;
o = ss . taboption ( 'advanced' , form . Flag , 'mesh_fwding' , _ ( 'Forward mesh peer traffic' ) ) ;
o . rmempty = false ;
o . default = '1' ;
o . depends ( 'mode' , 'mesh' ) ;
o = ss . taboption ( 'advanced' , form . Value , 'mesh_rssi_threshold' , _ ( 'RSSI threshold for joining' ) , _ ( '0 = not using RSSI threshold, 1 = do not change driver default' ) ) ;
o . rmempty = false ;
o . default = '0' ;
o . datatype = 'range(-255,1)' ;
o . depends ( 'mode' , 'mesh' ) ;
o = ss . taboption ( 'general' , form . Value , 'ssid' , _ ( '<abbr title="Extended Service Set Identifier">ESSID</abbr>' ) ) ;
o . datatype = 'maxlength(32)' ;
o . depends ( 'mode' , 'ap' ) ;
o . depends ( 'mode' , 'sta' ) ;
o . depends ( 'mode' , 'adhoc' ) ;
o . depends ( 'mode' , 'ahdemo' ) ;
o . depends ( 'mode' , 'monitor' ) ;
o . depends ( 'mode' , 'ap-wds' ) ;
o . depends ( 'mode' , 'sta-wds' ) ;
o . depends ( 'mode' , 'wds' ) ;
o = ss . taboption ( 'general' , form . Value , 'bssid' , _ ( '<abbr title="Basic Service Set Identifier">BSSID</abbr>' ) ) ;
o . datatype = 'macaddr' ;
2020-04-09 12:39:09 +00:00
o = ss . taboption ( 'general' , widgets . NetworkSelect , 'network' , _ ( 'Network' ) , _ ( 'Choose the network(s) you want to attach to this wireless interface or fill out the <em>custom</em> field to define a new network.' ) ) ;
2020-03-27 09:27:18 +00:00
o . rmempty = true ;
o . multiple = true ;
o . novirtual = true ;
o . write = function ( section _id , value ) {
return network . getDevice ( section _id ) . then ( L . bind ( function ( dev ) {
var old _networks = dev . getNetworks ( ) . reduce ( function ( o , v ) { o [ v . getName ( ) ] = v ; return o } , { } ) ,
new _networks = { } ,
values = L . toArray ( value ) ,
tasks = [ ] ;
for ( var i = 0 ; i < values . length ; i ++ ) {
new _networks [ values [ i ] ] = true ;
if ( old _networks [ values [ i ] ] )
continue ;
tasks . push ( network . getNetwork ( values [ i ] ) . then ( L . bind ( function ( name , net ) {
return net || network . addNetwork ( name , { proto : 'none' } ) ;
} , this , values [ i ] ) ) . then ( L . bind ( function ( dev , net ) {
if ( net ) {
2021-06-25 17:45:23 +00:00
if ( ! net . isEmpty ( ) ) {
var target _dev = net . getDevice ( ) ;
/* Resolve parent interface of vlan */
while ( target _dev && target _dev . getType ( ) == 'vlan' )
target _dev = target _dev . getParent ( ) ;
if ( ! target _dev || target _dev . getType ( ) != 'bridge' )
net . set ( 'type' , 'bridge' ) ;
}
2020-03-27 09:27:18 +00:00
net . addDevice ( dev ) ;
}
} , this , dev ) ) ) ;
}
for ( var name in old _networks )
if ( ! new _networks [ name ] )
tasks . push ( network . getNetwork ( name ) . then ( L . bind ( function ( dev , net ) {
if ( net )
net . deleteDevice ( dev ) ;
} , this , dev ) ) ) ;
return Promise . all ( tasks ) ;
} , this ) ) ;
} ;
if ( hwtype == 'mac80211' ) {
var mode = ss . children [ 0 ] ,
bssid = ss . children [ 5 ] ,
encr ;
mode . value ( 'mesh' , '802.11s' ) ;
mode . value ( 'ahdemo' , _ ( 'Pseudo Ad-Hoc (ahdemo)' ) ) ;
mode . value ( 'monitor' , _ ( 'Monitor' ) ) ;
bssid . depends ( 'mode' , 'adhoc' ) ;
bssid . depends ( 'mode' , 'sta' ) ;
bssid . depends ( 'mode' , 'sta-wds' ) ;
2021-06-25 17:45:23 +00:00
o = ss . taboption ( 'macfilter' , form . ListValue , 'macfilter' , _ ( 'MAC Address Filter' ) ) ;
2020-03-27 09:27:18 +00:00
o . depends ( 'mode' , 'ap' ) ;
o . depends ( 'mode' , 'ap-wds' ) ;
o . value ( '' , _ ( 'disable' ) ) ;
o . value ( 'allow' , _ ( 'Allow listed only' ) ) ;
o . value ( 'deny' , _ ( 'Allow all except listed' ) ) ;
o = ss . taboption ( 'macfilter' , form . DynamicList , 'maclist' , _ ( 'MAC-List' ) ) ;
o . datatype = 'macaddr' ;
2023-11-27 15:37:15 +00:00
o . retain = true ;
2020-03-27 09:27:18 +00:00
o . depends ( 'macfilter' , 'allow' ) ;
o . depends ( 'macfilter' , 'deny' ) ;
o . load = function ( section _id ) {
return network . getHostHints ( ) . then ( L . bind ( function ( hints ) {
hints . getMACHints ( ) . map ( L . bind ( function ( hint ) {
this . value ( hint [ 0 ] , hint [ 1 ] ? '%s (%s)' . format ( hint [ 0 ] , hint [ 1 ] ) : hint [ 0 ] ) ;
} , this ) ) ;
return form . DynamicList . prototype . load . apply ( this , [ section _id ] ) ;
} , this ) ) ;
} ;
mode . value ( 'ap-wds' , '%s (%s)' . format ( _ ( 'Access Point' ) , _ ( 'WDS' ) ) ) ;
mode . value ( 'sta-wds' , '%s (%s)' . format ( _ ( 'Client' ) , _ ( 'WDS' ) ) ) ;
mode . write = function ( section _id , value ) {
switch ( value ) {
case 'ap-wds' :
uci . set ( 'wireless' , section _id , 'mode' , 'ap' ) ;
uci . set ( 'wireless' , section _id , 'wds' , '1' ) ;
break ;
case 'sta-wds' :
uci . set ( 'wireless' , section _id , 'mode' , 'sta' ) ;
uci . set ( 'wireless' , section _id , 'wds' , '1' ) ;
break ;
default :
uci . set ( 'wireless' , section _id , 'mode' , value ) ;
uci . unset ( 'wireless' , section _id , 'wds' ) ;
break ;
}
} ;
mode . cfgvalue = function ( section _id ) {
var mode = uci . get ( 'wireless' , section _id , 'mode' ) ,
wds = uci . get ( 'wireless' , section _id , 'wds' ) ;
if ( mode == 'ap' && wds )
return 'ap-wds' ;
else if ( mode == 'sta' && wds )
return 'sta-wds' ;
return mode ;
} ;
2021-06-25 17:45:23 +00:00
o = ss . taboption ( 'general' , form . Flag , 'hidden' , _ ( 'Hide <abbr title="Extended Service Set Identifier">ESSID</abbr>' ) , _ ( 'Where the ESSID is hidden, clients may fail to roam and airtime efficiency may be significantly reduced.' ) ) ;
2020-03-27 09:27:18 +00:00
o . depends ( 'mode' , 'ap' ) ;
o . depends ( 'mode' , 'ap-wds' ) ;
2021-06-25 17:45:23 +00:00
o = ss . taboption ( 'general' , form . Flag , 'wmm' , _ ( 'WMM Mode' ) , _ ( 'Where Wi-Fi Multimedia (WMM) Mode QoS is disabled, clients may be limited to 802.11a/802.11g rates.' ) ) ;
2020-03-27 09:27:18 +00:00
o . depends ( 'mode' , 'ap' ) ;
o . depends ( 'mode' , 'ap-wds' ) ;
o . default = o . enabled ;
2023-11-27 15:37:15 +00:00
/* https://w1.fi/cgit/hostap/commit/?id=34f7c699a6bcb5c45f82ceb6743354ad79296078 */
/* multicast_to_unicast https://github.com/openwrt/openwrt/commit/7babb978ad9d7fc29acb1ff86afb1eb343af303a */
o = ss . taboption ( 'advanced' , form . Flag , 'multicast_to_unicast_all' , _ ( 'Multi To Unicast' ) , _ ( 'ARP, IPv4 and IPv6 (even 802.1Q) with multicast destination MACs are unicast to the STA MAC address. Note: This is not Directed Multicast Service (DMS) in 802.11v. Note: might break receiver STA multicast expectations.' ) ) ;
o . rmempty = true ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'advanced' , form . Flag , 'isolate' , _ ( 'Isolate Clients' ) , _ ( 'Prevents client-to-client communication' ) ) ;
o . depends ( 'mode' , 'ap' ) ;
o . depends ( 'mode' , 'ap-wds' ) ;
o = ss . taboption ( 'advanced' , form . Value , 'ifname' , _ ( 'Interface name' ) , _ ( 'Override default interface name' ) ) ;
o . optional = true ;
2023-11-27 15:37:15 +00:00
o . datatype = 'netdevname' ;
2020-03-27 09:27:18 +00:00
o . placeholder = radioNet . getIfname ( ) ;
if ( /^radio\d+\.network/ . test ( o . placeholder ) )
o . placeholder = '' ;
2023-11-27 15:37:15 +00:00
var macaddr = uci . get ( 'wireless' , radioNet . getName ( ) , 'macaddr' ) ;
o = ss . taboption ( 'advanced' , form . Value , 'macaddr' , _ ( 'MAC address' ) , _ ( 'Override default MAC address - the range of usable addresses might be limited by the driver' ) ) ;
o . value ( '' , _ ( 'driver default (%s)' ) . format ( ! macaddr ? radioNet . getActiveBSSID ( ) : _ ( 'no override' ) ) ) ;
o . value ( 'random' , _ ( 'randomly generated' ) ) ;
o . datatype = "or('random',macaddr)" ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'advanced' , form . Flag , 'short_preamble' , _ ( 'Short Preamble' ) ) ;
o . default = o . enabled ;
o = ss . taboption ( 'advanced' , form . Value , 'dtim_period' , _ ( 'DTIM Interval' ) , _ ( 'Delivery Traffic Indication Message Interval' ) ) ;
o . optional = true ;
o . placeholder = 2 ;
o . datatype = 'range(1,255)' ;
o = ss . taboption ( 'advanced' , form . Value , 'wpa_group_rekey' , _ ( 'Time interval for rekeying GTK' ) , _ ( 'sec' ) ) ;
o . optional = true ;
o . placeholder = 600 ;
o . datatype = 'uinteger' ;
o = ss . taboption ( 'advanced' , form . Flag , 'skip_inactivity_poll' , _ ( 'Disable Inactivity Polling' ) ) ;
o . optional = true ;
o . datatype = 'uinteger' ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'advanced' , form . Value , 'max_inactivity' , _ ( 'Station inactivity limit' ) , _ ( '802.11v: BSS Max Idle. Units: seconds.' ) ) ;
2020-03-27 09:27:18 +00:00
o . optional = true ;
o . placeholder = 300 ;
o . datatype = 'uinteger' ;
o = ss . taboption ( 'advanced' , form . Value , 'max_listen_interval' , _ ( 'Maximum allowed Listen Interval' ) ) ;
o . optional = true ;
o . placeholder = 65535 ;
o . datatype = 'uinteger' ;
o = ss . taboption ( 'advanced' , form . Flag , 'disassoc_low_ack' , _ ( 'Disassociate On Low Acknowledgement' ) , _ ( 'Allow AP mode to disconnect STAs based on low ACK condition' ) ) ;
o . default = o . enabled ;
}
encr = o = ss . taboption ( 'encryption' , form . ListValue , 'encryption' , _ ( 'Encryption' ) ) ;
o . depends ( 'mode' , 'ap' ) ;
o . depends ( 'mode' , 'sta' ) ;
o . depends ( 'mode' , 'adhoc' ) ;
o . depends ( 'mode' , 'ahdemo' ) ;
o . depends ( 'mode' , 'ap-wds' ) ;
o . depends ( 'mode' , 'sta-wds' ) ;
o . depends ( 'mode' , 'mesh' ) ;
o . cfgvalue = function ( section _id ) {
var v = String ( uci . get ( 'wireless' , section _id , 'encryption' ) ) ;
if ( v == 'wep' )
return 'wep-open' ;
else if ( v . match ( /\+/ ) )
return v . replace ( /\+.+$/ , '' ) ;
return v ;
} ;
o . write = function ( section _id , value ) {
var e = this . section . children . filter ( function ( o ) { return o . option == 'encryption' } ) [ 0 ] . formvalue ( section _id ) ,
co = this . section . children . filter ( function ( o ) { return o . option == 'cipher' } ) [ 0 ] , c = co . formvalue ( section _id ) ;
2020-04-09 12:39:09 +00:00
if ( value == 'wpa' || value == 'wpa2' || value == 'wpa3' || value == 'wpa3-mixed' )
2020-03-27 09:27:18 +00:00
uci . unset ( 'wireless' , section _id , 'key' ) ;
if ( co . isActive ( section _id ) && e && ( c == 'tkip' || c == 'ccmp' || c == 'tkip+ccmp' ) )
e += '+' + c ;
uci . set ( 'wireless' , section _id , 'encryption' , e ) ;
} ;
o = ss . taboption ( 'encryption' , form . ListValue , 'cipher' , _ ( 'Cipher' ) ) ;
o . depends ( 'encryption' , 'wpa' ) ;
o . depends ( 'encryption' , 'wpa2' ) ;
2020-04-09 12:39:09 +00:00
o . depends ( 'encryption' , 'wpa3' ) ;
o . depends ( 'encryption' , 'wpa3-mixed' ) ;
2020-03-27 09:27:18 +00:00
o . depends ( 'encryption' , 'psk' ) ;
o . depends ( 'encryption' , 'psk2' ) ;
o . depends ( 'encryption' , 'wpa-mixed' ) ;
o . depends ( 'encryption' , 'psk-mixed' ) ;
o . value ( 'auto' , _ ( 'auto' ) ) ;
o . value ( 'ccmp' , _ ( 'Force CCMP (AES)' ) ) ;
2024-08-27 07:29:31 +00:00
o . value ( 'ccmp256' , _ ( 'Force CCMP-256 (AES)' ) ) ;
o . value ( 'gcmp' , _ ( 'Force GCMP (AES)' ) ) ;
o . value ( 'gcmp256' , _ ( 'Force GCMP-256 (AES)' ) ) ;
2020-03-27 09:27:18 +00:00
o . value ( 'tkip' , _ ( 'Force TKIP' ) ) ;
o . value ( 'tkip+ccmp' , _ ( 'Force TKIP and CCMP (AES)' ) ) ;
o . write = ss . children . filter ( function ( o ) { return o . option == 'encryption' } ) [ 0 ] . write ;
o . cfgvalue = function ( section _id ) {
var v = String ( uci . get ( 'wireless' , section _id , 'encryption' ) ) ;
if ( v . match ( /\+/ ) ) {
v = v . replace ( /^[^+]+\+/ , '' ) ;
if ( v == 'aes' )
v = 'ccmp' ;
else if ( v == 'tkip+aes' || v == 'aes+tkip' || v == 'ccmp+tkip' )
v = 'tkip+ccmp' ;
}
return v ;
} ;
var crypto _modes = [ ] ;
if ( hwtype == 'mac80211' ) {
var has _supplicant = L . hasSystemFeature ( 'wpasupplicant' ) ,
has _hostapd = L . hasSystemFeature ( 'hostapd' ) ;
// Probe EAP support
var has _ap _eap = L . hasSystemFeature ( 'hostapd' , 'eap' ) ,
has _sta _eap = L . hasSystemFeature ( 'wpasupplicant' , 'eap' ) ;
// Probe SAE support
var has _ap _sae = L . hasSystemFeature ( 'hostapd' , 'sae' ) ,
has _sta _sae = L . hasSystemFeature ( 'wpasupplicant' , 'sae' ) ;
// Probe OWE support
var has _ap _owe = L . hasSystemFeature ( 'hostapd' , 'owe' ) ,
has _sta _owe = L . hasSystemFeature ( 'wpasupplicant' , 'owe' ) ;
2020-04-09 12:39:09 +00:00
// Probe Suite-B support
var has _ap _eap192 = L . hasSystemFeature ( 'hostapd' , 'suiteb192' ) ,
has _sta _eap192 = L . hasSystemFeature ( 'wpasupplicant' , 'suiteb192' ) ;
2020-09-18 13:23:21 +00:00
// Probe WEP support
var has _ap _wep = L . hasSystemFeature ( 'hostapd' , 'wep' ) ,
has _sta _wep = L . hasSystemFeature ( 'wpasupplicant' , 'wep' ) ;
2020-03-27 09:27:18 +00:00
if ( has _hostapd || has _supplicant ) {
2020-04-09 12:39:09 +00:00
crypto _modes . push ( [ 'psk2' , 'WPA2-PSK' , 35 ] ) ;
2020-03-27 09:27:18 +00:00
crypto _modes . push ( [ 'psk-mixed' , 'WPA-PSK/WPA2-PSK Mixed Mode' , 22 ] ) ;
2023-11-27 15:37:15 +00:00
crypto _modes . push ( [ 'psk' , 'WPA-PSK' , 12 ] ) ;
2020-03-27 09:27:18 +00:00
}
else {
encr . description = _ ( 'WPA-Encryption requires wpa_supplicant (for client mode) or hostapd (for AP and ad-hoc mode) to be installed.' ) ;
}
if ( has _ap _sae || has _sta _sae ) {
crypto _modes . push ( [ 'sae' , 'WPA3-SAE' , 31 ] ) ;
crypto _modes . push ( [ 'sae-mixed' , 'WPA2-PSK/WPA3-SAE Mixed Mode' , 30 ] ) ;
}
2020-09-18 13:23:21 +00:00
if ( has _ap _wep || has _sta _wep ) {
crypto _modes . push ( [ 'wep-open' , _ ( 'WEP Open System' ) , 11 ] ) ;
crypto _modes . push ( [ 'wep-shared' , _ ( 'WEP Shared Key' ) , 10 ] ) ;
}
2020-03-27 09:27:18 +00:00
if ( has _ap _eap || has _sta _eap ) {
2020-04-09 12:39:09 +00:00
if ( has _ap _eap192 || has _sta _eap192 ) {
crypto _modes . push ( [ 'wpa3' , 'WPA3-EAP' , 33 ] ) ;
crypto _modes . push ( [ 'wpa3-mixed' , 'WPA2-EAP/WPA3-EAP Mixed Mode' , 32 ] ) ;
}
crypto _modes . push ( [ 'wpa2' , 'WPA2-EAP' , 34 ] ) ;
2020-03-27 09:27:18 +00:00
crypto _modes . push ( [ 'wpa' , 'WPA-EAP' , 20 ] ) ;
}
if ( has _ap _owe || has _sta _owe ) {
crypto _modes . push ( [ 'owe' , 'OWE' , 1 ] ) ;
}
encr . crypto _support = {
'ap' : {
2020-09-18 13:23:21 +00:00
'wep-open' : has _ap _wep || _ ( 'Requires hostapd with WEP support' ) ,
'wep-shared' : has _ap _wep || _ ( 'Requires hostapd with WEP support' ) ,
2020-03-27 09:27:18 +00:00
'psk' : has _hostapd || _ ( 'Requires hostapd' ) ,
'psk2' : has _hostapd || _ ( 'Requires hostapd' ) ,
'psk-mixed' : has _hostapd || _ ( 'Requires hostapd' ) ,
'sae' : has _ap _sae || _ ( 'Requires hostapd with SAE support' ) ,
'sae-mixed' : has _ap _sae || _ ( 'Requires hostapd with SAE support' ) ,
'wpa' : has _ap _eap || _ ( 'Requires hostapd with EAP support' ) ,
'wpa2' : has _ap _eap || _ ( 'Requires hostapd with EAP support' ) ,
2020-04-09 12:39:09 +00:00
'wpa3' : has _ap _eap192 || _ ( 'Requires hostapd with EAP Suite-B support' ) ,
'wpa3-mixed' : has _ap _eap192 || _ ( 'Requires hostapd with EAP Suite-B support' ) ,
2020-03-27 09:27:18 +00:00
'owe' : has _ap _owe || _ ( 'Requires hostapd with OWE support' )
} ,
'sta' : {
2020-09-18 13:23:21 +00:00
'wep-open' : has _sta _wep || _ ( 'Requires wpa-supplicant with WEP support' ) ,
'wep-shared' : has _sta _wep || _ ( 'Requires wpa-supplicant with WEP support' ) ,
2020-03-27 09:27:18 +00:00
'psk' : has _supplicant || _ ( 'Requires wpa-supplicant' ) ,
'psk2' : has _supplicant || _ ( 'Requires wpa-supplicant' ) ,
'psk-mixed' : has _supplicant || _ ( 'Requires wpa-supplicant' ) ,
'sae' : has _sta _sae || _ ( 'Requires wpa-supplicant with SAE support' ) ,
'sae-mixed' : has _sta _sae || _ ( 'Requires wpa-supplicant with SAE support' ) ,
'wpa' : has _sta _eap || _ ( 'Requires wpa-supplicant with EAP support' ) ,
'wpa2' : has _sta _eap || _ ( 'Requires wpa-supplicant with EAP support' ) ,
2020-04-09 12:39:09 +00:00
'wpa3' : has _sta _eap192 || _ ( 'Requires wpa-supplicant with EAP Suite-B support' ) ,
'wpa3-mixed' : has _sta _eap192 || _ ( 'Requires wpa-supplicant with EAP Suite-B support' ) ,
2020-03-27 09:27:18 +00:00
'owe' : has _sta _owe || _ ( 'Requires wpa-supplicant with OWE support' )
} ,
'adhoc' : {
'wep-open' : true ,
'wep-shared' : true ,
'psk' : has _supplicant || _ ( 'Requires wpa-supplicant' ) ,
'psk2' : has _supplicant || _ ( 'Requires wpa-supplicant' ) ,
'psk-mixed' : has _supplicant || _ ( 'Requires wpa-supplicant' ) ,
} ,
'mesh' : {
'sae' : has _sta _sae || _ ( 'Requires wpa-supplicant with SAE support' )
} ,
'ahdemo' : {
'wep-open' : true ,
'wep-shared' : true
} ,
'wds' : {
'wep-open' : true ,
'wep-shared' : true
}
} ;
encr . crypto _support [ 'ap-wds' ] = encr . crypto _support [ 'ap' ] ;
encr . crypto _support [ 'sta-wds' ] = encr . crypto _support [ 'sta' ] ;
encr . validate = function ( section _id , value ) {
var modeopt = this . section . children . filter ( function ( o ) { return o . option == 'mode' } ) [ 0 ] ,
modeval = modeopt . formvalue ( section _id ) ,
modetitle = modeopt . vallist [ modeopt . keylist . indexOf ( modeval ) ] ,
enctitle = this . vallist [ this . keylist . indexOf ( value ) ] ;
if ( value == 'none' )
return true ;
if ( ! L . isObject ( this . crypto _support [ modeval ] ) || ! this . crypto _support [ modeval ] . hasOwnProperty ( value ) )
return _ ( 'The selected %s mode is incompatible with %s encryption' ) . format ( modetitle , enctitle ) ;
return this . crypto _support [ modeval ] [ value ] ;
} ;
}
else if ( hwtype == 'broadcom' ) {
crypto _modes . push ( [ 'psk2' , 'WPA2-PSK' , 33 ] ) ;
crypto _modes . push ( [ 'psk+psk2' , 'WPA-PSK/WPA2-PSK Mixed Mode' , 22 ] ) ;
2023-11-27 15:37:15 +00:00
crypto _modes . push ( [ 'psk' , 'WPA-PSK' , 12 ] ) ;
2020-09-18 13:23:21 +00:00
crypto _modes . push ( [ 'wep-open' , _ ( 'WEP Open System' ) , 11 ] ) ;
crypto _modes . push ( [ 'wep-shared' , _ ( 'WEP Shared Key' ) , 10 ] ) ;
2020-03-27 09:27:18 +00:00
}
crypto _modes . push ( [ 'none' , _ ( 'No Encryption' ) , 0 ] ) ;
crypto _modes . sort ( function ( a , b ) { return b [ 2 ] - a [ 2 ] } ) ;
for ( var i = 0 ; i < crypto _modes . length ; i ++ ) {
var security _level = ( crypto _modes [ i ] [ 2 ] >= 30 ) ? _ ( 'strong security' )
: ( crypto _modes [ i ] [ 2 ] >= 20 ) ? _ ( 'medium security' )
: ( crypto _modes [ i ] [ 2 ] >= 10 ) ? _ ( 'weak security' ) : _ ( 'open network' ) ;
encr . value ( crypto _modes [ i ] [ 0 ] , '%s (%s)' . format ( crypto _modes [ i ] [ 1 ] , security _level ) ) ;
}
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'encryption' , form . Value , 'auth_server' , _ ( 'RADIUS Authentication Server' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o . rmempty = true ;
o . datatype = 'host(0)' ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'encryption' , form . Value , 'auth_port' , _ ( 'RADIUS Authentication Port' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o . rmempty = true ;
o . datatype = 'port' ;
2023-11-27 15:37:15 +00:00
o . placeholder = '1812' ;
2020-03-27 09:27:18 +00:00
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'encryption' , form . Value , 'auth_secret' , _ ( 'RADIUS Authentication Secret' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o . rmempty = true ;
o . password = true ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'encryption' , form . Value , 'acct_server' , _ ( 'RADIUS Accounting Server' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o . rmempty = true ;
o . datatype = 'host(0)' ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'encryption' , form . Value , 'acct_port' , _ ( 'RADIUS Accounting Port' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o . rmempty = true ;
o . datatype = 'port' ;
2023-11-27 15:37:15 +00:00
o . placeholder = '1813' ;
2020-03-27 09:27:18 +00:00
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'encryption' , form . Value , 'acct_secret' , _ ( 'RADIUS Accounting Secret' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o . rmempty = true ;
o . password = true ;
2023-11-27 15:37:15 +00:00
/* extra RADIUS settings start */
o = ss . taboption ( 'encryption' , form . ListValue , 'dynamic_vlan' , _ ( 'RADIUS Dynamic VLAN Assignment' ) , _ ( 'Required: Rejects auth if RADIUS server does not provide appropriate VLAN attributes.' ) ) ;
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
o . value ( '0' , _ ( 'Disabled' ) ) ;
o . value ( '1' , _ ( 'Optional' ) ) ;
o . value ( '2' , _ ( 'Required' ) ) ;
o . write = function ( section _id , value ) {
return this . super ( 'write' , [ section _id , ( value == 0 ) ? null : value ] ) ;
}
o = ss . taboption ( 'encryption' , form . Flag , 'per_sta_vif' , _ ( 'RADIUS Per STA VLAN' ) , _ ( 'Each STA is assigned its own AP_VLAN interface.' ) ) ;
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
//hostapd internally defaults to vlan_naming=1 even with dynamic VLAN off
o = ss . taboption ( 'encryption' , form . Flag , 'vlan_naming' , _ ( 'RADIUS VLAN Naming' ) , _ ( 'Off: <code>vlanXXX</code>, e.g., <code>vlan1</code>. On: <code>vlan_tagged_interface.XXX</code>, e.g. <code>eth0.1</code>.' ) ) ;
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
o = ss . taboption ( 'encryption' , widgets . DeviceSelect , 'vlan_tagged_interface' , _ ( 'RADIUS VLAN Tagged Interface' ) , _ ( 'E.g. eth0, eth1' ) ) ;
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
o . size = 1 ;
o . rmempty = true ;
o . multiple = false ;
o . noaliases = true ;
o . nocreate = true ;
o . noinactive = true ;
o = ss . taboption ( 'encryption' , form . Value , 'vlan_bridge' , _ ( 'RADIUS VLAN Bridge Naming Scheme' ) , _ ( 'E.g. <code>br-vlan</code> or <code>brvlan</code>.' ) ) ;
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
o . rmempty = true ;
/* extra RADIUS settings end */
o = ss . taboption ( 'encryption' , form . Value , 'dae_client' , _ ( 'DAE-Client' ) , _ ( 'Dynamic Authorization Extension client.' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o . rmempty = true ;
o . datatype = 'host(0)' ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'encryption' , form . Value , 'dae_port' , _ ( 'DAE-Port' ) , _ ( 'Dynamic Authorization Extension port.' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o . rmempty = true ;
o . datatype = 'port' ;
2023-11-27 15:37:15 +00:00
o . placeholder = '3799' ;
2020-03-27 09:27:18 +00:00
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'encryption' , form . Value , 'dae_secret' , _ ( 'DAE-Secret' ) , _ ( 'Dynamic Authorization Extension secret.' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o . rmempty = true ;
o . password = true ;
2023-11-27 15:37:15 +00:00
//WPA(1) has only WPA IE. Only >= WPA2 has RSN IE Preauth frames.
o = ss . taboption ( 'encryption' , form . Flag , 'rsn_preauth' , _ ( 'RSN Preauth' ) , _ ( 'Robust Security Network (RSN): Allow roaming preauth for WPA2-EAP networks (and advertise it in WLAN beacons). Only works if the specified network interface is a bridge. Shortens the time-critical reassociation process.' ) ) ;
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . Value , '_wpa_key' , _ ( 'Key' ) ) ;
o . depends ( 'encryption' , 'psk' ) ;
o . depends ( 'encryption' , 'psk2' ) ;
o . depends ( 'encryption' , 'psk+psk2' ) ;
o . depends ( 'encryption' , 'psk-mixed' ) ;
o . depends ( 'encryption' , 'sae' ) ;
o . depends ( 'encryption' , 'sae-mixed' ) ;
o . datatype = 'wpakey' ;
o . rmempty = true ;
o . password = true ;
o . cfgvalue = function ( section _id ) {
var key = uci . get ( 'wireless' , section _id , 'key' ) ;
return /^[1234]$/ . test ( key ) ? null : key ;
} ;
o . write = function ( section _id , value ) {
uci . set ( 'wireless' , section _id , 'key' , value ) ;
uci . unset ( 'wireless' , section _id , 'key1' ) ;
uci . unset ( 'wireless' , section _id , 'key2' ) ;
uci . unset ( 'wireless' , section _id , 'key3' ) ;
uci . unset ( 'wireless' , section _id , 'key4' ) ;
} ;
o = ss . taboption ( 'encryption' , form . ListValue , '_wep_key' , _ ( 'Used Key Slot' ) ) ;
o . depends ( 'encryption' , 'wep-open' ) ;
o . depends ( 'encryption' , 'wep-shared' ) ;
o . value ( '1' , _ ( 'Key #%d' ) . format ( 1 ) ) ;
o . value ( '2' , _ ( 'Key #%d' ) . format ( 2 ) ) ;
o . value ( '3' , _ ( 'Key #%d' ) . format ( 3 ) ) ;
o . value ( '4' , _ ( 'Key #%d' ) . format ( 4 ) ) ;
o . cfgvalue = function ( section _id ) {
var slot = + uci . get ( 'wireless' , section _id , 'key' ) ;
return ( slot >= 1 && slot <= 4 ) ? String ( slot ) : '' ;
} ;
o . write = function ( section _id , value ) {
uci . set ( 'wireless' , section _id , 'key' , value ) ;
} ;
for ( var slot = 1 ; slot <= 4 ; slot ++ ) {
o = ss . taboption ( 'encryption' , form . Value , 'key%d' . format ( slot ) , _ ( 'Key #%d' ) . format ( slot ) ) ;
o . depends ( 'encryption' , 'wep-open' ) ;
o . depends ( 'encryption' , 'wep-shared' ) ;
o . datatype = 'wepkey' ;
o . rmempty = true ;
o . password = true ;
o . write = function ( section _id , value ) {
if ( value != null && ( value . length == 5 || value . length == 13 ) )
value = 's:%s' . format ( value ) ;
uci . set ( 'wireless' , section _id , this . option , value ) ;
} ;
}
if ( hwtype == 'mac80211' ) {
// Probe 802.11r support (and EAP support as a proxy for Openwrt)
var has _80211r = L . hasSystemFeature ( 'hostapd' , '11r' ) || L . hasSystemFeature ( 'hostapd' , 'eap' ) ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'roaming' , form . Flag , 'ieee80211r' , _ ( '802.11r Fast Transition' ) , _ ( 'Enables fast roaming among access points that belong to the same Mobility Domain' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
if ( has _80211r )
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'psk' , 'psk2' , 'psk-mixed' , 'sae' , 'sae-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o . rmempty = true ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'roaming' , form . Value , 'nasid' , _ ( 'NAS ID' ) , _ ( 'Used for two different purposes: RADIUS NAS ID and 802.11r R0KH-ID. Not needed with normal WPA(2)-PSK.' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o . depends ( { ieee80211r : '1' } ) ;
o . rmempty = true ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'roaming' , form . Value , 'mobility_domain' , _ ( 'Mobility Domain' ) , _ ( '4-character hexadecimal ID' ) ) ;
2020-03-27 09:27:18 +00:00
o . depends ( { ieee80211r : '1' } ) ;
o . placeholder = '4f57' ;
o . datatype = 'and(hexstring,length(4))' ;
o . rmempty = true ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'roaming' , form . Value , 'reassociation_deadline' , _ ( 'Reassociation Deadline' ) , _ ( 'time units (TUs / 1.024 ms) [1000-65535]' ) ) ;
2020-03-27 09:27:18 +00:00
o . depends ( { ieee80211r : '1' } ) ;
o . placeholder = '1000' ;
o . datatype = 'range(1000,65535)' ;
o . rmempty = true ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'roaming' , form . ListValue , 'ft_over_ds' , _ ( 'FT protocol' ) ) ;
2020-03-27 09:27:18 +00:00
o . depends ( { ieee80211r : '1' } ) ;
o . value ( '0' , _ ( 'FT over the Air' ) ) ;
2023-11-27 15:37:15 +00:00
o . value ( '1' , _ ( 'FT over DS' ) ) ;
2020-03-27 09:27:18 +00:00
o . rmempty = true ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'roaming' , form . Flag , 'ft_psk_generate_local' , _ ( 'Generate PMK locally' ) , _ ( 'When using a PSK, the PMK can be automatically generated. When enabled, the R0/R1 key options below are not applied. Disable this to use the R0 and R1 key options.' ) ) ;
2020-03-27 09:27:18 +00:00
o . depends ( { ieee80211r : '1' } ) ;
o . default = o . enabled ;
o . rmempty = false ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'roaming' , form . Value , 'r0_key_lifetime' , _ ( 'R0 Key Lifetime' ) , _ ( 'minutes' ) ) ;
2020-03-27 09:27:18 +00:00
o . depends ( { ieee80211r : '1' } ) ;
o . placeholder = '10000' ;
o . datatype = 'uinteger' ;
o . rmempty = true ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'roaming' , form . Value , 'r1_key_holder' , _ ( 'R1 Key Holder' ) , _ ( '6-octet identifier as a hex string - no colons' ) ) ;
2020-03-27 09:27:18 +00:00
o . depends ( { ieee80211r : '1' } ) ;
o . placeholder = '00004f577274' ;
o . datatype = 'and(hexstring,length(12))' ;
o . rmempty = true ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'roaming' , form . Flag , 'pmk_r1_push' , _ ( 'PMK R1 Push' ) ) ;
2020-03-27 09:27:18 +00:00
o . depends ( { ieee80211r : '1' } ) ;
o . placeholder = '0' ;
o . rmempty = true ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'roaming' , form . DynamicList , 'r0kh' , _ ( 'External R0 Key Holder List' ) , _ ( 'List of R0KHs in the same Mobility Domain. <br />Format: MAC-address,NAS-Identifier,256-bit key as hex string. <br />This list is used to map R0KH-ID (NAS Identifier) to a destination MAC address when requesting PMK-R1 key from the R0KH that the STA used during the Initial Mobility Domain Association.' ) ) ;
2020-03-27 09:27:18 +00:00
o . depends ( { ieee80211r : '1' } ) ;
o . rmempty = true ;
2023-11-27 15:37:15 +00:00
o = ss . taboption ( 'roaming' , form . DynamicList , 'r1kh' , _ ( 'External R1 Key Holder List' ) , _ ( 'List of R1KHs in the same Mobility Domain. <br />Format: MAC-address,R1KH-ID as 6 octets with colons,256-bit key as hex string. <br />This list is used to map R1KH-ID to a destination MAC address when sending PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD that can request PMK-R1 keys.' ) ) ;
2020-03-27 09:27:18 +00:00
o . depends ( { ieee80211r : '1' } ) ;
o . rmempty = true ;
// End of 802.11r options
2023-11-27 15:37:15 +00:00
// Probe 802.11k and 802.11v support via EAP support (full hostapd has EAP)
if ( L . hasSystemFeature ( 'hostapd' , 'eap' ) ) {
/* 802.11k settings start */ o =
ss . taboption ( 'roaming' , form . Flag , 'ieee80211k' , _ ( '802.11k RRM' ) , _ ( 'Radio Resource Measurement - Sends beacons to assist roaming. Not all clients support this.' ) ) ;
// add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['psk', 'psk2', 'psk-mixed', 'sae', 'sae-mixed'] });
o . depends ( 'mode' , 'ap' ) ;
o . depends ( 'mode' , 'ap-wds' ) ;
o = ss . taboption ( 'roaming' , form . Flag , 'rrm_neighbor_report' , _ ( 'Neighbour Report' ) , _ ( '802.11k: Enable neighbor report via radio measurements.' ) ) ;
o . depends ( { ieee80211k : '1' } ) ;
o . default = o . enabled ;
o = ss . taboption ( 'roaming' , form . Flag , 'rrm_beacon_report' , _ ( 'Beacon Report' ) , _ ( '802.11k: Enable beacon report via radio measurements.' ) ) ;
o . depends ( { ieee80211k : '1' } ) ;
o . default = o . enabled ;
/* 802.11k settings end */
/* 802.11v settings start */
o = ss . taboption ( 'roaming' , form . ListValue , 'time_advertisement' , _ ( 'Time advertisement' ) , _ ( '802.11v: Time Advertisement in management frames.' ) ) ;
o . value ( '0' , _ ( 'Disabled' ) ) ;
o . value ( '2' , _ ( 'Enabled' ) ) ;
o . write = function ( section _id , value ) {
return this . super ( 'write' , [ section _id , ( value == 2 ) ? value : null ] ) ;
}
//Pull current System TZ setting
var tz = uci . get ( 'system' , '@system[0]' , 'timezone' ) ;
o = ss . taboption ( 'roaming' , form . Value , 'time_zone' , _ ( 'Time zone' ) , _ ( '802.11v: Local Time Zone Advertisement in management frames.' ) ) ;
o . value ( tz ) ;
o . rmempty = true ;
o = ss . taboption ( 'roaming' , form . Flag , 'wnm_sleep_mode' , _ ( 'WNM Sleep Mode' ) , _ ( '802.11v: Wireless Network Management (WNM) Sleep Mode (extended sleep mode for stations).' ) ) ;
o . rmempty = true ;
/* wnm_sleep_mode_no_keys: https://git.openwrt.org/?p=openwrt/openwrt.git;a=commitdiff;h=bf98faaac8ed24cf7d3d93dd4fcd7304d109363b */
o = ss . taboption ( 'roaming' , form . Flag , 'wnm_sleep_mode_no_keys' , _ ( 'WNM Sleep Mode Fixes' ) , _ ( '802.11v: Wireless Network Management (WNM) Sleep Mode Fixes: Prevents reinstallation attacks.' ) ) ;
o . rmempty = true ;
o = ss . taboption ( 'roaming' , form . Flag , 'bss_transition' , _ ( 'BSS Transition' ) , _ ( '802.11v: Basic Service Set (BSS) transition management.' ) ) ;
o . rmempty = true ;
/* in master, but not 21.02.1: proxy_arp */
o = ss . taboption ( 'roaming' , form . Flag , 'proxy_arp' , _ ( 'ProxyARP' ) , _ ( '802.11v: Proxy ARP enables non-AP STA to remain in power-save for longer.' ) ) ;
o . rmempty = true ;
/* TODO: na_mcast_to_ucast is missing: needs adding to hostapd.sh - nice to have */
}
/* 802.11v settings end */
}
if ( hwtype == 'mac80211' ) {
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . ListValue , 'eap_type' , _ ( 'EAP-Method' ) ) ;
o . value ( 'tls' , 'TLS' ) ;
o . value ( 'ttls' , 'TTLS' ) ;
o . value ( 'peap' , 'PEAP' ) ;
o . value ( 'fast' , 'FAST' ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . Flag , 'ca_cert_usesystem' , _ ( 'Use system certificates' ) , _ ( "Validate server certificate using built-in system CA bundle,<br />requires the \"ca-bundle\" package" ) ) ;
o . enabled = '1' ;
o . disabled = '0' ;
o . default = o . disabled ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o . validate = function ( section _id , value ) {
if ( value == '1' && ! L . hasSystemFeature ( 'cabundle' ) ) {
return _ ( "This option cannot be used because the ca-bundle package is not installed." ) ;
}
return true ;
} ;
o = ss . taboption ( 'encryption' , form . FileUpload , 'ca_cert' , _ ( 'Path to CA-Certificate' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , ca _cert _usesystem : [ '0' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . Value , 'subject_match' , _ ( 'Certificate constraint (Subject)' ) , _ ( "Certificate constraint substring - e.g. /CN=wifi.mycompany.com<br />See `logread -f` during handshake for actual values" ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . DynamicList , 'altsubject_match' , _ ( 'Certificate constraint (SAN)' ) , _ ( "Certificate constraint(s) via Subject Alternate Name values<br />(supported attributes: EMAIL, DNS, URI) - e.g. DNS:wifi.mycompany.com" ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . DynamicList , 'domain_match' , _ ( 'Certificate constraint (Domain)' ) , _ ( "Certificate constraint(s) against DNS SAN values (if available)<br />or Subject CN (exact match)" ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . DynamicList , 'domain_suffix_match' , _ ( 'Certificate constraint (Wildcard)' ) , _ ( "Certificate constraint(s) against DNS SAN values (if available)<br />or Subject CN (suffix match)" ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . FileUpload , 'client_cert' , _ ( 'Path to Client-Certificate' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , eap _type : [ 'tls' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . FileUpload , 'priv_key' , _ ( 'Path to Private Key' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , eap _type : [ 'tls' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . Value , 'priv_key_pwd' , _ ( 'Password of Private Key' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , eap _type : [ 'tls' ] } ) ;
2020-03-27 09:27:18 +00:00
o . password = true ;
o = ss . taboption ( 'encryption' , form . ListValue , 'auth' , _ ( 'Authentication' ) ) ;
o . value ( 'PAP' , 'PAP' ) ;
o . value ( 'CHAP' , 'CHAP' ) ;
o . value ( 'MSCHAP' , 'MSCHAP' ) ;
o . value ( 'MSCHAPV2' , 'MSCHAPv2' ) ;
2020-04-09 12:39:09 +00:00
o . value ( 'EAP-GTC' , 'EAP-GTC' ) ;
o . value ( 'EAP-MD5' , 'EAP-MD5' ) ;
o . value ( 'EAP-MSCHAPV2' , 'EAP-MSCHAPv2' ) ;
o . value ( 'EAP-TLS' , 'EAP-TLS' ) ;
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , eap _type : [ 'fast' , 'peap' , 'ttls' ] } ) ;
2020-03-27 09:27:18 +00:00
o . validate = function ( section _id , value ) {
var eo = this . section . children . filter ( function ( o ) { return o . option == 'eap_type' } ) [ 0 ] ,
ev = eo . formvalue ( section _id ) ;
if ( ev != 'ttls' && ( value == 'PAP' || value == 'CHAP' || value == 'MSCHAP' || value == 'MSCHAPV2' ) )
return _ ( 'This authentication type is not applicable to the selected EAP method.' ) ;
return true ;
} ;
o = ss . taboption ( 'encryption' , form . Flag , 'ca_cert2_usesystem' , _ ( 'Use system certificates for inner-tunnel' ) , _ ( "Validate server certificate using built-in system CA bundle,<br />requires the \"ca-bundle\" package" ) ) ;
o . enabled = '1' ;
o . disabled = '0' ;
o . default = o . disabled ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , auth : [ 'EAP-TLS' ] } ) ;
2020-03-27 09:27:18 +00:00
o . validate = function ( section _id , value ) {
if ( value == '1' && ! L . hasSystemFeature ( 'cabundle' ) ) {
return _ ( "This option cannot be used because the ca-bundle package is not installed." ) ;
}
return true ;
} ;
o = ss . taboption ( 'encryption' , form . FileUpload , 'ca_cert2' , _ ( 'Path to inner CA-Certificate' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , auth : [ 'EAP-TLS' ] , ca _cert2 _usesystem : [ '0' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . Value , 'subject_match2' , _ ( 'Inner certificate constraint (Subject)' ) , _ ( "Certificate constraint substring - e.g. /CN=wifi.mycompany.com<br />See `logread -f` during handshake for actual values" ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , auth : [ 'EAP-TLS' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . DynamicList , 'altsubject_match2' , _ ( 'Inner certificate constraint (SAN)' ) , _ ( "Certificate constraint(s) via Subject Alternate Name values<br />(supported attributes: EMAIL, DNS, URI) - e.g. DNS:wifi.mycompany.com" ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , auth : [ 'EAP-TLS' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . DynamicList , 'domain_match2' , _ ( 'Inner certificate constraint (Domain)' ) , _ ( "Certificate constraint(s) against DNS SAN values (if available)<br />or Subject CN (exact match)" ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , auth : [ 'EAP-TLS' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . DynamicList , 'domain_suffix_match2' , _ ( 'Inner certificate constraint (Wildcard)' ) , _ ( "Certificate constraint(s) against DNS SAN values (if available)<br />or Subject CN (suffix match)" ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , auth : [ 'EAP-TLS' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . FileUpload , 'client_cert2' , _ ( 'Path to inner Client-Certificate' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , auth : [ 'EAP-TLS' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . FileUpload , 'priv_key2' , _ ( 'Path to inner Private Key' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , auth : [ 'EAP-TLS' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . Value , 'priv_key2_pwd' , _ ( 'Password of inner Private Key' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , auth : [ 'EAP-TLS' ] } ) ;
2020-03-27 09:27:18 +00:00
o . password = true ;
o = ss . taboption ( 'encryption' , form . Value , 'identity' , _ ( 'Identity' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , eap _type : [ 'fast' , 'peap' , 'tls' , 'ttls' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . Value , 'anonymous_identity' , _ ( 'Anonymous Identity' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , eap _type : [ 'fast' , 'peap' , 'tls' , 'ttls' ] } ) ;
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . Value , 'password' , _ ( 'Password' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'sta' , 'sta-wds' ] , encryption : [ 'wpa' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] , eap _type : [ 'fast' , 'peap' , 'ttls' ] } ) ;
2020-03-27 09:27:18 +00:00
o . password = true ;
if ( hwtype == 'mac80211' ) {
// ieee802.11w options
2021-06-25 17:45:23 +00:00
o = ss . taboption ( 'encryption' , form . ListValue , 'ieee80211w' , _ ( '802.11w Management Frame Protection' ) , _ ( "Note: Some wireless drivers do not fully support 802.11w. E.g. mwlwifi may have problems" ) ) ;
2023-11-27 15:37:15 +00:00
o . value ( '0' , _ ( 'Disabled' ) ) ;
2021-06-25 17:45:23 +00:00
o . value ( '1' , _ ( 'Optional' ) ) ;
o . value ( '2' , _ ( 'Required' ) ) ;
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' , 'sta' , 'sta-wds' ] , encryption : [ 'owe' , 'psk2' , 'psk-mixed' , 'sae' , 'sae-mixed' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
o . defaults = {
'2' : [ { encryption : 'sae' } , { encryption : 'owe' } , { encryption : 'wpa3' } , { encryption : 'wpa3-mixed' } ] ,
'1' : [ { encryption : 'sae-mixed' } ] ,
2023-11-27 15:37:15 +00:00
'0' : [ ]
} ;
o . write = function ( section _id , value ) {
if ( value != this . default )
return form . ListValue . prototype . write . call ( this , section _id , value ) ;
else
return form . ListValue . prototype . remove . call ( this , section _id ) ;
2020-03-27 09:27:18 +00:00
} ;
2021-06-25 17:45:23 +00:00
o = ss . taboption ( 'encryption' , form . Value , 'ieee80211w_max_timeout' , _ ( '802.11w maximum timeout' ) , _ ( '802.11w Association SA Query maximum timeout' ) ) ;
o . depends ( 'ieee80211w' , '1' ) ;
o . depends ( 'ieee80211w' , '2' ) ;
o . datatype = 'uinteger' ;
o . placeholder = '1000' ;
o . rmempty = true ;
o = ss . taboption ( 'encryption' , form . Value , 'ieee80211w_retry_timeout' , _ ( '802.11w retry timeout' ) , _ ( '802.11w Association SA Query retry timeout' ) ) ;
o . depends ( 'ieee80211w' , '1' ) ;
o . depends ( 'ieee80211w' , '2' ) ;
o . datatype = 'uinteger' ;
o . placeholder = '201' ;
o . rmempty = true ;
2024-10-21 13:26:28 +00:00
var version _omr = uci . get ( 'openmptcprouter' , 'settings' , 'version' ) || '' ;
if ( ! version _omr . includes ( '5.4' ) ) {
2024-10-12 06:26:05 +00:00
if ( L . hasSystemFeature ( 'hostapd' , 'ocv' ) || L . hasSystemFeature ( 'wpasupplicant' , 'ocv' ) ) {
o = ss . taboption ( 'encryption' , form . ListValue , 'ocv' , _ ( 'Operating Channel Validation' ) , _ ( "Note: Workaround mode allows a STA that claims OCV capability to connect even if the STA doesn't send OCI or negotiate PMF." ) ) ;
o . value ( '0' , _ ( 'Disabled' ) ) ;
o . value ( '1' , _ ( 'Enabled' ) ) ;
o . value ( '2' , _ ( 'Enabled (workaround mode)' ) ) ;
o . default = '0' ;
o . depends ( 'ieee80211w' , '1' ) ;
o . depends ( 'ieee80211w' , '2' ) ;
o . validate = function ( section _id , value ) {
var modeopt = this . section . children . filter ( function ( o ) { return o . option == 'mode' } ) [ 0 ] ,
modeval = modeopt . formvalue ( section _id ) ;
if ( ( value == '2' ) && ( ( modeval == 'sta' ) || ( modeval == 'sta-wds' ) ) ) {
return _ ( 'Workaround mode can only be used when acting as an access point.' ) ;
}
2024-08-27 07:29:31 +00:00
2024-10-12 06:26:05 +00:00
return true ;
}
2024-08-27 07:29:31 +00:00
}
}
2020-03-27 09:27:18 +00:00
o = ss . taboption ( 'encryption' , form . Flag , 'wpa_disable_eapol_key_retries' , _ ( 'Enable key reinstallation (KRACK) countermeasures' ) , _ ( 'Complicates key reinstallation attacks on the client side by disabling retransmission of EAPOL-Key frames that are used to install keys. This workaround might cause interoperability issues and reduced robustness of key negotiation especially in environments with heavy traffic load.' ) ) ;
2020-04-09 12:39:09 +00:00
add _dependency _permutations ( o , { mode : [ 'ap' , 'ap-wds' ] , encryption : [ 'psk2' , 'psk-mixed' , 'sae' , 'sae-mixed' , 'wpa2' , 'wpa3' , 'wpa3-mixed' ] } ) ;
2020-03-27 09:27:18 +00:00
2020-11-27 17:13:04 +00:00
if ( L . hasSystemFeature ( 'hostapd' , 'wps' ) && L . hasSystemFeature ( 'wpasupplicant' ) ) {
2020-03-27 09:27:18 +00:00
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' ) ;
}
}
}
} ) ;
} ;
s . handleRemove = function ( section _id , ev ) {
document . querySelector ( '.cbi-section-table-row[data-sid="%s"]' . format ( section _id ) ) . style . opacity = 0.5 ;
return form . TypedSection . prototype . handleRemove . apply ( this , [ section _id , ev ] ) ;
} ;
s . handleScan = function ( radioDev , ev ) {
2020-12-03 10:26:41 +00:00
var table = E ( 'table' , { 'class' : 'table' } , [
E ( 'tr' , { 'class' : 'tr table-titles' } , [
E ( 'th' , { 'class' : 'th col-2 middle center' } , _ ( 'Signal' ) ) ,
E ( 'th' , { 'class' : 'th col-4 middle left' } , _ ( 'SSID' ) ) ,
E ( 'th' , { 'class' : 'th col-2 middle center hide-xs' } , _ ( 'Channel' ) ) ,
E ( 'th' , { 'class' : 'th col-2 middle left hide-xs' } , _ ( 'Mode' ) ) ,
E ( 'th' , { 'class' : 'th col-3 middle left hide-xs' } , _ ( 'BSSID' ) ) ,
E ( 'th' , { 'class' : 'th col-3 middle left' } , _ ( 'Encryption' ) ) ,
E ( 'th' , { 'class' : 'th cbi-section-actions right' } , ' ' ) ,
2020-03-27 09:27:18 +00:00
] )
] ) ;
var stop = E ( 'button' , {
'class' : 'btn' ,
'click' : L . bind ( this . handleScanStartStop , this ) ,
'style' : 'display:none' ,
'data-state' : 'stop'
} , _ ( 'Stop refresh' ) ) ;
cbi _update _table ( table , [ ] , E ( 'em' , { class : 'spinning' } , _ ( 'Starting wireless scan...' ) ) ) ;
var md = ui . showModal ( _ ( 'Join Network: Wireless Scan' ) , [
table ,
E ( 'div' , { 'class' : 'right' } , [
stop ,
' ' ,
E ( 'button' , {
'class' : 'btn' ,
'click' : L . bind ( this . handleScanAbort , this )
} , _ ( 'Dismiss' ) )
] )
] ) ;
md . style . maxWidth = '90%' ;
md . style . maxHeight = 'none' ;
this . pollFn = L . bind ( this . handleScanRefresh , this , radioDev , { } , table , stop ) ;
2020-04-09 12:39:09 +00:00
poll . add ( this . pollFn ) ;
poll . start ( ) ;
2020-03-27 09:27:18 +00:00
} ;
s . handleScanRefresh = function ( radioDev , scanCache , table , stop ) {
return radioDev . getScanList ( ) . then ( L . bind ( function ( results ) {
var rows = [ ] ;
for ( var i = 0 ; i < results . length ; i ++ )
scanCache [ results [ i ] . bssid ] = results [ i ] ;
for ( var k in scanCache )
if ( scanCache [ k ] . stale )
results . push ( scanCache [ k ] ) ;
results . sort ( function ( a , b ) {
var diff = ( b . quality - a . quality ) || ( a . channel - b . channel ) ;
if ( diff )
return diff ;
if ( a . ssid < b . ssid )
return - 1 ;
else if ( a . ssid > b . ssid )
return 1 ;
if ( a . bssid < b . bssid )
return - 1 ;
else if ( a . bssid > b . bssid )
return 1 ;
} ) ;
for ( var i = 0 ; i < results . length ; i ++ ) {
var res = results [ i ] ,
qv = res . quality || 0 ,
qm = res . quality _max || 0 ,
q = ( qv > 0 && qm > 0 ) ? Math . floor ( ( 100 / qm ) * qv ) : 0 ,
s = res . stale ? 'opacity:0.5' : '' ;
rows . push ( [
E ( 'span' , { 'style' : s } , render _signal _badge ( q , res . signal , res . noise ) ) ,
E ( 'span' , { 'style' : s } , ( res . ssid != null ) ? '%h' . format ( res . ssid ) : E ( 'em' , _ ( 'hidden' ) ) ) ,
E ( 'span' , { 'style' : s } , '%d' . format ( res . channel ) ) ,
E ( 'span' , { 'style' : s } , '%h' . format ( res . mode ) ) ,
E ( 'span' , { 'style' : s } , '%h' . format ( res . bssid ) ) ,
E ( 'span' , { 'style' : s } , '%h' . format ( network . formatWifiEncryption ( res . encryption ) ) ) ,
E ( 'div' , { 'class' : 'right' } , E ( 'button' , {
'class' : 'cbi-button cbi-button-action important' ,
2020-11-27 17:13:04 +00:00
'click' : ui . createHandlerFn ( this , 'handleJoin' , radioDev , res )
2020-03-27 09:27:18 +00:00
} , _ ( 'Join Network' ) ) )
] ) ;
res . stale = true ;
}
cbi _update _table ( table , rows ) ;
stop . disabled = false ;
stop . style . display = '' ;
stop . classList . remove ( 'spinning' ) ;
} , this ) ) ;
} ;
s . handleScanStartStop = function ( ev ) {
var btn = ev . currentTarget ;
if ( btn . getAttribute ( 'data-state' ) == 'stop' ) {
2020-04-09 12:39:09 +00:00
poll . remove ( this . pollFn ) ;
2020-03-27 09:27:18 +00:00
btn . firstChild . data = _ ( 'Start refresh' ) ;
btn . setAttribute ( 'data-state' , 'start' ) ;
}
else {
2020-04-09 12:39:09 +00:00
poll . add ( this . pollFn ) ;
2020-03-27 09:27:18 +00:00
btn . firstChild . data = _ ( 'Stop refresh' ) ;
btn . setAttribute ( 'data-state' , 'stop' ) ;
btn . classList . add ( 'spinning' ) ;
btn . disabled = true ;
}
} ;
s . handleScanAbort = function ( ev ) {
2020-04-09 12:39:09 +00:00
var md = dom . parent ( ev . target , 'div[aria-modal="true"]' ) ;
2020-03-27 09:27:18 +00:00
if ( md ) {
md . style . maxWidth = '' ;
md . style . maxHeight = '' ;
}
ui . hideModal ( ) ;
2020-04-09 12:39:09 +00:00
poll . remove ( this . pollFn ) ;
2020-03-27 09:27:18 +00:00
this . pollFn = null ;
} ;
s . handleJoinConfirm = function ( radioDev , bss , form , ev ) {
var nameopt = L . toArray ( form . lookupOption ( 'name' , '_new_' ) ) [ 0 ] ,
passopt = L . toArray ( form . lookupOption ( 'password' , '_new_' ) ) [ 0 ] ,
2020-11-27 17:13:04 +00:00
ssidopt = L . toArray ( form . lookupOption ( 'ssid' , '_new_' ) ) [ 0 ] ,
2020-03-27 09:27:18 +00:00
bssidopt = L . toArray ( form . lookupOption ( 'bssid' , '_new_' ) ) [ 0 ] ,
zoneopt = L . toArray ( form . lookupOption ( 'zone' , '_new_' ) ) [ 0 ] ,
replopt = L . toArray ( form . lookupOption ( 'replace' , '_new_' ) ) [ 0 ] ,
nameval = ( nameopt && nameopt . isValid ( '_new_' ) ) ? nameopt . formvalue ( '_new_' ) : null ,
passval = ( passopt && passopt . isValid ( '_new_' ) ) ? passopt . formvalue ( '_new_' ) : null ,
2020-11-27 17:13:04 +00:00
ssidval = ( ssidopt && ssidopt . isValid ( '_new_' ) ) ? ssidopt . formvalue ( '_new_' ) : null ,
2020-03-27 09:27:18 +00:00
bssidval = ( bssidopt && bssidopt . isValid ( '_new_' ) ) ? bssidopt . formvalue ( '_new_' ) : null ,
zoneval = zoneopt ? zoneopt . formvalue ( '_new_' ) : null ,
enc = L . isObject ( bss . encryption ) ? bss . encryption : null ,
is _wep = ( enc && Array . isArray ( enc . wep ) ) ,
2020-11-27 17:13:04 +00:00
is _psk = ( enc && Array . isArray ( enc . wpa ) && L . toArray ( enc . authentication ) . filter ( function ( a ) { return a == 'psk' } ) . length > 0 ) ,
is _sae = ( enc && Array . isArray ( enc . wpa ) && L . toArray ( enc . authentication ) . filter ( function ( a ) { return a == 'sae' } ) . length > 0 ) ;
2020-03-27 09:27:18 +00:00
if ( nameval == null || ( passopt && passval == null ) )
return ;
var section _id = null ;
return this . map . save ( function ( ) {
var wifi _sections = uci . sections ( 'wireless' , 'wifi-iface' ) ;
if ( replopt . formvalue ( '_new_' ) == '1' ) {
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' ) ;
uci . unset ( 'wireless' , radioDev . getName ( ) , 'disabled' ) ;
}
2025-01-14 18:24:13 +00:00
var htmodes = radioDev . getHTModes ( ) ;
if ( bss . vht _operation && htmodes && htmodes . indexOf ( 'VHT20' ) !== - 1 ) {
for ( var w = bss . vht _operation . channel _width ; w >= 20 ; w /= 2 ) {
if ( htmodes . indexOf ( 'VHT' + w ) !== - 1 ) {
uci . set ( 'wireless' , radioDev . getName ( ) , 'htmode' , 'VHT' + w ) ;
break ;
}
}
}
else if ( bss . ht _operation && htmodes && htmodes . indexOf ( 'HT20' ) !== - 1 ) {
var w = ( bss . ht _operation . secondary _channel _offset == 'no secondary' ) ? 20 : 40 ;
uci . set ( 'wireless' , radioDev . getName ( ) , 'htmode' , 'HT' + w ) ;
}
else {
uci . remove ( 'wireless' , radioDev . getName ( ) , 'htmode' ) ;
}
uci . set ( 'wireless' , radioDev . getName ( ) , 'channel' , bss . channel ) ;
2020-03-27 09:27:18 +00:00
section _id = next _free _sid ( wifi _sections . length ) ;
uci . add ( 'wireless' , 'wifi-iface' , section _id ) ;
uci . set ( 'wireless' , section _id , 'device' , radioDev . getName ( ) ) ;
uci . set ( 'wireless' , section _id , 'mode' , ( bss . mode == 'Ad-Hoc' ) ? 'adhoc' : 'sta' ) ;
uci . set ( 'wireless' , section _id , 'network' , nameval ) ;
if ( bss . ssid != null ) {
uci . set ( 'wireless' , section _id , 'ssid' , bss . ssid ) ;
if ( bssidval == '1' )
uci . set ( 'wireless' , section _id , 'bssid' , bss . bssid ) ;
}
else if ( bss . bssid != null ) {
uci . set ( 'wireless' , section _id , 'bssid' , bss . bssid ) ;
}
2020-11-27 17:13:04 +00:00
if ( ssidval != null )
uci . set ( 'wireless' , section _id , 'ssid' , ssidval ) ;
2020-03-27 09:27:18 +00:00
if ( is _sae ) {
uci . set ( 'wireless' , section _id , 'encryption' , 'sae' ) ;
uci . set ( 'wireless' , section _id , 'key' , passval ) ;
}
else if ( is _psk ) {
for ( var i = enc . wpa . length - 1 ; i >= 0 ; i -- ) {
if ( enc . wpa [ i ] == 2 ) {
uci . set ( 'wireless' , section _id , 'encryption' , 'psk2' ) ;
break ;
}
else if ( enc . wpa [ i ] == 1 ) {
uci . set ( 'wireless' , section _id , 'encryption' , 'psk' ) ;
break ;
}
}
uci . set ( 'wireless' , section _id , 'key' , passval ) ;
}
else if ( is _wep ) {
uci . set ( 'wireless' , section _id , 'encryption' , 'wep-open' ) ;
uci . set ( 'wireless' , section _id , 'key' , '1' ) ;
uci . set ( 'wireless' , section _id , 'key1' , passval ) ;
}
else {
uci . set ( 'wireless' , section _id , 'encryption' , 'none' ) ;
}
return network . addNetwork ( nameval , { proto : 'dhcp' } ) . then ( function ( net ) {
firewall . deleteNetwork ( net . getName ( ) ) ;
var zonePromise = zoneval
? firewall . getZone ( zoneval ) . then ( function ( zone ) { return zone || firewall . addZone ( zoneval ) } )
: Promise . resolve ( ) ;
return zonePromise . then ( function ( zone ) {
if ( zone )
zone . addNetwork ( net . getName ( ) ) ;
} ) ;
} ) ;
} ) . then ( L . bind ( function ( ) {
2023-11-27 15:37:15 +00:00
ui . showModal ( null , E ( 'p' , { 'class' : 'spinning' } , [ _ ( 'Loading data…' ) ] ) ) ;
2020-03-27 09:27:18 +00:00
return this . renderMoreOptionsModal ( section _id ) ;
} , this ) ) ;
} ;
s . handleJoin = function ( radioDev , bss , ev ) {
2020-11-27 17:13:04 +00:00
poll . remove ( this . pollFn ) ;
2020-03-27 09:27:18 +00:00
var m2 = new form . Map ( 'wireless' ) ,
s2 = m2 . section ( form . NamedSection , '_new_' ) ,
enc = L . isObject ( bss . encryption ) ? bss . encryption : null ,
is _wep = ( enc && Array . isArray ( enc . wep ) ) ,
is _psk = ( enc && Array . isArray ( enc . wpa ) && L . toArray ( enc . authentication ) . filter ( function ( a ) { return a == 'psk' || a == 'sae' } ) ) ,
replace , passphrase , name , bssid , zone ;
var nameUsed = function ( name ) {
var s = uci . get ( 'network' , name ) ;
if ( s != null && s [ '.type' ] != 'interface' )
return true ;
var net = ( s != null ) ? network . instantiateNetwork ( name ) : null ;
return ( net != null && ! net . isEmpty ( ) ) ;
} ;
s2 . render = function ( ) {
return Promise . all ( [
{ } ,
this . renderUCISection ( '_new_' )
] ) . then ( this . renderContents . bind ( this ) ) ;
} ;
2020-11-27 17:13:04 +00:00
if ( bss . ssid == null ) {
name = s2 . option ( form . Value , 'ssid' , _ ( 'Network SSID' ) , _ ( 'The correct SSID must be manually specified when joining a hidden wireless network' ) ) ;
name . rmempty = false ;
} ;
2020-03-27 09:27:18 +00:00
replace = s2 . option ( form . Flag , 'replace' , _ ( 'Replace wireless configuration' ) , _ ( 'Check this option to delete the existing networks from this radio.' ) ) ;
name = s2 . option ( form . Value , 'name' , _ ( 'Name of the new network' ) , _ ( 'The allowed characters are: <code>A-Z</code>, <code>a-z</code>, <code>0-9</code> and <code>_</code>' ) ) ;
name . datatype = 'uciname' ;
name . default = 'wwan' ;
name . rmempty = false ;
name . validate = function ( section _id , value ) {
if ( nameUsed ( value ) )
return _ ( 'The network name is already used' ) ;
return true ;
} ;
for ( var i = 2 ; nameUsed ( name . default ) ; i ++ )
name . default = 'wwan%d' . format ( i ) ;
if ( is _wep || is _psk ) {
passphrase = s2 . option ( form . Value , 'password' , is _wep ? _ ( 'WEP passphrase' ) : _ ( 'WPA passphrase' ) , _ ( 'Specify the secret encryption key here.' ) ) ;
passphrase . datatype = is _wep ? 'wepkey' : 'wpakey' ;
passphrase . password = true ;
passphrase . rmempty = false ;
}
if ( bss . ssid != null ) {
bssid = s2 . option ( form . Flag , 'bssid' , _ ( 'Lock to BSSID' ) , _ ( 'Instead of joining any network with a matching SSID, only connect to the BSSID <code>%h</code>.' ) . format ( bss . bssid ) ) ;
bssid . default = '0' ;
}
2020-04-09 12:39:09 +00:00
zone = s2 . option ( widgets . ZoneSelect , 'zone' , _ ( 'Create / Assign firewall-zone' ) , _ ( 'Choose the firewall zone you want to assign to this interface. Select <em>unspecified</em> to remove the interface from the associated zone or fill out the <em>custom</em> field to define a new zone and attach the interface to it.' ) ) ;
2020-03-27 09:27:18 +00:00
zone . default = 'wan' ;
return m2 . render ( ) . then ( L . bind ( function ( nodes ) {
ui . showModal ( _ ( 'Joining Network: %q' ) . replace ( /%q/ , '"%h"' . format ( bss . ssid ) ) , [
nodes ,
E ( 'div' , { 'class' : 'right' } , [
E ( 'button' , {
'class' : 'btn' ,
'click' : ui . hideModal
} , _ ( 'Cancel' ) ) , ' ' ,
E ( 'button' , {
'class' : 'cbi-button cbi-button-positive important' ,
'click' : ui . createHandlerFn ( this , 'handleJoinConfirm' , radioDev , bss , m2 )
} , _ ( 'Submit' ) )
] )
] , 'cbi-modal' ) . querySelector ( '[id="%s"] input[class][type]' . format ( ( passphrase || name ) . cbid ( '_new_' ) ) ) . focus ( ) ;
} , this ) ) ;
} ;
s . handleAdd = function ( radioDev , ev ) {
var section _id = next _free _sid ( uci . sections ( 'wireless' , 'wifi-iface' ) . length ) ;
uci . unset ( 'wireless' , radioDev . getName ( ) , 'disabled' ) ;
uci . add ( 'wireless' , 'wifi-iface' , section _id ) ;
uci . set ( 'wireless' , section _id , 'device' , radioDev . getName ( ) ) ;
uci . set ( 'wireless' , section _id , 'mode' , 'ap' ) ;
uci . set ( 'wireless' , section _id , 'ssid' , 'OpenWrt' ) ;
uci . set ( 'wireless' , section _id , 'encryption' , 'none' ) ;
this . addedSection = section _id ;
return this . renderMoreOptionsModal ( section _id ) ;
} ;
o = s . option ( form . DummyValue , '_badge' ) ;
o . modalonly = false ;
o . textvalue = function ( section _id ) {
var inst = this . section . lookupRadioOrNetwork ( section _id ) ,
node = E ( 'div' , { 'class' : 'center' } ) ;
if ( inst . getWifiNetworks )
node . appendChild ( render _radio _badge ( inst ) ) ;
else
node . appendChild ( render _network _badge ( inst ) ) ;
return node ;
} ;
o = s . option ( form . DummyValue , '_stat' ) ;
o . modalonly = false ;
o . textvalue = function ( section _id ) {
var inst = this . section . lookupRadioOrNetwork ( section _id ) ;
if ( inst . getWifiNetworks )
return render _radio _status ( inst , this . section . wifis . filter ( function ( e ) {
return ( e . getWifiDeviceName ( ) == inst . getName ( ) ) ;
} ) ) ;
else
return render _network _status ( inst ) ;
} ;
return m . render ( ) . then ( L . bind ( function ( m , nodes ) {
2020-04-09 12:39:09 +00:00
poll . add ( L . bind ( function ( ) {
2020-03-27 09:27:18 +00:00
var section _ids = m . children [ 0 ] . cfgsections ( ) ,
tasks = [ network . getHostHints ( ) , network . getWifiDevices ( ) ] ;
for ( var i = 0 ; i < section _ids . length ; i ++ ) {
var row = nodes . querySelector ( '.cbi-section-table-row[data-sid="%s"]' . format ( section _ids [ i ] ) ) ,
dsc = row . querySelector ( '[data-name="_stat"] > div' ) ,
btns = row . querySelectorAll ( '.cbi-section-actions button' ) ;
if ( dsc . getAttribute ( 'restart' ) == '' ) {
dsc . setAttribute ( 'restart' , '1' ) ;
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' ) ;
btns [ 0 ] . classList . remove ( 'spinning' ) ;
btns [ 0 ] . disabled = false ;
}
}
return Promise . all ( tasks )
. then ( L . bind ( function ( hosts _radios ) {
var tasks = [ ] ;
for ( var i = 0 ; i < hosts _radios [ 1 ] . length ; i ++ )
tasks . push ( hosts _radios [ 1 ] [ i ] . getWifiNetworks ( ) ) ;
return Promise . all ( tasks ) . then ( function ( data ) {
hosts _radios [ 2 ] = [ ] ;
for ( var i = 0 ; i < data . length ; i ++ )
hosts _radios [ 2 ] . push . apply ( hosts _radios [ 2 ] , data [ i ] ) ;
return hosts _radios ;
} ) ;
} , network ) )
. then ( L . bind ( function ( hosts _radios _wifis ) {
var tasks = [ ] ;
for ( var i = 0 ; i < hosts _radios _wifis [ 2 ] . length ; i ++ )
tasks . push ( hosts _radios _wifis [ 2 ] [ i ] . getAssocList ( ) ) ;
return Promise . all ( tasks ) . then ( function ( data ) {
hosts _radios _wifis [ 3 ] = [ ] ;
for ( var i = 0 ; i < data . length ; i ++ ) {
var wifiNetwork = hosts _radios _wifis [ 2 ] [ i ] ,
radioDev = hosts _radios _wifis [ 1 ] . filter ( function ( d ) { return d . getName ( ) == wifiNetwork . getWifiDeviceName ( ) } ) [ 0 ] ;
for ( var j = 0 ; j < data [ i ] . length ; j ++ )
hosts _radios _wifis [ 3 ] . push ( Object . assign ( { radio : radioDev , network : wifiNetwork } , data [ i ] [ j ] ) ) ;
}
return hosts _radios _wifis ;
} ) ;
} , network ) )
. then ( L . bind ( this . poll _status , this , nodes ) ) ;
} , this ) , 5 ) ;
2020-12-03 10:26:41 +00:00
var table = E ( 'table' , { 'class' : 'table assoclist' , 'id' : 'wifi_assoclist_table' } , [
E ( 'tr' , { 'class' : 'tr table-titles' } , [
E ( 'th' , { 'class' : 'th nowrap' } , _ ( 'Network' ) ) ,
2021-06-25 17:45:23 +00:00
E ( 'th' , { 'class' : 'th hide-xs' } , _ ( 'MAC address' ) ) ,
2020-12-03 10:26:41 +00:00
E ( 'th' , { 'class' : 'th' } , _ ( 'Host' ) ) ,
E ( 'th' , { 'class' : 'th' } , _ ( 'Signal / Noise' ) ) ,
E ( 'th' , { 'class' : 'th' } , _ ( 'RX Rate / TX Rate' ) )
2020-03-27 09:27:18 +00:00
] )
] ) ;
cbi _update _table ( table , [ ] , E ( 'em' , { 'class' : 'spinning' } , _ ( 'Collecting data...' ) ) )
return E ( [ nodes , E ( 'h3' , _ ( 'Associated Stations' ) ) , table ] ) ;
} , this , m ) ) ;
2023-11-27 15:37:15 +00:00
} ,
handleReset : null
2020-03-27 09:27:18 +00:00
} ) ;