Esempio n. 1
0
void lchan_set_state(struct gsm_lchan *lchan, enum gsm_lchan_state state)
{
	DEBUGP(DL1C, "%s state %s -> %s\n",
	       gsm_lchan_name(lchan),
	       gsm_lchans_name(lchan->state),
	       gsm_lchans_name(state));
	lchan->state = state;
}
Esempio n. 2
0
/* receive a L1 uplink measurement from L1 */
int lchan_new_ul_meas(struct gsm_lchan *lchan, struct bts_ul_meas *ulm)
{
	DEBUGP(DMEAS, "%s adding measurement, num_ul_meas=%d\n",
		gsm_lchan_name(lchan), lchan->meas.num_ul_meas);

	if (lchan->state != LCHAN_S_ACTIVE) {
		LOGP(DMEAS, LOGL_NOTICE, "%s measurement during state: %s\n",
			gsm_lchan_name(lchan), gsm_lchans_name(lchan->state));
	}

	if (lchan->meas.num_ul_meas >= ARRAY_SIZE(lchan->meas.uplink)) {
		LOGP(DMEAS, LOGL_NOTICE, "%s no space for uplink measurement\n",
			gsm_lchan_name(lchan));
		return -ENOSPC;
	}

	memcpy(&lchan->meas.uplink[lchan->meas.num_ul_meas++], ulm,
		sizeof(*ulm));

	return 0;
}
Esempio n. 3
0
/* obtain the next to-be transmitted dowlink SACCH frame (L2 hdr + L3); returns pointer to lchan->si buffer */
uint8_t *lchan_sacch_get(struct gsm_lchan *lchan)
{
	uint32_t tmp, i;

	for (i = 0; i < _MAX_SYSINFO_TYPE; i++) {
		tmp = (lchan->si.last + 1 + i) % _MAX_SYSINFO_TYPE;
		if (!(lchan->si.valid & (1 << tmp)))
			continue;
		lchan->si.last = tmp;
		return GSM_LCHAN_SI(lchan, tmp);
	}
	LOGP(DL1P, LOGL_NOTICE, "%s SACCH no SI available\n", gsm_lchan_name(lchan));
	return NULL;
}
Esempio n. 4
0
/*! \brief receive a traffic L1 primitive for a given lchan */
int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
{
	GsmL1_Prim_t *l1p = msgb_l1prim(l1p_msg);
	GsmL1_PhDataInd_t *data_ind = &l1p->u.phDataInd;
	uint8_t payload_type = data_ind->msgUnitParam.u8Buffer[0];
	uint8_t *payload = data_ind->msgUnitParam.u8Buffer + 1;
	uint8_t payload_len, sid_first[7] = {0};
	struct msgb *rmsg = NULL;
	struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)].lchan[l1sap_chan2ss(chan_nr)];

	if (is_recv_only(lchan->abis_ip.speech_mode))
		return -EAGAIN;

	if (data_ind->msgUnitParam.u8Size < 1) {
		LOGP(DL1C, LOGL_ERROR, "chan_nr %d Rx Payload size 0\n",
			chan_nr);
		return -EINVAL;
	}
	payload_len = data_ind->msgUnitParam.u8Size - 1;

	switch (payload_type) {
	case GsmL1_TchPlType_Fr:
#if defined(L1_HAS_EFR) && defined(USE_L1_RTP_MODE)
	case GsmL1_TchPlType_Efr:
#endif
		if (lchan->type != GSM_LCHAN_TCH_F)
			goto err_payload_match;
		break;
	case GsmL1_TchPlType_Hr:
		if (lchan->type != GSM_LCHAN_TCH_H)
			goto err_payload_match;
		break;
	case GsmL1_TchPlType_Amr:
		if (lchan->type != GSM_LCHAN_TCH_H &&
		    lchan->type != GSM_LCHAN_TCH_F)
			goto err_payload_match;
		break;
	case GsmL1_TchPlType_Amr_Onset:
		if (lchan->type != GSM_LCHAN_TCH_H &&
		    lchan->type != GSM_LCHAN_TCH_F)
			goto err_payload_match;
		/* according to 3GPP TS 26.093 ONSET frames precede the first
		   speech frame of a speech burst - set the marker for next RTP
		   frame */
		lchan->rtp_tx_marker = true;
		break;
	case GsmL1_TchPlType_Amr_SidFirstP1:
		if (lchan->type != GSM_LCHAN_TCH_H)
			goto err_payload_match;
		LOGP(DL1C, LOGL_DEBUG, "DTX: received SID_FIRST_P1 from L1 "
		     "(%d bytes)\n", payload_len);
		break;
	case GsmL1_TchPlType_Amr_SidFirstP2:
		if (lchan->type != GSM_LCHAN_TCH_H)
			goto err_payload_match;
		LOGP(DL1C, LOGL_DEBUG, "DTX: received SID_FIRST_P2 from L1 "
		     "(%d bytes)\n", payload_len);
		break;
	case GsmL1_TchPlType_Amr_SidFirstInH:
		if (lchan->type != GSM_LCHAN_TCH_H)
			goto err_payload_match;
		lchan->rtp_tx_marker = true;
		LOGP(DL1C, LOGL_DEBUG, "DTX: received SID_FIRST_INH from L1 "
		     "(%d bytes)\n", payload_len);
		break;
	case GsmL1_TchPlType_Amr_SidUpdateInH:
		if (lchan->type != GSM_LCHAN_TCH_H)
			goto err_payload_match;
		lchan->rtp_tx_marker = true;
		LOGP(DL1C, LOGL_DEBUG, "DTX: received SID_UPDATE_INH from L1 "
		     "(%d bytes)\n", payload_len);
		break;
	default:
		LOGP(DL1C, LOGL_NOTICE, "%s Rx Payload Type %s is unsupported\n",
			gsm_lchan_name(lchan),
			get_value_string(femtobts_tch_pl_names, payload_type));
		break;
	}


	switch (payload_type) {
	case GsmL1_TchPlType_Fr:
		rmsg = l1_to_rtppayload_fr(payload, payload_len, lchan);
		break;
	case GsmL1_TchPlType_Hr:
		rmsg = l1_to_rtppayload_hr(payload, payload_len, lchan);
		break;
#if defined(L1_HAS_EFR) && defined(USE_L1_RTP_MODE)
	case GsmL1_TchPlType_Efr:
		rmsg = l1_to_rtppayload_efr(payload, payload_len, lchan);
		break;
#endif
	case GsmL1_TchPlType_Amr:
		rmsg = l1_to_rtppayload_amr(payload, payload_len, lchan);
		break;
	case GsmL1_TchPlType_Amr_SidFirstP1:
		memcpy(sid_first, payload, payload_len);
		int len = osmo_amr_rtp_enc(sid_first, 0, AMR_SID, AMR_GOOD);
		if (len < 0)
			return 0;
		rmsg = l1_to_rtppayload_amr(sid_first, len, lchan);
		break;
	}

	if (rmsg)
		return add_l1sap_header(trx, rmsg, lchan, chan_nr,
					data_ind->u32Fn);

	return 0;

err_payload_match:
	LOGP(DL1C, LOGL_ERROR, "%s Rx Payload Type %s incompatible with lchan\n",
		gsm_lchan_name(lchan),
		get_value_string(femtobts_tch_pl_names, payload_type));
	return -EINVAL;
}
Esempio n. 5
0
/*! \brief function for incoming RTP via TCH.req
 *  \param[in] rtp_pl buffer containing RTP payload
 *  \param[in] rtp_pl_len length of \a rtp_pl
 *  \param[in] use_cache Use cached payload instead of parsing RTP
 *  \param[in] marker RTP header Marker bit (indicates speech onset)
 *  \returns 0 if encoding result can be sent further to L1 without extra actions
 *           positive value if data is ready AND extra actions are required
 *           negative value otherwise (no data for L1 encoded)
 *
 * This function prepares a msgb with a L1 PH-DATA.req primitive and
 * queues it into lchan->dl_tch_queue.
 *
 * Note that the actual L1 primitive header is not fully initialized
 * yet, as things like the frame number, etc. are unknown at the time we
 * pre-fill the primtive.
 */
int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
		    const uint8_t *rtp_pl, unsigned int rtp_pl_len, uint32_t fn,
		    bool use_cache, bool marker)
{
	uint8_t *payload_type;
	uint8_t *l1_payload, ft;
	int rc = 0;
	bool is_sid = false;

	DEBUGP(DRTP, "%s RTP IN: %s\n", gsm_lchan_name(lchan),
		osmo_hexdump(rtp_pl, rtp_pl_len));

	payload_type = &data[0];
	l1_payload = &data[1];

	switch (lchan->tch_mode) {
	case GSM48_CMODE_SPEECH_V1:
		if (lchan->type == GSM_LCHAN_TCH_F) {
			*payload_type = GsmL1_TchPlType_Fr;
			rc = rtppayload_to_l1_fr(l1_payload,
						 rtp_pl, rtp_pl_len);
			if (rc && lchan->ts->trx->bts->dtxd)
				is_sid = osmo_fr_check_sid(rtp_pl, rtp_pl_len);
		} else{
			*payload_type = GsmL1_TchPlType_Hr;
			rc = rtppayload_to_l1_hr(l1_payload,
						 rtp_pl, rtp_pl_len);
			if (rc && lchan->ts->trx->bts->dtxd)
				is_sid = osmo_hr_check_sid(rtp_pl, rtp_pl_len);
		}
		if (is_sid)
			dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, -1);
		break;
#if defined(L1_HAS_EFR) && defined(USE_L1_RTP_MODE)
	case GSM48_CMODE_SPEECH_EFR:
		*payload_type = GsmL1_TchPlType_Efr;
		rc = rtppayload_to_l1_efr(l1_payload, rtp_pl,
					  rtp_pl_len);
		/* FIXME: detect and save EFR SID */
		break;
#endif
	case GSM48_CMODE_SPEECH_AMR:
		if (use_cache) {
			*payload_type = GsmL1_TchPlType_Amr;
			rtppayload_to_l1_amr(l1_payload, lchan->tch.dtx.cache,
					     lchan->tch.dtx.len, ft);
			*len = lchan->tch.dtx.len + 1;
			return 0;
		}

		rc = dtx_dl_amr_fsm_step(lchan, rtp_pl, rtp_pl_len, fn,
					 l1_payload, marker, len, &ft);
		if (rc < 0)
			return rc;
		if (!dtx_dl_amr_enabled(lchan)) {
			*payload_type = GsmL1_TchPlType_Amr;
			rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len,
					     ft);
			return 0;
		}

		/* DTX DL-specific logic below: */
		switch (lchan->tch.dtx.dl_amr_fsm->state) {
		case ST_ONSET_V:
			*payload_type = GsmL1_TchPlType_Amr_Onset;
			dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0);
			*len = 3;
			return 1;
		case ST_VOICE:
			*payload_type = GsmL1_TchPlType_Amr;
			rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len,
					     ft);
			return 0;
		case ST_SID_F1:
			if (lchan->type == GSM_LCHAN_TCH_H) { /* AMR HR */
				*payload_type = GsmL1_TchPlType_Amr_SidFirstP1;
				rtppayload_to_l1_amr(l1_payload + 2, rtp_pl,
						     rtp_pl_len, ft);
				return 0;
			}
			/* AMR FR */
			*payload_type = GsmL1_TchPlType_Amr;
			rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len,
					     ft);
			return 0;
		case ST_SID_F2:
			*payload_type = GsmL1_TchPlType_Amr;
			rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len,
					     ft);
			return 0;
		case ST_F1_INH:
			*payload_type = GsmL1_TchPlType_Amr_SidFirstInH;
			*len = 3;
			dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0);
			return 1;
		case ST_U_INH:
			*payload_type = GsmL1_TchPlType_Amr_SidUpdateInH;
			*len = 3;
			dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0);
			return 1;
		case ST_SID_U:
			return -EAGAIN;
		case ST_FACCH:
			return -EBADMSG;
		default:
			LOGP(DRTP, LOGL_ERROR, "Unhandled DTX DL AMR FSM state "
			     "%d\n", lchan->tch.dtx.dl_amr_fsm->state);
			return -EINVAL;
		}
		break;
	default:
		/* we don't support CSD modes */
		rc = -1;
		break;
	}

	if (rc < 0) {
		LOGP(DRTP, LOGL_ERROR, "%s unable to parse RTP payload\n",
		     gsm_lchan_name(lchan));
		return -EBADMSG;
	}

	*len = rc + 1;

	DEBUGP(DRTP, "%s RTP->L1: %s\n", gsm_lchan_name(lchan),
		osmo_hexdump(data, *len));
	return 0;
}
Esempio n. 6
0
static int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
{
	uint32_t ber_full_sum = 0;
	uint32_t irssi_full_sum = 0;
	uint32_t ber_sub_sum = 0;
	uint32_t irssi_sub_sum = 0;
	int32_t taqb_sum = 0;
	unsigned int num_meas_sub = 0;
	int i;

	/* if measurement period is not complete, abort */
	if (!is_meas_complete(lchan->ts->pchan, lchan->ts->nr,
			      lchan->nr, fn))
		return 0;

	/* if there are no measurements, skip computation */
	if (lchan->meas.num_ul_meas == 0)
		return 0;

	/* compute the actual measurements */

	/* step 1: add up */
	for (i = 0; i < lchan->meas.num_ul_meas; i++) {
		struct bts_ul_meas *m = &lchan->meas.uplink[i];

		ber_full_sum += m->ber10k;
		irssi_full_sum += m->inv_rssi;
		taqb_sum += m->ta_offs_qbits;

		if (m->is_sub) {
			num_meas_sub++;
			ber_sub_sum += m->ber10k;
			irssi_sub_sum += m->inv_rssi;
		}
	}

	/* step 2: divide */
	ber_full_sum = ber_full_sum / lchan->meas.num_ul_meas;
	irssi_full_sum = irssi_full_sum / lchan->meas.num_ul_meas;
	taqb_sum = taqb_sum / lchan->meas.num_ul_meas;

	if (num_meas_sub) {
		ber_sub_sum = ber_sub_sum / num_meas_sub;
		irssi_sub_sum = irssi_sub_sum / num_meas_sub;
	}

	DEBUGP(DMEAS, "%s Computed TA(% 4dqb) BER-FULL(%2u.%02u%%), RSSI-FULL(-%3udBm), "
		"BER-SUB(%2u.%02u%%), RSSI-SUB(-%3udBm)\n", gsm_lchan_name(lchan),
		taqb_sum, ber_full_sum/100,
		ber_full_sum%100, irssi_full_sum, ber_sub_sum/100, ber_sub_sum%100,
		irssi_sub_sum);

	/* store results */
	lchan->meas.res.rxlev_full = dbm2rxlev((int)irssi_full_sum * -1);
	lchan->meas.res.rxlev_sub = dbm2rxlev((int)irssi_sub_sum * -1);
	lchan->meas.res.rxqual_full = ber10k_to_rxqual(ber_full_sum);
	lchan->meas.res.rxqual_sub = ber10k_to_rxqual(ber_sub_sum);

	lchan->meas.flags |= LC_UL_M_F_RES_VALID;
	lchan->meas.num_ul_meas = 0;

	/* send a signal indicating computation is complete */

	return 1;
}
Esempio n. 7
0
/*! \brief receive a traffic L1 primitive for a given lchan */
int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
{
	GsmL1_Prim_t *l1p = msgb_l1prim(l1p_msg);
	GsmL1_PhDataInd_t *data_ind = &l1p->u.phDataInd;
	uint8_t *payload, payload_type, payload_len, sid_first[9] = { 0 };
	struct msgb *rmsg = NULL;
	struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)].lchan[l1sap_chan2ss(chan_nr)];

	if (is_recv_only(lchan->abis_ip.speech_mode))
		return -EAGAIN;

	if (data_ind->msgUnitParam.u8Size < 1) {
		LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "chan_nr %d Rx Payload size 0\n", chan_nr);
		/* Push empty payload to upper layers */
		rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP");
		return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
					data_ind->measParam.fBer * 10000,
					data_ind->measParam.fLinkQuality * 10);
	}

	payload_type = data_ind->msgUnitParam.u8Buffer[0];
	payload = data_ind->msgUnitParam.u8Buffer + 1;
	payload_len = data_ind->msgUnitParam.u8Size - 1;

	/* clear RTP marker if the marker has previously sent */
	if (!lchan->tch.dtx.is_speech_resume)
		lchan->rtp_tx_marker = false;

	switch (payload_type) {
	case GsmL1_TchPlType_Fr:
	case GsmL1_TchPlType_Efr:
		if (lchan->type != GSM_LCHAN_TCH_F)
			goto err_payload_match;
		break;
	case GsmL1_TchPlType_Hr:
		if (lchan->type != GSM_LCHAN_TCH_H)
			goto err_payload_match;
		break;
	case GsmL1_TchPlType_Amr:
		if (lchan->type != GSM_LCHAN_TCH_H &&
		    lchan->type != GSM_LCHAN_TCH_F)
			goto err_payload_match;
		break;
	case GsmL1_TchPlType_Amr_Onset:
		if (lchan->type != GSM_LCHAN_TCH_H &&
		    lchan->type != GSM_LCHAN_TCH_F)
			goto err_payload_match;
		/* according to 3GPP TS 26.093 ONSET frames precede the first
		   speech frame of a speech burst - set the marker for next RTP
		   frame */
		lchan->tch.dtx.is_speech_resume = true;
		lchan->rtp_tx_marker = true;
		break;
	case GsmL1_TchPlType_Amr_SidFirstP1:
		if (lchan->type != GSM_LCHAN_TCH_H)
			goto err_payload_match;
		LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_P1 from L1 "
		     "(%d bytes)\n", payload_len);
		break;
	case GsmL1_TchPlType_Amr_SidFirstP2:
		if (lchan->type != GSM_LCHAN_TCH_H)
			goto err_payload_match;
		LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_P2 from L1 "
		     "(%d bytes)\n", payload_len);
		break;
	case GsmL1_TchPlType_Amr_SidFirstInH:
		if (lchan->type != GSM_LCHAN_TCH_H)
			goto err_payload_match;
		lchan->tch.dtx.is_speech_resume = true;
		lchan->rtp_tx_marker = true;
		LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_INH from L1 "
		     "(%d bytes)\n", payload_len);
		break;
	case GsmL1_TchPlType_Amr_SidUpdateInH:
		if (lchan->type != GSM_LCHAN_TCH_H)
			goto err_payload_match;
		lchan->tch.dtx.is_speech_resume = true;
		lchan->rtp_tx_marker = true;
		LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_UPDATE_INH from L1 "
		     "(%d bytes)\n", payload_len);
		break;
	default:
		LOGPFN(DL1P, LOGL_NOTICE, data_ind->u32Fn, "%s Rx Payload Type %s is unsupported\n",
			gsm_lchan_name(lchan),
			get_value_string(oc2gbts_tch_pl_names, payload_type));
		break;
	}

	LOGP(DL1P, LOGL_DEBUG, "%s %s lchan->rtp_tx_marker = %s, len=%u\n",
			gsm_lchan_name(lchan),
			get_value_string(oc2gbts_tch_pl_names, payload_type),
			lchan->rtp_tx_marker ? "true" : "false",
			payload_len);

	switch (payload_type) {
	case GsmL1_TchPlType_Fr:
		rmsg = l1_to_rtppayload_fr(payload, payload_len, lchan);
		break;
	case GsmL1_TchPlType_Hr:
		rmsg = l1_to_rtppayload_hr(payload, payload_len, lchan);
		break;
	case GsmL1_TchPlType_Efr:
		rmsg = l1_to_rtppayload_efr(payload, payload_len, lchan);
		break;
	case GsmL1_TchPlType_Amr:
		rmsg = l1_to_rtppayload_amr(payload, payload_len, lchan);
		break;
	case GsmL1_TchPlType_Amr_SidFirstP1:
		memcpy(sid_first, payload, payload_len);
		int len = osmo_amr_rtp_enc(sid_first, 0, AMR_SID, AMR_GOOD);
		if (len < 0)
			return 0;
		rmsg = l1_to_rtppayload_amr(sid_first, len, lchan);
		break;
	}

	if (rmsg)
		return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
					data_ind->measParam.fBer * 10000,
					data_ind->measParam.fLinkQuality * 10);

	return 0;

err_payload_match:
	LOGPFN(DL1P, LOGL_ERROR, data_ind->u32Fn, "%s Rx Payload Type %s incompatible with lchan\n",
		gsm_lchan_name(lchan), get_value_string(oc2gbts_tch_pl_names, payload_type));
	return -EINVAL;
}