2020-07-27 15:12:54 +00:00
'use strict' ;
2020-07-28 18:51:10 +00:00
'require ui' ;
2021-06-11 08:18:10 +00:00
'require dom' ;
2020-07-27 15:12:54 +00:00
'require uci' ;
'require form' ;
'require network' ;
'require baseclass' ;
'require validation' ;
'require tools.widgets as widgets' ;
function validateAddr ( section _id , value ) {
if ( value == '' )
return true ;
var ipv6 = /6$/ . test ( this . section . formvalue ( section _id , 'mode' ) ) ,
addr = ipv6 ? validation . parseIPv6 ( value ) : validation . parseIPv4 ( value ) ;
return addr ? true : ( ipv6 ? _ ( 'Expecting a valid IPv6 address' ) : _ ( 'Expecting a valid IPv4 address' ) ) ;
}
function setIfActive ( section _id , value ) {
if ( this . isActive ( section _id ) ) {
uci . set ( 'network' , section _id , this . ucioption , value ) ;
/* Requires http://lists.openwrt.org/pipermail/openwrt-devel/2020-July/030397.html */
if ( false && this . option == 'ifname_multi' ) {
var devname = this . section . formvalue ( section _id , 'name_complex' ) ,
m = devname ? devname . match ( /^br-([A-Za-z0-9_]+)$/ ) : null ;
if ( m && uci . get ( 'network' , m [ 1 ] , 'type' ) == 'bridge' ) {
uci . set ( 'network' , m [ 1 ] , 'ifname' , devname ) ;
uci . unset ( 'network' , m [ 1 ] , 'type' ) ;
}
}
}
}
function validateQoSMap ( section _id , value ) {
if ( value == '' )
return true ;
var m = value . match ( /^(\d+):(\d+)$/ ) ;
if ( ! m || + m [ 1 ] > 0xFFFFFFFF || + m [ 2 ] > 0xFFFFFFFF )
return _ ( 'Expecting two priority values separated by a colon' ) ;
return true ;
}
2021-06-05 16:41:39 +00:00
function deviceSectionExists ( section _id , devname , ignore _type _match ) {
2020-07-27 15:12:54 +00:00
var exists = false ;
uci . sections ( 'network' , 'device' , function ( ss ) {
2021-06-05 16:41:39 +00:00
exists = exists || (
ss [ '.name' ] != section _id &&
ss . name == devname &&
( ! ignore _type _match || ! ignore _type _match . test ( ss . type || '' ) )
) ;
2020-07-27 15:12:54 +00:00
} ) ;
return exists ;
}
function isBridgePort ( dev ) {
if ( ! dev )
return false ;
if ( dev . isBridgePort ( ) )
return true ;
var isPort = false ;
uci . sections ( 'network' , null , function ( s ) {
if ( s [ '.type' ] != 'interface' && s [ '.type' ] != 'device' )
return ;
if ( s . type == 'bridge' && L . toArray ( s . ifname ) . indexOf ( dev . getName ( ) ) > - 1 )
isPort = true ;
} ) ;
return isPort ;
}
2021-06-11 08:18:10 +00:00
function updateDevBadge ( node , dev ) {
var type = dev . getType ( ) ,
up = dev . getCarrier ( ) ;
2020-07-28 18:51:10 +00:00
2021-06-11 08:18:10 +00:00
dom . content ( node , [
2020-07-28 18:51:10 +00:00
E ( 'img' , {
'class' : 'middle' ,
'src' : L . resource ( 'icons/%s%s.png' ) . format ( type , up ? '' : '_disabled' )
} ) ,
2021-03-18 16:19:42 +00:00
'\x0a' , dev . getName ( )
2020-07-28 18:51:10 +00:00
] ) ;
2021-06-11 08:18:10 +00:00
return node ;
}
function renderDevBadge ( dev ) {
return updateDevBadge ( E ( 'span' , {
'class' : 'ifacebadge port-status-device' ,
'style' : 'font-weight:normal' ,
'data-device' : dev . getName ( )
} ) , dev ) ;
}
function updatePortStatus ( node , dev ) {
var carrier = dev . getCarrier ( ) ,
duplex = dev . getDuplex ( ) ,
speed = dev . getSpeed ( ) ,
desc ;
if ( carrier && speed > 0 && duplex != null )
desc = E ( 'abbr' , {
'title' : '%d MBit/s, %s' . format ( speed , duplex == 'full' ? _ ( 'full-duplex' ) : _ ( 'half-duplex' ) )
} , [ '%d%s' . format ( speed , duplex == 'full' ? 'FD' : 'HD' ) ] ) ;
else if ( carrier )
desc = document . createTextNode ( _ ( 'Connected' ) ) ;
else
desc = document . createTextNode ( _ ( 'no link' ) ) ;
dom . content ( node , [ desc ] ) ;
return node ;
}
function renderPortStatus ( dev ) {
return updatePortStatus ( E ( 'span' , {
'class' : 'port-status-link' ,
'data-device' : dev . getName ( )
} ) , dev ) ;
2020-07-28 18:51:10 +00:00
}
2020-07-27 15:12:54 +00:00
function lookupDevName ( s , section _id ) {
var typeui = s . getUIElement ( section _id , 'type' ) ,
typeval = typeui ? typeui . getValue ( ) : s . cfgvalue ( section _id , 'type' ) ,
ifnameui = s . getUIElement ( section _id , 'ifname_single' ) ,
ifnameval = ifnameui ? ifnameui . getValue ( ) : s . cfgvalue ( section _id , 'ifname_single' ) ;
return ( typeval == 'bridge' ) ? 'br-%s' . format ( section _id ) : ifnameval ;
}
function lookupDevSection ( s , section _id , autocreate ) {
var devname = lookupDevName ( s , section _id ) ,
devsection = null ;
uci . sections ( 'network' , 'device' , function ( ds ) {
if ( ds . name == devname )
devsection = ds [ '.name' ] ;
} ) ;
if ( autocreate && ! devsection ) {
devsection = uci . add ( 'network' , 'device' ) ;
uci . set ( 'network' , devsection , 'name' , devname ) ;
}
return devsection ;
}
function getDeviceValue ( dev , method ) {
if ( dev && dev . getL3Device )
dev = dev . getL3Device ( ) ;
if ( dev && typeof ( dev [ method ] ) == 'function' )
return dev [ method ] . apply ( dev ) ;
return '' ;
}
function deviceCfgValue ( section _id ) {
if ( arguments . length == 2 )
return ;
var ds = lookupDevSection ( this . section , section _id , false ) ;
return ( ds ? uci . get ( 'network' , ds , this . option ) : null ) ||
2021-03-29 18:08:48 +00:00
( this . migrate ? uci . get ( 'network' , section _id , this . option ) : null ) ||
2020-07-27 15:12:54 +00:00
this . default ;
}
function deviceWrite ( section _id , formvalue ) {
var ds = lookupDevSection ( this . section , section _id , true ) ;
uci . set ( 'network' , ds , this . option , formvalue ) ;
2021-03-29 18:08:48 +00:00
if ( this . migrate )
uci . unset ( 'network' , section _id , this . option ) ;
2020-07-27 15:12:54 +00:00
}
function deviceRemove ( section _id ) {
2021-03-29 20:33:35 +00:00
var ds = lookupDevSection ( this . section , section _id , false ) ;
2020-07-27 15:12:54 +00:00
2021-03-29 20:33:35 +00:00
uci . unset ( 'network' , ds , this . option ) ;
2020-07-27 15:12:54 +00:00
2021-03-29 18:08:48 +00:00
if ( this . migrate )
uci . unset ( 'network' , section _id , this . option ) ;
2020-07-27 15:12:54 +00:00
}
function deviceRefresh ( section _id ) {
var dev = network . instantiateDevice ( lookupDevName ( this . section , section _id ) ) ,
uielem = this . getUIElement ( section _id ) ;
if ( uielem ) {
switch ( this . option ) {
case 'mtu' :
case 'mtu6' :
uielem . setPlaceholder ( dev . getMTU ( ) ) ;
break ;
case 'macaddr' :
uielem . setPlaceholder ( dev . getMAC ( ) ) ;
break ;
}
uielem . setValue ( this . cfgvalue ( section _id ) ) ;
}
}
2021-03-29 20:33:35 +00:00
function sectionParse ( ) {
var ds = lookupDevSection ( this , this . section , false ) ;
return form . NamedSection . prototype . parse . apply ( this ) . then ( function ( ) {
var sv = ds ? uci . get ( 'network' , ds ) : null ;
if ( sv ) {
var empty = true ;
for ( var opt in sv ) {
if ( opt . charAt ( 0 ) == '.' || opt == 'name' )
continue ;
empty = false ;
}
if ( empty )
uci . remove ( 'network' , ds ) ;
}
} ) ;
}
2020-07-28 18:51:10 +00:00
var cbiTagValue = form . Value . extend ( {
renderWidget : function ( section _id , option _index , cfgvalue ) {
var widget = new ui . Dropdown ( cfgvalue || [ '-' ] , {
'-' : E ( [ ] , [
E ( 'span' , { 'class' : 'hide-open' , 'style' : 'font-family:monospace' } , [ '—' ] ) ,
E ( 'span' , { 'class' : 'hide-close' } , [ _ ( 'Do not participate' , 'VLAN port state' ) ] )
] ) ,
'u' : E ( [ ] , [
E ( 'span' , { 'class' : 'hide-open' , 'style' : 'font-family:monospace' } , [ 'u' ] ) ,
E ( 'span' , { 'class' : 'hide-close' } , [ _ ( 'Egress untagged' , 'VLAN port state' ) ] )
] ) ,
't' : E ( [ ] , [
E ( 'span' , { 'class' : 'hide-open' , 'style' : 'font-family:monospace' } , [ 't' ] ) ,
E ( 'span' , { 'class' : 'hide-close' } , [ _ ( 'Egress tagged' , 'VLAN port state' ) ] )
] ) ,
'*' : E ( [ ] , [
E ( 'span' , { 'class' : 'hide-open' , 'style' : 'font-family:monospace' } , [ '*' ] ) ,
E ( 'span' , { 'class' : 'hide-close' } , [ _ ( 'Primary VLAN ID' , 'VLAN port state' ) ] )
] )
} , {
id : this . cbid ( section _id ) ,
sort : [ '-' , 'u' , 't' , '*' ] ,
optional : false ,
multiple : true
} ) ;
var field = this ;
widget . toggleItem = function ( sb , li , force _state ) {
var lis = li . parentNode . querySelectorAll ( 'li' ) ,
toggle = ui . Dropdown . prototype . toggleItem ;
toggle . apply ( this , [ sb , li , force _state ] ) ;
if ( force _state != null )
return ;
switch ( li . getAttribute ( 'data-value' ) )
{
case '-' :
if ( li . hasAttribute ( 'selected' ) ) {
for ( var i = 0 ; i < lis . length ; i ++ ) {
switch ( lis [ i ] . getAttribute ( 'data-value' ) ) {
case '-' :
break ;
case '*' :
toggle . apply ( this , [ sb , lis [ i ] , false ] ) ;
lis [ i ] . setAttribute ( 'unselectable' , '' ) ;
break ;
default :
toggle . apply ( this , [ sb , lis [ i ] , false ] ) ;
}
}
}
break ;
case 't' :
case 'u' :
if ( li . hasAttribute ( 'selected' ) ) {
for ( var i = 0 ; i < lis . length ; i ++ ) {
switch ( lis [ i ] . getAttribute ( 'data-value' ) ) {
case li . getAttribute ( 'data-value' ) :
break ;
case '*' :
lis [ i ] . removeAttribute ( 'unselectable' ) ;
break ;
default :
toggle . apply ( this , [ sb , lis [ i ] , false ] ) ;
}
}
}
else {
toggle . apply ( this , [ sb , li , true ] ) ;
}
break ;
case '*' :
if ( li . hasAttribute ( 'selected' ) ) {
var section _ids = field . section . cfgsections ( ) ;
for ( var i = 0 ; i < section _ids . length ; i ++ ) {
var other _widget = field . getUIElement ( section _ids [ i ] ) ,
other _value = L . toArray ( other _widget . getValue ( ) ) ;
if ( other _widget === this )
continue ;
var new _value = other _value . filter ( function ( v ) { return v != '*' } ) ;
if ( new _value . length == other _value . length )
continue ;
other _widget . setValue ( new _value ) ;
break ;
}
}
}
} ;
var node = widget . render ( ) ;
node . style . minWidth = '4em' ;
if ( cfgvalue == '-' )
node . querySelector ( 'li[data-value="*"]' ) . setAttribute ( 'unselectable' , '' ) ;
2021-03-18 16:19:42 +00:00
return E ( 'div' , { 'style' : 'display:inline-block' } , node ) ;
2020-07-28 18:51:10 +00:00
} ,
cfgvalue : function ( section _id ) {
var pname = this . port ,
spec = L . toArray ( uci . get ( 'network' , section _id , 'ports' ) ) . filter ( function ( p ) { return p . replace ( /:[ut*]+$/ , '' ) == pname } ) [ 0 ] ;
if ( spec && spec . match ( /t/ ) )
return spec . match ( /\*/ ) ? [ 't' , '*' ] : [ 't' ] ;
else if ( spec )
return spec . match ( /\*/ ) ? [ 'u' , '*' ] : [ 'u' ] ;
else
return [ '-' ] ;
} ,
write : function ( section _id , value ) {
var ports = [ ] ;
for ( var i = 0 ; i < this . section . children . length ; i ++ ) {
var opt = this . section . children [ i ] ;
if ( opt . port ) {
var val = L . toArray ( opt . formvalue ( section _id ) ) . join ( '' ) ;
switch ( val ) {
case '-' :
break ;
case 'u' :
ports . push ( opt . port ) ;
break ;
default :
ports . push ( '%s:%s' . format ( opt . port , val ) ) ;
break ;
}
}
}
uci . set ( 'network' , section _id , 'ports' , ports ) ;
} ,
remove : function ( ) { }
} ) ;
2020-07-27 15:12:54 +00:00
return baseclass . extend ( {
replaceOption : function ( s , tabName , optionClass , optionName , optionTitle , optionDescription ) {
var o = s . getOption ( optionName ) ;
if ( o ) {
if ( o . tab ) {
s . tabs [ o . tab ] . children = s . tabs [ o . tab ] . children . filter ( function ( opt ) {
return opt . option != optionName ;
} ) ;
}
s . children = s . children . filter ( function ( opt ) {
return opt . option != optionName ;
} ) ;
}
return s . taboption ( tabName , optionClass , optionName , optionTitle , optionDescription ) ;
} ,
addOption : function ( s , tabName , optionClass , optionName , optionTitle , optionDescription ) {
var o = this . replaceOption ( s , tabName , optionClass , optionName , optionTitle , optionDescription ) ;
if ( s . sectiontype == 'interface' && optionName != 'type' && optionName != 'vlan_filtering' ) {
2021-03-29 18:08:48 +00:00
o . migrate = true ;
2020-07-27 15:12:54 +00:00
o . cfgvalue = deviceCfgValue ;
o . write = deviceWrite ;
o . remove = deviceRemove ;
o . refresh = deviceRefresh ;
}
return o ;
} ,
addDeviceOptions : function ( s , dev , isNew ) {
2021-05-17 08:53:57 +00:00
var o , ss ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
s . tab ( 'devgeneral' , _ ( 'General device options' ) ) ;
s . tab ( 'devadvanced' , _ ( 'Advanced device options' ) ) ;
s . tab ( 'brport' , _ ( 'Bridge port specific options' ) ) ;
s . tab ( 'bridgevlan' , _ ( 'Bridge VLAN filtering' ) ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devgeneral' , form . ListValue , 'type' , _ ( 'Device type' ) ) ;
o . readonly = ! isNew ;
o . value ( '' , _ ( 'Network device' ) ) ;
o . value ( 'bridge' , _ ( 'Bridge device' ) ) ;
o . value ( '8021q' , _ ( 'VLAN (802.1q)' ) ) ;
o . value ( '8021ad' , _ ( 'VLAN (802.1ad)' ) ) ;
o . value ( 'macvlan' , _ ( 'MAC VLAN' ) ) ;
o . value ( 'veth' , _ ( 'Virtual Ethernet' ) ) ;
o = this . addOption ( s , 'devgeneral' , widgets . DeviceSelect , 'name_simple' , _ ( 'Existing device' ) ) ;
o . readonly = ! isNew ;
o . rmempty = false ;
o . noaliases = true ;
o . default = ( dev ? dev . getName ( ) : '' ) ;
o . ucioption = 'name' ;
o . write = o . remove = setIfActive ;
o . filter = function ( section _id , value ) {
2021-06-05 16:41:39 +00:00
return ! deviceSectionExists ( section _id , value , /^(?:bridge|8021q|8021ad|macvlan|veth)$/ ) ;
2021-05-17 08:53:57 +00:00
} ;
o . validate = function ( section _id , value ) {
2021-06-05 16:41:39 +00:00
return deviceSectionExists ( section _id , value , /^(?:bridge|8021q|8021ad|macvlan|veth)$/ )
? _ ( 'A configuration for the device "%s" already exists' ) . format ( value ) : true ;
2021-05-17 08:53:57 +00:00
} ;
o . depends ( 'type' , '' ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devgeneral' , widgets . DeviceSelect , 'ifname_single' , _ ( 'Base device' ) ) ;
2020-07-27 15:12:54 +00:00
o . readonly = ! isNew ;
o . rmempty = false ;
2021-05-17 08:53:57 +00:00
o . noaliases = true ;
2020-07-27 15:12:54 +00:00
o . default = ( dev ? dev . getName ( ) : '' ) . match ( /^.+\.\d+$/ ) ? dev . getName ( ) . replace ( /\.\d+$/ , '' ) : '' ;
o . ucioption = 'ifname' ;
o . validate = function ( section _id , value ) {
2021-06-01 12:35:31 +00:00
if ( isNew ) {
var type = this . section . formvalue ( section _id , 'type' ) ,
name = this . section . getUIElement ( section _id , 'name_complex' ) ;
2020-07-27 15:12:54 +00:00
2021-06-01 12:35:31 +00:00
if ( type == 'macvlan' && value && name && ! name . isChanged ( ) ) {
var i = 0 ;
2020-07-27 15:12:54 +00:00
2021-06-01 12:35:31 +00:00
while ( deviceSectionExists ( section _id , '%smac%d' . format ( value , i ) ) )
i ++ ;
2020-07-27 15:12:54 +00:00
2021-06-01 12:35:31 +00:00
name . setValue ( '%smac%d' . format ( value , i ) ) ;
name . triggerValidation ( ) ;
}
2020-07-27 15:12:54 +00:00
}
return true ;
} ;
2021-05-17 08:53:57 +00:00
o . write = o . remove = setIfActive ;
o . depends ( 'type' , '8021q' ) ;
o . depends ( 'type' , '8021ad' ) ;
o . depends ( 'type' , 'macvlan' ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devgeneral' , form . Value , 'vid' , _ ( 'VLAN ID' ) ) ;
2020-07-27 15:12:54 +00:00
o . readonly = ! isNew ;
o . datatype = 'range(1, 4094)' ;
o . rmempty = false ;
o . default = ( dev ? dev . getName ( ) : '' ) . match ( /^.+\.\d+$/ ) ? dev . getName ( ) . replace ( /^.+\./ , '' ) : '' ;
o . validate = function ( section _id , value ) {
var base = this . section . formvalue ( section _id , 'ifname_single' ) ,
vid = this . section . formvalue ( section _id , 'vid' ) ,
name = this . section . getUIElement ( section _id , 'name_complex' ) ;
if ( base && vid && name && ! name . isChanged ( ) ) {
name . setValue ( '%s.%d' . format ( base , vid ) ) ;
name . triggerValidation ( ) ;
}
return true ;
} ;
o . depends ( 'type' , '8021q' ) ;
o . depends ( 'type' , '8021ad' ) ;
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devgeneral' , form . ListValue , 'mode' , _ ( 'Mode' ) ) ;
2020-07-27 15:12:54 +00:00
o . value ( 'vepa' , _ ( 'VEPA (Virtual Ethernet Port Aggregator)' , 'MACVLAN mode' ) ) ;
o . value ( 'private' , _ ( 'Private (Prevent communication between MAC VLANs)' , 'MACVLAN mode' ) ) ;
o . value ( 'bridge' , _ ( 'Bridge (Support direct communication between MAC VLANs)' , 'MACVLAN mode' ) ) ;
o . value ( 'passthru' , _ ( 'Pass-through (Mirror physical device to single MAC VLAN)' , 'MACVLAN mode' ) ) ;
o . depends ( 'type' , 'macvlan' ) ;
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devgeneral' , form . Value , 'name_complex' , _ ( 'Device name' ) ) ;
o . rmempty = false ;
o . datatype = 'maxlength(15)' ;
o . readonly = ! isNew ;
o . ucioption = 'name' ;
o . write = o . remove = setIfActive ;
o . validate = function ( section _id , value ) {
2021-06-05 16:41:39 +00:00
return deviceSectionExists ( section _id , value , /^$/ ) ? _ ( 'The device name "%s" is already taken' ) . format ( value ) : true ;
2021-05-17 08:53:57 +00:00
} ;
o . depends ( { type : '' , '!reverse' : true } ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devadvanced' , form . DynamicList , 'ingress_qos_mapping' , _ ( 'Ingress QoS mapping' ) , _ ( 'Defines a mapping of VLAN header priority to the Linux internal packet priority on incoming frames' ) ) ;
2020-07-27 15:12:54 +00:00
o . rmempty = true ;
o . validate = validateQoSMap ;
o . depends ( 'type' , '8021q' ) ;
o . depends ( 'type' , '8021ad' ) ;
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devadvanced' , form . DynamicList , 'egress_qos_mapping' , _ ( 'Egress QoS mapping' ) , _ ( 'Defines a mapping of Linux internal packet priority to VLAN header priority but for outgoing frames' ) ) ;
2020-07-27 15:12:54 +00:00
o . rmempty = true ;
o . validate = validateQoSMap ;
o . depends ( 'type' , '8021q' ) ;
o . depends ( 'type' , '8021ad' ) ;
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devgeneral' , widgets . DeviceSelect , 'ifname_multi' , _ ( 'Bridge ports' ) ) ;
2020-07-27 15:12:54 +00:00
o . size = 10 ;
o . rmempty = true ;
o . multiple = true ;
o . noaliases = true ;
o . nobridges = true ;
2021-05-17 12:01:24 +00:00
o . ucioption = 'ports' ;
2021-05-17 08:53:57 +00:00
o . write = o . remove = setIfActive ;
o . default = L . toArray ( dev ? dev . getPorts ( ) : null ) . filter ( function ( p ) { return p . getType ( ) != 'wifi' } ) . map ( function ( p ) { return p . getName ( ) } ) ;
o . filter = function ( section _id , device _name ) {
var bridge _name = uci . get ( 'network' , section _id , 'name' ) ,
choice _dev = network . instantiateDevice ( device _name ) ,
parent _dev = choice _dev . getParent ( ) ;
/* only show wifi networks which are already present in "option ifname" */
if ( choice _dev . getType ( ) == 'wifi' ) {
2021-05-17 12:01:24 +00:00
var ifnames = L . toArray ( uci . get ( 'network' , section _id , 'ports' ) ) ;
2021-05-17 08:53:57 +00:00
for ( var i = 0 ; i < ifnames . length ; i ++ )
if ( ifnames [ i ] == device _name )
return true ;
return false ;
}
2021-03-18 16:19:42 +00:00
2021-05-17 08:53:57 +00:00
return ( ! parent _dev || parent _dev . getName ( ) != bridge _name ) ;
} ;
o . description = _ ( 'Specifies the wired ports to attach to this bridge. In order to attach wireless networks, choose the associated interface as network in the wireless settings.' )
2020-07-27 15:12:54 +00:00
o . onchange = function ( ev , section _id , values ) {
ss . updatePorts ( values ) ;
return ss . parse ( ) . then ( function ( ) {
ss . redraw ( ) ;
} ) ;
} ;
o . depends ( 'type' , 'bridge' ) ;
2021-05-17 08:53:57 +00:00
o = this . replaceOption ( s , 'devgeneral' , form . Flag , 'bridge_empty' , _ ( 'Bring up empty bridge' ) , _ ( 'Bring up the bridge interface even if no ports are attached' ) ) ;
2020-07-27 15:12:54 +00:00
o . default = o . disabled ;
o . depends ( 'type' , 'bridge' ) ;
2021-05-17 08:53:57 +00:00
o = this . replaceOption ( s , 'devadvanced' , form . Value , 'priority' , _ ( 'Priority' ) ) ;
2020-07-27 15:12:54 +00:00
o . placeholder = '32767' ;
o . datatype = 'range(0, 65535)' ;
o . depends ( 'type' , 'bridge' ) ;
2021-05-17 08:53:57 +00:00
o = this . replaceOption ( s , 'devadvanced' , form . Value , 'ageing_time' , _ ( 'Ageing time' ) , _ ( 'Timeout in seconds for learned MAC addresses in the forwarding database' ) ) ;
2020-07-27 15:12:54 +00:00
o . placeholder = '30' ;
o . datatype = 'uinteger' ;
o . depends ( 'type' , 'bridge' ) ;
2021-05-17 08:53:57 +00:00
o = this . replaceOption ( s , 'devadvanced' , form . Flag , 'stp' , _ ( 'Enable <abbr title="Spanning Tree Protocol">STP</abbr>' ) , _ ( 'Enables the Spanning Tree Protocol on this bridge' ) ) ;
2020-07-27 15:12:54 +00:00
o . default = o . disabled ;
o . depends ( 'type' , 'bridge' ) ;
2021-05-17 08:53:57 +00:00
o = this . replaceOption ( s , 'devadvanced' , form . Value , 'hello_time' , _ ( 'Hello interval' ) , _ ( 'Interval in seconds for STP hello packets' ) ) ;
2020-07-27 15:12:54 +00:00
o . placeholder = '2' ;
o . datatype = 'range(1, 10)' ;
o . depends ( { type : 'bridge' , stp : '1' } ) ;
2021-05-17 08:53:57 +00:00
o = this . replaceOption ( s , 'devadvanced' , form . Value , 'forward_delay' , _ ( 'Forward delay' ) , _ ( 'Time in seconds to spend in listening and learning states' ) ) ;
2020-07-27 15:12:54 +00:00
o . placeholder = '15' ;
o . datatype = 'range(2, 30)' ;
o . depends ( { type : 'bridge' , stp : '1' } ) ;
2021-05-17 08:53:57 +00:00
o = this . replaceOption ( s , 'devadvanced' , form . Value , 'max_age' , _ ( 'Maximum age' ) , _ ( 'Timeout in seconds until topology updates on link loss' ) ) ;
2020-07-27 15:12:54 +00:00
o . placeholder = '20' ;
o . datatype = 'range(6, 40)' ;
o . depends ( { type : 'bridge' , stp : '1' } ) ;
2021-05-17 08:53:57 +00:00
o = this . replaceOption ( s , 'devadvanced' , form . Flag , 'igmp_snooping' , _ ( 'Enable <abbr title="Internet Group Management Protocol">IGMP</abbr> snooping' ) , _ ( 'Enables IGMP snooping on this bridge' ) ) ;
2020-07-27 15:12:54 +00:00
o . default = o . disabled ;
o . depends ( 'type' , 'bridge' ) ;
2021-05-17 08:53:57 +00:00
o = this . replaceOption ( s , 'devadvanced' , form . Value , 'hash_max' , _ ( 'Maximum snooping table size' ) ) ;
2020-07-27 15:12:54 +00:00
o . placeholder = '512' ;
o . datatype = 'uinteger' ;
o . depends ( { type : 'bridge' , igmp _snooping : '1' } ) ;
2021-05-17 08:53:57 +00:00
o = this . replaceOption ( s , 'devadvanced' , form . Flag , 'multicast_querier' , _ ( 'Enable multicast querier' ) ) ;
2020-07-27 15:12:54 +00:00
o . defaults = { '1' : [ { 'igmp_snooping' : '1' } ] , '0' : [ { 'igmp_snooping' : '0' } ] } ;
o . depends ( 'type' , 'bridge' ) ;
2021-05-17 08:53:57 +00:00
o = this . replaceOption ( s , 'devadvanced' , form . Value , 'robustness' , _ ( 'Robustness' ) , _ ( 'The robustness value allows tuning for the expected packet loss on the network. If a network is expected to be lossy, the robustness value may be increased. IGMP is robust to (Robustness-1) packet losses' ) ) ;
2020-07-27 15:12:54 +00:00
o . placeholder = '2' ;
o . datatype = 'min(1)' ;
o . depends ( { type : 'bridge' , multicast _querier : '1' } ) ;
2021-05-17 08:53:57 +00:00
o = this . replaceOption ( s , 'devadvanced' , form . Value , 'query_interval' , _ ( 'Query interval' ) , _ ( 'Interval in centiseconds between multicast general queries. By varying the value, an administrator may tune the number of IGMP messages on the subnet; larger values cause IGMP Queries to be sent less often' ) ) ;
2020-07-27 15:12:54 +00:00
o . placeholder = '12500' ;
o . datatype = 'uinteger' ;
o . depends ( { type : 'bridge' , multicast _querier : '1' } ) ;
2021-05-17 08:53:57 +00:00
o = this . replaceOption ( s , 'devadvanced' , form . Value , 'query_response_interval' , _ ( 'Query response interval' ) , _ ( 'The max response time in centiseconds inserted into the periodic general queries. By varying the value, an administrator may tune the burstiness of IGMP messages on the subnet; larger values make the traffic less bursty, as host responses are spread out over a larger interval' ) ) ;
2020-07-27 15:12:54 +00:00
o . placeholder = '1000' ;
o . datatype = 'uinteger' ;
o . validate = function ( section _id , value ) {
var qiopt = L . toArray ( this . map . lookupOption ( 'query_interval' , section _id ) ) [ 0 ] ,
qival = qiopt ? ( qiopt . formvalue ( section _id ) || qiopt . placeholder ) : '' ;
if ( value != '' && qival != '' && + value >= + qival )
return _ ( 'The query response interval must be lower than the query interval value' ) ;
return true ;
} ;
o . depends ( { type : 'bridge' , multicast _querier : '1' } ) ;
2021-05-17 08:53:57 +00:00
o = this . replaceOption ( s , 'devadvanced' , form . Value , 'last_member_interval' , _ ( 'Last member interval' ) , _ ( 'The max response time in centiseconds inserted into group-specific queries sent in response to leave group messages. It is also the amount of time between group-specific query messages. This value may be tuned to modify the "leave latency" of the network. A reduced value results in reduced time to detect the loss of the last member of a group' ) ) ;
2020-07-27 15:12:54 +00:00
o . placeholder = '100' ;
o . datatype = 'uinteger' ;
o . depends ( { type : 'bridge' , multicast _querier : '1' } ) ;
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devgeneral' , form . Value , 'mtu' , _ ( 'MTU' ) ) ;
o . placeholder = getDeviceValue ( dev , 'getMTU' ) ;
2020-07-27 15:12:54 +00:00
o . datatype = 'max(9200)' ;
2021-05-17 08:53:57 +00:00
o . depends ( 'type' , '' ) ;
2021-05-27 19:01:41 +00:00
o . depends ( 'type' , 'bridge' ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devgeneral' , form . Value , 'macaddr' , _ ( 'MAC address' ) ) ;
o . placeholder = getDeviceValue ( dev , 'getMAC' ) ;
2020-07-27 15:12:54 +00:00
o . datatype = 'macaddr' ;
2021-05-17 08:53:57 +00:00
o . depends ( 'type' , '' ) ;
2021-05-27 19:01:41 +00:00
o . depends ( 'type' , 'bridge' ) ;
2020-07-27 15:12:54 +00:00
o . depends ( 'type' , 'macvlan' ) ;
o . depends ( 'type' , 'veth' ) ;
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devgeneral' , form . Value , 'peer_name' , _ ( 'Peer device name' ) ) ;
2020-07-27 15:12:54 +00:00
o . rmempty = true ;
o . datatype = 'maxlength(15)' ;
o . depends ( 'type' , 'veth' ) ;
o . load = function ( section _id ) {
var sections = uci . sections ( 'network' , 'device' ) ,
idx = 0 ;
for ( var i = 0 ; i < sections . length ; i ++ )
if ( sections [ i ] [ '.name' ] == section _id )
break ;
else if ( sections [ i ] . type == 'veth' )
idx ++ ;
this . placeholder = 'veth%d' . format ( idx ) ;
return form . Value . prototype . load . apply ( this , arguments ) ;
} ;
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devgeneral' , form . Value , 'peer_macaddr' , _ ( 'Peer MAC address' ) ) ;
2020-07-27 15:12:54 +00:00
o . rmempty = true ;
o . datatype = 'macaddr' ;
o . depends ( 'type' , 'veth' ) ;
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devgeneral' , form . Value , 'txqueuelen' , _ ( 'TX queue length' ) ) ;
2020-07-27 15:12:54 +00:00
o . placeholder = dev ? dev . _devstate ( 'qlen' ) : '' ;
o . datatype = 'uinteger' ;
2021-05-17 08:53:57 +00:00
o . depends ( 'type' , '' ) ;
2020-07-27 15:12:54 +00:00
2021-06-07 09:51:06 +00:00
o = this . addOption ( s , 'devadvanced' , form . Flag , 'promisc' , _ ( 'Enable promiscuous mode' ) ) ;
2020-07-27 15:12:54 +00:00
o . default = o . disabled ;
2021-05-17 08:53:57 +00:00
o . depends ( 'type' , '' ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devadvanced' , form . ListValue , 'rpfilter' , _ ( 'Reverse path filter' ) ) ;
2020-07-27 15:12:54 +00:00
o . default = '' ;
o . value ( '' , _ ( 'disabled' ) ) ;
o . value ( 'loose' , _ ( 'Loose filtering' ) ) ;
o . value ( 'strict' , _ ( 'Strict filtering' ) ) ;
o . cfgvalue = function ( section _id ) {
var val = form . ListValue . prototype . cfgvalue . apply ( this , [ section _id ] ) ;
switch ( val || '' ) {
case 'loose' :
case '1' :
return 'loose' ;
case 'strict' :
case '2' :
return 'strict' ;
default :
return '' ;
}
} ;
2021-05-17 08:53:57 +00:00
o . depends ( 'type' , '' ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devadvanced' , form . Flag , 'acceptlocal' , _ ( 'Accept local' ) , _ ( 'Accept packets with local source addresses' ) ) ;
2020-07-27 15:12:54 +00:00
o . default = o . disabled ;
2021-05-17 08:53:57 +00:00
o . depends ( 'type' , '' ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devadvanced' , form . Flag , 'sendredirects' , _ ( 'Send ICMP redirects' ) ) ;
2020-07-27 15:12:54 +00:00
o . default = o . enabled ;
2021-05-17 08:53:57 +00:00
o . depends ( 'type' , '' ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devadvanced' , form . Value , 'neighreachabletime' , _ ( 'Neighbour cache validity' ) , _ ( 'Time in milliseconds' ) ) ;
2020-07-27 15:12:54 +00:00
o . placeholder = '30000' ;
o . datatype = 'uinteger' ;
2021-05-17 08:53:57 +00:00
o . depends ( 'type' , '' ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devadvanced' , form . Value , 'neighgcstaletime' , _ ( 'Stale neighbour cache timeout' ) , _ ( 'Timeout in seconds' ) ) ;
2020-07-27 15:12:54 +00:00
o . placeholder = '60' ;
o . datatype = 'uinteger' ;
2021-05-17 08:53:57 +00:00
o . depends ( 'type' , '' ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devadvanced' , form . Value , 'neighlocktime' , _ ( 'Minimum ARP validity time' ) , _ ( 'Minimum required time in seconds before an ARP entry may be replaced. Prevents ARP cache thrashing.' ) ) ;
2020-07-27 15:12:54 +00:00
o . placeholder = '0' ;
o . datatype = 'uinteger' ;
2021-05-17 08:53:57 +00:00
o . depends ( 'type' , '' ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devgeneral' , form . Flag , 'ipv6' , _ ( 'Enable IPv6' ) ) ;
2021-03-29 18:08:48 +00:00
o . migrate = false ;
2020-07-27 15:12:54 +00:00
o . default = o . enabled ;
2021-05-17 08:53:57 +00:00
o . depends ( 'type' , '' ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devgeneral' , form . Value , 'mtu6' , _ ( 'IPv6 MTU' ) ) ;
o . placeholder = getDeviceValue ( dev , 'getMTU' ) ;
2020-07-27 15:12:54 +00:00
o . datatype = 'max(9200)' ;
2021-05-17 08:53:57 +00:00
o . depends ( Object . assign ( { ipv6 : '1' } , 'type' , '' ) ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devgeneral' , form . Value , 'dadtransmits' , _ ( 'DAD transmits' ) , _ ( 'Amount of Duplicate Address Detection probes to send' ) ) ;
2020-07-27 15:12:54 +00:00
o . placeholder = '1' ;
o . datatype = 'uinteger' ;
2021-05-17 08:53:57 +00:00
o . depends ( Object . assign ( { ipv6 : '1' } , 'type' , '' ) ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devadvanced' , form . Flag , 'multicast' , _ ( 'Enable multicast support' ) ) ;
2020-07-27 15:12:54 +00:00
o . default = o . enabled ;
2021-05-17 08:53:57 +00:00
o . depends ( 'type' , '' ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devadvanced' , form . ListValue , 'igmpversion' , _ ( 'Force IGMP version' ) ) ;
2020-07-27 15:12:54 +00:00
o . value ( '' , _ ( 'No enforcement' ) ) ;
o . value ( '1' , _ ( 'Enforce IGMPv1' ) ) ;
o . value ( '2' , _ ( 'Enforce IGMPv2' ) ) ;
o . value ( '3' , _ ( 'Enforce IGMPv3' ) ) ;
2021-05-17 08:53:57 +00:00
o . depends ( Object . assign ( { multicast : '1' } , 'type' , '' ) ) ;
2020-07-27 15:12:54 +00:00
2021-05-17 08:53:57 +00:00
o = this . addOption ( s , 'devadvanced' , form . ListValue , 'mldversion' , _ ( 'Force MLD version' ) ) ;
2020-07-27 15:12:54 +00:00
o . value ( '' , _ ( 'No enforcement' ) ) ;
o . value ( '1' , _ ( 'Enforce MLD version 1' ) ) ;
o . value ( '2' , _ ( 'Enforce MLD version 2' ) ) ;
2021-05-17 08:53:57 +00:00
o . depends ( Object . assign ( { multicast : '1' } , 'type' , '' ) ) ;
2020-07-27 15:12:54 +00:00
if ( isBridgePort ( dev ) ) {
o = this . addOption ( s , 'brport' , form . Flag , 'learning' , _ ( 'Enable MAC address learning' ) ) ;
o . default = o . enabled ;
2021-05-17 08:53:57 +00:00
o . depends ( 'type' , '' ) ;
2020-07-27 15:12:54 +00:00
o = this . addOption ( s , 'brport' , form . Flag , 'unicast_flood' , _ ( 'Enable unicast flooding' ) ) ;
o . default = o . enabled ;
2021-05-17 08:53:57 +00:00
o . depends ( 'type' , '' ) ;
2020-07-27 15:12:54 +00:00
o = this . addOption ( s , 'brport' , form . Flag , 'isolated' , _ ( 'Port isolation' ) , _ ( 'Only allow communication with non-isolated bridge ports when enabled' ) ) ;
o . default = o . disabled ;
2021-05-17 08:53:57 +00:00
o . depends ( 'type' , '' ) ;
2020-07-27 15:12:54 +00:00
o = this . addOption ( s , 'brport' , form . ListValue , 'multicast_router' , _ ( 'Multicast routing' ) ) ;
o . value ( '' , _ ( 'Never' ) ) ;
o . value ( '1' , _ ( 'Learn' ) ) ;
o . value ( '2' , _ ( 'Always' ) ) ;
2021-05-17 08:53:57 +00:00
o . depends ( Object . assign ( { multicast : '1' } , 'type' , '' ) ) ;
2020-07-27 15:12:54 +00:00
o = this . addOption ( s , 'brport' , form . Flag , 'multicast_to_unicast' , _ ( 'Multicast to unicast' ) , _ ( 'Forward multicast packets as unicast packets on this device.' ) ) ;
o . default = o . disabled ;
2021-05-17 08:53:57 +00:00
o . depends ( Object . assign ( { multicast : '1' } , 'type' , '' ) ) ;
2020-07-27 15:12:54 +00:00
o = this . addOption ( s , 'brport' , form . Flag , 'multicast_fast_leave' , _ ( 'Enable multicast fast leave' ) ) ;
o . default = o . disabled ;
2021-05-17 08:53:57 +00:00
o . depends ( Object . assign ( { multicast : '1' } , 'type' , '' ) ) ;
2020-07-27 15:12:54 +00:00
}
2020-07-28 18:51:10 +00:00
o = this . addOption ( s , 'bridgevlan' , form . Flag , 'vlan_filtering' , _ ( 'Enable VLAN filterering' ) ) ;
o . depends ( 'type' , 'bridge' ) ;
o . updateDefaultValue = function ( section _id ) {
2021-05-17 08:53:57 +00:00
var device = uci . get ( 'network' , s . section , 'name' ) ,
2020-07-28 18:51:10 +00:00
uielem = this . getUIElement ( section _id ) ,
has _vlans = false ;
uci . sections ( 'network' , 'bridge-vlan' , function ( bvs ) {
has _vlans = has _vlans || ( bvs . device == device ) ;
} ) ;
this . default = has _vlans ? this . enabled : this . disabled ;
if ( uielem && ! uielem . isChanged ( ) )
uielem . setValue ( this . default ) ;
} ;
o = this . addOption ( s , 'bridgevlan' , form . SectionValue , 'bridge-vlan' , form . TableSection , 'bridge-vlan' ) ;
o . depends ( 'type' , 'bridge' ) ;
o . renderWidget = function ( /* ... */ ) {
return form . SectionValue . prototype . renderWidget . apply ( this , arguments ) . then ( L . bind ( function ( node ) {
node . style . overflowX = 'auto' ;
2021-06-09 19:55:14 +00:00
node . style . overflowY = 'hidden' ;
2020-07-28 18:51:10 +00:00
return node ;
} , this ) ) ;
} ;
ss = o . subsection ;
ss . addremove = true ;
ss . anonymous = true ;
ss . renderHeaderRows = function ( /* ... */ ) {
var node = form . TableSection . prototype . renderHeaderRows . apply ( this , arguments ) ;
node . querySelectorAll ( '.th' ) . forEach ( function ( th ) {
th . classList . add ( 'middle' ) ;
} ) ;
return node ;
} ;
ss . filter = function ( section _id ) {
2021-05-17 08:53:57 +00:00
var devname = uci . get ( 'network' , s . section , 'name' ) ;
2020-07-28 18:51:10 +00:00
return ( uci . get ( 'network' , section _id , 'device' ) == devname ) ;
} ;
ss . render = function ( /* ... */ ) {
return form . TableSection . prototype . render . apply ( this , arguments ) . then ( L . bind ( function ( node ) {
if ( this . node )
this . node . parentNode . replaceChild ( node , this . node ) ;
this . node = node ;
return node ;
} , this ) ) ;
} ;
ss . redraw = function ( ) {
return this . load ( ) . then ( L . bind ( this . render , this ) ) ;
} ;
ss . updatePorts = function ( ports ) {
var devices = ports . map ( function ( port ) {
return network . instantiateDevice ( port )
} ) . filter ( function ( dev ) {
return dev . getType ( ) != 'wifi' || dev . isUp ( ) ;
} ) ;
this . children = this . children . filter ( function ( opt ) { return ! opt . option . match ( /^port_/ ) } ) ;
for ( var i = 0 ; i < devices . length ; i ++ ) {
2021-06-11 08:18:10 +00:00
o = ss . option ( cbiTagValue , 'port_%s' . format ( sfh ( devices [ i ] . getName ( ) ) ) , renderDevBadge ( devices [ i ] ) , renderPortStatus ( devices [ i ] ) ) ;
2020-07-28 18:51:10 +00:00
o . port = devices [ i ] . getName ( ) ;
}
var section _ids = this . cfgsections ( ) ,
device _names = devices . reduce ( function ( names , dev ) { names [ dev . getName ( ) ] = true ; return names } , { } ) ;
for ( var i = 0 ; i < section _ids . length ; i ++ ) {
var old _spec = L . toArray ( uci . get ( 'network' , section _ids [ i ] , 'ports' ) ) ,
new _spec = old _spec . filter ( function ( spec ) { return device _names [ spec . replace ( /:[ut*]+$/ , '' ) ] } ) ;
if ( old _spec . length != new _spec . length )
uci . set ( 'network' , section _ids [ i ] , 'ports' , new _spec . length ? new _spec : null ) ;
}
} ;
ss . handleAdd = function ( ev ) {
return s . parse ( ) . then ( L . bind ( function ( ) {
2021-05-17 08:53:57 +00:00
var device = uci . get ( 'network' , s . section , 'name' ) ,
2020-07-28 18:51:10 +00:00
section _ids = this . cfgsections ( ) ,
section _id = null ,
max _vlan _id = 0 ;
if ( ! device )
return ;
for ( var i = 0 ; i < section _ids . length ; i ++ ) {
var vid = + uci . get ( 'network' , section _ids [ i ] , 'vlan' ) ;
if ( vid > max _vlan _id )
max _vlan _id = vid ;
}
section _id = uci . add ( 'network' , 'bridge-vlan' ) ;
uci . set ( 'network' , section _id , 'device' , device ) ;
uci . set ( 'network' , section _id , 'vlan' , max _vlan _id + 1 ) ;
s . children . forEach ( function ( opt ) {
switch ( opt . option ) {
case 'type' :
case 'name_complex' :
var input = opt . map . findElement ( 'id' , 'widget.%s' . format ( opt . cbid ( s . section ) ) ) ;
if ( input )
input . disabled = true ;
break ;
}
} ) ;
s . getOption ( 'vlan_filtering' ) . updateDefaultValue ( s . section ) ;
return this . redraw ( ) ;
} , this ) ) ;
} ;
o = ss . option ( form . Value , 'vlan' , _ ( 'VLAN ID' ) ) ;
o . datatype = 'range(1, 4094)' ;
o . renderWidget = function ( /* ... */ ) {
var node = form . Value . prototype . renderWidget . apply ( this , arguments ) ;
node . style . width = '5em' ;
return node ;
} ;
o . validate = function ( section _id , value ) {
var section _ids = this . section . cfgsections ( ) ;
for ( var i = 0 ; i < section _ids . length ; i ++ ) {
if ( section _ids [ i ] == section _id )
continue ;
if ( uci . get ( 'network' , section _ids [ i ] , 'vlan' ) == value )
return _ ( 'The VLAN ID must be unique' ) ;
}
return true ;
} ;
o = ss . option ( form . Flag , 'local' , _ ( 'Local' ) ) ;
o . default = o . enabled ;
2021-03-18 16:19:42 +00:00
var ports = [ ] ;
2021-05-17 08:53:57 +00:00
var seen _ports = { } ;
2021-03-18 16:19:42 +00:00
2021-05-17 12:01:24 +00:00
L . toArray ( uci . get ( 'network' , s . section , 'ports' ) ) . forEach ( function ( port ) {
seen _ports [ port ] = true ;
2021-05-17 08:53:57 +00:00
} ) ;
2021-03-18 16:19:42 +00:00
2021-05-17 08:53:57 +00:00
uci . sections ( 'network' , 'bridge-vlan' , function ( bvs ) {
L . toArray ( bvs . ports ) . forEach ( function ( portspec ) {
var m = portspec . match ( /^([^:]+)(?::[ut*]+)?$/ ) ;
2021-03-18 16:19:42 +00:00
2021-05-17 08:53:57 +00:00
if ( m )
seen _ports [ m [ 1 ] ] = true ;
2021-03-18 16:19:42 +00:00
} ) ;
2021-05-17 08:53:57 +00:00
} ) ;
2021-03-18 16:19:42 +00:00
2021-05-17 08:53:57 +00:00
for ( var port _name in seen _ports )
ports . push ( port _name ) ;
2021-03-18 16:19:42 +00:00
2021-06-11 08:18:10 +00:00
ports . sort ( function ( a , b ) {
var m1 = a . match ( /^(.+?)([0-9]*)$/ ) ,
m2 = b . match ( /^(.+?)([0-9]*)$/ ) ;
if ( m1 [ 1 ] < m2 [ 1 ] )
return - 1 ;
else if ( m1 [ 1 ] > m2 [ 1 ] )
return 1 ;
else
return + ( m1 [ 2 ] || 0 ) - + ( m2 [ 2 ] || 0 ) ;
} ) ;
2020-07-28 18:51:10 +00:00
ss . updatePorts ( ports ) ;
2021-06-11 08:18:10 +00:00
} ,
updateDevBadge : updateDevBadge ,
updatePortStatus : updatePortStatus
2020-07-27 15:12:54 +00:00
} ) ;