v37 sysupgrade-v37.bin (2026-07-25)
50,473,789 bytes, md5 353fc69dac266a5b7a5dea4647b24eb6.
- LuCI status/channel_analysis.js: 3 patches (freq.band from mhz,
scan band from channel<=14, deferred graph on tab-active). Same
mt_wifi capability gap as v36 wireless.js (no freqlist.band, no
hostapd system features).
- 30-mss-clamp: re-assert net.bridge.bridge-nf-call-{iptables,ip6tables,arptables}=1
and idempotently re-add nft inet fw4 mangle_forward set 1360 on
every ifup (was applied silently-skipped at boot before br_netfilter
module loaded; live module reset defaults to 0, MSS clamp inert,
Windows 1460B SYNs die at vxlan0).
- rc.local: re-assert bridge-nf sysctls at end of boot (post fw4 / post
module load) as second belt-and-braces layer.
- wireless.js carried forward from v36 (5 selector patches).
U-Boot flash only (never sysupgrade - fit_do_upgrade silent fails).
WiFi key/preshared_key/network config sanitized.
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
# x1pro
|
||||
|
||||
这是一个x1pro 刷机成cudytr3000
|
||||
|
||||
## v37 (2026-07-25)
|
||||
`sysupgrade-v37.bin` (50,473,789 B, md5 `353fc69dac266a5b7a5dea4647b24eb6`) — 修 LuCI 信道分析页 3 补丁 (mt_wifi freq.band/扫描 band/tab-active) + 坑#6 根治 (rc.local + 30-mss-clamp 在 br_netfilter 加载后兜底重写 `net.bridge.bridge-nf-call-*=1` 与 `nft mangle_forward set 1360`). 详细如 `记忆/project_v37_build.md` (本地内存索引).
|
||||
|
||||
+20
-9
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require dom';
|
||||
require 'request';
|
||||
'require request';
|
||||
|
||||
var IW_ESSID = {};
|
||||
'require poll';
|
||||
@@ -312,18 +312,20 @@ var CBIWifiFrequencyValue = form.Value.extend({
|
||||
network.getWifiDevice(section_id),
|
||||
this.callFrequencyList(freqdev)
|
||||
]).then(L.bind(function(data) {
|
||||
// v36: mt_wifi has no hostapd — always offer 'auto' channel
|
||||
this.channels = {
|
||||
'2g': L.hasSystemFeature('hostapd', 'acs') ? [ 'auto', 'auto', { available: true } ] : [],
|
||||
'5g': L.hasSystemFeature('hostapd', 'acs') ? [ 'auto', 'auto', { available: true } ] : [],
|
||||
'6g': L.hasSystemFeature('hostapd', 'acs') ? [ 'auto', 'auto', { available: true } ] : [],
|
||||
'2g': [ 'auto', 'auto', { available: true } ],
|
||||
'5g': [ 'auto', 'auto', { available: true } ],
|
||||
'6g': [ 'auto', 'auto', { available: true } ],
|
||||
'60g': []
|
||||
};
|
||||
const wifidevs = data[0];
|
||||
const freqlist = data[1];
|
||||
|
||||
freqlist.forEach(freq => {
|
||||
// v36: rpcd-iwinfo on mt_wifi lacks freq.band — derive from mhz
|
||||
if (!freq.band)
|
||||
return;
|
||||
freq.band = (freq.mhz > 50000) ? 60 : (freq.mhz >= 5900) ? 6 : (freq.mhz >= 5000) ? 5 : 2;
|
||||
|
||||
const band = '%dg'.format(freq.band);
|
||||
const available = (freq.restricted && freq.no_ir) ? false: true;
|
||||
@@ -342,19 +344,27 @@ var CBIWifiFrequencyValue = form.Value.extend({
|
||||
const hwmodelist = L.toArray(wifidevs ? wifidevs.getHWModes() : null)
|
||||
.reduce(function(o, v) { o[v] = true; return o; }, {});
|
||||
|
||||
// v36: mt_wifi netifd handler reports no hwmodes — assume a/b/g/n/ac/ax
|
||||
if (!Object.keys(hwmodelist).length)
|
||||
Object.assign(hwmodelist, { a: true, b: true, g: true, n: true, ac: true, ax: true });
|
||||
|
||||
// Define supported modes
|
||||
this.modes = [
|
||||
'', 'Legacy', { available: hwmodelist.a || hwmodelist.b || hwmodelist.g },
|
||||
'n', 'N', { available: hwmodelist.n },
|
||||
'ac', 'AC', { available: L.hasSystemFeature('hostapd', '11ac') && hwmodelist.ac },
|
||||
'ax', 'AX', { available: L.hasSystemFeature('hostapd', '11ax') && hwmodelist.ax },
|
||||
'be', 'BE', { available: L.hasSystemFeature('hostapd', '11be') && hwmodelist.be }
|
||||
'ac', 'AC', { available: hwmodelist.ac },
|
||||
'ax', 'AX', { available: hwmodelist.ax },
|
||||
'be', 'BE', { available: hwmodelist.be }
|
||||
];
|
||||
|
||||
// Create a list of HT modes based on device capabilities
|
||||
const htmodelist = L.toArray(wifidevs ? wifidevs.getHTModes() : null)
|
||||
.reduce(function(o, v) { o[v] = true; return o; }, {});
|
||||
|
||||
// v36: mt_wifi reports no htmodes — assume HT/VHT/HE up to 160MHz
|
||||
if (!Object.keys(htmodelist).length)
|
||||
Object.assign(htmodelist, { HT20: true, HT40: true, VHT20: true, VHT40: true, VHT80: true, VHT160: true, HE20: true, HE40: true, HE80: true, HE160: true });
|
||||
|
||||
this.htmodes = {
|
||||
'': [ '', '-', { available: true } ],
|
||||
'n': [
|
||||
@@ -2377,8 +2387,9 @@ return view.extend({
|
||||
const m = out && out.match(/ESSID: "([^"]*)"/);
|
||||
if (m) IW_ESSID[ifname] = m[1];
|
||||
}, this)).catch(function(){});
|
||||
}));
|
||||
});
|
||||
}, this));
|
||||
});
|
||||
}, this));
|
||||
|
||||
const tasks = [ network.getHostHints(), network.getWifiDevices() ];
|
||||
|
||||
+531
@@ -0,0 +1,531 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require poll';
|
||||
'require request';
|
||||
'require network';
|
||||
'require ui';
|
||||
'require rpc';
|
||||
'require tools.prng as random';
|
||||
|
||||
return view.extend({
|
||||
callFrequencyList : rpc.declare({
|
||||
object: 'iwinfo',
|
||||
method: 'freqlist',
|
||||
params: [ 'device' ],
|
||||
expect: { results: [] }
|
||||
}),
|
||||
|
||||
callInfo : rpc.declare({
|
||||
object: 'iwinfo',
|
||||
method: 'info',
|
||||
params: [ 'device' ],
|
||||
expect: { }
|
||||
}),
|
||||
|
||||
render_signal_badge: function(signalPercent, signalValue) {
|
||||
var icon, title, value;
|
||||
|
||||
if (signalPercent < 0)
|
||||
icon = L.resource('icons/signal-none.svg');
|
||||
else if (signalPercent == 0)
|
||||
icon = L.resource('icons/signal-000-000.svg');
|
||||
else if (signalPercent < 25)
|
||||
icon = L.resource('icons/signal-000-025.svg');
|
||||
else if (signalPercent < 50)
|
||||
icon = L.resource('icons/signal-025-050.svg');
|
||||
else if (signalPercent < 75)
|
||||
icon = L.resource('icons/signal-050-075.svg');
|
||||
else
|
||||
icon = L.resource('icons/signal-075-100.svg');
|
||||
|
||||
value = '%d\xa0%s'.format(signalValue, _('dBm'));
|
||||
title = '%s: %d %s'.format(_('Signal'), signalValue, _('dBm'));
|
||||
|
||||
return E('div', {
|
||||
'class': 'ifacebadge',
|
||||
'title': title,
|
||||
'data-signal': signalValue
|
||||
}, [
|
||||
E('img', { 'src': icon }),
|
||||
value
|
||||
]);
|
||||
},
|
||||
|
||||
add_wifi_to_graph: function(chan_analysis, res, scanCache, channels, channel_width) {
|
||||
const offset_tbl = chan_analysis.offset_tbl;
|
||||
const height = chan_analysis.graph.offsetHeight - 2;
|
||||
const step = chan_analysis.col_width;
|
||||
const height_diff = (height-(height-(res.signal*-4)));
|
||||
|
||||
if (scanCache[res.bssid].color == null)
|
||||
scanCache[res.bssid].color = random.derive_color(res.bssid);
|
||||
|
||||
if (scanCache[res.bssid].graph == null || scanCache[res.bssid].graph === undefined) {
|
||||
const group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
||||
const line = document.createElementNS('http://www.w3.org/2000/svg', 'polyline');
|
||||
const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||
const color = scanCache[res.bssid].color;
|
||||
|
||||
line.setAttribute('style', 'fill:'+color+'4f'+';stroke:'+color+';stroke-width:0.5');
|
||||
text.setAttribute('style', 'fill:'+color+';font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000');
|
||||
text.appendChild(document.createTextNode(res.ssid || res.bssid));
|
||||
|
||||
group.appendChild(line);
|
||||
group.appendChild(text);
|
||||
|
||||
chan_analysis.graph.firstElementChild.appendChild(group);
|
||||
scanCache[res.bssid].graph = { group : group, line : line, text : text };
|
||||
}
|
||||
|
||||
channels.forEach(function(channel) {
|
||||
if (channel_width > 2) {
|
||||
if (!("main" in scanCache[res.bssid].graph)) {
|
||||
const main = document.createElementNS('http://www.w3.org/2000/svg', 'polyline');
|
||||
main.setAttribute('style', 'fill:url(#GradientVerticalCenteredBlack)');
|
||||
scanCache[res.bssid].graph.group.appendChild(main);
|
||||
chan_analysis.graph.firstElementChild.lastElementChild.appendChild(main);
|
||||
scanCache[res.bssid].graph["main"] = main;
|
||||
}
|
||||
const main_offset = offset_tbl[res.channel];
|
||||
const points = [
|
||||
(main_offset-(step*(2 )))+','+height,
|
||||
(main_offset-(step*(2-1)))+','+height_diff,
|
||||
(main_offset+(step*(2-1)))+','+height_diff,
|
||||
(main_offset+(step*(2 )))+','+height
|
||||
];
|
||||
scanCache[res.bssid].graph.main.setAttribute('points', points);
|
||||
}
|
||||
|
||||
const chan_offset = offset_tbl[channel];
|
||||
const points = [
|
||||
(chan_offset-(step*(channel_width )))+','+height,
|
||||
(chan_offset-(step*(channel_width-1)))+','+height_diff,
|
||||
(chan_offset+(step*(channel_width-1)))+','+height_diff,
|
||||
(chan_offset+(step*(channel_width )))+','+height
|
||||
];
|
||||
|
||||
scanCache[res.bssid].graph.text.setAttribute('x', offset_tbl[res.channel]-step);
|
||||
scanCache[res.bssid].graph.text.setAttribute('y', height_diff - 2);
|
||||
scanCache[res.bssid].graph.line.setAttribute('points', points);
|
||||
scanCache[res.bssid].graph.group.style.zIndex = res.signal*-1;
|
||||
scanCache[res.bssid].graph.group.style.opacity = res.stale ? '0.5' : null;
|
||||
})
|
||||
},
|
||||
|
||||
create_channel_graph: function(chan_analysis, freq_tbl, band) {
|
||||
/* v37: hidden tabs have offsetWidth=0 — defer graph creation until tab active */
|
||||
if (!chan_analysis.tab_listener) {
|
||||
chan_analysis.tab_listener = true;
|
||||
chan_analysis.tab.addEventListener('cbi-tab-active', L.bind(function(ev) {
|
||||
this.active_tab = ev.detail.tab;
|
||||
if (!chan_analysis.drawn)
|
||||
this.create_channel_graph(chan_analysis, freq_tbl, band);
|
||||
if (!this.radios[this.active_tab].loadedOnce)
|
||||
poll.start();
|
||||
}, this));
|
||||
}
|
||||
if (chan_analysis.drawn || chan_analysis.graph.offsetWidth <= 2)
|
||||
return;
|
||||
chan_analysis.drawn = true;
|
||||
|
||||
var columns = (band != 2) ? freq_tbl.length * 4 : freq_tbl.length + 3,
|
||||
chan_graph = chan_analysis.graph,
|
||||
G = chan_graph.firstElementChild,
|
||||
step = (chan_graph.offsetWidth - 2) / columns,
|
||||
curr_offset = step;
|
||||
|
||||
function createGraphHLine(graph, pos, width, dash) {
|
||||
var elem = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
||||
elem.setAttribute('x1', pos);
|
||||
elem.setAttribute('y1', 0);
|
||||
elem.setAttribute('x2', pos);
|
||||
elem.setAttribute('y2', '100%');
|
||||
elem.setAttribute('style', 'stroke:black;stroke-width:'+width+';stroke-dasharray:'+dash);
|
||||
graph.appendChild(elem);
|
||||
}
|
||||
|
||||
function createGraphText(graph, pos, text) {
|
||||
var elem = document.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||
elem.setAttribute('y', 15);
|
||||
elem.setAttribute('style', 'fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000');
|
||||
elem.setAttribute('x', pos + 5);
|
||||
elem.appendChild(document.createTextNode(text));
|
||||
graph.appendChild(elem);
|
||||
}
|
||||
|
||||
chan_analysis.col_width = step;
|
||||
|
||||
createGraphHLine(G,curr_offset, 0.1, 1);
|
||||
for (var i=0; i< freq_tbl.length;i++) {
|
||||
var channel = freq_tbl[i]
|
||||
chan_analysis.offset_tbl[channel] = curr_offset+step;
|
||||
|
||||
if (band != 2) {
|
||||
createGraphHLine(G,curr_offset+step, 0.1, 3);
|
||||
if (channel < 100)
|
||||
createGraphText(G,curr_offset-(step/2), channel);
|
||||
else
|
||||
createGraphText(G,curr_offset-step, channel);
|
||||
} else {
|
||||
createGraphHLine(G,curr_offset+step, 0.1, 0);
|
||||
createGraphText(G,curr_offset+step, channel);
|
||||
}
|
||||
curr_offset += step;
|
||||
|
||||
if ((band != 2) && freq_tbl[i+1]) {
|
||||
var next_channel = freq_tbl[i+1];
|
||||
/* Check if we are transitioning to another 5/6Ghz band range */
|
||||
if ((next_channel - channel) == 4) {
|
||||
for (var j=1; j < 4; j++) {
|
||||
chan_analysis.offset_tbl[channel+j] = curr_offset+step;
|
||||
if (j == 2)
|
||||
createGraphHLine(G,curr_offset+step, 0.1, 0);
|
||||
else
|
||||
createGraphHLine(G,curr_offset+step, 0.1, 1);
|
||||
curr_offset += step;
|
||||
}
|
||||
} else {
|
||||
chan_analysis.offset_tbl[channel+1] = curr_offset+step;
|
||||
createGraphHLine(G,curr_offset+step, 0.1, 1);
|
||||
curr_offset += step;
|
||||
|
||||
chan_analysis.offset_tbl[next_channel-2] = curr_offset+step;
|
||||
createGraphHLine(G,curr_offset+step, 0.5, 0);
|
||||
curr_offset += step;
|
||||
|
||||
chan_analysis.offset_tbl[next_channel-1] = curr_offset+step;
|
||||
createGraphHLine(G,curr_offset+step, 0.1, 1);
|
||||
curr_offset += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
createGraphHLine(G,curr_offset+step, 0.1, 1);
|
||||
|
||||
chan_analysis.tab.addEventListener('cbi-tab-active', L.bind(function(ev) {
|
||||
this.active_tab = ev.detail.tab;
|
||||
if (!this.radios[this.active_tab].loadedOnce)
|
||||
poll.start();
|
||||
}, this));
|
||||
},
|
||||
|
||||
handleScanRefresh: function() {
|
||||
if (!this.active_tab)
|
||||
return;
|
||||
|
||||
var radio = this.radios[this.active_tab];
|
||||
|
||||
return Promise.all([
|
||||
radio.dev.getScanList(),
|
||||
this.callInfo(radio.dev.getName())
|
||||
]).then(L.bind(function(data) {
|
||||
var results = data[0],
|
||||
local_wifi = data[1],
|
||||
table = radio.table,
|
||||
chan_analysis = radio.graph,
|
||||
scanCache = radio.scanCache,
|
||||
band = radio.band;
|
||||
|
||||
var rows = [];
|
||||
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
if (scanCache[results[i].bssid] == null)
|
||||
scanCache[results[i].bssid] = {};
|
||||
|
||||
scanCache[results[i].bssid].data = results[i];
|
||||
scanCache[results[i].bssid].data.stale = false;
|
||||
}
|
||||
|
||||
if (band + 'g' == radio.dev.get('band')) {
|
||||
if (scanCache[local_wifi.bssid] == null)
|
||||
scanCache[local_wifi.bssid] = {};
|
||||
|
||||
scanCache[local_wifi.bssid].data = local_wifi;
|
||||
|
||||
if (chan_analysis.offset_tbl[local_wifi.channel] != null && local_wifi.center_chan1) {
|
||||
var center_channels = [local_wifi.center_chan1],
|
||||
chan_width_text = local_wifi.htmode.replace(/(V)*H[TE]/,''), /* Handle HT VHT HE */
|
||||
chan_width = parseInt(chan_width_text)/10;
|
||||
|
||||
if (local_wifi.center_chan2) {
|
||||
center_channels.push(local_wifi.center_chan2);
|
||||
chan_width = 8;
|
||||
}
|
||||
|
||||
local_wifi.signal = -10;
|
||||
local_wifi.ssid = 'Local Interface';
|
||||
|
||||
this.add_wifi_to_graph(chan_analysis, local_wifi, scanCache, center_channels, chan_width);
|
||||
rows.push([
|
||||
this.render_signal_badge(q, local_wifi.signal),
|
||||
[
|
||||
E('span', { 'style': 'color:'+scanCache[local_wifi.bssid].color }, '⬤ '),
|
||||
local_wifi.ssid
|
||||
],
|
||||
'%d'.format(local_wifi.channel),
|
||||
'%h MHz'.format(chan_width_text),
|
||||
'%h'.format(local_wifi.mode),
|
||||
'%h'.format(local_wifi.bssid)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
for (var k in scanCache)
|
||||
if (scanCache[k].data.stale)
|
||||
results.push(scanCache[k].data);
|
||||
|
||||
results.sort(function(a, b) {
|
||||
if (a.channel - b.channel)
|
||||
return 1;
|
||||
|
||||
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' : '',
|
||||
center_channels = [res.channel],
|
||||
chan_width = 2;
|
||||
|
||||
/* Skip WiFi not supported by the current band */
|
||||
/* v37: rpcd-iwinfo scan results lack band (mhz is 0/garbage) — derive from channel */
|
||||
if (!res.band)
|
||||
res.band = (res.channel <= 14) ? 2 : 5;
|
||||
|
||||
if (band != res.band)
|
||||
continue;
|
||||
if (chan_analysis.offset_tbl[res.channel] == null)
|
||||
continue;
|
||||
|
||||
res.channel_width = "20 MHz";
|
||||
if (res.ht_operation != null) {
|
||||
/* Detect 40 MHz operation by looking for the presence of
|
||||
* a secondary channel. */
|
||||
if (res.ht_operation.secondary_channel_offset == "below") {
|
||||
res.channel_width = "40 MHz";
|
||||
chan_width = 4; /* 40 MHz Channel Used */
|
||||
center_channels[0] -= 2;
|
||||
} else if (res.ht_operation.secondary_channel_offset == "above") {
|
||||
res.channel_width = "40 MHz";
|
||||
chan_width = 4; /* 40 MHz Channel Used */
|
||||
center_channels[0] += 2;
|
||||
} else {
|
||||
/* Fallback to 20 MHz due to discovery of other APs on the
|
||||
* same channel (802.11n coexistence mechanism). */
|
||||
if (res.ht_operation.channel_width == 2040)
|
||||
res.channel_width = "20 MHz (40 MHz Intolerant)";
|
||||
}
|
||||
}
|
||||
|
||||
/* if channel_width <= 40, refer to HT (above) for actual channel width,
|
||||
* as vht_operation.channel_width == 40 really only means that the used
|
||||
* bandwidth is <= 40 and could be 20 Mhz as well */
|
||||
if (res.vht_operation?.channel_width > 40) {
|
||||
center_channels[0] = res.vht_operation.center_freq_1;
|
||||
if (res.vht_operation.channel_width == 80) {
|
||||
chan_width = 8;
|
||||
res.channel_width = "80 MHz";
|
||||
|
||||
/* If needed, adjust based on the 802.11ac Wave 2 interop workaround. */
|
||||
if (res.vht_operation.center_freq_2) {
|
||||
var diff = Math.abs(res.vht_operation.center_freq_2 -
|
||||
res.vht_operation.center_freq_1);
|
||||
|
||||
if (diff == 8) {
|
||||
chan_width = 16;
|
||||
res.channel_width = "160 MHz";
|
||||
center_channels.push(res.vht_operation.center_freq_2);
|
||||
} else if (diff > 8) {
|
||||
chan_width = 8;
|
||||
res.channel_width = "80+80 MHz";
|
||||
center_channels.push(res.vht_operation.center_freq_2);
|
||||
}
|
||||
}
|
||||
} else if (res.vht_operation.channel_width == 8080) {
|
||||
res.channel_width = "80+80 MHz";
|
||||
chan_width = 8;
|
||||
center_channels.push(res.vht_operation.center_freq_2);
|
||||
} else if (res.vht_operation.channel_width == 160) {
|
||||
res.channel_width = "160 MHz";
|
||||
chan_width = 16;
|
||||
}
|
||||
}
|
||||
|
||||
if (res.he_operation?.channel_width > 20) {
|
||||
center_channels[0] = res.he_operation.center_freq_1;
|
||||
chan_width = res.he_operation.channel_width / 10;
|
||||
switch (res.he_operation.channel_width) {
|
||||
case 40:
|
||||
res.channel_width = "40 MHz";
|
||||
break;
|
||||
case 80:
|
||||
res.channel_width = "80 MHz";
|
||||
break;
|
||||
case 160:
|
||||
res.channel_width = "160 MHz";
|
||||
center_channels.push(res.he_operation.center_freq_2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (res.eht_operation?.channel_width == 320) {
|
||||
chan_width = 32;
|
||||
res.channel_width = "320 MHz";
|
||||
center_channels.push(res.eht_operation.center_freq_2);
|
||||
}
|
||||
|
||||
this.add_wifi_to_graph(chan_analysis, res, scanCache, center_channels, chan_width);
|
||||
|
||||
rows.push([
|
||||
E('span', { 'style': s }, this.render_signal_badge(q, res.signal)),
|
||||
E('span', { 'style': s }, [
|
||||
E('span', { 'style': 'color:'+scanCache[results[i].bssid].color }, '⬤ '),
|
||||
(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.channel_width)),
|
||||
E('span', { 'style': s }, '%h'.format(res.mode)),
|
||||
E('span', { 'style': s }, '%h'.format(res.bssid))
|
||||
]);
|
||||
|
||||
scanCache[results[i].bssid].data.stale = true;
|
||||
}
|
||||
|
||||
cbi_update_table(table, rows);
|
||||
|
||||
if (!radio.loadedOnce) {
|
||||
radio.loadedOnce = true;
|
||||
poll.stop();
|
||||
}
|
||||
}, this))
|
||||
},
|
||||
|
||||
radios : {},
|
||||
|
||||
loadSVG : function(src) {
|
||||
return request.get(src).then(function(response) {
|
||||
if (!response.ok)
|
||||
throw new Error(response.statusText);
|
||||
|
||||
return E('div', {
|
||||
'id': 'channel_graph',
|
||||
'style': 'width:100%;height:400px;border:1px solid #000;background:#fff'
|
||||
}, E(response.text()));
|
||||
});
|
||||
},
|
||||
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
this.loadSVG(L.resource('svg/channel_analysis.svg')),
|
||||
network.getWifiDevices().then(L.bind(function(data) {
|
||||
var tasks = [], ret = [];
|
||||
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
ret[data[i].getName()] = { dev : data[i] };
|
||||
|
||||
tasks.push(this.callFrequencyList(data[i].getName())
|
||||
.then(L.bind(function(radio, data) {
|
||||
ret[radio.getName()].freq = data;
|
||||
}, this, data[i])));
|
||||
}
|
||||
|
||||
return Promise.all(tasks).then(function() { return ret; })
|
||||
}, this))
|
||||
]);
|
||||
},
|
||||
|
||||
render: function(data) {
|
||||
var svg = data[0],
|
||||
wifiDevs = data[1];
|
||||
|
||||
var h2 = E('div', {'class' : 'cbi-title-section'}, [
|
||||
E('h2', {'class': 'cbi-title-field'}, [ _('Channel Analysis') ]),
|
||||
E('div', {'class': 'cbi-title-buttons' }, [
|
||||
E('button', {
|
||||
'class': 'cbi-button cbi-button-edit',
|
||||
'click': ui.createHandlerFn(this, 'handleScanRefresh')
|
||||
}, [ _('Refresh Channels') ])])
|
||||
]);
|
||||
|
||||
var tabs = E('div', {}, E('div'));
|
||||
|
||||
for (var ifname in wifiDevs) {
|
||||
var bands = {
|
||||
[2] : { title: '2.4GHz', channels: [] },
|
||||
[5] : { title: '5GHz', channels: [] },
|
||||
[6] : { title: '6GHz', channels: [] },
|
||||
};
|
||||
|
||||
/* Split FrequencyList in Bands */
|
||||
wifiDevs[ifname].freq.forEach(function(freq) {
|
||||
/* v37: rpcd-iwinfo on mt_wifi lacks freq.band — derive from mhz */
|
||||
if (!freq.band)
|
||||
freq.band = (freq.mhz > 50000) ? 60 : (freq.mhz >= 5900) ? 6 : (freq.mhz >= 5000) ? 5 : 2;
|
||||
|
||||
if (bands[freq.band])
|
||||
bands[freq.band].channels.push(freq.channel);
|
||||
});
|
||||
|
||||
for (var band in bands) {
|
||||
if (bands[band].channels.length == 0)
|
||||
continue;
|
||||
|
||||
var csvg = svg.cloneNode(true),
|
||||
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-3 middle left' }, _('Channel Width')),
|
||||
E('th', { 'class': 'th col-2 middle left hide-xs' }, _('Mode')),
|
||||
E('th', { 'class': 'th col-3 middle left hide-xs' }, _('BSSID'))
|
||||
])
|
||||
]),
|
||||
tab = E('div', { 'data-tab': ifname+band, 'data-tab-title': ifname+' ('+bands[band].title+')' },
|
||||
[E('br'),csvg,E('br'),table,E('br')]),
|
||||
graph_data = {
|
||||
graph: csvg,
|
||||
offset_tbl: {},
|
||||
col_width: 0,
|
||||
tab: tab,
|
||||
};
|
||||
|
||||
this.radios[ifname+band] = {
|
||||
dev: wifiDevs[ifname].dev,
|
||||
band: band,
|
||||
graph: graph_data,
|
||||
table: table,
|
||||
scanCache: {},
|
||||
loadedOnce: false,
|
||||
};
|
||||
|
||||
cbi_update_table(table, [], E('em', { class: 'spinning' }, _('Starting wireless scan...')));
|
||||
|
||||
tabs.firstElementChild.appendChild(tab)
|
||||
|
||||
requestAnimationFrame(L.bind(this.create_channel_graph, this, graph_data, bands[band].channels, band));
|
||||
}
|
||||
}
|
||||
|
||||
ui.tabs.initTabGroup(tabs.firstElementChild.childNodes);
|
||||
|
||||
this.pollFn = L.bind(this.handleScanRefresh, this);
|
||||
poll.add(this.pollFn);
|
||||
|
||||
return E('div', {}, [h2, tabs]);
|
||||
},
|
||||
|
||||
handleSaveApply: null,
|
||||
handleSave: null,
|
||||
handleReset: null
|
||||
});
|
||||
@@ -1,11 +1,12 @@
|
||||
#!/bin/sh
|
||||
# === MSS clamp persistence (坑 #12 part 3) ===
|
||||
# === MSS clamp persistence (坑 #12 part 3 + 坑 #6 2026-07-25 加固) ===
|
||||
# fw4 reload (triggered by any ifup) wipes the nft rule added by 20-vxlan hotplug.
|
||||
# This iface hotplug re-adds the rule after every interface ifup event,
|
||||
# but only if the rule is missing (idempotent).
|
||||
# Idempotency: grep for the unique "set 1360" string before adding.
|
||||
# br_netfilter 晚加载会把 bridge-nf-call-* sysctl 重置回 0 (sysctl.d 开机时键不存在被静默跳过)。
|
||||
# This iface hotplug re-asserts both after every interface ifup event (idempotent).
|
||||
[ "$ACTION" = "ifup" ] || exit 0
|
||||
sleep 2 # wait for fw4 reload to complete
|
||||
nft list chain inet fw4 mangle_forward 2>/dev/null | grep -q 'set 1360' || \
|
||||
nft add rule inet fw4 mangle_forward 'iifname "br-lan" tcp flags syn tcp option maxseg size set 1360' 2>/dev/null
|
||||
sysctl -w net.bridge.bridge-nf-call-iptables=1 >/dev/null 2>&1
|
||||
sysctl -w net.bridge.bridge-nf-call-ip6tables=1 >/dev/null 2>&1
|
||||
sysctl -w net.bridge.bridge-nf-call-arptables=1 >/dev/null 2>&1
|
||||
nft list chain inet fw4 mangle_forward 2>/dev/null | grep -q 'set 1360' || nft add rule inet fw4 mangle_forward 'iifname "br-lan" tcp flags syn tcp option maxseg size set 1360' 2>/dev/null
|
||||
exit 0
|
||||
|
||||
@@ -23,4 +23,12 @@ echo 32768 > /proc/sys/net/core/rps_sock_flow_entries 2>/dev/null
|
||||
# Log-only (no uci mutation); see /etc/wifi-band-verify.sh for rationale.
|
||||
( /etc/wifi-band-verify.sh >/dev/null 2>&1 & )
|
||||
|
||||
|
||||
# === bridge-nf re-assert (keng #6 加固 2026-07-25) ===
|
||||
# sysctl.d/99-bridge-nf.conf 开机应用时 br_netfilter 可能未加载, 键不存在被静默跳过;
|
||||
# 模块晚加载后默认值 0 会让 MSS clamp 对桥接流量失效. rc.local 最后兜底.
|
||||
sysctl -w net.bridge.bridge-nf-call-iptables=1 2>/dev/null
|
||||
sysctl -w net.bridge.bridge-nf-call-ip6tables=1 2>/dev/null
|
||||
sysctl -w net.bridge.bridge-nf-call-arptables=1 2>/dev/null
|
||||
|
||||
exit 0
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user