diff options
author | Luca Melette <luca@srlabs.de> | 2012-01-24 19:52:30 +0100 |
---|---|---|
committer | Luca Melette <luca@srlabs.de> | 2012-01-24 19:52:30 +0100 |
commit | ac07dfab60e4eb562e7df0782745f0cd074aa54f (patch) | |
tree | 1a696a49de31edc786690b3df89afe186c09ed32 | |
parent | 9dd1f00e836044d9378350882e54c8c7442b3e60 (diff) |
Code from cell_log patch v2, plus minor fixes
43 files changed, 2180 insertions, 427 deletions
diff --git a/include/l1ctl_proto.h b/include/l1ctl_proto.h index c1220d60..a4cbf55b 100644 --- a/include/l1ctl_proto.h +++ b/include/l1ctl_proto.h @@ -56,6 +56,7 @@ enum { L1CTL_TRAFFIC_REQ, L1CTL_TRAFFIC_CONF, L1CTL_TRAFFIC_IND, + L1CTL_BURST_IND, }; enum ccch_mode { @@ -139,6 +140,20 @@ struct l1ctl_traffic_ind { uint8_t data[TRAFFIC_DATA_LEN]; } __attribute__((packed)); +/* raw burst data. This is following the header */ +#define BI_FLG_DUMMY (1<<4) +#define BI_FLG_SACCH (1<<5) + +struct l1ctl_burst_ind { + uint32_t frame_nr; + uint16_t band_arfcn; /* ARFCN + band + ul indicator */ + uint8_t chan_nr; /* GSM 08.58 channel number (9.3.1) */ + uint8_t flags; /* BI_FLG_xxx + burst_id = 2LSBs */ + uint8_t rx_level; /* 0 .. 63 in typical GSM notation (dBm+110) */ + uint8_t snr; /* Reported SNR >> 8 (0-255) */ + uint8_t bits[15]; /* 114 bits + 2 steal bits. Filled MSB first */ +} __attribute__((packed)); + /* * uplink info */ diff --git a/pre-built/compal_e86.bin b/pre-built/compal_e86.bin Binary files differnew file mode 100755 index 00000000..ea8c6870 --- /dev/null +++ b/pre-built/compal_e86.bin diff --git a/pre-built/compal_e88.bin b/pre-built/compal_e88.bin Binary files differnew file mode 100755 index 00000000..c19f9fd3 --- /dev/null +++ b/pre-built/compal_e88.bin diff --git a/pre-built/compal_e99.bin b/pre-built/compal_e99.bin Binary files differnew file mode 100755 index 00000000..94f0583c --- /dev/null +++ b/pre-built/compal_e99.bin diff --git a/pre-built/gta0x.bin b/pre-built/gta0x.bin Binary files differnew file mode 100755 index 00000000..11c1fe4e --- /dev/null +++ b/pre-built/gta0x.bin diff --git a/pre-built/pirelli.bin b/pre-built/pirelli.bin Binary files differnew file mode 100755 index 00000000..caa3956b --- /dev/null +++ b/pre-built/pirelli.bin diff --git a/pre-built/se_j100.bin b/pre-built/se_j100.bin Binary files differnew file mode 100755 index 00000000..2b433694 --- /dev/null +++ b/pre-built/se_j100.bin diff --git a/src/host/layer23/include/osmocom/bb/common/osmocom_data.h b/src/host/layer23/include/osmocom/bb/common/osmocom_data.h index ab7c2502..7cec8575 100644 --- a/src/host/layer23/include/osmocom/bb/common/osmocom_data.h +++ b/src/host/layer23/include/osmocom/bb/common/osmocom_data.h @@ -92,6 +92,7 @@ enum osmobb_l1ctl_sig { S_L1CTL_TCH_MODE_CONF, S_L1CTL_LOSS_IND, S_L1CTL_NEIGH_PM_IND, + S_L1CTL_BURST_IND, }; enum osmobb_global_sig { @@ -128,4 +129,9 @@ struct osmobb_neigh_pm_ind { uint8_t rx_lev; }; +struct osmobb_msg_ind { + struct osmocom_ms *ms; + struct msgb *msg; +}; + #endif diff --git a/src/host/layer23/include/osmocom/bb/misc/xcch.h b/src/host/layer23/include/osmocom/bb/misc/xcch.h new file mode 100644 index 00000000..9fe42957 --- /dev/null +++ b/src/host/layer23/include/osmocom/bb/misc/xcch.h @@ -0,0 +1,15 @@ +/* + * xcch.h + * + * Copyright (c) 2011 Sylvain Munaut <tnt@246tNt.com> + */ + +#ifndef __XCCH_H__ +#define __XCCH_H__ + +#include <stdint.h> +#include <osmocom/core/bits.h> + +int xcch_decode(uint8_t *l2_data, sbit_t *bursts); + +#endif /* __XCCH_H__ */ diff --git a/src/host/layer23/src/common/l1ctl.c b/src/host/layer23/src/common/l1ctl.c index f998ebcf..b5888bd6 100644 --- a/src/host/layer23/src/common/l1ctl.c +++ b/src/host/layer23/src/common/l1ctl.c @@ -237,6 +237,7 @@ 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); msgb_free(msg); + osmo_signal_dispatch(SS_L1CTL, S_L1CTL_LOSS_IND, ms); return 0; } @@ -265,6 +266,41 @@ printf("Dropping frame with %u bit errors\n", dl->num_biterr); return lapdm_phsap_up(&pp.oph, le); } +/* Receive L1CTL_BURST_IND (Data Indication from L1) */ +static int rx_ph_burst_ind(struct osmocom_ms *ms, struct msgb *msg) +{ + struct l1ctl_burst_ind *bi; + struct osmobb_msg_ind mi; + uint8_t chan_type, chan_ts, chan_ss; + struct gsm_time rx_time; + uint16_t arfcn; + + /* Header handling */ + bi = (struct l1ctl_burst_ind *) msg->l1h; + + rsl_dec_chan_nr(bi->chan_nr, &chan_type, &chan_ss, &chan_ts); + gsm_fn2gsmtime(&rx_time, ntohl(bi->frame_nr)); + arfcn = ntohs(bi->band_arfcn); + + /* Debug print */ + LOGP(DL1C, LOGL_NOTICE, "BURST IND: @(%6d = %.4u/%.2u/%.2u) (%4d dBm, SNR %3d%s%s)\n", + rx_time.fn, rx_time.t1, rx_time.t2, rx_time.t3, + (int)bi->rx_level-110, bi->snr, + arfcn & ARFCN_UPLINK ? ", UL" : "", + bi->flags & BI_FLG_SACCH ? ", SACCH" : "" + ); + + /* Dispatch signal !HACK! */ + mi.ms = ms; + mi.msg = msg; + osmo_signal_dispatch(SS_L1CTL, S_L1CTL_BURST_IND, &mi); + + /* Done with the message */ + msgb_free(msg); + + return 0; +} + /* Receive L1CTL_DATA_CONF (Data Confirm from L1) */ static int rx_ph_data_conf(struct osmocom_ms *ms, struct msgb *msg) { @@ -917,6 +953,9 @@ int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg) case L1CTL_DATA_IND: rc = rx_ph_data_ind(ms, msg); break; + case L1CTL_BURST_IND: + rc = rx_ph_burst_ind(ms, msg); + break; case L1CTL_DATA_CONF: rc = rx_ph_data_conf(ms, msg); break; diff --git a/src/host/layer23/src/common/main.c b/src/host/layer23/src/common/main.c index eb47b262..e1badb01 100644 --- a/src/host/layer23/src/common/main.c +++ b/src/host/layer23/src/common/main.c @@ -51,7 +51,7 @@ struct log_target *stderr_target; void *l23_ctx = NULL; -static char *layer2_socket_path = "/tmp/osmocom_l2"; +static char *layer2_socket_path = "/tmp/osmocom_log"; static char *sap_socket_path = "/tmp/osmocom_sap"; struct llist_head ms_list; static struct osmocom_ms *ms = NULL; diff --git a/src/host/layer23/src/misc/Makefile.am b/src/host/layer23/src/misc/Makefile.am index 0b59f389..ab22c4fe 100644 --- a/src/host/layer23/src/misc/Makefile.am +++ b/src/host/layer23/src/misc/Makefile.am @@ -2,12 +2,10 @@ 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 cbch_sniff +bin_PROGRAMS = bcch_scan ccch_scan cell_log 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 +ccch_scan_SOURCES = ../common/main.c app_ccch_scan.c rslms.c xcch.c cell_log_LDADD = $(LDADD) -lm cell_log_SOURCES = ../common/main.c app_cell_log.c cell_log.c \ ../../../gsmmap/geo.c -cbch_sniff_SOURCES = ../common/main.c app_cbch_sniff.c diff --git a/src/host/layer23/src/misc/app_ccch_scan.c b/src/host/layer23/src/misc/app_ccch_scan.c index d301b7b7..494df5b6 100644 --- a/src/host/layer23/src/misc/app_ccch_scan.c +++ b/src/host/layer23/src/misc/app_ccch_scan.c @@ -1,4 +1,3 @@ -/* CCCH passive sniffer */ /* (C) 2010-2011 by Holger Hans Peter Freyther * (C) 2010 by Harald Welte <laforge@gnumonks.org> * @@ -23,6 +22,12 @@ #include <stdint.h> #include <errno.h> #include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include <getopt.h> + +#include <arpa/inet.h> #include <osmocom/core/msgb.h> #include <osmocom/gsm/rsl.h> @@ -31,6 +36,9 @@ #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> @@ -41,27 +49,70 @@ #include <l1ctl_proto.h> +#include <osmocom/bb/misc/xcch.h> + +#include "cellid.c" +#include "assignment.c" + +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; - int ccch_enabled; - int rach_count; - struct gsm_sysinfo_freq cell_arfcns[1024]; + int has_si1; + int has_si3; + int ccch_mode; + + enum dch_state_t dch_state; + uint8_t dch_nr; + int dch_badcnt; + int dch_ciph; + + FILE * fh; + struct osmocom_ms *ms; + + int sniffing; + + sbit_t bursts_dl[116 * 4]; + sbit_t bursts_ul[116 * 4]; + + struct gsm_sysinfo_freq cell_arfcns[1024]; + + uint8_t kc[8]; + uint8_t wanted_tmsi[4]; + uint8_t tmsi_matched; } app_state; +inline int not_zero(uint8_t *t, unsigned size) +{ + unsigned i; + + for (i=0; i<size; i++) { + if (t[i]) + break; + } + + if (i == size) + return 0; + else + return 1; +} 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; + struct gsm48_system_information_type_3 *si3 = + (struct gsm48_system_information_type_3 *) 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; @@ -76,16 +127,8 @@ static void dump_bcch(struct osmocom_ms *ms, uint8_t tc, const uint8_t *data) } 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; @@ -97,64 +140,36 @@ static void dump_bcch(struct osmocom_ms *ms, uint8_t tc, const uint8_t *data) l1ctl_tx_ccch_mode_req(ms, app_state.ccch_mode); } + + if (!app_state.has_si3) { + set_cid(si3->lai.digits, si3->lai.lac, si3->cell_identity); + LOGP(DRR, LOGL_ERROR, "SI3 received.\n"); + app_state.has_si3 = 1; + } 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_2quater: break; case GSM48_MT_RR_SYSINFO_5bis: break; @@ -167,66 +182,100 @@ static void dump_bcch(struct osmocom_ms *ms, uint8_t tc, const uint8_t *data) }; } - -/** - * 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) +void parse_chandesc(struct gsm48_chan_desc *chan_desc, + uint8_t mob_alloc_len, + const uint8_t *mob_alloc, + struct gsm_assignment *ga) { - struct gsm48_imm_ass *ia = msgb_l3(msg); - uint8_t ch_type, ch_subch, ch_ts; - - /* Discard packet TBF assignement */ - if (ia->page_mode & 0xf0) - return 0; - - /* FIXME: compare RA and GSM time with when we sent RACH req */ + ga->chan_nr = chan_desc->chan_nr; + ga->h = chan_desc->h0.h; - rsl_dec_chan_nr(ia->chan_desc.chan_nr, &ch_type, &ch_subch, &ch_ts); - - if (!ia->chan_desc.h0.h) { + if (!ga->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); - + ga->tsc = chan_desc->h0.tsc; + ga->h0.band_arfcn = chan_desc->h0.arfcn_low | (chan_desc->h0.arfcn_high << 8); } else { /* Hopping */ - uint8_t maio, hsn, ma_len; - uint16_t ma[64], arfcn; + uint16_t 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); + ga->tsc = chan_desc->h1.tsc; + ga->h1.hsn = chan_desc->h1.hsn; + ga->h1.maio = chan_desc->h1.maio_low | (chan_desc->h1.maio_high << 2); /* decode mobile allocation */ - ma_len = 0; + ga->h1.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; + k = mob_alloc_len - (j>>3) - 1; + if (mob_alloc[k] & (1 << (j&7))) { + ga->h1.ma[ga->h1.ma_len++] = arfcn; } j++; } } } +} - LOGPC(DRR, LOGL_NOTICE, "\n"); - return 0; +void follow_assignment(struct osmocom_ms *ms, struct gsm_assignment *ga) +{ + /* Set state */ + app_state.dch_state = DCH_WAIT_EST; + app_state.dch_nr = ga->chan_nr; + app_state.dch_badcnt = 0; + + /* Tune to new channel */ + if (!ga->h) { + l1ctl_tx_dm_est_req_h0(ms, + ga->h0.band_arfcn, ga->chan_nr, ga->tsc, + GSM48_CMODE_SIGN, 0); + } else { + l1ctl_tx_dm_est_req_h1(ms, + ga->h1.maio, ga->h1.hsn, ga->h1.ma, ga->h1.ma_len, + ga->chan_nr, ga->tsc, + GSM48_CMODE_SIGN, 0); + } +} + +void gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms) +{ + struct gsm48_imm_ass *ia = msgb_l3(msg); + struct gsm_assignment ga; + + if (app_state.sniffing) + return; + + /* only our tmsi */ + if (!app_state.tmsi_matched && not_zero(app_state.wanted_tmsi, 4)) + return; + + /* Discard packet TBF assignement */ + if (ia->page_mode & 0xf0) + return; + + /* If we're not ready yet, or just busy ... */ + if ((!(app_state.has_si1 && app_state.has_si3)) || (app_state.dch_state != DCH_NONE)) + return; + + parse_chandesc(&ia->chan_desc, ia->mob_alloc_len, ia->mob_alloc, &ga); + + follow_assignment(ms, &ga); +} + +void gsm48_rx_imm_ass_ext(struct msgb *msg, struct osmocom_ms *ms) +{ + struct gsm48_imm_ass_ext *iae = msgb_l3(msg); + struct gsm_assignment ga; + + printf("EXT!!!\n"); + fflush(stdout); + + /* First */ + parse_chandesc(&iae->chan_desc1, iae->mob_alloc_len, iae->mob_alloc, &ga); + + /* Second */ + parse_chandesc(&iae->chan_desc2, iae->mob_alloc_len, iae->mob_alloc, &ga); } static const char *pag_print_mode(int mode) @@ -235,7 +284,7 @@ static const char *pag_print_mode(int mode) case 0: return "Normal paging"; case 1: - return "Extended paging"; + return "Ext.ed paging"; case 2: return "Paging reorganization"; case 3: @@ -249,9 +298,9 @@ static char *chan_need(int need) { switch (need) { case 0: - return "any"; + return "any "; case 1: - return "sdch"; + return "sdch "; case 2: return "tch/f"; case 3: @@ -267,18 +316,25 @@ static char *mi_type_to_string(int type) case GSM_MI_TYPE_NONE: return "none"; case GSM_MI_TYPE_IMSI: - return "imsi"; + return "IMSI"; case GSM_MI_TYPE_IMEI: - return "imei"; + return "IMEI"; case GSM_MI_TYPE_IMEISV: - return "imeisv"; + return "IMEISV"; case GSM_MI_TYPE_TMSI: - return "tmsi"; + return "TMSI"; default: return "invalid"; } } +void tmsi_match(uint8_t *t) +{ + if(!memcmp(t, app_state.wanted_tmsi, 4)) { + app_state.tmsi_matched = 1; + } +} + /** * This can contain two MIs. The size checking is a bit of a mess. */ @@ -310,6 +366,7 @@ static int gsm48_rx_paging_p1(struct msgb *msg, struct osmocom_ms *ms) chan_need(pag->cneed1), mi_type_to_string(mi_type), mi_string); + tmsi_match(&pag->data[2]); } /* check if we have a MI type in here */ @@ -326,11 +383,12 @@ static int gsm48_rx_paging_p1(struct msgb *msg, struct osmocom_ms *ms) } 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", + LOGP(DRR, LOGL_NOTICE, "Paging1: %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); + tmsi_match(&pag->data[2 + len1 + 3]); } return 0; } @@ -347,12 +405,15 @@ static int gsm48_rx_paging_p2(struct msgb *msg, struct osmocom_ms *ms) } pag = msgb_l3(msg); - LOGP(DRR, LOGL_NOTICE, "Paging1: %s chan %s to TMSI M(0x%x) \n", + LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to TMSI M(%u) \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", + chan_need(pag->cneed1), ntohl(pag->tmsi1)); + tmsi_match((uint8_t *)&pag->tmsi1); + + LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to TMSI M(%u) \n", pag_print_mode(pag->pag_mode), - chan_need(pag->cneed2), pag->tmsi2); + chan_need(pag->cneed1), ntohl(pag->tmsi2)); + tmsi_match((uint8_t *)&pag->tmsi2); /* no optional element */ if (msgb_l3len(msg) < sizeof(*pag) + 3) @@ -371,11 +432,12 @@ static int gsm48_rx_paging_p2(struct msgb *msg, struct osmocom_ms *ms) } 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", + LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to %s M(%s) \n", pag_print_mode(pag->pag_mode), - "n/a ", + "n/a ", mi_type_to_string(mi_type), mi_string); + tmsi_match(&pag->data[3]); return 0; } @@ -390,29 +452,151 @@ static int gsm48_rx_paging_p3(struct msgb *msg, struct osmocom_ms *ms) } pag = msgb_l3(msg); - LOGP(DRR, LOGL_NOTICE, "Paging1: %s chan %s to TMSI M(0x%x) \n", + LOGP(DRR, LOGL_NOTICE, "Paging3: %s chan %s to TMSI M(%u) \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", + chan_need(pag->cneed1), ntohl(pag->tmsi1)); + tmsi_match((uint8_t *)&pag->tmsi1); + + LOGP(DRR, LOGL_NOTICE, "Paging3: %s chan %s to TMSI M(%u) \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", + chan_need(pag->cneed1), ntohl(pag->tmsi2)); + tmsi_match((uint8_t *)&pag->tmsi2); + + LOGP(DRR, LOGL_NOTICE, "Paging3: %s chan %s to TMSI M(%u) \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", + chan_need(pag->cneed3), ntohl(pag->tmsi3)); + tmsi_match((uint8_t *)&pag->tmsi3); + + LOGP(DRR, LOGL_NOTICE, "Paging3: %s chan %s to TMSI M(%u) \n", pag_print_mode(pag->pag_mode), - "n/a ", pag->tmsi4); + chan_need(pag->cneed4), ntohl(pag->tmsi4)); + tmsi_match((uint8_t *)&pag->tmsi4); return 0; } +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, "%s_%04d%02d%02d_%02d%02d_%d_%d_%02x.dat", + get_cid_str(), + 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; + uint16_t arfcn; + int ul, do_rel=0; + + /* Header handling */ + bi = (struct l1ctl_burst_ind *) msg->l1h; + + arfcn = ntohs(bi->band_arfcn); + 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; + app_state.tmsi_matched = 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 */ + if (app_state.dch_nr < 0x20) + do_rel = app_state.dch_badcnt >= 100; + else + do_rel = app_state.dch_badcnt >= 6; + } + } + + /* Save the burst and try decoding */ + if (app_state.dch_state == DCH_ACTIVE) { + local_burst_decode(bi); + fwrite(bi, sizeof(*bi), 1, app_state.fh); + } + + /* Release ? */ + if (do_rel) { + /* L1 release */ + l1ctl_tx_dm_rel_req(ms); + + /* tune back to BCCH */ + 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; + } + + /* proceed only on correct TMSI */ + if (not_zero(app_state.wanted_tmsi, 4) && !app_state.tmsi_matched) + return; + + /* reset TMSI match */ + app_state.tmsi_matched = 0; + + /* releasing everything */ + app_state.sniffing = 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"); + /* 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) { + return 0; + } switch (sih->system_information) { case GSM48_MT_RR_PAG_REQ_1: @@ -427,6 +611,9 @@ int gsm48_rx_ccch(struct msgb *msg, struct osmocom_ms *ms) case GSM48_MT_RR_IMM_ASS: gsm48_rx_imm_ass(msg, ms); break; + case GSM48_MT_RR_IMM_ASS_EXT: + gsm48_rx_imm_ass_ext(msg, ms); + break; case GSM48_MT_RR_NOTIF_NCH: /* notification for voice call groups and such */ break; @@ -444,48 +631,185 @@ int gsm48_rx_ccch(struct msgb *msg, struct osmocom_ms *ms) 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); - /* 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 local_burst_decode(struct l1ctl_burst_ind *bi) +{ + 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); + + 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; } - return 0; + 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); + } + } } void layer3_app_reset(void) { /* Reset state */ app_state.has_si1 = 0; + app_state.has_si3 = 0; app_state.ccch_mode = CCCH_MODE_NONE; - app_state.ccch_enabled = 0; - app_state.rach_count = 0; + app_state.dch_state = DCH_NONE; + app_state.dch_badcnt = 0; + app_state.dch_ciph = 0; + app_state.sniffing = 0; + app_state.tmsi_matched = 0; + + if (app_state.fh) + fclose(app_state.fh); + app_state.fh = NULL; memset(&app_state.cell_arfcns, 0x00, sizeof(app_state.cell_arfcns)); + + reset_cid(); } 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; + static unsigned loss_count = 0; if (subsys != SS_L1CTL) return 0; switch (signal) { + case S_L1CTL_BURST_IND: + mi = signal_data; + loss_count = 0; + layer3_rx_burst(mi->ms, mi->msg); + break; + case S_L1CTL_RESET: + loss_count = 0; 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; + + case S_L1CTL_FBSB_RESP: + loss_count = 0; + break; + + case S_L1CTL_FBSB_ERR: + layer3_app_reset(); + sleep(1); + return l1ctl_tx_fbsb_req(app_state.ms, app_state.ms->test_arfcn, + L1CTL_FBSB_F_FB01SB, 100, 0, + CCCH_MODE_NONE); + break; + case S_L1CTL_LOSS_IND: + loss_count++; + if (loss_count > 10) { + loss_count = 0; + layer3_app_reset(); + return l1ctl_tx_fbsb_req(app_state.ms, app_state.ms->test_arfcn, + L1CTL_FBSB_F_FB01SB, 100, 0, + CCCH_MODE_NONE); + } + break; } return 0; } @@ -495,12 +819,63 @@ 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); + app_state.ms = ms; 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 [] = { + {"tmsi", 1, 0, 't'}, + }; + + *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"); + printf(" -t --tmsi TMSI Filter assignments with specified TMSI (paging only)\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; + case 't': + if (osmo_hexparse(optarg, app_state.wanted_tmsi, 4) != 4) { + fprintf(stderr, "Invalid TMSI\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:t:", + .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() diff --git a/src/host/layer23/src/misc/app_cell_log.c b/src/host/layer23/src/misc/app_cell_log.c index 27290be7..0456a4b8 100644 --- a/src/host/layer23/src/misc/app_cell_log.c +++ b/src/host/layer23/src/misc/app_cell_log.c @@ -40,8 +40,12 @@ extern struct log_target *stderr_target; extern void *l23_ctx; -char *logname = "/var/log/osmocom.log"; +char *logname = "./osmocom.log"; int RACH_MAX = 2; +char *scan_band = 0; +int wait_time = 300; +int log_gprs = 0; +int scan_only = 0; int _scan_work(struct osmocom_ms *ms) { @@ -99,7 +103,11 @@ static int l23_getopt_options(struct option **options) {"gpsd-port", 1, 0, 'p'}, #endif {"gps", 1, 0, 'g'}, - {"baud", 1, 0, 'b'} + {"baud", 1, 0, 'b'}, + {"band", 1, 0, 'B'}, + {"log-gprs", 0, 0, 'G'}, + {"only-scan", 0, 0, 'O'}, + {"wait-time", 1, 0, 'w'} }; *options = opts; @@ -116,6 +124,10 @@ static int l23_cfg_print_help() printf(" -p --port PORT 2947. gpsd port\n"); printf(" -f --gps DEVICE /dev/ttyACM0. GPS serial device.\n"); printf(" -b --baud BAUDRAT The baud rate of the GPS device\n"); + printf(" -B --band BAND Select scan band, one of: all (default), 900, 1800, 850, 1900.\n"); + printf(" -G --log-gprs Log some GPRS if available\n"); + printf(" -O --only-scan Do a scan and show available ARFCNs, no data logging\n"); + printf(" -w --wait-time TIME Time to wait in each cell\n"); return 0; } @@ -172,6 +184,18 @@ static int l23_cfg_handle(int c, const char *optarg) g.gps_type = GPS_TYPE_SERIAL; LOGP(DGPS, LOGL_INFO, "Setting GPS baudrate to %u\n", g.baud); break; + case 'B': + scan_band = strdup(optarg); + break; + case 'G': + log_gprs = 1; + break; + case 'O': + scan_only = 1; + break; + case 'w': + wait_time = atoi(optarg); + break; } return 0; @@ -182,7 +206,7 @@ cmd_line_error: static struct l23_app_info info = { .copyright = "Copyright (C) 2010 Andreas Eversberg\n", - .getopt_string = "g:p:l:r:nf:b:", + .getopt_string = "g:p:l:r:nf:b:B:w:GO", .cfg_supported = l23_cfg_supported, .cfg_getopt_opt = l23_getopt_options, .cfg_handle_opt = l23_cfg_handle, diff --git a/src/host/layer23/src/misc/arfcn_sort b/src/host/layer23/src/misc/arfcn_sort new file mode 100755 index 00000000..4d437d59 --- /dev/null +++ b/src/host/layer23/src/misc/arfcn_sort @@ -0,0 +1,5 @@ +#!/bin/bash +for arfcn in `ls *.dat|cut -f7 -d_|sort -g|uniq`; do + mkdir -p $arfcn; + mv *_${arfcn}_* $arfcn; +done diff --git a/src/host/layer23/src/misc/assignment.c b/src/host/layer23/src/misc/assignment.c new file mode 100644 index 00000000..65122262 --- /dev/null +++ b/src/host/layer23/src/misc/assignment.c @@ -0,0 +1,150 @@ +#include <osmocom/gsm/rsl.h> +#include <osmocom/gsm/tlv.h> +#include <osmocom/gsm/gsm48.h> +#include <osmocom/gsm/gsm48_ie.h> +#include <osmocom/gsm/protocol/gsm_04_08.h> + +#include "assignment.h" + +void parse_assignment(uint8_t *msg, unsigned len, struct gsm_sysinfo_freq *cell_arfcns, struct gsm_assignment *ga) +{ + struct gsm48_hdr *hdr; + struct gsm48_ass_cmd *ac; + struct gsm48_ho_cmd *hoc; + struct gsm48_chan_desc *cd; + int payload_len = 0; + uint8_t *payload_data; + struct tlv_parsed tp; + uint8_t *ma = 0; + uint8_t ma_len; + uint8_t ch_type, ch_subch, ch_ts; + unsigned i, mask; + + hdr = (struct gsm48_hdr *) msg; + + /* handover */ + if (hdr->msg_type == 0x2b) { + hoc = (struct gsm48_ho_cmd *) hdr->data; + cd = &hoc->chan_desc; + payload_len = len - 3 - sizeof(*hdr) - sizeof(*hoc); + payload_data = hoc->data; + } + + /* assignment */ + if (hdr->msg_type == 0x2e) { + ac = (struct gsm48_ass_cmd *) hdr->data; + cd = &ac->chan_desc; + payload_len = len - 3 - sizeof(*hdr) - sizeof(*ac); + payload_data = ac->data; + } + + if (!payload_len) + return; + + /* Parse TLV in the message */ + tlv_parse(&tp, &gsm48_rr_att_tlvdef, payload_data, payload_len, 0, 0); + + ma_len = 0; + ma = NULL; + mask = 0; + + /* Cell channel description */ + if (TLVP_PRESENT(&tp, GSM48_IE_CELL_CH_DESC)) { + const uint8_t *v = TLVP_VAL(&tp, GSM48_IE_CELL_CH_DESC); + uint8_t len = TLVP_LEN(&tp, GSM48_IE_CELL_CH_DESC); + gsm48_decode_freq_list(cell_arfcns, (uint8_t *) v, len, 0xff, 0x02); + mask = 0x02; + } else if (TLVP_PRESENT(&tp, GSM48_IE_MA_AFTER)) { + /* Mobile allocation */ + const uint8_t *v = TLVP_VAL(&tp, GSM48_IE_MA_AFTER); + uint8_t len = TLVP_LEN(&tp, GSM48_IE_MA_AFTER); + + ma_len = len; + ma = (uint8_t *) v; + mask = 0x01; + } else if (TLVP_PRESENT(&tp, GSM48_IE_FREQ_L_AFTER)) { + /* Frequency list after time */ + const uint8_t *v = TLVP_VAL(&tp, GSM48_IE_FREQ_L_AFTER); + uint8_t len = TLVP_LEN(&tp, GSM48_IE_FREQ_L_AFTER); + gsm48_decode_freq_list(cell_arfcns, (uint8_t *) v, len, 0xff, 0x04); + ma_len = 0; + ma = NULL; + mask = 0x04; + } else { + /* Use the old one */ + for (i=0; i<1024; i++) { + cell_arfcns[i].mask &= ~0x02; + if (cell_arfcns[i].mask & 0x01) { + cell_arfcns[i].mask |= 0x02; + mask = 0x02; + } + } + } + + /* Channel mode (HR/FR/EFR/AMR) */ + if (TLVP_PRESENT(&tp, GSM48_IE_CHANMODE_1)) { + const uint8_t *v = TLVP_VAL(&tp, GSM48_IE_CHANMODE_1); + //uint8_t len = TLVP_LEN(&tp, GSM48_IE_CHANMODE_1); + ga->chan_mode = v[0]; + } + + /* Multirate configuration */ + if (TLVP_PRESENT(&tp, GSM48_IE_MUL_RATE_CFG)) { + const uint8_t *v = TLVP_VAL(&tp, GSM48_IE_MUL_RATE_CFG); + //uint8_t len = TLVP_LEN(&tp, GSM48_IE_MUL_RATE_CFG); + ga->rate_conf = v[1]; + } + + rsl_dec_chan_nr(cd->chan_nr, &ch_type, &ch_subch, &ch_ts); + + ga->h = cd->h0.h; + ga->chan_nr = cd->chan_nr; + + if (!ga->h) { + /* Non-Hopping */ + uint16_t arfcn = cd->h0.arfcn_low | (cd->h0.arfcn_high << 8); + + ga->tsc = cd->h0.tsc; + ga->h0.band_arfcn = arfcn; + } else { + /* Hopping */ + uint16_t arfcn; + int i, j, k; + + ga->tsc = cd->h1.tsc; + ga->h1.maio = cd->h1.maio_low | (cd->h1.maio_high << 2);; + ga->h1.hsn = cd->h1.hsn; + + /* decode mobile allocation */ + if (ma) { + for (i=1, j=0; i<=1024; i++) { + arfcn = i & 1023; + if (cell_arfcns[arfcn].mask & mask) { + k = ma_len - (j>>3) - 1; + if (ma[k] & (1 << (j&7))) { + ga->h1.ma[ga->h1.ma_len++] = arfcn; + } + j++; + } + } + if (ga->h1.ma_len == 0) { + /* cell information not found */ + /* just compute ma_len */ + for (i=0; i<(ma_len*8); i++){ + int k = i/8; + + if (ma[k] & (1 << (i&7))) { + ga->h1.ma_len++; + } + } + } + } else { + for (i=1, j=0; i<=1024; i++) { + arfcn = i & 1023; + if (cell_arfcns[arfcn].mask & mask) { + ga->h1.ma[ga->h1.ma_len++] = arfcn; + } + } + } + } +} diff --git a/src/host/layer23/src/misc/assignment.h b/src/host/layer23/src/misc/assignment.h new file mode 100644 index 00000000..dfe40952 --- /dev/null +++ b/src/host/layer23/src/misc/assignment.h @@ -0,0 +1,28 @@ +#ifndef ASSIGNMENT_H +#define ASSIGNMENT_H + +#include <stdint.h> +#include <osmocom/gsm/gsm48_ie.h> + +struct gsm_assignment { + int chan_nr; + int tsc; + int h; + union { + struct { + int band_arfcn; + } h0; + struct { + int maio; + int hsn; + uint16_t ma[64]; + int ma_len; + } h1; + }; + int chan_mode; + int rate_conf; +}; + +void parse_assignment(uint8_t *msg, unsigned len, struct gsm_sysinfo_freq *cell_arfcns, struct gsm_assignment *ga); + +#endif diff --git a/src/host/layer23/src/misc/cell_log.c b/src/host/layer23/src/misc/cell_log.c index aa964f48..32d295dd 100644 --- a/src/host/layer23/src/misc/cell_log.c +++ b/src/host/layer23/src/misc/cell_log.c @@ -45,10 +45,19 @@ #include <osmocom/bb/misc/cell_log.h> #include "../../../gsmmap/geo.h" -#define READ_WAIT 2, 0 +#define READ_WAIT 5, 0 +#define IMM_WAIT 60, 0 #define RACH_WAIT 0, 900000 -#define MIN_RXLEV -106 +#define MIN_RXLEV -90 #define MAX_DIST 2000 +#define NUM_SYSINFO 30 + +extern int wait_time; +extern int log_gprs; +extern int scan_only; +extern char *scan_band; + +#include "cellid.c" enum { SCAN_STATE_PM, @@ -58,7 +67,12 @@ enum { }; /* ranges of bands */ -static uint16_t band_range[][2] = {{0, 124}, {512, 885}, {955, 1023}, {0, 0}}; +static uint16_t *band_range = 0; +static uint16_t range_all[] = {0, 124, 128, 251, 512, 885, 955, 1023, 0, 0}; +static uint16_t range_900[] = {0, 124, 955, 1023, 0, 0}; +static uint16_t range_1800[] = {512, 885, 0, 0}; +static uint16_t range_850[] = {128, 251, 0, 0}; +static uint16_t range_1900[] = {512|ARFCN_PCS, 810|ARFCN_PCS, 0, 0}; #define INFO_FLG_PM 1 #define INFO_FLG_SYNC 2 @@ -77,10 +91,36 @@ static struct pm_info { int8_t rxlev; } pm[1024]; +enum dch_state_t { + DCH_NONE, + DCH_WAIT_EST, + DCH_ACTIVE, + DCH_WAIT_REL, +}; + +static struct { + uint8_t * si[NUM_SYSINFO]; + int ccch_mode; + + enum dch_state_t dch_state; + uint8_t dch_nr; + int dch_badcnt; + + FILE * fh; + + struct gsm_sysinfo_freq cell_arfcns[1024]; +} app_state; + +static int sdcch = 0; +static int got_data = 0; +static int stop_raw = 0; +static int collecting = 0; +static int short_count; static int started = 0; static int state; static int8_t min_rxlev = MIN_RXLEV; static int sync_count; +static int sync_retry; static int pm_index, pm_gps_valid; static double pm_gps_x, pm_gps_y, pm_gps_z; static int arfcn; @@ -116,6 +156,8 @@ static void start_sync(void); static void start_rach(void); static void start_pm(void); +static int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms); + static void log_gps(void) { if (!g.enable || !g.valid) @@ -185,8 +227,9 @@ static void log_sysinfo(void) if (log_si.ta != 0xff) sprintf(ta_str, " TA=%d", log_si.ta); - LOGP(DSUM, LOGL_INFO, "Cell: ARFCN=%d MCC=%s MNC=%s (%s, %s)%s\n", - arfcn, gsm_print_mcc(s->mcc), gsm_print_mnc(s->mnc), + rxlev = meas->rxlev / meas->frames - 110; + LOGP(DSUM, LOGL_INFO, "Cell: ARFCN=%d PWR=%ddB MCC=%s MNC=%s (%s, %s)%s\n", + arfcn, rxlev, gsm_print_mcc(s->mcc), gsm_print_mnc(s->mnc), gsm_get_mcc(s->mcc), gsm_get_mnc(s->mcc, s->mnc), ta_str); LOGFILE("[sysinfo]\n"); @@ -194,8 +237,8 @@ static void log_sysinfo(void) log_time(); log_gps(); LOGFILE("bsic %d,%d\n", s->bsic >> 3, s->bsic & 7); - rxlev = meas->rxlev / meas->frames - 110; LOGFILE("rxlev %d\n", rxlev); + LOGFILE("mcc %s mnc %s\n", gsm_print_mcc(s->mcc), gsm_print_mnc(s->mnc)); if (s->si1) log_frame("si1", s->si1_msg); if (s->si2) @@ -217,9 +260,13 @@ static void log_sysinfo(void) static void timeout_cb(void *arg) { + if (sdcch) { + stop_raw = 1; + } switch (state) { case SCAN_STATE_READ: LOGP(DRR, LOGL_INFO, "Timeout reading BCCH\n"); + printf("Timeout\n"); start_sync(); break; case SCAN_STATE_RACH: @@ -266,7 +313,7 @@ static void start_rach(void) "(OTHER with NECI)\n", chan_req_val); } else { chan_req_mask = 0x1f; - chan_req_val = 0xe0; + chan_req_val = 0xf0; LOGP(DRR, LOGL_INFO, "CHANNEL REQUEST: %02x (OTHER no NECI)\n", chan_req_val); } @@ -305,6 +352,8 @@ static void start_sync(void) int i, dist = 0; char dist_str[32] = ""; + if (sdcch) + return; arfcn = 0xffff; for (i = 0; i <= 1023; i++) { if ((pm[i].flags & INFO_FLG_PM) @@ -329,19 +378,30 @@ static void start_sync(void) sprintf(dist_str, " dist %d", (int)dist); } if (dist > MAX_DIST || arfcn == 0xffff || rxlev < min_rxlev) { + if (scan_only) { + scan_exit(); + exit(0); + } memset(pm, 0, sizeof(pm)); pm_index = 0; - sync_count = 0; + printf("end of sync\n"); + wait_time *= 2; start_pm(); return; } pm[arfcn].flags |= INFO_FLG_SYNC; - LOGP(DSUM, LOGL_INFO, "Sync ARFCN %d (rxlev %d, %d syncs " - "left)%s\n", arfcn, pm[arfcn].rxlev, sync_count--, dist_str); memset(&sysinfo, 0, sizeof(sysinfo)); sysinfo.arfcn = arfcn; state = SCAN_STATE_SYNC; l1ctl_tx_reset_req(ms, L1CTL_RES_T_FULL); + stop_raw = 0; + collecting = 0; + sync_retry = 0; + reset_cid(); + memset(&app_state.cell_arfcns, 0x00, sizeof(app_state.cell_arfcns)); + got_data = (log_gprs ? 0 : 1); + if (!scan_only) + printf("\nARFCN %d: tuning\n", arfcn); l1ctl_tx_fbsb_req(ms, arfcn, L1CTL_FBSB_F_FB01SB, 100, 0, CCCH_MODE_NONE); } @@ -351,8 +411,8 @@ static void start_pm(void) uint16_t from, to; state = SCAN_STATE_PM; - from = band_range[pm_index][0]; - to = band_range[pm_index][1]; + from = band_range[2*pm_index+0]; + to = band_range[2*pm_index+1]; if (from == 0 && to == 0) { LOGP(DSUM, LOGL_INFO, "Measurement done\n"); @@ -374,6 +434,10 @@ static int signal_cb(unsigned int subsys, unsigned int signal, { struct osmobb_meas_res *mr; struct osmobb_fbsb_res *fr; + struct osmobb_msg_ind *mi; + struct osmocom_ms *ms; + static unsigned loss_count = 0; + uint16_t index; if (subsys != SS_L1CTL) @@ -389,149 +453,80 @@ static int signal_cb(unsigned int subsys, unsigned int signal, sync_count++; // printf("rxlev %d = %d (sync_count %d)\n", index, pm[index].rxlev, sync_count); break; + case S_L1CTL_BURST_IND: + mi = signal_data; + layer3_rx_burst(mi->ms, mi->msg); + break; case S_L1CTL_PM_DONE: pm_index++; start_pm(); break; case S_L1CTL_FBSB_RESP: + if (sdcch) + break; + if (!scan_only) + printf("ARFCN %d: got sync\n", arfcn); + state = SCAN_STATE_READ; fr = signal_data; + ms = fr->ms; sysinfo.bsic = fr->bsic; - state = SCAN_STATE_READ; memset(&ms->meas, 0, sizeof(ms->meas)); memset(&log_si, 0, sizeof(log_si)); + loss_count = 0; log_si.flags |= INFO_FLG_SYNC; log_si.ta = 0xff; /* invalid */ - start_timer(READ_WAIT); + if (!collecting) { + start_timer(READ_WAIT); + } LOGP(DRR, LOGL_INFO, "Synchronized, start reading\n"); break; case S_L1CTL_FBSB_ERR: - LOGP(DRR, LOGL_INFO, "Sync failed\n"); - start_sync(); + if (scan_only || (sync_retry > wait_time/60)) { + start_sync(); + } else { + printf("ARFCN %d: resync\n", arfcn); + fr = signal_data; + ms = fr->ms; + sync_retry++; + l1ctl_tx_dm_rel_req(ms); + sleep(1); + return l1ctl_tx_fbsb_req(ms, arfcn, + L1CTL_FBSB_F_FB01SB, 100, 0, + CCCH_MODE_NONE); + } break; case S_L1CTL_RESET: - if (started) - break; - started = 1; - memset(pm, 0, sizeof(pm)); - pm_index = 0; - sync_count = 0; - start_pm(); - } - return 0; -} - -static int ta_result(uint8_t ta) -{ - stop_timer(); - - if (ta == 0xff) - LOGP(DSUM, LOGL_INFO, "Got assignment reject\n"); - else { - LOGP(DSUM, LOGL_DEBUG, "Got assignment TA = %d\n", ta); - log_si.ta = ta; - } - - log_sysinfo(); - start_sync(); - - return 0; -} - -/* match request reference agains request */ -static int match_ra(struct osmocom_ms *ms, struct gsm48_req_ref *ref) -{ - uint8_t ia_t1, ia_t2, ia_t3; - - /* filter confirmed RACH requests only */ - if (rach_ref.valid && ref->ra == rach_ref.cr) { - ia_t1 = ref->t1; - ia_t2 = ref->t2; - ia_t3 = (ref->t3_high << 3) | ref->t3_low; - if (ia_t1 == rach_ref.t1 && ia_t2 == rach_ref.t2 - && ia_t3 == rach_ref.t3) { - LOGP(DRR, LOGL_INFO, "request %02x matches " - "(fn=%d,%d,%d)\n", ref->ra, ia_t1, ia_t2, - ia_t3); - return 1; - } else - LOGP(DRR, LOGL_INFO, "request %02x matches but not " - "frame number (IMM.ASS fn=%d,%d,%d != RACH " - "fn=%d,%d,%d)\n", ref->ra, ia_t1, ia_t2, ia_t3, - rach_ref.t1, rach_ref.t2, rach_ref.t3); - } - - return 0; -} - -/* 9.1.18 IMMEDIATE ASSIGNMENT is received */ -static int imm_ass(struct osmocom_ms *ms, struct msgb *msg) -{ - struct gsm48_imm_ass *ia = msgb_l3(msg); - - LOGP(DRR, LOGL_INFO, "IMMEDIATE ASSIGNMENT:\n"); - - if (state != SCAN_STATE_RACH) { - LOGP(DRR, LOGL_INFO, "Not for us, no request.\n"); - return 0; - } - - /* request ref */ - if (match_ra(ms, &ia->req_ref)) { - return ta_result(ia->timing_advance); - } - LOGP(DRR, LOGL_INFO, "Request, but not for us.\n"); - - return 0; -} - -/* 9.1.19 IMMEDIATE ASSIGNMENT EXTENDED is received */ -static int imm_ass_ext(struct osmocom_ms *ms, struct msgb *msg) -{ - struct gsm48_imm_ass_ext *ia = msgb_l3(msg); - - LOGP(DRR, LOGL_INFO, "IMMEDIATE ASSIGNMENT EXTENDED:\n"); - - if (state != SCAN_STATE_RACH) { - LOGP(DRR, LOGL_INFO, "Not for us, no request.\n"); - return 0; - } - - /* request ref 1 */ - if (match_ra(ms, &ia->req_ref1)) { - return ta_result(ia->timing_advance1); - } - /* request ref 2 */ - if (match_ra(ms, &ia->req_ref2)) { - return ta_result(ia->timing_advance2); - } - LOGP(DRR, LOGL_INFO, "Request, but not for us.\n"); - - return 0; -} - -/* 9.1.20 IMMEDIATE ASSIGNMENT REJECT is received */ -static int imm_ass_rej(struct osmocom_ms *ms, struct msgb *msg) -{ - struct gsm48_imm_ass_rej *ia = msgb_l3(msg); - int i; - struct gsm48_req_ref *req_ref; - - LOGP(DRR, LOGL_INFO, "IMMEDIATE ASSIGNMENT REJECT:\n"); - - if (state != SCAN_STATE_RACH) { - LOGP(DRR, LOGL_INFO, "Not for us, no request.\n"); - return 0; - } - - for (i = 0; i < 4; i++) { - /* request reference */ - req_ref = (struct gsm48_req_ref *) - (((uint8_t *)&ia->req_ref1) + i * 4); - LOGP(DRR, LOGL_INFO, "IMMEDIATE ASSIGNMENT REJECT " - "(ref 0x%02x)\n", req_ref->ra); - if (match_ra(ms, req_ref)) { - return ta_result(0xff); + if (sdcch) { + printf("RESET! while sdcch\n"); + } else { + if (started) + break; + started = 1; + loss_count = 0; + memset(pm, 0, sizeof(pm)); + pm_index = 0; + start_pm(); } + break; + case S_L1CTL_LOSS_IND: + if (sdcch) + break; + loss_count++; + ms = signal_data; + if (loss_count > 10) { + loss_count = 0; + if (sync_retry > 3) { + start_sync(); + } else { + sync_retry++; + l1ctl_tx_dm_rel_req(ms); + sleep(1); + return l1ctl_tx_fbsb_req(ms, arfcn, + L1CTL_FBSB_F_FB01SB, 100, 0, + CCCH_MODE_NONE); + } + } + break; } return 0; @@ -548,11 +543,12 @@ static int pch_agch(struct osmocom_ms *ms, struct msgb *msg) case GSM48_MT_RR_PAG_REQ_3: return 0; case GSM48_MT_RR_IMM_ASS: - return imm_ass(ms, msg); +// return imm_ass(ms, msg); + return gsm48_rx_imm_ass(msg, ms); case GSM48_MT_RR_IMM_ASS_EXT: - return imm_ass_ext(ms, msg); +// return imm_ass_ext(ms, msg); case GSM48_MT_RR_IMM_ASS_REJ: - return imm_ass_rej(ms, msg); +// return imm_ass_rej(ms, msg); default: return -EINVAL; } @@ -564,7 +560,12 @@ static int new_sysinfo(void) struct gsm48_sysinfo *s = &sysinfo; /* restart timer */ - start_timer(READ_WAIT); + //start_timer(READ_WAIT); + + if (s->si3 && scan_only) { + log_sysinfo(); + start_sync(); + } /* mandatory */ if (!s->si1 || !s->si2 || !s->si3 || !s->si4) { @@ -586,10 +587,9 @@ static int new_sysinfo(void) LOGP(DRR, LOGL_INFO, "Sysinfo complete\n"); - stop_timer(); + log_sysinfo(); - rach_count = 0; - start_rach(); + start_timer(IMM_WAIT); return 0; } @@ -599,6 +599,10 @@ static int bcch(struct osmocom_ms *ms, struct msgb *msg) { struct gsm48_sysinfo *s = &sysinfo; struct gsm48_system_information_type_header *sih = msgb_l3(msg); + struct gsm48_system_information_type_1 *si1 = + (struct gsm48_system_information_type_1 *) msgb_l3(msg); + struct gsm48_system_information_type_3 *si3 = + (struct gsm48_system_information_type_3 *) msgb_l3(msg); uint8_t ccch_mode; if (msgb_l3len(msg) != 23) { @@ -613,6 +617,10 @@ static int bcch(struct osmocom_ms *ms, struct msgb *msg) gsm48_decode_sysinfo1(s, (struct gsm48_system_information_type_1 *) sih, msgb_l3len(msg)); + gsm48_decode_freq_list(app_state.cell_arfcns, + si1->cell_channel_description, + sizeof(si1->cell_channel_description), + 0xff, 0x01); return new_sysinfo(); case GSM48_MT_RR_SYSINFO_2: if (!memcmp(sih, s->si2_msg, sizeof(s->si2_msg))) @@ -649,6 +657,7 @@ static int bcch(struct osmocom_ms *ms, struct msgb *msg) CCCH_MODE_NON_COMBINED; LOGP(DRR, LOGL_INFO, "Changing CCCH_MODE to %d\n", ccch_mode); l1ctl_tx_ccch_mode_req(ms, ccch_mode); + set_cid(si3->lai.digits, si3->lai.lac, si3->cell_identity); return new_sysinfo(); case GSM48_MT_RR_SYSINFO_4: if (!memcmp(sih, s->si4_msg, sizeof(s->si4_msg))) @@ -780,6 +789,32 @@ static int rcv_rsl(struct msgb *msg, struct lapdm_entity *le, void *l3ctx) return rc; } +void set_freq_range() +{ + if (!scan_band) { + band_range = range_all; + return; + } + if (!strcmp(scan_band, "900")) { + band_range = range_900; + return; + } + if (!strcmp(scan_band, "1800")) { + band_range = range_1800; + return; + } + if (!strcmp(scan_band, "850")) { + band_range = range_850; + return; + } + if (!strcmp(scan_band, "1900")) { + band_range = range_1900; + return; + } + printf("Bad frequency range\n"); + exit(-1); +} + int scan_init(struct osmocom_ms *_ms) { ms = _ms; @@ -787,6 +822,8 @@ int scan_init(struct osmocom_ms *_ms) memset(&timer, 0, sizeof(timer)); lapdm_channel_set_l3(&ms->lapdm_channel, &rcv_rsl, ms); g.enable = 1; + sdcch = 0; + set_freq_range(); osmo_gps_init(); if (osmo_gps_open()) g.enable = 0; @@ -817,3 +854,235 @@ int scan_exit(void) return 0; } + +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; + + if (sdcch) + return 0; + + /* If we're busy ... */ + if (app_state.dch_state != DCH_NONE) + return 0; + + /* Discard packet TBF assignement */ + if (ia->page_mode & 0xf0) { + if (got_data) { + return 0; + } else { + got_data = 1; + printf("ARFCN %d: got DATA assignment\n", arfcn); + } + } else { + printf("ARFCN %d: got SDCCH assignment\n", arfcn); + } + + layer3_app_reset(); + + 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); + if (arfcn != _arfcn) + printf("ARFCN %d: not jumping to ARFCN %d!\n", arfcn, _arfcn); + + DEBUGP(DRR, "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); + + DEBUGP(DRR, "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++; + } + } + + if (!ma_len) { + if (ia->page_mode & 0xf0) + got_data = 0; + return; + } + + /* 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); + } + + DEBUGPC(DRR, "\n"); + + /* Set state */ + app_state.dch_state = DCH_WAIT_EST; + app_state.dch_nr = ia->chan_desc.chan_nr; + app_state.dch_badcnt = 0; + + sdcch = 1; + if (!collecting) { + collecting = 1; + short_count = 0; + start_timer(wait_time, 0); + } + + return rv; +} + +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, "%s_%04d%02d%02d_%02d%02d_%d_%d_%02x.dat", + get_cid_str(), + lt.tm_year + 1900, lt.tm_mon, lt.tm_mday, + lt.tm_hour, lt.tm_min, + 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 l_arfcn; + int ul, do_rel=0; + static unsigned rcv_frames; + static unsigned rcv_snr; + + if (!sdcch) + return; + + /* Header handling */ + bi = (struct l1ctl_burst_ind *) msg->l1h; + + l_arfcn = ntohs(bi->band_arfcn); + rx_dbm = rxlev2dbm(bi->rx_level); + ul = !!(l_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 > 100) { + /* Change state */ + app_state.dch_state = DCH_ACTIVE; + app_state.dch_badcnt = 0; + rcv_frames = 0; + rcv_snr = 0; + printf("ARFCN %d: session begin\n", arfcn); + + /* Open output */ + app_state.fh = fopen(gen_filename(ms, bi), "wb"); + } else { + /* Abandon ? */ + //do_rel = (app_state.dch_badcnt++) >= 8; + } + } + } + + /* Check for channel end */ + if (app_state.dch_state == DCH_ACTIVE) { + if (!ul) { + /* Bad burst counting */ + if (bi->snr < 100) + app_state.dch_badcnt++; + else if (app_state.dch_badcnt >= 2) + app_state.dch_badcnt -= 2; + else + app_state.dch_badcnt = 0; + + /* Release condition */ + if (bi->chan_nr & 0xe0) + do_rel = app_state.dch_badcnt >= 4; + } + + if (!ul) { + rcv_frames++; + rcv_snr += bi->snr; + + /* capture up to 3 minutes */ + if (rcv_frames >= 40000) + do_rel = 1; + } + + /* Save the burst */ + fwrite(bi, sizeof(*bi), 1, app_state.fh); + } + + /* SNR check */ + if (do_rel) { + printf("ARFCN %d: session end, frames=%d SNR_avg=%d\n", arfcn, rcv_frames, rcv_snr/rcv_frames); + if ((bi->chan_nr & 0xe0) && (rcv_frames < 20)) + short_count++; + rcv_frames = 0; + rcv_snr = 0; + app_state.dch_state = DCH_NONE; + app_state.dch_badcnt = 0; + if (app_state.fh) { + fclose(app_state.fh); + app_state.fh = NULL; + } + sdcch = 0; + if (stop_raw || (short_count > 3)) { + collecting = 0; + pm[arfcn].flags |= INFO_FLG_SYNC; + start_sync(); + } else { + l1ctl_tx_dm_rel_req(ms); + l1ctl_tx_fbsb_req(ms, arfcn, L1CTL_FBSB_F_FB01SB, 100, 0, CCCH_MODE_NON_COMBINED); + } + } +} + +void layer3_app_reset(void) +{ + /* Reset state */ + memset(app_state.si, 0, NUM_SYSINFO*sizeof(uint8_t*)); + app_state.ccch_mode = CCCH_MODE_NONE; + app_state.dch_state = DCH_NONE; + app_state.dch_badcnt = 0; + + if (app_state.fh) + fclose(app_state.fh); + app_state.fh = NULL; +} + diff --git a/src/host/layer23/src/misc/cellid.c b/src/host/layer23/src/misc/cellid.c new file mode 100644 index 00000000..afc53658 --- /dev/null +++ b/src/host/layer23/src/misc/cellid.c @@ -0,0 +1,110 @@ +#ifndef _cellid_c_ +#define _cellid_c_ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <arpa/inet.h> +#include <osmocom/gsm/protocol/gsm_04_08.h> + +struct gsm_cell_id { + uint16_t mcc; + uint16_t mnc; + uint16_t lac; + uint16_t cid; +}; + +static struct gsm_cell_id *_gcid = 0; + +static char _gcid_str[32] = "\0"; + +const char *get_cid_str() +{ + if (_gcid) + return _gcid_str; + + return "unknown"; +} + +void reset_cid() +{ + if (_gcid) + free(_gcid); + _gcid = 0; +} + +void set_cid(uint8_t *digits, uint16_t nlac, uint16_t ncid) +{ + if (_gcid) + return; + + _gcid = malloc(sizeof(struct gsm_cell_id)); + + _gcid->mcc = (digits[0] & 0xf) * 100; + _gcid->mcc += (digits[0] >> 4) * 10; + _gcid->mcc += (digits[1] & 0xf) * 1; + + if ((digits[1] >> 4) == 0xf) { + _gcid->mnc = (digits[2] & 0xf) * 10; + _gcid->mnc += (digits[2] >> 4) * 1; + } else { + _gcid->mnc = (digits[2] & 0xf) * 100; + _gcid->mnc += (digits[2] >> 4) * 10; + _gcid->mnc += (digits[1] >> 4) * 1; + } + + _gcid->lac = ntohs(nlac); + _gcid->cid = ntohs(ncid); + + sprintf(_gcid_str, "%d_%d_%.04X_%.04X", + _gcid->mcc, _gcid->mnc, + _gcid->lac, _gcid->cid); + + printf("Cell ID: %s\n", _gcid_str); + fflush(stdout); +} + +void set_cid_from_si6(uint8_t *msg) +{ + struct gsm48_system_information_type_6 *si; + + if (_gcid) + return; + + si = (struct gsm48_system_information_type_6 *) &msg[5]; + + if (((msg[2] & 0x1c) == 0) && + ((msg[4] & 0xfc) != 0) && + (si->rr_protocol_discriminator == 6) && + (si->system_information == 0x1e)) { + _gcid = malloc(sizeof(struct gsm_cell_id)); + + memset(_gcid, 0, sizeof(struct gsm_cell_id)); + + _gcid->cid = ntohs(si->cell_identity); + + _gcid->lac = ntohs(si->lai.lac); + + _gcid->mcc = (si->lai.digits[0] & 0xf) * 100; + _gcid->mcc += (si->lai.digits[0] >> 4) * 10; + _gcid->mcc += (si->lai.digits[1] & 0xf) * 1; + + if ((si->lai.digits[1] >> 4) == 0xf) { + _gcid->mnc = (si->lai.digits[2] & 0xf) * 10; + _gcid->mnc += (si->lai.digits[2] >> 4) * 1; + } else { + _gcid->mnc = (si->lai.digits[2] & 0xf) * 100; + _gcid->mnc += (si->lai.digits[2] >> 4) * 10; + _gcid->mnc += (si->lai.digits[1] >> 4) * 1; + } + + sprintf(_gcid_str, "%d_%d_%.04X_%.04X", + _gcid->mcc, _gcid->mnc, + _gcid->lac, _gcid->cid); + + printf("Cell ID: %s\n", _gcid_str); + fflush(stdout); + } +} + +#endif diff --git a/src/host/layer23/src/misc/xcch.c b/src/host/layer23/src/misc/xcch.c new file mode 100644 index 00000000..9da34fe8 --- /dev/null +++ b/src/host/layer23/src/misc/xcch.c @@ -0,0 +1,153 @@ +/* + * xcch.c + * + * Copyright (c) 2011 Sylvain Munaut <tnt@246tNt.com> + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +#include <osmocom/core/bits.h> +#include <osmocom/core/conv.h> + + +/* + * GSM xCCH parity (FIRE code) + * + * g(x) = (x^23 + 1)(x^17 + x^3 + 1) + * = x^40 + x^26 + x^23 + x^17 + x^3 + 1 + */ + + +static int +xcch_parity_check(ubit_t *d) +{ + const uint64_t poly = 0x0004820009ULL; + const uint64_t remainder = 0xffffffffffULL; + uint64_t crc = 0; + int i; + + /* Compute CRC */ + for (i=0; i<184; i++) { + uint64_t bit = d[i] & 1; + crc ^= (bit << 39); + if (crc & (1ULL<<39)) { + crc <<= 1; + crc ^= poly; + } else { + crc <<= 1; + } + crc &= (1ULL << 40) - 1; + } + + crc ^= remainder; + + /* Check it */ + for (i=0; i<40; i++) + if (d[184+i] ^ ((crc >> (39-i)) & 1)) + return 1; + + return 0; +} + + +/* + * GSM xCCH convolutional coding + * + * G_0 = 1 + x^3 + x^4 + * G_1 = 1 + x + x^3 + x^4 + */ + +static const uint8_t conv_xcch_next_output[][2] = { + { 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 }, + { 3, 0 }, { 2, 1 }, { 3, 0 }, { 2, 1 }, + { 3, 0 }, { 2, 1 }, { 3, 0 }, { 2, 1 }, + { 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 }, +}; + +static const uint8_t conv_xcch_next_state[][2] = { + { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 }, + { 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 }, + { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 }, + { 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 }, +}; + +const struct osmo_conv_code conv_xcch = { + .N = 2, + .K = 5, + .len = 224, + .next_output = conv_xcch_next_output, + .next_state = conv_xcch_next_state, +}; + + +/* + * GSM xCCH interleaving and burst mapping + * + * Interleaving: + * + * Given 456 coded input bits, form 4 blocks of 114 bits: + * + * i(B, j) = c(n, k) k = 0, ..., 455 + * n = 0, ..., N, N + 1, ... + * B = B_0 + 4n + (k mod 4) + * j = 2(49k mod 57) + ((k mod 8) div 4) + * + * Mapping on Burst: + * + * e(B, j) = i(B, j) + * e(B, 59 + j) = i(B, 57 + j) j = 0, ..., 56 + * e(B, 57) = h_l(B) + * e(B, 58) = h_n(B) + * + * Where hl(B) and hn(B) are bits in burst B indicating flags. + */ + +static void +xcch_deinterleave(sbit_t *cB, sbit_t *iB) +{ + int j, k, B; + + for (k=0; k<456; k++) { + B = k & 3; + j = 2 * ((49 * k) % 57) + ((k & 7) >> 2); + cB[k] = iB[B * 114 + j]; + } +} + +static void +xcch_burst_unmap(sbit_t *iB, sbit_t *eB, sbit_t *hl, sbit_t *hn) +{ + memcpy(iB, eB, 57); + memcpy(iB+57, eB+59, 57); + + if (hl) + *hl = eB[57]; + + if (hn) + *hn = eB[58]; +} + +int +xcch_decode(uint8_t *l2_data, sbit_t *bursts) +{ + sbit_t iB[456], cB[456]; + ubit_t conv[224]; + int i, rv; + + for (i=0; i<4; i++) + xcch_burst_unmap(&iB[i * 114], &bursts[i * 116], NULL, NULL); + + xcch_deinterleave(cB, iB); + + osmo_conv_decode(&conv_xcch, cB, conv); + + rv = xcch_parity_check(conv); + if (rv) + return -1; + + osmo_ubit2pbit_ext(l2_data, 0, conv, 0, 184, 1); + + return 0; +} diff --git a/src/host/osmocon/osmocon.c b/src/host/osmocon/osmocon.c index fc29506c..7bce1f2d 100644 --- a/src/host/osmocon/osmocon.c +++ b/src/host/osmocon/osmocon.c @@ -130,9 +130,9 @@ struct dnload { enum dnload_state state; enum romload_state romload_state; enum mtk_state mtk_state; - enum dnload_mode mode, previous_mode; + enum dnload_mode mode; struct osmo_fd serial_fd; - char *filename, *previous_filename; + char *filename; char *chainload_filename; int expect_hdlc; @@ -217,6 +217,45 @@ static const uint8_t mtk_init_cmd[] = { 0xa0, 0x0a, 0x50, 0x05 }; static const uint8_t mtk_init_resp[] = { 0x5f, 0xf5, 0xaf, 0xfa }; static const uint8_t mtk_command[] = { 0xa1, 0xa2, 0xa4, 0xa8 }; + +static int cable_type = 0; + +int serial_up_to_eleven(void) +{ + int rv; + + /* Attempt custom baudrate */ + switch(cable_type) { + case 0: + rv = osmo_serial_set_baudrate(dnload.serial_fd.fd, B115200); + break; + case 1: + rv = osmo_serial_set_baudrate(dnload.serial_fd.fd, B460800); + break; + case 2: + rv = osmo_serial_set_custom_baudrate(dnload.serial_fd.fd, 406250); + } + if (rv == 0) + return 0; + +#ifdef I_HAVE_A_CP210x /* and I know what I'm doing, I swear ! */ + /* Try closest standard baudrate (CP210x reprogrammed adapters) */ + rv = osmo_serial_set_baudrate(dnload.serial_fd.fd, B460800); + if (rv == 0) + return 0; +#endif + + /* Everything failed */ + fprintf(stderr, "!!!\n"); + fprintf(stderr, "!!! ERROR !!!\n"); + fprintf(stderr, "!!!\n"); + fprintf(stderr, "!!! Unable to set custom baudrate, please use appropriate cable\n"); + fprintf(stderr, "!!! ( see wiki http://bb.osmocom.org/trac/wiki/Sniffing )\n"); + fprintf(stderr, "!!!\n"); + + exit(-1); +} + static void beacon_timer_cb(void *p) { int rc; @@ -813,21 +852,22 @@ static int handle_read(void) dnload.write_ptr = dnload.data; dnload.expect_hdlc = 1; + /* check for romloader chainloading mode used as a workaround * for the magic on the C139/C140 and J100i */ if (dnload.chainload_filename != NULL) { printf("Enabled Compal ramloader -> Calypso romloader" " chainloading mode\n"); bufptr = buffer; - dnload.previous_filename = dnload.filename; dnload.filename = dnload.chainload_filename; - dnload.previous_mode = dnload.mode; dnload.mode = MODE_ROMLOAD; osmo_serial_set_baudrate(dnload.serial_fd.fd, ROMLOAD_INIT_BAUDRATE); tick_timer.cb = &beacon_timer_cb; tick_timer.data = &tick_timer; osmo_timer_schedule(&tick_timer, 0, dnload.beacon_interval); } + else + serial_up_to_eleven(); } else if (!memcmp(buffer, phone_nack, sizeof(phone_nack))) { printf("Received DOWNLOAD NACK from phone, something went" " wrong :(\n"); @@ -971,22 +1011,11 @@ static int handle_read_romload(void) if (!memcmp(buffer, romload_branch_ack, sizeof(romload_branch_ack))) { printf("Received branch ack, your code is running now!\n"); + serial_up_to_eleven(); dnload.serial_fd.when = BSC_FD_READ; dnload.romload_state = FINISHED; dnload.write_ptr = dnload.data; dnload.expect_hdlc = 1; - - if (dnload.chainload_filename == NULL) - break; - - /* if using chainloading mode, switch back to the Compal - * ramloader settings to make sure the auto-reload - * feature works */ - bufptr = buffer; - dnload.romload_state = WAITING_IDENTIFICATION; - dnload.filename = dnload.previous_filename; - dnload.mode = dnload.previous_mode; - osmo_serial_set_baudrate(dnload.serial_fd.fd, MODEM_BAUDRATE); } else if (!memcmp(buffer, romload_branch_nack, sizeof(romload_branch_nack))) { printf("Received branch nack, aborting\n"); @@ -1398,16 +1427,15 @@ int main(int argc, char **argv) { int opt, flags; uint32_t tmp_load_address = ROMLOAD_ADDRESS; - const char *serial_dev = "/dev/ttyUSB1"; - const char *layer2_un_path = "/tmp/osmocom_l2"; + const char *serial_dev = "/dev/ttyUSB0"; + const char *layer2_un_path = "/tmp/osmocom_log"; const char *loader_un_path = "/tmp/osmocom_loader"; - dnload.mode = MODE_C123; + dnload.mode = MODE_C123xor; dnload.chainload_filename = NULL; - dnload.previous_filename = NULL; dnload.beacon_interval = DEFAULT_BEACON_INTERVAL; - while ((opt = getopt(argc, argv, "d:hl:p:m:c:s:i:v")) != -1) { + while ((opt = getopt(argc, argv, "d:hl:p:m:c:s:i:vCF")) != -1) { switch (opt) { case 'p': serial_dev = optarg; @@ -1435,6 +1463,12 @@ int main(int argc, char **argv) case 'i': dnload.beacon_interval = atoi(optarg) * 1000; break; + case 'C': + cable_type = 1; + break; + case 'F': + cable_type = 2; + break; case 'h': default: usage(argv[0]); diff --git a/src/shared/libosmocore/include/osmocom/gsm/protocol/gsm_04_08.h b/src/shared/libosmocore/include/osmocom/gsm/protocol/gsm_04_08.h index 39470e78..ce780926 100644 --- a/src/shared/libosmocore/include/osmocom/gsm/protocol/gsm_04_08.h +++ b/src/shared/libosmocore/include/osmocom/gsm/protocol/gsm_04_08.h @@ -793,6 +793,7 @@ struct gsm48_rr_status { #define GSM48_MT_RR_SYSINFO_2bis 0x02 #define GSM48_MT_RR_SYSINFO_2ter 0x03 +#define GSM48_MT_RR_SYSINFO_2quater 0x07 #define GSM48_MT_RR_SYSINFO_5bis 0x05 #define GSM48_MT_RR_SYSINFO_5ter 0x06 #define GSM48_MT_RR_SYSINFO_9 0x04 diff --git a/src/target/firmware/board/compal_e86/init.c b/src/target/firmware/board/compal_e86/init.c index 1de61933..0f069953 100644 --- a/src/target/firmware/board/compal_e86/init.c +++ b/src/target/firmware/board/compal_e86/init.c @@ -107,6 +107,7 @@ void board_init(void) /* initialize MODEM UART to be used for sercomm*/ uart_init(SERCOMM_UART_NR, 1); + //uart_baudrate(SERCOMM_UART_NR, UART_460800); uart_baudrate(SERCOMM_UART_NR, UART_115200); /* initialize IRDA UART to be used for old-school console code. @@ -129,8 +130,7 @@ void board_init(void) /* Initialize LCD driver (uses UWire) */ display = &td014_display; display_init(); - bl_mode_pwl(1); - bl_level(0); + bl_mode_pwl(0); /* Initialize keypad driver */ keypad_init(1); diff --git a/src/target/firmware/board/compal_e88/init.c b/src/target/firmware/board/compal_e88/init.c index a5bf880e..c5a05b54 100644 --- a/src/target/firmware/board/compal_e88/init.c +++ b/src/target/firmware/board/compal_e88/init.c @@ -103,6 +103,7 @@ void board_init(void) /* initialize MODEM UART to be used for sercomm*/ uart_init(SERCOMM_UART_NR, 1); + //uart_baudrate(SERCOMM_UART_NR, UART_460800); uart_baudrate(SERCOMM_UART_NR, UART_115200); /* Initialize IRDA UART to be used for old-school console code. @@ -125,8 +126,7 @@ void board_init(void) /* Initialize LCD driver (uses I2C) and backlight */ display = &st7558_display; display_init(); - bl_mode_pwl(1); - bl_level(50); + bl_mode_pwl(0); /* Initialize keypad driver */ keypad_init(1); diff --git a/src/target/firmware/board/compal_e99/init.c b/src/target/firmware/board/compal_e99/init.c index 0c218a8d..76878388 100644 --- a/src/target/firmware/board/compal_e99/init.c +++ b/src/target/firmware/board/compal_e99/init.c @@ -107,6 +107,7 @@ void board_init(void) /* initialize MODEM UART to be used for sercomm*/ uart_init(SERCOMM_UART_NR, 1); + //uart_baudrate(SERCOMM_UART_NR, UART_460800); uart_baudrate(SERCOMM_UART_NR, UART_115200); /* initialize IRDA UART to be used for old-school console code. @@ -129,8 +130,7 @@ void board_init(void) /* Initialize LCD driver (uses UWire) and backlight */ display = &ssd1783_display; display_init(); - bl_mode_pwl(1); - bl_level(50); + bl_mode_pwl(0); /* Initialize keypad driver */ keypad_init(1); diff --git a/src/target/firmware/board/gta0x/init.c b/src/target/firmware/board/gta0x/init.c index 4f256ea0..fe1c2cbd 100644 --- a/src/target/firmware/board/gta0x/init.c +++ b/src/target/firmware/board/gta0x/init.c @@ -103,6 +103,7 @@ void board_init(void) /* initialize MODEM UART to be used for sercomm*/ uart_init(SERCOMM_UART_NR, 1); + //uart_baudrate(SERCOMM_UART_NR, UART_460800); uart_baudrate(SERCOMM_UART_NR, UART_115200); /* Initialize IRDA UART to be used for old-school console code. @@ -125,8 +126,7 @@ void board_init(void) /* Initialize LCD driver (uses I2C) and backlight */ display = &st7558_display; display_init(); - bl_mode_pwl(1); - bl_level(50); + bl_mode_pwl(0); /* Initialize keypad driver */ keypad_init(1); diff --git a/src/target/firmware/board/pirelli_dpl10/init.c b/src/target/firmware/board/pirelli_dpl10/init.c index 53fb2576..a6d8fa6e 100644 --- a/src/target/firmware/board/pirelli_dpl10/init.c +++ b/src/target/firmware/board/pirelli_dpl10/init.c @@ -91,6 +91,7 @@ void board_init(void) /* initialize MODEM UART to be used for sercomm*/ uart_init(SERCOMM_UART_NR, 1); + //uart_baudrate(SERCOMM_UART_NR, UART_460800); uart_baudrate(SERCOMM_UART_NR, UART_115200); /* Initialize IRDA UART to be used for old-school console code. @@ -113,8 +114,7 @@ void board_init(void) /* Initialize LCD driver (uses I2C) and backlight */ display = &st7558_display; display_init(); - bl_mode_pwl(1); - bl_level(0); + bl_mode_pwl(0); /* Initialize keypad driver */ keypad_init(1); diff --git a/src/target/firmware/calypso/dsp.c b/src/target/firmware/calypso/dsp.c index 1daecb2d..0ca272ec 100644 --- a/src/target/firmware/calypso/dsp.c +++ b/src/target/firmware/calypso/dsp.c @@ -85,6 +85,7 @@ struct dsp_section { #include "dsp_params.c" #include "dsp_bootcode.c" #include "dsp_dumpcode.c" +#include "dsp_sniffcode.c" struct dsp_api dsp_api = { .ndb = (T_NDB_MCU_DSP *) BASE_API_NDB, @@ -204,7 +205,8 @@ static void dsp_set_params(int16_t *param_tab, int param_size) /* Start DSP up to bootloader */ dsp_pre_boot(dsp_bootcode); - /* FIXME: Implement Patch download, if any */ + dputs("Installing DSP sniff patch\n"); + dsp_bl_upload_sections(dsp_sniffcode); dputs("Setting some dsp_api.ndb values\n"); dsp_api.ndb->d_background_enable = 0; @@ -225,7 +227,9 @@ static void dsp_set_params(int16_t *param_tab, int param_size) dputs("Setting API NDB parameters\n"); for (i = 0; i < param_size; i ++) *param_ptr++ = param_tab[i]; - + + dsp_api.param->d_gprs_install_address = DSP_SNIFF_PATCH_START; + dsp_dump_version(); dputs("Finishing download phase\n"); diff --git a/src/target/firmware/calypso/dsp_sniffcode.c b/src/target/firmware/calypso/dsp_sniffcode.c new file mode 100644 index 00000000..865ce815 --- /dev/null +++ b/src/target/firmware/calypso/dsp_sniffcode.c @@ -0,0 +1,42 @@ +/* Generated from src/target_dsp/calypso/dsp_sniff.bin */ + +#define _SA_DECL (const uint16_t *)&(const uint16_t []) + +static const struct dsp_section dsp_sniffcode[] = { + { + .addr = 0x015c, + .size = 0x0051, + .data = _SA_DECL { + 0x76f8, 0x3f6b, 0x0160, 0xfc00, + 0x76f8, 0x439e, 0x0164, 0xfc00, + 0x7711, 0x2000, 0x61f8, 0x3fb0, + 0x0001, 0xf820, 0x016d, 0x7711, + 0x208a, 0x7311, 0x2114, 0x7699, + 0x0000, 0x6d91, 0x7311, 0x2115, + 0xf020, 0xb12c, 0xf074, 0xaac3, + 0x7211, 0x2114, 0xf495, 0xf495, + 0x1281, 0xf845, 0x018a, 0xf010, + 0x0001, 0x8081, 0xf074, 0xb74c, + 0xf020, 0x018b, 0xf074, 0xaa9f, + 0xf073, 0x0178, 0xfc00, 0xe834, + 0xf074, 0xa9ea, 0x7213, 0x2115, + 0xf495, 0xf495, 0x7093, 0x3fa4, + 0x7093, 0x3fa5, 0x7093, 0x3fa7, + 0x7093, 0x3fa6, 0x7093, 0x0cce, + 0x7712, 0x0ccf, 0x7711, 0x001c, + 0x47f8, 0x0011, 0xe589, 0x7313, + 0x2115, 0x7211, 0x2114, 0xf495, + 0xf495, 0x6be1, 0x0001, 0x0001, + 0xfc00, + }, + }, + { /* Guard */ + .addr = 0, + .size = 0, + .data = NULL, + }, +}; + +#undef _SA_DECL + +#define DSP_SNIFF_PATCH_START 0x015c diff --git a/src/target/firmware/include/inttypes.h b/src/target/firmware/include/inttypes.h new file mode 100644 index 00000000..dcbd6e19 --- /dev/null +++ b/src/target/firmware/include/inttypes.h @@ -0,0 +1 @@ +stdint.h
\ No newline at end of file diff --git a/src/target/firmware/include/layer1/prim.h b/src/target/firmware/include/layer1/prim.h index 30c51ae6..73f7c681 100644 --- a/src/target/firmware/include/layer1/prim.h +++ b/src/target/firmware/include/layer1/prim.h @@ -31,4 +31,8 @@ extern const struct tdma_sched_item tch_a_sched_set[]; extern const struct tdma_sched_item tch_d_sched_set[]; extern const struct tdma_sched_item neigh_pm_sched_set[]; +extern const struct tdma_sched_item sniff_xcch_dl_sched_set[]; +extern const struct tdma_sched_item sniff_xcch_ul_sched_set[]; +extern const struct tdma_sched_item sniff_tch_sched_set[]; + #endif /* _L1_PRIM_H */ diff --git a/src/target/firmware/include/rf/trf6151.h b/src/target/firmware/include/rf/trf6151.h index f0891b6b..c1eaf3b2 100644 --- a/src/target/firmware/include/rf/trf6151.h +++ b/src/target/firmware/include/rf/trf6151.h @@ -22,7 +22,9 @@ int trf6151_set_gain(uint8_t dbm); uint8_t trf6151_get_gain(void); /* Request the PLL to be tuned to the given frequency */ -void trf6151_set_arfcn(uint16_t arfcn, int uplink); +/* arfcn must have ARFCN_UPLINK flag set if you want uplink ! */ +/* tx selects the TX path only and doesn't set UL band ! */ +void trf6151_set_arfcn(uint16_t arfcn, int tx); enum trf6151_mode { TRF6151_IDLE, diff --git a/src/target/firmware/layer1/Makefile b/src/target/firmware/layer1/Makefile index 455a444a..59b9ace2 100644 --- a/src/target/firmware/layer1/Makefile +++ b/src/target/firmware/layer1/Makefile @@ -5,5 +5,5 @@ layer1_SRCS=avg.c agc.c afc.c toa.c sync.c tdma_sched.c tpu_window.c init.c \ l23_api.c mframe_sched.c sched_gsmtime.c async.c rfch.c apc.c layer1_SRCS += prim_pm.c prim_rach.c prim_tx_nb.c prim_rx_nb.c prim_fbsb.c \ - prim_freq.c prim_utils.c prim_tch.c + prim_freq.c prim_utils.c prim_tch.c prim_sniff.c diff --git a/src/target/firmware/layer1/l23_api.c b/src/target/firmware/layer1/l23_api.c index ed43e142..24c6d3ae 100644 --- a/src/target/firmware/layer1/l23_api.c +++ b/src/target/firmware/layer1/l23_api.c @@ -47,7 +47,7 @@ /* the size we will allocate struct msgb* for HDLC */ #define L3_MSG_HEAD 4 -#define L3_MSG_SIZE (sizeof(struct l1ctl_hdr)+sizeof(struct l1ctl_info_dl)+sizeof(struct l1ctl_traffic_ind) + L3_MSG_HEAD) +#define L3_MSG_SIZE (sizeof(struct l1ctl_hdr)+sizeof(struct l1ctl_info_dl)+sizeof(struct l1ctl_burst_ind) + L3_MSG_HEAD) void l1_queue_for_l2(struct msgb *msg) { @@ -251,7 +251,7 @@ static void l1ctl_rx_dm_est_req(struct msgb *msg) } /* figure out which MF tasks to enable */ - l1a_mftask_set(chan_nr2mf_task_mask(ul->chan_nr, NEIGH_MODE_PM)); + l1a_mftask_set(chan_nr2mf_task_mask(ul->chan_nr, 0)); } /* receive a L1CTL_DM_FREQ_REQ from L23 */ diff --git a/src/target/firmware/layer1/mframe_sched.c b/src/target/firmware/layer1/mframe_sched.c index 6281c3d6..9087e8be 100644 --- a/src/target/firmware/layer1/mframe_sched.c +++ b/src/target/firmware/layer1/mframe_sched.c @@ -52,6 +52,10 @@ struct mframe_sched_item { #define NB_QUAD_FH_UL NB_QUAD_UL #define NEIGH_PM neigh_pm_sched_set +#define SNIFF_QUAD_DL sniff_xcch_dl_sched_set +#define SNIFF_QUAD_UL sniff_xcch_ul_sched_set +#define SNIFF_TCH sniff_tch_sched_set + /* BCCH Normal */ static const struct mframe_sched_item mf_bcch_norm[] = { { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 2 }, @@ -88,112 +92,112 @@ static const struct mframe_sched_item mf_ccch_comb[] = { /* SDCCH/4 in a combined CCCH on C0T0, cannot be FH */ static const struct mframe_sched_item mf_sdcch4_0[] = { - { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 22 }, - { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 22+15 }, - { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 42, + { .sched_set = SNIFF_QUAD_DL, .modulo = 51, .frame_nr = 22 }, + { .sched_set = SNIFF_QUAD_UL, .modulo = 51, .frame_nr = 22+15 }, + { .sched_set = SNIFF_QUAD_DL, .modulo = 2*51, .frame_nr = 42, .flags = MF_F_SACCH }, - { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 42+15, + { .sched_set = SNIFF_QUAD_UL, .modulo = 2*51, .frame_nr = 42+15, .flags = MF_F_SACCH }, { .sched_set = NULL } }; static const struct mframe_sched_item mf_sdcch4_1[] = { - { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 26 }, - { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 26+15 }, - { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 46, + { .sched_set = SNIFF_QUAD_DL, .modulo = 51, .frame_nr = 26 }, + { .sched_set = SNIFF_QUAD_UL, .modulo = 51, .frame_nr = 26+15 }, + { .sched_set = SNIFF_QUAD_DL, .modulo = 2*51, .frame_nr = 46, .flags = MF_F_SACCH }, - { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 46+15, + { .sched_set = SNIFF_QUAD_UL, .modulo = 2*51, .frame_nr = 46+15, .flags = MF_F_SACCH }, { .sched_set = NULL } }; static const struct mframe_sched_item mf_sdcch4_2[] = { - { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 32 }, - { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 32+15 }, - { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 51+42, + { .sched_set = SNIFF_QUAD_DL, .modulo = 51, .frame_nr = 32 }, + { .sched_set = SNIFF_QUAD_UL, .modulo = 51, .frame_nr = 32+15 }, + { .sched_set = SNIFF_QUAD_DL, .modulo = 2*51, .frame_nr = 51+42, .flags = MF_F_SACCH }, - { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 51+42+15, + { .sched_set = SNIFF_QUAD_UL, .modulo = 2*51, .frame_nr = 51+42+15, .flags = MF_F_SACCH }, { .sched_set = NULL } }; static const struct mframe_sched_item mf_sdcch4_3[] = { - { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 36 }, - { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 36+15 }, - { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 51+46, + { .sched_set = SNIFF_QUAD_DL, .modulo = 51, .frame_nr = 36 }, + { .sched_set = SNIFF_QUAD_UL, .modulo = 51, .frame_nr = 36+15 }, + { .sched_set = SNIFF_QUAD_DL, .modulo = 2*51, .frame_nr = 51+46, .flags = MF_F_SACCH }, - { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 51+46+15, + { .sched_set = SNIFF_QUAD_UL, .modulo = 2*51, .frame_nr = 51+46+15, .flags = MF_F_SACCH }, { .sched_set = NULL } }; /* SDCCH/8, can be frequency hopping (FH) */ static const struct mframe_sched_item mf_sdcch8_0[] = { - { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 0 }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 0+15 }, - { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 32, + { .sched_set = SNIFF_QUAD_DL, .modulo = 51, .frame_nr = 0 }, + { .sched_set = SNIFF_QUAD_UL, .modulo = 51, .frame_nr = 0+15 }, + { .sched_set = SNIFF_QUAD_DL, .modulo = 2*51, .frame_nr = 32, .flags = MF_F_SACCH }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 32+15, + { .sched_set = SNIFF_QUAD_UL, .modulo = 2*51, .frame_nr = 32+15, .flags = MF_F_SACCH }, { .sched_set = NULL } }; static const struct mframe_sched_item mf_sdcch8_1[] = { - { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 4 }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 4+15 }, - { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 36, + { .sched_set = SNIFF_QUAD_DL, .modulo = 51, .frame_nr = 4 }, + { .sched_set = SNIFF_QUAD_UL, .modulo = 51, .frame_nr = 4+15 }, + { .sched_set = SNIFF_QUAD_DL, .modulo = 2*51, .frame_nr = 36, .flags = MF_F_SACCH }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 36+15, + { .sched_set = SNIFF_QUAD_UL, .modulo = 2*51, .frame_nr = 36+15, .flags = MF_F_SACCH }, { .sched_set = NULL } }; static const struct mframe_sched_item mf_sdcch8_2[] = { - { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 8 }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 8+15 }, - { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 40, + { .sched_set = SNIFF_QUAD_DL, .modulo = 51, .frame_nr = 8 }, + { .sched_set = SNIFF_QUAD_UL, .modulo = 51, .frame_nr = 8+15 }, + { .sched_set = SNIFF_QUAD_DL, .modulo = 2*51, .frame_nr = 40, .flags = MF_F_SACCH }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 40+15, + { .sched_set = SNIFF_QUAD_UL, .modulo = 2*51, .frame_nr = 40+15, .flags = MF_F_SACCH }, { .sched_set = NULL } }; static const struct mframe_sched_item mf_sdcch8_3[] = { - { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 12 }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 12+15 }, - { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 44, + { .sched_set = SNIFF_QUAD_DL, .modulo = 51, .frame_nr = 12 }, + { .sched_set = SNIFF_QUAD_UL, .modulo = 51, .frame_nr = 12+15 }, + { .sched_set = SNIFF_QUAD_DL, .modulo = 2*51, .frame_nr = 44, .flags = MF_F_SACCH }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 44+15, + { .sched_set = SNIFF_QUAD_UL, .modulo = 2*51, .frame_nr = 44+15, .flags = MF_F_SACCH }, { .sched_set = NULL } }; static const struct mframe_sched_item mf_sdcch8_4[] = { - { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 16 }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 16+15 }, - { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+32, + { .sched_set = SNIFF_QUAD_DL, .modulo = 51, .frame_nr = 16 }, + { .sched_set = SNIFF_QUAD_UL, .modulo = 51, .frame_nr = 16+15 }, + { .sched_set = SNIFF_QUAD_DL, .modulo = 2*51, .frame_nr = 51+32, .flags = MF_F_SACCH }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+32+15, + { .sched_set = SNIFF_QUAD_UL, .modulo = 2*51, .frame_nr = 51+32+15, .flags = MF_F_SACCH }, { .sched_set = NULL } }; static const struct mframe_sched_item mf_sdcch8_5[] = { - { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 20 }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 20+15 }, - { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+36, + { .sched_set = SNIFF_QUAD_DL, .modulo = 51, .frame_nr = 20 }, + { .sched_set = SNIFF_QUAD_UL, .modulo = 51, .frame_nr = 20+15 }, + { .sched_set = SNIFF_QUAD_DL, .modulo = 2*51, .frame_nr = 51+36, .flags = MF_F_SACCH }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+36+15, + { .sched_set = SNIFF_QUAD_UL, .modulo = 2*51, .frame_nr = 51+36+15, .flags = MF_F_SACCH }, { .sched_set = NULL } }; static const struct mframe_sched_item mf_sdcch8_6[] = { - { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 24 }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 24+15 }, - { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+40, + { .sched_set = SNIFF_QUAD_DL, .modulo = 51, .frame_nr = 24 }, + { .sched_set = SNIFF_QUAD_UL, .modulo = 51, .frame_nr = 24+15 }, + { .sched_set = SNIFF_QUAD_DL, .modulo = 2*51, .frame_nr = 51+40, .flags = MF_F_SACCH }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+40+15, + { .sched_set = SNIFF_QUAD_UL, .modulo = 2*51, .frame_nr = 51+40+15, .flags = MF_F_SACCH }, { .sched_set = NULL } }; static const struct mframe_sched_item mf_sdcch8_7[] = { - { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 28 }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 28+15 }, - { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+44, + { .sched_set = SNIFF_QUAD_DL, .modulo = 51, .frame_nr = 28 }, + { .sched_set = SNIFF_QUAD_UL, .modulo = 51, .frame_nr = 28+15 }, + { .sched_set = SNIFF_QUAD_DL, .modulo = 2*51, .frame_nr = 51+44, .flags = MF_F_SACCH }, - { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+44+15, + { .sched_set = SNIFF_QUAD_UL, .modulo = 2*51, .frame_nr = 51+44+15, .flags = MF_F_SACCH }, { .sched_set = NULL } }; @@ -210,73 +214,61 @@ static const struct mframe_sched_item mf_neigh_pm51[] = { #define TCH_D tch_d_sched_set static const struct mframe_sched_item mf_tch_f_even[] = { - { .sched_set = TCH, .modulo = 13, .frame_nr = 0 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 1 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 2 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 3 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 4 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 5 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 6 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 7 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 8 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 9 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 10 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 11 }, - { .sched_set = TCH_A, .modulo = 26, .frame_nr = 12, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 0 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 1 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 2 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 3 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 4 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 5 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 6 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 7 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 8 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 9 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 10 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 11 }, + { .sched_set = SNIFF_TCH, .modulo = 26, .frame_nr = 12, .flags = MF_F_SACCH }, { .sched_set = NULL } }; static const struct mframe_sched_item mf_tch_f_odd[] = { - { .sched_set = TCH, .modulo = 13, .frame_nr = 0 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 1 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 2 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 3 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 4 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 5 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 6 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 7 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 8 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 9 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 10 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 11 }, - { .sched_set = TCH_A, .modulo = 26, .frame_nr = 25, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 0 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 1 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 2 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 3 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 4 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 5 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 6 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 7 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 8 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 9 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 10 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 11 }, + { .sched_set = SNIFF_TCH, .modulo = 26, .frame_nr = 25, .flags = MF_F_SACCH }, { .sched_set = NULL } }; static const struct mframe_sched_item mf_tch_h_0[] = { - { .sched_set = TCH, .modulo = 13, .frame_nr = 0 }, - { .sched_set = TCH_D, .modulo = 13, .frame_nr = 1 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 2 }, - { .sched_set = TCH_D, .modulo = 13, .frame_nr = 3 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 4 }, - { .sched_set = TCH_D, .modulo = 13, .frame_nr = 5 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 6 }, - { .sched_set = TCH_D, .modulo = 13, .frame_nr = 7 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 8 }, - { .sched_set = TCH_D, .modulo = 13, .frame_nr = 9 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 10 }, - { .sched_set = TCH_D, .modulo = 13, .frame_nr = 11 }, - { .sched_set = TCH_A, .modulo = 26, .frame_nr = 12, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 0 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 2 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 4 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 6 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 8 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 10 }, + { .sched_set = SNIFF_TCH, .modulo = 26, .frame_nr = 12, .flags = MF_F_SACCH }, { .sched_set = NULL } }; static const struct mframe_sched_item mf_tch_h_1[] = { - { .sched_set = TCH_D, .modulo = 13, .frame_nr = 0 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 1 }, - { .sched_set = TCH_D, .modulo = 13, .frame_nr = 2 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 3 }, - { .sched_set = TCH_D, .modulo = 13, .frame_nr = 4 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 5 }, - { .sched_set = TCH_D, .modulo = 13, .frame_nr = 6 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 7 }, - { .sched_set = TCH_D, .modulo = 13, .frame_nr = 8 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 9 }, - { .sched_set = TCH_D, .modulo = 13, .frame_nr = 10 }, - { .sched_set = TCH, .modulo = 13, .frame_nr = 11 }, - { .sched_set = TCH_A, .modulo = 26, .frame_nr = 25, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 1 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 3 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 5 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 7 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 9 }, + { .sched_set = SNIFF_TCH, .modulo = 13, .frame_nr = 11 }, + { .sched_set = SNIFF_TCH, .modulo = 26, .frame_nr = 25, .flags = MF_F_SACCH }, { .sched_set = NULL } }; diff --git a/src/target/firmware/layer1/prim_rach.c b/src/target/firmware/layer1/prim_rach.c index 47f74241..9370589d 100644 --- a/src/target/firmware/layer1/prim_rach.c +++ b/src/target/firmware/layer1/prim_rach.c @@ -73,7 +73,7 @@ static int l1s_tx_rach_cmd(__unused uint8_t p1, __unused uint8_t p2, __unused ui dsp_api.db_w->d_task_ra = RACH_DSP_TASK; - l1s_tx_win_ctrl(l1s.serving_cell.arfcn, L1_TXWIN_AB, 0, 3); + l1s_tx_win_ctrl(l1s.serving_cell.arfcn | ARFCN_UPLINK, L1_TXWIN_AB, 0, 3); return 0; } diff --git a/src/target/firmware/layer1/prim_sniff.c b/src/target/firmware/layer1/prim_sniff.c new file mode 100644 index 00000000..37dcd32a --- /dev/null +++ b/src/target/firmware/layer1/prim_sniff.c @@ -0,0 +1,279 @@ +/* Layer 1 - Sniffing Bursts */ + +/* (C) 2010 by Sylvain Munaut <tnt@246tNt.com> + * + * 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. + * + */ + +// #define DEBUG +#undef DEBUG /* Very bw hungry */ + +#include <stdint.h> +#include <string.h> + +#include <defines.h> +#include <byteorder.h> + +#include <debug.h> + +#include <osmocom/gsm/gsm_utils.h> + +#include <calypso/dsp.h> +#include <layer1/agc.h> +#include <layer1/l23_api.h> +#include <layer1/rfch.h> +#include <layer1/sync.h> +#include <layer1/tdma_sched.h> +#include <layer1/tpu_window.h> + + +/* ------------------------------------------------------------------------ */ +/* Sniff TASK API */ +/* ------------------------------------------------------------------------ */ + +#define SNIFF_DSP_TASK 23 + +#define BASE_API_RAM 0xffd00000 +#define BASE_SNIFF_API_RAM (BASE_API_RAM + (0x2000 - 0x800) * sizeof(uint16_t)) + +struct sniff_burst { + uint16_t toa; + uint16_t pm; + uint16_t angle; + uint16_t snr; + uint16_t dummy_ind; + uint16_t bits[29]; +}; + +struct sniff_db { + uint16_t w_nb; + uint16_t r_nb; + struct sniff_burst bursts[4]; +}; + +struct sniff_api { + struct sniff_db db[2]; + uint16_t db_ptr; + uint16_t burst_ptr; +}; + +static inline struct sniff_db * +sniff_get_page(int r_wn /* 0=W, 1=R */) +{ + struct sniff_api *sapi = (void*)BASE_SNIFF_API_RAM; + int idx = r_wn ? dsp_api.r_page : dsp_api.w_page; + return &sapi->db[idx]; +} + + +/* ------------------------------------------------------------------------ */ +/* Local state */ +/* ------------------------------------------------------------------------ */ + +struct sniff_local_db { + uint32_t fn; + uint8_t w_nb; + uint8_t r_nb; +}; + +static struct sniff_local_db _ldbs[2]; + +static inline struct sniff_local_db * +sniff_get_local_page(int r_wn /* 0=W, 1=R */) +{ + struct sniff_local_db *ldb; + int idx = r_wn ? dsp_api.r_page : dsp_api.w_page; + + /* Get page */ + ldb = &_ldbs[idx]; + + /* Clear page if it's not properly in sync */ + if (!r_wn) { + if (ldb->fn != l1s.next_time.fn) { + memset(ldb, 0x00, sizeof(struct sniff_local_db)); + ldb->fn = l1s.next_time.fn; + } + } + + return ldb; +} + + +/* ------------------------------------------------------------------------ */ +/* Sniff command & response */ +/* ------------------------------------------------------------------------ */ + +static int +l1s_sniff_resp(uint8_t ul, uint8_t burst_id, uint16_t p3) +{ + struct sniff_db *sp = sniff_get_page(1); + struct sniff_local_db *lsp = sniff_get_local_page(1); + struct sniff_api *sapi = (void*)BASE_SNIFF_API_RAM; + + struct msgb *msg; + struct l1ctl_burst_ind *bi; + + struct gsm_time rx_time; + uint16_t rf_arfcn; + uint8_t mf_task_id = p3 & 0xff; + uint8_t mf_task_flags = p3 >> 8; + uint8_t tn; + + int bidx, i; + + /* Debug */ + printd("Fn: %d - %d - lsp->w_nb: %d - lsp->r_nb: %d - sp->w_nb: %d - sp->r_nb: %d\n", + l1s.current_time.fn-1, ul, + sp->w_nb, lsp->r_nb, + sp->w_nb, sp->r_nb + ); + printd(" -> %d %04hx %04hx | %04hx %04hx %04hx %04hx %04hx\n", + dsp_api.r_page, + sapi->db_ptr, + sapi->burst_ptr, + sp->bursts[bidx].toa, + sp->bursts[bidx].pm, + sp->bursts[bidx].angle, + sp->bursts[bidx].snr, + sp->bursts[bidx].dummy_ind + ); + + for (i=0; i<29; i++) + printd("%04hx%c", sp->bursts[bidx].bits[i], i==28?'\n':' '); + + /* Burst index in DSP response */ + bidx = lsp->r_nb++; + + /* The radio parameters for _this_ burst */ + gsm_fn2gsmtime(&rx_time, l1s.current_time.fn - 1); + rfch_get_params(&rx_time, &rf_arfcn, NULL, &tn); + + /* Create message */ + msg = l1ctl_msgb_alloc(L1CTL_BURST_IND); + if (!msg) + goto exit; + + bi = (struct l1ctl_burst_ind *) msgb_put(msg, sizeof(*bi)); + + /* Meta data */ + /* Time */ + bi->frame_nr = htonl(rx_time.fn); + + /* ARFCN */ + if (ul) + rf_arfcn |= ARFCN_UPLINK; + bi->band_arfcn = htons(rf_arfcn); + + /* Set Channel Number depending on MFrame Task ID */ + bi->chan_nr = mframe_task2chan_nr(mf_task_id, tn); + + /* Set burst id */ + bi->flags = burst_id; + + /* Set SACCH indication */ + if (mf_task_flags & MF_F_SACCH) + bi->flags |= BI_FLG_SACCH; + + /* Set dummy indication */ + if (sp->bursts[bidx].dummy_ind) + bi->flags |= BI_FLG_DUMMY; + + /* DSP measurements */ + bi->rx_level = dbm2rxlev(agc_inp_dbm8_by_pm(sp->bursts[bidx].pm >> 3)>>3); + bi->snr = (sp->bursts[bidx].snr - 1) >> 6; + + /* Pack bits */ + memset(bi->bits, 0x00, sizeof(bi->bits)); + + for (i=0; i<116; i++) + { + int sbit = 0x0008 << ((3 - (i & 3)) << 2); + int sword = i >> 2; + int dbit = 1 << (7 - (i & 7)); + int dbyte = i >> 3; + + if (sp->bursts[bidx].bits[sword] & sbit) + bi->bits[dbyte] |= dbit; + } + + /* Send it ! */ + l1_queue_for_l2(msg); + +exit: + /* mark READ page as being used */ + dsp_api.r_page_used = 1; + + return 0; +} + +static int +l1s_sniff_cmd(uint8_t ul, __unused uint8_t burst_id, __unused uint16_t p3) +{ + struct sniff_db *sp = sniff_get_page(0); + struct sniff_local_db *lsp = sniff_get_local_page(0); + uint16_t arfcn; + uint8_t tsc, tn; + + printd("CMD: %d %d %d\n", lsp->w_nb); + + sp->w_nb = ++lsp->w_nb; + sp->r_nb = 0; + + rfch_get_params(&l1s.next_time, &arfcn, &tsc, &tn); + + dsp_load_rx_task(SNIFF_DSP_TASK, 0, tsc); + + /* enable dummy bursts detection */ + dsp_api.db_w->d_ctrl_system |= (1 << B_BCCH_FREQ_IND); + + if (ul) { + l1s_rx_win_ctrl(arfcn | ARFCN_UPLINK, L1_RXWIN_NB, 3); + } else { + l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB, 0); + } + + return 0; +} + +const struct tdma_sched_item sniff_xcch_dl_sched_set[] = { + SCHED_ITEM_DT(l1s_sniff_cmd, 0, 0, 0), SCHED_END_FRAME(), + SCHED_ITEM_DT(l1s_sniff_cmd, 0, 0, 1), SCHED_END_FRAME(), + SCHED_ITEM(l1s_sniff_resp, -5, 0, 0), SCHED_ITEM_DT(l1s_sniff_cmd, 0, 0, 2), SCHED_END_FRAME(), + SCHED_ITEM(l1s_sniff_resp, -5, 0, 1), SCHED_ITEM_DT(l1s_sniff_cmd, 0, 0, 3), SCHED_END_FRAME(), + SCHED_ITEM(l1s_sniff_resp, -5, 0, 2), SCHED_END_FRAME(), + SCHED_ITEM(l1s_sniff_resp, -5, 0, 3), SCHED_END_FRAME(), + SCHED_END_SET() +}; + +const struct tdma_sched_item sniff_xcch_ul_sched_set[] = { + SCHED_ITEM_DT(l1s_sniff_cmd, 3, 1, 0), SCHED_END_FRAME(), + SCHED_ITEM_DT(l1s_sniff_cmd, 3, 1, 1), SCHED_END_FRAME(), + SCHED_ITEM(l1s_sniff_resp, -4, 1, 0), SCHED_ITEM_DT(l1s_sniff_cmd, 3, 1, 2), SCHED_END_FRAME(), + SCHED_ITEM(l1s_sniff_resp, -4, 1, 1), SCHED_ITEM_DT(l1s_sniff_cmd, 3, 1, 3), SCHED_END_FRAME(), + SCHED_ITEM(l1s_sniff_resp, -4, 1, 2), SCHED_END_FRAME(), + SCHED_ITEM(l1s_sniff_resp, -4, 1, 3), SCHED_END_FRAME(), + SCHED_END_SET() +}; + +const struct tdma_sched_item sniff_tch_sched_set[] = { + SCHED_ITEM_DT(l1s_sniff_cmd, 0, 0, 0), SCHED_ITEM_DT(l1s_sniff_cmd, 3, 1, 0), SCHED_END_FRAME(), + SCHED_END_FRAME(), + SCHED_ITEM(l1s_sniff_resp, -5, 0, 0), SCHED_ITEM(l1s_sniff_resp, -4, 1, 0), SCHED_END_FRAME(), + SCHED_END_SET() +}; + diff --git a/src/target/firmware/layer1/prim_tch.c b/src/target/firmware/layer1/prim_tch.c index 96858fb6..292ca103 100644 --- a/src/target/firmware/layer1/prim_tch.c +++ b/src/target/firmware/layer1/prim_tch.c @@ -479,7 +479,7 @@ skip_tx_traffic: l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB, 0); dsp_load_tx_task(TCHT_DSP_TASK, 0, tsc); /* burst_id unused for TCH */ - l1s_tx_win_ctrl(arfcn, L1_TXWIN_NB, 0, 3); + l1s_tx_win_ctrl(arfcn | ARFCN_UPLINK, L1_TXWIN_NB, 0, 3); return 0; } @@ -738,7 +738,7 @@ static int l1s_tch_a_cmd(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3) l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB, 0); dsp_load_tx_task(TCHA_DSP_TASK, 0, tsc); /* burst_id unused for TCHA */ - l1s_tx_win_ctrl(arfcn, L1_TXWIN_NB, 0, 3); + l1s_tx_win_ctrl(arfcn, L1_TXWIN_NB | ARFCN_UPLINK, 0, 3); return 0; } diff --git a/src/target/firmware/layer1/prim_tx_nb.c b/src/target/firmware/layer1/prim_tx_nb.c index 3038178b..df13c757 100644 --- a/src/target/firmware/layer1/prim_tx_nb.c +++ b/src/target/firmware/layer1/prim_tx_nb.c @@ -123,7 +123,7 @@ static int l1s_tx_cmd(uint8_t p1, uint8_t burst_id, uint16_t p3) dsp_load_tx_task(DUL_DSP_TASK, burst_id, tsc); - l1s_tx_win_ctrl(arfcn, L1_TXWIN_NB, 0, 3); + l1s_tx_win_ctrl(arfcn | ARFCN_UPLINK, L1_TXWIN_NB, 0, 3); return 0; } diff --git a/src/target/firmware/rf/trf6151.c b/src/target/firmware/rf/trf6151.c index 53604024..96210fc6 100644 --- a/src/target/firmware/rf/trf6151.c +++ b/src/target/firmware/rf/trf6151.c @@ -428,12 +428,16 @@ static void trf6151_band_select(enum trf6151_gsm_band band) } /* Set ARFCN. Takes 2 reg_write, i.e. 8 TPU instructions */ -void trf6151_set_arfcn(uint16_t arfcn, int uplink) +void trf6151_set_arfcn(uint16_t arfcn, int tx) { uint32_t freq_khz; uint16_t pll_config; + int uplink; enum trf6151_gsm_band pll_band; + uplink = !!(arfcn & ARFCN_UPLINK); + arfcn != ~ARFCN_UPLINK; + switch (gsm_arfcn2band(arfcn)) { case GSM_BAND_850: case GSM_BAND_900: @@ -452,7 +456,7 @@ void trf6151_set_arfcn(uint16_t arfcn, int uplink) freq_khz = gsm_arfcn2freq10(arfcn, uplink) * 100; printd("ARFCN %u -> %u kHz\n", arfcn, freq_khz); - if (uplink == 0) + if (!tx) trf6151_pll_rx(freq_khz, &pll_config, &pll_band); else trf6151_pll_tx(freq_khz, &pll_config, &pll_band); @@ -512,7 +516,7 @@ uint8_t trf6151_get_gain(void) void trf6151_test(uint16_t arfcn) { - /* Select ARFCN 871 downlink */ + /* Select ARFCN downlink */ trf6151_set_arfcn(arfcn, 0); trf6151_set_mode(TRF6151_RX); @@ -532,7 +536,7 @@ void trf6151_test(uint16_t arfcn) void trf6151_tx_test(uint16_t arfcn) { /* Select ARFCN uplink */ - trf6151_set_arfcn(arfcn, 1); + trf6151_set_arfcn(arfcn | ARFCN_UPLINK, 1); trf6151_set_mode(TRF6151_TX); tpu_enq_wait(TRF6151_RX_PLL_DELAY); diff --git a/src/target_dsp/calypso/Makefile b/src/target_dsp/calypso/Makefile index 40ee4ec5..266da7aa 100644 --- a/src/target_dsp/calypso/Makefile +++ b/src/target_dsp/calypso/Makefile @@ -1,4 +1,4 @@ -all: dsp_dump.bin +all: dsp_dump.bin dsp_sniff.bin CROSS=tic54x-coff- @@ -11,5 +11,8 @@ CROSS=tic54x-coff- dsp_dump.coff: bl_stage3.o dsp_dump.lds $(CROSS)ld --script dsp_dump.lds bl_stage3.o -o $@ +dsp_sniff.coff: dsp_sniff.o dsp_patch.lds + $(CROSS)ld --script dsp_patch.lds dsp_sniff.o -o $@ + clean: rm -f *.o *.bin *.coff diff --git a/src/target_dsp/calypso/dsp_patch.lds b/src/target_dsp/calypso/dsp_patch.lds new file mode 100644 index 00000000..0695121d --- /dev/null +++ b/src/target_dsp/calypso/dsp_patch.lds @@ -0,0 +1,25 @@ +OUTPUT_FORMAT("coff1-c54x") +OUTPUT_ARCH("") +MEMORY +{ + dram (RWXI) : ORIGIN = 0x015C, LENGTH = 0x0600 + apiram (RWXI) : ORIGIN = 0x2000, LENGTH = 0x1000 +} +SECTIONS +{ + . = 0x015C; + + .text : + { + *(.text) + } > dram + + + . = 0x2000; + + .apiram : + { + PROVIDE(_api_ram = .); + *(.apiram) + } > apiram +} diff --git a/src/target_dsp/calypso/dsp_sniff.S b/src/target_dsp/calypso/dsp_sniff.S new file mode 100644 index 00000000..5a323f29 --- /dev/null +++ b/src/target_dsp/calypso/dsp_sniff.S @@ -0,0 +1,175 @@ +; DSP Sniffing task patch + +; +; (C) 2010 by Sylvain Munaut <tnt@246tNt.com> +; +; 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. +; + +; ---------------------------------------------------------------------------- +; Known symbols +; ---------------------------------------------------------------------------- + + ; Variables +patch_install_fptr .equ 0x3F6B ; Patch install function ptr +dsp_page .equ 0x3FB0 ; Current ndb.d_dsp_page +task_fn_entry .equ 0x4387 + 23 ; Task 23 index in JT_4387 + + ; Functions +a5_setup .equ 0xB12C +dma_queue_setup .equ 0xB74C + +jt4387_exec .equ 0xA9EA + +fq_4320_push .equ 0xAA9F +fq_4330_push .equ 0xAA6C +fq_4340_push .equ 0xAAC3 + + +; ---------------------------------------------------------------------------- +; Our double buffer API +; ---------------------------------------------------------------------------- + + .section .apiram + +sniff_db0 .ds 138 +sniff_db1 .ds 138 +sniff_db_ptr .ds 1 +sniff_burst_ptr .ds 1 + + +; ---------------------------------------------------------------------------- +; The code itself +; ---------------------------------------------------------------------------- + + .text + +; +; Patch init +; +; Called during DSP boot (around the middle) +; +patch_init: + st #patch_install, *(patch_install_fptr) + ret + +; +; Patch install +; +; Called after DSP init. That's were the overriding of all the +; jump tables should be done. +; +patch_install: + st #sniff_task, *(task_fn_entry) + ret + +; +; New sniff task +; +; Called by the dispatch code when the value 23 is found in d_task_d +; +sniff_task: + ; Setup our double buffer zone ptr + stm #sniff_db0, AR1 + bitf *(dsp_page), #1 + bc 1f, ntc + stm #sniff_db1, AR1 +1: + + mvmd AR1, @sniff_db_ptr + + ; Prepare the burst_ptr and burst_counter + ; sniff_db_ptr->r_nb = 0 + st #0, *+AR1 + + ; sniff_burst_ptr = sniff_db_ptr + 2; + mar *AR1+ + mvmd AR1, @sniff_burst_ptr + + ; Queue A5 setup in FQ4340 + ; (needed to make sure the a5 bits are zeroed) + ld #a5_setup, 0, A + call fq_4340_push + + ; Prepare bursts reception + ; (we queue as many many as bursts to RX) +1: + ; Decrement & Check counter + mvdm @sniff_db_ptr, AR1 + nop ; (pipeline conflict) + nop ; (pipeline conflict) + + ldu *AR1, A + bc 2f, aeq + sub #1, A + stl A, *AR1 + + ; Queue the DMA + call dma_queue_setup + + ; Queue Burst handler in FQ4320 + ld #burst_handler, 0, A + call fq_4320_push + + ; Loop + b 1b +2: + + ; Done + ret + +; +; Burst data handler +; +; Called once the DMA transfer is done and the IQ bits are received. +; Most maintenance tasks (like cleanup after DMA and inth stuff) are +; done for us. Only real work goes here. +; +burst_handler: + ; NB demodulation + ld #0x34, A + call jt4387_exec + + ; Base burst storage address + mvdm @sniff_burst_ptr, AR3 + nop ; (pipeline conflict) + nop ; (pipeline conflict) + + ; Copy "metadata" + mvkd @0x3FA4, *AR3+ ; D_TOA + mvkd @0x3FA5, *AR3+ ; D_PM + mvkd @0x3FA7, *AR3+ ; D_ANGLE + mvkd @0x3FA6, *AR3+ ; D_SNR + mvkd @0x0CCE, *AR3+ ; dummy burst indicator + + ; Copy the softbits + stm #0x0CCF, AR2 ; src + stm #28, AR1 ; size-1 (29 words = 116 bits) + rpt *(AR1) + mvdd *AR2+, *AR3+ + + ; Store the new pointer + mvmd AR3, @sniff_burst_ptr + + ; Increment received bursts count + mvdm @sniff_db_ptr, AR1 + nop ; (pipeline conflict) + nop ; (pipeline conflict) + addm #1, *AR1(1) + + ; Done + ret |