struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan, uint32_t fn) { struct msgb *msg; GsmL1_Prim_t *l1p; GsmL1_PhDataReq_t *data_req; GsmL1_MsgUnitParam_t *msu_param; uint8_t *payload_type; uint8_t *l1_payload; int rc; msg = l1p_msgb_alloc(); if (!msg) return NULL; l1p = msgb_l1prim(msg); data_req = &l1p->u.phDataReq; msu_param = &data_req->msgUnitParam; payload_type = &msu_param->u8Buffer[0]; l1_payload = &msu_param->u8Buffer[1]; switch (lchan->tch_mode) { case GSM48_CMODE_SPEECH_AMR: if (lchan->type == GSM_LCHAN_TCH_H && dtx_dl_amr_enabled(lchan)) { /* we have to explicitly handle sending SID FIRST P2 for AMR HR in here */ *payload_type = GsmL1_TchPlType_Amr_SidFirstP2; rc = dtx_dl_amr_fsm_step(lchan, NULL, 0, fn, l1_payload, false, &(msu_param->u8Size), NULL); if (rc == 0) return msg; } *payload_type = GsmL1_TchPlType_Amr; break; case GSM48_CMODE_SPEECH_V1: if (lchan->type == GSM_LCHAN_TCH_F) *payload_type = GsmL1_TchPlType_Fr; else *payload_type = GsmL1_TchPlType_Hr; break; case GSM48_CMODE_SPEECH_EFR: *payload_type = GsmL1_TchPlType_Efr; break; default: msgb_free(msg); return NULL; } rc = repeat_last_sid(lchan, l1_payload, fn); if (!rc) { msgb_free(msg); return NULL; } msu_param->u8Size = rc; return msg; }
static int _l1if_req_compl(struct lc15l1_hdl *fl1h, struct msgb *msg, int is_system_prim, l1if_compl_cb *cb, void *data) { struct wait_l1_conf *wlc; struct osmo_wqueue *wqueue; unsigned int timeout_secs; /* allocate new wsc and store reference to mutex and conf_id */ wlc = talloc_zero(fl1h, struct wait_l1_conf); wlc->cb = cb; wlc->cb_data = data; /* Make sure we actually have received a REQUEST type primitive */ if (is_system_prim == 0) { GsmL1_Prim_t *l1p = msgb_l1prim(msg); LOGP(DL1P, LOGL_INFO, "Tx L1 prim %s\n", get_value_string(lc15bts_l1prim_names, l1p->id)); if (lc15bts_get_l1prim_type(l1p->id) != L1P_T_REQ) { LOGP(DL1C, LOGL_ERROR, "L1 Prim %s is not a Request!\n", get_value_string(lc15bts_l1prim_names, l1p->id)); talloc_free(wlc); return -EINVAL; } wlc->is_sys_prim = 0; wlc->conf_prim_id = lc15bts_get_l1prim_conf(l1p->id); wlc->conf_hLayer3 = l1p_get_hLayer3(l1p); wqueue = &fl1h->write_q[MQ_L1_WRITE]; timeout_secs = 30; } else { Litecell15_Prim_t *sysp = msgb_sysprim(msg); LOGP(DL1C, LOGL_INFO, "Tx SYS prim %s\n", get_value_string(lc15bts_sysprim_names, sysp->id)); if (lc15bts_get_sysprim_type(sysp->id) != L1P_T_REQ) { LOGP(DL1C, LOGL_ERROR, "SYS Prim %s is not a Request!\n", get_value_string(lc15bts_sysprim_names, sysp->id)); talloc_free(wlc); return -EINVAL; } wlc->is_sys_prim = 1; wlc->conf_prim_id = lc15bts_get_sysprim_conf(sysp->id); wqueue = &fl1h->write_q[MQ_SYS_WRITE]; timeout_secs = 30; } /* enqueue the message in the queue and add wsc to list */ if (osmo_wqueue_enqueue(wqueue, msg) != 0) { /* So we will get a timeout but the log message might help */ LOGP(DL1C, LOGL_ERROR, "Write queue for %s full. dropping msg.\n", is_system_prim ? "system primitive" : "gsm"); msgb_free(msg); } llist_add(&wlc->list, &fl1h->wlc_list); /* schedule a timer for timeout_secs seconds. If DSP fails to respond, we terminate */ wlc->timer.data = wlc; wlc->timer.cb = l1if_req_timeout; osmo_timer_schedule(&wlc->timer, timeout_secs, 0); return 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; }
/*! \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; }