Decode cross-spec "reserved" values via the sibling specs
- REFRESH '07'/'08': use the TS 31.111 §8.6 names ("Steering of Roaming" /
"... for I-WLAN", per TS 23.122 / TS 24.234) instead of "Reserved (...)"
- envelope tags 'E1'-'E3': TS 31.111 §9.1 leaves them reserved for future
usage — drop the placeholder label and decode them as unknown
- TR result '28' = Bearer Independent Protocol temporary error (TS 102 223
§8.12); '29' stays reserved
- PLI qualifier '0B' = MEID of the terminal added; '05' documented as
TS 31.111's Timing Advance (ETSI text says "Reserved for GSM")
- ISO 7816-4:2005 Table 6: add '62 86' (sensor) and '63 81' (file filled)
- drop the two fabricated '66xx' names (no such rows in the pinned specs)
- tests: add the new value tests plus a guard that no decoder table emits
a "Reserved ..." label
- v2.1.1; SW cache simtrace-analyser-v56
This commit is contained in:
1 parent
561801a983
commit
d4a378695c
7 files changed
+78
-13
No files matched your search
+1
-1
@@ -2706,7 +2706,7 @@ function onFilterChange() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ──────────────────── Versioning ────────────────────
|
// ──────────────────── Versioning ────────────────────
|
||||||
const PWA_VERSION = '2.1.0';
|
const PWA_VERSION = '2.1.1';
|
||||||
const MIN_SERVER_VERSION = '1.0.0';
|
const MIN_SERVER_VERSION = '1.0.0';
|
||||||
|
|
||||||
function parseVersion(v) {
|
function parseVersion(v) {
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = 'simtrace-analyser-v55';
|
const CACHE = 'simtrace-analyser-v56';
|
||||||
|
|
||||||
const PRECACHE = [
|
const PRECACHE = [
|
||||||
'index.html',
|
'index.html',
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.backends._legacy:_Backend"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "simtrace-analyser"
|
name = "simtrace-analyser"
|
||||||
version = "2.1.0"
|
version = "2.1.1"
|
||||||
description = "SIMtrace Analyser — APDU trace analyser for GSMTAP/PCAP captures (bundles the simtrace2-pysniff utility)"
|
description = "SIMtrace Analyser — APDU trace analyser for GSMTAP/PCAP captures (bundles the simtrace2-pysniff utility)"
|
||||||
readme = {file = "README.md", content-type = "text/markdown"}
|
readme = {file = "README.md", content-type = "text/markdown"}
|
||||||
license = {text = "GPL-2.0-or-later"}
|
license = {text = "GPL-2.0-or-later"}
|
||||||
|
|||||||
@@ -17,18 +17,18 @@ SW_NAMES = {
|
|||||||
(0x62, 0x83): 'Warning — selected file deactivated',
|
(0x62, 0x83): 'Warning — selected file deactivated',
|
||||||
(0x62, 0x84): 'Warning — FCI not formatted per ISO',
|
(0x62, 0x84): 'Warning — FCI not formatted per ISO',
|
||||||
(0x62, 0x85): 'Warning — selected file in termination state',
|
(0x62, 0x85): 'Warning — selected file in termination state',
|
||||||
|
(0x62, 0x86): 'No input data available from a sensor on the card',
|
||||||
(0x62, 0xf1): 'More data available',
|
(0x62, 0xf1): 'More data available',
|
||||||
(0x62, 0xf2): 'More data available and proactive command pending',
|
(0x62, 0xf2): 'More data available and proactive command pending',
|
||||||
(0x62, 0xf3): 'Response data available',
|
(0x62, 0xf3): 'Response data available',
|
||||||
(0x63, 0x00): 'Warning — no information',
|
(0x63, 0x00): 'Warning — no information',
|
||||||
|
(0x63, 0x81): 'File filled up by the last write',
|
||||||
(0x63, 0xf1): 'More data expected',
|
(0x63, 0xf1): 'More data expected',
|
||||||
(0x63, 0xf2): 'More data expected and proactive command pending',
|
(0x63, 0xf2): 'More data expected and proactive command pending',
|
||||||
(0x64, 0x00): 'Execution error — no information',
|
(0x64, 0x00): 'Execution error — no information',
|
||||||
(0x64, 0x01): 'Execution error — immediate response required',
|
(0x64, 0x01): 'Execution error — immediate response required',
|
||||||
(0x65, 0x00): 'Execution error — no information, NV memory changed',
|
(0x65, 0x00): 'Execution error — no information, NV memory changed',
|
||||||
(0x65, 0x81): 'Execution error — memory failure',
|
(0x65, 0x81): 'Execution error — memory failure',
|
||||||
(0x66, 0x00): 'Security error — no information',
|
|
||||||
(0x66, 0x81): 'Reserved for security-related issues',
|
|
||||||
(0x67, 0x00): 'Checking error — wrong length',
|
(0x67, 0x00): 'Checking error — wrong length',
|
||||||
(0x68, 0x00): 'Checking error — no information',
|
(0x68, 0x00): 'Checking error — no information',
|
||||||
(0x68, 0x81): 'Logical channel not supported',
|
(0x68, 0x81): 'Logical channel not supported',
|
||||||
@@ -1030,8 +1030,8 @@ REFRESH_MODES = {
|
|||||||
0x04: 'UICC Reset',
|
0x04: 'UICC Reset',
|
||||||
0x05: 'NAA Application Reset',
|
0x05: 'NAA Application Reset',
|
||||||
0x06: 'NAA Session Reset',
|
0x06: 'NAA Session Reset',
|
||||||
0x07: 'Reserved (Steering of Roaming)',
|
0x07: 'Steering of Roaming',
|
||||||
0x08: 'Reserved (Steering of Roaming for I-WLAN)',
|
0x08: 'Steering of Roaming for I-WLAN',
|
||||||
0x09: 'eUICC Profile State Change',
|
0x09: 'eUICC Profile State Change',
|
||||||
0x0A: 'Application Update',
|
0x0A: 'Application Update',
|
||||||
}
|
}
|
||||||
@@ -1053,9 +1053,8 @@ ENVELOPE_TYPES = {
|
|||||||
0xDE: 'ENVELOPE CONTAINER',
|
0xDE: 'ENVELOPE CONTAINER',
|
||||||
0xDF: 'PROSE REPORT',
|
0xDF: 'PROSE REPORT',
|
||||||
0xE0: '5G PROSE REPORT',
|
0xE0: '5G PROSE REPORT',
|
||||||
0xE1: 'Reserved for 3GPP',
|
# 'E1'-'E3': reserved for 3GPP (for future usage) per TS 31.111 §9.1 —
|
||||||
0xE2: 'Reserved for 3GPP',
|
# no name assigned yet, so they decode as unknown.
|
||||||
0xE3: 'Reserved for 3GPP',
|
|
||||||
0xE4: 'GSMA',
|
0xE4: 'GSMA',
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1100,12 +1099,14 @@ PLI_QUALIFIERS = {
|
|||||||
0x02: 'Network Measurement results',
|
0x02: 'Network Measurement results',
|
||||||
0x03: 'Date, time and time zone',
|
0x03: 'Date, time and time zone',
|
||||||
0x04: 'Language setting',
|
0x04: 'Language setting',
|
||||||
|
# ETSI TS 102 223: "Reserved for GSM" — defined by TS 31.111 §8.6.
|
||||||
0x05: 'Timing Advance',
|
0x05: 'Timing Advance',
|
||||||
0x06: 'Access Technology (single)',
|
0x06: 'Access Technology (single)',
|
||||||
0x07: 'ESN of the terminal',
|
0x07: 'ESN of the terminal',
|
||||||
0x08: 'IMEISV',
|
0x08: 'IMEISV',
|
||||||
0x09: 'Search Mode',
|
0x09: 'Search Mode',
|
||||||
0x0A: 'Battery charge state',
|
0x0A: 'Battery charge state',
|
||||||
|
0x0B: 'MEID of the terminal',
|
||||||
0x0C: 'Current WSID',
|
0x0C: 'Current WSID',
|
||||||
0x0D: 'Broadcast Network info',
|
0x0D: 'Broadcast Network info',
|
||||||
0x0E: 'Multiple Access Technologies',
|
0x0E: 'Multiple Access Technologies',
|
||||||
@@ -1410,7 +1411,8 @@ TR_RESULTS = {
|
|||||||
0x25: 'Interaction with call control by NAA, temporary problem',
|
0x25: 'Interaction with call control by NAA, temporary problem',
|
||||||
0x26: 'Launch browser generic error',
|
0x26: 'Launch browser generic error',
|
||||||
0x27: 'MMS temporary problem',
|
0x27: 'MMS temporary problem',
|
||||||
# '28'-'29' reserved for 3GPP
|
0x28: 'Bearer Independent Protocol temporary error',
|
||||||
|
# '29' reserved for 3GPP (for future usage)
|
||||||
0x30: 'Command beyond ME capabilities',
|
0x30: 'Command beyond ME capabilities',
|
||||||
0x31: 'Command type not understood by ME',
|
0x31: 'Command type not understood by ME',
|
||||||
0x32: 'Command data not understood by ME',
|
0x32: 'Command data not understood by ME',
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
"""Single source of truth for the SIMtrace Analyser version."""
|
"""Single source of truth for the SIMtrace Analyser version."""
|
||||||
|
|
||||||
__version__ = '2.1.0'
|
__version__ = '2.1.1'
|
||||||
@@ -136,6 +136,12 @@ class TestCommandTypeTables(unittest.TestCase):
|
|||||||
self.assertEqual(ENVELOPE_TYPES[0xD3], 'MENU SELECTION')
|
self.assertEqual(ENVELOPE_TYPES[0xD3], 'MENU SELECTION')
|
||||||
self.assertEqual(ENVELOPE_TYPES[0xD6], 'EVENT DOWNLOAD')
|
self.assertEqual(ENVELOPE_TYPES[0xD6], 'EVENT DOWNLOAD')
|
||||||
|
|
||||||
|
def test_unassigned_envelope_tags_unnamed(self):
|
||||||
|
# TS 31.111 §9.1: 'E1'-'E3' reserved for 3GPP (for future usage);
|
||||||
|
# no name exists, so no placeholder label may be shown.
|
||||||
|
for tag in (0xE1, 0xE2, 0xE3):
|
||||||
|
self.assertNotIn(tag, ENVELOPE_TYPES)
|
||||||
|
|
||||||
|
|
||||||
class TestChangeAndFidiDecoding(unittest.TestCase):
|
class TestChangeAndFidiDecoding(unittest.TestCase):
|
||||||
def test_change_reset_assert(self):
|
def test_change_reset_assert(self):
|
||||||
@@ -215,6 +221,13 @@ class TestPliQualifier(unittest.TestCase):
|
|||||||
self.assertEqual(r['cat_command'], 'PROVIDE LOCAL INFORMATION')
|
self.assertEqual(r['cat_command'], 'PROVIDE LOCAL INFORMATION')
|
||||||
self.assertEqual(r['cmd']['qualifier'], '0x03 Date, time and time zone')
|
self.assertEqual(r['cmd']['qualifier'], '0x03 Date, time and time zone')
|
||||||
|
|
||||||
|
def test_fetch_pli_meid(self):
|
||||||
|
# '0B' = MEID of the terminal (TS 102 223 §8.6).
|
||||||
|
r = decode_message(bytes.fromhex(
|
||||||
|
'801200000BD009810301260B820281829000'))
|
||||||
|
self.assertEqual(r['cat_command'], 'PROVIDE LOCAL INFORMATION')
|
||||||
|
self.assertEqual(r['cmd']['qualifier'], '0x0B MEID of the terminal')
|
||||||
|
|
||||||
def test_non_pli_no_qualifier(self):
|
def test_non_pli_no_qualifier(self):
|
||||||
r = decode_message(bytes.fromhex(
|
r = decode_message(bytes.fromhex(
|
||||||
'801400000C810301250002028281830100910F'))
|
'801400000C810301250002028281830100910F'))
|
||||||
@@ -1757,6 +1770,23 @@ class TestSwWrongLength(unittest.TestCase):
|
|||||||
from simtrace_analyser.decode import decode_sw
|
from simtrace_analyser.decode import decode_sw
|
||||||
self.assertIsNone(decode_sw(bytes.fromhex('6205'))['name'])
|
self.assertIsNone(decode_sw(bytes.fromhex('6205'))['name'])
|
||||||
|
|
||||||
|
def test_62_86_sensor_warning(self):
|
||||||
|
from simtrace_analyser.decode import decode_sw
|
||||||
|
self.assertEqual(decode_sw(bytes.fromhex('6286'))['name'],
|
||||||
|
'No input data available from a sensor on the card')
|
||||||
|
|
||||||
|
def test_63_81_file_filled_warning(self):
|
||||||
|
from simtrace_analyser.decode import decode_sw
|
||||||
|
self.assertEqual(decode_sw(bytes.fromhex('6381'))['name'],
|
||||||
|
'File filled up by the last write')
|
||||||
|
|
||||||
|
def test_66_class_not_fabricated(self):
|
||||||
|
# No '66xx' row exists in ISO 7816-4:2005 Table 6 or TS 102 221
|
||||||
|
# tables 10.9/10.10 — the decoder must not invent a name.
|
||||||
|
from simtrace_analyser.decode import decode_sw
|
||||||
|
self.assertIsNone(decode_sw(bytes.fromhex('6600'))['name'])
|
||||||
|
self.assertIsNone(decode_sw(bytes.fromhex('6681'))['name'])
|
||||||
|
|
||||||
|
|
||||||
class TestStatusFcp(unittest.TestCase):
|
class TestStatusFcp(unittest.TestCase):
|
||||||
def test_status_body_is_fcp(self):
|
def test_status_body_is_fcp(self):
|
||||||
@@ -1849,6 +1879,32 @@ class TestRefresh(unittest.TestCase):
|
|||||||
self.assertEqual(r['cmd']['qualifier'], '0x01 File Change Notification')
|
self.assertEqual(r['cmd']['qualifier'], '0x01 File Change Notification')
|
||||||
self.assertEqual(r['cmd']['file_list'], ['6F07', '6F20'])
|
self.assertEqual(r['cmd']['file_list'], ['6F07', '6F20'])
|
||||||
|
|
||||||
|
def test_steering_of_roaming(self):
|
||||||
|
# ETSI "Reserved for GSM/3G" — TS 31.111 §8.6 defines the mode.
|
||||||
|
r = decode_message(bytes.fromhex('801200000bd0098103010107820281829000'))
|
||||||
|
self.assertEqual(r['cmd']['qualifier'], '0x07 Steering of Roaming')
|
||||||
|
|
||||||
|
def test_steering_of_roaming_iwlan(self):
|
||||||
|
r = decode_message(bytes.fromhex('801200000bd0098103010108820281829000'))
|
||||||
|
self.assertEqual(r['cmd']['qualifier'],
|
||||||
|
'0x08 Steering of Roaming for I-WLAN')
|
||||||
|
|
||||||
|
|
||||||
|
class TestNoReservedLabels(unittest.TestCase):
|
||||||
|
# ETSI 'Reserved for GSM/3GPP' values must be resolved via the sibling
|
||||||
|
# spec or left unnamed — never surfaced as a 'Reserved ...' label.
|
||||||
|
|
||||||
|
def test_no_reserved_labels(self):
|
||||||
|
from simtrace_analyser import decode as d
|
||||||
|
for name in ('SW_NAMES', 'REFRESH_MODES', 'ENVELOPE_TYPES',
|
||||||
|
'TR_RESULTS', 'PLI_QUALIFIERS', 'CAT_COMMAND_TYPES',
|
||||||
|
'EVENT_TYPES'):
|
||||||
|
table = getattr(d, name)
|
||||||
|
for value in table.values():
|
||||||
|
if isinstance(value, str):
|
||||||
|
self.assertFalse(value.startswith('Reserved'),
|
||||||
|
f'{name}: {value}')
|
||||||
|
|
||||||
|
|
||||||
class TestIdleModeText(unittest.TestCase):
|
class TestIdleModeText(unittest.TestCase):
|
||||||
"""SET UP IDLE MODE TEXT (TS 102 223 §6.6.13) proactive command."""
|
"""SET UP IDLE MODE TEXT (TS 102 223 §6.6.13) proactive command."""
|
||||||
@@ -2005,6 +2061,13 @@ class TestSpecRegistry(unittest.TestCase):
|
|||||||
self.assertEqual(TR_RESULTS[0x3C], 'Frames error')
|
self.assertEqual(TR_RESULTS[0x3C], 'Frames error')
|
||||||
self.assertEqual(TR_RESULTS[0x3D], 'MMS error')
|
self.assertEqual(TR_RESULTS[0x3D], 'MMS error')
|
||||||
|
|
||||||
|
def test_tr_result_bip_temporary(self):
|
||||||
|
# '28' per TS 102 223 §8.12 (timer in Additional information).
|
||||||
|
from simtrace_analyser.decode import TR_RESULTS
|
||||||
|
self.assertEqual(TR_RESULTS[0x28],
|
||||||
|
'Bearer Independent Protocol temporary error')
|
||||||
|
self.assertNotIn(0x29, TR_RESULTS)
|
||||||
|
|
||||||
def test_envelope_types_extended(self):
|
def test_envelope_types_extended(self):
|
||||||
from simtrace_analyser.decode import ENVELOPE_TYPES
|
from simtrace_analyser.decode import ENVELOPE_TYPES
|
||||||
self.assertEqual(ENVELOPE_TYPES[0xD9], 'USSD DOWNLOAD')
|
self.assertEqual(ENVELOPE_TYPES[0xD9], 'USSD DOWNLOAD')
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ class TestImportEndpoint(unittest.TestCase):
|
|||||||
class TestVersion(unittest.TestCase):
|
class TestVersion(unittest.TestCase):
|
||||||
def test_package_version(self):
|
def test_package_version(self):
|
||||||
from simtrace2_pysniff import __version__
|
from simtrace2_pysniff import __version__
|
||||||
self.assertEqual(__version__, '2.1.0')
|
self.assertEqual(__version__, '2.1.1')
|
||||||
|
|
||||||
def test_status_includes_version(self):
|
def test_status_includes_version(self):
|
||||||
import os
|
import os
|
||||||
|
|||||||
Reference in new issue
Block a user