net: network-state monitor and permanent-rejection FPLMN (v2.7.0)
server: - netsim: LOCI/PSLOCI dummy builders take a status; the EPSLOCI dummy is wiped to 0B F6 + FF per UICC_NAA.md C3; roaming_denied now emulates the permanent 'PLMN not allowed' rejection (C3a): status 010, EPSNSC dropped, EF.FPLMN append with TS 31.102 4.2.16 shift semantics and a home-PLMN guard (HPLMNwAcT/EHPLMN, IMSI fallback), optional 'Rejection: write FPLMN' toggle; write steps carry the logical key; SCENARIO_SERVICE map; insert_fplmn/fplmn_entries/parse_imsi helpers - netstate.py: cached per-session monitor state for the 12 network EFs, step-based patch, simulated service state, derived location with country/ operator (optional MCC/MNC list) and roaming class - server: monitor read at equip right after a readable ICCID (skipped otherwise), cleared on card removal; GET /api/net-state and POST /api/net-state-refresh; net-sim patches the cache from the written bytes and re-reads EF.IMSI; Location-status events set the service state and re-read EF.IMSI (multi-IMSI applets) frontend: - Phone tab: 'Network state' panel next to Network simulation with the simulated service badge (Undefined until simulated; normal/limited/no service + rejection marker), location/roaming line, compact per-file summaries with full-decode tooltips and a Refresh button; no card polling - EF decoders: EF.FPLMN (FFFFFF gaps are not terminators) and EF.EHPLMN - i18n EN/RU, help updated; SW cache simple-v203 tests: 295 Python / 453 frontend
This commit is contained in:
@@ -24,7 +24,7 @@ function extractFunc(src, name) {
|
||||
const FNS = [
|
||||
'efBytes', 'efHex', 'efSwapNibbles', 'efAllFf', 'efRstripFf', 'efTlv', 'efUcs2Be',
|
||||
'efGsm7Octets', 'efAnnexA', 'efBcdAddress', 'efBcdAddressLen', 'efPlmn', 'efPlmnAct', 'efPnnText',
|
||||
'efDecIccid', 'efDecImsi', 'efDecLi', 'efDecServiceTable', 'efDecPlmnList', 'efDecPlmnWact',
|
||||
'efDecIccid', 'efDecImsi', 'efDecLi', 'efDecServiceTable', 'efDecPlmnList', 'efDecFplmn', 'efDecPlmnWact',
|
||||
'efDecSpn', 'efDecLoci', 'efDecPsLoci', 'efDecEpsLoci', 'efDecEpsNsc', 'efDecKc', 'efDecAcc',
|
||||
'efDecPhase', 'efDecCbmi', 'efDecCbmir', 'efDecEcc', 'efDecOpl', 'efDecAd', 'efDecAcl',
|
||||
'efDecSmsp', 'efDecSpdi', 'efDecNai', 'efDecDir', 'efDecArr', 'efDecPnn', 'efDecAdn',
|
||||
@@ -84,6 +84,12 @@ test('EF decoders match the pinned spec / pySim test vectors', () => {
|
||||
assert.deepStrictEqual(efDecEcc(efBytes('19f101')), { number: '911', esc: '0x01' });
|
||||
assert.deepStrictEqual(efDecKc(efBytes('837d783609a3858f05')), { kc: '837D783609A3858F', ksi: 0 });
|
||||
assert.deepStrictEqual(efDecPlmnList(efBytes('22F860')), { plmns: [{ mcc: '228', mnc: '06' }] });
|
||||
// EF.FPLMN: a FFFFFF gap in any position is skipped, not a terminator
|
||||
assert.deepStrictEqual(efDecFplmn(efBytes('22F860FFFFFF62F210')),
|
||||
{ plmns: [{ mcc: '228', mnc: '06' }, { mcc: '262', mnc: '01' }] });
|
||||
assert.deepStrictEqual(efDecFplmn(efBytes('FFFFFFFF')), { plmns: [] });
|
||||
assert.strictEqual(efFindDecoder('EF.EHPLMN', null).fn, efDecPlmnList);
|
||||
assert.strictEqual(efFindDecoder('EF.FPLMN', null).fn, efDecFplmn);
|
||||
assert.deepStrictEqual(efDecCbmi(efBytes('0010FFFF0020')), { message_ids: [16, 32] });
|
||||
assert.deepStrictEqual(efDecCbmir(efBytes('0000FFFEFFFF')), { ranges: [['0000', 'FFFE']] });
|
||||
assert.deepStrictEqual(efDecPhase(efBytes('03')), { phase: 'phase 2 and higher' });
|
||||
|
||||
Reference in New Issue
Block a user