From 0446d2a93c21f47d11d4f1eb67a0168007d503e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=90=D0=BD=D1=82=D0=BE=D0=BD=20=D0=A2=D1=80=D0=BE=D1=88?=
=?UTF-8?q?=D0=B8=D0=BD?=
Date: Mon, 21 Sep 2026 01:14:45 +0300
Subject: [PATCH] ui: FPLMN manual-selection clear and duplicate guard
(v2.7.19)
Attaching to a PLMN listed in EF.FPLMN used to write successful locations
anyway, i.e. it attached to a forbidden network. Per TS 23.122 a
successful manual selection removes the entry, so the attach scenarios
clear it first:
- netsim.remove_fplmn() clears every occurrence of the PLMN (entries are
not compacted; FFFFFF gaps stay); insert_fplmn() returns None when the
PLMN is already listed, so roaming_denied no longer stores duplicates
(the live card had '250-99, 250-99').
- clear_fplmn() step, called from write_real_locations() -> covers
attach_eps, attach_2g and the sms_received location rewrite; the write
is logged as a normal fplmn update_binary.
- tests: remove_fplmn duplicates/absent/gaps; roaming_denied duplicate
skip; attach clears both occurrences before the location writes;
make_runner now copies FakeFileInfo so seeded data does not leak
between tests.
- help EN/RU and AGENTS updated.
---
frontend/help-ru.html | 6 ++---
frontend/help.html | 6 ++---
frontend/index.html | 6 ++---
frontend/sw.js | 2 +-
pyproject.toml | 2 +-
pysim_simple_server/netsim.py | 40 ++++++++++++++++++++++++++-
pysim_simple_server/server.py | 2 +-
tests/test_netsim.py | 51 ++++++++++++++++++++++++++++++++++-
8 files changed, 101 insertions(+), 14 deletions(-)
diff --git a/frontend/help-ru.html b/frontend/help-ru.html
index e2b703a..92b031f 100644
--- a/frontend/help-ru.html
+++ b/frontend/help-ru.html
@@ -482,14 +482,14 @@
Воспроизводит шаблоны записи реального телефона при смене сетевых условий (исследование трасс в projects/UICC_NAA.md): подключение EPS, потеря сервиса / ограниченный сервис, запрет роуминга, откат на 2G, приём SMS, перенастройка cell broadcast и AUTHENTICATE. По кнопке на сценарий; карта должна быть подключена.
Подключение EPS / 2G — запись реального контекста EPS NAS (KSI, KASME, счётчики NAS, алгоритм) и реальных LOCI/PSLOCI/EPSLOCI (в 2G дополнительно реальные Kc/KcGPRS).
-
Потеря сервиса / ограниченный сервис / запрет роуминга — событие Location status (только если карта на него подписана), инвалидация EPSNSC (по желанию с сохранением старого KASME), фиктивные location-файлы (LOCI/PSLOCI сохраняют PLMN, LAC FFFE, статус 01; EPSLOCI стирается до 0B F6 + FF×13 + FF FE 01) и инвалидация Kc. Запрет роуминга эмулирует постоянный отказ «PLMN not allowed» (NAS cause #11): location-файлы получают статус 010 (EPSLOCI 0B F6 + FF×13 + FF FE 02), запрещённый VPLMN дописывается в EF.FPLMN по семантике сдвига из TS 31.102 §4.2.16 (домашняя сеть не записывается), ключевой контекст стирается.
+
Подключение EPS / 2G — запись реального контекста EPS NAS (KSI, KASME, счётчики NAS, алгоритм) и реальных LOCI/PSLOCI/EPSLOCI (в 2G дополнительно реальные Kc/KcGPRS). Подключение считается успешным ручным выбором выбранного PLMN: если он есть в EF.FPLMN, его записи сначала очищаются (TS 23.122), поэтому подключение к запрещённой сети не проходит незаметно.
+
Потеря сервиса / ограниченный сервис / запрет роуминга — событие Location status (только если карта на него подписана), инвалидация EPSNSC (по желанию с сохранением старого KASME), фиктивные location-файлы (LOCI/PSLOCI сохраняют PLMN, LAC FFFE, статус 01; EPSLOCI стирается до 0B F6 + FF×13 + FF FE 01) и инвалидация Kc. Запрет роуминга эмулирует постоянный отказ «PLMN not allowed» (NAS cause #11): location-файлы получают статус 010 (EPSLOCI 0B F6 + FF×13 + FF FE 02), запрещённый VPLMN дописывается в EF.FPLMN по семантике сдвига из TS 31.102 §4.2.16 (домашняя сеть не записывается, дубликаты не создаются — уже имеющаяся запись пропускается), ключевой контекст стирается.
Серия переподключений — реальная → невалидная запись EPSNSC подряд (число циклов и задержка настраиваются).
Принято SMS — инкремент счётчика EF.SMSstatus (чтение-изменение-запись) и, по желанию, перезапись location-файлов.
Перенастройка CB — запись списков CBMI/CBMIR или их очистка (все FF).
AUTHENTICATE — команда AUTHENTICATE (3G/EPS/5G, 00 88 00 81 22) с заданными или случайными RAND/AUTN и показ ответа (успех DB или ошибка синхронизации DC с AUTS).
-
Параметры (свёрнуты) задают оператора (поиск по мировому списку MCC/MNC с сервера плюс выбор случайного роуминг-оператора и кнопка «Домашняя сеть», заполняющая HPLMN карты из первой записи EF.HPLMNwAcT с откатом на IMSI), LAC/Cell ID/TAC/RAC, необязательные идентификаторы (пусто = случайно: TMSI, GUTI, KSI, KASME, Kc, счётчики NAS, алгоритм, RAND/AUTN), переключатели сценария (включая «Отказ: записать FPLMN») и число циклов/задержку. Журнал шагов показывает каждую запись, ENVELOPE и AUTHENTICATE с их SW. Отправляются только UPDATE BINARY/RECORD, ENVELOPE и AUTHENTICATE — FPLMN записывается только сценарием постоянного отказа (TS 31.102 §4.2.16), а 5GS location-файлы не записываются; записи меняют карту и видны в последующих сравнениях снимков.
+
Параметры (свёрнуты) задают оператора (поиск по мировому списку MCC/MNC с сервера плюс выбор случайного роуминг-оператора и кнопка «Домашняя сеть», заполняющая HPLMN карты из первой записи EF.HPLMNwAcT с откатом на IMSI), LAC/Cell ID/TAC/RAC, необязательные идентификаторы (пусто = случайно: TMSI, GUTI, KSI, KASME, Kc, счётчики NAS, алгоритм, RAND/AUTN), переключатели сценария (включая «Отказ: записать FPLMN») и число циклов/задержку. Журнал шагов показывает каждую запись, ENVELOPE и AUTHENTICATE с их SW. Отправляются только UPDATE BINARY/RECORD, ENVELOPE и AUTHENTICATE — FPLMN дописывается только сценарием постоянного отказа (TS 31.102 §4.2.16, без дубликатов), а подключение к сети из списка сначала очищает её запись (успешный ручной выбор, TS 23.122); 5GS location-файлы не записываются; записи меняют карту и видны в последующих сравнениях снимков.
Монитор сетевого состояния
Рядом с кнопками симуляции компактная панель «Сетевое состояние» показывает, что сейчас хранит карта и что было сэмулировано последним. В заголовке — сэмулированное состояние сервиса: Не определено, пока его не задаст сценарий или событие Location status, затем Обычный сервис (зелёный), Ограниченный сервис (жёлтый) или Нет сервиса (красный), с красной пометкой PLMN не разрешён, если location-файлы или EF.FPLMN указывают на отказ регистрации — плюс текущее местоположение: PLMN, страна и оператор (из необязательного мирового списка MCC/MNC, если он загружен), LAI/RAI/TAI и класс роуминга (Домашняя сеть, если PLMN совпадает с HPLMN; Эквивалентная домашней, если он есть в EF.EHPLMN; иначе Гостевая (роуминг)). Ниже — по одной компактной строке на контролируемый файл (IMSI, EHPLMN, SPDI, HPLMNwAcT, LOCI, PSLOCI, EPSLOCI, EPSNSC, CBMI, CBMIR, SMSstatus, FPLMN) с декодированной сводкой и признаком последнего обновления (init, write, read, refresh); при наведении — все декодированные поля; длинные списки PLMN сокращаются (EF.HPLMNwAcT показывает только первую сеть и пометку … +N, а технологии доступа — в подсказке). Панель читает файлы один раз при подключении карты (только если ICCID читается), обновляет их на месте по записанным симулятором байтам, перечитывает EF.IMSI после каждого сценария и события Location status (мульти-IMSI апплеты) и никогда не опрашивает карту — кнопка «Обновить» перечитывает все файлы по требованию.
Replays the write patterns a real phone performs when the network condition changes (trace study in projects/UICC_NAA.md): EPS attach, service loss / limited service, roaming denial, 2G fallback, SMS delivery, cell-broadcast reconfiguration and AUTHENTICATE. One button per scenario; the card must be equipped.
Cold boot — invalidate EPSNSC (KSI 07, key wiped) and dummy the location files.
-
EPS attach / 2G attach — store a real EPS NAS context (KSI, KASME, NAS counts, algorithm) and write real LOCI/PSLOCI/EPSLOCI (2G also writes real Kc/KcGPRS).
-
Service lost / Limited service / Roaming denied — send the Location status event (only when the card subscribed to it), invalidate EPSNSC (optionally keeping the old KASME), dummy the location files (the LOCI/PSLOCI keep the PLMN, LAC FFFE, status 01; EPSLOCI is wiped to 0B F6 + FF×13 + FF FE 01) and invalidate Kc. Roaming denied emulates a permanent “PLMN not allowed” rejection (NAS cause #11): the location files carry status 010 (EPSLOCI 0B F6 + FF×13 + FF FE 02), the denied VPLMN is appended to EF.FPLMN with the shift-list semantics of TS 31.102 §4.2.16 (never the home PLMN) and the key context is dropped.
+
EPS attach / 2G attach — store a real EPS NAS context (KSI, KASME, NAS counts, algorithm) and write real LOCI/PSLOCI/EPSLOCI (2G also writes real Kc/KcGPRS). The attach is treated as a successful manual selection of the chosen PLMN: if it is listed in EF.FPLMN, its entries are cleared first (TS 23.122), so an attach never succeeds silently to a forbidden network.
+
Service lost / Limited service / Roaming denied — send the Location status event (only when the card subscribed to it), invalidate EPSNSC (optionally keeping the old KASME), dummy the location files (the LOCI/PSLOCI keep the PLMN, LAC FFFE, status 01; EPSLOCI is wiped to 0B F6 + FF×13 + FF FE 01) and invalidate Kc. Roaming denied emulates a permanent “PLMN not allowed” rejection (NAS cause #11): the location files carry status 010 (EPSLOCI 0B F6 + FF×13 + FF FE 02), the denied VPLMN is appended to EF.FPLMN with the shift-list semantics of TS 31.102 §4.2.16 (never the home PLMN, never duplicated — an entry already listed is skipped) and the key context is dropped.
Churn — replay real → invalid EPSNSC records back-to-back (count and delay configurable).
SMS received — bump the EF.SMSstatus counter (read-modify-write) and optionally rewrite the location files.
CB reconfig — write the CBMI/CBMIR message-ID lists or clear them (all FF).
AUTHENTICATE — send AUTHENTICATE (3G/EPS/5G, 00 88 00 81 22) with the given or random RAND/AUTN and show the response (success DB or synchronisation failure DC with AUTS).
-
Parameters (collapsed) provide the operator (searchable worldwide MCC/MNC list served from the server, plus a random roaming picker and a Home network button that fills the card’s HPLMN from EF.HPLMNwAcT’s first record, falling back to the IMSI), LAC/Cell ID/TAC/RAC, optional identity values (empty = random: TMSI, GUTI, KSI, KASME, Kc, NAS counts, algorithm, RAND/AUTN), the scenario toggles (including Rejection: write FPLMN) and the churn count/delay. The step log lists every write, ENVELOPE and AUTHENTICATE with its SW. Only UPDATE BINARY/RECORD, ENVELOPE and AUTHENTICATE are sent — FPLMN is written only by the permanent rejection scenario (TS 31.102 §4.2.16) and the 5GS location files are never written; the writes change the card and are visible to later snapshot comparisons.
+
Parameters (collapsed) provide the operator (searchable worldwide MCC/MNC list served from the server, plus a random roaming picker and a Home network button that fills the card’s HPLMN from EF.HPLMNwAcT’s first record, falling back to the IMSI), LAC/Cell ID/TAC/RAC, optional identity values (empty = random: TMSI, GUTI, KSI, KASME, Kc, NAS counts, algorithm, RAND/AUTN), the scenario toggles (including Rejection: write FPLMN) and the churn count/delay. The step log lists every write, ENVELOPE and AUTHENTICATE with its SW. Only UPDATE BINARY/RECORD, ENVELOPE and AUTHENTICATE are sent — FPLMN is appended only by the permanent rejection scenario (TS 31.102 §4.2.16, never duplicated) and an attach to a listed PLMN clears its entry first (successful manual selection, TS 23.122), and the 5GS location files are never written; the writes change the card and are visible to later snapshot comparisons.
Network state monitor
Next to the simulation buttons a compact Network state panel shows what the card currently holds and what was last simulated. Its header carries the simulated service state — Undefined until a scenario or a Location status event sets it, then Normal service (green), Limited service (amber) or No service (red), with a red PLMN not allowed marker when the location files or EF.FPLMN show a rejection — plus the current location: PLMN, country and operator (from the optional worldwide MCC/MNC list when loaded), the LAI/RAI/TAI, and the roaming class (Home when the PLMN equals the HPLMN, Home equivalent when it is in EF.EHPLMN, otherwise Guest). Below it, one compact line per monitored file (IMSI, EHPLMN, SPDI, HPLMNwAcT, LOCI, PSLOCI, EPSLOCI, EPSNSC, CBMI, CBMIR, SMSstatus, FPLMN) with its decoded summary and how it was last updated (init, write, read, refresh); hover for the full decoded fields — long PLMN lists are abbreviated (EF.HPLMNwAcT shows only the first network plus a … +N counter, with the access technologies in the tooltip). The panel reads the files once at equip (only when the ICCID was readable), updates them in place from the bytes the simulator wrote, re-reads EF.IMSI after every scenario and Location-status event (multi-IMSI applets) and never polls the card — use Refresh to re-read all files on demand.