static TEE_Result internal_manage_channel(struct tee_se_session *s, bool open_ops, int *channel_id) { struct cmd_apdu *cmd; struct resp_apdu *resp; TEE_Result ret; size_t tx_buf_len = 0, rx_buf_len = 1; uint8_t open_flag = (open_ops) ? OPEN_CHANNEL : CLOSE_CHANNEL; uint8_t channel_flag = (open_flag == OPEN_CHANNEL) ? OPEN_NEXT_AVAILABLE : *channel_id; assert(s); cmd = alloc_cmd_apdu(ISO7816_CLA, MANAGE_CHANNEL_CMD, open_flag, channel_flag, tx_buf_len, rx_buf_len, NULL); resp = alloc_resp_apdu(rx_buf_len); ret = tee_se_session_transmit(s, cmd, resp); if (ret != TEE_SUCCESS) { EMSG("exchange apdu failed: %d", ret); return ret; } if (resp->sw1 == CMD_OK_SW1 && resp->sw2 == CMD_OK_SW2) { if (open_ops) *channel_id = resp->base.data_buf[0]; ret = TEE_SUCCESS; } else { EMSG("operation failed, sw1:%02X, sw2:%02X", resp->sw1, resp->sw2); ret = TEE_ERROR_NOT_SUPPORTED; } apdu_release(to_apdu_base(cmd)); apdu_release(to_apdu_base(resp)); return ret; }
static TEE_Result internal_select(struct tee_se_channel *c, struct tee_se_aid *aid, int select_ops) { struct cmd_apdu *cmd; struct resp_apdu *resp; struct tee_se_session *s; TEE_Result ret; TEE_SEReaderProperties prop; size_t rx_buf_len = 0; int channel_id; uint8_t cla_channel; assert(c); s = tee_se_channel_get_session(c); channel_id = tee_se_channel_get_id(c); if (channel_id >= MAX_LOGICAL_CHANNEL) panic("invalid channel id"); cla_channel = iso7816_get_cla_channel(channel_id); if (select_ops == FIRST_OR_ONLY_OCCURRENCE) { assert(aid); cmd = alloc_cmd_apdu(ISO7816_CLA | cla_channel, SELECT_CMD, SELECT_BY_AID, select_ops, aid->length, rx_buf_len, aid->aid); } else { cmd = alloc_cmd_apdu(ISO7816_CLA | cla_channel, SELECT_CMD, SELECT_BY_AID, select_ops, 0, rx_buf_len, NULL); } resp = alloc_resp_apdu(rx_buf_len); ret = tee_se_session_transmit(s, cmd, resp); if (ret != TEE_SUCCESS) { EMSG("exchange apdu failed: %d", ret); return ret; } tee_se_reader_get_properties(s->reader_proxy, &prop); if (prop.selectResponseEnable) tee_se_channel_set_select_response(c, resp); if (aid) tee_se_channel_set_aid(c, aid); if (resp->sw1 == CMD_OK_SW1 && resp->sw2 == CMD_OK_SW2) { ret = TEE_SUCCESS; } else { EMSG("operation failed, sw1:%02X, sw2:%02X", resp->sw1, resp->sw2); if (resp->sw1 == 0x6A && resp->sw2 == 0x83) ret = TEE_ERROR_ITEM_NOT_FOUND; else ret = TEE_ERROR_NOT_SUPPORTED; } apdu_release(to_apdu_base(cmd)); apdu_release(to_apdu_base(resp)); return ret; }
TEE_Result syscall_se_channel_transmit(unsigned long channel_handle, void *cmd, unsigned long cmd_len, void *resp, uint64_t *resp_len) { TEE_Result ret; struct tee_se_channel *c = tee_svc_uref_to_kaddr(channel_handle); struct tee_ta_session *sess; struct tee_se_service *service; struct cmd_apdu *cmd_apdu; struct resp_apdu *resp_apdu; void *kcmd_buf; uint64_t kresp_len; ret = tee_ta_get_current_session(&sess); if (ret != TEE_SUCCESS) return ret; service = to_user_ta_ctx(sess->ctx)->se_service; if (!tee_se_service_is_channel_valid(service, c)) return TEE_ERROR_BAD_PARAMETERS; ret = tee_svc_copy_from_user(&kresp_len, resp_len, sizeof(kresp_len)); if (ret != TEE_SUCCESS) return ret; kcmd_buf = malloc(cmd_len); if (kcmd_buf == NULL) return TEE_ERROR_OUT_OF_MEMORY; ret = tee_svc_copy_from_user(kcmd_buf, cmd, cmd_len); if (ret != TEE_SUCCESS) goto err_free_cmd_buf; cmd_apdu = alloc_cmd_apdu_from_buf(kcmd_buf, cmd_len); if (cmd_apdu == NULL) goto err_free_cmd_buf; kresp_len -= 2; /* reserve space for SW1 and SW2 */ resp_apdu = alloc_resp_apdu(kresp_len); if (resp_apdu == NULL) goto err_free_cmd_apdu; ret = tee_se_channel_transmit(c, cmd_apdu, resp_apdu); if (ret != TEE_SUCCESS) goto err_free_resp_apdu; kresp_len = apdu_get_length(to_apdu_base(resp_apdu)); ret = tee_svc_copy_to_user(resp_len, &kresp_len, sizeof(*resp_len)); if (ret != TEE_SUCCESS) goto err_free_resp_apdu; ret = tee_svc_copy_to_user(resp, resp_apdu_get_data(resp_apdu), kresp_len); if (ret != TEE_SUCCESS) goto err_free_resp_apdu; apdu_release(to_apdu_base(resp_apdu)); apdu_release(to_apdu_base(cmd_apdu)); free(kcmd_buf); return TEE_SUCCESS; err_free_resp_apdu: apdu_release(to_apdu_base(resp_apdu)); err_free_cmd_apdu: apdu_release(to_apdu_base(cmd_apdu)); err_free_cmd_buf: free(kcmd_buf); return ret; }