summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPiotr Krysik <perper@o2.pl>2009-06-27 13:18:13 +0200
committerPiotr Krysik <perper@o2.pl>2009-06-27 13:18:13 +0200
commit43640a6e4d574c1c5a99a89a3ab6742b83b2183f (patch)
tree64031b8f010e0e967e2b242ae5606a09c3417887 /src
parentf1df46a5c04d38f155cd8f8c8315eeb1f3fc7c2e (diff)
added dirty tch/f decoding to gsm-receiver (which also should be removed in the future)
Diffstat (limited to 'src')
-rw-r--r--src/lib/Makefile.am10
-rw-r--r--src/lib/decoder/Makefile.am28
-rw-r--r--src/lib/decoder/a5-1-2.c429
-rw-r--r--src/lib/gsm.i2
-rw-r--r--src/lib/gsm_constants.h7
-rw-r--r--src/lib/gsm_receiver_cf.cc163
-rw-r--r--src/lib/gsm_receiver_cf.h31
-rwxr-xr-xsrc/python/gsm_receive.py7
-rwxr-xr-xsrc/python/gsm_receive_usrp.py2
9 files changed, 202 insertions, 477 deletions
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 91819fa..925eaca 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -29,7 +29,8 @@ SUBDIRS = decoder
ourpythondir = $(grpythondir)
ourlibdir = $(grpyexecdir)
-AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) $(WITH_INCLUDES) -I$(DECODER_INCLUDEDIR)
+AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) $(WITH_INCLUDES)
+# -I$(OPEN_BTS_INCLUDES)
SWIGPYTHONARGS = $(SWIGPYTHONFLAGS) $(SWIGGRFLAGS) $(WITH_SWIG_INCLUDES) \
$(WITH_INCLUDES)
@@ -76,11 +77,10 @@ _gsm_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version
# link the library against some comon swig runtime code and the
# c++ standard library
_gsm_la_LIBADD = \
- $(PYTHON_LDFLAGS) \
- libgsmdemod.la \
+ $(PYTHON_LDFLAGS) \
+ libgsmdemod.la \
-lstdc++ \
- decoder/libdecoder.la
-# $(DECODER_LA)
+ $(DECODER_LA)
#libgsmdemod_la_LIBADD =
diff --git a/src/lib/decoder/Makefile.am b/src/lib/decoder/Makefile.am
index 1ad7899..1726d68 100644
--- a/src/lib/decoder/Makefile.am
+++ b/src/lib/decoder/Makefile.am
@@ -21,28 +21,36 @@
include $(top_srcdir)/Makefile.common
-AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) -I$(MAIN_INCLUDEDIR)
+AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
+
+SUBDIRS = openbtsstuff
noinst_LTLIBRARIES = libdecoder.la
+libdecoder_la_LIBADD = \
+ openbtsstuff/libopenbtsdecoder.la
+
libdecoder_la_SOURCES = \
sch.c \
cch.c \
fire_crc.c \
gsmstack.c \
+ interleave.c \
out_pcap.c \
- tun.c \
- interleave.c
-
-noinst_HEADERS = \
- sch.h \
+ tun.c
+# tch.c \
+# conv.c
+
+noinst_HEADERS = \
+ sch.h \
cch.h \
fire_crc.h \
gsmstack.h \
interleave.h \
- system.h \
out_pcap.h \
tun.h \
- gsmtap.h
-
-# burst_types.h
+ system.h \
+ gsmtap.h \
+ a5-1-2.h
+# tch.h \
+# conv.h
diff --git a/src/lib/decoder/a5-1-2.c b/src/lib/decoder/a5-1-2.c
deleted file mode 100644
index 64370d2..0000000
--- a/src/lib/decoder/a5-1-2.c
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * A pedagogical implementation of the GSM A5/1 and A5/2 "voice privacy"
- * encryption algorithms.
- *
- * Copyright (C) 1998-1999: Marc Briceno, Ian Goldberg, and David Wagner
- *
- * The source code below is optimized for instructional value and clarity.
- * Performance will be terrible, but that's not the point.
- *
- * This software may be export-controlled by US law.
- *
- * This software is free for commercial and non-commercial use as long as
- * the following conditions are adhered to.
- * Copyright remains the authors' and as such any Copyright notices in
- * the code are not to be removed.
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The license and distribution terms for any publicly available version
- * or derivative of this code cannot be changed. i.e. this code cannot
- * simply be copied and put under another distribution license
- * [including the GNU Public License].
- *
- * Background: The Global System for Mobile communications is the most
- * widely deployed digital cellular telephony system in the world. GSM
- * makes use of four core cryptographic algorithms, none of which has
- * been published by the GSM MOU. This failure to subject the
- * algorithms to public review is all the more puzzling given that over
- * 215 million GSM subscribers are expected to rely on the claimed
- * security of the system.
- *
- * The four core GSM cryptographic algorithms are:
- * A3 authentication algorithm
- * A5/1 "stronger" over-the-air voice-privacy algorithm
- * A5/2 "weaker" over-the-air voice-privacy algorithm
- * A8 voice-privacy key generation algorithm
- *
- * In April of 1998, our group showed that COMP128, the algorithm used by the
- * overwhelming majority of GSM providers for both A3 and A8 functionality
- * is fatally flawed and allows for cloning of GSM mobile phones.
- *
- * Furthermore, we demonstrated that all A8 implementations we could locate,
- * including the few that did not use COMP128 for key generation, had been
- * deliberately weakened by reducing the keyspace from 64 bits to 54 bits.
- * The remaining 10 bits are simply set to zero!
- *
- * See http://www.scard.org/gsm for additional information.
- *
- * [May 1999]
- * One question so far unanswered is if A5/1, the "stronger" of the two
- * widely deployed voice-privacy algorithm is at least as strong as the
- * key. Meaning: "Does A5/1 have a work factor of at least 54 bits"?
- * Absent a publicly available A5/1 reference implementation, this question
- * could not be answered. We hope that our reference implementation below,
- * which has been verified against official A5/1 test vectors, will provide
- * the cryptographic community with the base on which to construct the
- * answer to this important question.
- *
- * Initial indications about the strength of A5/1 are not encouraging.
- * A variant of A5, while not A5/1 itself, has been estimated to have a
- * work factor of well below 54 bits. See http://jya.com/crack-a5.htm for
- * background information and references.
- *
- * With COMP128 broken and A5/1 published below, we will now turn our
- * attention to A5/2.
- *
- * [August 1999]
- * 19th Annual International Cryptology Conference - Crypto'99
- * Santa Barbara, California
- *
- * A5/2 has been added to the previously published A5/1 source. Our
- * implementation has been verified against official test vectors.
- *
- * This means that our group has now reverse engineered the entire set
- * of cryptographic algorithms used in the overwhelming majority of GSM
- * installations, including all the over-the-air "voice privacy" algorithms.
- *
- * The "voice privacy" algorithm A5/2 proved especially weak. Which perhaps
- * should come as no surprise, since even GSM MOU members have admitted that
- * A5/2 was designed with heavy input by intelligence agencies to ensure
- * breakability. Just how insecure is A5/2? It can be broken in real time
- * with a work factor of a mere 16 bits. GSM might just as well use no "voice
- * privacy" algorithm at all.
- *
- * We announced the break of A5/2 at the Crypto'99 Rump Session.
- * Details will be published in a scientific paper following soon.
- *
- *
- * -- Marc Briceno <marc@scard.org>
- * Voice: +1 (925) 798-4042
- *
- */
-
-
-#include <stdio.h>
-
-
-/* Masks for the shift registers */
-#define R1MASK 0x07FFFF /* 19 bits, numbered 0..18 */
-#define R2MASK 0x3FFFFF /* 22 bits, numbered 0..21 */
-#define R3MASK 0x7FFFFF /* 23 bits, numbered 0..22 */
-#ifdef A5_2
-#define R4MASK 0x01FFFF /* 17 bits, numbered 0..16 */
-#endif /* A5_2 */
-
-
-#ifndef A5_2
-/* Middle bit of each of the three shift registers, for clock control */
-#define R1MID 0x000100 /* bit 8 */
-#define R2MID 0x000400 /* bit 10 */
-#define R3MID 0x000400 /* bit 10 */
-#else /* A5_2 */
-/* A bit of R4 that controls each of the shift registers */
-#define R4TAP1 0x000400 /* bit 10 */
-#define R4TAP2 0x000008 /* bit 3 */
-#define R4TAP3 0x000080 /* bit 7 */
-#endif /* A5_2 */
-
-
-/* Feedback taps, for clocking the shift registers.
- * These correspond to the primitive polynomials
- * x^19 + x^5 + x^2 + x + 1, x^22 + x + 1,
- * x^23 + x^15 + x^2 + x + 1, and x^17 + x^5 + 1. */
-
-
-#define R1TAPS 0x072000 /* bits 18,17,16,13 */
-#define R2TAPS 0x300000 /* bits 21,20 */
-#define R3TAPS 0x700080 /* bits 22,21,20,7 */
-#ifdef A5_2
-#define R4TAPS 0x010800 /* bits 16,11 */
-#endif /* A5_2 */
-
-
-typedef unsigned char byte;
-typedef unsigned long word;
-typedef word bit;
-
-
-/* Calculate the parity of a 32-bit word, i.e. the sum of its bits modulo 2
-*/
-bit parity(word x) {
- x ^= x>>16;
- x ^= x>>8;
- x ^= x>>4;
- x ^= x>>2;
- x ^= x>>1;
- return x&1;
-}
-
-
-/* Clock one shift register. For A5/2, when the last bit of the frame
- * is loaded in, one particular bit of each register is forced to '1';
- * that bit is passed in as the last argument. */
-#ifndef A5_2
-word clockone(word reg, word mask, word taps) {
-#else /* A5_2 */
-word clockone(word reg, word mask, word taps, word loaded_bit) {
-#endif /* A5_2 */
- word t = reg & taps;
- reg = (reg << 1) & mask;
- reg |= parity(t);
-#ifdef A5_2
- reg |= loaded_bit;
-#endif /* A5_2 */
- return reg;
-}
-
-
-/* The three shift registers. They're in global variables to make the code
- * easier to understand.
- * A better implementation would not use global variables. */
-word R1, R2, R3;
-#ifdef A5_2
-word R4;
-#endif /* A5_2 */
-
-
-/* Return 1 iff at least two of the parameter words are non-zero. */
-bit majority(word w1, word w2, word w3) {
- int sum = (w1 != 0) + (w2 != 0) + (w3 != 0);
- if (sum >= 2)
- return 1;
- else
- return 0;
-}
-
-
-/* Clock two or three of R1,R2,R3, with clock control
- * according to their middle bits.
- * Specifically, we clock Ri whenever Ri's middle bit
- * agrees with the majority value of the three middle bits. For A5/2,
- * use particular bits of R4 instead of the middle bits. Also, for A5/2,
- * always clock R4.
- * If allP == 1, clock all three of R1,R2,R3, ignoring their middle bits.
- * This is only used for key setup. If loaded == 1, then this is the last
- * bit of the frame number, and if we're doing A5/2, we have to set a
- * particular bit in each of the four registers. */
-void clock(int allP, int loaded) {
-#ifndef A5_2
- bit maj = majority(R1&R1MID, R2&R2MID, R3&R3MID);
- if (allP || (((R1&R1MID)!=0) == maj))
- R1 = clockone(R1, R1MASK, R1TAPS);
- if (allP || (((R2&R2MID)!=0) == maj))
- R2 = clockone(R2, R2MASK, R2TAPS);
- if (allP || (((R3&R3MID)!=0) == maj))
- R3 = clockone(R3, R3MASK, R3TAPS);
-#else /* A5_2 */
- bit maj = majority(R4&R4TAP1, R4&R4TAP2, R4&R4TAP3);
- if (allP || (((R4&R4TAP1)!=0) == maj))
- R1 = clockone(R1, R1MASK, R1TAPS, loaded<<15);
- if (allP || (((R4&R4TAP2)!=0) == maj))
- R2 = clockone(R2, R2MASK, R2TAPS, loaded<<16);
- if (allP || (((R4&R4TAP3)!=0) == maj))
- R3 = clockone(R3, R3MASK, R3TAPS, loaded<<18);
- R4 = clockone(R4, R4MASK, R4TAPS, loaded<<10);
-#endif /* A5_2 */
-}
-
-
-/* Generate an output bit from the current state.
- * You grab a bit from each register via the output generation taps;
- * then you XOR the resulting three bits. For A5/2, in addition to
- * the top bit of each of R1,R2,R3, also XOR in a majority function
- * of three particular bits of the register (one of them complemented)
- * to make it non-linear. Also, for A5/2, delay the output by one
- * clock cycle for some reason. */
-bit getbit() {
- bit topbits = (((R1 >> 18) ^ (R2 >> 21) ^ (R3 >> 22)) & 0x01);
-#ifndef A5_2
- return topbits;
-#else /* A5_2 */
- static bit delaybit = 0;
- bit nowbit = delaybit;
- delaybit = (
- topbits
- ^ majority(R1&0x8000, (~R1)&0x4000, R1&0x1000)
- ^ majority((~R2)&0x10000, R2&0x2000, R2&0x200)
- ^ majority(R3&0x40000, R3&0x10000, (~R3)&0x2000)
- );
- return nowbit;
-#endif /* A5_2 */
-}
-
-
-/* Do the A5 key setup. This routine accepts a 64-bit key and
- * a 22-bit frame number. */
-void keysetup(byte key[8], word frame) {
- int i;
- bit keybit, framebit;
-
-
- /* Zero out the shift registers. */
- R1 = R2 = R3 = 0;
-#ifdef A5_2
- R4 = 0;
-#endif /* A5_2 */
-
-
- /* Load the key into the shift registers,
- * LSB of first byte of key array first,
- * clocking each register once for every
- * key bit loaded. (The usual clock
- * control rule is temporarily disabled.) */
- for (i=0; i<64; i++) {
- clock(1,0); /* always clock */
- keybit = (key[i/8] >> (i&7)) & 1; /* The i-th bit of the key */
- R1 ^= keybit; R2 ^= keybit; R3 ^= keybit;
-#ifdef A5_2
- R4 ^= keybit;
-#endif /* A5_2 */
- }
-
-
- /* Load the frame number into the shift registers, LSB first,
- * clocking each register once for every key bit loaded.
- * (The usual clock control rule is still disabled.)
- * For A5/2, signal when the last bit is being clocked in. */
- for (i=0; i<22; i++) {
- clock(1,i==21); /* always clock */
- framebit = (frame >> i) & 1; /* The i-th bit of the frame # */
- R1 ^= framebit; R2 ^= framebit; R3 ^= framebit;
-#ifdef A5_2
- R4 ^= framebit;
-#endif /* A5_2 */
- }
-
-
- /* Run the shift registers for 100 clocks
- * to mix the keying material and frame number
- * together with output generation disabled,
- * so that there is sufficient avalanche.
- * We re-enable the majority-based clock control
- * rule from now on. */
- for (i=0; i<100; i++) {
- clock(0,0);
- }
- /* For A5/2, we have to load the delayed output bit. This does _not_
- * change the state of the registers. For A5/1, this is a no-op. */
- getbit();
-
-
- /* Now the key is properly set up. */
-}
-
-
-/* Generate output. We generate 228 bits of
- * keystream output. The first 114 bits is for
- * the A->B frame; the next 114 bits is for the
- * B->A frame. You allocate a 15-byte buffer
- * for each direction, and this function fills
- * it in. */
-void run(byte AtoBkeystream[], byte BtoAkeystream[]) {
- int i;
-
-
- /* Zero out the output buffers. */
- for (i=0; i<=113/8; i++)
- AtoBkeystream[i] = BtoAkeystream[i] = 0;
-
-
- /* Generate 114 bits of keystream for the
- * A->B direction. Store it, MSB first. */
- for (i=0; i<114; i++) {
- clock(0,0);
- AtoBkeystream[i/8] |= getbit() << (7-(i&7));
- }
-
-
- /* Generate 114 bits of keystream for the
- * B->A direction. Store it, MSB first. */
- for (i=0; i<114; i++) {
- clock(0,0);
- BtoAkeystream[i/8] |= getbit() << (7-(i&7));
- }
-}
-
-
-/* Test the code by comparing it against
- * a known-good test vector. */
-void test() {
-#ifndef A5_2
- byte key[8] = {0x12, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
- word frame = 0x134;
- byte goodAtoB[15] = { 0x53, 0x4E, 0xAA, 0x58, 0x2F, 0xE8, 0x15,
- 0x1A, 0xB6, 0xE1, 0x85, 0x5A, 0x72, 0x8C, 0x00 };
- byte goodBtoA[15] = { 0x24, 0xFD, 0x35, 0xA3, 0x5D, 0x5F, 0xB6,
- 0x52, 0x6D, 0x32, 0xF9, 0x06, 0xDF, 0x1A, 0xC0 };
-#else /* A5_2 */
- byte key[8] = {0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- word frame = 0x21;
- byte goodAtoB[15] = { 0xf4, 0x51, 0x2c, 0xac, 0x13, 0x59, 0x37,
- 0x64, 0x46, 0x0b, 0x72, 0x2d, 0xad, 0xd5, 0x00 };
- byte goodBtoA[15] = { 0x48, 0x00, 0xd4, 0x32, 0x8e, 0x16, 0xa1,
- 0x4d, 0xcd, 0x7b, 0x97, 0x22, 0x26, 0x51, 0x00 };
-#endif /* A5_2 */
- byte AtoB[15], BtoA[15];
- int i, failed=0;
-
-
- keysetup(key, frame);
- run(AtoB, BtoA);
-
-
- /* Compare against the test vector. */
- for (i=0; i<15; i++)
- if (AtoB[i] != goodAtoB[i])
- failed = 1;
- for (i=0; i<15; i++)
- if (BtoA[i] != goodBtoA[i])
- failed = 1;
-
-
- /* Print some debugging output. */
- printf("key: 0x");
- for (i=0; i<8; i++)
- printf("%02X", key[i]);
- printf("\n");
- printf("frame number: 0x%06X\n", (unsigned int)frame);
- printf("known good output:\n");
- printf(" A->B: 0x");
- for (i=0; i<15; i++)
- printf("%02X", goodAtoB[i]);
- printf(" B->A: 0x");
- for (i=0; i<15; i++)
- printf("%02X", goodBtoA[i]);
- printf("\n");
- printf("observed output:\n");
- printf(" A->B: 0x");
- for (i=0; i<15; i++)
- printf("%02X", AtoB[i]);
- printf(" B->A: 0x");
- for (i=0; i<15; i++)
- printf("%02X", BtoA[i]);
- printf("\n");
-
-
- if (!failed) {
- printf("Self-check succeeded: everything looks ok.\n");
- exit(0);
- } else {
- /* Problems! The test vectors didn't compare*/
- printf("\nI don't know why this broke; contact the authors.\n");
- }
-}
-
-
-int main(void) {
- test();
- return 0;
-} \ No newline at end of file
diff --git a/src/lib/gsm.i b/src/lib/gsm.i
index b5a33f2..3a5c561 100644
--- a/src/lib/gsm.i
+++ b/src/lib/gsm.i
@@ -38,7 +38,7 @@
GR_SWIG_BLOCK_MAGIC(gsm,receiver_cf);
-gsm_receiver_cf_sptr gsm_make_receiver_cf ( gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr);
+gsm_receiver_cf_sptr gsm_make_receiver_cf ( gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key);
class gsm_receiver_cf : public gr_block
{
diff --git a/src/lib/gsm_constants.h b/src/lib/gsm_constants.h
index 74d2e2e..939099d 100644
--- a/src/lib/gsm_constants.h
+++ b/src/lib/gsm_constants.h
@@ -9,10 +9,11 @@
#define GUARD_BITS 8
#define GUARD_FRACTIONAL 0.25 //fractional part of guard period
#define GUARD_PERIOD GUARD_BITS + GUARD_FRACTIONAL
-#define DATA_BITS 58 //size of 1 data block in normal burst
+#define DATA_BITS 57 //size of 1 data block in normal burst
+#define STEALING_BIT 1
#define N_TRAIN_BITS 26
#define N_SYNC_BITS 64
-#define USEFUL_BITS 142 //(2*DATA_BITS + N_TRAIN_BITS )
+#define USEFUL_BITS 142 //(2*(DATA_BITS+STEALING_BIT) + N_TRAIN_BITS )
#define FCCH_BITS USEFUL_BITS
#define BURST_SIZE (USEFUL_BITS+2*TAIL_BITS)
@@ -22,7 +23,7 @@
#define FRAME_BITS (TS_PER_FRAME * TS_BITS + 2) // 156.25 * 8
#define FCCH_POS TAIL_BITS
#define SYNC_POS 39
-#define TRAIN_POS ( TAIL_BITS + DATA_BITS + 5) //first 5 bits of a training sequence
+#define TRAIN_POS ( TAIL_BITS + (DATA_BITS+STEALING_BIT) + 5) //first 5 bits of a training sequence
//aren't used for channel impulse response estimation
#define TRAIN_BEGINNING 5
#define SAFETY_MARGIN 6 //
diff --git a/src/lib/gsm_receiver_cf.cc b/src/lib/gsm_receiver_cf.cc
index f94e303..4742b33 100644
--- a/src/lib/gsm_receiver_cf.cc
+++ b/src/lib/gsm_receiver_cf.cc
@@ -33,21 +33,102 @@
#include <numeric>
#include <gsm_receiver_cf.h>
#include <viterbi_detector.h>
+#include <string.h>
#include <sch.h>
+
+#include "RxBurst.h"
+#include "GSMCommon.h"
+
#define SYNC_SEARCH_RANGE 30
-#define TRAIN_SEARCH_RANGE 40
+// #define TRAIN_SEARCH_RANGE 40
+//FIXME: decide to use this define or not
//TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready
+void decrypt(const unsigned char * burst_binary, byte * KC, float * decrypted_data, unsigned FN)
+{
+ byte AtoB[2*DATA_BITS];
+
+ keysetup(KC, FN);
+ runA51(AtoB);
+
+ for (int i = 0; i < 148; i++) {
+ decrypted_data[i] = burst_binary[i];
+ }
+
+ for (int i = 0; i < 57; i++) {
+ decrypted_data[i+3] = AtoB[i] ^ burst_binary[i+3];
+ }
+
+ for (int i = 0; i < 57; i++) {
+ decrypted_data[i+88] = AtoB[i+57] ^ burst_binary[i+88];
+ }
+}
+
+void gsm_receiver_cf::read_key(std::string key)
+{
+ int i;
+ int b;
+ for (i = 0;i < 8;i++) {
+ b = d_hex_to_int[(char)key[(i)*2]]*16 + d_hex_to_int[(char)key[i*2+1]];
+ d_KC[i] = (byte)b;
+ }
+}
+
void gsm_receiver_cf::process_normal_burst(burst_counter burst_nr, const unsigned char * burst_binary)
{
- if (burst_nr.get_timeslot_nr() == 0) {
-// printf(" %2d %6x %6x", burst_nr.get_t2(), burst_nr.get_frame_nr(), burst_nr.get_frame_nr_mod());
-// for (int i = 0; i < BURST_SIZE ; i++) {
-// printf(" %d", burst_binary[i]);
-// }
-// std::cout << "\n";
-// std::cout << " bcc: " << d_bcc << "\n";
+// static byte KC[] = { 0xAD, 0x6A, 0x3E, 0xC2, 0xB4, 0x42, 0xE4, 0x00 };
+// static byte KC[] = { 0x2B, 0x08, 0x74, 0x9F, 0xDD, 0x0D, 0x9C, 0x00 };
+// printf("%x", KC[0]);
+ float decrypted_data[148];
+ unsigned char * voice_frame;
+
+// if (burst_nr.get_timeslot_nr() == 7) {
+ if (burst_nr.get_timeslot_nr() >= 1 && burst_nr.get_timeslot_nr() <= 7) {
+ decrypt(burst_binary, d_KC, decrypted_data, burst_nr.get_frame_nr_mod());
+
+ GSM::Time time(burst_nr.get_frame_nr(), burst_nr.get_timeslot_nr());
+ GSM::RxBurst rxbrst(decrypted_data, time);
+ switch (burst_nr.get_timeslot_nr()) {
+ case 1:
+ if ( d_tch_decoder1.processBurst( rxbrst ) == true) {
+ fwrite(d_tch_decoder1.get_voice_frame(), 1 , 33, d_gsm_file);
+ }
+ break;
+ case 2:
+ if ( d_tch_decoder2.processBurst( rxbrst ) == true) {
+ fwrite(d_tch_decoder2.get_voice_frame(), 1 , 33, d_gsm_file);
+ }
+ break;
+ case 3:
+ if ( d_tch_decoder3.processBurst( rxbrst ) == true) {
+ fwrite(d_tch_decoder3.get_voice_frame(), 1 , 33, d_gsm_file);
+ }
+ break;
+ case 4:
+ if ( d_tch_decoder4.processBurst( rxbrst ) == true) {
+ fwrite(d_tch_decoder4.get_voice_frame(), 1 , 33, d_gsm_file);
+ }
+ break;
+ case 5:
+ if ( d_tch_decoder5.processBurst( rxbrst ) == true) {
+ fwrite(d_tch_decoder5.get_voice_frame(), 1 , 33, d_gsm_file);
+ }
+ break;
+ case 6:
+ if ( d_tch_decoder6.processBurst( rxbrst ) == true) {
+ fwrite(d_tch_decoder6.get_voice_frame(), 1 , 33, d_gsm_file);
+ }
+ break;
+ case 7:
+ if ( d_tch_decoder7.processBurst( rxbrst ) == true) {
+ fwrite(d_tch_decoder7.get_voice_frame(), 1 , 33, d_gsm_file);
+ }
+ break;
+ }
+ }
+
+ if (burst_nr.get_timeslot_nr() == 0) {
GS_process(&d_gs_ctx, TIMESLOT0, 6, &burst_binary[3], burst_nr.get_frame_nr());
}
}
@@ -59,8 +140,24 @@ void gsm_receiver_cf::configure_receiver()
d_channel_conf.set_burst_types(TSC0, TEST_CCH_FRAMES, sizeof(TEST_CCH_FRAMES) / sizeof(unsigned), normal_burst);
d_channel_conf.set_burst_types(TSC0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst);
+ d_channel_conf.set_multiframe_type(TIMESLOT1, multiframe_26);
+ d_channel_conf.set_burst_types(TIMESLOT1, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
+ d_channel_conf.set_multiframe_type(TIMESLOT2, multiframe_26);
+ d_channel_conf.set_burst_types(TIMESLOT2, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
+
+ d_channel_conf.set_multiframe_type(TIMESLOT3, multiframe_26);
+ d_channel_conf.set_burst_types(TIMESLOT3, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
+ d_channel_conf.set_multiframe_type(TIMESLOT4, multiframe_26);
+ d_channel_conf.set_burst_types(TIMESLOT4, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
+
+ d_channel_conf.set_multiframe_type(TIMESLOT5, multiframe_26);
+ d_channel_conf.set_burst_types(TIMESLOT5, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
+ d_channel_conf.set_multiframe_type(TIMESLOT6, multiframe_26);
+ d_channel_conf.set_burst_types(TIMESLOT6, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
+
d_channel_conf.set_multiframe_type(TIMESLOT7, multiframe_26);
d_channel_conf.set_burst_types(TIMESLOT7, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
+
}
@@ -70,9 +167,9 @@ typedef std::vector<float> vector_float;
typedef boost::circular_buffer<float> circular_buffer_float;
gsm_receiver_cf_sptr
-gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr)
+gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key)
{
- return gsm_receiver_cf_sptr(new gsm_receiver_cf(tuner, synchronizer, osr));
+ return gsm_receiver_cf_sptr(new gsm_receiver_cf(tuner, synchronizer, osr, key));
}
static const int MIN_IN = 1; // mininum number of input streams
@@ -83,7 +180,7 @@ static const int MAX_OUT = 1; // maximum number of output streams
/*
* The private constructor
*/
-gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr)
+gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key)
: gr_block("gsm_receiver",
gr_make_io_signature(MIN_IN, MAX_IN, sizeof(gr_complex)),
gr_make_io_signature(MIN_OUT, MAX_OUT, 142 * sizeof(float))),
@@ -95,15 +192,21 @@ gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer,
d_freq_offset(0),
d_state(first_fcch_search),
d_burst_nr(osr),
- d_failed_sch(0)
+ d_failed_sch(0),
+ d_tch_decoder1( GSM::gFACCH_TCHFMapping ),
+ d_tch_decoder2( GSM::gFACCH_TCHFMapping ),
+ d_tch_decoder3( GSM::gFACCH_TCHFMapping ),
+ d_tch_decoder4( GSM::gFACCH_TCHFMapping ),
+ d_tch_decoder5( GSM::gFACCH_TCHFMapping ),
+ d_tch_decoder6( GSM::gFACCH_TCHFMapping ),
+ d_tch_decoder7( GSM::gFACCH_TCHFMapping )
{
int i;
gmsk_mapper(SYNC_BITS, N_SYNC_BITS, d_sch_training_seq, gr_complex(0.0, -1.0));
-
for (i = 0; i < TRAIN_SEQ_NUM; i++) {
gr_complex startpoint;
if (i == 6) { //this is nasty hack
- startpoint = gr_complex(-1.0, 0.0); //if I don't change it here all bits of normal bursts for BTSes with bcc=6 will have negative values
+ startpoint = gr_complex(-1.0, 0.0); //if I don't change it here all bits of normal bursts for BTSes with bcc=6 will have reversed values
} else {
startpoint = gr_complex(1.0, 0.0); //I've checked this hack for bcc==0,1,2,3,4,6
} //I don't know what about bcc==5 and 7 yet
@@ -111,7 +214,25 @@ gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer,
gmsk_mapper(train_seq[i], N_TRAIN_BITS, d_norm_training_seq[i], startpoint);
}
-
+ d_gsm_file = fopen( "speech.gsm", "wb" );
+
+ d_hex_to_int['0'] = 0;
+ d_hex_to_int['4'] = 4;
+ d_hex_to_int['8'] = 8;
+ d_hex_to_int['c'] = 0xc;
+ d_hex_to_int['1'] = 1;
+ d_hex_to_int['5'] = 5;
+ d_hex_to_int['9'] = 9;
+ d_hex_to_int['d'] = 0xd;
+ d_hex_to_int['2'] = 2;
+ d_hex_to_int['6'] = 6;
+ d_hex_to_int['a'] = 0xa;
+ d_hex_to_int['e'] = 0xe;
+ d_hex_to_int['3'] = 3;
+ d_hex_to_int['7'] = 7;
+ d_hex_to_int['b'] = 0xb;
+ d_hex_to_int['f'] = 0xf;
+ read_key(key);
/* Initialize GSM Stack */
GS_new(&d_gs_ctx); //TODO: remove it! it's not a right place for a decoder
}
@@ -153,7 +274,7 @@ gsm_receiver_cf::general_work(int noutput_items,
break;
case next_fcch_search: { //this state is used because it takes some time (a bunch of buffered samples)
- float prev_freq_offset = d_freq_offset; //before previous set_frequqency cause change
+ float prev_freq_offset = d_freq_offset; //before previous set_frequqency cause change
if (find_fcch_burst(input, nitems_items[0])) {
if (abs(prev_freq_offset - d_freq_offset) > FCCH_MAX_FREQ_OFFSET) {
set_frequency(d_freq_offset); //call set_frequncy only frequency offset change is greater than some value
@@ -253,13 +374,13 @@ gsm_receiver_cf::general_work(int noutput_items,
break;
case normal_burst: //if it's normal burst
- burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], TRAIN_SEARCH_RANGE, d_bcc); //get channel impulse response for given training sequence number - d_bcc
+ burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], d_bcc); //get channel impulse response for given training sequence number - d_bcc
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); //MLSE detection of bits
process_normal_burst(d_burst_nr, output_binary); //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready
break;
case dummy_or_normal: {
- burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], TRAIN_SEARCH_RANGE, TS_DUMMY);
+ burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], TS_DUMMY);
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary);
std::vector<unsigned char> v(20);
@@ -268,7 +389,7 @@ gsm_receiver_cf::general_work(int noutput_items,
int different_bits = (it - v.begin());
if (different_bits > 2) {
- burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], TRAIN_SEARCH_RANGE, d_bcc);
+ burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], d_bcc);
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary);
if (!output_binary[0] && !output_binary[1] && !output_binary[2]) {
process_normal_burst(d_burst_nr, output_binary); //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready
@@ -283,7 +404,7 @@ gsm_receiver_cf::general_work(int noutput_items,
break;
case dummy: //if it's dummy
- burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], TRAIN_SEARCH_RANGE, TS_DUMMY); //read dummy
+ burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], TS_DUMMY); //read dummy
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); // but as far as I know it's pointless
break;
case empty: //if it's empty burst
@@ -652,7 +773,7 @@ inline void gsm_receiver_cf::mafi(const gr_complex * input, int nitems, gr_compl
//TODO: get_norm_chan_imp_resp is similar to get_sch_chan_imp_resp - consider joining this two functions
//TODO: this is place where most errors are introduced and can be corrected by improvements to this fuction
//especially computations of strongest_window_nr
-int gsm_receiver_cf::get_norm_chan_imp_resp(const gr_complex *input, gr_complex * chan_imp_resp, unsigned search_range, int bcc)
+int gsm_receiver_cf::get_norm_chan_imp_resp(const gr_complex *input, gr_complex * chan_imp_resp, int bcc)
{
vector_complex correlation_buffer;
vector_float power_buffer;
diff --git a/src/lib/gsm_receiver_cf.h b/src/lib/gsm_receiver_cf.h
index 9454997..21cb1ff 100644
--- a/src/lib/gsm_receiver_cf.h
+++ b/src/lib/gsm_receiver_cf.h
@@ -31,13 +31,17 @@
#include <gsm_receiver_config.h>
#include <gsmstack.h> //TODO: remember to remove this line in the future!
+#include "GSML1FEC.h" //!!
+#include <a5-1-2.h>//!!
+#include <string>//!!
+#include <map>//!!
class gsm_receiver_cf;
typedef boost::shared_ptr<gsm_receiver_cf> gsm_receiver_cf_sptr;
typedef std::vector<gr_complex> vector_complex;
-gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr);
+gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key);
/** GSM Receiver GNU Radio block
*
@@ -50,7 +54,16 @@ gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synch
class gsm_receiver_cf : public gr_block
{
private:
-
+ std::map<char,int> d_hex_to_int;
+ FILE * d_gsm_file; //!!
+ byte d_KC[8]; //!!
+ GSM::TCHFACCHL1Decoder d_tch_decoder1; //!!
+ GSM::TCHFACCHL1Decoder d_tch_decoder2; //!!
+ GSM::TCHFACCHL1Decoder d_tch_decoder3; //!!
+ GSM::TCHFACCHL1Decoder d_tch_decoder4; //!!
+ GSM::TCHFACCHL1Decoder d_tch_decoder5; //!!
+ GSM::TCHFACCHL1Decoder d_tch_decoder6; //!!
+ GSM::TCHFACCHL1Decoder d_tch_decoder7; //!!
/**@name Configuration of the receiver */
//@{
const int d_OSR; ///< oversampling ratio
@@ -104,8 +117,8 @@ class gsm_receiver_cf : public gr_block
// GSM Stack
GS_CTX d_gs_ctx;//TODO: remove it! it'a not right place for a decoder
- friend gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr);
- gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr);
+ friend gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key);
+ gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key);
/** Function whis is used to search a FCCH burst and to compute frequency offset before
* "synchronized" state of the receiver
@@ -209,8 +222,14 @@ class gsm_receiver_cf : public gr_block
* @param bcc base station color code - number of a training sequence
* @return first sample number of normal burst
*/
- int get_norm_chan_imp_resp(const gr_complex * input, gr_complex * chan_imp_resp, unsigned search_range, int bcc);
+ int get_norm_chan_imp_resp(const gr_complex * input, gr_complex * chan_imp_resp, int bcc);
+
+ /**
+ *
+ */
+ void read_key(std::string key);
+
/**
*
*/
@@ -220,6 +239,8 @@ class gsm_receiver_cf : public gr_block
*
*/
void configure_receiver();
+
+
public:
~gsm_receiver_cf();
diff --git a/src/python/gsm_receive.py b/src/python/gsm_receive.py
index 40c1520..4cfb876 100755
--- a/src/python/gsm_receive.py
+++ b/src/python/gsm_receive.py
@@ -6,7 +6,7 @@ from gnuradio.eng_option import eng_option
from optparse import OptionParser
from os import sys
-for extdir in ['../../debug/src/lib','../../debug/src/lib/.libs']:
+for extdir in ['../../debug/src/lib','../../debug/src/lib/.libs','../lib','../lib/.libs','../..debug/src/lib/decoder/openbts/SIP']:
if extdir not in sys.path:
sys.path.append(extdir)
import gsm
@@ -82,7 +82,7 @@ class gsm_receiver_first_blood(gr.top_block):
return interpolator
def _set_receiver(self):
- receiver = gsm.receiver_cf(self.tuner_callback, self.synchronizer_callback, self.options.osr)
+ receiver = gsm.receiver_cf(self.tuner_callback, self.synchronizer_callback, self.options.osr, self.options.key.replace(' ', '').lower())
return receiver
def _process_options(self):
@@ -95,6 +95,9 @@ class gsm_receiver_first_blood(gr.top_block):
help="Input filename")
parser.add_option("-O", "--outputfile", type="string", default="cfile2.out",
help="Output filename")
+ parser.add_option("-k", "--key", type="string", default="2B 08 74 9F DD 0D 9C 00",
+ help="KC session key")
+
(options, args) = parser.parse_args ()
return (options, args)
diff --git a/src/python/gsm_receive_usrp.py b/src/python/gsm_receive_usrp.py
index 7d28633..a4e9720 100755
--- a/src/python/gsm_receive_usrp.py
+++ b/src/python/gsm_receive_usrp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#this file isn't ready to use now - gsm-receiver lacks realtime processing capability
-#there are many underruns of buffer from usrp's samples, many blocks of samples get lost and
+#there are many underruns of buffer for samples from usrp's, many blocks of samples get lost and
#receiver isn't prepared for this situation too well
from gnuradio import gr, gru, blks2
personal git repositories of Harald Welte. Your mileage may vary