aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Wild <ewild@sysmocom.de>2019-11-27 14:43:16 +0100
committerEric Wild <ewild@sysmocom.de>2019-11-28 13:42:16 +0100
commit9e622dc4b7b7cb383f3afc885aeace40e0367b0c (patch)
treea4ac9b6289bed6565c3f94fe7388bbae3d00ab28
parentad1edce363aaa40b840a57a623bbc9ce5b89889d (diff)
attempt at handling card insertion/removal
-rw-r--r--ccid_common/ccid_device.c13
-rw-r--r--ccid_common/ccid_device.h3
-rw-r--r--ccid_common/ccid_slot_fsm.c33
-rw-r--r--ccid_common/iso7816_fsm.c68
-rw-r--r--ccid_common/iso7816_fsm.h1
-rw-r--r--sysmoOCTSIM/main.c2
6 files changed, 89 insertions, 31 deletions
diff --git a/ccid_common/ccid_device.c b/ccid_common/ccid_device.c
index c67c52e..11edd3e 100644
--- a/ccid_common/ccid_device.c
+++ b/ccid_common/ccid_device.c
@@ -438,9 +438,20 @@ static int ccid_handle_xfr_block(struct ccid_slot *cs, struct msgb *msg)
{
const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
const struct ccid_header *ch = (const struct ccid_header *) u;
+ struct msgb *resp;
+ int rc;
/* handle this asynchronously */
- cs->ci->slot_ops->xfr_block_async(cs, msg, &u->xfr_block);
+ rc = cs->ci->slot_ops->xfr_block_async(cs, msg, &u->xfr_block);
+ if (rc < 0) {
+ msgb_trim(msg, sizeof(struct ccid_rdr_to_pc_data_block));
+ resp = ccid_gen_data_block(cs, u->xfr_block.hdr.bSeq, CCID_CMD_STATUS_FAILED, -rc, 0, 0);
+ goto out;
+ }
+ /* busy */
+ return 1;
+out:
+ ccid_slot_send_unbusy(cs, resp);
return 1;
}
diff --git a/ccid_common/ccid_device.h b/ccid_common/ccid_device.h
index 8390783..38a71db 100644
--- a/ccid_common/ccid_device.h
+++ b/ccid_common/ccid_device.h
@@ -78,13 +78,14 @@ struct ccid_slot_ops {
void (*icc_power_on_async)(struct ccid_slot *cs, struct msgb *msg,
const struct ccid_pc_to_rdr_icc_power_on *ipo);
- void (*xfr_block_async)(struct ccid_slot *cs, struct msgb *msg,
+ int (*xfr_block_async)(struct ccid_slot *cs, struct msgb *msg,
const struct ccid_pc_to_rdr_xfr_block *xfb);
void (*set_power)(struct ccid_slot *cs, bool enable);
void (*set_clock)(struct ccid_slot *cs, enum ccid_clock_command cmd);
int (*set_params)(struct ccid_slot *cs, uint8_t seq, enum ccid_protocol_num proto,
const struct ccid_pars_decoded *pars_dec);
int (*set_rate_and_clock)(struct ccid_slot *cs, uint32_t freq_hz, uint32_t rate_bps);
+ void (*icc_set_insertion_status)(struct ccid_slot *cs, bool present);
};
/* An instance of CCID (i.e. a card reader device) */
diff --git a/ccid_common/ccid_slot_fsm.c b/ccid_common/ccid_slot_fsm.c
index 8bdcfd5..8d38f29 100644
--- a/ccid_common/ccid_slot_fsm.c
+++ b/ccid_common/ccid_slot_fsm.c
@@ -66,6 +66,23 @@ static void iso_fsm_slot_pre_proc_cb(struct ccid_slot *cs, struct msgb *msg)
/* do nothing; real hardware would update the slot related state here */
}
+static void iso_fsm_slot_icc_set_insertion_status(struct ccid_slot *cs, bool present) {
+ struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
+
+ if(present == cs->icc_present)
+ return;
+
+ cs->icc_present = present;
+
+ if (!present) {
+ osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_CARD_REMOVAL, NULL);
+ card_uart_ctrl(ss->cuart, CUART_CTL_RST, true);
+ card_uart_ctrl(ss->cuart, CUART_CTL_POWER, false);
+ cs->icc_powered = false;
+ cs->cmd_busy = false;
+ }
+}
+
static void iso_fsm_slot_icc_power_on_async(struct ccid_slot *cs, struct msgb *msg,
const struct ccid_pc_to_rdr_icc_power_on *ipo)
{
@@ -113,6 +130,15 @@ static void iso_fsm_clot_user_cb(struct osmo_fsm_inst *fi, int event, int cause,
ccid_slot_send_unbusy(cs, resp);
msgb_free(tpdu);
break;
+ case ISO7816_E_TPDU_FAILED_IND:
+ tpdu = data;
+ LOGPCS(cs, LOGL_DEBUG, "%s(event=%d, cause=%d, data=%s)\n", __func__, event, cause,
+ msgb_hexdump(tpdu));
+ /* FIXME: other error causes than card removal?*/
+ resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_FAILED, CCID_ERR_ICC_MUTE, msgb_l2(tpdu), 0);
+ ccid_slot_send_unbusy(cs, resp);
+ msgb_free(tpdu);
+ break;
case ISO7816_E_PPS_DONE_IND:
tpdu = data;
/* pps was successful, so we know these values are fine */
@@ -147,12 +173,15 @@ static void iso_fsm_clot_user_cb(struct osmo_fsm_inst *fi, int event, int cause,
}
}
-static void iso_fsm_slot_xfr_block_async(struct ccid_slot *cs, struct msgb *msg,
+static int iso_fsm_slot_xfr_block_async(struct ccid_slot *cs, struct msgb *msg,
const struct ccid_pc_to_rdr_xfr_block *xfb)
{
struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
struct msgb *tpdu;
+ if(!cs->icc_present)
+ return -CCID_ERR_ICC_MUTE;
+
ss->seq = xfb->hdr.bSeq;
/* must be '0' for TPDU level exchanges or for short APDU */
@@ -171,6 +200,7 @@ static void iso_fsm_slot_xfr_block_async(struct ccid_slot *cs, struct msgb *msg,
LOGPCS(cs, LOGL_DEBUG, "scheduling TPDU transfer: %s\n", msgb_hexdump(tpdu));
osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_XCEIVE_TPDU_CMD, tpdu);
/* continues in iso_fsm_clot_user_cb once response/error/timeout is received */
+ return 0;
}
@@ -296,6 +326,7 @@ const struct ccid_slot_ops iso_fsm_slot_ops = {
.init = iso_fsm_slot_init,
.pre_proc_cb = iso_fsm_slot_pre_proc_cb,
.icc_power_on_async = iso_fsm_slot_icc_power_on_async,
+ .icc_set_insertion_status = iso_fsm_slot_icc_set_insertion_status,
.xfr_block_async = iso_fsm_slot_xfr_block_async,
.set_power = iso_fsm_slot_set_power,
.set_clock = iso_fsm_slot_set_clock,
diff --git a/ccid_common/iso7816_fsm.c b/ccid_common/iso7816_fsm.c
index d02a955..98c32d3 100644
--- a/ccid_common/iso7816_fsm.c
+++ b/ccid_common/iso7816_fsm.c
@@ -45,7 +45,6 @@ enum iso7816_3_state {
ISO7816_S_IN_ATR, /*!< while we are receiving the ATR */
ISO7816_S_WAIT_TPDU, /*!< waiting for start of new TPDU */
ISO7816_S_IN_TPDU, /*!< inside a single TPDU */
- ISO7816_S_IN_PPS_REQ, /*!< while we are inside the PPS request */
ISO7816_S_WAIT_PPS_RSP, /*!< waiting for start of the PPS response */
ISO7816_S_IN_PPS_RSP, /*!< while we are inside the PPS request */
};
@@ -230,6 +229,7 @@ static void iso7816_3_reset_action(struct osmo_fsm_inst *fi, uint32_t event, voi
{
struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);
OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);
+ struct msgb *msg;
switch (event) {
case ISO7816_E_RESET_REL_IND:
@@ -238,6 +238,16 @@ static void iso7816_3_reset_action(struct osmo_fsm_inst *fi, uint32_t event, voi
osmo_fsm_inst_state_chg_ms(fi, ISO7816_S_WAIT_ATR,
fi_cycles2ms(fi, 40000), T_WAIT_ATR);
break;
+ case ISO7816_E_PPS_FAILED_IND:
+ msg = data;
+ /* notify user about PPS result */
+ ip->user_cb(fi, event, 0, msg);
+ break;
+ case ISO7816_E_TPDU_FAILED_IND:
+ msg = data;
+ /* hand finished TPDU to user */
+ ip->user_cb(fi, event, 0, msg);
+ break;
default:
OSMO_ASSERT(0);
}
@@ -375,19 +385,6 @@ static void iso7816_3_allstate_action(struct osmo_fsm_inst *fi, uint32_t event,
}
}
-static void iso7816_3_in_pps_req_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct iso7816_3_priv *tfp = get_iso7816_3_priv(fi);
-
- switch (event) {
- case ISO7816_E_XCEIVE_PPS_CMD:
- osmo_fsm_inst_state_chg(fi, ISO7816_S_WAIT_PPS_RSP, 0, 0);
- break;
- default:
- OSMO_ASSERT(0);
- }
-}
-
static void iso7816_3_s_wait_pps_rsp_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
@@ -434,7 +431,9 @@ static void iso7816_3_s_ins_pps_rsp_action(struct osmo_fsm_inst *fi, uint32_t ev
static const struct osmo_fsm_state iso7816_3_states[] = {
[ISO7816_S_RESET] = {
.name = "RESET",
- .in_event_mask = S(ISO7816_E_RESET_REL_IND),
+ .in_event_mask = S(ISO7816_E_RESET_REL_IND) |
+ S(ISO7816_E_PPS_FAILED_IND)|
+ S(ISO7816_E_TPDU_FAILED_IND),
.out_state_mask = S(ISO7816_S_WAIT_ATR) |
S(ISO7816_S_RESET),
.action = iso7816_3_reset_action,
@@ -467,7 +466,6 @@ static const struct osmo_fsm_state iso7816_3_states[] = {
.out_state_mask = S(ISO7816_S_RESET) |
S(ISO7816_S_WAIT_TPDU) |
S(ISO7816_S_IN_TPDU) |
- S(ISO7816_S_IN_PPS_REQ) |
S(ISO7816_S_WAIT_PPS_RSP),
.action = iso7816_3_wait_tpdu_action,
.onenter = iso7816_3_wait_tpdu_onenter,
@@ -486,15 +484,6 @@ static const struct osmo_fsm_state iso7816_3_states[] = {
S(ISO7816_S_IN_TPDU),
.action = iso7816_3_in_tpdu_action,
},
- [ISO7816_S_IN_PPS_REQ] = {
- .name = "IN_PPS_REQ",
- .in_event_mask = S(ISO7816_E_XCEIVE_TPDU_CMD),
- .out_state_mask = S(ISO7816_S_RESET) |
- S(ISO7816_S_WAIT_TPDU) |
- S(ISO7816_S_IN_PPS_REQ) |
- S(ISO7816_S_WAIT_PPS_RSP),
- .action = iso7816_3_in_pps_req_action,
- },
[ISO7816_S_WAIT_PPS_RSP] = {
.name = "WAIT_PPS_RESP",
.in_event_mask = S(ISO7816_E_TX_COMPL) |
@@ -881,18 +870,27 @@ static void pps_s_wait_ppss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state
struct pps_fsm_priv *atp = fi->priv;
if (!atp->rx_cmd)
- atp->rx_cmd = msgb_alloc_c(fi, 6, "ATR"); /* TS + 32 chars */
+ atp->rx_cmd = msgb_alloc_c(fi, 6, "PPSRSP"); /* at most 6 */
else
msgb_reset(atp->rx_cmd);
+
+ /* notify in case card got pulled out */
+ if (atp->tx_cmd){
+ osmo_fsm_inst_dispatch(fi->proc.parent,
+ ISO7816_E_PPS_FAILED_IND, atp->tx_cmd);
+ atp->tx_cmd = 0;
+ }
}
static void pps_s_tx_pps_req_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct pps_fsm_priv *atp = fi->priv;
- atp->tx_cmd = data;
struct osmo_fsm_inst *parent_fi = fi->proc.parent;
struct iso7816_3_priv *ip = get_iso7816_3_priv(parent_fi);
+ /* keep the buffer to compare it with the received response */
+ atp->tx_cmd = data;
+
switch (event) {
case ISO7816_E_XCEIVE_PPS_CMD:
osmo_fsm_inst_state_chg(fi, PPS_S_WAIT_PPSS, 0, 0);
@@ -972,6 +970,8 @@ static void pps_wait_pX_action(struct osmo_fsm_inst *fi, uint32_t event, void *d
osmo_fsm_inst_dispatch(fi->proc.parent,
ISO7816_E_PPS_FAILED_IND, atp->tx_cmd);
}
+ /* ownership transfer */
+ atp->tx_cmd = 0;
}
break;
default:
@@ -1093,6 +1093,16 @@ static struct tpdu_fsm_priv *get_tpdu_fsm_priv(struct osmo_fsm_inst *fi)
return (struct tpdu_fsm_priv *) fi->priv;
}
+static void tpdu_s_init_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
+{
+ struct tpdu_fsm_priv *tfp = get_tpdu_fsm_priv(fi);
+
+ /* notify in case card got pulled out */
+ if (tfp->tpdu){
+ osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_FAILED_IND, tfp->tpdu);
+ tfp->tpdu = 0;
+ }
+}
static void tpdu_s_init_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
@@ -1311,6 +1321,9 @@ static void tpdu_s_sw2_action(struct osmo_fsm_inst *fi, uint32_t event, void *da
osmo_fsm_inst_state_chg(fi, TPDU_S_DONE, 0, 0);
/* Notify parent FSM */
osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_TPDU_DONE_IND, tfp->tpdu);
+
+ /* ownership transfer */
+ tfp->tpdu = 0;
break;
default:
OSMO_ASSERT(0);
@@ -1342,6 +1355,7 @@ static const struct osmo_fsm_state tpdu_states[] = {
.out_state_mask = S(TPDU_S_INIT) |
S(TPDU_S_TX_HDR),
.action = tpdu_s_init_action,
+ .onenter = tpdu_s_init_onenter,
},
[TPDU_S_TX_HDR] = {
.name = "TX_HDR",
diff --git a/ccid_common/iso7816_fsm.h b/ccid_common/iso7816_fsm.h
index f512709..d4aee59 100644
--- a/ccid_common/iso7816_fsm.h
+++ b/ccid_common/iso7816_fsm.h
@@ -32,6 +32,7 @@ enum iso7816_3_event {
ISO7816_E_ATR_DONE_IND, /*!< ATR Done indication from ATR child FSM */
ISO7816_E_ATR_ERR_IND, /*!< ATR Error indication from ATR child FSM */
ISO7816_E_TPDU_DONE_IND, /*!< TPDU Done indication from TPDU child FSM */
+ ISO7816_E_TPDU_FAILED_IND, /*!< TPDU Failed indication from TPDU child FSM */
ISO7816_E_TPDU_CLEAR_REQ, /*!< Return TPDU FSM to TPDU_S_INIT */
};
diff --git a/sysmoOCTSIM/main.c b/sysmoOCTSIM/main.c
index 7ddca92..959e7eb 100644
--- a/sysmoOCTSIM/main.c
+++ b/sysmoOCTSIM/main.c
@@ -303,7 +303,7 @@ static void poll_card_detect(void)
for (i = 0; i < 8; i++){
bool level = ncn8025_interrupt_level(i);
new_mask |= level << i;
- g_ci.slot[i].icc_present = level;
+ g_ci.slot_ops->icc_set_insertion_status(&g_ci.slot[i], level);
}
/* notify the user/host about any changes */