* Boston, MA 02110-1301 USA.
*/
+#include "qmi-message.h"
+
static int uim_slot = 0;
+static int channel_id = -1;
+static uint8_t aid[16];
+static uint8_t apdu[1024];
#define cmd_uim_verify_pin1_cb no_cb
static enum qmi_cmd_result
qmi_set_uim_power_on_sim_request(msg, &data);
return QMI_CMD_REQUEST;
}
+
+#define cmd_uim_channel_id_cb no_cb
+static enum qmi_cmd_result
+cmd_uim_channel_id_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
+{
+ char *err;
+ int value = strtoul(arg, &err, 10);
+ if ((err && *err) || value < 1 || value > 4) {
+ uqmi_add_error("Invalid Channel-ID value. Allowed: [1,2,3,4]");
+ return QMI_CMD_EXIT;
+ }
+
+ channel_id = value;
+
+ return QMI_CMD_DONE;
+}
+
+static void cmd_uim_open_logical_channel_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
+{
+ struct qmi_uim_open_logical_channel_response res;
+ void *c;
+
+ qmi_parse_uim_open_logical_channel_response(msg, &res);
+
+ c = blobmsg_open_table(&status, NULL);
+ blobmsg_add_u32(&status, "channel_id", res.data.channel_id);
+ blobmsg_add_u32(&status, "sw1", res.data.card_result.sw1);
+ blobmsg_add_u32(&status, "sw2", res.data.card_result.sw2);
+ blobmsg_close_table(&status, c);
+}
+
+static enum qmi_cmd_result
+cmd_uim_open_logical_channel_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
+{
+ struct qmi_uim_open_logical_channel_request data = {
+ QMI_INIT(slot, uim_slot),
+ QMI_INIT_ARRAY(aid, aid, (strlen(arg) / 2)),
+ };
+
+
+ if (!uim_slot) {
+ uqmi_add_error("UIM-Slot not set");
+ return QMI_CMD_EXIT;
+ }
+
+ if (!arg) {
+ uqmi_add_error("Missing AID argument");
+ return QMI_CMD_EXIT;
+ }
+
+ if (strlen(arg) % 2 || strlen(arg) > sizeof(aid) * 2 ||
+ !uqmi_hexstring_parse(aid, (uint8_t *)arg, strlen(arg))) {
+ uqmi_add_error("Invalid AID argument");
+ return QMI_CMD_EXIT;
+ }
+
+ qmi_set_uim_open_logical_channel_request(msg, &data);
+ return QMI_CMD_REQUEST;
+}
+
+#define cmd_uim_close_logical_channel_cb no_cb
+static enum qmi_cmd_result
+cmd_uim_close_logical_channel_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
+{
+ struct qmi_uim_logical_channel_request data = {
+ QMI_INIT(slot, uim_slot),
+ QMI_INIT(channel_id, channel_id),
+ };
+
+ if (!uim_slot) {
+ uqmi_add_error("UIM-Slot not set. Use --uim-slot <slot> to set it.");
+ return QMI_CMD_EXIT;
+ }
+
+ if (channel_id < 1) {
+ uqmi_add_error("Invalid channel-id set.");
+ return QMI_CMD_EXIT;
+ }
+
+ qmi_set_uim_logical_channel_request(msg, &data);
+ return QMI_CMD_REQUEST;
+}
+
+static void cmd_uim_send_apdu_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
+{
+ struct qmi_uim_send_apdu_response res;
+ uint8_t *hexstr;
+ void *c;
+
+ qmi_parse_uim_send_apdu_response(msg, &res);
+
+ hexstr = calloc(1, res.data.apdu_response_n * 2 + 1);
+ if (!hexstr)
+ return;
+
+ uqmi_hexstring_create(hexstr, res.data.apdu_response, res.data.apdu_response_n);
+
+ c = blobmsg_open_table(&status, NULL);
+ blobmsg_add_string(&status, "response", (char *)hexstr);
+ blobmsg_close_table(&status, c);
+
+ free(hexstr);
+}
+
+static enum qmi_cmd_result
+cmd_uim_send_apdu_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg)
+{
+ struct qmi_uim_send_apdu_request data = {
+ QMI_INIT(slot, uim_slot),
+ QMI_INIT(channel_id, channel_id),
+ QMI_INIT_ARRAY(apdu, apdu, (strlen(arg) / 2)),
+ };
+
+
+ if (!uim_slot) {
+ uqmi_add_error("UIM-Slot not set. Use --uim-slot <slot> to set it.");
+ return QMI_CMD_EXIT;
+ }
+
+ if (!arg) {
+ uqmi_add_error("Missing APDU argument");
+ return QMI_CMD_EXIT;
+ }
+
+ if (strlen(arg) % 2 || strlen(arg) > sizeof(apdu) * 2 ||
+ !uqmi_hexstring_parse(apdu, (uint8_t *)arg, strlen(arg))) {
+ uqmi_add_error("Invalid APDU argument");
+ return QMI_CMD_EXIT;
+ }
+
+ qmi_set_uim_send_apdu_request(msg, &data);
+ return QMI_CMD_REQUEST;
+}
__uqmi_command(uim_verify_pin2, uim-verify-pin2, required, QMI_SERVICE_UIM), \
__uqmi_command(uim_get_sim_state, uim-get-sim-state, no, QMI_SERVICE_UIM), \
__uqmi_command(uim_power_off, uim-power-off, no, QMI_SERVICE_UIM), \
- __uqmi_command(uim_power_on, uim-power-on, no, QMI_SERVICE_UIM) \
+ __uqmi_command(uim_power_on, uim-power-on, no, QMI_SERVICE_UIM), \
+ __uqmi_command(uim_channel_id, uim-channel-id, required, CMD_TYPE_OPTION), \
+ __uqmi_command(uim_open_logical_channel, uim-channel-open, required, QMI_SERVICE_UIM), \
+ __uqmi_command(uim_close_logical_channel, uim-channel-close, no, QMI_SERVICE_UIM), \
+ __uqmi_command(uim_send_apdu, uim-apdu-send, required, QMI_SERVICE_UIM) \
#define uim_helptext \
" --uim-slot: SIM slot [1-2]\n" \
" --uim-power-on: Power on SIM card\n" \
" --uim-slot: SIM slot [1-2]\n" \
+ " --uim-channel-open <AID>: Open channel for AID\n" \
+ " --uim-slot: SIM slot [1-2]\n" \
+ " --uim-channel-close: Close channel\n" \
+ " --uim-slot: SIM slot [1-2]\n" \
+ " --uim-channel-id: Channel-id\n" \
+ " --uim-apdu-send <cmd>: Send APDU command to ICC\n" \
+ " --uim-slot: SIM slot [1-2]\n" \
+ " --uim-channel-id: Channel-id\n" \
int qmi_service_release_client_id(struct qmi_dev *qmi, QmiService svc);
QmiService qmi_service_get_by_name(const char *str);
+static inline uint8_t *uqmi_hexstring_parse(uint8_t *output,
+ const uint8_t *hexstr,
+ size_t hexstr_size)
+{
+ uint8_t *out = output;
+ size_t i;
+
+ for (i = 0; i < hexstr_size; i += 2) {
+ if (hexstr[i] >= '0' && hexstr[i] <= '9')
+ *out = (hexstr[i] - '0') << 4;
+ else if (hexstr[i] >= 'a' && hexstr[i] <= 'f')
+ *out = (hexstr[i] - 'a' + 10) << 4;
+ else if (hexstr[i] >= 'A' && hexstr[i] <= 'F')
+ *out = (hexstr[i] - 'A' + 10) << 4;
+ else
+ return NULL;
+
+ if (i + 1 >= hexstr_size)
+ return NULL;
+
+ if (hexstr[i + 1] >= '0' && hexstr[i + 1] <= '9')
+ *out |= hexstr[i + 1] - '0';
+ else if (hexstr[i + 1] >= 'a' && hexstr[i + 1] <= 'f')
+ *out |= hexstr[i + 1] - 'a' + 10;
+ else if (hexstr[i + 1] >= 'A' && hexstr[i + 1] <= 'F')
+ *out |= hexstr[i + 1] - 'A' + 10;
+ else
+ return NULL;
+
+ out++;
+ }
+
+ return output;
+}
+
+static inline uint8_t *uqmi_hexstring_create(uint8_t *output,
+ const uint8_t *data,
+ size_t data_size)
+{
+ uint8_t *out = output;
+ size_t i;
+
+ for (i = 0; i < data_size; i++) {
+ *out++ = "0123456789abcdef"[data[i] >> 4];
+ *out++ = "0123456789abcdef"[data[i] & 0xf];
+ }
+
+ return output;
+}
+
#endif