/* Apply power to the simcard (use nullpointer to ignore atr) */ int calypso_sim_powerup(uint8_t *atr) { /* Enable level shifters and voltage regulator */ twl3025_reg_write(VRPCSIM, VRPCSIM_SIMLEN | VRPCSIM_RSIMEN | VRPCSIM_SIMSEL); #if (SIM_DEBUG == 1) puts(" * Power enabled!\n"); #endif delay_ms(SIM_OPERATION_DELAY); /* Enable clock */ writew(REG_SIM_CMD_MODULE_CLK_EN | REG_SIM_CMD_CMDSTART, REG_SIM_CMD); #if (SIM_DEBUG == 1) puts(" * Clock enabled!\n"); #endif delay_ms(SIM_OPERATION_DELAY); /* Release reset */ writew(readw(REG_SIM_CONF1) | REG_SIM_CONF1_CONFBYPASS | REG_SIM_CONF1_CONFSRSTLEV | REG_SIM_CONF1_CONFSVCCLEV, REG_SIM_CONF1); #if (SIM_DEBUG == 1) puts(" * Reset released!\n"); #endif /* Catch ATR */ if(atr != 0) return calypso_sim_receive(atr); else return 0; }
/* Apply power to the simcard (use nullpointer to ignore atr) */ int calypso_sim_powerup(uint8_t *atr) { /* Enable level shifters and voltage regulator */ #if 1 // 2.9V twl3025_reg_write(VRPCSIM, VRPCSIM_SIMLEN | VRPCSIM_RSIMEN | VRPCSIM_SIMSEL); #else // 1.8V twl3025_reg_write(VRPCSIM, VRPCSIM_SIMLEN | VRPCSIM_RSIMEN); #endif printd(" * Power enabled!\n"); delay_ms(SIM_OPERATION_DELAY); /* Enable clock */ writew(REG_SIM_CMD_MODULE_CLK_EN | REG_SIM_CMD_CMDSTART, REG_SIM_CMD); printd(" * Clock enabled!\n"); delay_ms(SIM_OPERATION_DELAY); /* Release reset */ writew(readw(REG_SIM_CONF1) | REG_SIM_CONF1_CONFBYPASS | REG_SIM_CONF1_CONFSRSTLEV | REG_SIM_CONF1_CONFSVCCLEV, REG_SIM_CONF1); printd(" * Reset released!\n"); /* Catch ATR */ if(atr != 0) { calypso_sim_receive(atr, 0); while (!rxDoneFlag) ; } return 0; }
/* reset the simcard (see note 1) */ int calypso_sim_reset(uint8_t *atr) { /* Pull reset down */ writew(readw(REG_SIM_CONF1) & ~REG_SIM_CONF1_CONFSRSTLEV , REG_SIM_CONF1); #if (SIM_DEBUG == 1) puts(" * Reset pulled down!\n"); #endif delay_ms(SIM_OPERATION_DELAY); /* Pull reset down */ writew(readw(REG_SIM_CONF1) | REG_SIM_CONF1_CONFSRSTLEV , REG_SIM_CONF1); #if (SIM_DEBUG == 1) puts(" * Reset released!\n"); #endif /* Catch ATR */ if(atr != 0) return calypso_sim_receive(atr); else return 0; }
/* reset the simcard (see note 1) */ int calypso_sim_reset(uint8_t *atr) { /* Pull reset down */ writew(readw(REG_SIM_CONF1) & ~REG_SIM_CONF1_CONFSRSTLEV, REG_SIM_CONF1); printd(" * Reset pulled down!\n"); delay_ms(SIM_OPERATION_DELAY); /* Pull reset down */ writew(readw(REG_SIM_CONF1) | REG_SIM_CONF1_CONFSRSTLEV, REG_SIM_CONF1); printd(" * Reset released!\n"); /* Catch ATR */ if(atr != 0) { calypso_sim_receive(atr, 0); while (!rxDoneFlag) ; } return 0; }
/* Transceive T0 Apdu to sim acording to GSM 11.11 Page 34 */ int calypso_sim_transceive(uint8_t cla, /* Class (in GSM context mostly 0xA0 */ uint8_t ins, /* Instruction */ uint8_t p1, /* First parameter */ uint8_t p2, /* Second parameter */ uint8_t p3le, /* Length of the data that should be transceived */ uint8_t *data, /* Data payload */ uint8_t *status, /* Status word (2 byte array, see note 1) */ uint8_t mode) /* Mode of operation: 1=GET, 0=PUT */ /* Note 1: You can use a null-pointer (0) if you are not interested in the status word */ { uint8_t transmissionBuffer[256]; uint8_t numberOfReceivedBytes; #if (SIM_DEBUG == 1) printf("SIM-T0: Transceiving APDU-Header: (%02x %02x %02x %02x %02x)\n",cla,ins,p1,p2,p3le); #endif /* Transmit APDU header */ memset(transmissionBuffer,0,sizeof(transmissionBuffer)); transmissionBuffer[0] = cla; transmissionBuffer[1] = ins; transmissionBuffer[2] = p1; transmissionBuffer[3] = p2; transmissionBuffer[4] = p3le; calypso_sim_transmit(transmissionBuffer,5); /* Case 1: No input, No Output */ if(p3le == 0) { #if (SIM_DEBUG == 1) puts("SIM-T0: Case 1: No input, No Output (See also GSM 11.11 Page 34)\n"); #endif numberOfReceivedBytes = calypso_sim_receive(transmissionBuffer); if(numberOfReceivedBytes == 2) { #if (SIM_DEBUG == 1) printf("SIM-T0: Status-word received: %02x %02x\n", transmissionBuffer[0], transmissionBuffer[1]); #endif /* Hand back status word */ if(status != 0) { status[0] = transmissionBuffer[0]; status[1] = transmissionBuffer[1]; } return 0; } else { #if (SIM_DEBUG == 1) puts("SIM-T0: T0 Protocol error -- aborting!\n"); #endif return -1; } } /* Case 2: No input / Output of known length */ else if(mode == SIM_APDU_PUT) { #if (SIM_DEBUG == 1) puts("SIM-T0: Case 2: No input / Output of known length (See also GSM 11.11 Page 34)\n"); #endif numberOfReceivedBytes = calypso_sim_receive(transmissionBuffer); /* Error situation: The card has aborted, sends no data but a status word */ if(numberOfReceivedBytes == 2) { #if (SIM_DEBUG == 1) printf("SIM-T0: Status-word received (ERROR): %02x %02x\n", transmissionBuffer[0], transmissionBuffer[1]); #endif /* Hand back status word */ if(status != 0) { status[0] = transmissionBuffer[0]; status[1] = transmissionBuffer[1]; } return 0; } /* Acknoledge byte received */ else if(numberOfReceivedBytes == 1) { #if (SIM_DEBUG == 1) printf("SIM-T0: ACK received: %02x\n", transmissionBuffer[0]); #endif /* Check if ACK is valid */ if(transmissionBuffer[0] != ins) { #if (SIM_DEBUG == 1) puts("SIM-T0: T0 Protocol error: Invalid ACK byte -- aborting!\n"); #endif return -1; } /* Transmit body */ calypso_sim_transmit(data,p3le); /* Receive status word */ numberOfReceivedBytes = calypso_sim_receive(transmissionBuffer); /* Check status word */ if(numberOfReceivedBytes == 2) { #if (SIM_DEBUG == 1) printf("SIM-T0: Status-word received: %02x %02x\n", transmissionBuffer[0], transmissionBuffer[1]); #endif /* Hand back status word */ if(status != 0) { status[0] = transmissionBuffer[0]; status[1] = transmissionBuffer[1]; } return 0; } else { #if (SIM_DEBUG == 1) puts("SIM-T0: T0 Protocol error: Missing or invalid status word -- aborting!\n"); #endif return -1; } } else { #if (SIM_DEBUG == 1) puts("SIM-T0: T0 Protocol error: Missing ACK byte -- aborting!\n"); #endif return -1; } } /* Case 4: Input / No output */ else if(mode == SIM_APDU_GET) { #if (SIM_DEBUG == 1) puts("SIM-T0: Case 4: Input / No output (See also GSM 11.11 Page 34)\n"); #endif numberOfReceivedBytes = calypso_sim_receive(data); /* Error situation: The card has aborted, sends no data but a status word */ if(numberOfReceivedBytes == 2) { #if (SIM_DEBUG == 1) printf("SIM-T0: Status-word received (ERROR): %02x %02x\n", data[0], data[1]); #endif /* Hand back status word */ if(status != 0) { status[0] = data[0]; status[1] = data[1]; } return 0; } /* Data correctly received */ else if(numberOfReceivedBytes == p3le + 1 + 2) { #if (SIM_DEBUG == 1) printf("SIM-T0: ACK received: %02x\n", data[0]); #endif /* Check if ACK is valid */ if(data[0] != ins) { #if (SIM_DEBUG == 1) puts("SIM-T0: T0 Protocol error: Invalid ACK byte -- aborting!\n"); #endif return -1; } #if (SIM_DEBUG == 1) printf("SIM-T0: Status-word received: %02x %02x\n", data[p3le + 1], data[p3le + 2]); #endif /* Hand back status word */ if(status != 0) { status[0] = data[p3le + 1]; status[1] = data[p3le + 2]; } /* Move data one position left to cut away the ACK-Byte */ memcpy(data,data+1,p3le); return 0; } else { #if (SIM_DEBUG == 1) puts("SIM-T0: T0 Protocol error: Incorrect or missing answer -- aborting!\n"); #endif return -1; } } /* Should not happen, if it happens then the programmer has submitted invalid parameters! */ else { #if (SIM_DEBUG == 1) puts("SIM-T0: T0 Protocol error: Invalid case (program bug!) -- aborting!\n"); #endif } /* Note: The other cases are not implemented because they are already covered by the CASE 1,2 and 4. */ return 0; }
/* handling sim events */ void sim_handler(void) { static struct msgb *msg; struct l1ctl_hdr *l1h; static uint8_t mode; static uint8_t *response; static uint16_t length; switch (sim_state) { case SIM_STATE_IDLE: if (!sim_len) break; /* wait for SIM command */ /* check if instructions expects a response */ if (/* GET RESPONSE needs SIM_APDU_GET */ (sim_len == 5 && sim_data[0] == SIM_CLASS && sim_data[1] == SIM_GET_RESPONSE && sim_data[2] == 0x00 && sim_data[3] == 0x00) || /* READ BINARY/RECORD needs SIM_APDU_GET */ (sim_len >= 5 && sim_data[0] == SIM_CLASS && (sim_data[1] == SIM_READ_BINARY || sim_data[1] == SIM_READ_RECORD))) mode = SIM_APDU_GET; else mode = SIM_APDU_PUT; length = sim_data[4]; /* allocate space for expected response */ msg = msgb_alloc_headroom(256, L3_MSG_HEAD + sizeof(struct l1ctl_hdr), "l1ctl1"); response = msgb_put(msg, length + 2 + 1); sim_state = SIM_STATE_TX_HEADER; /* send APDU header */ calypso_sim_transmit(sim_data, 5); break; case SIM_STATE_TX_HEADER: if (!txDoneFlag) break; /* wait until header is transmitted */ /* Disable all interrupt driven functions */ writew(0xFF, REG_SIM_MASKIT); /* Case 1: No input, No Output */ if (length == 0) { sim_state = SIM_STATE_RX_STATUS; calypso_sim_receive(response + 1, 2); break; } /* Case 2: No input / Output of known length */ if (mode == SIM_APDU_PUT) { sim_state = SIM_STATE_RX_ACK; calypso_sim_receive(response, 1); break; /* Case 4: Input / No output */ } else { sim_state = SIM_STATE_RX_ACK_DATA; calypso_sim_receive(response, length + 1 + 2); } break; case SIM_STATE_RX_STATUS: if (!rxDoneFlag) break; /* wait until data is received */ /* Disable all interrupt driven functions */ writew(0xFF, REG_SIM_MASKIT); /* disable special ignore case */ sim_ignore_waiting_char = 0; /* wrong number of bytes received */ if (sim_rx_character_count != 2) { puts("SIM: Failed to read status\n"); goto error; } msgb_pull(msg, length + 1); /* pull up to status info */ goto queue; case SIM_STATE_RX_ACK: if (!rxDoneFlag) break; /* wait until data is received */ /* Disable all interrupt driven functions */ writew(0xFF, REG_SIM_MASKIT); /* error received */ if (sim_rx_character_count == 2) { puts("SIM: command failed\n"); msgb_pull(msg, msg->len - 2); msg->data[0] = response[0]; msg->data[1] = response[1]; goto queue; } /* wrong number of bytes received */ if (sim_rx_character_count != 1) { puts("SIM: ACK read failed\n"); goto error; } if (response[0] != sim_data[1]) { puts("SIM: ACK does not match request\n"); goto error; } sim_state = SIM_STATE_TX_DATA; calypso_sim_transmit(sim_data + 5, length); break; case SIM_STATE_TX_DATA: if (!txDoneFlag) break; /* wait until data is transmitted */ /* Disable all interrupt driven functions */ writew(0xFF, REG_SIM_MASKIT); /* Ignore waiting char for RUN GSM ALGORITHM */ /* TODO: implement proper handling of the "Procedure Bytes" than this is no longer needed */ if(sim_data[1] == 0x88) sim_ignore_waiting_char = 1; sim_state = SIM_STATE_RX_STATUS; calypso_sim_receive(response + length + 1, 2); break; case SIM_STATE_RX_ACK_DATA: if (!rxDoneFlag) break; /* wait until data is received */ /* Disable all interrupt driven functions */ writew(0xFF, REG_SIM_MASKIT); /* error received */ if (sim_rx_character_count == 2) { puts("SIM: command failed\n"); msgb_pull(msg, msg->len - 2); msg->data[0] = response[0]; msg->data[1] = response[1]; goto queue; } /* wrong number of bytes received */ if (sim_rx_character_count != length + 1 + 2) { puts("SIM: Failed to read data\n"); goto error; } msgb_pull(msg, 1); /* pull ACK byte */ goto queue; } return; error: msgb_pull(msg, msg->len - 2); msg->data[0] = 0; msg->data[1] = 0; queue: printf("SIM Response (%d): %s\n", msg->len, osmo_hexdump(msg->data, msg->len)); l1h = (struct l1ctl_hdr *) msgb_push(msg, sizeof(*l1h)); l1h->msg_type = L1CTL_SIM_CONF; l1h->flags = 0; msg->l1h = (uint8_t *)l1h; l1_queue_for_l2(msg); /* go IDLE */ sim_state = SIM_STATE_IDLE; sim_len = 0; return; }