buffer[1] = GSM1111_INST_CHANGE_CHV;
buffer[2] = 0x00;
buffer[3] = chv_no;
- buffer[4] = 8;
+ buffer[4] = 16;
for (i = 0; i < 8; i++) {
if (i < length_old)
buffer[5 + i] = chv_old[i];
buffer[1] = GSM1111_INST_UNBLOCK_CHV;
buffer[2] = 0x00;
buffer[3] = (chv_no == 1) ? 0 : chv_no;
- buffer[4] = 8;
+ buffer[4] = 16;
for (i = 0; i < 8; i++) {
if (i < length_unblk)
buffer[5 + i] = chv_unblk[i];
static int sim_process_job(struct osmocom_ms *ms)
{
struct gsm_sim *sim = &ms->sim;
- uint8_t *payload;
- uint16_t payload_len;
+ uint8_t *payload, *payload2;
+ uint16_t payload_len, payload_len2;
struct sim_hdr *sh;
uint8_t cause;
int i;
sim->job_state = SIM_JST_RUN_GSM_ALGO;
return gsm1111_tx_run_gsm_algo(ms, payload);
case SIM_JOB_PIN1_UNLOCK:
+ payload_len = strlen((char *)payload);
if (payload_len < 4 || payload_len > 8) {
LOGP(DSIM, LOGL_ERROR, "key not in range 4..8\n");
break;
}
sim->job_state = SIM_JST_PIN1_UNLOCK;
- memcpy(sim->pin1, payload, payload_len);
- sim->pin1_len = payload_len;
return gsm1111_tx_verify_chv(ms, 0x01, payload, payload_len);
case SIM_JOB_PIN2_UNLOCK:
+ payload_len = strlen((char *)payload);
if (payload_len < 4 || payload_len > 8) {
LOGP(DSIM, LOGL_ERROR, "key not in range 4..8\n");
break;
}
sim->job_state = SIM_JST_PIN2_UNLOCK;
- memcpy(sim->pin2, payload, payload_len);
- sim->pin2_len = payload_len;
return gsm1111_tx_verify_chv(ms, 0x02, payload, payload_len);
case SIM_JOB_PIN1_CHANGE:
- if (!sim->pin1_len) {
- LOGP(DSIM, LOGL_ERROR, "no pin set\n");
+ payload_len = strlen((char *)payload);
+ payload2 = payload + payload_len + 1;
+ payload_len2 = strlen((char *)payload2);
+ if (payload_len < 4 || payload_len > 8) {
+ LOGP(DSIM, LOGL_ERROR, "key1 not in range 4..8\n");
break;
}
- if (payload_len < 4 || payload_len > 8 || !sim->pin1_len) {
- LOGP(DSIM, LOGL_ERROR, "key not in range 4..8\n");
+ if (payload_len2 < 4 || payload_len2 > 8) {
+ LOGP(DSIM, LOGL_ERROR, "key2 not in range 4..8\n");
break;
}
sim->job_state = SIM_JST_PIN1_CHANGE;
- return gsm1111_tx_change_chv(ms, 0x01, sim->pin1, sim->pin1_len,
- payload, payload_len);
+ return gsm1111_tx_change_chv(ms, 0x01, payload, payload_len,
+ payload2, payload_len2);
case SIM_JOB_PIN2_CHANGE:
- if (!sim->pin2_len) {
- LOGP(DSIM, LOGL_ERROR, "no pin set\n");
+ payload_len = strlen((char *)payload);
+ payload2 = payload + payload_len + 1;
+ payload_len2 = strlen((char *)payload2);
+ if (payload_len < 4 || payload_len > 8) {
+ LOGP(DSIM, LOGL_ERROR, "key1 not in range 4..8\n");
break;
}
- if (payload_len < 4 || payload_len > 8) {
- LOGP(DSIM, LOGL_ERROR, "key not in range 4..8\n");
+ if (payload_len2 < 4 || payload_len2 > 8) {
+ LOGP(DSIM, LOGL_ERROR, "key2 not in range 4..8\n");
break;
}
sim->job_state = SIM_JST_PIN2_CHANGE;
- return gsm1111_tx_change_chv(ms, 0x02, sim->pin1, sim->pin1_len,
- payload, payload_len);
+ return gsm1111_tx_change_chv(ms, 0x02, payload, payload_len,
+ payload2, payload_len2);
case SIM_JOB_PIN1_DISABLE:
- if (!sim->pin1_len) {
- LOGP(DSIM, LOGL_ERROR, "no pin set\n");
+ payload_len = strlen((char *)payload);
+ if (payload_len < 4 || payload_len > 8) {
+ LOGP(DSIM, LOGL_ERROR, "key not in range 4..8\n");
break;
}
sim->job_state = SIM_JST_PIN1_DISABLE;
- return gsm1111_tx_disable_chv(ms, sim->pin1, sim->pin1_len);
+ return gsm1111_tx_disable_chv(ms, payload, payload_len);
case SIM_JOB_PIN1_ENABLE:
- if (!sim->pin1_len) {
- LOGP(DSIM, LOGL_ERROR, "no pin set\n");
+ payload_len = strlen((char *)payload);
+ if (payload_len < 4 || payload_len > 8) {
+ LOGP(DSIM, LOGL_ERROR, "key not in range 4..8\n");
break;
}
sim->job_state = SIM_JST_PIN1_ENABLE;
- return gsm1111_tx_enable_chv(ms, sim->pin1, sim->pin1_len);
+ return gsm1111_tx_enable_chv(ms, payload, payload_len);
case SIM_JOB_PIN1_UNBLOCK:
- if (payload_len < 12 || payload_len > 16) {
- LOGP(DSIM, LOGL_ERROR, "key not in range 4..8\n");
+ payload_len = strlen((char *)payload);
+ payload2 = payload + payload_len + 1;
+ payload_len2 = strlen((char *)payload2);
+ if (payload_len != 8) {
+ LOGP(DSIM, LOGL_ERROR, "key1 not 8 digits\n");
break;
}
- sim->job_state = SIM_JST_PIN1_UNLOCK;
- memcpy(sim->pin1, payload + 8, payload_len - 8);
- sim->pin1_len = payload_len;
+ if (payload_len2 < 4 || payload_len2 > 8) {
+ LOGP(DSIM, LOGL_ERROR, "key2 not in range 4..8\n");
+ break;
+ }
+ sim->job_state = SIM_JST_PIN1_UNBLOCK;
/* NOTE: CHV1 is coded 0x00 here */
- return gsm1111_tx_unblock_chv(ms, 0x00, payload, 8, payload + 8,
- payload_len - 8);
+ return gsm1111_tx_unblock_chv(ms, 0x00, payload, payload_len,
+ payload2, payload_len2);
case SIM_JOB_PIN2_UNBLOCK:
- if (payload_len < 12 || payload_len > 16) {
- LOGP(DSIM, LOGL_ERROR, "key not in range 4..8\n");
+ payload_len = strlen((char *)payload);
+ payload2 = payload + payload_len + 1;
+ payload_len2 = strlen((char *)payload2);
+ if (payload_len != 8) {
+ LOGP(DSIM, LOGL_ERROR, "key1 not 8 digits\n");
break;
}
- sim->job_state = SIM_JST_PIN2_UNLOCK;
- memcpy(sim->pin2, payload + 8, payload_len - 8);
- sim->pin2_len = payload_len;
- return gsm1111_tx_unblock_chv(ms, 0x02, payload, 8, payload + 8,
- payload_len - 8);
+ if (payload_len2 < 4 || payload_len2 > 8) {
+ LOGP(DSIM, LOGL_ERROR, "key2 not in range 4..8\n");
+ break;
+ }
+ sim->job_state = SIM_JST_PIN2_UNBLOCK;
+ return gsm1111_tx_unblock_chv(ms, 0x02, payload, payload_len,
+ payload2, payload_len2);
}
LOGP(DSIM, LOGL_ERROR, "unknown job %x, please fix\n", sh->job_type);
switch (sw1) {
case GSM1111_STAT_SECURITY:
- LOGP(DSIM, LOGL_NOTICE, "SIM Security\n");
- pin_cause[0] = SIM_CAUSE_PIN1_REQUIRED;
- pin_cause[1] = 1; /* PIN retries left */
- gsm_sim_reply(ms, SIM_JOB_ERROR, pin_cause, 2);
- msgb_free(msg);
- return 0;
+ LOGP(DSIM, LOGL_NOTICE, "SIM Security\n");
+ /* error */
+ if (sw2 != GSM1111_SEC_NO_ACCESS && sw2 != GSM1111_SEC_BLOCKED)
+ goto sim_error;
+
+ /* select the right remaining counter an cause */
+ // FIXME: read status to replace "*_remain"-counters
+ switch (sim->job_state) {
+ case SIM_JST_PIN1_UNBLOCK:
+ if (sw2 == GSM1111_SEC_NO_ACCESS) {
+ pin_cause[0] = SIM_CAUSE_PIN1_BLOCKED;
+ pin_cause[1] = --sim->unblk1_remain;
+ } else {
+ pin_cause[0] = SIM_CAUSE_PUC_BLOCKED;
+ pin_cause[1] = 0;
+ }
+ break;
+ case SIM_JST_PIN2_UNLOCK:
+ case SIM_JST_PIN2_CHANGE:
+ if (sw2 == GSM1111_SEC_NO_ACCESS && sim->chv2_remain) {
+ pin_cause[0] = SIM_CAUSE_PIN2_REQUIRED;
+ pin_cause[1] = sim->chv2_remain--;
+ } else {
+ pin_cause[0] = SIM_CAUSE_PIN2_BLOCKED;
+ pin_cause[1] = sim->unblk2_remain;
+ }
+ break;
+ case SIM_JST_PIN2_UNBLOCK:
+ if (sw2 == GSM1111_SEC_NO_ACCESS) {
+ pin_cause[0] = SIM_CAUSE_PIN2_BLOCKED;
+ pin_cause[1] = --sim->unblk2_remain;
+ } else {
+ pin_cause[0] = SIM_CAUSE_PUC_BLOCKED;
+ pin_cause[1] = 0;
+ }
+ case SIM_JST_PIN1_UNLOCK:
+ case SIM_JST_PIN1_CHANGE:
+ case SIM_JST_PIN1_DISABLE:
+ case SIM_JST_PIN1_ENABLE:
+ default:
+ if (sw2 == GSM1111_SEC_NO_ACCESS && sim->chv1_remain) {
+ pin_cause[0] = SIM_CAUSE_PIN1_REQUIRED;
+ pin_cause[1] = sim->chv1_remain--;
+ } else {
+ pin_cause[0] = SIM_CAUSE_PIN1_BLOCKED;
+ pin_cause[1] = sim->unblk1_remain;
+ }
+ break;
+ }
+ gsm_sim_reply(ms, SIM_JOB_ERROR, pin_cause, 2);
+ msgb_free(msg);
+ return 0;
case GSM1111_STAT_MEM_PROBLEM:
if (sw2 >= 0x40) {
LOGP(DSIM, LOGL_NOTICE, "memory of SIM failed\n");
case GSM1111_STAT_RESPONSE:
case GSM1111_STAT_RESPONSE_TOO:
LOGP(DSIM, LOGL_INFO, "command successfull\n");
- switch (sh->job_type) {
- case SIM_JOB_PIN1_CHANGE:
- memcpy(sim->pin1, payload, payload_len);
- sim->pin1_len = payload_len;
- break;
- case SIM_JOB_PIN2_CHANGE:
- memcpy(sim->pin2, payload, payload_len);
- sim->pin2_len = payload_len;
- break;
- }
break;
default:
LOGP(DSIM, LOGL_INFO, "command failed\n");
- switch (sh->job_type) {
- case SIM_JOB_PIN1_UNLOCK:
- case SIM_JOB_PIN1_UNBLOCK:
- sim->pin1_len = 0;
- break;
- case SIM_JOB_PIN2_UNLOCK:
- case SIM_JOB_PIN2_UNBLOCK:
- sim->pin2_len = 0;
- break;
- }
request_error:
cause = SIM_CAUSE_REQUEST_ERROR;
gsm_sim_reply(ms, SIM_JOB_ERROR, &cause, 1);
}
mfdf = (struct gsm1111_response_mfdf *)data;
mfdf_gsm = (struct gsm1111_response_mfdf_gsm *)(data + 13);
+ sim->chv1_remain = mfdf_gsm->chv1_remain;
+ sim->chv2_remain = mfdf_gsm->chv2_remain;
+ sim->unblk1_remain = mfdf_gsm->unblk1_remain;
+ sim->unblk2_remain = mfdf_gsm->unblk2_remain;
/* if MF was selected */
if (sim->path[0] == 0) {
/* if MF was selected, but MF is not indicated */
uint8_t *payload = msg->data + sizeof(*sh);
uint16_t payload_len = msg->len - sizeof(*sh);
int rc;
+ struct subscr_sim_file *sf = &subscr_sim_files[subscr->sim_file_index];
/* error handling */
if (sh->job_type == SIM_JOB_ERROR) {
vty_notify(ms, NULL);
vty_notify(ms, "PIN is blocked\n");
+ if (payload[1]) {
+ vty_notify(ms, "Please give PUC for ICCID %s "
+ "(you have %d tries left)\n",
+ subscr->iccid, payload[1]);
+ }
+ subscr->sim_pin_required = 1;
+ break;
+ case SIM_CAUSE_PUC_BLOCKED:
+ LOGP(DMM, LOGL_NOTICE, "PUC is blocked\n");
+
+ vty_notify(ms, NULL);
+ vty_notify(ms, "PUC is blocked\n");
+ subscr->sim_pin_required = 1;
break;
default:
- if (!subscr_sim_files[subscr->sim_file_index].
- mandatory) {
+ if (sf->func && !sf->mandatory) {
LOGP(DMM, LOGL_NOTICE, "SIM reading failed, "
"ignoring!\n");
goto ignore;
return;
}
- /* call function do decode SIM reply */
- rc = subscr_sim_files[subscr->sim_file_index].func(ms, payload,
- payload_len);
+ /* if pin was successfully unlocked, then resend request */
+ if (subscr->sim_pin_required) {
+ subscr->sim_pin_required = 0;
+ subscr_sim_request(ms);
+ return;
+ }
+
+ /* done when nothing more to read. this happens on PIN requests */
+ if (!sf->func)
+ return;
+ /* call function do decode SIM reply */
+ rc = sf->func(ms, payload, payload_len);
if (rc) {
LOGP(DMM, LOGL_NOTICE, "SIM reading failed, file invalid\n");
if (subscr_sim_files[subscr->sim_file_index].mandatory) {
}
/* enter PIN */
-void gsm_subscr_sim_pin(struct osmocom_ms *ms, char *pin)
+void gsm_subscr_sim_pin(struct osmocom_ms *ms, char *pin1, char *pin2,
+ int8_t mode)
{
struct gsm_subscriber *subscr = &ms->subscr;
struct msgb *nmsg;
+ uint8_t job;
- if (!subscr->sim_pin_required) {
- LOGP(DMM, LOGL_ERROR, "No PIN required now\n");
- return;
+ switch (mode) {
+ case -1:
+ job = SIM_JOB_PIN1_DISABLE;
+ LOGP(DMM, LOGL_INFO, "disabling PIN %s\n", pin1);
+ break;
+ case 1:
+ job = SIM_JOB_PIN1_ENABLE;
+ LOGP(DMM, LOGL_INFO, "enabling PIN %s\n", pin1);
+ break;
+ case 2:
+ job = SIM_JOB_PIN1_CHANGE;
+ LOGP(DMM, LOGL_INFO, "changing PIN %s to %s\n", pin1, pin2);
+ break;
+ case 99:
+ job = SIM_JOB_PIN1_UNBLOCK;
+ LOGP(DMM, LOGL_INFO, "unblocking PIN %s with PUC %s\n", pin1,
+ pin2);
+ break;
+ default:
+ if (!subscr->sim_pin_required) {
+ LOGP(DMM, LOGL_ERROR, "No PIN required now\n");
+ return;
+ }
+ LOGP(DMM, LOGL_INFO, "entering PIN %s\n", pin1);
+ job = SIM_JOB_PIN1_UNLOCK;
}
- subscr->sim_pin_required = 0;
- LOGP(DMM, LOGL_INFO, "Unlocking PIN %s\n", pin);
- nmsg = gsm_sim_msgb_alloc(subscr->sim_handle_update,
- SIM_JOB_PIN1_UNLOCK);
+ nmsg = gsm_sim_msgb_alloc(subscr->sim_handle_query, job);
if (!nmsg)
return;
- memcpy(msgb_put(nmsg, strlen(pin)), pin, strlen(pin));
+ memcpy(msgb_put(nmsg, strlen(pin1) + 1), pin1, strlen(pin1) + 1);
+ memcpy(msgb_put(nmsg, strlen(pin2) + 1), pin2, strlen(pin2) + 1);
sim_job(ms, nmsg);
}
if (!ms)
return CMD_WARNING;
+ if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
+ vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
if (!ms->subscr.sim_pin_required) {
vty_out(vty, "No PIN is required at this time!%s", VTY_NEWLINE);
return CMD_WARNING;
}
- gsm_subscr_sim_pin(ms, (char *)argv[1]);
+ gsm_subscr_sim_pin(ms, (char *)argv[1], "", 0);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(sim_disable_pin, sim_disable_pin_cmd, "sim disable-pin MS_NAME PIN",
+ "SIM actions\nDisable PIN of SIM card\nName of MS (see \"show ms\")\n"
+ "PIN number")
+{
+ struct osmocom_ms *ms;
+
+ ms = get_ms(argv[0], vty);
+ if (!ms)
+ return CMD_WARNING;
+
+ if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
+ vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ gsm_subscr_sim_pin(ms, (char *)argv[1], "", -1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(sim_enable_pin, sim_enable_pin_cmd, "sim enable-pin MS_NAME PIN",
+ "SIM actions\nEnable PIN of SIM card\nName of MS (see \"show ms\")\n"
+ "PIN number")
+{
+ struct osmocom_ms *ms;
+
+ ms = get_ms(argv[0], vty);
+ if (!ms)
+ return CMD_WARNING;
+
+ if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
+ vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ gsm_subscr_sim_pin(ms, (char *)argv[1], "", 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(sim_change_pin, sim_change_pin_cmd, "sim change-pin MS_NAME OLD NEW",
+ "SIM actions\nChange PIN of SIM card\nName of MS (see \"show ms\")\n"
+ "Old PIN number\nNew PIN number")
+{
+ struct osmocom_ms *ms;
+
+ ms = get_ms(argv[0], vty);
+ if (!ms)
+ return CMD_WARNING;
+
+ if (strlen(argv[1]) < 4 || strlen(argv[1]) > 8) {
+ vty_out(vty, "Old PIN must be in range 4..8!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (strlen(argv[2]) < 4 || strlen(argv[2]) > 8) {
+ vty_out(vty, "New PIN must be in range 4..8!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ gsm_subscr_sim_pin(ms, (char *)argv[1], (char *)argv[2], 2);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(sim_unblock_pin, sim_unblock_pin_cmd, "sim unblock-pin MS_NAME PUC NEW",
+ "SIM actions\nChange PIN of SIM card\nName of MS (see \"show ms\")\n"
+ "Personal Unblock Key\nNew PIN number")
+{
+ struct osmocom_ms *ms;
+
+ ms = get_ms(argv[0], vty);
+ if (!ms)
+ return CMD_WARNING;
+
+ if (strlen(argv[1]) != 8) {
+ vty_out(vty, "PUC must be 8 digits!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (strlen(argv[2]) < 4 || strlen(argv[2]) > 8) {
+ vty_out(vty, "PIN must be in range 4..8!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ gsm_subscr_sim_pin(ms, (char *)argv[1], (char *)argv[2], 99);
return CMD_SUCCESS;
}
install_element(ENABLE_NODE, &sim_reader_cmd);
install_element(ENABLE_NODE, &sim_remove_cmd);
install_element(ENABLE_NODE, &sim_pin_cmd);
+ install_element(ENABLE_NODE, &sim_disable_pin_cmd);
+ install_element(ENABLE_NODE, &sim_enable_pin_cmd);
+ install_element(ENABLE_NODE, &sim_change_pin_cmd);
+ install_element(ENABLE_NODE, &sim_unblock_pin_cmd);
install_element(ENABLE_NODE, &network_search_cmd);
install_element(ENABLE_NODE, &network_show_cmd);
install_element(ENABLE_NODE, &network_select_cmd);