#include <arpa/inet.h>
-#include <l1a_l23_interface.h>
+#include <l1ctl_proto.h>
#include <osmocore/signal.h>
#include <osmocore/logging.h>
struct l1ctl_info_dl *dl;
struct l1ctl_fbsb_conf *sb;
struct gsm_time tm;
+ struct osmobb_fbsb_res fr;
if (msgb_l3len(msg) < sizeof(*dl) + sizeof(*sb)) {
LOGP(DL1C, LOGL_ERROR, "FBSB RESP: MSG too short %u\n",
dl = (struct l1ctl_info_dl *) msg->l1h;
sb = (struct l1ctl_fbsb_conf *) dl->payload;
- printf("snr=%04x, arfcn=%u result=%u\n", dl->snr, ntohs(dl->band_arfcn),
- sb->result);
+ LOGP(DL1C, LOGL_INFO, "snr=%04x, arfcn=%u result=%u\n", dl->snr,
+ ntohs(dl->band_arfcn), sb->result);
if (sb->result != 0) {
LOGP(DL1C, LOGL_ERROR, "FBSB RESP: result=%u\n", sb->result);
gsm_fn2gsmtime(&tm, ntohl(dl->frame_nr));
DEBUGP(DL1C, "SCH: SNR: %u TDMA: (%.4u/%.2u/%.2u) bsic: %d\n",
dl->snr, tm.t1, tm.t2, tm.t3, sb->bsic);
- dispatch_signal(SS_L1CTL, S_L1CTL_FBSB_RESP, ms);
+ fr.ms = ms;
+ fr.snr = dl->snr;
+ fr.bsic = sb->bsic;
+ dispatch_signal(SS_L1CTL, S_L1CTL_FBSB_RESP, &fr);
return 0;
}
return 0;
}
-char *chan_nr2string(uint8_t chan_nr)
-{
- static char str[20];
- uint8_t cbits = chan_nr >> 3;
-
- str[0] = '\0';
-
- if (cbits == 0x01)
- sprintf(str, "TCH/F");
- else if ((cbits & 0x1e) == 0x02)
- sprintf(str, "TCH/H(%u)", cbits & 0x01);
- else if ((cbits & 0x1c) == 0x04)
- sprintf(str, "SDCCH/4(%u)", cbits & 0x03);
- else if ((cbits & 0x18) == 0x08)
- sprintf(str, "SDCCH/8(%u)", cbits & 0x07);
- else if (cbits == 0x10)
- sprintf(str, "BCCH");
- else if (cbits == 0x11)
- sprintf(str, "RACH");
- else if (cbits == 0x12)
- sprintf(str, "PCH/AGCH");
- else
- sprintf(str, "UNKNOWN");
-
- return str;
-}
-
/* Receive L1CTL_DATA_IND (Data Indication from L1) */
static int rx_ph_data_ind(struct osmocom_ms *ms, struct msgb *msg)
{
gsm_fn2gsmtime(&tm, ntohl(dl->frame_nr));
rsl_dec_chan_nr(dl->chan_nr, &chan_type, &chan_ss, &chan_ts);
- DEBUGP(DL1C, "%s (%.4u/%.2u/%.2u) %s\n",
- chan_nr2string(dl->chan_nr), tm.t1, tm.t2, tm.t3,
+ DEBUGP(DL1C, "%s (%.4u/%.2u/%.2u) %d dBm: %s\n",
+ rsl_chan_nr_str(dl->chan_nr), tm.t1, tm.t2, tm.t3,
+ (int)dl->rx_level-110,
hexdump(ccch->data, sizeof(ccch->data)));
+ meas->last_fn = ntohl(dl->frame_nr);
meas->frames++;
+ meas->snr += dl->snr;
meas->berr += dl->num_biterr;
meas->rxlev += dl->rx_level;
- if (dl->num_biterr) {
-printf("dropping frame with %u bit errors\n", dl->num_biterr);
+ /* counting loss criteria */
+ if (!(dl->link_id & 0x40)) {
+ switch (chan_type) {
+ case RSL_CHAN_PCH_AGCH:
+ if (!meas->ds_fail)
+ break;
+ if (dl->fire_crc >= 2)
+ meas->dsc -= 4;
+ else
+ meas->dsc += 1;
+ if (meas->dsc > meas->ds_fail)
+ meas->dsc = meas->ds_fail;
+ if (meas->dsc < meas->ds_fail)
+ printf("LOSS counter for CCCH %d\n", meas->dsc);
+ if (meas->dsc > 0)
+ break;
+ meas->ds_fail = 0;
+ dispatch_signal(SS_L1CTL, S_L1CTL_LOSS_IND, ms);
+ break;
+ }
+ } else {
+ switch (chan_type) {
+ case RSL_CHAN_Bm_ACCHs:
+ case RSL_CHAN_Lm_ACCHs:
+ case RSL_CHAN_SDCCH4_ACCH:
+ case RSL_CHAN_SDCCH8_ACCH:
+ if (!meas->rl_fail)
+ break;
+ if (dl->fire_crc >= 2)
+ meas->s -= 1;
+ else
+ meas->s += 2;
+ if (meas->s > meas->rl_fail)
+ meas->s = meas->rl_fail;
+ if (meas->s < meas->rl_fail)
+ printf("LOSS counter for ACCH %d\n", meas->s);
+ if (meas->s > 0)
+ break;
+ meas->rl_fail = 0;
+ dispatch_signal(SS_L1CTL, S_L1CTL_LOSS_IND, ms);
+ break;
+ }
+ }
+
+ if (dl->fire_crc >= 2) {
+printf("Dropping frame with %u bit errors\n", dl->num_biterr);
LOGP(DL1C, LOGL_NOTICE, "Dropping frame with %u bit errors\n",
dl->num_biterr);
return 0;
}
/* Transmit L1CTL_DATA_REQ */
-int tx_ph_data_req(struct osmocom_ms *ms, struct msgb *msg, uint8_t chan_nr,
- uint8_t link_id)
+int l1ctl_tx_data_req(struct osmocom_ms *ms, struct msgb *msg,
+ uint8_t chan_nr, uint8_t link_id)
{
struct l1ctl_hdr *l1h;
struct l1ctl_info_ul *l1i_ul;
struct msgb *msg;
struct l1ctl_fbsb_req *req;
- printf("Sync Req\n");
+ LOGP(DL1C, LOGL_INFO, "Sync Req\n");
msg = osmo_l1_alloc(L1CTL_FBSB_REQ);
if (!msg)
return -1;
- memset(&ms->meas, 0, sizeof(ms->meas));
-
req = (struct l1ctl_fbsb_req *) msgb_put(msg, sizeof(*req));
req->band_arfcn = htons(osmo_make_band_arfcn(ms, arfcn));
req->timeout = htons(timeout);
/* Threshold when to consider FB_MODE1: 4kHz - 1kHz */
- req->freq_err_thresh1 = htons(4000 - 1000);
+ req->freq_err_thresh1 = htons(11000 - 1000);
/* Threshold when to consider SCH: 1kHz - 200Hz */
req->freq_err_thresh2 = htons(1000 - 200);
/* not used yet! */
struct msgb *msg;
struct l1ctl_ccch_mode_req *req;
- printf("CCCH Mode Req\n");
+ LOGP(DL1C, LOGL_INFO, "CCCH Mode Req\n");
msg = osmo_l1_alloc(L1CTL_CCCH_MODE_REQ);
if (!msg)
return osmo_send_l1(ms, msg);
}
+/* Transmit L1CTL_TCH_MODE_REQ */
+int l1ctl_tx_tch_mode_req(struct osmocom_ms *ms, uint8_t tch_mode)
+{
+ struct msgb *msg;
+ struct l1ctl_tch_mode_req *req;
+
+ LOGP(DL1C, LOGL_INFO, "TCH Mode Req\n");
+
+ msg = osmo_l1_alloc(L1CTL_TCH_MODE_REQ);
+ if (!msg)
+ return -1;
+
+ req = (struct l1ctl_tch_mode_req *) msgb_put(msg, sizeof(*req));
+ req->tch_mode = tch_mode;
+
+ return osmo_send_l1(ms, msg);
+}
+
/* Transmit L1CTL_PARAM_REQ */
-int l1ctl_tx_ph_param_req(struct osmocom_ms *ms, uint8_t ta, uint8_t tx_power)
+int l1ctl_tx_param_req(struct osmocom_ms *ms, uint8_t ta, uint8_t tx_power)
{
struct msgb *msg;
struct l1ctl_info_ul *ul;
return osmo_send_l1(ms, msg);
}
+/* Transmit L1CTL_CRYPTO_REQ */
+int l1ctl_tx_crypto_req(struct osmocom_ms *ms, uint8_t algo, uint8_t *key,
+ uint8_t len)
+{
+ struct msgb *msg;
+ struct l1ctl_info_ul *ul;
+ struct l1ctl_crypto_req *req;
+
+ msg = osmo_l1_alloc(L1CTL_CRYPTO_REQ);
+ if (!msg)
+ return -1;
+
+ DEBUGP(DL1C, "CRYPTO Req. algo=%d, len=%d\n", algo, len);
+ ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
+ req = (struct l1ctl_crypto_req *) msgb_put(msg, sizeof(*req) + len);
+ req->algo = algo;
+ if (len)
+ memcpy(req->key, key, len);
+
+ return osmo_send_l1(ms, msg);
+}
+
/* Transmit L1CTL_RACH_REQ */
-int tx_ph_rach_req(struct osmocom_ms *ms, uint8_t ra, uint8_t fn51,
- uint8_t mf_off)
+int l1ctl_tx_rach_req(struct osmocom_ms *ms, uint8_t ra, uint16_t offset,
+ uint8_t combined)
{
struct msgb *msg;
struct l1ctl_info_ul *ul;
if (!msg)
return -1;
- DEBUGP(DL1C, "RACH Req. fn51=%d, mf_off=%d\n", fn51, mf_off);
+ DEBUGP(DL1C, "RACH Req. offset=%d combined=%d\n", offset, combined);
ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
req = (struct l1ctl_rach_req *) msgb_put(msg, sizeof(*req));
req->ra = ra;
- req->fn51 = fn51;
- req->mf_off = mf_off;
+ req->offset = htons(offset);
+ req->combined = combined;
return osmo_send_l1(ms, msg);
}
/* Transmit L1CTL_DM_EST_REQ */
-int tx_ph_dm_est_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,
- uint8_t chan_nr, uint8_t tsc)
+int l1ctl_tx_dm_est_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,
+ uint8_t chan_nr, uint8_t tsc, uint8_t tch_mode)
{
struct msgb *msg;
struct l1ctl_info_ul *ul;
if (!msg)
return -1;
- printf("Tx Dedic.Mode Est Req (arfcn=%u, chan_nr=0x%02x)\n",
- band_arfcn, chan_nr);
-
- memset(&ms->meas, 0, sizeof(ms->meas));
+ LOGP(DL1C, LOGL_INFO, "Tx Dedic.Mode Est Req (arfcn=%u, "
+ "chan_nr=0x%02x)\n", band_arfcn, chan_nr);
ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
ul->chan_nr = chan_nr;
req->tsc = tsc;
req->h = 0;
req->h0.band_arfcn = htons(band_arfcn);
+ req->tch_mode = tch_mode;
return osmo_send_l1(ms, msg);
}
-int tx_ph_dm_est_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
- uint16_t *ma, uint8_t ma_len, uint8_t chan_nr, uint8_t tsc)
+int l1ctl_tx_dm_est_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
+ uint16_t *ma, uint8_t ma_len,
+ uint8_t chan_nr, uint8_t tsc, uint8_t tch_mode)
{
struct msgb *msg;
struct l1ctl_info_ul *ul;
if (!msg)
return -1;
- printf("Tx Dedic.Mode Est Req (maio=%u, hsn=%u, "
+ LOGP(DL1C, LOGL_INFO, "Tx Dedic.Mode Est Req (maio=%u, hsn=%u, "
"chan_nr=0x%02x)\n", maio, hsn, chan_nr);
- memset(&ms->meas, 0, sizeof(ms->meas));
-
ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
ul->chan_nr = chan_nr;
ul->link_id = 0;
req->h1.maio = maio;
req->h1.hsn = hsn;
req->h1.n = ma_len;
+ for (i = 0; i < ma_len; i++)
+ req->h1.ma[i] = htons(ma[i]);
+ req->tch_mode = tch_mode;
+
+ return osmo_send_l1(ms, msg);
+}
+
+/* Transmit L1CTL_DM_FREQ_REQ */
+int l1ctl_tx_dm_freq_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,
+ uint8_t tsc, uint16_t fn)
+{
+ struct msgb *msg;
+ struct l1ctl_info_ul *ul;
+ struct l1ctl_dm_freq_req *req;
+
+ msg = osmo_l1_alloc(L1CTL_DM_FREQ_REQ);
+ if (!msg)
+ return -1;
+
+ LOGP(DL1C, LOGL_INFO, "Tx Dedic.Mode Freq Req (arfcn=%u, fn=%d)\n",
+ band_arfcn, fn);
+
+ ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
+ ul->chan_nr = 0;
+ ul->link_id = 0;
+
+ req = (struct l1ctl_dm_freq_req *) msgb_put(msg, sizeof(*req));
+ req->fn = htons(fn);
+ req->tsc = tsc;
+ req->h = 0;
+ req->h0.band_arfcn = htons(band_arfcn);
+
+ return osmo_send_l1(ms, msg);
+}
+
+int l1ctl_tx_dm_freq_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
+ uint16_t *ma, uint8_t ma_len,
+ uint8_t tsc, uint16_t fn)
+{
+ struct msgb *msg;
+ struct l1ctl_info_ul *ul;
+ struct l1ctl_dm_freq_req *req;
+ int i;
+
+ msg = osmo_l1_alloc(L1CTL_DM_FREQ_REQ);
+ if (!msg)
+ return -1;
+
+ LOGP(DL1C, LOGL_INFO, "Tx Dedic.Mode Freq Req (maio=%u, hsn=%u, "
+ "fn=%d)\n", maio, hsn, fn);
+
+ ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
+ ul->chan_nr = 0;
+ ul->link_id = 0;
+
+ req = (struct l1ctl_dm_freq_req *) msgb_put(msg, sizeof(*req));
+ req->fn = htons(fn);
+ req->tsc = tsc;
+ req->h = 1;
+ req->h1.maio = maio;
+ req->h1.hsn = hsn;
+ req->h1.n = ma_len;
for (i = 0; i < ma_len; i++)
req->h1.ma[i] = htons(ma[i]);
}
/* Transmit L1CTL_DM_REL_REQ */
-int tx_ph_dm_rel_req(struct osmocom_ms *ms)
+int l1ctl_tx_dm_rel_req(struct osmocom_ms *ms)
{
struct msgb *msg;
struct l1ctl_info_ul *ul;
if (!msg)
return -1;
- printf("Tx Dedic.Mode Rel Req\n");
-
- memset(&ms->meas, 0, sizeof(ms->meas));
+ LOGP(DL1C, LOGL_INFO, "Tx Dedic.Mode Rel Req\n");
ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
return osmo_send_l1(ms, msg);
}
+int l1ctl_tx_sim_req(struct osmocom_ms *ms, uint8_t *data, uint16_t length)
+{
+ struct msgb *msg;
+ uint8_t *dat;
+
+ msg = osmo_l1_alloc(L1CTL_SIM_REQ);
+ if (!msg)
+ return -1;
+
+ dat = msgb_put(msg, length);
+ memcpy(dat, data, length);
+
+ return osmo_send_l1(ms, msg);
+}
+
+/* just forward the SIM response to the SIM handler */
+static int rx_l1_sim_conf(struct osmocom_ms *ms, struct msgb *msg)
+{
+ uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
+ uint8_t *data = msg->data + sizeof(struct l1ctl_hdr);
+
+ LOGP(DL1C, LOGL_INFO, "SIM %s\n", hexdump(data, len));
+
+ /* pull the L1 header from the msgb */
+ msgb_pull(msg, sizeof(struct l1ctl_hdr));
+ msg->l1h = NULL;
+
+ sim_apdu_resp(ms, msg);
+
+ return 0;
+}
+
/* Transmit L1CTL_PM_REQ */
int l1ctl_tx_pm_req_range(struct osmocom_ms *ms, uint16_t arfcn_from,
uint16_t arfcn_to)
if (!msg)
return -1;
- printf("Tx PM Req (%u-%u)\n", arfcn_from, arfcn_to);
+ LOGP(DL1C, LOGL_INFO, "Tx PM Req (%u-%u)\n", arfcn_from, arfcn_to);
pm = (struct l1ctl_pm_req *) msgb_put(msg, sizeof(*pm));
pm->type = 1;
pm->range.band_arfcn_from = htons(arfcn_from);
if (!msg)
return -1;
- printf("Tx Reset Req (%u)\n", type);
+ LOGP(DL1C, LOGL_INFO, "Tx Reset Req (%u)\n", type);
res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res));
res->type = type;
/* Receive L1CTL_RESET_IND */
static int rx_l1_reset(struct osmocom_ms *ms)
{
- printf("Layer1 Reset indication\n");
+ LOGP(DL1C, LOGL_INFO, "Layer1 Reset indication\n");
dispatch_signal(SS_L1CTL, S_L1CTL_RESET, ms);
return 0;
return 0;
}
-/* Receive L1CTL_MODE_CONF */
+/* Receive L1CTL_CCCH_MODE_CONF */
static int rx_l1_ccch_mode_conf(struct osmocom_ms *ms, struct msgb *msg)
{
struct osmobb_ccch_mode_conf mc;
struct l1ctl_ccch_mode_conf *conf;
if (msgb_l3len(msg) < sizeof(*conf)) {
- LOGP(DL1C, LOGL_ERROR, "MODE CONF: MSG too short %u\n",
+ LOGP(DL1C, LOGL_ERROR, "CCCH MODE CONF: MSG too short %u\n",
msgb_l3len(msg));
return -1;
}
conf = (struct l1ctl_ccch_mode_conf *) msg->l1h;
- printf("mode=%u\n", conf->ccch_mode);
+ LOGP(DL1C, LOGL_INFO, "CCCH MODE CONF: mode=%u\n", conf->ccch_mode);
mc.ccch_mode = conf->ccch_mode;
mc.ms = ms;
return 0;
}
+/* Receive L1CTL_TCH_MODE_CONF */
+static int rx_l1_tch_mode_conf(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct osmobb_tch_mode_conf mc;
+ struct l1ctl_tch_mode_conf *conf;
+
+ if (msgb_l3len(msg) < sizeof(*conf)) {
+ LOGP(DL1C, LOGL_ERROR, "TCH MODE CONF: MSG too short %u\n",
+ msgb_l3len(msg));
+ return -1;
+ }
+
+ conf = (struct l1ctl_tch_mode_conf *) msg->l1h;
+
+ LOGP(DL1C, LOGL_INFO, "TCH MODE CONF: mode=%u\n", conf->tch_mode);
+
+ mc.tch_mode = conf->tch_mode;
+ mc.ms = ms;
+ dispatch_signal(SS_L1CTL, S_L1CTL_TCH_MODE_CONF, &mc);
+
+ return 0;
+}
+
/* Receive incoming data from L1 using L1CTL format */
int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg)
{
break;
case L1CTL_PM_CONF:
rc = rx_l1_pm_conf(ms, msg);
- msgb_free(msg);
if (l1h->flags & L1CTL_F_DONE)
dispatch_signal(SS_L1CTL, S_L1CTL_PM_DONE, ms);
+ msgb_free(msg);
break;
case L1CTL_RACH_CONF:
rc = rx_l1_rach_conf(ms, msg);
rc = rx_l1_ccch_mode_conf(ms, msg);
msgb_free(msg);
break;
+ case L1CTL_TCH_MODE_CONF:
+ rc = rx_l1_tch_mode_conf(ms, msg);
+ msgb_free(msg);
+ break;
+ case L1CTL_SIM_CONF:
+ rc = rx_l1_sim_conf(ms, msg);
+ break;
default:
- fprintf(stderr, "Unknown MSG: %u\n", l1h->msg_type);
+ LOGP(DL1C, LOGL_ERROR, "Unknown MSG: %u\n", l1h->msg_type);
msgb_free(msg);
break;
}