/* 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); }
/* 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); }
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; }
/* 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; }