[24/33] Add SDCCH/SACCH/FACCH messages to PH-/MPH-/TCH-SAP interface
diff mbox

Message ID 1409176492-13269-25-git-send-email-laforge@gnumonks.org
State Superseded
Headers show

Commit Message

Harald Welte Aug. 27, 2014, 9:54 p.m. UTC
From: Andreas Eversberg <jolly@eversberg.eu>

This part moves control channel message primitives from osmo-bts-sysmo to
common part.

In order to control ciphering fo BTS model, CIPHER (MPH_INFO) messages are
used.
---
 src/common/l1sap.c         | 181 ++++++++++++++++++++++++++++++++++++-
 src/osmo-bts-sysmo/l1_if.c | 219 ++++++++++++++++++---------------------------
 2 files changed, 265 insertions(+), 135 deletions(-)

Patch
diff mbox

diff --git a/src/common/l1sap.c b/src/common/l1sap.c
index 9068bb8..14dbde9 100644
--- a/src/common/l1sap.c
+++ b/src/common/l1sap.c
@@ -69,6 +69,54 @@  struct msgb *l1sap_msgb_alloc(unsigned int l2_len)
 	return msg;
 }
 
+static int l1sap_tx_ciph_req(struct gsm_bts_trx *trx, uint8_t chan_nr,
+	uint8_t downlink, uint8_t uplink)
+{
+	struct osmo_phsap_prim l1sap_ciph;
+
+	osmo_prim_init(&l1sap_ciph.oph, SAP_GSM_PH, PRIM_MPH_INFO,
+		PRIM_OP_REQUEST, NULL);
+	l1sap_ciph.u.info.type = PRIM_INFO_ACT_CIPH;
+	l1sap_ciph.u.info.u.ciph_req.chan_nr = chan_nr;
+	l1sap_ciph.u.info.u.ciph_req.downlink = downlink;
+	l1sap_ciph.u.info.u.ciph_req.uplink = uplink;
+
+	return l1sap_down(trx, &l1sap_ciph);
+}
+
+
+/* check if the message is a GSM48_MT_RR_CIPH_M_CMD, and if yes, enable
+ * uni-directional de-cryption on the uplink. We need this ugly layering
+ * violation as we have no way of passing down L3 metadata (RSL CIPHERING CMD)
+ * to this point in L1 */
+static int check_for_ciph_cmd(struct msgb *msg, struct gsm_lchan *lchan,
+	uint8_t chan_nr)
+{
+
+	/* only do this if we are in the right state */
+	switch (lchan->ciph_state) {
+	case LCHAN_CIPH_NONE:
+	case LCHAN_CIPH_RX_REQ:
+		break;
+	default:
+		return 0;
+	}
+
+	/* First byte (Address Field) of LAPDm header) */
+	if (msg->data[0] != 0x03)
+		return 0;
+	/* First byte (protocol discriminator) of RR */
+	if ((msg->data[3] & 0xF) != GSM48_PDISC_RR)
+		return 0;
+	/* 2nd byte (msg type) of RR */
+	if ((msg->data[4] & 0x3F) != GSM48_MT_RR_CIPH_M_CMD)
+		return 0;
+
+	l1sap_tx_ciph_req(lchan->ts->trx, chan_nr, 0, 1);
+
+	return 1;
+}
+
 /* time information received from bts model */
 static int l1sap_info_time_ind(struct gsm_bts_trx *trx,
 	struct osmo_phsap_prim *l1sap,
@@ -193,10 +241,13 @@  static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx,
 {
 	struct msgb *msg = l1sap->oph.msg;
 	struct gsm_time g_time;
+	struct gsm_lchan *lchan;
 	uint8_t chan_nr, link_id;
-	uint8_t tn;
+	uint8_t tn, ss;
 	uint32_t fn;
 	uint8_t *p, *si;
+	struct lapdm_entity *le;
+	struct osmo_phsap_prim pp;
 	int rc;
 
 	chan_nr = rts_ind->chan_nr;
@@ -241,6 +292,52 @@  static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx,
 			memcpy(p, si, GSM_MACBLOCK_LEN);
 		else
 			memcpy(p, fill_frame, GSM_MACBLOCK_LEN);
+	} else if (!(chan_nr & 0x80)) { /* only TCH/F, TCH/H, SDCCH/4 and SDCCH/8 have C5 bit cleared */
+		if (L1SAP_IS_CHAN_TCHH(chan_nr))
+			ss = L1SAP_CHAN2SS_TCHH(chan_nr); /* TCH/H */
+		else if (L1SAP_IS_CHAN_SDCCH4(chan_nr))
+			ss = L1SAP_CHAN2SS_SDCCH4(chan_nr); /* SDCCH/4 */
+		else if (L1SAP_IS_CHAN_SDCCH8(chan_nr))
+			ss = L1SAP_CHAN2SS_SDCCH8(chan_nr); /* SDCCH/8 */
+		else
+			ss = 0; /* TCH/F */
+		lchan = &trx->ts[tn].lchan[ss];
+		if (L1SAP_IS_LINK_SACCH(link_id)) {
+			p = msgb_put(msg, GSM_MACBLOCK_LEN);
+			/* L1-header, if not set/modified by layer 1 */
+			p[0] = lchan->ms_power;
+			p[1] = lchan->rqd_ta;
+			le = &lchan->lapdm_ch.lapdm_acch;
+		} else
+			le = &lchan->lapdm_ch.lapdm_dcch;
+		rc = lapdm_phsap_dequeue_prim(le, &pp);
+		if (rc < 0) {
+			if (L1SAP_IS_LINK_SACCH(link_id)) {
+				/* No SACCH data from LAPDM pending, send SACCH filling */
+				uint8_t *si = lchan_sacch_get(lchan);
+				if (si) {
+					/* The +2 is empty space where the DSP inserts the L1 hdr */
+					memcpy(p + 2, si, GSM_MACBLOCK_LEN - 2);
+				} else
+					memcpy(p + 2, fill_frame, GSM_MACBLOCK_LEN - 2);
+			} else if ((!L1SAP_IS_CHAN_TCHF(chan_nr) && !L1SAP_IS_CHAN_TCHH(chan_nr))
+				|| lchan->rsl_cmode == RSL_CMOD_SPD_SIGN) {
+				/* send fill frame only, if not TCH/x != Signalling, otherwise send empty frame */
+				p = msgb_put(msg, GSM_MACBLOCK_LEN);
+				memcpy(p, fill_frame, GSM_MACBLOCK_LEN);
+			} /* else the message remains empty, so TCH frames are sent */
+		} else {
+			/* The +2 is empty space where the DSP inserts the L1 hdr */
+			if (L1SAP_IS_LINK_SACCH(link_id))
+				memcpy(p + 2, pp.oph.msg->data + 2, GSM_MACBLOCK_LEN - 2);
+			else {
+				p = msgb_put(msg, GSM_MACBLOCK_LEN);
+				memcpy(p, pp.oph.msg->data, GSM_MACBLOCK_LEN);
+				/* check if it is a RR CIPH MODE CMD. if yes, enable RX ciphering */
+				check_for_ciph_cmd(pp.oph.msg, lchan, chan_nr);
+			}
+			msgb_free(pp.oph.msg);
+		}
 	} else if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr)) {
 		p = msgb_put(msg, GSM_MACBLOCK_LEN);
 #warning "TODO: Yet another assumption that BS_AG_BLKS_RES=1"
@@ -352,12 +449,46 @@  static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx,
 	return 0;
 }
 
+/* process radio link timeout counter S */
+static void radio_link_timeout(struct gsm_lchan *lchan, int bad_frame)
+{
+	struct gsm_bts_role_bts *btsb = lchan->ts->trx->bts->role;
+
+	/* if link loss criterion already reached */
+	if (lchan->s == 0) {
+		DEBUGP(DMEAS, "%s radio link counter S already 0.\n",
+			gsm_lchan_name(lchan));
+		return;
+	}
+
+	if (bad_frame) {
+		/* count down radio link counter S */
+		lchan->s--;
+		DEBUGP(DMEAS, "%s counting down radio link counter S=%d\n",
+			gsm_lchan_name(lchan), lchan->s);
+		if (lchan->s == 0)
+			rsl_tx_conn_fail(lchan, RSL_ERR_RADIO_LINK_FAIL);
+		return;
+	}
+
+	if (lchan->s < btsb->radio_link_timeout) {
+		/* count up radio link counter S */
+		lchan->s += 2;
+		if (lchan->s > btsb->radio_link_timeout)
+			lchan->s = btsb->radio_link_timeout;
+		DEBUGP(DMEAS, "%s counting up radio link counter S=%d\n",
+			gsm_lchan_name(lchan), lchan->s);
+	}
+}
+
 /* DATA received from bts model */
 static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
 	 struct osmo_phsap_prim *l1sap, struct ph_data_param *data_ind)
 {
 	struct msgb *msg = l1sap->oph.msg;
 	struct gsm_time g_time;
+	struct gsm_lchan *lchan;
+	struct lapdm_entity *le;
 	uint8_t *data = msg->l2h;
 	int len = msgb_l2len(msg);
 	uint8_t chan_nr, link_id;
@@ -397,7 +528,53 @@  static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
 		return 0;
 	}
 
-	return 0;
+	lchan = &trx->ts[tn].lchan[ss];
+
+	/* bad frame */
+	if (len == 0) {
+		if (L1SAP_IS_LINK_SACCH(link_id))
+			radio_link_timeout(lchan, 1);
+		return -EINVAL;
+	}
+
+	if (L1SAP_IS_LINK_SACCH(link_id)) {
+		radio_link_timeout(lchan, 0);
+		le = &lchan->lapdm_ch.lapdm_acch;
+		/* save the SACCH L1 header in the lchan struct for RSL MEAS RES */
+		if (len < 2) {
+			LOGP(DL1P, LOGL_NOTICE, "SACCH with size %u<2 !?!\n",
+				len);
+			return -EINVAL;
+		}
+		/* Some brilliant engineer decided that the ordering of
+		 * fields on the Um interface is different from the
+		 * order of fields in RLS. See TS 04.04 (Chapter 7.2)
+		 * vs. TS 08.58 (Chapter 9.3.10). */
+		lchan->meas.l1_info[0] = data[0] << 3;
+		lchan->meas.l1_info[0] |= ((data[0] >> 5) & 1) << 2;
+		lchan->meas.l1_info[1] = data[1];
+		lchan->meas.flags |= LC_UL_M_F_L1_VALID;
+	} else
+		le = &lchan->lapdm_ch.lapdm_dcch;
+
+	/* if this is the first valid message after enabling Rx
+	 * decryption, we have to enable Tx encryption */
+	if (lchan->ciph_state == LCHAN_CIPH_RX_CONF) {
+		/* HACK: check if it's an I frame, in order to
+		 * ignore some still buffered/queued UI frames received
+		 * before decryption was enabled */
+		if (data[0] == 0x01 && (data[1] & 0x01) == 0) {
+			l1sap_tx_ciph_req(trx, chan_nr, 1, 0);
+		}
+	}
+
+	/* SDCCH, SACCH and FACCH all go to LAPDm */
+	msgb_pull(msg, (msg->l2h - msg->data));
+	msg->l1h = NULL;
+	lapdm_phsap_up(&l1sap->oph, le);
+
+	/* don't free, because we forwarded data */
+	return 1;
 }
 
 /* TCH received from bts model */
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c
index f17972b..6a6437e 100644
--- a/src/osmo-bts-sysmo/l1_if.c
+++ b/src/osmo-bts-sysmo/l1_if.c
@@ -464,7 +464,11 @@  static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
 	u32Fn = l1sap->u.data.fn;
 	u8Tn = L1SAP_CHAN2TS(chan_nr);
 	subCh = 0x1f;
-	if (L1SAP_IS_CHAN_TCHF(chan_nr)) {
+	if (L1SAP_IS_LINK_SACCH(link_id)) {
+		sapi = GsmL1_Sapi_Sacch;
+		if (!L1SAP_IS_CHAN_TCHF(chan_nr))
+			subCh = l1sap_chan2ss(chan_nr);
+	} else if (L1SAP_IS_CHAN_TCHF(chan_nr)) {
 		if (trx->ts[u8Tn].pchan == GSM_PCHAN_PDCH) {
 			if (L1SAP_IS_PTCCH(u32Fn)) {
 				sapi = GsmL1_Sapi_Ptcch;
@@ -473,7 +477,20 @@  static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
 				sapi = GsmL1_Sapi_Pdtch;
 				u8BlockNbr = L1SAP_FN2MACBLOCK(u32Fn);
 			}
+		} else {
+			sapi = GsmL1_Sapi_FacchF;
+			u8BlockNbr = (u32Fn % 13) >> 2;
 		}
+	} else if (L1SAP_IS_CHAN_TCHH(chan_nr)) {
+		subCh = L1SAP_CHAN2SS_TCHH(chan_nr);
+		sapi = GsmL1_Sapi_FacchH;
+		u8BlockNbr = (u32Fn % 26) >> 3;
+	} else if (L1SAP_IS_CHAN_SDCCH4(chan_nr)) {
+		subCh = L1SAP_CHAN2SS_SDCCH4(chan_nr);
+		sapi = GsmL1_Sapi_Sdcch;
+	} else if (L1SAP_IS_CHAN_SDCCH8(chan_nr)) {
+		subCh = L1SAP_CHAN2SS_SDCCH8(chan_nr);
+		sapi = GsmL1_Sapi_Sdcch;
 	} else if (L1SAP_IS_CHAN_BCCH(chan_nr)) {
 		sapi = GsmL1_Sapi_Bcch;
 	} else if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr)) {
@@ -603,12 +620,27 @@  static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
 static int mph_info_req(struct gsm_bts_trx *trx, struct msgb *msg,
 		        struct osmo_phsap_prim *l1sap)
 {
+	struct femtol1_hdl *fl1 = trx_femtol1_hdl(trx);
 	uint8_t u8Tn, ss;
 	uint8_t chan_nr;
 	struct gsm_lchan *lchan;
 	int rc = 0;
 
 	switch (l1sap->u.info.type) {
+	case PRIM_INFO_ACT_CIPH:
+		chan_nr = l1sap->u.info.u.ciph_req.chan_nr;
+		u8Tn = L1SAP_CHAN2TS(chan_nr);
+		ss = l1sap_chan2ss(chan_nr);
+		lchan = &trx->ts[u8Tn].lchan[ss];
+		if (l1sap->u.info.u.ciph_req.uplink) {
+			l1if_set_ciphering(fl1, lchan, 0);
+			lchan->ciph_state = LCHAN_CIPH_RX_REQ;
+		}
+		if (l1sap->u.info.u.ciph_req.downlink) {
+			l1if_set_ciphering(fl1, lchan, 1);
+			lchan->ciph_state = LCHAN_CIPH_TXRX_REQ;
+		}
+		break;
 	case PRIM_INFO_ACTIVATE:
 	case PRIM_INFO_DEACTIVATE:
 	case PRIM_INFO_MODIFY:
@@ -701,6 +733,40 @@  static uint8_t chan_nr_by_sapi(enum gsm_phys_chan_config pchan,
 	case GsmL1_Sapi_Bcch:
 		cbits = 0x10;
 		break;
+	case GsmL1_Sapi_Sacch:
+		switch(pchan) {
+		case GSM_PCHAN_TCH_F:
+			cbits = 0x01;
+			break;
+		case GSM_PCHAN_TCH_H:
+			cbits = 0x02 + subCh;
+			break;
+		case GSM_PCHAN_CCCH_SDCCH4:
+			cbits = 0x04 + subCh;
+			break;
+		case GSM_PCHAN_SDCCH8_SACCH8C:
+			cbits = 0x08 + subCh;
+			break;
+		default:
+			LOGP(DL1C, LOGL_ERROR, "SACCH for pchan %d?\n",
+				pchan);
+			return 0;
+		}
+		break;
+	case GsmL1_Sapi_Sdcch:
+		switch(pchan) {
+		case GSM_PCHAN_CCCH_SDCCH4:
+			cbits = 0x04 + subCh;
+			break;
+		case GSM_PCHAN_SDCCH8_SACCH8C:
+			cbits = 0x08 + subCh;
+			break;
+		default:
+			LOGP(DL1C, LOGL_ERROR, "SDCCH for pchan %d?\n",
+				pchan);
+			return 0;
+		}
+		break;
 	case GsmL1_Sapi_Agch:
 	case GsmL1_Sapi_Pch:
 		cbits = 0x12;
@@ -723,6 +789,12 @@  static uint8_t chan_nr_by_sapi(enum gsm_phys_chan_config pchan,
 	case GsmL1_Sapi_TchH:
 		cbits = 0x02 + subCh;
 		break;
+	case GsmL1_Sapi_FacchF:
+		cbits = 0x01;
+		break;
+	case GsmL1_Sapi_FacchH:
+		cbits = 0x02 + subCh;
+		break;
 	case GsmL1_Sapi_Ptcch:
 		if (!L1SAP_IS_PTCCH(u32Fn)) {
 			LOGP(DL1C, LOGL_FATAL, "Not expecting PTCCH at frame "
@@ -757,11 +829,8 @@  static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1,
 	struct msgb *resp_msg;
 	GsmL1_PhDataReq_t *data_req;
 	GsmL1_MsgUnitParam_t *msu_param;
-	struct lapdm_entity *le;
-	struct gsm_lchan *lchan;
 	struct gsm_time g_time;
 	uint32_t t3p;
-	struct osmo_phsap_prim pp;
 	int rc;
 	struct osmo_phsap_prim *l1sap;
 	uint8_t chan_nr, link_id;
@@ -772,7 +841,10 @@  static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1,
 		rts_ind->subCh, rts_ind->u8Tn, rts_ind->u32Fn);
 	if (chan_nr) {
 		fn = rts_ind->u32Fn;
-		link_id = 0;
+		if (rts_ind->sapi == GsmL1_Sapi_Sacch)
+			link_id = 0x40;
+		else
+			link_id = 0;
 		rc = msgb_trim(l1p_msg, sizeof(*l1sap));
 		if (rc < 0)
 			MSGB_ABORT(l1p_msg, "No room for primitive\n");
@@ -899,27 +971,6 @@  empty_frame:
 	goto tx;
 }
 
-/* determine LAPDm entity inside LAPDm channel for given L1 sapi */
-static struct lapdm_entity *le_by_l1_sapi(struct lapdm_channel *lc, GsmL1_Sapi_t sapi)
-{
-	switch (sapi) {
-	case GsmL1_Sapi_Sacch:
-		return &lc->lapdm_acch;
-	default:
-		return &lc->lapdm_dcch;
-	}
-}
-
-static uint8_t gen_link_id(GsmL1_Sapi_t l1_sapi, uint8_t lapdm_sapi)
-{
-	uint8_t c_bits = 0;
-
-	if (l1_sapi == GsmL1_Sapi_Sacch)
-		c_bits = 0x40;
-
-	return c_bits | (lapdm_sapi & 7);
-}
-
 static void dump_meas_res(int ll, GsmL1_MeasParam_t *m)
 {
 	LOGPC(DL1C, ll, ", Meas: RSSI %-3.2f dBm,  Qual %-3.2f dB,  "
@@ -943,46 +994,11 @@  static int process_meas_res(struct gsm_lchan *lchan, GsmL1_MeasParam_t *m)
 	return lchan_new_ul_meas(lchan, &ulm);
 }
 
-/* process radio link timeout counter S */
-static void radio_link_timeout(struct gsm_lchan *lchan, int bad_frame)
-{
-	struct gsm_bts_role_bts *btsb = lchan->ts->trx->bts->role;
-
-	/* if link loss criterion already reached */
-	if (lchan->s == 0) {
-		DEBUGP(DMEAS, "%s radio link counter S already 0.\n",
-			gsm_lchan_name(lchan));
-		return;
-	}
-
-	if (bad_frame) {
-		/* count down radio link counter S */
-		lchan->s--;
-		DEBUGP(DMEAS, "%s counting down radio link counter S=%d\n",
-			gsm_lchan_name(lchan), lchan->s);
-		if (lchan->s == 0)
-			rsl_tx_conn_fail(lchan, RSL_ERR_RADIO_LINK_FAIL);
-		return;
-	}
-
-	if (lchan->s < btsb->radio_link_timeout) {
-		/* count up radio link counter S */
-		lchan->s += 2;
-		if (lchan->s > btsb->radio_link_timeout)
-			lchan->s = btsb->radio_link_timeout;
-		DEBUGP(DMEAS, "%s counting up radio link counter S=%d\n",
-			gsm_lchan_name(lchan), lchan->s);
-	}
-}
-
 static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_ind,
 			      struct msgb *l1p_msg)
 {
 	struct gsm_bts_trx *trx = fl1->priv;
-	struct osmo_phsap_prim pp;
 	struct gsm_lchan *lchan;
-	struct lapdm_entity *le;
-	struct msgb *msg;
 	uint8_t chan_nr, link_id;
 	struct osmo_phsap_prim *l1sap;
 	uint32_t fn;
@@ -1002,6 +1018,12 @@  static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
 
 	chan_nr = chan_nr_by_sapi(trx->ts[data_ind->u8Tn].pchan, data_ind->sapi,
 		data_ind->subCh, data_ind->u8Tn, data_ind->u32Fn);
+	if (!chan_nr) {
+		LOGP(DL1C, LOGL_ERROR, "PH-DATA-INDICATION for unknown sapi "
+			"%d\n", data_ind->sapi);
+		msgb_free(l1p_msg);
+		return ENOTSUP;
+	}
 	fn = data_ind->u32Fn;
 	link_id =  (data_ind->sapi == GsmL1_Sapi_Sacch) ? 0x40 : 0x00;
 
@@ -1023,84 +1045,15 @@  static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
 	if (lchan->ho.active == HANDOVER_WAIT_FRAME)
 		handover_frame(lchan);
 
-	switch (data_ind->sapi) {
-	case GsmL1_Sapi_Sacch:
-		radio_link_timeout(lchan, (data_ind->msgUnitParam.u8Size == 0));
-		if (data_ind->msgUnitParam.u8Size == 0)
-			break;
-		/* save the SACCH L1 header in the lchan struct for RSL MEAS RES */
-		if (data_ind->msgUnitParam.u8Size < 2) {
-			LOGP(DL1C, LOGL_NOTICE, "SACCH with size %u<2 !?!\n",
-				data_ind->msgUnitParam.u8Size);
-			break;
-		}
-		/* Some brilliant engineer decided that the ordering of
-		 * fields on the Um interface is different from the
-		 * order of fields in RLS. See TS 04.04 (Chapter 7.2)
-		 * vs. TS 08.58 (Chapter 9.3.10). */
-		lchan->meas.l1_info[0] = data_ind->msgUnitParam.u8Buffer[0] << 3;
-		lchan->meas.l1_info[0] |= ((data_ind->msgUnitParam.u8Buffer[0] >> 5) & 1) << 2;
-		lchan->meas.l1_info[1] = data_ind->msgUnitParam.u8Buffer[1];
-		lchan->meas.flags |= LC_UL_M_F_L1_VALID;
-		/* fall-through */
-	case GsmL1_Sapi_Sdcch:
-	case GsmL1_Sapi_FacchF:
-	case GsmL1_Sapi_FacchH:
-		/* Check and Re-check for the SACCH */
-		if (data_ind->msgUnitParam.u8Size == 0) {
-			LOGP(DL1C, LOGL_NOTICE, "%s %s data is null.\n",
-				gsm_lchan_name(lchan),
-				get_value_string(femtobts_l1sapi_names, data_ind->sapi));
-			break;
-		}
-
-		check_for_first_ciphrd(fl1, &data_ind->msgUnitParam, lchan);
-
-		/* SDCCH, SACCH and FACCH all go to LAPDm */
-		le = le_by_l1_sapi(&lchan->lapdm_ch, data_ind->sapi);
-		/* allocate and fill LAPDm primitive */
-		msg = msgb_alloc_headroom(128, 64, "PH-DATA.ind");
-		osmo_prim_init(&pp.oph, SAP_GSM_PH, PRIM_PH_DATA,
-				PRIM_OP_INDICATION, msg);
-
-		/* copy over actual MAC block */
-		msg->l2h = msgb_put(msg, data_ind->msgUnitParam.u8Size);
-		memcpy(msg->l2h, data_ind->msgUnitParam.u8Buffer,
-			data_ind->msgUnitParam.u8Size);
-
-		/* LAPDm requires those... */
-		pp.u.data.chan_nr = gsm_lchan2chan_nr(lchan);
-		pp.u.data.link_id = gen_link_id(data_ind->sapi, 0);
-
-		/* feed into the LAPDm code of libosmogsm */
-		rc = lapdm_phsap_up(&pp.oph, le);
-		break;
-	case GsmL1_Sapi_TchF:
-	case GsmL1_Sapi_TchH:
+	/* check for TCH */
+	if (data_ind->sapi == GsmL1_Sapi_TchF
+	 || data_ind->sapi == GsmL1_Sapi_TchH) {
 		/* TCH speech frame handling */
 		rc = l1if_tch_rx(trx, chan_nr, l1p_msg);
-		break;
-	case GsmL1_Sapi_Pdtch:
-	case GsmL1_Sapi_Pacch:
-	case GsmL1_Sapi_Ptcch:
-		break;
-	case GsmL1_Sapi_Idle:
-		/* nothing to send */
-		break;
-	default:
-		LOGP(DL1C, LOGL_NOTICE, "Rx PH-DATA.ind for unknown L1 SAPI %s\n",
-			get_value_string(femtobts_l1sapi_names, data_ind->sapi));
-		break;
-	}
-
-	if (!chan_nr) {
-		/* message was handled by old code, not by L1SAP */
 		msgb_free(l1p_msg);
 		return rc;
 	}
 
-	/* if we proceed to this point, the message has to be handled via L1SAP */
-
 	/* get data pointer and length */
 	data = data_ind->msgUnitParam.u8Buffer;
 	len = data_ind->msgUnitParam.u8Size;