summaryrefslogtreecommitdiffstats
path: root/Src/osmolib
diff options
context:
space:
mode:
authorTom2012-05-21 18:30:02 +0200
committerTom2012-05-21 18:30:02 +0200
commit818bd7c053bb9c17f323134a244e6822fa02b99f (patch)
treeade9ada0879c08a6ae329287bf1f4301fb1d849d /Src/osmolib
parentfinished experiments seciton apart from tables where data is needed and appendix (diff)
downloadimsi-catcher-detection-818bd7c053bb9c17f323134a244e6822fa02b99f.tar.gz
imsi-catcher-detection-818bd7c053bb9c17f323134a244e6822fa02b99f.tar.xz
imsi-catcher-detection-818bd7c053bb9c17f323134a244e6822fa02b99f.zip
added sections on paging and paging feature in c code, lot of minor changes in tex files
Diffstat (limited to 'Src/osmolib')
-rw-r--r--Src/osmolib/src/host/layer23/src/misc/Makefile.am3
-rwxr-xr-xSrc/osmolib/src/host/layer23/src/misc/enc_scanbin0 -> 896781 bytes
-rw-r--r--Src/osmolib/src/host/layer23/src/misc/enc_scan.c556
-rw-r--r--Src/osmolib/src/host/layer23/src/misc/enc_scan_old.c785
4 files changed, 1343 insertions, 1 deletions
diff --git a/Src/osmolib/src/host/layer23/src/misc/Makefile.am b/Src/osmolib/src/host/layer23/src/misc/Makefile.am
index 1c5bd5c..8e9d7f6 100644
--- a/Src/osmolib/src/host/layer23/src/misc/Makefile.am
+++ b/Src/osmolib/src/host/layer23/src/misc/Makefile.am
@@ -2,11 +2,12 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS)
LDADD = ../common/liblayer23.a $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS)
-bin_PROGRAMS = bcch_scan ccch_scan echo_test cell_log catcher cbch_sniff
+bin_PROGRAMS = bcch_scan ccch_scan echo_test enc_scan cell_log catcher cbch_sniff
bcch_scan_SOURCES = ../common/main.c app_bcch_scan.c bcch_scan.c
ccch_scan_SOURCES = ../common/main.c app_ccch_scan.c rslms.c
echo_test_SOURCES = ../common/main.c app_echo_test.c
+enc_scan_SOURCES = ../common/main.c enc_scan.c rslms.c
cell_log_LDADD = $(LDADD) -lm
cell_log_SOURCES = ../common/main.c app_cell_log.c cell_log.c \
../../../gsmmap/geo.c
diff --git a/Src/osmolib/src/host/layer23/src/misc/enc_scan b/Src/osmolib/src/host/layer23/src/misc/enc_scan
new file mode 100755
index 0000000..3b26c35
--- /dev/null
+++ b/Src/osmolib/src/host/layer23/src/misc/enc_scan
Binary files differ
diff --git a/Src/osmolib/src/host/layer23/src/misc/enc_scan.c b/Src/osmolib/src/host/layer23/src/misc/enc_scan.c
new file mode 100644
index 0000000..bfba4ed
--- /dev/null
+++ b/Src/osmolib/src/host/layer23/src/misc/enc_scan.c
@@ -0,0 +1,556 @@
+/* CCCH passive sniffer */
+/* (C) 2010-2011 by Holger Hans Peter Freyther
+ * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/rsl.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/gsm/gsm48_ie.h>
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/core/signal.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+
+#include <osmocom/bb/common/logging.h>
+#include <osmocom/bb/misc/rslms.h>
+#include <osmocom/bb/misc/layer3.h>
+#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/common/l1ctl.h>
+#include <osmocom/bb/common/l23_app.h>
+
+#include <l1ctl_proto.h>
+
+static struct {
+ int has_si1;
+ int ccch_mode;
+ int ccch_enabled;
+ int rach_count;
+ struct gsm_sysinfo_freq cell_arfcns[1024];
+} app_state;
+
+
+static void dump_bcch(struct osmocom_ms *ms, uint8_t tc, const uint8_t *data)
+{
+ struct gsm48_system_information_type_header *si_hdr;
+ si_hdr = (struct gsm48_system_information_type_header *) data;
+
+ /* GSM 05.02 §6.3.1.3 Mapping of BCCH data */
+ switch (si_hdr->system_information) {
+ case GSM48_MT_RR_SYSINFO_1:
+#ifdef BCCH_TC_CHECK
+ if (tc != 0)
+ //LOGP(DRR, LOGL_ERROR, "SI1 on the wrong TC: %d\n", tc);
+#endif
+ if (!app_state.has_si1) {
+ struct gsm48_system_information_type_1 *si1 =
+ (struct gsm48_system_information_type_1 *)data;
+
+ gsm48_decode_freq_list(app_state.cell_arfcns,
+ si1->cell_channel_description,
+ sizeof(si1->cell_channel_description),
+ 0xff, 0x01);
+
+ app_state.has_si1 = 1;
+ //LOGP(DRR, LOGL_ERROR, "SI1 received.\n");
+ }
+ break;
+ case GSM48_MT_RR_SYSINFO_2:
+#ifdef BCCH_TC_CHECK
+ if (tc != 1)
+ //LOGP(DRR, LOGL_ERROR, "SI2 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_3:
+#ifdef BCCH_TC_CHECK
+ if (tc != 2 && tc != 6)
+ //LOGP(DRR, LOGL_ERROR, "SI3 on the wrong TC: %d\n", tc);
+#endif
+ if (app_state.ccch_mode == CCCH_MODE_NONE) {
+ struct gsm48_system_information_type_3 *si3 =
+ (struct gsm48_system_information_type_3 *)data;
+
+ if (si3->control_channel_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C)
+ app_state.ccch_mode = CCCH_MODE_COMBINED;
+ else
+ app_state.ccch_mode = CCCH_MODE_NON_COMBINED;
+
+ l1ctl_tx_ccch_mode_req(ms, app_state.ccch_mode);
+ }
+ break;
+ case GSM48_MT_RR_SYSINFO_4:
+#ifdef BCCH_TC_CHECK
+ if (tc != 3 && tc != 7)
+ //LOGP(DRR, LOGL_ERROR, "SI4 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_5:
+ break;
+ case GSM48_MT_RR_SYSINFO_6:
+ break;
+ case GSM48_MT_RR_SYSINFO_7:
+#ifdef BCCH_TC_CHECK
+ if (tc != 7)
+ //LOGP(DRR, LOGL_ERROR, "SI7 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_8:
+#ifdef BCCH_TC_CHECK
+ if (tc != 3)
+ //LOGP(DRR, LOGL_ERROR, "SI8 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_9:
+#ifdef BCCH_TC_CHECK
+ if (tc != 4)
+ //LOGP(DRR, LOGL_ERROR, "SI9 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_13:
+#ifdef BCCH_TC_CHECK
+ if (tc != 4 && tc != 0)
+ //LOGP(DRR, LOGL_ERROR, "SI13 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_16:
+#ifdef BCCH_TC_CHECK
+ if (tc != 6)
+ //LOGP(DRR, LOGL_ERROR, "SI16 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_17:
+#ifdef BCCH_TC_CHECK
+ if (tc != 2)
+ //LOGP(DRR, LOGL_ERROR, "SI17 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_2bis:
+#ifdef BCCH_TC_CHECK
+ if (tc != 5)
+ //LOGP(DRR, LOGL_ERROR, "SI2bis on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_2ter:
+#ifdef BCCH_TC_CHECK
+ if (tc != 5 && tc != 4)
+ //LOGP(DRR, LOGL_ERROR, "SI2ter on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_5bis:
+ break;
+ case GSM48_MT_RR_SYSINFO_5ter:
+ break;
+ default:
+ /*
+ LOGP(DRR, LOGL_ERROR, "Unknown SI: %d\n",
+ si_hdr->system_information);
+ */
+ break;
+ };
+}
+
+/* send location updating request * (as part of RSLms EST IND /
+ LAPDm SABME) */
+
+static int gsm48_tx_loc_upd_req(struct osmocom_ms *ms, uint8_t chan_nr)
+{
+ LOGP(DRR,LOGL_NOTICE, "tx-loc-upd-req");
+ struct msgb *msg = msgb_alloc_headroom(256, 16, "loc_upd_req");
+ struct gsm48_hdr *gh;
+ struct gsm48_loc_upd_req *lu_r;
+
+ //DEBUGP(DMM, "chan_nr=%u\n", chan_nr);
+
+ msg->l3h = msgb_put(msg, sizeof(*gh));
+ gh = (struct gsm48_hdr *) msg->l3h;
+ gh->proto_discr = GSM48_PDISC_MM;
+ gh->msg_type = GSM48_MT_MM_LOC_UPD_REQUEST;
+ lu_r = (struct gsm48_loc_upd_req *) msgb_put(msg, sizeof(*lu_r));
+ lu_r->type = GSM48_LUPD_IMSI_ATT;
+ lu_r->key_seq = 0;
+ /* FIXME: set LAI and CM1 */
+ /* FIXME: set MI */
+
+ lu_r->mi_len = 0;
+
+ return rslms_tx_rll_req_l3(ms, RSL_MT_EST_REQ, chan_nr, 0, msg);
+}
+
+
+/**
+ * This method used to send a l1ctl_tx_dm_est_req_h0 or
+ * a l1ctl_tx_dm_est_req_h1 to the layer1 to follow this
+ * assignment. The code has been removed.
+ */
+static int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms)
+{
+ struct gsm48_imm_ass *ia = msgb_l3(msg);
+ uint8_t ch_type, ch_subch, ch_ts;
+
+ //needed to go to dedicated mode
+ int rv;
+
+ /* Discard packet TBF assignement */
+ if (ia->page_mode & 0xf0)
+ return 0;
+
+ /* FIXME: compare RA and GSM time with when we sent RACH req */
+
+ rsl_dec_chan_nr(ia->chan_desc.chan_nr, &ch_type, &ch_subch, &ch_ts);
+
+ if (!ia->chan_desc.h0.h) {
+ /* Non-hopping */
+ uint16_t arfcn;
+
+ arfcn = ia->chan_desc.h0.arfcn_low | (ia->chan_desc.h0.arfcn_high << 8);
+
+ LOGP(DRR, LOGL_NOTICE, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
+ "ARFCN=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
+ ia->chan_desc.chan_nr, arfcn, ch_ts, ch_subch,
+ ia->chan_desc.h0.tsc);
+
+ /* request L1 to go to dedicated mode on assigned channel */
+
+ rv = l1ctl_tx_dm_est_req_h0(ms,
+ arfcn, ia->chan_desc.chan_nr, ia->chan_desc.h0.tsc,
+ GSM48_CMODE_SIGN,0);
+
+
+ } else {
+ /* Hopping */
+ uint8_t maio, hsn, ma_len;
+ uint16_t ma[64], arfcn;
+ int i, j, k;
+
+ hsn = ia->chan_desc.h1.hsn;
+ maio = ia->chan_desc.h1.maio_low | (ia->chan_desc.h1.maio_high << 2);
+
+ LOGP(DRR, LOGL_NOTICE, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
+ "HSN=%u, MAIO=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
+ ia->chan_desc.chan_nr, hsn, maio, ch_ts, ch_subch,
+ ia->chan_desc.h1.tsc);
+
+ /* decode mobile allocation */
+ ma_len = 0;
+ for (i=1, j=0; i<=1024; i++) {
+ arfcn = i & 1023;
+ if (app_state.cell_arfcns[arfcn].mask & 0x01) {
+ k = ia->mob_alloc_len - (j>>3) - 1;
+ if (ia->mob_alloc[k] & (1 << (j&7))) {
+ ma[ma_len++] = arfcn;
+ }
+ j++;
+ }
+ }
+ /* request L1 to go to dedicated mode on assigned channel */
+
+ rv = l1ctl_tx_dm_est_req_h1(ms,
+ maio, hsn, ma, ma_len,
+ ia->chan_desc.chan_nr, ia->chan_desc.h1.tsc,
+ GSM48_CMODE_SIGN,0);
+
+ }
+
+ LOGPC(DRR, LOGL_NOTICE, "\n");
+
+ rv = gsm48_tx_loc_upd_req(ms, ia->chan_desc.chan_nr);
+
+ return rv;
+ return 0;
+}
+
+static const char *pag_print_mode(int mode)
+{
+ switch (mode) {
+ case 0:
+ return "Normal paging";
+ case 1:
+ return "Extended paging";
+ case 2:
+ return "Paging reorganization";
+ case 3:
+ return "Same as before";
+ default:
+ return "invalid";
+ }
+}
+
+static char *chan_need(int need)
+{
+ switch (need) {
+ case 0:
+ return "any";
+ case 1:
+ return "sdch";
+ case 2:
+ return "tch/f";
+ case 3:
+ return "tch/h";
+ default:
+ return "invalid";
+ }
+}
+
+static char *mi_type_to_string(int type)
+{
+ switch (type) {
+ case GSM_MI_TYPE_NONE:
+ return "none";
+ case GSM_MI_TYPE_IMSI:
+ return "imsi";
+ case GSM_MI_TYPE_IMEI:
+ return "imei";
+ case GSM_MI_TYPE_IMEISV:
+ return "imeisv";
+ case GSM_MI_TYPE_TMSI:
+ return "tmsi";
+ default:
+ return "invalid";
+ }
+}
+
+/**
+ * This can contain two MIs. The size checking is a bit of a mess.
+ */
+static int gsm48_rx_paging_p1(struct msgb *msg, struct osmocom_ms *ms)
+{
+ struct gsm48_paging1 *pag;
+ int len1, len2, mi_type, tag;
+ char mi_string[GSM48_MI_SIZE];
+
+ /* is there enough room for the header + LV? */
+ if (msgb_l3len(msg) < sizeof(*pag) + 2) {
+ //LOGP(DRR, LOGL_ERROR, "PagingRequest is too short.\n");
+ return -1;
+ }
+
+ pag = msgb_l3(msg);
+ len1 = pag->data[0];
+ mi_type = pag->data[1] & GSM_MI_TYPE_MASK;
+
+ if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1) {
+ //LOGP(DRR, LOGL_ERROR, "PagingRequest with wrong MI\n");
+ return -1;
+ }
+
+ if (mi_type != GSM_MI_TYPE_NONE) {
+ gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[1], len1);
+ LOGP(DRR, LOGL_NOTICE, "Paging1: %s chan %s to %s M(%s) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed1),
+ mi_type_to_string(mi_type),
+ mi_string);
+ }
+
+ /* check if we have a MI type in here */
+ if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1 + 3)
+ return 0;
+
+ tag = pag->data[2 + len1 + 0];
+ len2 = pag->data[2 + len1 + 1];
+ mi_type = pag->data[2 + len1 + 2] & GSM_MI_TYPE_MASK;
+ if (tag == GSM48_IE_MOBILE_ID && mi_type != GSM_MI_TYPE_NONE) {
+ if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1 + 3 + len2) {
+ //LOGP(DRR, LOGL_ERROR, "Optional MI does not fit here.\n");
+ return -1;
+ }
+
+ gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[2 + len1 + 2], len2);
+ LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to %s M(%s) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed2),
+ mi_type_to_string(mi_type),
+ mi_string);
+ }
+ return 0;
+}
+
+static int gsm48_rx_paging_p2(struct msgb *msg, struct osmocom_ms *ms)
+{
+ struct gsm48_paging2 *pag;
+ int tag, len, mi_type;
+ char mi_string[GSM48_MI_SIZE];
+
+ if (msgb_l3len(msg) < sizeof(*pag)) {
+ //LOGP(DRR, LOGL_ERROR, "Paging2 message is too small.\n");
+ return -1;
+ }
+
+ pag = msgb_l3(msg);
+ LOGP(DRR, LOGL_NOTICE, "Paging1: %s chan %s to TMSI M(0x%x) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed1), pag->tmsi1);
+ LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to TMSI M(0x%x) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed2), pag->tmsi2);
+ /* no optional element */
+ if (msgb_l3len(msg) < sizeof(*pag) + 3)
+ return 0;
+
+ tag = pag->data[0];
+ len = pag->data[1];
+ mi_type = pag->data[2] & GSM_MI_TYPE_MASK;
+
+ if (tag != GSM48_IE_MOBILE_ID)
+ return 0;
+
+ if (msgb_l3len(msg) < sizeof(*pag) + 3 + len) {
+ //LOGP(DRR, LOGL_ERROR, "Optional MI does not fit in here\n");
+ return -1;
+ }
+
+ gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[2], len);
+ LOGP(DRR, LOGL_NOTICE, "Paging3: %s chan %s to %s M(%s) \n",
+ pag_print_mode(pag->pag_mode),
+ "n/a ",
+ mi_type_to_string(mi_type),
+ mi_string);
+ return 0;
+}
+
+static int gsm48_rx_paging_p3(struct msgb *msg, struct osmocom_ms *ms)
+{
+ struct gsm48_paging3 *pag;
+
+ if (msgb_l3len(msg) < sizeof(*pag)) {
+ //LOGP(DRR, LOGL_ERROR, "Paging3 message is too small.\n");
+ return -1;
+ }
+
+ pag = msgb_l3(msg);
+ LOGP(DRR, LOGL_NOTICE, "Paging1: %s chan %s to TMSI M(0x%x) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed1), pag->tmsi1);
+ LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to TMSI M(0x%x) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed2), pag->tmsi2);
+ LOGP(DRR, LOGL_NOTICE, "Paging3: %s chan %s to TMSI M(0x%x) \n",
+ pag_print_mode(pag->pag_mode),
+ "n/a ", pag->tmsi3);
+ LOGP(DRR, LOGL_NOTICE, "Paging4: %s chan %s to TMSI M(0x%x) \n",
+ pag_print_mode(pag->pag_mode),
+ "n/a ", pag->tmsi4);
+ return 0;
+}
+
+int gsm48_rx_ccch(struct msgb *msg, struct osmocom_ms *ms)
+{
+ struct gsm48_system_information_type_header *sih = msgb_l3(msg);
+ int rc = 0;
+
+ //if (sih->rr_protocol_discriminator != GSM48_PDISC_RR)
+ //LOGP(DRR, LOGL_ERROR, "PCH pdisc != RR\n");
+
+ switch (sih->system_information) {
+ case GSM48_MT_RR_PAG_REQ_1:
+ gsm48_rx_paging_p1(msg, ms);
+ break;
+ case GSM48_MT_RR_PAG_REQ_2:
+ gsm48_rx_paging_p2(msg, ms);
+ break;
+ case GSM48_MT_RR_PAG_REQ_3:
+ gsm48_rx_paging_p3(msg, ms);
+ break;
+ case GSM48_MT_RR_IMM_ASS:
+ gsm48_rx_imm_ass(msg, ms);
+ break;
+ case GSM48_MT_RR_NOTIF_NCH:
+ /* notification for voice call groups and such */
+ break;
+ case 0x07:
+ /* wireshark know that this is SI2 quater and for 3G interop */
+ break;
+ default:
+ LOGP(DRR, LOGL_NOTICE, "unknown PCH/AGCH type 0x%02x\n",
+ sih->system_information);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+int gsm48_rx_bcch(struct msgb *msg, struct osmocom_ms *ms)
+{
+ /* FIXME: we have lost the gsm frame time until here, need to store it
+ * in some msgb context */
+ //dump_bcch(dl->time.tc, ccch->data);
+ dump_bcch(ms, 0, msg->l3h);
+
+ /* Req channel logic */
+ if (app_state.ccch_enabled && (app_state.rach_count < 2)) {
+ l1ctl_tx_rach_req(ms, app_state.rach_count, 0,
+ app_state.ccch_mode == CCCH_MODE_COMBINED);
+ app_state.rach_count++;
+ }
+
+ return 0;
+}
+
+void layer3_app_reset(void)
+{
+ /* Reset state */
+ app_state.has_si1 = 0;
+ app_state.ccch_mode = CCCH_MODE_NONE;
+ app_state.ccch_enabled = 0;
+ app_state.rach_count = 0;
+
+ memset(&app_state.cell_arfcns, 0x00, sizeof(app_state.cell_arfcns));
+}
+
+static int signal_cb(unsigned int subsys, unsigned int signal,
+ void *handler_data, void *signal_data)
+{
+ struct osmocom_ms *ms;
+
+ if (subsys != SS_L1CTL)
+ return 0;
+
+ switch (signal) {
+ case S_L1CTL_RESET:
+ ms = signal_data;
+ layer3_app_reset();
+ return l1ctl_tx_fbsb_req(ms, ms->test_arfcn,
+ L1CTL_FBSB_F_FB01SB, 100, 0,
+ CCCH_MODE_NONE);
+ break;
+ }
+ return 0;
+}
+
+
+int l23_app_init(struct osmocom_ms *ms)
+{
+ osmo_signal_register_handler(SS_L1CTL, &signal_cb, NULL);
+ l1ctl_tx_reset_req(ms, L1CTL_RES_T_FULL);
+ return layer3_init(ms);
+}
+
+static struct l23_app_info info = {
+ .copyright = "Copyright (C) 2010 Harald Welte <laforge@gnumonks.org>\n",
+ .contribution = "Contributions by Holger Hans Peter Freyther\n",
+};
+
+struct l23_app_info *l23_app_info()
+{
+ return &info;
+}
diff --git a/Src/osmolib/src/host/layer23/src/misc/enc_scan_old.c b/Src/osmolib/src/host/layer23/src/misc/enc_scan_old.c
new file mode 100644
index 0000000..1c097df
--- /dev/null
+++ b/Src/osmolib/src/host/layer23/src/misc/enc_scan_old.c
@@ -0,0 +1,785 @@
+/* CCCH passive sniffer */
+/* (C) 2010-2011 by Holger Hans Peter Freyther
+ * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <getopt.h>
+
+#include <arpa/inet.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/rsl.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/gsm/gsm48_ie.h>
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/core/signal.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/core/gsmtap_util.h>
+#include <osmocom/core/bits.h>
+#include <osmocom/gsm/a5.h>
+
+#include <osmocom/bb/common/logging.h>
+#include <osmocom/bb/misc/rslms.h>
+#include <osmocom/bb/misc/layer3.h>
+#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/common/l1ctl.h>
+#include <osmocom/bb/common/l23_app.h>
+
+#include <l1ctl_proto.h>
+
+#include <osmocom/bb/misc/xcch.h>
+
+extern struct gsmtap_inst *gsmtap_inst;
+
+enum dch_state_t {
+ DCH_NONE,
+ DCH_WAIT_EST,
+ DCH_ACTIVE,
+ DCH_WAIT_REL,
+};
+
+static struct {
+ int has_si1;
+ int ccch_mode;
+
+ enum dch_state_t dch_state;
+ uint8_t dch_nr;
+ int dch_badcnt;
+ int dch_ciph;
+
+ FILE * fh;
+
+ sbit_t bursts_dl[116 * 4];
+ sbit_t bursts_ul[116 * 4];
+
+ struct gsm_sysinfo_freq cell_arfcns[1024];
+
+ uint8_t kc[8];
+} app_state;
+
+
+static void dump_bcch(struct osmocom_ms *ms, uint8_t tc, const uint8_t *data)
+{
+ struct gsm48_system_information_type_header *si_hdr;
+ si_hdr = (struct gsm48_system_information_type_header *) data;
+
+ /* GSM 05.02 §6.3.1.3 Mapping of BCCH data */
+ switch (si_hdr->system_information) {
+ case GSM48_MT_RR_SYSINFO_1:
+#ifdef BCCH_TC_CHECK
+ if (tc != 0)
+ LOGP(DRR, LOGL_ERROR, "SI1 on the wrong TC: %d\n", tc);
+#endif
+ if (!app_state.has_si1) {
+ struct gsm48_system_information_type_1 *si1 =
+ (struct gsm48_system_information_type_1 *)data;
+
+ gsm48_decode_freq_list(app_state.cell_arfcns,
+ si1->cell_channel_description,
+ sizeof(si1->cell_channel_description),
+ 0xff, 0x01);
+
+ app_state.has_si1 = 1;
+ LOGP(DRR, LOGL_ERROR, "SI1 received.\n");
+ }
+ break;
+ case GSM48_MT_RR_SYSINFO_2:
+#ifdef BCCH_TC_CHECK
+ if (tc != 1)
+ LOGP(DRR, LOGL_ERROR, "SI2 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_3:
+#ifdef BCCH_TC_CHECK
+ if (tc != 2 && tc != 6)
+ LOGP(DRR, LOGL_ERROR, "SI3 on the wrong TC: %d\n", tc);
+#endif
+ if (app_state.ccch_mode == CCCH_MODE_NONE) {
+ struct gsm48_system_information_type_3 *si3 =
+ (struct gsm48_system_information_type_3 *)data;
+
+ if (si3->control_channel_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C)
+ app_state.ccch_mode = CCCH_MODE_COMBINED;
+ else
+ app_state.ccch_mode = CCCH_MODE_NON_COMBINED;
+
+ l1ctl_tx_ccch_mode_req(ms, app_state.ccch_mode);
+ }
+ break;
+ case GSM48_MT_RR_SYSINFO_4:
+#ifdef BCCH_TC_CHECK
+ if (tc != 3 && tc != 7)
+ LOGP(DRR, LOGL_ERROR, "SI4 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_5:
+ break;
+ case GSM48_MT_RR_SYSINFO_6:
+ break;
+ case GSM48_MT_RR_SYSINFO_7:
+#ifdef BCCH_TC_CHECK
+ if (tc != 7)
+ LOGP(DRR, LOGL_ERROR, "SI7 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_8:
+#ifdef BCCH_TC_CHECK
+ if (tc != 3)
+ LOGP(DRR, LOGL_ERROR, "SI8 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_9:
+#ifdef BCCH_TC_CHECK
+ if (tc != 4)
+ LOGP(DRR, LOGL_ERROR, "SI9 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_13:
+#ifdef BCCH_TC_CHECK
+ if (tc != 4 && tc != 0)
+ LOGP(DRR, LOGL_ERROR, "SI13 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_16:
+#ifdef BCCH_TC_CHECK
+ if (tc != 6)
+ LOGP(DRR, LOGL_ERROR, "SI16 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_17:
+#ifdef BCCH_TC_CHECK
+ if (tc != 2)
+ LOGP(DRR, LOGL_ERROR, "SI17 on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_2bis:
+#ifdef BCCH_TC_CHECK
+ if (tc != 5)
+ LOGP(DRR, LOGL_ERROR, "SI2bis on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_2ter:
+#ifdef BCCH_TC_CHECK
+ if (tc != 5 && tc != 4)
+ LOGP(DRR, LOGL_ERROR, "SI2ter on the wrong TC: %d\n", tc);
+#endif
+ break;
+ case GSM48_MT_RR_SYSINFO_5bis:
+ break;
+ case GSM48_MT_RR_SYSINFO_5ter:
+ break;
+ default:
+ fprintf(stderr, "\tUnknown SI");
+ break;
+ };
+}
+
+
+/**
+ * This method used to send a l1ctl_tx_dm_est_req_h0 or
+ * a l1ctl_tx_dm_est_req_h1 to the layer1 to follow this
+ * assignment. The code has been removed.
+ */
+static int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms)
+{
+ struct gsm48_imm_ass *ia = msgb_l3(msg);
+ uint8_t ch_type, ch_subch, ch_ts;
+ int rv;
+
+ /* Discard packet TBF assignement */
+ if (ia->page_mode & 0xf0)
+ return 0;
+
+ /* If we're not ready yet, or just busy ... */
+ if ((!app_state.has_si1) || (app_state.dch_state != DCH_NONE))
+ return 0;
+
+ rsl_dec_chan_nr(ia->chan_desc.chan_nr, &ch_type, &ch_subch, &ch_ts);
+
+ if (!ia->chan_desc.h0.h) {
+ /* Non-hopping */
+ uint16_t arfcn;
+
+ arfcn = ia->chan_desc.h0.arfcn_low | (ia->chan_desc.h0.arfcn_high << 8);
+
+ LOGP(DRR, LOGL_NOTICE, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
+ "ARFCN=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
+ ia->chan_desc.chan_nr, arfcn, ch_ts, ch_subch,
+ ia->chan_desc.h0.tsc);
+
+ /* request L1 to go to dedicated mode on assigned channel */
+ rv = l1ctl_tx_dm_est_req_h0(ms,
+ arfcn, ia->chan_desc.chan_nr, ia->chan_desc.h0.tsc,
+ GSM48_CMODE_SIGN, 0);
+ } else {
+ /* Hopping */
+ uint8_t maio, hsn, ma_len;
+ uint16_t ma[64], arfcn;
+ int i, j, k;
+
+ hsn = ia->chan_desc.h1.hsn;
+ maio = ia->chan_desc.h1.maio_low | (ia->chan_desc.h1.maio_high << 2);
+
+ LOGP(DRR, LOGL_NOTICE, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
+ "HSN=%u, MAIO=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
+ ia->chan_desc.chan_nr, hsn, maio, ch_ts, ch_subch,
+ ia->chan_desc.h1.tsc);
+
+ /* decode mobile allocation */
+ ma_len = 0;
+ for (i=1, j=0; i<=1024; i++) {
+ arfcn = i & 1023;
+ if (app_state.cell_arfcns[arfcn].mask & 0x01) {
+ k = ia->mob_alloc_len - (j>>3) - 1;
+ if (ia->mob_alloc[k] & (1 << (j&7))) {
+ ma[ma_len++] = arfcn;
+ }
+ j++;
+ }
+ }
+
+ /* request L1 to go to dedicated mode on assigned channel */
+ rv = l1ctl_tx_dm_est_req_h1(ms,
+ maio, hsn, ma, ma_len,
+ ia->chan_desc.chan_nr, ia->chan_desc.h1.tsc,
+ GSM48_CMODE_SIGN, 0);
+ }
+
+ LOGPC(DRR, LOGL_NOTICE, "\n");
+
+ /* Set state */
+ app_state.dch_state = DCH_WAIT_EST;
+ app_state.dch_nr = ia->chan_desc.chan_nr;
+ app_state.dch_badcnt = 0;
+
+ return rv;
+}
+
+static const char *pag_print_mode(int mode)
+{
+ switch (mode) {
+ case 0:
+ return "Normal paging";
+ case 1:
+ return "Extended paging";
+ case 2:
+ return "Paging reorganization";
+ case 3:
+ return "Same as before";
+ default:
+ return "invalid";
+ }
+}
+
+static char *chan_need(int need)
+{
+ switch (need) {
+ case 0:
+ return "any";
+ case 1:
+ return "sdch";
+ case 2:
+ return "tch/f";
+ case 3:
+ return "tch/h";
+ default:
+ return "invalid";
+ }
+}
+
+static char *mi_type_to_string(int type)
+{
+ switch (type) {
+ case GSM_MI_TYPE_NONE:
+ return "none";
+ case GSM_MI_TYPE_IMSI:
+ return "imsi";
+ case GSM_MI_TYPE_IMEI:
+ return "imei";
+ case GSM_MI_TYPE_IMEISV:
+ return "imeisv";
+ case GSM_MI_TYPE_TMSI:
+ return "tmsi";
+ default:
+ return "invalid";
+ }
+}
+
+/**
+ * This can contain two MIs. The size checking is a bit of a mess.
+ */
+static int gsm48_rx_paging_p1(struct msgb *msg, struct osmocom_ms *ms)
+{
+ struct gsm48_paging1 *pag;
+ int len1, len2, mi_type, tag;
+ char mi_string[GSM48_MI_SIZE];
+
+ /* is there enough room for the header + LV? */
+ if (msgb_l3len(msg) < sizeof(*pag) + 2) {
+ LOGP(DRR, LOGL_ERROR, "PagingRequest is too short.\n");
+ return -1;
+ }
+
+ pag = msgb_l3(msg);
+ len1 = pag->data[0];
+ mi_type = pag->data[1] & GSM_MI_TYPE_MASK;
+
+ if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1) {
+ LOGP(DRR, LOGL_ERROR, "PagingRequest with wrong MI\n");
+ return -1;
+ }
+
+ if (mi_type != GSM_MI_TYPE_NONE) {
+ gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[1], len1);
+ LOGP(DRR, LOGL_NOTICE, "Paging1: %s chan %s to %s M(%s) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed1),
+ mi_type_to_string(mi_type),
+ mi_string);
+ }
+
+ /* check if we have a MI type in here */
+ if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1 + 3)
+ return 0;
+
+ tag = pag->data[2 + len1 + 0];
+ len2 = pag->data[2 + len1 + 1];
+ mi_type = pag->data[2 + len1 + 2] & GSM_MI_TYPE_MASK;
+ if (tag == GSM48_IE_MOBILE_ID && mi_type != GSM_MI_TYPE_NONE) {
+ if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1 + 3 + len2) {
+ LOGP(DRR, LOGL_ERROR, "Optional MI does not fit here.\n");
+ return -1;
+ }
+
+ gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[2 + len1 + 2], len2);
+ LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to %s M(%s) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed2),
+ mi_type_to_string(mi_type),
+ mi_string);
+ }
+ return 0;
+}
+
+static int gsm48_rx_paging_p2(struct msgb *msg, struct osmocom_ms *ms)
+{
+ struct gsm48_paging2 *pag;
+ int tag, len, mi_type;
+ char mi_string[GSM48_MI_SIZE];
+
+ if (msgb_l3len(msg) < sizeof(*pag)) {
+ LOGP(DRR, LOGL_ERROR, "Paging2 message is too small.\n");
+ return -1;
+ }
+
+ pag = msgb_l3(msg);
+ LOGP(DRR, LOGL_NOTICE, "Paging1: %s chan %s to TMSI M(0x%x) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed1), pag->tmsi1);
+ LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to TMSI M(0x%x) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed1), pag->tmsi2);
+
+ /* no optional element */
+ if (msgb_l3len(msg) < sizeof(*pag) + 3)
+ return 0;
+
+ tag = pag->data[0];
+ len = pag->data[1];
+ mi_type = pag->data[2] & GSM_MI_TYPE_MASK;
+
+ if (tag != GSM48_IE_MOBILE_ID)
+ return 0;
+
+ if (msgb_l3len(msg) < sizeof(*pag) + 3 + len) {
+ LOGP(DRR, LOGL_ERROR, "Optional MI does not fit in here\n");
+ return -1;
+ }
+
+ gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[2], len);
+ LOGP(DRR, LOGL_NOTICE, "Paging3: %s chan %s to %s M(%s) \n",
+ pag_print_mode(pag->pag_mode),
+ "n/a ",
+ mi_type_to_string(mi_type),
+ mi_string);
+
+ return 0;
+}
+
+int gsm48_rx_ccch(struct msgb *msg, struct osmocom_ms *ms)
+{
+ struct gsm48_system_information_type_header *sih = msgb_l3(msg);
+ int rc = 0;
+
+ /* CCCH marks the end of WAIT_REL */
+ if (app_state.dch_state == DCH_WAIT_REL)
+ app_state.dch_state = DCH_NONE;
+
+ if (sih->rr_protocol_discriminator != GSM48_PDISC_RR)
+ LOGP(DRR, LOGL_ERROR, "PCH pdisc != RR\n");
+
+ switch (sih->system_information) {
+ case GSM48_MT_RR_PAG_REQ_1:
+ gsm48_rx_paging_p1(msg, ms);
+ break;
+ case GSM48_MT_RR_PAG_REQ_2:
+ gsm48_rx_paging_p2(msg, ms);
+ break;
+ case GSM48_MT_RR_PAG_REQ_3:
+ LOGP(DRR, LOGL_ERROR, "PAGING of type 3 is not implemented.\n");
+ break;
+ case GSM48_MT_RR_IMM_ASS:
+ gsm48_rx_imm_ass(msg, ms);
+ break;
+ case GSM48_MT_RR_NOTIF_NCH:
+ /* notification for voice call groups and such */
+ break;
+ case 0x07:
+ /* wireshark know that this is SI2 quater and for 3G interop */
+ break;
+ default:
+ LOGP(DRR, LOGL_NOTICE, "unknown PCH/AGCH type 0x%02x\n",
+ sih->system_information);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+int gsm48_rx_bcch(struct msgb *msg, struct osmocom_ms *ms)
+{
+ /* BCCH marks the end of WAIT_REL */
+ if (app_state.dch_state == DCH_WAIT_REL)
+ app_state.dch_state = DCH_NONE;
+
+ /* FIXME: we have lost the gsm frame time until here, need to store it
+ * in some msgb context */
+ //dump_bcch(dl->time.tc, ccch->data);
+ dump_bcch(ms, 0, msg->l3h);
+
+ return 0;
+}
+
+
+static void local_burst_decode(struct l1ctl_burst_ind *bi)
+{
+ int16_t rx_dbm;
+ uint16_t arfcn;
+ uint32_t fn;
+ uint8_t cbits, tn, lch_idx;
+ int ul, bid, i;
+ sbit_t *bursts;
+ ubit_t bt[116];
+
+ /* Get params (Only for SDCCH and SACCH/{4,8,F,H}) */
+ arfcn = ntohs(bi->band_arfcn);
+ rx_dbm = rxlev2dbm(bi->rx_level);
+
+ fn = ntohl(bi->frame_nr);
+ ul = !!(arfcn & ARFCN_UPLINK);
+ bursts = ul ? app_state.bursts_ul : app_state.bursts_dl;
+
+ cbits = bi->chan_nr >> 3;
+ tn = bi->chan_nr & 7;
+
+ bid = -1;
+
+ if (cbits == 0x01) { /* TCH/F */
+ lch_idx = 0;
+ if (bi->flags & BI_FLG_SACCH) {
+ uint32_t fn_report;
+ fn_report = (fn - (tn * 13) + 104) % 104;
+ bid = (fn_report - 12) / 26;
+ }
+ } else if ((cbits & 0x1e) == 0x02) { /* TCH/H */
+ lch_idx = cbits & 1;
+ if (bi->flags & BI_FLG_SACCH) {
+ uint32_t fn_report;
+ uint8_t tn_report = (tn & ~1) | lch_idx;
+ fn_report = (fn - (tn_report * 13) + 104) % 104;
+ bid = (fn_report - 12) / 26;
+ }
+ } else if ((cbits & 0x1c) == 0x04) { /* SDCCH/4 */
+ lch_idx = cbits & 3;
+ bid = bi->flags & 3;
+ } else if ((cbits & 0x18) == 0x08) { /* SDCCH/8 */
+ lch_idx = cbits & 7;
+ bid = bi->flags & 3;
+ }
+
+ if (bid == -1)
+ return;
+
+ /* Clear if new set */
+ if (bid == 0)
+ memset(bursts, 0x00, 116 * 4);
+
+ /* Unpack (ignore hu/hl) */
+ osmo_pbit2ubit_ext(bt, 0, bi->bits, 0, 57, 0);
+ osmo_pbit2ubit_ext(bt, 59, bi->bits, 57, 57, 0);
+ bt[57] = bt[58] = 1;
+
+ /* A5/x */
+ if (app_state.dch_ciph) {
+ ubit_t ks_dl[114], ks_ul[114], *ks = ul ? ks_ul : ks_dl;
+ osmo_a5(app_state.dch_ciph, app_state.kc, fn, ks_dl, ks_ul);
+ for (i= 0; i< 57; i++) bt[i] ^= ks[i];
+ for (i=59; i<116; i++) bt[i] ^= ks[i-2];
+ }
+
+ /* Convert to softbits */
+ for (i=0; i<116; i++)
+ bursts[(116*bid)+i] = bt[i] ? - (bi->snr >> 1) : (bi->snr >> 1);
+
+ /* If last, decode */
+ if (bid == 3)
+ {
+ uint8_t l2[23];
+ int rv;
+ rv = xcch_decode(l2, bursts);
+
+ if (rv == 0)
+ {
+ uint8_t chan_type, chan_ts, chan_ss;
+ uint8_t gsmtap_chan_type;
+
+ /* Send to GSMTAP */
+ rsl_dec_chan_nr(bi->chan_nr, &chan_type, &chan_ss, &chan_ts);
+ gsmtap_chan_type = chantype_rsl2gsmtap(
+ chan_type,
+ bi->flags & BI_FLG_SACCH ? 0x40 : 0x00
+ );
+ gsmtap_send(gsmtap_inst,
+ arfcn, chan_ts, gsmtap_chan_type, chan_ss,
+ ntohl(bi->frame_nr), bi->rx_level, bi->snr,
+ l2, sizeof(l2)
+ );
+
+ /* Crude CIPH.MOD.COMMAND detect */
+ if ((l2[3] == 0x06) && (l2[4] == 0x35) && (l2[5] & 1))
+ app_state.dch_ciph = 1 + ((l2[5] >> 1) & 7);
+ }
+ }
+}
+
+static char *
+gen_filename(struct osmocom_ms *ms, struct l1ctl_burst_ind *bi)
+{
+ static char buffer[256];
+ time_t d;
+ struct tm lt;
+
+ time(&d);
+ localtime_r(&d, &lt);
+
+ snprintf(buffer, 256, "bursts_%04d%02d%02d_%02d%02d_%d_%d_%02x.dat",
+ lt.tm_year + 1900, lt.tm_mon, lt.tm_mday,
+ lt.tm_hour, lt.tm_min,
+ ms->test_arfcn,
+ ntohl(bi->frame_nr),
+ bi->chan_nr
+ );
+
+ return buffer;
+}
+
+void layer3_rx_burst(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct l1ctl_burst_ind *bi;
+ int16_t rx_dbm;
+ uint16_t arfcn;
+ int ul, do_rel=0;
+
+ /* Header handling */
+ bi = (struct l1ctl_burst_ind *) msg->l1h;
+
+ arfcn = ntohs(bi->band_arfcn);
+ rx_dbm = rxlev2dbm(bi->rx_level);
+ ul = !!(arfcn & ARFCN_UPLINK);
+
+ /* Check for channel start */
+ if (app_state.dch_state == DCH_WAIT_EST) {
+ if (bi->chan_nr == app_state.dch_nr) {
+ if (bi->snr > 64) {
+ /* Change state */
+ app_state.dch_state = DCH_ACTIVE;
+ app_state.dch_badcnt = 0;
+
+ /* Open output */
+ app_state.fh = fopen(gen_filename(ms, bi), "wb");
+ } else {
+ /* Abandon ? */
+ do_rel = (app_state.dch_badcnt++) >= 4;
+ }
+ }
+ }
+
+ /* Check for channel end */
+ if (app_state.dch_state == DCH_ACTIVE) {
+ if (!ul) {
+ /* Bad burst counting */
+ if (bi->snr < 64)
+ app_state.dch_badcnt++;
+ else if (app_state.dch_badcnt >= 2)
+ app_state.dch_badcnt -= 2;
+ else
+ app_state.dch_badcnt = 0;
+
+ /* Release condition */
+ do_rel = app_state.dch_badcnt >= 6;
+ }
+ }
+
+ /* Release ? */
+ if (do_rel) {
+ /* L1 release */
+ l1ctl_tx_dm_rel_req(ms);
+ l1ctl_tx_fbsb_req(ms, ms->test_arfcn,
+ L1CTL_FBSB_F_FB01SB, 100, 0,
+ app_state.ccch_mode);
+
+ /* Change state */
+ app_state.dch_state = DCH_WAIT_REL;
+ app_state.dch_badcnt = 0;
+ app_state.dch_ciph = 0;
+
+ /* Close output */
+ if (app_state.fh) {
+ fclose(app_state.fh);
+ app_state.fh = NULL;
+ }
+ }
+
+ /* Save the burst */
+ if (app_state.dch_state == DCH_ACTIVE)
+ fwrite(bi, sizeof(*bi), 1, app_state.fh);
+
+ /* Try local decoding */
+ if (app_state.dch_state == DCH_ACTIVE)
+ local_burst_decode(bi);
+}
+
+void layer3_app_reset(void)
+{
+ /* Reset state */
+ app_state.has_si1 = 0;
+ app_state.ccch_mode = CCCH_MODE_NONE;
+ app_state.dch_state = DCH_NONE;
+ app_state.dch_badcnt = 0;
+ app_state.dch_ciph = 0;
+
+ if (app_state.fh)
+ fclose(app_state.fh);
+ app_state.fh = NULL;
+
+ memset(&app_state.cell_arfcns, 0x00, sizeof(app_state.cell_arfcns));
+}
+
+static int signal_cb(unsigned int subsys, unsigned int signal,
+ void *handler_data, void *signal_data)
+{
+ struct osmocom_ms *ms;
+ struct osmobb_msg_ind *mi;
+
+ if (subsys != SS_L1CTL)
+ return 0;
+
+ switch (signal) {
+ case S_L1CTL_BURST_IND:
+ mi = signal_data;
+ layer3_rx_burst(mi->ms, mi->msg);
+ break;
+
+ case S_L1CTL_RESET:
+ ms = signal_data;
+ layer3_app_reset();
+ return l1ctl_tx_fbsb_req(ms, ms->test_arfcn,
+ L1CTL_FBSB_F_FB01SB, 100, 0,
+ CCCH_MODE_NONE);
+ break;
+ }
+ return 0;
+}
+
+
+int l23_app_init(struct osmocom_ms *ms)
+{
+ osmo_signal_register_handler(SS_L1CTL, &signal_cb, NULL);
+ l1ctl_tx_reset_req(ms, L1CTL_RES_T_FULL);
+ return layer3_init(ms);
+}
+
+static int l23_cfg_supported()
+{
+ return L23_OPT_TAP | L23_OPT_DBG;
+}
+
+static int l23_getopt_options(struct option **options)
+{
+ static struct option opts [] = {
+ {"kc", 1, 0, 'k'},
+ };
+
+ *options = opts;
+ return ARRAY_SIZE(opts);
+}
+
+static int l23_cfg_print_help()
+{
+ printf("\nApplication specific\n");
+ printf(" -k --kc KEY Key to use to try to decipher DCCHs\n");
+
+ return 0;
+}
+
+static int l23_cfg_handle(int c, const char *optarg)
+{
+ switch (c) {
+ case 'k':
+ if (osmo_hexparse(optarg, app_state.kc, 8) != 8) {
+ fprintf(stderr, "Invalid Kc\n");
+ exit(-1);
+ }
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static struct l23_app_info info = {
+ .copyright = "Copyright (C) 2010 Harald Welte <laforge@gnumonks.org>\n",
+ .contribution = "Contributions by Holger Hans Peter Freyther\n",
+ .getopt_string = "k:",
+ .cfg_supported = l23_cfg_supported,
+ .cfg_getopt_opt = l23_getopt_options,
+ .cfg_handle_opt = l23_cfg_handle,
+ .cfg_print_help = l23_cfg_print_help,
+};
+
+struct l23_app_info *l23_app_info()
+{
+ return &info;
+}