From 818bd7c053bb9c17f323134a244e6822fa02b99f Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 21 May 2012 18:30:02 +0200 Subject: added sections on paging and paging feature in c code, lot of minor changes in tex files --- Src/osmolib/src/host/layer23/src/misc/Makefile.am | 3 +- Src/osmolib/src/host/layer23/src/misc/enc_scan | Bin 0 -> 896781 bytes Src/osmolib/src/host/layer23/src/misc/enc_scan.c | 556 +++++++++++++++ .../src/host/layer23/src/misc/enc_scan_old.c | 785 +++++++++++++++++++++ 4 files changed, 1343 insertions(+), 1 deletion(-) create mode 100755 Src/osmolib/src/host/layer23/src/misc/enc_scan create mode 100644 Src/osmolib/src/host/layer23/src/misc/enc_scan.c create mode 100644 Src/osmolib/src/host/layer23/src/misc/enc_scan_old.c (limited to 'Src/osmolib/src') 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 Binary files /dev/null and b/Src/osmolib/src/host/layer23/src/misc/enc_scan 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 + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +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 \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 + * + * 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 +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +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, <); + + 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 \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; +} -- cgit v1.2.3-55-g7522