6 function isCIDR(value
) {
7 return Array
.isArray(value
) || /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/(\d{1,2}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/.test(value
);
10 function calculateBroadcast(s
, use_cfgvalue
) {
11 var readfn
= use_cfgvalue
? 'cfgvalue' : 'formvalue',
12 addropt
= s
.children
.filter(function(o
) { return o
.option
== 'ipaddr'})[0],
13 addrvals
= addropt
? L
.toArray(addropt
[readfn
](s
.section
)) : [],
14 maskopt
= s
.children
.filter(function(o
) { return o
.option
== 'netmask'})[0],
15 maskval
= maskopt
? maskopt
[readfn
](s
.section
) : null,
16 firstsubnet
= maskval
? addrvals
[0] + '/' + maskval
: addrvals
.filter(function(a
) { return a
.indexOf('/') > 0 })[0];
18 if (firstsubnet
== null)
21 var addr_mask
= firstsubnet
.split('/'),
22 addr
= validation
.parseIPv4(addr_mask
[0]),
26 mask
= validation
.parseIPv4(network
.prefixToMask(+mask
));
28 mask
= validation
.parseIPv4(mask
);
31 addr
[0] | (~mask
[0] >>> 0 & 255),
32 addr
[1] | (~mask
[1] >>> 0 & 255),
33 addr
[2] | (~mask
[2] >>> 0 & 255),
34 addr
[3] | (~mask
[3] >>> 0 & 255)
40 function validateBroadcast(section_id
, value
) {
41 var opt
= this.map
.lookupOption('broadcast', section_id
),
42 node
= opt
? this.map
.findElement('id', opt
[0].cbid(section_id
)) : null,
43 addr
= node
? calculateBroadcast(this.section
, false) : null;
47 node
.querySelector('input').setAttribute('placeholder', addr
);
49 node
.querySelector('input').removeAttribute('placeholder');
55 return network
.registerProtocol('static', {
56 CBIIPValue
: form
.Value
.extend({
57 handleSwitch: function(section_id
, option_index
, ev
) {
58 var maskopt
= this.map
.lookupOption('netmask', section_id
);
60 if (maskopt
== null || !this.isValid(section_id
))
63 var maskval
= maskopt
[0].formvalue(section_id
),
64 addrval
= this.formvalue(section_id
),
65 prefix
= maskval
? network
.maskToPrefix(maskval
) : 32;
70 this.datatype
= 'or(cidr4,ipmask4)';
72 var parent
= L
.dom
.parent(ev
.target
, '.cbi-value-field');
73 L
.dom
.content(parent
, form
.DynamicList
.prototype.renderWidget
.apply(this, [
76 addrval
? '%s/%d'.format(addrval
, prefix
) : ''
79 var masknode
= this.map
.findElement('id', maskopt
[0].cbid(section_id
));
81 parent
= L
.dom
.parent(masknode
, '.cbi-value');
82 parent
.parentNode
.removeChild(parent
);
86 renderWidget: function(section_id
, option_index
, cfgvalue
) {
87 var maskopt
= this.map
.lookupOption('netmask', section_id
),
88 widget
= isCIDR(cfgvalue
) ? 'DynamicList' : 'Value';
90 if (widget
== 'DynamicList') {
91 this.datatype
= 'or(cidr4,ipmask4)';
92 this.placeholder
= _('Add IPv4 address…');
95 this.datatype
= 'ip4addr("nomask")';
98 var node
= form
[widget
].prototype.renderWidget
.apply(this, [ section_id
, option_index
, cfgvalue
]);
100 if (widget
== 'Value')
101 L
.dom
.append(node
, E('button', {
102 'class': 'cbi-button cbi-button-neutral',
103 'title': _('Switch to CIDR list notation'),
104 'aria-label': _('Switch to CIDR list notation'),
105 'click': L
.bind(this.handleSwitch
, this, section_id
, option_index
)
111 validate
: validateBroadcast
114 CBINetmaskValue
: form
.Value
.extend({
115 render: function(option_index
, section_id
, in_table
) {
116 var addropt
= this.section
.children
.filter(function(o
) { return o
.option
== 'ipaddr' })[0],
117 addrval
= addropt
? addropt
.cfgvalue(section_id
) : null;
119 if (addrval
!= null && isCIDR(addrval
))
122 this.value('255.255.255.0');
123 this.value('255.255.0.0');
124 this.value('255.0.0.0');
126 return form
.Value
.prototype.render
.apply(this, [ option_index
, section_id
, in_table
]);
129 datatype
: 'ip4addr("true")',
130 validate
: validateBroadcast
133 CBIGatewayValue
: form
.Value
.extend({
134 datatype
: 'ip4addr("nomask")',
136 render: function(option_index
, section_id
, in_table
) {
137 return network
.getWANNetworks().then(L
.bind(function(wans
) {
138 if (wans
.length
== 1) {
139 var gwaddr
= wans
[0].getGatewayAddr();
140 this.placeholder
= gwaddr
? '%s (%s)'.format(gwaddr
, wans
[0].getName()) : '';
143 return form
.Value
.prototype.render
.apply(this, [ option_index
, section_id
, in_table
]);
147 validate: function(section_id
, value
) {
148 var addropt
= this.section
.children
.filter(function(o
) { return o
.option
== 'ipaddr' })[0],
149 addrval
= addropt
? L
.toArray(addropt
.cfgvalue(section_id
)) : null;
151 if (addrval
!= null) {
152 for (var i
= 0; i
< addrval
.length
; i
++) {
153 var addr
= addrval
[i
].split('/')[0];
155 return _('The gateway address must not be a local IP address');
163 CBIBroadcastValue
: form
.Value
.extend({
164 datatype
: 'ip4addr("nomask")',
166 render: function(option_index
, section_id
, in_table
) {
167 this.placeholder
= calculateBroadcast(this.section
, true);
168 return form
.Value
.prototype.render
.apply(this, [ option_index
, section_id
, in_table
]);
172 getI18n: function() {
173 return _('Static address');
176 renderFormOptions: function(s
) {
179 s
.taboption('general', this.CBIIPValue
, 'ipaddr', _('IPv4 address'));
180 s
.taboption('general', this.CBINetmaskValue
, 'netmask', _('IPv4 netmask'));
181 s
.taboption('general', this.CBIGatewayValue
, 'gateway', _('IPv4 gateway'));
182 s
.taboption('general', this.CBIBroadcastValue
, 'broadcast', _('IPv4 broadcast'));
184 o
= s
.taboption('general', form
.DynamicList
, 'ip6addr', _('IPv6 address'));
185 o
.datatype
= 'ip6addr';
186 o
.placeholder
= _('Add IPv6 address…');
187 o
.depends('ip6assign', '');
189 o
= s
.taboption('general', form
.Value
, 'ip6gw', _('IPv6 gateway'));
190 o
.datatype
= 'ip6addr("nomask")';
191 o
.depends('ip6assign', '');
193 o
= s
.taboption('general', form
.Value
, 'ip6prefix', _('IPv6 routed prefix'), _('Public prefix routed to this device for distribution to clients.'));
194 o
.datatype
= 'ip6addr';
195 o
.depends('ip6assign', '');