Beispiel #1
0
/* Asynchronous completion handler for NB transmit */
static void l1a_tx_nb_compl(__unused enum l1_compl c)
{
	struct msgb *msg;

	msg = l1_create_l2_msg(L1CTL_DATA_CONF, last_txnb_fn, 0, 0);
	l1_queue_for_l2(msg);
}
Beispiel #2
0
/* Asynchronous completion handler for FB detection */
static void l1a_rach_compl(__unused enum l1_compl c)
{
	struct msgb *msg;

	msg = l1_create_l2_msg(L1CTL_RACH_CONF, last_rach.fn, 0,
				last_rach.band_arfcn);
	l1_queue_for_l2(msg);
}
Beispiel #3
0
static int l1ctl_fbsb_resp(uint8_t res)
{
	struct msgb *msg;
	struct l1ctl_fbsb_conf *resp;

	msg = l1_create_l2_msg(L1CTL_FBSB_CONF, fbs.mon.time.fn,
				l1s_snr_int(fbs.mon.snr),
				fbs.req.band_arfcn);
	if (!msg)
		return -ENOMEM;

	resp = (struct l1ctl_fbsb_conf *) msgb_put(msg, sizeof(*resp));
	resp->initial_freq_err = htons(fbs.initial_freq_err);
	resp->result = res;
	resp->bsic = fbs.mon.bsic;

	/* no need to set BSIC, as it is never used here */
	l1_queue_for_l2(msg);

	return 0;
}
Beispiel #4
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;
}