This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/OpenBSC@lists.osmocom.org/.
Andreas Eversberg jolly at eversberg.euInstead of handling primitves itself, sysmo-bts code sends and receives PH-/MPH-/TCH primitves to and from common code. --- src/osmo-bts-sysmo/l1_if.c | 1092 +++++++++++++++++-------------------- src/osmo-bts-sysmo/l1_if.h | 13 +- src/osmo-bts-sysmo/main.c | 3 +- src/osmo-bts-sysmo/oml.c | 46 +- src/osmo-bts-sysmo/sysmobts_vty.c | 94 ---- src/osmo-bts-sysmo/tch.c | 117 +--- 6 files changed, 559 insertions(+), 806 deletions(-) diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 6efb9d6..f2e4440 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -32,21 +32,17 @@ #include <osmocom/core/select.h> #include <osmocom/core/timer.h> #include <osmocom/core/write_queue.h> -#include <osmocom/core/gsmtap.h> -#include <osmocom/core/gsmtap_util.h> #include <osmocom/gsm/gsm_utils.h> #include <osmocom/gsm/lapdm.h> -#include <osmocom/trau/osmo_ortp.h> - #include <osmo-bts/logging.h> #include <osmo-bts/bts.h> #include <osmo-bts/oml.h> -#include <osmo-bts/rsl.h> #include <osmo-bts/gsm_data.h> #include <osmo-bts/paging.h> #include <osmo-bts/measurement.h> #include <osmo-bts/pcu_if.h> +#include <osmo-bts/l1sap.h> #include <sysmocom/femtobts/superfemto.h> #include <sysmocom/femtobts/gsml1prim.h> @@ -63,98 +59,6 @@ extern int pcu_direct; #define MIN_QUAL_RACH 5.0f /* at least 5 dB C/I */ #define MIN_QUAL_NORM -0.5f /* at least -1 dB C/I */ -/* mapping from femtobts L1 SAPI to GSMTAP channel type */ -static const uint8_t l1sapi2gsmtap_cht[GsmL1_Sapi_NUM] = { - [GsmL1_Sapi_Idle] = 255, - [GsmL1_Sapi_Fcch] = 255, - [GsmL1_Sapi_Sch] = 255, - [GsmL1_Sapi_Sacch] = GSMTAP_CHANNEL_SDCCH | GSMTAP_CHANNEL_ACCH, - [GsmL1_Sapi_Sdcch] = GSMTAP_CHANNEL_SDCCH, - [GsmL1_Sapi_Bcch] = GSMTAP_CHANNEL_BCCH, - [GsmL1_Sapi_Pch] = GSMTAP_CHANNEL_PCH, - [GsmL1_Sapi_Agch] = GSMTAP_CHANNEL_AGCH, - [GsmL1_Sapi_Cbch] = GSMTAP_CHANNEL_CBCH51, - [GsmL1_Sapi_Rach] = GSMTAP_CHANNEL_RACH, - [GsmL1_Sapi_TchF] = 255, - [GsmL1_Sapi_FacchF] = GSMTAP_CHANNEL_TCH_F, - [GsmL1_Sapi_TchH] = 255, - [GsmL1_Sapi_FacchH] = GSMTAP_CHANNEL_TCH_H, - [GsmL1_Sapi_Nch] = GSMTAP_CHANNEL_CCCH, - [GsmL1_Sapi_Pdtch] = GSMTAP_CHANNEL_PACCH, - [GsmL1_Sapi_Pacch] = GSMTAP_CHANNEL_PACCH, - [GsmL1_Sapi_Pbcch] = 255, - [GsmL1_Sapi_Pagch] = 255, - [GsmL1_Sapi_Ppch] = 255, - [GsmL1_Sapi_Pnch] = 255, - [GsmL1_Sapi_Ptcch] = GSMTAP_CHANNEL_PTCCH, - [GsmL1_Sapi_Prach] = 255, -}; - -static void tx_to_gsmtap(struct femtol1_hdl *fl1h, struct msgb *msg) -{ - struct gsm_bts_trx *trx = fl1h->priv; - GsmL1_Prim_t *l1p = msgb_l1prim(msg); - GsmL1_PhDataReq_t *data_req = &l1p->u.phDataReq; - - if (fl1h->gsmtap) { - uint8_t ss, chan_type; - if (data_req->subCh == 0x1f) - ss = 0; - else - ss = data_req->subCh; - - if (!(fl1h->gsmtap_sapi_mask & (1 << data_req->sapi))) - return; - - chan_type = l1sapi2gsmtap_cht[data_req->sapi]; - if (chan_type == 255) - return; - - gsmtap_send(fl1h->gsmtap, trx->arfcn, data_req->u8Tn, - chan_type, ss, data_req->u32Fn, 0, 0, - data_req->msgUnitParam.u8Buffer, - data_req->msgUnitParam.u8Size); - } -} - -static void ul_to_gsmtap(struct femtol1_hdl *fl1h, struct msgb *msg) -{ - struct gsm_bts_trx *trx = fl1h->priv; - GsmL1_Prim_t *l1p = msgb_l1prim(msg); - GsmL1_PhDataInd_t *data_ind = &l1p->u.phDataInd; - int skip = 0; - - if (fl1h->gsmtap) { - uint8_t ss, chan_type; - if (data_ind->subCh == 0x1f) - ss = 0; - else - ss = data_ind->subCh; - - if (!(fl1h->gsmtap_sapi_mask & (1 << data_ind->sapi))) - return; - - chan_type = l1sapi2gsmtap_cht[data_ind->sapi]; - if (chan_type == 255) - return; - if (chan_type == GSMTAP_CHANNEL_PACCH - || chan_type == GSMTAP_CHANNEL_PDCH) { - if (data_ind->msgUnitParam.u8Buffer[0] - != GsmL1_PdtchPlType_Full) - return; - skip = 1; - } - - gsmtap_send(fl1h->gsmtap, trx->arfcn | GSMTAP_ARFCN_F_UPLINK, - data_ind->u8Tn, chan_type, ss, data_ind->u32Fn, - data_ind->measParam.fRssi, - data_ind->measParam.fLinkQuality, - data_ind->msgUnitParam.u8Buffer + skip, - data_ind->msgUnitParam.u8Size - skip); - } -} - - struct wait_l1_conf { struct llist_head list; /* internal linked list */ struct osmo_timer_list timer; /* timer for L1 timeout */ @@ -314,74 +218,442 @@ empty_req_from_rts_ind(GsmL1_Prim_t *l1p, return empty_req; } -/* obtain a ptr to the lapdm_channel for a given hLayer2 */ -static struct lapdm_channel * -get_lapdm_chan_by_hl2(struct gsm_bts_trx *trx, uint32_t hLayer2) -{ - struct gsm_lchan *lchan; +static const uint8_t fill_frame[GSM_MACBLOCK_LEN] = { + 0x03, 0x03, 0x01, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, + 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, + 0x2B, 0x2B, 0x2B +}; - lchan = l1if_hLayer_to_lchan(trx, hLayer2); - if (!lchan) - return NULL; +static void dump_meas_res(int ll, GsmL1_MeasParam_t *m) +{ + LOGPC(DL1C, ll, ", Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, " + "BER %-3.2f, Timing %d\n", m->fRssi, m->fLinkQuality, + m->fBer, m->i16BurstTiming); +} - return &lchan->lapdm_ch; +static int process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr, + GsmL1_MeasParam_t *m) +{ + struct osmo_phsap_prim l1sap; + + memset(&l1sap, 0, sizeof(l1sap)); + osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO, + PRIM_OP_INDICATION, NULL); + l1sap.u.info.type = PRIM_INFO_MEAS; + l1sap.u.info.u.meas_ind.chan_nr = chan_nr; + l1sap.u.info.u.meas_ind.ta_offs_qbits = m->i16BurstTiming; + l1sap.u.info.u.meas_ind.ber10k = (unsigned int) (m->fBer * 100); + l1sap.u.info.u.meas_ind.inv_rssi = (uint8_t) (m->fRssi * -1); + + return l1sap_up(trx, &l1sap); } -/* 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 femtol1_hdl *fl1h, - struct msgb *msg, struct gsm_lchan *lchan) +/* primitive from common part */ +int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) { + struct femtol1_hdl *fl1 = trx_femtol1_hdl(trx); + struct msgb *msg = l1sap->oph.msg; + uint32_t u32Fn; + uint8_t u8Tn, subCh, u8BlockNbr = 0, sapi, ss; + uint8_t chan_nr, link_id; + int rc = 0; + struct msgb *nmsg = NULL; + GsmL1_Prim_t *l1p; + struct gsm_lchan *lchan; + + switch (OSMO_PRIM_HDR(&l1sap->oph)) { + case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST): + if (!msg) { + LOGP(DL1C, LOGL_FATAL, "PH-DATA.req without msg. " + "Please fix!\n"); + abort(); + } + chan_nr = l1sap->u.data.chan_nr; + link_id = l1sap->u.data.link_id; + u32Fn = l1sap->u.data.fn; + u8Tn = L1SAP_CHAN2TS(chan_nr); + subCh = 0x1f; + 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; + u8BlockNbr = L1SAP_FN2PTCCHBLOCK(u32Fn); + } else { + 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)) { +#warning Set BS_AG_BLKS_RES + /* The sapi depends on DSP configuration, not + * on the actual SYSTEM INFORMATION 3. */ + u8BlockNbr = L1SAP_FN2CCCHBLOCK(u32Fn); + if (u8BlockNbr >= 1) + sapi = GsmL1_Sapi_Pch; + else + sapi = GsmL1_Sapi_Agch; + } else { + LOGP(DL1C, LOGL_NOTICE, "unknown prim %d op %d " + "chan_nr %d link_id %d\n", l1sap->oph.primitive, + l1sap->oph.operation, chan_nr, link_id); + rc = -EINVAL; + goto done; + } + + msgb_pull(msg, sizeof(*l1sap)); + + /* create new message */ + nmsg = l1p_msgb_alloc(); + l1p = msgb_l1prim(nmsg); + if (msg->len) { + /* data request */ + GsmL1_PhDataReq_t *data_req = &l1p->u.phDataReq; + GsmL1_MsgUnitParam_t *msu_param; + + 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; + msu_param = &data_req->msgUnitParam; + msu_param->u8Size = msg->len; + memcpy(msu_param->u8Buffer, msg->data, msg->len); + } 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); + break; + case OSMO_PRIM(PRIM_TCH, PRIM_OP_REQUEST): + 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) { + rc = -ENOMEM; + goto done; + } + 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) { + rc = -ENOMEM; + goto done; + } + } + + l1p = msgb_l1prim(nmsg); - /* only do this if we are in the right state */ - switch (lchan->ciph_state) { - case LCHAN_CIPH_NONE: - case LCHAN_CIPH_RX_REQ: + /* 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); + break; + case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_REQUEST): + 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.downlink) { + l1if_set_ciphering(fl1, lchan, 1); + lchan->ciph_state = LCHAN_CIPH_RX_REQ; + } + if (l1sap->u.info.u.ciph_req.uplink) { + l1if_set_ciphering(fl1, lchan, 0); + lchan->ciph_state = LCHAN_CIPH_TXRX_REQ; + } + break; + case PRIM_INFO_ACTIVATE: + case PRIM_INFO_DEACTIVATE: + case PRIM_INFO_MODIFY: + chan_nr = l1sap->u.info.u.act_req.chan_nr; + u8Tn = L1SAP_CHAN2TS(chan_nr); + ss = l1sap_chan2ss(chan_nr); + lchan = &trx->ts[u8Tn].lchan[ss]; + if (l1sap->u.info.type == PRIM_INFO_ACTIVATE) + l1if_rsl_chan_act(lchan); + else if (l1sap->u.info.type == PRIM_INFO_MODIFY) + l1if_rsl_mode_modify(lchan); + else if (l1sap->u.info.u.act_req.sacch_only) + l1if_rsl_deact_sacch(lchan); + else + l1if_rsl_chan_rel(lchan); + break; + default: + LOGP(DL1C, LOGL_NOTICE, "unknown MPH-INFO.req %d\n", + l1sap->u.info.type); + rc = -EINVAL; + goto done; + } break; default: - return 0; + LOGP(DL1C, LOGL_NOTICE, "unknown prim %d op %d\n", + l1sap->oph.primitive, l1sap->oph.operation); + rc = -EINVAL; + goto done; } - /* 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) +done: + if (msg) + msgb_free(msg); + return rc; +} + +static int handle_mph_time_ind(struct femtol1_hdl *fl1, + GsmL1_MphTimeInd_t *time_ind) +{ + struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts *bts = trx->bts; + struct osmo_phsap_prim l1sap; + uint32_t fn; + + /* increment the primitive count for the alive timer */ + fl1->alive_prim_cnt++; + + /* ignore every time indication, except for c0 */ + if (trx != bts->c0) { return 0; + } - lchan->ciph_state = LCHAN_CIPH_RX_REQ; - l1if_set_ciphering(fl1h, lchan, 0); + fn = time_ind->u32Fn; - return 1; + memset(&l1sap, 0, sizeof(l1sap)); + osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO, + PRIM_OP_INDICATION, NULL); + l1sap.u.info.type = PRIM_INFO_TIME; + l1sap.u.info.u.time_ind.fn = fn; + + return l1sap_up(trx, &l1sap); } -static const uint8_t fill_frame[GSM_MACBLOCK_LEN] = { - 0x03, 0x03, 0x01, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, - 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, - 0x2B, 0x2B, 0x2B -}; +static uint8_t chan_nr_by_sapi(enum gsm_phys_chan_config pchan, + GsmL1_Sapi_t sapi, GsmL1_SubCh_t subCh, + uint8_t u8Tn, uint32_t u32Fn) +{ + uint8_t cbits = 0; + switch (sapi) { + 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; + break; + case GsmL1_Sapi_TchF: + cbits = 0x01; + break; + 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_Pdtch: + case GsmL1_Sapi_Pacch: + switch(pchan) { + case GSM_PCHAN_PDCH: + cbits = 0x01; + break; + default: + LOGP(DL1C, LOGL_ERROR, "PDTCH for pchan %d?\n", + pchan); + return 0; + } + break; + case GsmL1_Sapi_Ptcch: + if (!L1SAP_IS_PTCCH(u32Fn)) { + LOGP(DL1C, LOGL_FATAL, "Not expecting PTCCH at frame " + "number other than 12, got it at %u (%u). " + "Please fix!\n", u32Fn % 52, u32Fn); + abort(); + } + switch(pchan) { + case GSM_PCHAN_PDCH: + cbits = 0x01; + break; + default: + LOGP(DL1C, LOGL_ERROR, "PTCCH for pchan %d?\n", + pchan); + return 0; + } + break; + default: + return 0; + } + + return (cbits << 3) | u8Tn; +} static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, - GsmL1_PhReadyToSendInd_t *rts_ind) + GsmL1_PhReadyToSendInd_t *rts_ind, + struct msgb *l1p_msg) { struct gsm_bts_trx *trx = fl1->priv; struct gsm_bts *bts = trx->bts; - struct gsm_bts_role_bts *btsb = bts->role; + struct osmo_phsap_prim *l1sap; + struct gsm_time g_time; + uint8_t chan_nr, link_id; + uint32_t fn; + int rc; 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; - uint8_t *si; - struct osmo_phsap_prim pp; - int rc; + + /* in case we need to forward primitive to 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); + if (chan_nr) { + fn = rts_ind->u32Fn; + 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"); + l1sap = msgb_l1sap_prim(l1p_msg); + 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); + } gsm_fn2gsmtime(&g_time, rts_ind->u32Fn); @@ -389,57 +661,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; - case GsmL1_Sapi_Pdtch: - case GsmL1_Sapi_Pacch: - return pcu_tx_rts_req(&trx->ts[rts_ind->u8Tn], 0, - rts_ind->u32Fn, rts_ind->u16Arfcn, rts_ind->u8BlockNbr); - case GsmL1_Sapi_Ptcch: - return pcu_tx_rts_req(&trx->ts[rts_ind->u8Tn], 1, - rts_ind->u32Fn, rts_ind->u16Arfcn, rts_ind->u8BlockNbr); - 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(); @@ -451,6 +672,7 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, switch (rts_ind->sapi) { case GsmL1_Sapi_Sch: + gsm_fn2gsmtime(&g_time, rts_ind->u32Fn); /* compute T3prime */ t3p = (g_time.t3 - 1) / 10; /* fill SCH burst with data */ @@ -460,87 +682,6 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, msu_param->u8Buffer[2] = (g_time.t1 << 7) | (g_time.t2 << 2) | (t3p >> 1); msu_param->u8Buffer[3] = (t3p & 1); break; - case GsmL1_Sapi_Bcch: - /* get them from bts->si_buf[] */ - si = bts_sysinfo_get(bts, &g_time); - if (si) - memcpy(msu_param->u8Buffer, si, GSM_MACBLOCK_LEN); - else - memcpy(msu_param->u8Buffer, fill_frame, GSM_MACBLOCK_LEN); - break; - case GsmL1_Sapi_Sacch: - /* resolve the L2 entity using rts_ind->hLayer2 */ - lchan = l1if_hLayer_to_lchan(trx, rts_ind->hLayer2); - le = &lchan->lapdm_ch.lapdm_acch; - /* if the DSP is taking care of power control - * (ul_power_target==0), then this value will be - * overridden. */ - msu_param->u8Buffer[0] = lchan->ms_power; - rc = lapdm_phsap_dequeue_prim(le, &pp); - if (rc < 0) { - /* No SACCH data from LAPDM pending, send SACCH filling */ - uint8_t *si = lchan_sacch_get(lchan, &g_time); - if (si) { - /* The +2 is empty space where the DSP inserts the L1 hdr */ - memcpy(msu_param->u8Buffer+2, si, GSM_MACBLOCK_LEN-2); - } else - memcpy(msu_param->u8Buffer+2, fill_frame, GSM_MACBLOCK_LEN-2); - } else { - /* The +2 is empty space where the DSP inserts the L1 hdr */ - memcpy(msu_param->u8Buffer+2, pp.oph.msg->data, GSM_MACBLOCK_LEN-2); - msgb_free(pp.oph.msg); - } - break; - case GsmL1_Sapi_Sdcch: - /* resolve the L2 entity using rts_ind->hLayer2 */ - lchan = l1if_hLayer_to_lchan(trx, rts_ind->hLayer2); - le = &lchan->lapdm_ch.lapdm_dcch; - rc = lapdm_phsap_dequeue_prim(le, &pp); - if (rc < 0) - memcpy(msu_param->u8Buffer, fill_frame, GSM_MACBLOCK_LEN); - else { - memcpy(msu_param->u8Buffer, 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(fl1, pp.oph.msg, lchan); - msgb_free(pp.oph.msg); - } - break; - case GsmL1_Sapi_Agch: - /* special queue of messages from IMM ASS CMD */ - { - struct msgb *msg = bts_agch_dequeue(bts); - if (!msg) - memcpy(msu_param->u8Buffer, fill_frame, GSM_MACBLOCK_LEN); - else { - memcpy(msu_param->u8Buffer, msg->data, msg->len); - msgb_free(msg); - } - } - break; - case GsmL1_Sapi_Pch: - rc = paging_gen_msg(btsb->paging_state, msu_param->u8Buffer, &g_time); - 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 */ - lchan = l1if_hLayer_to_lchan(trx, rts_ind->hLayer2); - le = &lchan->lapdm_ch.lapdm_dcch; - rc = lapdm_phsap_dequeue_prim(le, &pp); - if (rc < 0) - goto empty_frame; - else { - memcpy(msu_param->u8Buffer, 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(fl1, pp.oph.msg, lchan); - msgb_free(pp.oph.msg); - } - break; case GsmL1_Sapi_Prach: goto empty_frame; break; @@ -548,13 +689,12 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, memcpy(msu_param->u8Buffer, fill_frame, GSM_MACBLOCK_LEN); break; } -tx: - - tx_to_gsmtap(fl1, resp_msg); +tx: /* transmit */ osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], resp_msg); + msgb_free(l1p_msg); return 0; empty_frame: @@ -564,143 +704,38 @@ empty_frame: goto tx; } -static int handle_mph_time_ind(struct femtol1_hdl *fl1, - GsmL1_MphTimeInd_t *time_ind) -{ - struct gsm_bts_trx *trx = fl1->priv; - struct gsm_bts *bts = trx->bts; - struct gsm_bts_role_bts *btsb = bts->role; - - int frames_expired = time_ind->u32Fn - fl1->gsm_time.fn; - - /* update time on PCU interface */ - pcu_tx_time_ind(time_ind->u32Fn); - - /* Update our data structures with the current GSM time */ - gsm_fn2gsmtime(&fl1->gsm_time, time_ind->u32Fn); - - /* check if the measurement period of some lchan has ended - * and pre-compute the respective measurement */ - trx_meas_check_compute(fl1->priv, time_ind->u32Fn -1); - - /* increment the primitive count for the alive timer */ - fl1->alive_prim_cnt++; - - /* increment number of RACH slots that have passed by since the - * last time indication */ - if (trx == bts->c0) { - unsigned int num_rach_per_frame; - /* 27 / 51 taken from TS 05.01 Figure 3 */ - if (bts->c0->ts[0].pchan == GSM_PCHAN_CCCH_SDCCH4) - num_rach_per_frame = 27; - else - num_rach_per_frame = 51; - - btsb->load.rach.total += frames_expired * num_rach_per_frame; - } - - return 0; -} - -/* 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, " - "BER %-3.2f, Timing %d\n", m->fRssi, m->fLinkQuality, - m->fBer, m->i16BurstTiming); -} - -static int process_meas_res(struct gsm_lchan *lchan, GsmL1_MeasParam_t *m) -{ - struct bts_ul_meas ulm; - - /* in the GPRS case we are not interested in measurement - * processing. The PCU will take care of it */ - if (lchan->type == GSM_LCHAN_PDTCH) - return 0; - - ulm.ta_offs_qbits = m->i16BurstTiming; - ulm.ber10k = (unsigned int) (m->fBer * 100); - ulm.inv_rssi = (uint8_t) (m->fRssi * -1); - - 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; - int rc = 0; - - ul_to_gsmtap(fl1, l1p_msg); + struct osmo_phsap_prim *l1sap; + uint8_t chan_nr, link_id; + uint32_t fn; + uint8_t *data, len; + int rc; - lchan = l1if_hLayer_to_lchan(fl1->priv, data_ind->hLayer2); - if (!lchan) { - LOGP(DL1C, LOGL_ERROR, "unable to resolve lchan by hLayer2\n"); - return -ENODEV; + /* chan_nr and link_id */ + 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); + return ENOTSUP; } + fn = data_ind->u32Fn; + if (data_ind->sapi == GsmL1_Sapi_Sacch) + link_id = 0x40; + else + link_id = 0; - process_meas_res(lchan, &data_ind->measParam); + /* uplink measurement */ + process_meas_res(trx, chan_nr, &data_ind->measParam); if (data_ind->measParam.fLinkQuality < fl1->min_qual_norm - && data_ind->msgUnitParam.u8Size != 0) - return 0; + && data_ind->msgUnitParam.u8Size != 0) { + msgb_free(l1p_msg); + return 0; + } DEBUGP(DL1C, "Rx PH-DATA.ind %s (hL2 %08x): %s", get_value_string(femtobts_l1sapi_names, data_ind->sapi), @@ -709,165 +744,85 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i data_ind->msgUnitParam.u8Size)); dump_meas_res(LOGL_DEBUG, &data_ind->measParam); - 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; - } - - /* 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_ind->msgUnitParam.u8Buffer[0] == 0x01 && - (data_ind->msgUnitParam.u8Buffer[1] & 0x01) == 0) { - l1if_set_ciphering(fl1, lchan, 1); - lchan->ciph_state = LCHAN_CIPH_TXRX_REQ; - } - } - - /* 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: - /* TCH speech frame handling */ - rc = l1if_tch_rx(lchan, l1p_msg); - break; - case GsmL1_Sapi_Pdtch: - case GsmL1_Sapi_Pacch: - /* drop incomplete UL block */ - if (!data_ind->msgUnitParam.u8Size - || data_ind->msgUnitParam.u8Buffer[0] - != GsmL1_PdtchPlType_Full) - break; - /* PDTCH / PACCH frame handling */ - rc = pcu_tx_data_ind(&trx->ts[data_ind->u8Tn], 0, - data_ind->u32Fn, data_ind->u16Arfcn, - data_ind->u8BlockNbr, - data_ind->msgUnitParam.u8Buffer + 1, - data_ind->msgUnitParam.u8Size - 1, - (int8_t) (data_ind->measParam.fRssi)); - break; - case GsmL1_Sapi_Ptcch: - /* PTCCH frame handling */ - rc = pcu_tx_data_ind(&trx->ts[data_ind->u8Tn], 1, - data_ind->u32Fn, data_ind->u16Arfcn, - data_ind->u8BlockNbr, - data_ind->msgUnitParam.u8Buffer, - data_ind->msgUnitParam.u8Size, - (int8_t) (data_ind->measParam.fRssi)); - 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; - } - - return rc; + /* check for TCH */ + if (data_ind->sapi == GsmL1_Sapi_TchF + || data_ind->sapi == GsmL1_Sapi_TchH) { + /* TCH speech frame handling */ + return l1if_tch_rx(trx, chan_nr, l1p_msg); + } + + /* get data pointer and length */ + data = data_ind->msgUnitParam.u8Buffer; + len = data_ind->msgUnitParam.u8Size; + /* pull lower header part before data */ + msgb_pull(l1p_msg, data - l1p_msg->data); + /* trim remaining data to it's size, to get rid of upper header part */ + rc = msgb_trim(l1p_msg, len); + if (rc < 0) + MSGB_ABORT(l1p_msg, "No room for primitive data\n"); + l1p_msg->l2h = l1p_msg->data; + /* push new l1 header */ + l1p_msg->l1h = msgb_push(l1p_msg, sizeof(*l1sap)); + /* fill header */ + l1sap = msgb_l1sap_prim(l1p_msg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_DATA, 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); } -static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind) +static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind, + struct msgb *l1p_msg) { struct gsm_bts_trx *trx = fl1->priv; struct gsm_bts *bts = trx->bts; struct gsm_bts_role_bts *btsb = bts->role; - struct osmo_phsap_prim pp; - struct lapdm_channel *lc; - uint8_t acc_delay; + struct osmo_phsap_prim *l1sap; + uint32_t fn; + uint8_t ra, acc_delay; + int rc; /* increment number of busy RACH slots, if required */ if (trx == bts->c0 && ra_ind->measParam.fRssi >= btsb->load.rach.busy_thresh) btsb->load.rach.busy++; - if (ra_ind->measParam.fLinkQuality < fl1->min_qual_rach) + if (ra_ind->measParam.fLinkQuality < fl1->min_qual_rach) { + msgb_free(l1p_msg); return 0; + } - /* increment number of RACH slots with valid RACH burst */ - if (trx == bts->c0) - btsb->load.rach.access++; - - DEBUGP(DL1C, "Rx PH-RA.ind"); dump_meas_res(LOGL_DEBUG, &ra_ind->measParam); - lc = get_lapdm_chan_by_hl2(fl1->priv, ra_ind->hLayer2); - if (!lc) { - LOGP(DL1C, LOGL_ERROR, "unable to resolve LAPD channel by hLayer2\n"); - return -ENODEV; + if (ra_ind->msgUnitParam.u8Size != 1) { + LOGP(DL1C, LOGL_ERROR, "PH-RACH-INDICATION has %d bits\n", + ra_ind->sapi); + msgb_free(l1p_msg); + return 0; } + fn = ra_ind->u32Fn; + ra = ra_ind->msgUnitParam.u8Buffer[0]; /* check for under/overflow / sign */ if (ra_ind->measParam.i16BurstTiming < 0) acc_delay = 0; else acc_delay = ra_ind->measParam.i16BurstTiming >> 2; - if (acc_delay > btsb->max_ta) { - LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n", - acc_delay, btsb->max_ta); - return 0; - } - - /* check for packet access */ - if (trx == bts->c0 - && (ra_ind->msgUnitParam.u8Buffer[0] & 0xf0) == 0x70) { - LOGP(DL1C, LOGL_INFO, "RACH for packet access\n"); - return pcu_tx_rach_ind(bts, ra_ind->measParam.i16BurstTiming, - ra_ind->msgUnitParam.u8Buffer[0], ra_ind->u32Fn); - } - - osmo_prim_init(&pp.oph, SAP_GSM_PH, PRIM_PH_RACH, - PRIM_OP_INDICATION, NULL); - - pp.u.rach_ind.ra = ra_ind->msgUnitParam.u8Buffer[0]; - pp.u.rach_ind.fn = ra_ind->u32Fn; - pp.u.rach_ind.acc_delay = acc_delay; - - return lapdm_phsap_up(&pp.oph, &lc->lapdm_dcch); + rc = msgb_trim(l1p_msg, sizeof(*l1sap)); + if (rc < 0) + MSGB_ABORT(l1p_msg, "No room for primitive data\n"); + l1sap = msgb_l1sap_prim(l1p_msg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RACH, PRIM_OP_INDICATION, + l1p_msg); + l1sap->u.rach_ind.ra = ra; + l1sap->u.rach_ind.acc_delay = acc_delay; + l1sap->u.rach_ind.fn = fn; + + return l1sap_up(trx, l1sap); } /* handle any random indication from the L1 */ @@ -885,21 +840,19 @@ static int l1if_handle_ind(struct femtol1_hdl *fl1, struct msgb *msg) case GsmL1_PrimId_PhConnectInd: break; case GsmL1_PrimId_PhReadyToSendInd: - rc = handle_ph_readytosend_ind(fl1, &l1p->u.phReadyToSendInd); + return handle_ph_readytosend_ind(fl1, &l1p->u.phReadyToSendInd, msg); break; case GsmL1_PrimId_PhDataInd: - rc = handle_ph_data_ind(fl1, &l1p->u.phDataInd, msg); + return handle_ph_data_ind(fl1, &l1p->u.phDataInd, msg); break; case GsmL1_PrimId_PhRaInd: - rc = handle_ph_ra_ind(fl1, &l1p->u.phRaInd); + return handle_ph_ra_ind(fl1, &l1p->u.phRaInd, msg); break; default: break; } - /* Special return value '1' means: do not free */ - if (rc != 1) - msgb_free(msg); + msgb_free(msg); return rc; } @@ -1203,46 +1156,6 @@ int l1if_set_trace_flags(struct femtol1_hdl *hdl, uint32_t flags) return osmo_wqueue_enqueue(&hdl->write_q[MQ_SYS_WRITE], msg); } -/* send packet data request to L1 */ -int l1if_pdch_req(struct gsm_bts_trx_ts *ts, int is_ptcch, uint32_t fn, - uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len) -{ - struct gsm_bts_trx *trx = ts->trx; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); - struct msgb *msg; - GsmL1_Prim_t *l1p; - GsmL1_PhDataReq_t *data_req; - GsmL1_MsgUnitParam_t *msu_param; - struct gsm_time g_time; - - gsm_fn2gsmtime(&g_time, fn); - - DEBUGP(DL1P, "TX packet data %02u/%02u/%02u is_ptcch=%d trx=%d ts=%d " - "block_nr=%d, arfcn=%d, len=%d\n", g_time.t1, g_time.t2, - g_time.t3, is_ptcch, ts->trx->nr, ts->nr, block_nr, arfcn, len); - - msg = l1p_msgb_alloc(); - l1p = msgb_l1prim(msg); - l1p->id = GsmL1_PrimId_PhDataReq; - data_req = &l1p->u.phDataReq; - data_req->hLayer1 = fl1h->hLayer1; - data_req->sapi = (is_ptcch) ? GsmL1_Sapi_Ptcch : GsmL1_Sapi_Pdtch; - data_req->subCh = GsmL1_SubCh_NA; - data_req->u8BlockNbr = block_nr; - data_req->u8Tn = ts->nr; - data_req->u32Fn = fn; - msu_param = &data_req->msgUnitParam; - msu_param->u8Size = len; - memcpy(msu_param->u8Buffer, data, len); - - tx_to_gsmtap(fl1h, msg); - - /* transmit */ - osmo_wqueue_enqueue(&fl1h->write_q[MQ_L1_WRITE], msg); - - return 0; -} - struct femtol1_hdl *l1if_open(void *priv) { struct femtol1_hdl *fl1h; @@ -1290,10 +1203,6 @@ struct femtol1_hdl *l1if_open(void *priv) return NULL; } - fl1h->gsmtap = gsmtap_source_init("localhost", GSMTAP_UDP_PORT, 1); - if (fl1h->gsmtap) - gsmtap_source_add_sink(fl1h->gsmtap); - return fl1h; } @@ -1304,8 +1213,3 @@ int l1if_close(struct femtol1_hdl *fl1h) return 0; } -/* temporary stub to make this patch compile */ -int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) -{ - return -ENOTSUP; -} diff --git a/src/osmo-bts-sysmo/l1_if.h b/src/osmo-bts-sysmo/l1_if.h index 7947ea2..388f1fb 100644 --- a/src/osmo-bts-sysmo/l1_if.h +++ b/src/osmo-bts-sysmo/l1_if.h @@ -50,9 +50,6 @@ struct femtol1_hdl { char *calib_path; struct llist_head wlc_list; - struct gsmtap_inst *gsmtap; - uint32_t gsmtap_sapi_mask; - void *priv; /* user reference */ struct osmo_timer_list alive_timer; @@ -97,7 +94,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); @@ -106,6 +105,12 @@ int l1if_set_ciphering(struct femtol1_hdl *fl1h, struct gsm_lchan *lchan, int dir_downlink); +/* channel control */ +int l1if_rsl_chan_act(struct gsm_lchan *lchan); +int l1if_rsl_chan_rel(struct gsm_lchan *lchan); +int l1if_rsl_deact_sacch(struct gsm_lchan *lchan); +int l1if_rsl_mode_modify(struct gsm_lchan *lchan); + /* calibration loading */ int calib_load(struct femtol1_hdl *fl1h); diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index 7e7f761..465f99d 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -45,6 +45,7 @@ #include <osmo-bts/vty.h> #include <osmo-bts/bts_model.h> #include <osmo-bts/pcu_if.h> +#include <osmo-bts/l1sap.h> #define SYSMOBTS_RF_LOCK_PATH "/var/lock/bts_rf_lock" @@ -254,6 +255,7 @@ int main(int argc, char **argv) bts_log_init(NULL); + bts = gsm_bts_alloc(tall_bts_ctx); vty_init(&bts_vty_info); bts_vty_init(bts, &bts_log_info); @@ -271,7 +273,6 @@ int main(int argc, char **argv) } } - bts = gsm_bts_alloc(tall_bts_ctx); if (bts_init(bts) < 0) { fprintf(stderr, "unable to to open bts\n"); exit(1); diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index aeddad7..399576e 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -35,11 +35,27 @@ #include <osmo-bts/amr.h> #include <osmo-bts/bts.h> #include <osmo-bts/bts_model.h> +#include <osmo-bts/l1sap.h> #include "l1_if.h" #include "femtobts.h" #include "utils.h" +static int mph_info_chan_confirm(struct gsm_lchan *lchan, + enum osmo_mph_info_type type, uint8_t cause) +{ + struct osmo_phsap_prim l1sap; + + memset(&l1sap, 0, sizeof(l1sap)); + osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO, PRIM_OP_CONFIRM, + NULL); + l1sap.u.info.type = type; + l1sap.u.info.u.act_cnf.chan_nr = gsm_lchan2chan_nr(lchan); + l1sap.u.info.u.act_cnf.cause = cause; + + return l1sap_up(lchan->ts->trx, &l1sap); +} + enum sapi_cmd_type { SAPI_CMD_ACTIVATE, SAPI_CMD_CONFIG_CIPHERING, @@ -858,7 +874,7 @@ static int sapi_activate_cb(struct gsm_lchan *lchan, int status) if (status != GsmL1_Status_Success) { lchan_set_state(lchan, LCHAN_S_BROKEN); sapi_clear_queue(&lchan->sapi_cmds); - rsl_tx_chan_act_nack(lchan, RSL_ERR_EQUIPMENT_FAIL); + mph_info_chan_confirm(lchan, PRIM_INFO_ACTIVATE, RSL_ERR_EQUIPMENT_FAIL); return -1; } @@ -869,7 +885,7 @@ static int sapi_activate_cb(struct gsm_lchan *lchan, int status) return 0; lchan_set_state(lchan, LCHAN_S_ACTIVE); - rsl_tx_chan_act_ack(lchan); + mph_info_chan_confirm(lchan, PRIM_INFO_ACTIVATE, 0); /* set the initial ciphering parameters for both directions */ l1if_set_ciphering(fl1h, lchan, 0); @@ -891,7 +907,6 @@ static void enqueue_sapi_act_cmd(struct gsm_lchan *lchan, int sapi, int dir) int lchan_activate(struct gsm_lchan *lchan, enum gsm_lchan_state lchan_state) { - struct gsm_bts_role_bts *btsb = lchan->ts->trx->bts->role; struct femtol1_hdl *fl1h = trx_femtol1_hdl(lchan->ts->trx); const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type]; unsigned int i; @@ -920,8 +935,6 @@ int lchan_activate(struct gsm_lchan *lchan, enum gsm_lchan_state lchan_state) #warning "FIXME: Should this be in sapi_activate_cb?" lchan_init_lapdm(lchan); - lchan->s = btsb->radio_link_timeout; - return 0; } @@ -1177,7 +1190,7 @@ int l1if_set_ciphering(struct femtol1_hdl *fl1h, return 0; } -int bts_model_rsl_mode_modify(struct gsm_lchan *lchan) +int l1if_rsl_mode_modify(struct gsm_lchan *lchan) { if (lchan->state != LCHAN_S_ACTIVE) return -1; @@ -1286,7 +1299,7 @@ static int sapi_deactivate_cb(struct gsm_lchan *lchan, int status) gsm_lchan_name(lchan)); lchan_set_state(lchan, LCHAN_S_BROKEN); sapi_clear_queue(&lchan->sapi_cmds); - rsl_tx_rf_rel_ack(lchan); + mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0); return -1; } @@ -1298,7 +1311,7 @@ static int sapi_deactivate_cb(struct gsm_lchan *lchan, int status) return 0; lchan_set_state(lchan, LCHAN_S_NONE); - rsl_tx_rf_rel_ack(lchan); + mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0); return 0; } @@ -1358,7 +1371,7 @@ static int lchan_deactivate_sapis(struct gsm_lchan *lchan) LOGP(DL1C, LOGL_ERROR, "%s all SAPIs already released?\n", gsm_lchan_name(lchan)); lchan_set_state(lchan, LCHAN_S_BROKEN); - rsl_tx_rf_rel_ack(lchan); + mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0); } return res; @@ -1398,13 +1411,6 @@ static int lchan_deactivate_sacch(struct gsm_lchan *lchan) return 0; } -struct gsm_time *bts_model_get_time(struct gsm_bts *bts) -{ - struct femtol1_hdl *fl1h = trx_femtol1_hdl(bts->c0); - - return &fl1h->gsm_time; -} - /* callback from OML */ int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type, struct tlv_parsed *old_attr, struct tlv_parsed *new_attr, @@ -1457,17 +1463,17 @@ int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo, mo->nm_state.administrative = adm_state; return oml_mo_statechg_ack(mo); } -int bts_model_rsl_chan_act(struct gsm_lchan *lchan, struct tlv_parsed *tp) + +int l1if_rsl_chan_act(struct gsm_lchan *lchan) { //uint8_t mode = *TLVP_VAL(tp, RSL_IE_CHAN_MODE); //uint8_t type = *TLVP_VAL(tp, RSL_IE_ACT_TYPE); - lchan->sacch_deact = 0; lchan_activate(lchan, LCHAN_S_ACT_REQ); return 0; } -int bts_model_rsl_chan_rel(struct gsm_lchan *lchan) +int l1if_rsl_chan_rel(struct gsm_lchan *lchan) { /* A duplicate RF Release Request, ignore it */ if (lchan->state == LCHAN_S_REL_REQ) @@ -1476,7 +1482,7 @@ int bts_model_rsl_chan_rel(struct gsm_lchan *lchan) return 0; } -int bts_model_rsl_deact_sacch(struct gsm_lchan *lchan) +int l1if_rsl_deact_sacch(struct gsm_lchan *lchan) { /* Only de-activate the SACCH if the lchan is active */ if (lchan->state != LCHAN_S_ACTIVE) diff --git a/src/osmo-bts-sysmo/sysmobts_vty.c b/src/osmo-bts-sysmo/sysmobts_vty.c index 61deda4..998ed80 100644 --- a/src/osmo-bts-sysmo/sysmobts_vty.c +++ b/src/osmo-bts-sysmo/sysmobts_vty.c @@ -83,34 +83,6 @@ DEFUN(cfg_bts_no_auto_band, cfg_bts_no_auto_band_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_gsmtap_sapi, cfg_trx_gsmtap_sapi_cmd, - "HIDDEN", "HIDDEN") -{ - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); - int sapi; - - sapi = get_string_value(femtobts_l1sapi_names, argv[0]); - - fl1h->gsmtap_sapi_mask |= (1 << sapi); - - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_no_gsmtap_sapi, cfg_trx_no_gsmtap_sapi_cmd, - "HIDDEN", "HIDDEN") -{ - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); - int sapi; - - sapi = get_string_value(femtobts_l1sapi_names, argv[0]); - - fl1h->gsmtap_sapi_mask &= ~(1 << sapi); - - return CMD_SUCCESS; -} - DEFUN(cfg_trx_clkcal_def, cfg_trx_clkcal_def_cmd, "clock-calibration default", "Set the clock calibration value\n" "Default Clock DAC value\n") @@ -397,44 +369,6 @@ DEFUN(set_tx_power, set_tx_power_cmd, return CMD_SUCCESS; } -DEFUN(loopback, loopback_cmd, - "trx <0-0> <0-7> loopback <0-1>", - TRX_STR - "Timeslot number\n" - "Set TCH loopback\n" - "Logical Channel Number\n") -{ - int trx_nr = atoi(argv[0]); - int ts_nr = atoi(argv[1]); - int lchan_nr = atoi(argv[2]); - struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr); - struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr]; - struct gsm_lchan *lchan = &ts->lchan[lchan_nr]; - - lchan->loopback = 1; - - return CMD_SUCCESS; -} - -DEFUN(no_loopback, no_loopback_cmd, - "no trx <0-0> <0-7> loopback <0-1>", - NO_STR TRX_STR - "Timeslot number\n" - "Set TCH loopback\n" - "Logical Channel Number\n") -{ - int trx_nr = atoi(argv[0]); - int ts_nr = atoi(argv[1]); - int lchan_nr = atoi(argv[2]); - struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr); - struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr]; - struct gsm_lchan *lchan = &ts->lchan[lchan_nr]; - - lchan->loopback = 0; - - return CMD_SUCCESS; -} - void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) { @@ -447,7 +381,6 @@ void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) { struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); - int i; vty_out(vty, " clock-calibration %d%s", fl1h->clk_cal, VTY_NEWLINE); @@ -463,14 +396,6 @@ void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) VTY_NEWLINE); vty_out(vty, " min-qual-norm %.0f%s", fl1h->min_qual_norm * 10.0f, VTY_NEWLINE); - - for (i = 0; i < 32; i++) { - if (fl1h->gsmtap_sapi_mask & (1 << i)) { - const char *name = get_value_string(femtobts_l1sapi_names, i); - vty_out(vty, " gsmtap-sapi %s%s", osmo_str_tolower(name), - VTY_NEWLINE); - } - } } int bts_model_vty_init(struct gsm_bts *bts) @@ -492,20 +417,6 @@ int bts_model_vty_init(struct gsm_bts *bts) NO_STR TRX_STR DSP_TRACE_F_STR, "\n", "", 0); - cfg_trx_gsmtap_sapi_cmd.string = vty_cmd_string_from_valstr(bts, femtobts_l1sapi_names, - "gsmtap-sapi (", - "|",")", VTY_DO_LOWER); - cfg_trx_gsmtap_sapi_cmd.doc = vty_cmd_string_from_valstr(bts, femtobts_l1sapi_names, - "GSMTAP SAPI\n", - "\n", "", 0); - - cfg_trx_no_gsmtap_sapi_cmd.string = vty_cmd_string_from_valstr(bts, femtobts_l1sapi_names, - "no gsmtap-sapi (", - "|",")", VTY_DO_LOWER); - cfg_trx_no_gsmtap_sapi_cmd.doc = vty_cmd_string_from_valstr(bts, femtobts_l1sapi_names, - NO_STR "GSMTAP SAPI\n", - "\n", "", 0); - install_element_ve(&show_dsp_trace_f_cmd); install_element_ve(&show_sys_info_cmd); install_element_ve(&show_trx_clksrc_cmd); @@ -515,9 +426,6 @@ int bts_model_vty_init(struct gsm_bts *bts) install_element(ENABLE_NODE, &activate_lchan_cmd); install_element(ENABLE_NODE, &set_tx_power_cmd); - install_element(ENABLE_NODE, &loopback_cmd); - install_element(ENABLE_NODE, &no_loopback_cmd); - install_element(BTS_NODE, &cfg_bts_auto_band_cmd); install_element(BTS_NODE, &cfg_bts_no_auto_band_cmd); @@ -525,8 +433,6 @@ int bts_model_vty_init(struct gsm_bts *bts) install_element(TRX_NODE, &cfg_trx_clkcal_def_cmd); install_element(TRX_NODE, &cfg_trx_clksrc_cmd); install_element(TRX_NODE, &cfg_trx_cal_path_cmd); - install_element(TRX_NODE, &cfg_trx_gsmtap_sapi_cmd); - install_element(TRX_NODE, &cfg_trx_no_gsmtap_sapi_cmd); install_element(TRX_NODE, &cfg_trx_ul_power_target_cmd); install_element(TRX_NODE, &cfg_trx_min_qual_rach_cmd); install_element(TRX_NODE, &cfg_trx_min_qual_norm_cmd); diff --git a/src/osmo-bts-sysmo/tch.c b/src/osmo-bts-sysmo/tch.c index c6c782f..da62c84 100644 --- a/src/osmo-bts-sysmo/tch.c +++ b/src/osmo-bts-sysmo/tch.c @@ -39,6 +39,7 @@ #include <osmo-bts/bts.h> #include <osmo-bts/gsm_data.h> #include <osmo-bts/measurement.h> +#include <osmo-bts/l1sap.h> #include <sysmocom/femtobts/superfemto.h> #include <sysmocom/femtobts/gsml1prim.h> @@ -416,7 +417,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 @@ -428,14 +429,9 @@ 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; @@ -443,22 +439,8 @@ void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, DEBUGP(DRTP, "%s RTP IN: %s\n", gsm_lchan_name(lchan), osmo_hexdump(rtp_pl, rtp_pl_len)); - /* skip processing of incoming RTP frames if we are in loopback mode */ - if (lchan->loopback) - return; - - 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: @@ -493,40 +475,17 @@ 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; DEBUGP(DRTP, "%s RTP->L1: %s\n", gsm_lchan_name(lchan), - osmo_hexdump(msu_param->u8Buffer, msu_param->u8Size)); - - /* 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); + osmo_hexdump(data, *len)); } /*! \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; @@ -534,50 +493,15 @@ 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 (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) @@ -624,13 +548,20 @@ int l1if_tch_rx(struct gsm_lchan *lchan, struct msgb *l1p_msg) } if (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)); - /* 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); + + /* 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; -- 1.8.1.5