diff --git a/src/osmo-bts-trx/scheduler.c b/src/osmo-bts-trx/scheduler.c
index d4af2b7..10f8972 100644
--- a/src/osmo-bts-trx/scheduler.c
+++ b/src/osmo-bts-trx/scheduler.c
@@ -36,27 +36,12 @@
 #include <osmo-bts/rsl.h>
 #include <osmo-bts/l1sap.h>
 
-#include "l1_if.h"
 #include "scheduler.h"
 #include "scheduler_backend.h"
-#include "trx_if.h"
+//#include "trx_if.h"
 
 extern void *tall_bts_ctx;
 
-static struct gsm_bts *bts;
-
-/* clock states */
-static uint32_t transceiver_lost;
-uint32_t transceiver_last_fn;
-static struct timeval transceiver_clock_tv;
-static struct osmo_timer_list transceiver_clock_timer;
-
-/* clock advance for the transceiver */
-uint32_t trx_clock_advance = 20;
-
-/* advance RTS to give some time for data processing. (especially PCU) */
-uint32_t trx_rts_advance = 5; /* about 20ms */
-
 static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 	enum trx_chan_type chan);
 static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
@@ -1460,7 +1445,7 @@ int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink,
 }
 
 /* process ready-to-send */
-static int trx_sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn)
+int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn)
 {
 	struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
 	const struct trx_sched_frame *frame;
@@ -1498,8 +1483,7 @@ static int trx_sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn)
 }
 
 /* process downlink burst */
-static const ubit_t *trx_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn,
-	uint32_t fn)
+const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn)
 {
 	struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
 	struct l1sched_chan_state *l1cs;
@@ -1639,214 +1623,6 @@ next_frame:
 	return 0;
 }
 
-/* schedule all frames of all TRX for given FN */
-static int trx_sched_fn(uint32_t fn)
-{
-	struct gsm_bts_trx *trx;
-	uint8_t tn;
-	const ubit_t *bits;
-	uint8_t gain;
-
-	/* send time indication */
-	l1if_mph_time_ind(bts, fn);
-
-	/* advance frame number, so the transceiver has more time until
-	 * it must be transmitted. */
-	fn = (fn + trx_clock_advance) % GSM_HYPERFRAME;
-
-	/* process every TRX */
-	llist_for_each_entry(trx, &bts->trx_list, list) {
-		struct trx_l1h *l1h = trx_l1h_hdl(trx);
-		struct l1sched_trx *l1t = trx_l1sched_hdl(trx);
-
-		/* we don't schedule, if power is off */
-		if (!trx_if_powered(l1h))
-			continue;
-
-		/* process every TS of TRX */
-		for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
-			/* ready-to-send */
-			trx_sched_rts(l1t, tn,
-				(fn + trx_rts_advance) % GSM_HYPERFRAME);
-			/* get burst for FN */
-			bits = trx_sched_dl_burst(l1t, tn, fn);
-			if (!bits) {
-				/* if no bits, send no burst */
-				continue;
-			} else
-				gain = 0;
-			trx_if_data(l1h, tn, fn, gain, bits);
-		}
-	}
-
-	return 0;
-}
-
-
-/*
- * frame clock
- */
-
-#define FRAME_DURATION_uS	4615
-#define MAX_FN_SKEW		50
-#define TRX_LOSS_FRAMES		400
-
-extern int quit;
-/* this timer fires for every FN to be processed */
-static void trx_ctrl_timer_cb(void *data)
-{
-	struct gsm_bts *bts = data;
-	struct timeval tv_now, *tv_clock = &transceiver_clock_tv;
-	int32_t elapsed;
-
-	/* check if transceiver is still alive */
-	if (transceiver_lost++ == TRX_LOSS_FRAMES) {
-		struct gsm_bts_trx *trx;
-
-		LOGP(DL1C, LOGL_NOTICE, "No more clock from transceiver\n");
-
-no_clock:
-		transceiver_available = 0;
-
-		/* flush pending messages of transceiver */
-		/* close all logical channels and reset timeslots */
-		llist_for_each_entry(trx, &bts->trx_list, list) {
-			trx_if_flush(trx_l1h_hdl(trx));
-			trx_sched_reset(trx_l1sched_hdl(trx));
-			if (trx->nr == 0)
-				trx_if_cmd_poweroff(trx_l1h_hdl(trx));
-		}
-
-		/* tell BSC */
-		check_transceiver_availability(bts, 0);
-
-		return;
-	}
-
-	gettimeofday(&tv_now, NULL);
-
-	elapsed = (tv_now.tv_sec - tv_clock->tv_sec) * 1000000
-		+ (tv_now.tv_usec - tv_clock->tv_usec);
-
-	/* if someone played with clock, or if the process stalled */
-	if (elapsed > FRAME_DURATION_uS * MAX_FN_SKEW || elapsed < 0) {
-		LOGP(DL1C, LOGL_NOTICE, "PC clock skew: elapsed uS %d\n",
-			elapsed);
-		goto no_clock;
-	}
-
-	/* schedule next FN clock */
-	while (elapsed > FRAME_DURATION_uS / 2) {
-		tv_clock->tv_usec += FRAME_DURATION_uS;
-		if (tv_clock->tv_usec >= 1000000) {
-			tv_clock->tv_sec++;
-			tv_clock->tv_usec -= 1000000;
-		}
-		transceiver_last_fn = (transceiver_last_fn + 1) % GSM_HYPERFRAME;
-		trx_sched_fn(transceiver_last_fn);
-		elapsed -= FRAME_DURATION_uS;
-	}
-	osmo_timer_schedule(&transceiver_clock_timer, 0,
-		FRAME_DURATION_uS - elapsed);
-}
-
-
-/* receive clock from transceiver */
-int trx_sched_clock(uint32_t fn)
-{
-	struct timeval tv_now, *tv_clock = &transceiver_clock_tv;
-	int32_t elapsed;
-	int32_t elapsed_fn;
-
-	if (quit)
-		return 0;
-
-	/* reset lost counter */
-	transceiver_lost = 0;
-
-	gettimeofday(&tv_now, NULL);
-
-	/* clock becomes valid */
-	if (!transceiver_available) {
-		LOGP(DL1C, LOGL_NOTICE, "initial GSM clock received: fn=%u\n",
-			fn);
-
-		transceiver_available = 1;
-
-		/* start provisioning transceiver */
-		l1if_provision_transceiver(bts);
-
-		/* tell BSC */
-		check_transceiver_availability(bts, 1);
-
-new_clock:
-		transceiver_last_fn = fn;
-		trx_sched_fn(transceiver_last_fn);
-
-		/* schedule first FN clock */
-		memcpy(tv_clock, &tv_now, sizeof(struct timeval));
-		memset(&transceiver_clock_timer, 0,
-			sizeof(transceiver_clock_timer));
-		transceiver_clock_timer.cb = trx_ctrl_timer_cb;
-	        transceiver_clock_timer.data = bts;
-		osmo_timer_schedule(&transceiver_clock_timer, 0,
-			FRAME_DURATION_uS);
-
-		return 0;
-	}
-
-	osmo_timer_del(&transceiver_clock_timer);
-
-	/* calculate elapsed time since last_fn */
-	elapsed = (tv_now.tv_sec - tv_clock->tv_sec) * 1000000
-		+ (tv_now.tv_usec - tv_clock->tv_usec);
-
-	/* how much frames have been elapsed since last fn processed */
-	elapsed_fn = (fn + GSM_HYPERFRAME - transceiver_last_fn) % GSM_HYPERFRAME;
-	if (elapsed_fn >= 135774)
-		elapsed_fn -= GSM_HYPERFRAME;
-
-	/* check for max clock skew */
-	if (elapsed_fn > MAX_FN_SKEW || elapsed_fn < -MAX_FN_SKEW) {
-		LOGP(DL1C, LOGL_NOTICE, "GSM clock skew: old fn=%u, "
-			"new fn=%u\n", transceiver_last_fn, fn);
-		goto new_clock;
-	}
-
-	LOGP(DL1C, LOGL_INFO, "GSM clock jitter: %d\n",
-		elapsed_fn * FRAME_DURATION_uS - elapsed);
-
-	/* too many frames have been processed already */
-	if (elapsed_fn < 0) {
-		/* set clock to the time or last FN should have been
-		 * transmitted. */
-		tv_clock->tv_sec = tv_now.tv_sec;
-		tv_clock->tv_usec = tv_now.tv_usec +
-			(0 - elapsed_fn) * FRAME_DURATION_uS;
-		if (tv_clock->tv_usec >= 1000000) {
-			tv_clock->tv_sec++;
-			tv_clock->tv_usec -= 1000000;
-		}
-		/* set time to the time our next FN has to be transmitted */
-		osmo_timer_schedule(&transceiver_clock_timer, 0,
-			FRAME_DURATION_uS * (1 - elapsed_fn));
-
-		return 0;
-	}
-
-	/* transmit what we still need to transmit */
-	while (fn != transceiver_last_fn) {
-		transceiver_last_fn = (transceiver_last_fn + 1) % GSM_HYPERFRAME;
-		trx_sched_fn(transceiver_last_fn);
-	}
-
-	/* schedule next FN to be transmitted */
-	memcpy(tv_clock, &tv_now, sizeof(struct timeval));
-	osmo_timer_schedule(&transceiver_clock_timer, 0, FRAME_DURATION_uS);
-
-	return 0;
-}
-
 struct l1sched_ts *l1sched_trx_get_ts(struct l1sched_trx *l1t, uint8_t tn)
 {
 	OSMO_ASSERT(tn < ARRAY_SIZE(l1t->ts));
diff --git a/src/osmo-bts-trx/scheduler.h b/src/osmo-bts-trx/scheduler.h
index c153b9e..13ef051 100644
--- a/src/osmo-bts-trx/scheduler.h
+++ b/src/osmo-bts-trx/scheduler.h
@@ -145,7 +145,7 @@ int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap
 int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap);
 
 /*! \brief PHY informs us of new (current) GSM freme nunmber */
-int trx_sched_clock(uint32_t fn);
+int trx_sched_clock(struct gsm_bts *bts, uint32_t fn);
 
 /*! \brief handle an UL burst received by PHY */
 int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
diff --git a/src/osmo-bts-trx/scheduler_backend.h b/src/osmo-bts-trx/scheduler_backend.h
index ea3e620..b808455 100644
--- a/src/osmo-bts-trx/scheduler_backend.h
+++ b/src/osmo-bts-trx/scheduler_backend.h
@@ -77,3 +77,5 @@ int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 	enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
 	float toa);
 
+const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn);
+int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn);
diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c
index a77f5a5..0aeb835 100644
--- a/src/osmo-bts-trx/scheduler_trx.c
+++ b/src/osmo-bts-trx/scheduler_trx.c
@@ -49,6 +49,18 @@
 
 extern void *tall_bts_ctx;
 
+/* clock states */
+static uint32_t transceiver_lost;
+uint32_t transceiver_last_fn;
+static struct timeval transceiver_clock_tv;
+static struct osmo_timer_list transceiver_clock_timer;
+
+/* clock advance for the transceiver */
+uint32_t trx_clock_advance = 20;
+
+/* advance RTS to give some time for data processing. (especially PCU) */
+uint32_t trx_rts_advance = 5; /* about 20ms */
+
 /* Enable this to multiply TOA of RACH by 10.
  * This is usefull to check tenth of timing advances with RSSI test tool.
  * Note that regular phones will not work when using this test! */
@@ -1238,3 +1250,211 @@ bfi:
 		(fn + GSM_HYPERFRAME - 10 - ((fn%26)==19) - ((fn%26)==20)) % GSM_HYPERFRAME,
 		chan, tch_data, rc);
 }
+
+/* schedule all frames of all TRX for given FN */
+static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn)
+{
+	struct gsm_bts_trx *trx;
+	uint8_t tn;
+	const ubit_t *bits;
+	uint8_t gain;
+
+	/* send time indication */
+	l1if_mph_time_ind(bts, fn);
+
+	/* advance frame number, so the transceiver has more time until
+	 * it must be transmitted. */
+	fn = (fn + trx_clock_advance) % GSM_HYPERFRAME;
+
+	/* process every TRX */
+	llist_for_each_entry(trx, &bts->trx_list, list) {
+		struct trx_l1h *l1h = trx_l1h_hdl(trx);
+		struct l1sched_trx *l1t = trx_l1sched_hdl(trx);
+
+		/* we don't schedule, if power is off */
+		if (!trx_if_powered(l1h))
+			continue;
+
+		/* process every TS of TRX */
+		for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
+			/* ready-to-send */
+			_sched_rts(l1t, tn,
+				(fn + trx_rts_advance) % GSM_HYPERFRAME);
+			/* get burst for FN */
+			bits = _sched_dl_burst(l1t, tn, fn);
+			if (!bits) {
+				/* if no bits, send no burst */
+				continue;
+			} else
+				gain = 0;
+			trx_if_data(l1h, tn, fn, gain, bits);
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+ * frame clock
+ */
+
+#define FRAME_DURATION_uS	4615
+#define MAX_FN_SKEW		50
+#define TRX_LOSS_FRAMES		400
+
+extern int quit;
+/* this timer fires for every FN to be processed */
+static void trx_ctrl_timer_cb(void *data)
+{
+	struct gsm_bts *bts = data;
+	struct timeval tv_now, *tv_clock = &transceiver_clock_tv;
+	int32_t elapsed;
+
+	/* check if transceiver is still alive */
+	if (transceiver_lost++ == TRX_LOSS_FRAMES) {
+		struct gsm_bts_trx *trx;
+
+		LOGP(DL1C, LOGL_NOTICE, "No more clock from transceiver\n");
+
+no_clock:
+		transceiver_available = 0;
+
+		/* flush pending messages of transceiver */
+		/* close all logical channels and reset timeslots */
+		llist_for_each_entry(trx, &bts->trx_list, list) {
+			trx_if_flush(trx_l1h_hdl(trx));
+			trx_sched_reset(trx_l1sched_hdl(trx));
+			if (trx->nr == 0)
+				trx_if_cmd_poweroff(trx_l1h_hdl(trx));
+		}
+
+		/* tell BSC */
+		check_transceiver_availability(bts, 0);
+
+		return;
+	}
+
+	gettimeofday(&tv_now, NULL);
+
+	elapsed = (tv_now.tv_sec - tv_clock->tv_sec) * 1000000
+		+ (tv_now.tv_usec - tv_clock->tv_usec);
+
+	/* if someone played with clock, or if the process stalled */
+	if (elapsed > FRAME_DURATION_uS * MAX_FN_SKEW || elapsed < 0) {
+		LOGP(DL1C, LOGL_NOTICE, "PC clock skew: elapsed uS %d\n",
+			elapsed);
+		goto no_clock;
+	}
+
+	/* schedule next FN clock */
+	while (elapsed > FRAME_DURATION_uS / 2) {
+		tv_clock->tv_usec += FRAME_DURATION_uS;
+		if (tv_clock->tv_usec >= 1000000) {
+			tv_clock->tv_sec++;
+			tv_clock->tv_usec -= 1000000;
+		}
+		transceiver_last_fn = (transceiver_last_fn + 1) % GSM_HYPERFRAME;
+		trx_sched_fn(bts, transceiver_last_fn);
+		elapsed -= FRAME_DURATION_uS;
+	}
+	osmo_timer_schedule(&transceiver_clock_timer, 0,
+		FRAME_DURATION_uS - elapsed);
+}
+
+
+/* receive clock from transceiver */
+int trx_sched_clock(struct gsm_bts *bts, uint32_t fn)
+{
+	struct timeval tv_now, *tv_clock = &transceiver_clock_tv;
+	int32_t elapsed;
+	int32_t elapsed_fn;
+
+	if (quit)
+		return 0;
+
+	/* reset lost counter */
+	transceiver_lost = 0;
+
+	gettimeofday(&tv_now, NULL);
+
+	/* clock becomes valid */
+	if (!transceiver_available) {
+		LOGP(DL1C, LOGL_NOTICE, "initial GSM clock received: fn=%u\n",
+			fn);
+
+		transceiver_available = 1;
+
+		/* start provisioning transceiver */
+		l1if_provision_transceiver(bts);
+
+		/* tell BSC */
+		check_transceiver_availability(bts, 1);
+
+new_clock:
+		transceiver_last_fn = fn;
+		trx_sched_fn(bts, transceiver_last_fn);
+
+		/* schedule first FN clock */
+		memcpy(tv_clock, &tv_now, sizeof(struct timeval));
+		memset(&transceiver_clock_timer, 0,
+			sizeof(transceiver_clock_timer));
+		transceiver_clock_timer.cb = trx_ctrl_timer_cb;
+	        transceiver_clock_timer.data = bts;
+		osmo_timer_schedule(&transceiver_clock_timer, 0,
+			FRAME_DURATION_uS);
+
+		return 0;
+	}
+
+	osmo_timer_del(&transceiver_clock_timer);
+
+	/* calculate elapsed time since last_fn */
+	elapsed = (tv_now.tv_sec - tv_clock->tv_sec) * 1000000
+		+ (tv_now.tv_usec - tv_clock->tv_usec);
+
+	/* how much frames have been elapsed since last fn processed */
+	elapsed_fn = (fn + GSM_HYPERFRAME - transceiver_last_fn) % GSM_HYPERFRAME;
+	if (elapsed_fn >= 135774)
+		elapsed_fn -= GSM_HYPERFRAME;
+
+	/* check for max clock skew */
+	if (elapsed_fn > MAX_FN_SKEW || elapsed_fn < -MAX_FN_SKEW) {
+		LOGP(DL1C, LOGL_NOTICE, "GSM clock skew: old fn=%u, "
+			"new fn=%u\n", transceiver_last_fn, fn);
+		goto new_clock;
+	}
+
+	LOGP(DL1C, LOGL_INFO, "GSM clock jitter: %d\n",
+		elapsed_fn * FRAME_DURATION_uS - elapsed);
+
+	/* too many frames have been processed already */
+	if (elapsed_fn < 0) {
+		/* set clock to the time or last FN should have been
+		 * transmitted. */
+		tv_clock->tv_sec = tv_now.tv_sec;
+		tv_clock->tv_usec = tv_now.tv_usec +
+			(0 - elapsed_fn) * FRAME_DURATION_uS;
+		if (tv_clock->tv_usec >= 1000000) {
+			tv_clock->tv_sec++;
+			tv_clock->tv_usec -= 1000000;
+		}
+		/* set time to the time our next FN has to be transmitted */
+		osmo_timer_schedule(&transceiver_clock_timer, 0,
+			FRAME_DURATION_uS * (1 - elapsed_fn));
+
+		return 0;
+	}
+
+	/* transmit what we still need to transmit */
+	while (fn != transceiver_last_fn) {
+		transceiver_last_fn = (transceiver_last_fn + 1) % GSM_HYPERFRAME;
+		trx_sched_fn(bts, transceiver_last_fn);
+	}
+
+	/* schedule next FN to be transmitted */
+	memcpy(tv_clock, &tv_now, sizeof(struct timeval));
+	osmo_timer_schedule(&transceiver_clock_timer, 0, FRAME_DURATION_uS);
+
+	return 0;
+}
diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c
index 16c9fc7..c9cfaef 100644
--- a/src/osmo-bts-trx/trx_if.c
+++ b/src/osmo-bts-trx/trx_if.c
@@ -121,6 +121,7 @@ static struct osmo_fd trx_ofd_clk;
 /* get clock from clock socket */
 static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what)
 {
+	struct trx_l1h *l1h = ofd->data;
 	char buf[1500];
 	int len;
 	uint32_t fn;
@@ -145,7 +146,7 @@ static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what)
 			"correctly, correcting to fn=%u\n", fn);
 	}
 
-	trx_sched_clock(fn);
+	trx_sched_clock(l1h->trx->bts, fn);
 
 	return 0;
 }
@@ -503,7 +504,7 @@ int trx_if_open(struct trx_l1h *l1h)
 
 	/* open sockets */
 	if (l1h->trx->nr == 0) {
-		rc = trx_udp_open(NULL, &trx_ofd_clk, base_port_local,
+		rc = trx_udp_open(l1h, &trx_ofd_clk, base_port_local,
 			trx_clk_read_cb);
 		if (rc < 0)
 			return rc;
