Пример #1
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;
}
Пример #2
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;
}