Code-review fixes: bad-format visibility, view-aware sync, counter hygiene
- The RAM step line (and the plain send's PoR line) now name a bad-format
failure ("bad format 02 (wrong length)") instead of reading "PoR ok": the
step record carries por_bad_format_name and ramStepLine renders it.
- ramSyncCounter follows the view the notice came from ('ram'/'sp' - preset
and keyset selectors alike) and refreshes the keyset labels after a sync.
- The ETSI-release line no longer hides behind the memory block (it needs
only the ELF list).
- /api/send-ota reports final_cntr only for a packet the card accepted: the
failed-envelope path used to persist the packet's own counter on a
rejection (the audit trail's small bump on cntr_low).
- _ram_detect_format's docstring corrected (both expanded codings execute on
the live ISD; the earlier bad format was a length-mismatched template).
- Tests: ramStepLine bad format, the view-aware notice, the accepted/rejected
final_cntr cases, and an end-to-end /api/counter-probe endpoint test
(400s, no write on a rejected walk, accepted+1 stored).
- sw cache simple-v356.
This commit is contained in:
@@ -1553,10 +1553,11 @@ def _ram_detect_format(server, scc, sp, state):
|
||||
"""Detect the card's RAM command format for one operation: send the
|
||||
read-only GET STATUS [ISD] probe compact, then in the two expanded
|
||||
codings; the first format whose remote SW succeeds wins (compact
|
||||
preferred). Cards implement different subsets - the live ISD answers the
|
||||
definite form with a Bad format TLV (wrong length) and executes the
|
||||
indefinite one, while an RFM applet took the definite form. Probe
|
||||
packets are recorded as steps and consume counters only when accepted;
|
||||
preferred). Cards implement different subsets: the reference TCA loader
|
||||
sends the listing queries wrapped and unchained, while the live card needs
|
||||
the compact chain (a length-mismatched template draws a Bad format TLV,
|
||||
which the step result names). Probe packets are recorded as steps and
|
||||
consume counters only when accepted;
|
||||
the result is used for this operation only - the next operation re-checks
|
||||
(v3.6.24)."""
|
||||
for fmt, apdu in (('compact', _RAM_PROBE_APDU),
|
||||
@@ -1579,7 +1580,8 @@ def _ram_detect_format(server, scc, sp, state):
|
||||
# accepted, so rejected attempts change nothing; the search walks a doubling
|
||||
# ladder (start+1, +2, +4, ...) and stops at a ceiling far below the 40-bit
|
||||
# maximum, where the counter would get blocked.
|
||||
COUNTER_PROBE_DEFAULT_APDU = '00A40000023F00' # SELECT MF: read-only, applet-visible
|
||||
COUNTER_PROBE_DEFAULT_APDU = '00A40000023F00' # SELECT MF, as TAR_PROBE_DEFAULT_APDU
|
||||
# (a literal: that constant is defined later)
|
||||
COUNTER_PROBE_CEILING = 'FFFFFFFF' # 32-bit default
|
||||
COUNTER_PROBE_MAX_ATTEMPTS = 40 # doubling covers 40 bits
|
||||
|
||||
@@ -1810,6 +1812,7 @@ def _ram_step_result(step_name, last_sw, por, por_hex, bytes_, segments):
|
||||
# the expanded script was rejected as malformed before executing:
|
||||
# there is no remote status word
|
||||
step['por_bad_format'] = por['bad_format']
|
||||
step['por_bad_format_name'] = por.get('bad_format_name')
|
||||
error = 'bad format %s (%s)' % (por['bad_format'],
|
||||
por.get('bad_format_name') or '')
|
||||
elif pstatus != 'por_ok':
|
||||
@@ -3793,7 +3796,8 @@ def _build_tr(scc, cmd_num, cmd_type, dev_src, dev_dst, cmd_qual, dt=None):
|
||||
|
||||
The object order follows TS 102 223 6.8.0: command details, device
|
||||
identities, Result, then the command-specific data objects (the echoed
|
||||
Duration for POLL INTERVAL, the PLI data for PROVIDE LOCAL INFORMATION)."""
|
||||
Duration for POLL INTERVAL, the PLI data for PROVIDE LOCAL INFORMATION).
|
||||
`dt` is a test seam for the PLI date/time default (see _pli_data_hex)."""
|
||||
base = bytes([0x81, 0x03, cmd_num, cmd_type, 0x00,
|
||||
0x82, 0x02, dev_dst, dev_src,
|
||||
0x03, 0x01, 0x00])
|
||||
@@ -7275,8 +7279,6 @@ class PysimHandler(BaseHTTPRequestHandler):
|
||||
resp = result
|
||||
if ram_format is not None:
|
||||
resp['ram_format'] = ram_format
|
||||
if _counter_valid(cntr) and counter_tracked:
|
||||
resp['final_cntr'] = cntr
|
||||
# A warning ENVELOPE may still carry the PoR (the
|
||||
# card's counter verdict): decode it so the caller
|
||||
# sees 'cntr_low' instead of a bare failure.
|
||||
@@ -7294,6 +7296,15 @@ class PysimHandler(BaseHTTPRequestHandler):
|
||||
resp.update(low)
|
||||
sys.stderr.write('OTA CNTR-LOW: the packet counter is not '
|
||||
'above the card\'s\n')
|
||||
# only a packet the card accepted consumes the
|
||||
# counter (a warning ENVELOPE can still carry a
|
||||
# por_ok PoR); a rejected one must leave the store
|
||||
# untouched (v3.9.x - it used to persist the
|
||||
# packet's own counter here)
|
||||
if (_counter_valid(cntr) and counter_tracked and
|
||||
failed_por.get('response_status') in
|
||||
('por_ok', 'actual_response_sms_submit')):
|
||||
resp['final_cntr'] = _ram_next_cntr(cntr, True)
|
||||
sys.stderr.write('OTA SEND FAILED: %s\n' % result.get('error'))
|
||||
else:
|
||||
resp = {'success': True, 'sw': result['sw'],
|
||||
@@ -7358,9 +7369,12 @@ class PysimHandler(BaseHTTPRequestHandler):
|
||||
# (v3.8.0). A pre-built packet may come without a
|
||||
# counter, and a packet whose SPI1 does not ask the card
|
||||
# to check it has none to track - nothing is reported
|
||||
# then (and int('') never happens).
|
||||
if _counter_valid(cntr) and counter_tracked:
|
||||
resp['final_cntr'] = _ram_next_cntr(cntr, accepted)
|
||||
# then (and int('') never happens). A rejected verdict
|
||||
# (cntr_low, PoR error) reports nothing either: the
|
||||
# store must not move on a packet the card did not
|
||||
# consume.
|
||||
if _counter_valid(cntr) and counter_tracked and accepted:
|
||||
resp['final_cntr'] = _ram_next_cntr(cntr, True)
|
||||
finally:
|
||||
if submit_handler and hasattr(scc, '_tp'):
|
||||
scc._tp.proactive_handler = old_proactive
|
||||
|
||||
Reference in New Issue
Block a user