1 /* 2 * uqmi -- tiny QMI support implementation 3 * 4 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the 18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301 USA. 20 */ 21 22 #include "qmi-message.h" 23 24 static int uim_slot = 0; 25 static int channel_id = -1; 26 static uint8_t aid[16]; 27 static uint8_t apdu[1024]; 28 29 #define cmd_uim_verify_pin1_cb no_cb 30 static enum qmi_cmd_result 31 cmd_uim_verify_pin1_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 32 { 33 struct qmi_uim_verify_pin_request data = { 34 QMI_INIT_SEQUENCE(session, 35 .session_type = QMI_UIM_SESSION_TYPE_CARD_SLOT_1, 36 .application_identifier_n = 0 37 ), 38 QMI_INIT_SEQUENCE(info, 39 .pin_id = QMI_UIM_PIN_ID_PIN1, 40 .pin_value = arg 41 ) 42 }; 43 qmi_set_uim_verify_pin_request(msg, &data); 44 return QMI_CMD_REQUEST; 45 } 46 47 #define cmd_uim_verify_pin2_cb no_cb 48 static enum qmi_cmd_result 49 cmd_uim_verify_pin2_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 50 { 51 struct qmi_uim_verify_pin_request data = { 52 QMI_INIT_SEQUENCE(session, 53 .session_type = QMI_UIM_SESSION_TYPE_CARD_SLOT_1, 54 .application_identifier_n = 0 55 ), 56 QMI_INIT_SEQUENCE(info, 57 .pin_id = QMI_UIM_PIN_ID_PIN2, 58 .pin_value = arg 59 ) 60 }; 61 qmi_set_uim_verify_pin_request(msg, &data); 62 return QMI_CMD_REQUEST; 63 } 64 65 static void cmd_uim_get_sim_state_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg) 66 { 67 struct qmi_uim_get_card_status_response res; 68 void * const card_table = blobmsg_open_table(&status, NULL); 69 static const char *card_application_states[] = { 70 [QMI_UIM_CARD_APPLICATION_STATE_UNKNOWN] = "unknown", 71 [QMI_UIM_CARD_APPLICATION_STATE_DETECTED] = "detected", 72 [QMI_UIM_CARD_APPLICATION_STATE_PIN1_OR_UPIN_PIN_REQUIRED] = "pin-required", 73 [QMI_UIM_CARD_APPLICATION_STATE_PUK1_OR_UPIN_PUK_REQUIRED] = "puk-required", 74 [QMI_UIM_CARD_APPLICATION_STATE_CHECK_PERSONALIZATION_STATE] = "check-personalization-state", 75 [QMI_UIM_CARD_APPLICATION_STATE_PIN1_BLOCKED] = "pin1-blocked", 76 [QMI_UIM_CARD_APPLICATION_STATE_ILLEGAL] = "illegal", 77 [QMI_UIM_CARD_APPLICATION_STATE_READY] = "ready", 78 }; 79 80 qmi_parse_uim_get_card_status_response(msg, &res); 81 82 for (int i = 0; i < res.data.card_status.cards_n; ++i) { 83 if (res.data.card_status.cards[i].card_state != QMI_UIM_CARD_STATE_PRESENT) 84 continue; 85 86 uint8_t card_application_state = QMI_UIM_CARD_APPLICATION_STATE_UNKNOWN; 87 uint8_t pin1_state = res.data.card_status.cards[i].upin_state; 88 uint8_t pin1_retries = res.data.card_status.cards[i].upin_retries; 89 uint8_t puk1_retries = res.data.card_status.cards[i].upuk_retries; 90 uint8_t pin2_state; 91 uint8_t pin2_retries; 92 uint8_t puk2_retries; 93 bool has_pin2 = false; 94 95 for (int j = 0; j < res.data.card_status.cards[i].applications_n; ++j) { 96 if (res.data.card_status.cards[i].applications[j].type == QMI_UIM_CARD_APPLICATION_TYPE_UNKNOWN) 97 continue; 98 99 card_application_state = pin1_state = res.data.card_status.cards[i].applications[j].state; 100 101 if (!res.data.card_status.cards[i].applications[j].upin_replaces_pin1) { 102 pin1_state = res.data.card_status.cards[i].applications[j].pin1_state; 103 pin1_retries = res.data.card_status.cards[i].applications[j].pin1_retries; 104 puk1_retries = res.data.card_status.cards[i].applications[j].puk1_retries; 105 } 106 107 pin2_state = res.data.card_status.cards[i].applications[j].pin2_state; 108 pin2_retries = res.data.card_status.cards[i].applications[j].pin2_retries; 109 puk2_retries = res.data.card_status.cards[i].applications[j].puk2_retries; 110 has_pin2 = true; 111 112 break; /* handle first application only for now */ 113 } 114 115 if (card_application_state > QMI_UIM_CARD_APPLICATION_STATE_READY) 116 card_application_state = QMI_UIM_CARD_APPLICATION_STATE_UNKNOWN; 117 118 blobmsg_add_u32(&status, "card_slot", i + 1); /* Slot is idx + 1 */ 119 blobmsg_add_string(&status, "card_application_state", card_application_states[card_application_state]); 120 blobmsg_add_string(&status, "pin1_status", get_pin_status(pin1_state)); 121 blobmsg_add_u32(&status, "pin1_verify_tries", pin1_retries); 122 blobmsg_add_u32(&status, "pin1_unlock_tries", puk1_retries); 123 if (has_pin2) { 124 blobmsg_add_string(&status, "pin2_status", get_pin_status(pin2_state)); 125 blobmsg_add_u32(&status, "pin2_verify_tries", pin2_retries); 126 blobmsg_add_u32(&status, "pin2_unlock_tries", puk2_retries); 127 } 128 129 break; /* handle only first preset SIM card for now */ 130 } 131 132 blobmsg_close_table(&status, card_table); 133 } 134 135 static enum qmi_cmd_result 136 cmd_uim_get_sim_state_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 137 { 138 qmi_set_uim_get_card_status_request(msg); 139 return QMI_CMD_REQUEST; 140 } 141 142 #define cmd_uim_slot_cb no_cb 143 static enum qmi_cmd_result 144 cmd_uim_slot_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 145 { 146 char *err; 147 int value = strtoul(arg, &err, 10); 148 if ((err && *err) || value < 1 || value > 2) { 149 uqmi_add_error("Invalid UIM-Slot value. Allowed: [1,2]"); 150 return QMI_CMD_EXIT; 151 } 152 153 uim_slot = value; 154 155 return QMI_CMD_DONE; 156 } 157 158 #define cmd_uim_power_off_cb no_cb 159 static enum qmi_cmd_result 160 cmd_uim_power_off_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 161 { 162 struct qmi_uim_power_off_sim_request data = { 163 QMI_INIT(slot, uim_slot) 164 }; 165 166 if (!uim_slot) { 167 uqmi_add_error("UIM-Slot not set. Use --uim-slot <slot> to set it."); 168 return QMI_CMD_EXIT; 169 } 170 171 qmi_set_uim_power_off_sim_request(msg, &data); 172 return QMI_CMD_REQUEST; 173 } 174 175 #define cmd_uim_power_on_cb no_cb 176 static enum qmi_cmd_result 177 cmd_uim_power_on_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 178 { 179 struct qmi_uim_power_on_sim_request data = { 180 QMI_INIT(slot, uim_slot) 181 }; 182 183 if (!uim_slot) { 184 uqmi_add_error("UIM-Slot not set. Use --uim-slot <slot> to set it."); 185 return QMI_CMD_EXIT; 186 } 187 188 qmi_set_uim_power_on_sim_request(msg, &data); 189 return QMI_CMD_REQUEST; 190 } 191 192 #define cmd_uim_channel_id_cb no_cb 193 static enum qmi_cmd_result 194 cmd_uim_channel_id_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 195 { 196 char *err; 197 int value = strtoul(arg, &err, 10); 198 if ((err && *err) || value < 1 || value > 4) { 199 uqmi_add_error("Invalid Channel-ID value. Allowed: [1,2,3,4]"); 200 return QMI_CMD_EXIT; 201 } 202 203 channel_id = value; 204 205 return QMI_CMD_DONE; 206 } 207 208 static void cmd_uim_open_logical_channel_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg) 209 { 210 struct qmi_uim_open_logical_channel_response res; 211 void *c; 212 213 qmi_parse_uim_open_logical_channel_response(msg, &res); 214 215 c = blobmsg_open_table(&status, NULL); 216 blobmsg_add_u32(&status, "channel_id", res.data.channel_id); 217 blobmsg_add_u32(&status, "sw1", res.data.card_result.sw1); 218 blobmsg_add_u32(&status, "sw2", res.data.card_result.sw2); 219 blobmsg_close_table(&status, c); 220 } 221 222 static enum qmi_cmd_result 223 cmd_uim_open_logical_channel_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 224 { 225 struct qmi_uim_open_logical_channel_request data = { 226 QMI_INIT(slot, uim_slot), 227 QMI_INIT_ARRAY(aid, aid, (strlen(arg) / 2)), 228 }; 229 230 231 if (!uim_slot) { 232 uqmi_add_error("UIM-Slot not set"); 233 return QMI_CMD_EXIT; 234 } 235 236 if (!arg) { 237 uqmi_add_error("Missing AID argument"); 238 return QMI_CMD_EXIT; 239 } 240 241 if (strlen(arg) % 2 || strlen(arg) > sizeof(aid) * 2 || 242 !uqmi_hexstring_parse(aid, (uint8_t *)arg, strlen(arg))) { 243 uqmi_add_error("Invalid AID argument"); 244 return QMI_CMD_EXIT; 245 } 246 247 qmi_set_uim_open_logical_channel_request(msg, &data); 248 return QMI_CMD_REQUEST; 249 } 250 251 #define cmd_uim_close_logical_channel_cb no_cb 252 static enum qmi_cmd_result 253 cmd_uim_close_logical_channel_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 254 { 255 struct qmi_uim_logical_channel_request data = { 256 QMI_INIT(slot, uim_slot), 257 QMI_INIT(channel_id, channel_id), 258 }; 259 260 if (!uim_slot) { 261 uqmi_add_error("UIM-Slot not set. Use --uim-slot <slot> to set it."); 262 return QMI_CMD_EXIT; 263 } 264 265 if (channel_id < 1) { 266 uqmi_add_error("Invalid channel-id set."); 267 return QMI_CMD_EXIT; 268 } 269 270 qmi_set_uim_logical_channel_request(msg, &data); 271 return QMI_CMD_REQUEST; 272 } 273 274 static void cmd_uim_send_apdu_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg) 275 { 276 struct qmi_uim_send_apdu_response res; 277 uint8_t *hexstr; 278 void *c; 279 280 qmi_parse_uim_send_apdu_response(msg, &res); 281 282 hexstr = calloc(1, res.data.apdu_response_n * 2 + 1); 283 if (!hexstr) 284 return; 285 286 uqmi_hexstring_create(hexstr, res.data.apdu_response, res.data.apdu_response_n); 287 288 c = blobmsg_open_table(&status, NULL); 289 blobmsg_add_string(&status, "response", (char *)hexstr); 290 blobmsg_close_table(&status, c); 291 292 free(hexstr); 293 } 294 295 static enum qmi_cmd_result 296 cmd_uim_send_apdu_prepare(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg, char *arg) 297 { 298 struct qmi_uim_send_apdu_request data = { 299 QMI_INIT(slot, uim_slot), 300 QMI_INIT(channel_id, channel_id), 301 QMI_INIT_ARRAY(apdu, apdu, (strlen(arg) / 2)), 302 }; 303 304 305 if (!uim_slot) { 306 uqmi_add_error("UIM-Slot not set. Use --uim-slot <slot> to set it."); 307 return QMI_CMD_EXIT; 308 } 309 310 if (!arg) { 311 uqmi_add_error("Missing APDU argument"); 312 return QMI_CMD_EXIT; 313 } 314 315 if (strlen(arg) % 2 || strlen(arg) > sizeof(apdu) * 2 || 316 !uqmi_hexstring_parse(apdu, (uint8_t *)arg, strlen(arg))) { 317 uqmi_add_error("Invalid APDU argument"); 318 return QMI_CMD_EXIT; 319 } 320 321 qmi_set_uim_send_apdu_request(msg, &data); 322 return QMI_CMD_REQUEST; 323 } 324
This page was automatically generated by LXR 0.3.1. • OpenWrt