firmware: card_emu: use Di in the waiting time

ISO 7816-3 section 10.2 defines WT = WI x 960 x Fi/f seconds,
store as etu, etu = Fi / (D x f) seconds, so the Fi cancels,
but the D does not:

	WT [etu] = WI x 960 x D

cemu dropped both (?!) -> WI x 960.
The old comment explains why Fi can be dropped, which is right, but
what about Di ?!
sniffer gets it right (wt_wi * 960UL * wt_d), so the two state machines
disagreed here again, by up to a factor of 64???!!?!!?

This was fixed in osmo-ccid-firmware in 066489d in 2020 but not ported
to st2.

Additionally the waiting time was only recalculated at the end of the ATR,
where D is still 1 by definition, so a PPS increasing D reprogrammed the
baud rate but left the waiting time untouched??!

etu duration shrinks with D by the same factor, wall clock WT is
independent of D, which is the whole point.
The old code decreased the waiting time by a factor of D:
after a PPS to D=8 the card emitted its NULL procedure byte at ~0.09s
instead of ~0.71s with a reader deadline of ~1.43s,
and the inactivity timeout fires 8x too early, which probably led to
unexplained wtime_exp errors.

Update wt when WI becomes known (end of ATR) and
where D changes (after the PPS response) + tests.

Change-Id: I4263176d6073029d01f9ff5b11a6311617956af6
This commit is contained in:
Eric Wild
2026-07-28 17:42:32 +02:00
committed by lynxis lazus
parent 88a6a782a2
commit b36adff672
2 changed files with 97 additions and 11 deletions
+25 -5
View File
@@ -386,6 +386,26 @@ static void emu_update_fidi(struct card_handle *ch)
ch->num, rc);
}
/*! Calculate the WT from current WI and D.
*
* ISO 7816-3 10.2 defines WT = WI x 960 x Fi / f [seconds].
* Our waiting time is stored in units of etu = Fi / (D x f) seconds
* -> the Fi cancels out, but D does not.
*
* WT [etu] = WI x 960 x D
*
* D is the value from ISO 7816-3 Table 8. Only 1..9 are defined,
* 0 and RFU range 10..15 have no D -> use D = 1 */
static void emu_update_wt(struct card_handle *ch)
{
uint8_t d = 1;
if (ch->D_index >= 1 && ch->D_index <= 9)
d = iso7816_3_di_table[ch->D_index];
ch->waiting_time = ch->wi * 960 * d;
}
/* Update the ISO 7816-3 TPDU receiver state */
static void card_set_state(struct card_handle *ch,
enum iso7816_3_card_state new_state)
@@ -505,11 +525,8 @@ static int tx_byte_atr(struct card_handle *ch)
}
}
}
/* update waiting time (see ISO 7816-3 10.2). We can drop the Fi
* multiplier as we store the waiting time in units of 'etu', and
* don't really care what the number of clock cycles or the absolute
* wall clock time is */
ch->waiting_time = ch->wi * 960;
/* update the waiting time now that WI is known (see emu_update_wt) */
emu_update_wt(ch);
/* go to next state */
card_set_state(ch, ISO_S_WAIT_TPDU);
return 0;
@@ -675,6 +692,9 @@ static int tx_byte_pts(struct card_handle *ch)
card_emu_uart_wait_tx_idle(ch->uart_chan);
/* update baud rate generator with F/D */
emu_update_fidi(ch);
/* the waiting time is expressed in etu and scales with D, so it has
* to be recomputed whenever D changes */
emu_update_wt(ch);
/* Wait for the next TPDU */
card_set_state(ch, ISO_S_WAIT_TPDU);
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);