diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h index 1cfc97548..de8463659 100644 --- a/include/osmo-bts/bts_model.h +++ b/include/osmo-bts/bts_model.h @@ -28,9 +28,6 @@ int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo, int bts_model_trx_deact_rf(struct gsm_bts_trx *trx); int bts_model_trx_close(struct gsm_bts_trx *trx); -void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, - unsigned int rtp_pl_len); - int bts_model_vty_init(struct gsm_bts *bts); void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts); diff --git a/src/common/l1sap.c b/src/common/l1sap.c index c6318608e..9068bb887 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -286,6 +286,72 @@ static int l1sap_handover_rach(struct gsm_bts_trx *trx, return 0; } +/* TCH-RTS-IND prim recevied from bts model */ +static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, struct ph_tch_param *rts_ind) +{ + struct msgb *resp_msg; + struct osmo_phsap_prim *resp_l1sap, empty_l1sap; + struct gsm_time g_time; + struct gsm_lchan *lchan; + uint8_t chan_nr; + uint8_t tn, ss; + uint32_t fn; + + chan_nr = rts_ind->chan_nr; + fn = rts_ind->fn; + tn = L1SAP_CHAN2TS(chan_nr); + + gsm_fn2gsmtime(&g_time, fn); + + DEBUGP(DL1P, "Rx TCH-RTS.ind %02u/%02u/%02u chan_nr=%d\n", + g_time.t1, g_time.t2, g_time.t3, chan_nr); + + /* get timeslot and subslot */ + tn = L1SAP_CHAN2TS(chan_nr); + if (L1SAP_IS_CHAN_TCHH(chan_nr)) + ss = L1SAP_CHAN2SS_TCHH(chan_nr); /* TCH/H */ + else + ss = 0; /* TCH/F */ + lchan = &trx->ts[tn].lchan[ss]; + + if (!lchan->loopback && lchan->abis_ip.rtp_socket) { + osmo_rtp_socket_poll(lchan->abis_ip.rtp_socket); + /* FIXME: we _assume_ that we never miss TDMA + * frames and that we always get to this point + * for every to-be-transmitted voice frame. A + * better solution would be to compute + * rx_user_ts based on how many TDMA frames have + * elapsed since the last call */ + lchan->abis_ip.rtp_socket->rx_user_ts += GSM_RTP_DURATION; + } + /* get a msgb from the dl_tx_queue */ + resp_msg = msgb_dequeue(&lchan->dl_tch_queue); + if (!resp_msg) { + LOGP(DL1P, LOGL_DEBUG, "%s DL TCH Tx queue underrun\n", + gsm_lchan_name(lchan)); + resp_l1sap = &empty_l1sap; + } else { + resp_msg->l2h = resp_msg->data; + msgb_push(resp_msg, sizeof(*resp_l1sap)); + resp_msg->l1h = resp_msg->data; + resp_l1sap = msgb_l1sap_prim(resp_msg); + } + + memset(resp_l1sap, 0, sizeof(*resp_l1sap)); + osmo_prim_init(&resp_l1sap->oph, SAP_GSM_PH, PRIM_TCH, PRIM_OP_REQUEST, + resp_msg); + resp_l1sap->u.tch.chan_nr = chan_nr; + resp_l1sap->u.tch.fn = fn; + + DEBUGP(DL1P, "Tx TCH.req %02u/%02u/%02u chan_nr=%d\n", + g_time.t1, g_time.t2, g_time.t3, chan_nr); + + l1sap_down(trx, resp_l1sap); + + return 0; +} + /* 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) @@ -334,6 +400,57 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx, return 0; } +/* TCH received from bts model */ +static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap, + struct ph_tch_param *tch_ind) +{ + struct msgb *msg = l1sap->oph.msg; + struct gsm_time g_time; + struct gsm_lchan *lchan; + uint8_t tn, ss, chan_nr; + uint32_t fn; + + chan_nr = tch_ind->chan_nr; + fn = tch_ind->fn; + tn = L1SAP_CHAN2TS(chan_nr); + if (L1SAP_IS_CHAN_TCHH(chan_nr)) + ss = L1SAP_CHAN2SS_TCHH(chan_nr); + else + ss = 0; + lchan = &trx->ts[tn].lchan[ss]; + + gsm_fn2gsmtime(&g_time, fn); + + DEBUGP(DL1P, "Rx TCH.ind %02u/%02u/%02u chan_nr=%d\n", + g_time.t1, g_time.t2, g_time.t3, chan_nr); + + msgb_pull(msg, sizeof(*l1sap)); + + /* hand msg to RTP code for transmission */ + if (lchan->abis_ip.rtp_socket) + osmo_rtp_send_frame(lchan->abis_ip.rtp_socket, + msg->data, msg->len, 160); + + /* if loopback is enabled, also queue received RTP data */ + if (lchan->loopback) { + struct msgb *tmp; + int count = 0; + + /* make sure the queue doesn't get too long */ + llist_for_each_entry(tmp, &lchan->dl_tch_queue, list) + count++; + while (count >= 1) { + tmp = msgb_dequeue(&lchan->dl_tch_queue); + msgb_free(tmp); + count--; + } + + msgb_enqueue(&lchan->dl_tch_queue, msg); + } + + return 0; +} + /* RACH received from bts model */ static int l1sap_ph_rach_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap, struct ph_rach_ind_param *rach_ind) @@ -389,9 +506,15 @@ int l1sap_up(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) case OSMO_PRIM(PRIM_PH_RTS, PRIM_OP_INDICATION): rc = l1sap_ph_rts_ind(trx, l1sap, &l1sap->u.data); break; + case OSMO_PRIM(PRIM_TCH_RTS, PRIM_OP_INDICATION): + rc = l1sap_tch_rts_ind(trx, l1sap, &l1sap->u.tch); + break; case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_INDICATION): rc = l1sap_ph_data_ind(trx, l1sap, &l1sap->u.data); break; + case OSMO_PRIM(PRIM_TCH, PRIM_OP_INDICATION): + rc = l1sap_tch_ind(trx, l1sap, &l1sap->u.tch); + break; case OSMO_PRIM(PRIM_PH_RACH, PRIM_OP_INDICATION): rc = l1sap_ph_rach_ind(trx, l1sap, &l1sap->u.rach_ind); break; @@ -441,6 +564,34 @@ int l1sap_pdch_req(struct gsm_bts_trx_ts *ts, int is_ptcch, uint32_t fn, return l1sap_down(ts->trx, l1sap); } +/*! \brief call-back function for incoming RTP */ +void l1sap_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, + unsigned int rtp_pl_len) +{ + struct gsm_lchan *lchan = rs->priv; + struct msgb *msg, *tmp; + struct osmo_phsap_prim *l1sap; + int count = 0; + + msg = l1sap_msgb_alloc(rtp_pl_len); + if (!msg) + return; + memcpy(msgb_put(msg, rtp_pl_len), rtp_pl, rtp_pl_len); + msgb_pull(msg, sizeof(*l1sap)); + + + /* make sure the queue doesn't get too long */ + llist_for_each_entry(tmp, &lchan->dl_tch_queue, list) + count++; + while (count >= 2) { + tmp = msgb_dequeue(&lchan->dl_tch_queue); + msgb_free(tmp); + count--; + } + + msgb_enqueue(&lchan->dl_tch_queue, msg); +} + static int l1sap_chan_act_dact_modify(struct gsm_bts_trx *trx, uint8_t chan_nr, enum osmo_mph_info_type type, uint8_t sacch_only) { diff --git a/src/common/rsl.c b/src/common/rsl.c index 724bd36e0..0908f1cc5 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -1481,7 +1480,7 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg) OSMO_RTP_P_JITBUF, btsb->rtp_jitter_buf_ms); lchan->abis_ip.rtp_socket->priv = lchan; - lchan->abis_ip.rtp_socket->rx_cb = &bts_model_rtp_rx_cb; + lchan->abis_ip.rtp_socket->rx_cb = &l1sap_rtp_rx_cb; if (connect_ip && connect_port) { /* if CRCX specifies a remote IP, we can bind() diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 0618e03e5..fb54799f6 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -38,8 +38,6 @@ #include #include -#include - #include #include #include @@ -542,6 +540,93 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, return 0; } +static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, + struct osmo_phsap_prim *l1sap) +{ + struct femtol1_hdl *fl1 = trx_femtol1_hdl(trx); + struct gsm_lchan *lchan; + uint32_t u32Fn; + uint8_t u8Tn, subCh, u8BlockNbr = 0, sapi, ss; + uint8_t chan_nr; + GsmL1_Prim_t *l1p; + struct msgb *nmsg; + + chan_nr = l1sap->u.tch.chan_nr; + u32Fn = l1sap->u.tch.fn; + u8Tn = L1SAP_CHAN2TS(chan_nr); + u8BlockNbr = (u32Fn % 13) >> 2; + if (L1SAP_IS_CHAN_TCHH(chan_nr)) { + ss = subCh = L1SAP_CHAN2SS_TCHH(chan_nr); + sapi = GsmL1_Sapi_TchH; + } else { + subCh = 0x1f; + ss = 0; + sapi = GsmL1_Sapi_TchF; + } + + lchan = &trx->ts[u8Tn].lchan[ss]; + + /* create new message and fill data */ + if (msg) { + msgb_pull(msg, sizeof(*l1sap)); + /* create new message */ + nmsg = l1p_msgb_alloc(); + if (!nmsg) + return -ENOMEM; + l1p = msgb_l1prim(nmsg); + l1if_tch_encode(lchan, + l1p->u.phDataReq.msgUnitParam.u8Buffer, + &l1p->u.phDataReq.msgUnitParam.u8Size, + msg->data, msg->len); + } + + /* no message/data, we generate an empty traffic msg */ + if (!nmsg) + nmsg = gen_empty_tch_msg(lchan); + + /* no traffic message, we generate an empty msg */ + if (!nmsg) { + nmsg = l1p_msgb_alloc(); + if (!nmsg) + return -ENOMEM; + } + + l1p = msgb_l1prim(nmsg); + + /* if we provide data, or if data is already in nmsg */ + if (l1p->u.phDataReq.msgUnitParam.u8Size) { + /* data request */ + GsmL1_PhDataReq_t *data_req = &l1p->u.phDataReq; + + l1p->id = GsmL1_PrimId_PhDataReq; + + data_req->hLayer1 = fl1->hLayer1; + data_req->u8Tn = u8Tn; + data_req->u32Fn = u32Fn; + data_req->sapi = sapi; + data_req->subCh = subCh; + data_req->u8BlockNbr = u8BlockNbr; + } else { + /* empty frame */ + GsmL1_PhEmptyFrameReq_t *empty_req = + &l1p->u.phEmptyFrameReq; + + l1p->id = GsmL1_PrimId_PhEmptyFrameReq; + + empty_req->hLayer1 = fl1->hLayer1; + empty_req->u8Tn = u8Tn; + empty_req->u32Fn = u32Fn; + empty_req->sapi = sapi; + empty_req->subCh = subCh; + empty_req->u8BlockNbr = u8BlockNbr; + } + /* send message to DSP's queue */ + osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg); + + msgb_free(msg); + return 0; +} + static int mph_info_req(struct gsm_bts_trx *trx, struct msgb *msg, struct osmo_phsap_prim *l1sap) { @@ -590,6 +675,9 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST): rc = ph_data_req(trx, msg, l1sap); break; + case OSMO_PRIM(PRIM_TCH, PRIM_OP_REQUEST): + rc = ph_tch_req(trx, msg, l1sap); + break; case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_REQUEST): rc = mph_info_req(trx, msg, l1sap); break; @@ -656,6 +744,12 @@ static uint8_t chan_nr_by_sapi(enum gsm_phys_chan_config pchan, return 0; } break; + case GsmL1_Sapi_TchF: + cbits = 0x01; + break; + case GsmL1_Sapi_TchH: + cbits = 0x02 + subCh; + break; case GsmL1_Sapi_Ptcch: if (!L1SAP_IS_PTCCH(u32Fn)) { LOGP(DL1C, LOGL_FATAL, "Not expecting PTCCH at frame " @@ -700,7 +794,6 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, uint8_t chan_nr, link_id; uint32_t fn; - /* check if primitive should be handled by common part */ chan_nr = chan_nr_by_sapi(trx->ts[rts_ind->u8Tn].pchan, rts_ind->sapi, rts_ind->subCh, rts_ind->u8Tn, rts_ind->u32Fn); @@ -711,11 +804,19 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, if (rc < 0) MSGB_ABORT(l1p_msg, "No room for primitive\n"); l1sap = msgb_l1sap_prim(l1p_msg); - osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RTS, - PRIM_OP_INDICATION, l1p_msg); - l1sap->u.data.link_id = link_id; - l1sap->u.data.chan_nr = chan_nr; - l1sap->u.data.fn = fn; + if (rts_ind->sapi == GsmL1_Sapi_TchF + || rts_ind->sapi == GsmL1_Sapi_TchH) { + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH_RTS, + PRIM_OP_INDICATION, l1p_msg); + l1sap->u.tch.chan_nr = chan_nr; + l1sap->u.tch.fn = fn; + } else { + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RTS, + PRIM_OP_INDICATION, l1p_msg); + l1sap->u.data.link_id = link_id; + l1sap->u.data.chan_nr = chan_nr; + l1sap->u.data.fn = fn; + } return l1sap_up(trx, l1sap); } @@ -726,50 +827,6 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, g_time.t1, g_time.t2, g_time.t3, get_value_string(femtobts_l1sapi_names, rts_ind->sapi)); - /* In case of TCH downlink trasnmission, we already have a l1 - * primitive msgb pre-allocated and pre-formatted in the - * dl_tch_queue. All we need to do is to pull it off the queue - * and transmit it */ - switch (rts_ind->sapi) { - case GsmL1_Sapi_TchF: - case GsmL1_Sapi_TchH: - /* resolve the L2 entity using rts_ind->hLayer2 */ - lchan = l1if_hLayer_to_lchan(trx, rts_ind->hLayer2); - if (!lchan) - break; - - if (!lchan->loopback && lchan->abis_ip.rtp_socket) { - osmo_rtp_socket_poll(lchan->abis_ip.rtp_socket); - /* FIXME: we _assume_ that we never miss TDMA - * frames and that we always get to this point - * for every to-be-transmitted voice frame. A - * better solution would be to compute - * rx_user_ts based on how many TDMA frames have - * elapsed since the last call */ - lchan->abis_ip.rtp_socket->rx_user_ts += GSM_RTP_DURATION; - } - /* get a msgb from the dl_tx_queue */ - resp_msg = msgb_dequeue(&lchan->dl_tch_queue); - /* if there is none, try to generate empty TCH frame - * like AMR SID_BAD */ - if (!resp_msg) { - LOGP(DL1C, LOGL_DEBUG, "%s DL TCH Tx queue underrun\n", - gsm_lchan_name(lchan)); - resp_msg = gen_empty_tch_msg(lchan); - /* if there really is none, break here and send empty */ - if (!resp_msg) - break; - } - - /* fill header */ - data_req_from_rts_ind(msgb_l1prim(resp_msg), rts_ind); - /* actually transmit it */ - goto tx; - break; - default: - break; - } - /* in all other cases, we need to allocate a new PH-DATA.ind * primitive msgb and start to fill it */ resp_msg = l1p_msgb_alloc(); @@ -831,12 +888,6 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, msgb_free(pp.oph.msg); } break; - case GsmL1_Sapi_TchF: - case GsmL1_Sapi_TchH: - /* only hit in case we have a RTP underflow, as real TCH - * frames are handled way above */ - goto empty_frame; - break; case GsmL1_Sapi_FacchF: case GsmL1_Sapi_FacchH: /* resolve the L2 entity using rts_ind->hLayer2 */ @@ -1070,7 +1121,7 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i case GsmL1_Sapi_TchF: case GsmL1_Sapi_TchH: /* TCH speech frame handling */ - rc = l1if_tch_rx(lchan, l1p_msg); + rc = l1if_tch_rx(trx, chan_nr, l1p_msg); break; case GsmL1_Sapi_Pdtch: case GsmL1_Sapi_Pacch: diff --git a/src/osmo-bts-sysmo/l1_if.h b/src/osmo-bts-sysmo/l1_if.h index 9acee0be7..56ca239ab 100644 --- a/src/osmo-bts-sysmo/l1_if.h +++ b/src/osmo-bts-sysmo/l1_if.h @@ -110,7 +110,9 @@ uint32_t l1if_lchan_to_hLayer(struct gsm_lchan *lchan); struct gsm_lchan *l1if_hLayer_to_lchan(struct gsm_bts_trx *trx, uint32_t hLayer); /* tch.c */ -int l1if_tch_rx(struct gsm_lchan *lchan, struct msgb *l1p_msg); +void l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, + const uint8_t *rtp_pl, unsigned int rtp_pl_len); +int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg); int l1if_tch_fill(struct gsm_lchan *lchan, uint8_t *l1_buffer); struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan); diff --git a/src/osmo-bts-sysmo/tch.c b/src/osmo-bts-sysmo/tch.c index 9e8903b2f..7cf49e3cf 100644 --- a/src/osmo-bts-sysmo/tch.c +++ b/src/osmo-bts-sysmo/tch.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -425,7 +426,7 @@ static int rtppayload_to_l1_amr(uint8_t *l1_payload, const uint8_t *rtp_payload, #define RTP_MSGB_ALLOC_SIZE 512 -/*! \brief call-back function for incoming RTP +/*! \brief function for incoming RTP via TCH.req * \param rs RTP Socket * \param[in] rtp_pl buffer containing RTP payload * \param[in] rtp_pl_len length of \a rtp_pl @@ -437,34 +438,18 @@ static int rtppayload_to_l1_amr(uint8_t *l1_payload, const uint8_t *rtp_payload, * yet, as things like the frame number, etc. are unknown at the time we * pre-fill the primtive. */ -void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, - unsigned int rtp_pl_len) +void l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, + const uint8_t *rtp_pl, unsigned int rtp_pl_len) { - struct gsm_lchan *lchan = rs->priv; - 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; - /* skip processing of incoming RTP frames if we are in loopback mode */ - if (lchan->loopback) - return; + DEBUGP(DRTP, "%s RTP IN: %s\n", gsm_lchan_name(lchan), + osmo_hexdump(rtp_pl, rtp_pl_len)); - msg = l1p_msgb_alloc(); - if (!msg) { - LOGP(DRTP, LOGL_ERROR, "%s: Failed to allocate Rx payload.\n", - gsm_lchan_name(lchan)); - return; - } - - 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]; + payload_type = &data[0]; + l1_payload = &data[1]; switch (lchan->tch_mode) { case GSM48_CMODE_SPEECH_V1: @@ -499,34 +484,13 @@ void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, if (rc < 0) { LOGP(DRTP, LOGL_ERROR, "%s unable to parse RTP payload\n", gsm_lchan_name(lchan)); - msgb_free(msg); return; } - msu_param->u8Size = rc + 1; + *len = rc + 1; - - /* make sure the number of entries in the dl_tch_queue is never - * more than 3 */ - { - struct msgb *tmp; - int count = 0; - - llist_for_each_entry(tmp, &lchan->dl_tch_queue, list) - count++; - - DEBUGP(DL1C, "%s DL TCH queue length = %u\n", - gsm_lchan_name(lchan), count); - - while (count >= 2) { - tmp = msgb_dequeue(&lchan->dl_tch_queue); - msgb_free(tmp); - count--; - } - } - - /* enqueue msgb to be transmitted to L1 */ - msgb_enqueue(&lchan->dl_tch_queue, msg); + DEBUGP(DRTP, "%s RTP->L1: %s\n", gsm_lchan_name(lchan), + osmo_hexdump(data, *len)); } static int is_recv_only(uint8_t speech_mode) @@ -535,7 +499,7 @@ static int is_recv_only(uint8_t speech_mode) } /*! \brief receive a traffic L1 primitive for a given lchan */ -int l1if_tch_rx(struct gsm_lchan *lchan, struct msgb *l1p_msg) +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; @@ -543,53 +507,18 @@ int l1if_tch_rx(struct gsm_lchan *lchan, struct msgb *l1p_msg) uint8_t *payload = data_ind->msgUnitParam.u8Buffer + 1; uint8_t payload_len; 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, "%s Rx Payload size 0\n", - gsm_lchan_name(lchan)); + LOGP(DL1C, LOGL_ERROR, "chan_nr %d Rx Payload size 0\n", + chan_nr); return -EINVAL; } payload_len = data_ind->msgUnitParam.u8Size - 1; - if (lchan->loopback) { - GsmL1_Prim_t *rl1p; - GsmL1_PhDataReq_t *data_req; - GsmL1_MsgUnitParam_t *msu_param; - - struct msgb *tmp; - int count = 0; - - /* generate a new msgb from the paylaod */ - rmsg = l1p_msgb_alloc(); - if (!rmsg) - return -ENOMEM; - - rl1p = msgb_l1prim(rmsg); - data_req = &rl1p->u.phDataReq; - msu_param = &data_req->msgUnitParam; - - memcpy(msu_param->u8Buffer, - data_ind->msgUnitParam.u8Buffer, - data_ind->msgUnitParam.u8Size); - msu_param->u8Size = data_ind->msgUnitParam.u8Size; - - /* make sure the queue doesn't get too long */ - llist_for_each_entry(tmp, &lchan->dl_tch_queue, list) - count++; - while (count >= 1) { - tmp = msgb_dequeue(&lchan->dl_tch_queue); - msgb_free(tmp); - count--; - } - - msgb_enqueue(&lchan->dl_tch_queue, rmsg); - - return 0; - } - switch (payload_type) { case GsmL1_TchPlType_Fr: #if defined(L1_HAS_EFR) && defined(USE_L1_RTP_MODE) @@ -633,11 +562,20 @@ int l1if_tch_rx(struct gsm_lchan *lchan, struct msgb *l1p_msg) } if (rmsg) { - /* hand rmsg to RTP code for transmission */ - if (lchan->abis_ip.rtp_socket) - osmo_rtp_send_frame(lchan->abis_ip.rtp_socket, - rmsg->data, rmsg->len, 160); - msgb_free(rmsg); + struct osmo_phsap_prim *l1sap; + + LOGP(DL1C, LOGL_DEBUG, "%s Rx -> RTP: %s\n", + gsm_lchan_name(lchan), osmo_hexdump(rmsg->data, rmsg->len)); + + /* add l1sap header */ + rmsg->l2h = rmsg->data; + msgb_push(rmsg, sizeof(*l1sap)); + rmsg->l1h = rmsg->data; + l1sap = msgb_l1sap_prim(rmsg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH, PRIM_OP_INDICATION, rmsg); + l1sap->u.tch.chan_nr = chan_nr; + + return l1sap_up(trx, l1sap); } return 0;