Dear all,
the valuable L1SAP abstraction has been sitting out of master for too long time. It is a pity that this has taken so long. I've finally been able to put some time into osmo-bts again and reviewed the following patch series. It consists of mostly Andreas' work, interspersed with smaller patches/fixups that I introduced after the respective original patch from Andreas.
I have started a sysmobts between all of the major steps in this patch series and did a short manual tests involving registration (LU) of two MS, mobile-to-mobile call and vty-to-mobile SMS. So far I couldn't see any problems. What has not been tested yet is the PCU interface as well as encryption support. I plan to do this later this week.
I intend to merge the code after this current review cycle. Please take your time to have a look and provide feedback (if any), so we can get this over and work on new features again, rather than infrastrutural changes.
I didn't yet rebase the osmo-bts-trx interface on top of the L1SAP, as I don't have a hardware setup for it, and I will leave it to the owners of such hardware to publish/push the respective code after L1SAP is merged.
Regards, Harald
From: Andreas Eversberg jolly@eversberg.eu
In case of a headroom in a message, the 'head' pointer will not point to the actual data. --- src/osmo-bts-sysmo/l1_transp_fwd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/osmo-bts-sysmo/l1_transp_fwd.c b/src/osmo-bts-sysmo/l1_transp_fwd.c index 5050705..87c230b 100644 --- a/src/osmo-bts-sysmo/l1_transp_fwd.c +++ b/src/osmo-bts-sysmo/l1_transp_fwd.c @@ -95,7 +95,7 @@ static int fwd_read_cb(struct osmo_fd *ofd) static int prim_write_cb(struct osmo_fd *ofd, struct msgb *msg) { /* write to the fd */ - return write(ofd->fd, msg->head, msg->len); + return write(ofd->fd, msg->l1h, msgb_l1len(msg)); }
int l1if_transport_open(int q, struct femtol1_hdl *fl1h)
From: Andreas Eversberg jolly@eversberg.eu
Instead of handling primitives directly at layer 1 specific code, osmo-bts handles primitives at common code.
When all primitive are moved, the l1sap interface will: - receive PH-DATA indications and forward them to layer 2. - check for RF link loss and notify BSC. - receive TCH indications and forward them via RTP. - receive PH-RTS indications and send PH-DATA requests with content according to its logical channel. - receive TCH-RTS indications and send TCH requests with content received via RTP or loopback from TCH indications. - send MPH-INFO requests to activate, deactivate and modify logical channels and handle their confirms. - receive MPH-INFO indications with measurements from tranceiver. - forward received and transmitted PH-DATA to GSMTAP. --- include/osmo-bts/Makefile.am | 2 +- include/osmo-bts/l1sap.h | 71 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 include/osmo-bts/l1sap.h
diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am index a55e642..c18c820 100644 --- a/include/osmo-bts/Makefile.am +++ b/include/osmo-bts/Makefile.am @@ -1,3 +1,3 @@ noinst_HEADERS = abis.h bts.h bts_model.h gsm_data.h logging.h measurement.h \ oml.h paging.h rsl.h signal.h vty.h amr.h pcu_if.h pcuif_proto.h \ - handover.h msg_utils.h tx_power.h control_if.h + handover.h msg_utils.h tx_power.h control_if.h l1sap.h diff --git a/include/osmo-bts/l1sap.h b/include/osmo-bts/l1sap.h new file mode 100644 index 0000000..a1dc303 --- /dev/null +++ b/include/osmo-bts/l1sap.h @@ -0,0 +1,71 @@ +#ifndef L1SAP_H +#define L1SAP_H + +/* timeslot and subslot from chan_nr */ +#define L1SAP_CHAN2TS(chan_nr) (chan_nr & 7) +#define L1SAP_CHAN2SS_TCHH(chan_nr) ((chan_nr >> 3) & 1) +#define L1SAP_CHAN2SS_SDCCH4(chan_nr) ((chan_nr >> 3) & 3) +#define L1SAP_CHAN2SS_SDCCH8(chan_nr) ((chan_nr >> 3) & 7) + +/* logical channel from chan_nr + link_id */ +#define L1SAP_IS_LINK_SACCH(link_id) ((link_id & 0xC0) == 0x40) +#define L1SAP_IS_CHAN_TCHF(chan_nr) ((chan_nr & 0xf8) == 0x08) +#define L1SAP_IS_CHAN_TCHH(chan_nr) ((chan_nr & 0xf0) == 0x10) +#define L1SAP_IS_CHAN_SDCCH4(chan_nr) ((chan_nr & 0xe0) == 0x20) +#define L1SAP_IS_CHAN_SDCCH8(chan_nr) ((chan_nr & 0xc0) == 0x40) +#define L1SAP_IS_CHAN_BCCH(chan_nr) ((chan_nr & 0xf8) == 0x80) +#define L1SAP_IS_CHAN_RACH(chan_nr) ((chan_nr & 0xf8) == 0x88) +#define L1SAP_IS_CHAN_AGCH_PCH(chan_nr) ((chan_nr & 0xf8) == 0x90) + +/* rach type from ra */ +#define L1SAP_IS_PACKET_RACH(ra) ((ra & 0xf0) == 0x70) + +/* CCCH block from frame number */ +#define L1SAP_FN2CCCHBLOCK(fn) ((fn % 51) / 5 - 1) + +/* PTCH layout from frame number */ +#define L1SAP_FN2MACBLOCK(fn) ((fn % 52) / 4) +#define L1SAP_FN2PTCCHBLOCK(fn) ((fn / 52) & 7) +#define L1SAP_IS_PTCCH(fn) ((fn % 52) == 12) + +/* subslot from any chan_nr */ +static inline uint8_t l1sap_chan2ss(uint8_t chan_nr) +{ + if (L1SAP_IS_CHAN_SDCCH8(chan_nr)) + return L1SAP_CHAN2SS_SDCCH8(chan_nr); + if (L1SAP_IS_CHAN_SDCCH4(chan_nr)) + return L1SAP_CHAN2SS_SDCCH4(chan_nr); + if (L1SAP_IS_CHAN_TCHH(chan_nr)) + return L1SAP_CHAN2SS_TCHH(chan_nr); + return 0; +} + + +/* allocate a msgb containing a osmo_phsap_prim + optional l2 data */ +struct msgb *l1sap_msgb_alloc(unsigned int l2_len); + +/* any L1 prim received from bts model */ +int l1sap_up(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap); + +/* pcu (socket interface) sends us a data request primitive */ +int l1sap_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); + +/* 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); + +/* channel control */ +int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr); +int l1sap_chan_rel(struct gsm_bts_trx *trx, uint8_t chan_nr); +int l1sap_chan_deact_sacch(struct gsm_bts_trx *trx, uint8_t chan_nr); +int l1sap_chan_modify(struct gsm_bts_trx *trx, uint8_t chan_nr); + +extern const struct value_string gsmtap_sapi_names[]; +extern struct gsmtap_inst *gsmtap; +extern uint32_t gsmtap_sapi_mask; +extern uint8_t gsmtap_sapi_acch; + +#define msgb_l1sap_prim(msg) ((struct osmo_phsap_prim *)(msg)->l1h) + +#endif /* L1SAP_H */
From: Andreas Eversberg jolly@eversberg.eu
This first part moves BCCH message primitives from osmo-bts-sysmo to common part. A new file "common/l1sap.c" is introduced to implement handling of layer 1 messages from/to BTS model. --- include/osmo-bts/bts_model.h | 2 + src/common/Makefile.am | 2 +- src/common/l1sap.c | 150 ++++++++++++++++++++++++++++++++++++++ src/osmo-bts-sysmo/l1_if.c | 167 +++++++++++++++++++++++++++++++++++++++---- tests/stubs.c | 2 + 5 files changed, 310 insertions(+), 13 deletions(-) create mode 100644 src/common/l1sap.c
diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h index 200d02d..f9b3f0b 100644 --- a/include/osmo-bts/bts_model.h +++ b/include/osmo-bts/bts_model.h @@ -48,4 +48,6 @@ int bts_model_oml_estab(struct gsm_bts *bts);
int bts_model_change_power(struct gsm_bts_trx *trx, int p_trxout_mdBm);
+int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap); + #endif diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 10627e2..6de6214 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -7,4 +7,4 @@ libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \ rsl.c vty.c paging.c measurement.c amr.c lchan.c \ load_indication.c pcu_sock.c handover.c msg_utils.c \ load_indication.c pcu_sock.c handover.c msg_utils.c \ - tx_power.c bts_ctrl_commands.c bts_ctrl_lookup.c + tx_power.c bts_ctrl_commands.c bts_ctrl_lookup.c l1sap.c diff --git a/src/common/l1sap.c b/src/common/l1sap.c new file mode 100644 index 0000000..f4f3246 --- /dev/null +++ b/src/common/l1sap.c @@ -0,0 +1,150 @@ +/* L1 SAP primitives */ + +/* (C) 2011 by Harald Welte laforge@gnumonks.org + * (C) 2013 by Andreas Eversberg jolly@eversberg.eu + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +#include <stdint.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <osmocom/core/msgb.h> +#include <osmocom/gsm/l1sap.h> +#include <osmocom/core/gsmtap.h> +#include <osmocom/core/gsmtap_util.h> +#include <osmocom/core/utils.h> + +#include <osmocom/trau/osmo_ortp.h> + +#include <osmo-bts/logging.h> +#include <osmo-bts/gsm_data.h> +#include <osmo-bts/l1sap.h> +#include <osmo-bts/pcu_if.h> +#include <osmo-bts/measurement.h> +#include <osmo-bts/bts.h> +#include <osmo-bts/rsl.h> +#include <osmo-bts/bts_model.h> + +static int l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *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 +}; + +/* allocate a msgb containing a osmo_phsap_prim + optional l2 data + * in order to wrap femtobts header arround l2 data, there must be enough space + * in front and behind data pointer */ +struct msgb *l1sap_msgb_alloc(unsigned int l2_len) +{ + struct msgb *msg = msgb_alloc_headroom(512, 128, "l1sap_prim"); + + if (!msg) + return NULL; + + msg->l1h = msgb_put(msg, sizeof(struct osmo_phsap_prim)); + + return msg; +} + +/* PH-RTS-IND prim recevied from bts model */ +static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, struct ph_data_param *rts_ind) +{ + struct msgb *msg = l1sap->oph.msg; + struct gsm_time g_time; + uint8_t chan_nr, link_id; + uint8_t tn; + uint32_t fn; + uint8_t *p, *si; + + chan_nr = rts_ind->chan_nr; + link_id = rts_ind->link_id; + fn = rts_ind->fn; + tn = L1SAP_CHAN2TS(chan_nr); + + gsm_fn2gsmtime(&g_time, fn); + + DEBUGP(DL1P, "Rx PH-RTS.ind %02u/%02u/%02u chan_nr=%d link_id=%d\n", + g_time.t1, g_time.t2, g_time.t3, chan_nr, link_id); + + /* reuse PH-RTS.ind for PH-DATA.req */ + if (!msg) { + LOGP(DL1P, LOGL_FATAL, "RTS without msg to be reused. Please " + "fix!\n"); + abort(); + } + msgb_trim(msg, sizeof(*l1sap)); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_DATA, PRIM_OP_REQUEST, + msg); + msg->l2h = msg->l1h + sizeof(*l1sap); + + if (L1SAP_IS_CHAN_BCCH(chan_nr)) { + p = msgb_put(msg, GSM_MACBLOCK_LEN); + /* get them from bts->si_buf[] */ + si = bts_sysinfo_get(trx->bts, &g_time); + if (si) + memcpy(p, si, GSM_MACBLOCK_LEN); + else + memcpy(p, fill_frame, GSM_MACBLOCK_LEN); + } + + DEBUGP(DL1P, "Tx PH-DATA.req %02u/%02u/%02u chan_nr=%d link_id=%d\n", + g_time.t1, g_time.t2, g_time.t3, chan_nr, link_id); + + l1sap_down(trx, l1sap); + + /* don't free, because we forwarded data */ + return 1; +} + +/* any L1 prim received from bts model */ +int l1sap_up(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) +{ + struct msgb *msg = l1sap->oph.msg; + int rc = 0; + + switch (OSMO_PRIM_HDR(&l1sap->oph)) { + case OSMO_PRIM(PRIM_PH_RTS, PRIM_OP_INDICATION): + rc = l1sap_ph_rts_ind(trx, l1sap, &l1sap->u.data); + break; + default: + LOGP(DL1P, LOGL_NOTICE, "unknown prim %d op %d\n", + l1sap->oph.primitive, l1sap->oph.operation); + break; + } + + /* Special return value '1' means: do not free */ + if (rc != 1) + msgb_free(msg); + + return rc; +} + +/* any L1 prim sent to bts model */ +static int l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) +{ + return bts_model_l1sap_down(trx, l1sap); +} + diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 4b9ab3e..54e4761 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -49,6 +49,7 @@ #include <osmo-bts/measurement.h> #include <osmo-bts/pcu_if.h> #include <osmo-bts/handover.h> +#include <osmo-bts/l1sap.h>
#include <sysmocom/femtobts/superfemto.h> #include <sysmocom/femtobts/gsml1prim.h> @@ -415,8 +416,135 @@ static const uint8_t fill_frame[GSM_MACBLOCK_LEN] = { 0x2B, 0x2B, 0x2B };
+static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, + struct osmo_phsap_prim *l1sap) +{ + struct femtol1_hdl *fl1 = trx_femtol1_hdl(trx); + uint32_t u32Fn; + uint8_t u8Tn, subCh, u8BlockNbr = 0, sapi; + uint8_t chan_nr, link_id; + GsmL1_Prim_t *l1p; + int len; + + 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_CHAN_BCCH(chan_nr)) { + sapi = GsmL1_Sapi_Bcch; + } 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); + return -EINVAL; + } + + /* pull and trim msg to start of payload */ + msgb_pull(msg, sizeof(*l1sap)); + len = msg->len; + msgb_trim(msg, 0); + + /* convert l1sap message to GsmL1 primitive, keep payload */ + if (len) { + /* data request */ + GsmL1_PhDataReq_t *data_req; + GsmL1_MsgUnitParam_t *msu_param; + uint8_t *temp; + + /* wrap zeroed l1p structure arrount payload + * this must be done in three steps, since the actual + * payload is not at the end but inside the l1p structure. */ + temp = l1p->u.phDataReq.msgUnitParam.u8Buffer; + msgb_push(msg, temp - (uint8_t *)l1p); + memset(msg->data, 0, msg->len); + msgb_put(msg, len); + memset(msg->tail, 0, sizeof(*l1p) - msg->len); + msgb_put(msg, sizeof(*l1p) - msg->len); + msg->l1h = msg->data; + + l1p = msgb_l1prim(msg); + l1p->id = GsmL1_PrimId_PhDataReq; + data_req = &l1p->u.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 = len; + } else { + /* empty frame */ + GsmL1_PhEmptyFrameReq_t *empty_req; + + /* put l1p structure */ + msgb_put(msg, sizeof(*l1p)); + memset(msg->data, 0, msg->len); + msg->l1h = msg->data; + + l1p = msgb_l1prim(msg); + l1p->id = GsmL1_PrimId_PhEmptyFrameReq; + empty_req = &l1p->u.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], msg); + + return 0; +} + +/* primitive from common part */ +int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) +{ + struct msgb *msg = l1sap->oph.msg; + int rc = 0; + + switch (OSMO_PRIM_HDR(&l1sap->oph)) { + case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST): + rc = ph_data_req(trx, msg, l1sap); + break; + default: + LOGP(DL1C, LOGL_NOTICE, "unknown prim %d op %d\n", + l1sap->oph.primitive, l1sap->oph.operation); + rc = -EINVAL; + } + + if (rc) + msgb_free(msg); + return rc; +} + +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; + 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; @@ -427,9 +555,31 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, struct gsm_lchan *lchan; struct gsm_time g_time; uint32_t t3p; - uint8_t *si; struct osmo_phsap_prim pp; int rc; + struct osmo_phsap_prim *l1sap; + 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); + if (chan_nr) { + fn = rts_ind->u32Fn; + 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); + 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);
@@ -508,14 +658,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); @@ -598,6 +740,7 @@ tx: /* transmit */ osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], resp_msg);
+ msgb_free(l1p_msg); return 0;
empty_frame: @@ -952,8 +1095,8 @@ 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); - break; + return handle_ph_readytosend_ind(fl1, &l1p->u.phReadyToSendInd, + msg); case GsmL1_PrimId_PhDataInd: rc = handle_ph_data_ind(fl1, &l1p->u.phDataInd, msg); break; diff --git a/tests/stubs.c b/tests/stubs.c index 959f445..f270f22 100644 --- a/tests/stubs.c +++ b/tests/stubs.c @@ -42,6 +42,8 @@ int bts_model_rsl_chan_mod(struct gsm_lchan *lchan) { return 0; } void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, unsigned int rtp_pl_len) {} +int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) +{ return 0; }
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)
On Wed, Aug 27, 2014 at 11:54:22PM +0200, Harald Welte wrote:
- /* don't free, because we forwarded data */
- return 1;
Maybe we can make that a define for the ownership handling instead of a magic number.
+static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
struct osmo_phsap_prim *l1sap)
+{
...
- } 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);
sure this should not happen in normal operation
msgb_free(l1sap);
return -EINVAL;
- }
/* wrap zeroed l1p structure arrount payload
around...
* this must be done in three steps, since the actual
* payload is not at the end but inside the l1p structure. */
maybe we can use the pull_to_l3 method hre?
- /* send message to DSP's queue */
- osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], msg);
The existing code doesn't do this either but wqueue_enqueue is written in a way that if the queue has reached the max depth the message will not be added. This was done to let the caller decide if it should clear the queue or wants to print the msgb. The result is that the result of enqueue should be checked and if the queuing was rejected msgb_free must be called.
+int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) +{
- struct msgb *msg = l1sap->oph.msg;
- int rc = 0;
- switch (OSMO_PRIM_HDR(&l1sap->oph)) {
- case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST):
rc = ph_data_req(trx, msg, l1sap);
break;
- default:
LOGP(DL1C, LOGL_NOTICE, "unknown prim %d op %d\n",
l1sap->oph.primitive, l1sap->oph.operation);
rc = -EINVAL;
- }
- if (rc)
msgb_free(msg);
did the rc == 1 turn into a rc != 0 here?
@@ -598,6 +740,7 @@ tx: /* transmit */ osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], resp_msg);
the existing osmo_queue_enquire issue.
@@ -952,8 +1095,8 @@ 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);
break;
return handle_ph_readytosend_ind(fl1, &l1p->u.phReadyToSendInd,
msg);
maybe it is better to split the switch into two cases to show the new and old memory semantics?
... in an effort to avoid introducing new/more spaghetti code
Also, use offsetof() instead of pointer calculation to determine the start of GsmL1_Prim_t.u.phDataReq.msgUnitParam.u8Buffer --- src/osmo-bts-sysmo/l1_if.c | 72 ++++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 25 deletions(-)
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 54e4761..542e3ce 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -1,6 +1,6 @@ /* Interface handler for Sysmocom L1 */
-/* (C) 2011 by Harald Welte laforge@gnumonks.org +/* (C) 2011-2014 by Harald Welte laforge@gnumonks.org * (C) 2014 by Holger Hans Peter Freyther * * All Rights Reserved @@ -416,6 +416,49 @@ static const uint8_t fill_frame[GSM_MACBLOCK_LEN] = { 0x2B, 0x2B, 0x2B };
+/* fill PH-DATA.req from l1sap primitive */ +static GsmL1_PhDataReq_t * +data_req_from_l1sap(GsmL1_Prim_t *l1p, struct femtol1_hdl *fl1, + uint8_t tn, uint32_t fn, uint8_t sapi, uint8_t sub_ch, + uint8_t block_nr, uint8_t len) +{ + GsmL1_PhDataReq_t *data_req = &l1p->u.phDataReq; + + l1p->id = GsmL1_PrimId_PhDataReq; + + /* copy fields from PH-RSS.ind */ + data_req->hLayer1 = fl1->hLayer1; + data_req->u8Tn = tn; + data_req->u32Fn = fn; + data_req->sapi = sapi; + data_req->subCh = sub_ch; + data_req->u8BlockNbr = block_nr; + + data_req->msgUnitParam.u8Size = len; + + return data_req; +} + +/* fill PH-EMPTY_FRAME.req from l1sap primitive */ +static GsmL1_PhEmptyFrameReq_t * +empty_req_from_l1sap(GsmL1_Prim_t *l1p, struct femtol1_hdl *fl1, + uint8_t tn, uint32_t fn, uint8_t sapi, + uint8_t subch, uint8_t block_nr) +{ + GsmL1_PhEmptyFrameReq_t *empty_req = &l1p->u.phEmptyFrameReq; + + l1p->id = GsmL1_PrimId_PhEmptyFrameReq; + + empty_req->hLayer1 = fl1->hLayer1; + empty_req->u8Tn = tn; + empty_req->u32Fn = fn; + empty_req->sapi = sapi; + empty_req->subCh = subch; + empty_req->u8BlockNbr = block_nr; + + return empty_req; +} + static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, struct osmo_phsap_prim *l1sap) { @@ -453,15 +496,11 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, /* convert l1sap message to GsmL1 primitive, keep payload */ if (len) { /* data request */ - GsmL1_PhDataReq_t *data_req; - GsmL1_MsgUnitParam_t *msu_param; - uint8_t *temp;
/* wrap zeroed l1p structure arrount payload * this must be done in three steps, since the actual * payload is not at the end but inside the l1p structure. */ - temp = l1p->u.phDataReq.msgUnitParam.u8Buffer; - msgb_push(msg, temp - (uint8_t *)l1p); + msgb_push(msg, offsetof(GsmL1_Prim_t, u.phDataReq.msgUnitParam.u8Buffer)); memset(msg->data, 0, msg->len); msgb_put(msg, len); memset(msg->tail, 0, sizeof(*l1p) - msg->len); @@ -469,19 +508,9 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, msg->l1h = msg->data;
l1p = msgb_l1prim(msg); - l1p->id = GsmL1_PrimId_PhDataReq; - data_req = &l1p->u.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 = len; + data_req_from_l1sap(l1p, fl1, u8Tn, u32Fn, sapi, subCh, u8BlockNbr, len); } else { /* empty frame */ - GsmL1_PhEmptyFrameReq_t *empty_req;
/* put l1p structure */ msgb_put(msg, sizeof(*l1p)); @@ -489,14 +518,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, msg->l1h = msg->data;
l1p = msgb_l1prim(msg); - l1p->id = GsmL1_PrimId_PhEmptyFrameReq; - empty_req = &l1p->u.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; + empty_req_from_l1sap(l1p, fl1, u8Tn, u32Fn, sapi, subCh, u8BlockNbr); }
/* send message to DSP's queue */
On Thu, Aug 28, 2014 at 01:54:38PM +0200, Holger Hans Peter Freyther wrote:
On Wed, Aug 27, 2014 at 11:54:23PM +0200, Harald Welte wrote:
... in an effort to avoid introducing new/more spaghetti code
thanks!
The other obvious candidate is the (now) long section at the beginning of ph_data_req() that determines sapi/subch/blocknr from the link_id and channel number. However, given that all major patches in the series touches the code, I decided to postpone that split until the series is merged.
From: Andreas Eversberg jolly@eversberg.eu
This part moves RACH message primitives from osmo-bts-sysmo to common part. --- src/common/l1sap.c | 69 +++++++++++++++++++++++++++++++++ src/osmo-bts-sysmo/l1_if.c | 97 +++++++++++++++------------------------------- 2 files changed, 101 insertions(+), 65 deletions(-)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index f4f3246..dfc81a4 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -119,6 +119,72 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx, return 1; }
+static int check_acc_delay(struct ph_rach_ind_param *rach_ind, + struct gsm_bts_role_bts *btsb, uint8_t *acc_delay) +{ + *acc_delay = rach_ind->acc_delay; + return *acc_delay <= btsb->max_ta; +} + +/* special case where handover RACH is detected */ +static int l1sap_handover_rach(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, struct ph_rach_ind_param *rach_ind) +{ + struct gsm_lchan *lchan; + uint8_t chan_nr; + uint8_t tn, ss; + + chan_nr = rach_ind->chan_nr; + tn = L1SAP_CHAN2TS(chan_nr); + ss = l1sap_chan2ss(chan_nr); + lchan = &trx->ts[tn].lchan[ss]; + + handover_rach(lchan, rach_ind->ra, rach_ind->acc_delay); + + /* must return 0, so in case of msg at l1sap, it will be freed */ + 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) +{ + struct gsm_bts *bts = trx->bts; + struct gsm_bts_role_bts *btsb = bts->role; + struct lapdm_channel *lc; + uint8_t acc_delay; + + DEBUGP(DL1P, "Rx PH-RA.ind"); + + lc = &trx->ts[0].lchan[4].lapdm_ch; + + /* check for under/overflow / sign */ + if (!check_acc_delay(rach_ind, btsb, &acc_delay)) { + LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n", + acc_delay, btsb->max_ta); + return 0; + } + + /* check for handover rach */ + if (trx != bts->c0 && rach_ind->chan_nr != 0x88) + return l1sap_handover_rach(trx, l1sap, rach_ind); + + /* check for packet access */ + if (trx == bts->c0 + && L1SAP_IS_PACKET_RACH(rach_ind->ra)) { + LOGP(DL1P, LOGL_INFO, "RACH for packet access\n"); + pcu_tx_rach_ind(bts, rach_ind->acc_delay << 2, + rach_ind->ra, rach_ind->fn); + return 0; + } + + LOGP(DL1P, LOGL_INFO, "RACH for RR access (toa=%d, ra=%d)\n", + rach_ind->acc_delay, rach_ind->ra); + lapdm_phsap_up(&l1sap->oph, &lc->lapdm_dcch); + + return 0; +} + /* any L1 prim received from bts model */ int l1sap_up(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) { @@ -129,6 +195,9 @@ 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_PH_RACH, PRIM_OP_INDICATION): + rc = l1sap_ph_rach_ind(trx, l1sap, &l1sap->u.rach_ind); + break; default: LOGP(DL1P, LOGL_NOTICE, "unknown prim %d op %d\n", l1sap->oph.primitive, l1sap->oph.operation); diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 542e3ce..c28e467 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -1015,91 +1015,58 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i return rc; }
-static int check_acc_delay(GsmL1_PhRaInd_t *ra_ind, struct gsm_bts_role_bts *btsb, - uint8_t *acc_delay) -{ - if (ra_ind->measParam.i16BurstTiming < 0) - *acc_delay = 0; - else - *acc_delay = ra_ind->measParam.i16BurstTiming >> 2; - return *acc_delay <= btsb->max_ta; -} - -static int handle_handover(struct gsm_lchan *lchan, struct gsm_bts_role_bts *btsb, - GsmL1_PhRaInd_t *ra_ind) -{ - uint8_t acc_delay; - if (!check_acc_delay(ra_ind, btsb, &acc_delay)) { - LOGP(DHO, LOGL_INFO, "%s ignoring RACH request %u > max_ta(%u)\n", - gsm_lchan_name(lchan), acc_delay, btsb->max_ta); - return 0; - } - - handover_rach(lchan, ra_ind->msgUnitParam.u8Buffer[0], acc_delay); - return 0; -} - -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 gsm_lchan *lchan; - 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 = 0; + 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; + }
- /* - * Check if this is a handover - */ - lchan = l1if_hLayer_to_lchan(trx, ra_ind->hLayer2); - if (lchan && lchan->ho.active == HANDOVER_ENABLED) - return handle_handover(lchan, btsb, ra_ind); + if (ra_ind->measParam.i16BurstTiming > 0) + acc_delay = ra_ind->measParam.i16BurstTiming >> 2;
- /* increment number of RACH slots with valid RACH burst */ - if (trx == bts->c0) + /* increment number of RACH slots with valid non-handover RACH burst */ + lchan = l1if_hLayer_to_lchan(trx, ra_ind->hLayer2); + if (trx == bts->c0 && !(lchan && lchan->ho.active == HANDOVER_ENABLED)) 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; - } - - /* check for under/overflow / sign */ - if (!check_acc_delay(ra_ind, btsb, &acc_delay)) { - LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n", - acc_delay, btsb->max_ta); + 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; }
- /* 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); + fn = ra_ind->u32Fn; + ra = ra_ind->msgUnitParam.u8Buffer[0]; + 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 */ @@ -1123,7 +1090,7 @@ static int l1if_handle_ind(struct femtol1_hdl *fl1, struct msgb *msg) rc = 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;
--- src/common/l1sap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index dfc81a4..5cb72b6 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -166,7 +166,7 @@ static int l1sap_ph_rach_ind(struct gsm_bts_trx *trx, }
/* check for handover rach */ - if (trx != bts->c0 && rach_ind->chan_nr != 0x88) + if (trx != bts->c0 && !L1SAP_IS_CHAN_RACH(rach_ind->chan_nr)) return l1sap_handover_rach(trx, l1sap, rach_ind);
/* check for packet access */
--- src/common/l1sap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 5cb72b6..c788a79 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -170,8 +170,7 @@ static int l1sap_ph_rach_ind(struct gsm_bts_trx *trx, return l1sap_handover_rach(trx, l1sap, rach_ind);
/* check for packet access */ - if (trx == bts->c0 - && L1SAP_IS_PACKET_RACH(rach_ind->ra)) { + if (trx == bts->c0 && L1SAP_IS_PACKET_RACH(rach_ind->ra)) { LOGP(DL1P, LOGL_INFO, "RACH for packet access\n"); pcu_tx_rach_ind(bts, rach_ind->acc_delay << 2, rach_ind->ra, rach_ind->fn);
--- src/common/l1sap.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index c788a79..a4db8fb 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -44,6 +44,7 @@ #include <osmo-bts/bts.h> #include <osmo-bts/rsl.h> #include <osmo-bts/bts_model.h> +#include <osmo-bts/handover.h>
static int l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap);
I don't understand why we would detect handover only on TRX1-n, but not on TRX0. It is perfectly valid for a handover to occur on TRX0. --- src/common/l1sap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index a4db8fb..2dedf02 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -167,7 +167,7 @@ static int l1sap_ph_rach_ind(struct gsm_bts_trx *trx, }
/* check for handover rach */ - if (trx != bts->c0 && !L1SAP_IS_CHAN_RACH(rach_ind->chan_nr)) + if (!L1SAP_IS_CHAN_RACH(rach_ind->chan_nr)) return l1sap_handover_rach(trx, l1sap, rach_ind);
/* check for packet access */
In case of a RACH INDICATION on CCCH, we need to set CHAN_NR to 0x88 (RSL_CHAN_RACH). In other cases, chan_nr needs to reflect the actual logical channel (TCH/SDCCH) on whcih the handover happened. --- src/osmo-bts-sysmo/l1_if.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index c28e467..9c6817c 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -1065,6 +1065,11 @@ static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind, l1sap->u.rach_ind.ra = ra; l1sap->u.rach_ind.acc_delay = acc_delay; l1sap->u.rach_ind.fn = fn; + if (!lchan || lchan->ts->pchan == GSM_PCHAN_CCCH || + lchan->ts->pchan == GSM_PCHAN_CCCH_SDCCH4) + l1sap->u.rach_ind.chan_nr = 0x88; + else + l1sap->u.rach_ind.chan_nr = gsm_lchan2chan_nr(lchan);
return l1sap_up(trx, l1sap); }
--- src/osmo-bts-sysmo/l1_if.c | 13 ------------- 1 file changed, 13 deletions(-)
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 9c6817c..d169b27 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -320,19 +320,6 @@ 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; - - lchan = l1if_hLayer_to_lchan(trx, hLayer2); - if (!lchan) - return NULL; - - return &lchan->lapdm_ch; -} - /* 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)
From: Andreas Eversberg jolly@eversberg.eu
This part moves PCH and AGCH message primitives from osmo-bts-sysmo to common part. --- src/common/l1sap.c | 8 ++++++++ src/osmo-bts-sysmo/l1_if.c | 19 ++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 2dedf02..da4cc48 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -79,6 +79,7 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx, uint8_t tn; uint32_t fn; uint8_t *p, *si; + int rc;
chan_nr = rts_ind->chan_nr; link_id = rts_ind->link_id; @@ -109,6 +110,13 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx, memcpy(p, si, GSM_MACBLOCK_LEN); else memcpy(p, fill_frame, GSM_MACBLOCK_LEN); + } else if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr)) { + p = msgb_put(msg, GSM_MACBLOCK_LEN); + /* if CCCH block is 0, it is AGCH */ + rc = bts_ccch_copy_msg(trx->bts, p, &g_time, + (L1SAP_FN2CCCHBLOCK(fn) < 1)); + if (rc <= 0) + memcpy(p, fill_frame, GSM_MACBLOCK_LEN); }
DEBUGP(DL1P, "Tx PH-DATA.req %02u/%02u/%02u chan_nr=%d link_id=%d\n", diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index d169b27..a3fd64e 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -468,6 +468,14 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, subCh = 0x1f; if (L1SAP_IS_CHAN_BCCH(chan_nr)) { sapi = GsmL1_Sapi_Bcch; + } else if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr)) { + /* 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, @@ -544,6 +552,10 @@ static uint8_t chan_nr_by_sapi(enum gsm_phys_chan_config pchan, case GsmL1_Sapi_Bcch: cbits = 0x10; break; + case GsmL1_Sapi_Agch: + case GsmL1_Sapi_Pch: + cbits = 0x12; + break; default: return 0; } @@ -707,13 +719,6 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, msgb_free(pp.oph.msg); } break; - case GsmL1_Sapi_Agch: - case GsmL1_Sapi_Pch: - rc = bts_ccch_copy_msg(bts, msu_param->u8Buffer, &g_time, - rts_ind->sapi == GsmL1_Sapi_Agch); - if (rc <= 0) - memcpy(msu_param->u8Buffer, fill_frame, GSM_MACBLOCK_LEN); - break; case GsmL1_Sapi_TchF: case GsmL1_Sapi_TchH: /* only hit in case we have a RTP underflow, as real TCH
This is a regression of the code compared to the existing sysmoBTS code, where the L1 tells us whether its AGCH or PCH. However, it was not used even in the old code, so we can afford to simply put a #warning here. --- src/common/l1sap.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index da4cc48..12be383 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -112,6 +112,7 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx, memcpy(p, fill_frame, GSM_MACBLOCK_LEN); } else if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr)) { p = msgb_put(msg, GSM_MACBLOCK_LEN); +#warning "TODO: Yet another assumption that BS_AG_BLKS_RES=1" /* if CCCH block is 0, it is AGCH */ rc = bts_ccch_copy_msg(trx->bts, p, &g_time, (L1SAP_FN2CCCHBLOCK(fn) < 1));
From: Andreas Eversberg jolly@eversberg.eu
This part moves PDTCH, PACCH and PTCCH message primitives from osmo-bts-sysmo to common part. --- src/common/l1sap.c | 90 +++++++++++++++++++++++++++ src/common/pcu_sock.c | 7 +-- src/osmo-bts-sysmo/l1_if.c | 152 ++++++++++++++++++++++++--------------------- 3 files changed, 172 insertions(+), 77 deletions(-)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 12be383..633a5a5 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -91,6 +91,19 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx, DEBUGP(DL1P, "Rx PH-RTS.ind %02u/%02u/%02u chan_nr=%d link_id=%d\n", g_time.t1, g_time.t2, g_time.t3, chan_nr, link_id);
+ if (trx->ts[tn].pchan == GSM_PCHAN_PDCH) { + if (L1SAP_IS_PTCCH(rts_ind->fn)) { + pcu_tx_rts_req(&trx->ts[tn], 1, fn, 1 /* ARFCN */, + L1SAP_FN2PTCCHBLOCK(fn)); + + return 0; + } + pcu_tx_rts_req(&trx->ts[tn], 0, fn, 0 /* ARFCN */, + L1SAP_FN2MACBLOCK(fn)); + + return 0; + } + /* reuse PH-RTS.ind for PH-DATA.req */ if (!msg) { LOGP(DL1P, LOGL_FATAL, "RTS without msg to be reused. Please " @@ -155,6 +168,54 @@ static int l1sap_handover_rach(struct gsm_bts_trx *trx, 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) +{ + struct msgb *msg = l1sap->oph.msg; + struct gsm_time g_time; + uint8_t *data = msg->l2h; + int len = msgb_l2len(msg); + uint8_t chan_nr, link_id; + uint8_t tn, ss; + uint32_t fn; + int8_t rssi; + + rssi = data_ind->rssi; + chan_nr = data_ind->chan_nr; + link_id = data_ind->link_id; + fn = data_ind->fn; + tn = L1SAP_CHAN2TS(chan_nr); + ss = l1sap_chan2ss(chan_nr); + + gsm_fn2gsmtime(&g_time, fn); + + DEBUGP(DL1P, "Rx PH-DATA.ind %02u/%02u/%02u chan_nr=%d link_id=%d\n", + g_time.t1, g_time.t2, g_time.t3, chan_nr, link_id); + + if (trx->ts[tn].pchan == GSM_PCHAN_PDCH) { + if (len == 0) + return -EINVAL; + if (L1SAP_IS_PTCCH(fn)) { + pcu_tx_data_ind(&trx->ts[tn], 1, fn, + 0 /* ARFCN */, L1SAP_FN2PTCCHBLOCK(fn), + data, len, rssi); + + return 0; + } + /* drop incomplete UL block */ + if (data[0] != 7) + return 0; + /* PDTCH / PACCH frame handling */ + pcu_tx_data_ind(&trx->ts[tn], 0, fn, 0 /* ARFCN */, + L1SAP_FN2MACBLOCK(fn), data + 1, len - 1, rssi); + + return 0; + } + + 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) @@ -204,6 +265,9 @@ 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_PH_DATA, PRIM_OP_INDICATION): + rc = l1sap_ph_data_ind(trx, l1sap, &l1sap->u.data); + break; case OSMO_PRIM(PRIM_PH_RACH, PRIM_OP_INDICATION): rc = l1sap_ph_rach_ind(trx, l1sap, &l1sap->u.rach_ind); break; @@ -226,3 +290,29 @@ static int l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) return bts_model_l1sap_down(trx, l1sap); }
+/* pcu (socket interface) sends us a data request primitive */ +int l1sap_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 msgb *msg; + struct osmo_phsap_prim *l1sap; + 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 = l1sap_msgb_alloc(len); + l1sap = msgb_l1sap_prim(msg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_DATA, PRIM_OP_REQUEST, + msg); + l1sap->u.data.chan_nr = 0x08 | ts->nr; + l1sap->u.data.link_id = 0x00; + l1sap->u.data.fn = fn; + msg->l2h = msgb_put(msg, len); + memcpy(msg->l2h, data, len); + + return l1sap_down(ts->trx, l1sap); +} diff --git a/src/common/pcu_sock.c b/src/common/pcu_sock.c index a978e46..515993e 100644 --- a/src/common/pcu_sock.c +++ b/src/common/pcu_sock.c @@ -40,6 +40,7 @@ #include <osmo-bts/rsl.h> #include <osmo-bts/signal.h> #include <osmo-bts/bts_model.h> +#include <osmo-bts/l1sap.h>
uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx);
@@ -57,10 +58,6 @@ static const char *sapi_string[] = { [PCU_IF_SAPI_PTCCH] = "PTCCH", };
-/* FIXME: common l1if include ? */ -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); - static int pcu_sock_send(struct gsm_network *net, struct msgb *msg); /* FIXME: move this to libosmocore */ int osmo_unixsock_listen(struct osmo_fd *bfd, int type, const char *path); @@ -512,7 +509,7 @@ static int pcu_rx_data_req(struct gsm_bts *bts, uint8_t msg_type, } ts = &trx->ts[data_req->ts_nr]; is_ptcch = (data_req->sapi == PCU_IF_SAPI_PTCCH); - rc = l1if_pdch_req(ts, is_ptcch, data_req->fn, data_req->arfcn, + rc = l1sap_pdch_req(ts, is_ptcch, data_req->fn, data_req->arfcn, data_req->block_nr, data_req->data, data_req->len); break; default: diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index a3fd64e..d4861e2 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -466,7 +466,17 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, u32Fn = l1sap->u.data.fn; u8Tn = L1SAP_CHAN2TS(chan_nr); subCh = 0x1f; - if (L1SAP_IS_CHAN_BCCH(chan_nr)) { + 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 if (L1SAP_IS_CHAN_BCCH(chan_nr)) { sapi = GsmL1_Sapi_Bcch; } else if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr)) { /* The sapi depends on DSP configuration, not @@ -556,6 +566,35 @@ static uint8_t chan_nr_by_sapi(enum gsm_phys_chan_config pchan, case GsmL1_Sapi_Pch: cbits = 0x12; 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; } @@ -648,13 +687,6 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, /* 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; } @@ -886,6 +918,10 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i struct gsm_lchan *lchan; struct lapdm_entity *le; struct msgb *msg; + uint8_t chan_nr, link_id; + struct osmo_phsap_prim *l1sap; + uint32_t fn; + uint8_t *data, len; int rc = 0;
ul_to_gsmtap(fl1, l1p_msg); @@ -895,14 +931,22 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i LOGP(DL1C, LOGL_ERROR, "unable to resolve lchan by hLayer2 for 0x%x\n", data_ind->hLayer2); + msgb_free(l1p_msg); return -ENODEV; }
+ chan_nr = chan_nr_by_sapi(trx->ts[data_ind->u8Tn].pchan, data_ind->sapi, + data_ind->subCh, data_ind->u8Tn, data_ind->u32Fn); + fn = data_ind->u32Fn; + link_id = (data_ind->sapi == GsmL1_Sapi_Sacch) ? 0x40 : 0x00; + process_meas_res(lchan, &data_ind->measParam);
if (data_ind->measParam.fLinkQuality < fl1->min_qual_norm - && data_ind->msgUnitParam.u8Size != 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), @@ -973,27 +1017,7 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i 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; case GsmL1_Sapi_Idle: /* nothing to send */ @@ -1004,7 +1028,32 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i break; }
- return rc; + if (!chan_nr) { + msgb_free(l1p_msg); + return rc; + } + + /* 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, @@ -1084,8 +1133,7 @@ static int l1if_handle_ind(struct femtol1_hdl *fl1, struct msgb *msg) return handle_ph_readytosend_ind(fl1, &l1p->u.phReadyToSendInd, msg); case GsmL1_PrimId_PhDataInd: - rc = handle_ph_data_ind(fl1, &l1p->u.phDataInd, msg); - break; + return handle_ph_data_ind(fl1, &l1p->u.phDataInd, msg); case GsmL1_PrimId_PhRaInd: return handle_ph_ra_ind(fl1, &l1p->u.phRaInd, msg); break; @@ -1538,46 +1586,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; -} - /* get those femtol1_hdl.hw_info elements that sre in EEPROM */ static int get_hwinfo_eeprom(struct femtol1_hdl *fl1h) {
--- src/osmo-bts-sysmo/l1_if.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index d4861e2..03e8a56 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -599,6 +599,7 @@ static uint8_t chan_nr_by_sapi(enum gsm_phys_chan_config pchan, return 0; }
+ /* not reached due to default case above */ return (cbits << 3) | u8Tn; }
@@ -1029,10 +1030,13 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i }
if (!chan_nr) { + /* message was handled by old code, not by L1SAP */ msgb_free(l1p_msg); return rc; }
+ /* if we proceed to this point, the message has to be handled via L1SAP */ + /* get data pointer and length */ data = data_ind->msgUnitParam.u8Buffer; len = data_ind->msgUnitParam.u8Size;
From: Andreas Eversberg jolly@eversberg.eu
This part moves GSM time handling from osmo-bts-sysmo part to common part. --- include/osmo-bts/gsm_data.h | 1 + src/common/l1sap.c | 50 ++++++++++++++++++++++++++++++++++ src/osmo-bts-sysmo/l1_if.c | 65 +++++++++++++++++++-------------------------- 3 files changed, 78 insertions(+), 38 deletions(-)
diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h index 5e0af77..c6866a3 100644 --- a/include/osmo-bts/gsm_data.h +++ b/include/osmo-bts/gsm_data.h @@ -80,6 +80,7 @@ struct gsm_bts_role_bts { struct { uint8_t tc4_ctr; } si; + struct gsm_time gsm_time; uint8_t radio_link_timeout;
/* used by the sysmoBTS to adjust band */ diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 633a5a5..6cb636d 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -69,6 +69,53 @@ struct msgb *l1sap_msgb_alloc(unsigned int l2_len) return msg; }
+/* time information received from bts model */ +static int l1sap_info_time_ind(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, + struct info_time_ind_param *info_time_ind) +{ + struct gsm_bts *bts = trx->bts; + struct gsm_bts_role_bts *btsb = bts->role; + + DEBUGP(DL1P, "MPH_INFO time ind %u\n", info_time_ind->fn); + + /* Update our data structures with the current GSM time */ + gsm_fn2gsmtime(&btsb->gsm_time, info_time_ind->fn); + + /* Update time on PCU interface */ + pcu_tx_time_ind(info_time_ind->fn); + + /* check if the measurement period of some lchan has ended + * and pre-compute the respective measurement */ + trx_meas_check_compute(trx, info_time_ind->fn - 1); + + /* increment 'total' for every possible rach */ + if (bts->c0->ts[0].pchan != GSM_PCHAN_CCCH_SDCCH4 + || (info_time_ind->fn % 51) < 27) + btsb->load.rach.total++; + + return 0; +} + +/* any L1 MPH_INFO indication prim recevied from bts model */ +static int l1sap_mph_info_ind(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, struct mph_info_param *info) +{ + int rc = 0; + + switch (info->type) { + case PRIM_INFO_TIME: + rc = l1sap_info_time_ind(trx, l1sap, &info->u.time_ind); + break; + default: + LOGP(DL1P, LOGL_NOTICE, "unknown MPH_INFO ind type %d\n", + info->type); + break; + } + + return rc; +} + /* PH-RTS-IND prim recevied from bts model */ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap, struct ph_data_param *rts_ind) @@ -262,6 +309,9 @@ int l1sap_up(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) int rc = 0;
switch (OSMO_PRIM_HDR(&l1sap->oph)) { + case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_INDICATION): + rc = l1sap_mph_info_ind(trx, l1sap, &l1sap->u.info); + break; case OSMO_PRIM(PRIM_PH_RTS, PRIM_OP_INDICATION): rc = l1sap_ph_rts_ind(trx, l1sap, &l1sap->u.data); break; diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 03e8a56..59a30f2 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -553,6 +553,33 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) 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; + } + + fn = time_ind->u32Fn; + + 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 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) @@ -797,44 +824,6 @@ 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) {
The original code handled both the fact where a TIME indication would be missed (and thus the frame number be higher than previous + 1), as well as the two cases for combined / non-combined CCCH.
The L1SAP code removed some of those bits, which I'm re-introducing here. --- src/common/l1sap.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 6cb636d..9bbbdf3 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -77,6 +77,8 @@ static int l1sap_info_time_ind(struct gsm_bts_trx *trx, struct gsm_bts *bts = trx->bts; struct gsm_bts_role_bts *btsb = bts->role;
+ int frames_expired = info_time_ind->fn - btsb->gsm_time.fn; + DEBUGP(DL1P, "MPH_INFO time ind %u\n", info_time_ind->fn);
/* Update our data structures with the current GSM time */ @@ -89,10 +91,18 @@ static int l1sap_info_time_ind(struct gsm_bts_trx *trx, * and pre-compute the respective measurement */ trx_meas_check_compute(trx, info_time_ind->fn - 1);
- /* increment 'total' for every possible rach */ - if (bts->c0->ts[0].pchan != GSM_PCHAN_CCCH_SDCCH4 - || (info_time_ind->fn % 51) < 27) - btsb->load.rach.total++; + /* 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; }
From: Andreas Eversberg jolly@eversberg.eu
--- include/osmo-bts/bts.h | 2 ++ include/osmo-bts/bts_model.h | 2 -- include/osmo-bts/rsl.h | 2 +- src/common/bts.c | 8 ++++++++ src/common/rsl.c | 3 ++- src/osmo-bts-sysmo/oml.c | 11 +---------- 6 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h index e489973..db30eb4 100644 --- a/include/osmo-bts/bts.h +++ b/include/osmo-bts/bts.h @@ -39,5 +39,7 @@ void load_timer_start(struct gsm_bts *bts);
void bts_update_status(enum bts_global_status which, int on);
+struct gsm_time *get_time(struct gsm_bts *bts); + #endif /* _BTS_H */
diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h index f9b3f0b..64161d2 100644 --- a/include/osmo-bts/bts_model.h +++ b/include/osmo-bts/bts_model.h @@ -12,8 +12,6 @@
int bts_model_init(struct gsm_bts *bts);
-struct gsm_time *bts_model_get_time(struct gsm_bts *bts); - int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type, struct tlv_parsed *old_attr, struct tlv_parsed *new_attr, void *obj); diff --git a/include/osmo-bts/rsl.h b/include/osmo-bts/rsl.h index 6e8122f..42ea6ef 100644 --- a/include/osmo-bts/rsl.h +++ b/include/osmo-bts/rsl.h @@ -17,7 +17,7 @@ int rsl_tx_chan_rqd(struct gsm_bts_trx *trx, struct gsm_time *gtime, uint8_t ra, uint8_t acc_delay); int rsl_tx_est_ind(struct gsm_lchan *lchan, uint8_t link_id, uint8_t *data, int len);
-int rsl_tx_chan_act_ack(struct gsm_lchan *lchan, struct gsm_time *gtime); +int rsl_tx_chan_act_ack(struct gsm_lchan *lchan); int rsl_tx_chan_act_nack(struct gsm_lchan *lchan, uint8_t cause); int rsl_tx_conn_fail(struct gsm_lchan *lchan, uint8_t cause); int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan); diff --git a/src/common/bts.c b/src/common/bts.c index 6cbafd1..74b5144 100644 --- a/src/common/bts.c +++ b/src/common/bts.c @@ -601,3 +601,11 @@ int bts_supports_cipher(struct gsm_bts_role_bts *bts, int rsl_cipher) sup = (1 << (rsl_cipher - 2)) & bts->support.ciphers; return sup > 0; } + +struct gsm_time *get_time(struct gsm_bts *bts) +{ + struct gsm_bts_role_bts *btsb = bts->role; + + return &btsb->gsm_time; +} + diff --git a/src/common/rsl.c b/src/common/rsl.c index 11c7c71..b2e5622 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -520,8 +520,9 @@ int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan) }
/* 8.4.2 sending CHANnel ACTIVation ACKnowledge */ -int rsl_tx_chan_act_ack(struct gsm_lchan *lchan, struct gsm_time *gtime) +int rsl_tx_chan_act_ack(struct gsm_lchan *lchan) { + struct gsm_time *gtime = get_time(lchan->ts->trx->bts); struct msgb *msg; uint8_t chan_nr = gsm_lchan2chan_nr(lchan); uint8_t ie[2]; diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index b590eff..853cb43 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -960,10 +960,8 @@ static int sapi_activate_cb(struct gsm_lchan *lchan, int status) if (lchan->state != LCHAN_S_ACT_REQ) return 0;
- struct gsm_time *time; lchan_set_state(lchan, LCHAN_S_ACTIVE); - time = bts_model_get_time(lchan->ts->trx->bts); - rsl_tx_chan_act_ack(lchan, time); + rsl_tx_chan_act_ack(lchan);
/* set the initial ciphering parameters for both directions */ l1if_set_ciphering(fl1h, lchan, 0); @@ -1518,13 +1516,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,
From: Andreas Eversberg jolly@eversberg.eu
This part replaces channel activation/deactivation/modification routines by MPH_INFO messages. --- include/osmo-bts/bts_model.h | 6 -- include/osmo-bts/l1sap.h | 2 +- src/common/handover.c | 3 +- src/common/l1sap.c | 145 +++++++++++++++++++++++++++++++++++++++++++ src/common/pcu_sock.c | 8 +-- src/common/rsl.c | 25 ++++---- src/osmo-bts-sysmo/l1_if.c | 41 ++++++++++++ src/osmo-bts-sysmo/l1_if.h | 7 +++ src/osmo-bts-sysmo/oml.c | 60 ++++++++---------- 9 files changed, 240 insertions(+), 57 deletions(-)
diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h index 64161d2..a219d5b 100644 --- a/include/osmo-bts/bts_model.h +++ b/include/osmo-bts/bts_model.h @@ -25,12 +25,6 @@ int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo, int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj, uint8_t adm_state);
-int bts_model_rsl_chan_act(struct gsm_lchan *lchan, struct tlv_parsed *tp); -int bts_model_rsl_chan_rel(struct gsm_lchan *lchan); -int bts_model_rsl_chan_mod(struct gsm_lchan *lchan); -int bts_model_rsl_deact_sacch(struct gsm_lchan *lchan); -int bts_model_rsl_mode_modify(struct gsm_lchan *lchan); - int bts_model_trx_deact_rf(struct gsm_bts_trx *trx); int bts_model_trx_close(struct gsm_bts_trx *trx);
diff --git a/include/osmo-bts/l1sap.h b/include/osmo-bts/l1sap.h index a1dc303..dee430f 100644 --- a/include/osmo-bts/l1sap.h +++ b/include/osmo-bts/l1sap.h @@ -56,7 +56,7 @@ void l1sap_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, unsigned int rtp_pl_len);
/* channel control */ -int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr); +int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr, struct tlv_parsed *tp); int l1sap_chan_rel(struct gsm_bts_trx *trx, uint8_t chan_nr); int l1sap_chan_deact_sacch(struct gsm_bts_trx *trx, uint8_t chan_nr); int l1sap_chan_modify(struct gsm_bts_trx *trx, uint8_t chan_nr); diff --git a/src/common/handover.c b/src/common/handover.c index 26a3f51..03433ea 100644 --- a/src/common/handover.c +++ b/src/common/handover.c @@ -33,6 +33,7 @@ #include <osmo-bts/rsl.h> #include <osmo-bts/logging.h> #include <osmo-bts/handover.h> +#include <osmo-bts/l1sap.h>
/* Transmit a handover related PHYS INFO on given lchan */ static int ho_tx_phys_info(struct gsm_lchan *lchan) @@ -114,7 +115,7 @@ void handover_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay)
/* Stop handover detection, wait for valid frame */ lchan->ho.active = HANDOVER_WAIT_FRAME; - if (bts_model_rsl_chan_mod(lchan) != 0) { + if (l1sap_chan_modify(lchan->ts->trx, gsm_lchan2chan_nr(lchan)) != 0) { LOGP(DHO, LOGL_ERROR, "%s failed to modify channel after handover\n", gsm_lchan_name(lchan)); diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 9bbbdf3..e9d815c 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -126,6 +126,67 @@ static int l1sap_mph_info_ind(struct gsm_bts_trx *trx, return rc; }
+/* activation confirm received from bts model */ +static int l1sap_info_act_cnf(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, + struct info_act_cnf_param *info_act_cnf) +{ + struct gsm_lchan *lchan; + + LOGP(DL1P, LOGL_INFO, "activate confirm chan_nr=%02x trx=%d\n", + info_act_cnf->chan_nr, trx->nr); + + lchan = &trx->ts[L1SAP_CHAN2TS(info_act_cnf->chan_nr)] + .lchan[l1sap_chan2ss(info_act_cnf->chan_nr)]; + + if (info_act_cnf->cause) + rsl_tx_chan_act_nack(lchan, info_act_cnf->cause); + else + rsl_tx_chan_act_ack(lchan); + + return 0; +} + +/* activation confirm received from bts model */ +static int l1sap_info_rel_cnf(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, + struct info_act_cnf_param *info_act_cnf) +{ + struct gsm_lchan *lchan; + + LOGP(DL1P, LOGL_INFO, "deactivate confirm chan_nr=%02x trx=%d\n", + info_act_cnf->chan_nr, trx->nr); + + lchan = &trx->ts[L1SAP_CHAN2TS(info_act_cnf->chan_nr)] + .lchan[l1sap_chan2ss(info_act_cnf->chan_nr)]; + + rsl_tx_rf_rel_ack(lchan); + + return 0; +} + +/* any L1 MPH_INFO confirm prim recevied from bts model */ +static int l1sap_mph_info_cnf(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, struct mph_info_param *info) +{ + int rc = 0; + + switch (info->type) { + case PRIM_INFO_ACTIVATE: + rc = l1sap_info_act_cnf(trx, l1sap, &info->u.act_cnf); + break; + case PRIM_INFO_DEACTIVATE: + rc = l1sap_info_rel_cnf(trx, l1sap, &info->u.act_cnf); + break; + default: + LOGP(DL1P, LOGL_NOTICE, "unknown MPH_INFO cnf type %d\n", + info->type); + break; + } + + return rc; +} + /* PH-RTS-IND prim recevied from bts model */ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap, struct ph_data_param *rts_ind) @@ -322,6 +383,9 @@ int l1sap_up(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_INDICATION): rc = l1sap_mph_info_ind(trx, l1sap, &l1sap->u.info); break; + case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_CONFIRM): + rc = l1sap_mph_info_cnf(trx, l1sap, &l1sap->u.info); + break; case OSMO_PRIM(PRIM_PH_RTS, PRIM_OP_INDICATION): rc = l1sap_ph_rts_ind(trx, l1sap, &l1sap->u.data); break; @@ -376,3 +440,84 @@ int l1sap_pdch_req(struct gsm_bts_trx_ts *ts, int is_ptcch, uint32_t fn,
return l1sap_down(ts->trx, l1sap); } + +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) +{ + struct osmo_phsap_prim l1sap; + + memset(&l1sap, 0, sizeof(l1sap)); + osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO, PRIM_OP_REQUEST, + NULL); + l1sap.u.info.type = type; + l1sap.u.info.u.act_req.chan_nr = chan_nr; + l1sap.u.info.u.act_req.sacch_only = sacch_only; + + return l1sap_down(trx, &l1sap); +} + +int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr, struct tlv_parsed *tp) +{ + struct gsm_bts_role_bts *btsb = trx->bts->role; + struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)] + .lchan[l1sap_chan2ss(chan_nr)]; + struct gsm48_chan_desc *cd; + int rc; + + LOGP(DL1P, LOGL_INFO, "activating channel chan_nr=%02x trx=%d\n", + chan_nr, trx->nr); + + if (tp && TLVP_PRESENT(tp, GSM48_IE_CHANDESC_2) && + TLVP_LEN(tp, GSM48_IE_CHANDESC_2) >= sizeof(*cd)) { + cd = (struct gsm48_chan_desc *) + TLVP_VAL(tp, GSM48_IE_CHANDESC_2); + + /* our L1 only supports one global TSC for all channels + * one one TRX, so we need to make sure not to activate + * channels with a different TSC!! */ + if (cd->h0.tsc != (lchan->ts->trx->bts->bsic & 7)) { + LOGP(DRSL, LOGL_ERROR, "lchan TSC %u != BSIC-TSC %u\n", + cd->h0.tsc, lchan->ts->trx->bts->bsic & 7); + return -RSL_ERR_SERV_OPT_UNIMPL; + } + } + + lchan->sacch_deact = 0; + lchan->s = btsb->radio_link_timeout; + + rc = l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_ACTIVATE, 0); + if (rc) + return -RSL_ERR_EQUIPMENT_FAIL; + return 0; +} + +int l1sap_chan_rel(struct gsm_bts_trx *trx, uint8_t chan_nr) +{ + LOGP(DL1P, LOGL_INFO, "deactivating channel chan_nr=%02x trx=%d\n", + chan_nr, trx->nr); + + return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_DEACTIVATE, + 0); +} + +int l1sap_chan_deact_sacch(struct gsm_bts_trx *trx, uint8_t chan_nr) +{ + struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)] + .lchan[l1sap_chan2ss(chan_nr)]; + + LOGP(DL1P, LOGL_INFO, "deactivating sacch chan_nr=%02x trx=%d\n", + chan_nr, trx->nr); + + lchan->sacch_deact = 1; + + return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_DEACTIVATE, + 1); +} + +int l1sap_chan_modify(struct gsm_bts_trx *trx, uint8_t chan_nr) +{ + LOGP(DL1P, LOGL_INFO, "modifying channel chan_nr=%02x trx=%d\n", + chan_nr, trx->nr); + + return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_MODIFY, 0); +} diff --git a/src/common/pcu_sock.c b/src/common/pcu_sock.c index 515993e..a4ca25f 100644 --- a/src/common/pcu_sock.c +++ b/src/common/pcu_sock.c @@ -39,7 +39,6 @@ #include <osmo-bts/bts.h> #include <osmo-bts/rsl.h> #include <osmo-bts/signal.h> -#include <osmo-bts/bts_model.h> #include <osmo-bts/l1sap.h>
uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx); @@ -543,9 +542,9 @@ static int pcu_rx_act_req(struct gsm_bts *bts, return -EINVAL; } if (act_req->activate) - bts_model_rsl_chan_act(lchan, NULL); + l1sap_chan_act(trx, gsm_lchan2chan_nr(lchan), NULL); else - bts_model_rsl_chan_rel(lchan); + l1sap_chan_rel(trx, gsm_lchan2chan_nr(lchan));
return 0; } @@ -650,7 +649,8 @@ static void pcu_sock_close(struct pcu_sock_state *state) if (ts->mo.nm_state.operational == NM_OPSTATE_ENABLED && ts->pchan == GSM_PCHAN_PDCH) { ts->lchan->rel_act_kind = LCHAN_REL_ACT_PCU; - bts_model_rsl_chan_rel(ts->lchan); + l1sap_chan_rel(trx, + gsm_lchan2chan_nr(ts->lchan)); } } } diff --git a/src/common/rsl.c b/src/common/rsl.c index b2e5622..1a52c6e 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -46,6 +46,7 @@ #include <osmo-bts/measurement.h> #include <osmo-bts/pcu_if.h> #include <osmo-bts/handover.h> +#include <osmo-bts/l1sap.h>
//#define FAKE_CIPH_MODE_COMPL
@@ -826,7 +827,7 @@ static int rsl_rx_chan_activ(struct msgb *msg)
/* actually activate the channel in the BTS */ lchan->rel_act_kind = LCHAN_REL_ACT_RSL; - rc = bts_model_rsl_chan_act(msg->lchan, &tp); + rc = l1sap_chan_act(lchan->ts->trx, dch->chan_nr, &tp); if (rc < 0) return rsl_tx_chan_act_nack(lchan, -rc);
@@ -834,10 +835,8 @@ static int rsl_rx_chan_activ(struct msgb *msg) }
/* 8.4.14 RF CHANnel RELease is received */ -static int rsl_rx_rf_chan_rel(struct gsm_lchan *lchan) +static int rsl_rx_rf_chan_rel(struct gsm_lchan *lchan, uint8_t chan_nr) { - int rc; - if (lchan->abis_ip.rtp_socket) { rsl_tx_ipac_dlcx_ind(lchan, RSL_ERR_NORMAL_UNSPEC); osmo_rtp_socket_free(lchan->abis_ip.rtp_socket); @@ -849,9 +848,11 @@ static int rsl_rx_rf_chan_rel(struct gsm_lchan *lchan) handover_reset(lchan);
lchan->rel_act_kind = LCHAN_REL_ACT_RSL; - rc = bts_model_rsl_chan_rel(lchan); + l1sap_chan_rel(lchan->ts->trx, chan_nr); + + lapdm_channel_exit(&lchan->lapdm_ch);
- return rc; + return 0; }
#ifdef FAKE_CIPH_MODE_COMPL @@ -1034,10 +1035,10 @@ static int rsl_tx_mode_modif_ack(struct gsm_lchan *lchan) /* 8.4.9 MODE MODIFY */ static int rsl_rx_mode_modif(struct msgb *msg) { + struct abis_rsl_dchan_hdr *dch = msgb_l2(msg); struct gsm_lchan *lchan = msg->lchan; struct rsl_ie_chan_mode *cm; struct tlv_parsed tp; - int rc;
rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
@@ -1078,12 +1079,12 @@ static int rsl_rx_mode_modif(struct msgb *msg) /* 9.3.53 MultiRate Control */ /* 9.3.54 Supported Codec Types */
- rc = bts_model_rsl_mode_modify(msg->lchan); + l1sap_chan_modify(lchan->ts->trx, dch->chan_nr);
/* FIXME: delay this until L1 says OK? */ - rsl_tx_mode_modif_ack(msg->lchan); + rsl_tx_mode_modif_ack(lchan);
- return rc; + return 0; }
/* 8.4.20 SACCH INFO MODify */ @@ -1734,13 +1735,13 @@ static int rsl_rx_dchan(struct gsm_bts_trx *trx, struct msgb *msg) ret = rsl_rx_chan_activ(msg); break; case RSL_MT_RF_CHAN_REL: - ret = rsl_rx_rf_chan_rel(msg->lchan); + ret = rsl_rx_rf_chan_rel(msg->lchan, dch->chan_nr); break; case RSL_MT_SACCH_INFO_MODIFY: ret = rsl_rx_sacch_inf_mod(msg); break; case RSL_MT_DEACTIVATE_SACCH: - ret = bts_model_rsl_deact_sacch(msg->lchan); + ret = l1sap_chan_deact_sacch(trx, dch->chan_nr); break; case RSL_MT_ENCR_CMD: ret = rsl_rx_encr_cmd(msg); diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 59a30f2..4a398ea 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -532,6 +532,44 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, return 0; }
+static int mph_info_req(struct gsm_bts_trx *trx, struct msgb *msg, + struct osmo_phsap_prim *l1sap) +{ + uint8_t u8Tn, ss; + uint8_t chan_nr; + struct gsm_lchan *lchan; + int rc = 0; + + switch (l1sap->u.info.type) { + 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) { + if (lchan->ho.active == HANDOVER_WAIT_FRAME) + l1if_rsl_chan_mod(lchan); + else + 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); + msgb_free(msg); + break; + default: + LOGP(DL1C, LOGL_NOTICE, "unknown MPH-INFO.req %d\n", + l1sap->u.info.type); + rc = -EINVAL; + } + + return rc; +} + /* primitive from common part */ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) { @@ -542,6 +580,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_MPH_INFO, PRIM_OP_REQUEST): + rc = mph_info_req(trx, msg, l1sap); + break; default: LOGP(DL1C, LOGL_NOTICE, "unknown prim %d op %d\n", l1sap->oph.primitive, l1sap->oph.operation); diff --git a/src/osmo-bts-sysmo/l1_if.h b/src/osmo-bts-sysmo/l1_if.h index 5efa25b..b0a624d 100644 --- a/src/osmo-bts-sysmo/l1_if.h +++ b/src/osmo-bts-sysmo/l1_if.h @@ -119,6 +119,13 @@ 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_chan_mod(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/oml.c b/src/osmo-bts-sysmo/oml.c index 853cb43..f490195 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -37,11 +37,27 @@ #include <osmo-bts/bts.h> #include <osmo-bts/bts_model.h> #include <osmo-bts/handover.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, @@ -950,7 +966,7 @@ static int sapi_activate_cb(struct gsm_lchan *lchan, int status) gsm_lchan_name(lchan), status); lchan_set_state(lchan, LCHAN_S_BROKEN); sapi_clear_queue(&lchan->sapi_cmds); - rsl_tx_chan_act_nack(lchan, RSL_ERR_PROCESSOR_OVERLOAD); + mph_info_chan_confirm(lchan, PRIM_INFO_ACTIVATE, RSL_ERR_PROCESSOR_OVERLOAD); return -1; }
@@ -961,7 +977,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); @@ -983,7 +999,6 @@ static void enqueue_sapi_act_cmd(struct gsm_lchan *lchan, int sapi, int dir)
int lchan_activate(struct gsm_lchan *lchan) { - 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; @@ -1017,8 +1032,6 @@ int lchan_activate(struct gsm_lchan *lchan) #warning "FIXME: Should this be in sapi_activate_cb?" lchan_init_lapdm(lchan);
- lchan->s = btsb->radio_link_timeout; - return 0; }
@@ -1279,7 +1292,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; @@ -1389,7 +1402,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; }
@@ -1401,7 +1414,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; }
@@ -1476,7 +1489,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; @@ -1633,30 +1646,11 @@ int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo, return oml_mo_statechg_nack(mo, NM_NACK_REQ_NOT_GRANT);
} -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); - struct gsm48_chan_desc *cd; - - /* osmo-pcu calls this without a valid 'tp' parameter, so we - * need to make sure we don't crash here */ - if (tp && TLVP_PRESENT(tp, GSM48_IE_CHANDESC_2) && - TLVP_LEN(tp, GSM48_IE_CHANDESC_2) >= sizeof(*cd)) { - cd = (struct gsm48_chan_desc *) - TLVP_VAL(tp, GSM48_IE_CHANDESC_2); - - /* our L1 only supports one global TSC for all channels - * one one TRX, so we need to make sure not to activate - * channels with a different TSC!! */ - if (cd->h0.tsc != (lchan->ts->trx->bts->bsic & 7)) { - LOGP(DRSL, LOGL_ERROR, "lchan TSC %u != BSIC-TSC %u\n", - cd->h0.tsc, lchan->ts->trx->bts->bsic & 7); - return -RSL_ERR_SERV_OPT_UNIMPL; - } - } - - lchan->sacch_deact = 0; lchan_activate(lchan); return 0; } @@ -1665,7 +1659,7 @@ int bts_model_rsl_chan_act(struct gsm_lchan *lchan, struct tlv_parsed *tp) * Modify the given lchan in the handover scenario. This is a lot like * second channel activation but with some additional activation. */ -int bts_model_rsl_chan_mod(struct gsm_lchan *lchan) +int l1if_rsl_chan_mod(struct gsm_lchan *lchan) { const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type]; unsigned int i; @@ -1689,7 +1683,7 @@ int bts_model_rsl_chan_mod(struct gsm_lchan *lchan) 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) { @@ -1702,7 +1696,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)
--- src/common/l1sap.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index e9d815c..c631860 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -467,6 +467,8 @@ int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr, struct tlv_parsed * LOGP(DL1P, LOGL_INFO, "activating channel chan_nr=%02x trx=%d\n", chan_nr, trx->nr);
+ /* osmo-pcu calls this without a valid 'tp' parameter, so we + * need to make sure ew don't crash here */ if (tp && TLVP_PRESENT(tp, GSM48_IE_CHANDESC_2) && TLVP_LEN(tp, GSM48_IE_CHANDESC_2) >= sizeof(*cd)) { cd = (struct gsm48_chan_desc *)
From: Andreas Eversberg jolly@eversberg.eu
This part moves TCH handling from osmo-bts-sysmo to common part. The RTP handling is done at the common part, so they can be used by other BTS models. --- include/osmo-bts/bts_model.h | 3 - src/common/l1sap.c | 151 ++++++++++++++++++++++++++++++++++++++ src/common/rsl.c | 3 +- src/osmo-bts-sysmo/l1_if.c | 169 ++++++++++++++++++++++++++++--------------- src/osmo-bts-sysmo/l1_if.h | 4 +- src/osmo-bts-sysmo/tch.c | 120 ++++++++---------------------- 6 files changed, 294 insertions(+), 156 deletions(-)
diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h index a219d5b..a0f4542 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 c631860..9068bb8 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 1a52c6e..dc49177 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -42,7 +42,6 @@ #include <osmo-bts/oml.h> #include <osmo-bts/amr.h> #include <osmo-bts/signal.h> -#include <osmo-bts/bts_model.h> #include <osmo-bts/measurement.h> #include <osmo-bts/pcu_if.h> #include <osmo-bts/handover.h> @@ -1395,7 +1394,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 4a398ea..5f7b8cf 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -38,8 +38,6 @@ #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> @@ -532,6 +530,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) { @@ -580,6 +665,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; @@ -646,6 +734,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 " @@ -690,7 +784,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); @@ -701,11 +794,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); } @@ -716,50 +817,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(); @@ -820,12 +877,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 */ @@ -1044,7 +1095,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 b0a624d..6f58e95 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 d101b47..997b45b 100644 --- a/src/osmo-bts-sysmo/tch.c +++ b/src/osmo-bts-sysmo/tch.c @@ -40,6 +40,7 @@ #include <osmo-bts/gsm_data.h> #include <osmo-bts/measurement.h> #include <osmo-bts/amr.h> +#include <osmo-bts/l1sap.h>
#include <sysmocom/femtobts/superfemto.h> #include <sysmocom/femtobts/gsml1prim.h> @@ -422,7 +423,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 @@ -434,34 +435,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; - - msg = l1p_msgb_alloc(); - if (!msg) { - LOGP(DRTP, LOGL_ERROR, "%s: Failed to allocate Rx payload.\n", - gsm_lchan_name(lchan)); - return; - } + DEBUGP(DRTP, "%s RTP IN: %s\n", gsm_lchan_name(lchan), + osmo_hexdump(rtp_pl, rtp_pl_len));
- 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: @@ -496,38 +481,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;
- /* 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)); }
/*! \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; @@ -535,50 +499,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) @@ -622,11 +551,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;
--- src/osmo-bts-sysmo/l1_if.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-)
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 5f7b8cf..3b5e823 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -586,29 +586,12 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, /* 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; + data_req_from_l1sap(l1p, fl1, u8Tn, u32Fn, sapi, subCh, + u8BlockNbr, + l1p->u.phDataReq.msgUnitParam.u8Size); } 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; + empty_req_from_l1sap(l1p, fl1, u8Tn, u32Fn, sapi, subCh, u8BlockNbr); } /* send message to DSP's queue */ osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg);
--- src/osmo-bts-sysmo/l1_if.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 3b5e823..f17972b 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -449,7 +449,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, { struct femtol1_hdl *fl1 = trx_femtol1_hdl(trx); uint32_t u32Fn; - uint8_t u8Tn, subCh, u8BlockNbr = 0, sapi; + uint8_t u8Tn, subCh, u8BlockNbr = 0, sapi = 0; uint8_t chan_nr, link_id; GsmL1_Prim_t *l1p; int len; @@ -539,7 +539,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, uint8_t u8Tn, subCh, u8BlockNbr = 0, sapi, ss; uint8_t chan_nr; GsmL1_Prim_t *l1p; - struct msgb *nmsg; + struct msgb *nmsg = NULL;
chan_nr = l1sap->u.tch.chan_nr; u32Fn = l1sap->u.tch.fn;
From: Andreas Eversberg jolly@eversberg.eu
This part moves control channel message primitives from osmo-bts-sysmo to common part.
In order to control ciphering fo BTS model, CIPHER (MPH_INFO) messages are used. --- src/common/l1sap.c | 181 ++++++++++++++++++++++++++++++++++++- src/osmo-bts-sysmo/l1_if.c | 219 ++++++++++++++++++--------------------------- 2 files changed, 265 insertions(+), 135 deletions(-)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 9068bb8..14dbde9 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -69,6 +69,54 @@ struct msgb *l1sap_msgb_alloc(unsigned int l2_len) return msg; }
+static int l1sap_tx_ciph_req(struct gsm_bts_trx *trx, uint8_t chan_nr, + uint8_t downlink, uint8_t uplink) +{ + struct osmo_phsap_prim l1sap_ciph; + + osmo_prim_init(&l1sap_ciph.oph, SAP_GSM_PH, PRIM_MPH_INFO, + PRIM_OP_REQUEST, NULL); + l1sap_ciph.u.info.type = PRIM_INFO_ACT_CIPH; + l1sap_ciph.u.info.u.ciph_req.chan_nr = chan_nr; + l1sap_ciph.u.info.u.ciph_req.downlink = downlink; + l1sap_ciph.u.info.u.ciph_req.uplink = uplink; + + return l1sap_down(trx, &l1sap_ciph); +} + + +/* check if the message is a GSM48_MT_RR_CIPH_M_CMD, and if yes, enable + * uni-directional de-cryption on the uplink. We need this ugly layering + * violation as we have no way of passing down L3 metadata (RSL CIPHERING CMD) + * to this point in L1 */ +static int check_for_ciph_cmd(struct msgb *msg, struct gsm_lchan *lchan, + uint8_t chan_nr) +{ + + /* only do this if we are in the right state */ + switch (lchan->ciph_state) { + case LCHAN_CIPH_NONE: + case LCHAN_CIPH_RX_REQ: + break; + default: + return 0; + } + + /* First byte (Address Field) of LAPDm header) */ + if (msg->data[0] != 0x03) + return 0; + /* First byte (protocol discriminator) of RR */ + if ((msg->data[3] & 0xF) != GSM48_PDISC_RR) + return 0; + /* 2nd byte (msg type) of RR */ + if ((msg->data[4] & 0x3F) != GSM48_MT_RR_CIPH_M_CMD) + return 0; + + l1sap_tx_ciph_req(lchan->ts->trx, chan_nr, 0, 1); + + return 1; +} + /* time information received from bts model */ static int l1sap_info_time_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap, @@ -193,10 +241,13 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx, { struct msgb *msg = l1sap->oph.msg; struct gsm_time g_time; + struct gsm_lchan *lchan; uint8_t chan_nr, link_id; - uint8_t tn; + uint8_t tn, ss; uint32_t fn; uint8_t *p, *si; + struct lapdm_entity *le; + struct osmo_phsap_prim pp; int rc;
chan_nr = rts_ind->chan_nr; @@ -241,6 +292,52 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx, memcpy(p, si, GSM_MACBLOCK_LEN); else memcpy(p, fill_frame, GSM_MACBLOCK_LEN); + } else if (!(chan_nr & 0x80)) { /* only TCH/F, TCH/H, SDCCH/4 and SDCCH/8 have C5 bit cleared */ + if (L1SAP_IS_CHAN_TCHH(chan_nr)) + ss = L1SAP_CHAN2SS_TCHH(chan_nr); /* TCH/H */ + else if (L1SAP_IS_CHAN_SDCCH4(chan_nr)) + ss = L1SAP_CHAN2SS_SDCCH4(chan_nr); /* SDCCH/4 */ + else if (L1SAP_IS_CHAN_SDCCH8(chan_nr)) + ss = L1SAP_CHAN2SS_SDCCH8(chan_nr); /* SDCCH/8 */ + else + ss = 0; /* TCH/F */ + lchan = &trx->ts[tn].lchan[ss]; + if (L1SAP_IS_LINK_SACCH(link_id)) { + p = msgb_put(msg, GSM_MACBLOCK_LEN); + /* L1-header, if not set/modified by layer 1 */ + p[0] = lchan->ms_power; + p[1] = lchan->rqd_ta; + le = &lchan->lapdm_ch.lapdm_acch; + } else + le = &lchan->lapdm_ch.lapdm_dcch; + rc = lapdm_phsap_dequeue_prim(le, &pp); + if (rc < 0) { + if (L1SAP_IS_LINK_SACCH(link_id)) { + /* No SACCH data from LAPDM pending, send SACCH filling */ + uint8_t *si = lchan_sacch_get(lchan); + if (si) { + /* The +2 is empty space where the DSP inserts the L1 hdr */ + memcpy(p + 2, si, GSM_MACBLOCK_LEN - 2); + } else + memcpy(p + 2, fill_frame, GSM_MACBLOCK_LEN - 2); + } else if ((!L1SAP_IS_CHAN_TCHF(chan_nr) && !L1SAP_IS_CHAN_TCHH(chan_nr)) + || lchan->rsl_cmode == RSL_CMOD_SPD_SIGN) { + /* send fill frame only, if not TCH/x != Signalling, otherwise send empty frame */ + p = msgb_put(msg, GSM_MACBLOCK_LEN); + memcpy(p, fill_frame, GSM_MACBLOCK_LEN); + } /* else the message remains empty, so TCH frames are sent */ + } else { + /* The +2 is empty space where the DSP inserts the L1 hdr */ + if (L1SAP_IS_LINK_SACCH(link_id)) + memcpy(p + 2, pp.oph.msg->data + 2, GSM_MACBLOCK_LEN - 2); + else { + p = msgb_put(msg, GSM_MACBLOCK_LEN); + memcpy(p, pp.oph.msg->data, GSM_MACBLOCK_LEN); + /* check if it is a RR CIPH MODE CMD. if yes, enable RX ciphering */ + check_for_ciph_cmd(pp.oph.msg, lchan, chan_nr); + } + msgb_free(pp.oph.msg); + } } else if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr)) { p = msgb_put(msg, GSM_MACBLOCK_LEN); #warning "TODO: Yet another assumption that BS_AG_BLKS_RES=1" @@ -352,12 +449,46 @@ static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx, return 0; }
+/* process radio link timeout counter S */ +static void radio_link_timeout(struct gsm_lchan *lchan, int bad_frame) +{ + struct gsm_bts_role_bts *btsb = lchan->ts->trx->bts->role; + + /* if link loss criterion already reached */ + if (lchan->s == 0) { + DEBUGP(DMEAS, "%s radio link counter S already 0.\n", + gsm_lchan_name(lchan)); + return; + } + + if (bad_frame) { + /* count down radio link counter S */ + lchan->s--; + DEBUGP(DMEAS, "%s counting down radio link counter S=%d\n", + gsm_lchan_name(lchan), lchan->s); + if (lchan->s == 0) + rsl_tx_conn_fail(lchan, RSL_ERR_RADIO_LINK_FAIL); + return; + } + + if (lchan->s < btsb->radio_link_timeout) { + /* count up radio link counter S */ + lchan->s += 2; + if (lchan->s > btsb->radio_link_timeout) + lchan->s = btsb->radio_link_timeout; + DEBUGP(DMEAS, "%s counting up radio link counter S=%d\n", + gsm_lchan_name(lchan), lchan->s); + } +} + /* DATA received from bts model */ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap, struct ph_data_param *data_ind) { struct msgb *msg = l1sap->oph.msg; struct gsm_time g_time; + struct gsm_lchan *lchan; + struct lapdm_entity *le; uint8_t *data = msg->l2h; int len = msgb_l2len(msg); uint8_t chan_nr, link_id; @@ -397,7 +528,53 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx, return 0; }
- return 0; + lchan = &trx->ts[tn].lchan[ss]; + + /* bad frame */ + if (len == 0) { + if (L1SAP_IS_LINK_SACCH(link_id)) + radio_link_timeout(lchan, 1); + return -EINVAL; + } + + if (L1SAP_IS_LINK_SACCH(link_id)) { + radio_link_timeout(lchan, 0); + le = &lchan->lapdm_ch.lapdm_acch; + /* save the SACCH L1 header in the lchan struct for RSL MEAS RES */ + if (len < 2) { + LOGP(DL1P, LOGL_NOTICE, "SACCH with size %u<2 !?!\n", + len); + return -EINVAL; + } + /* Some brilliant engineer decided that the ordering of + * fields on the Um interface is different from the + * order of fields in RLS. See TS 04.04 (Chapter 7.2) + * vs. TS 08.58 (Chapter 9.3.10). */ + lchan->meas.l1_info[0] = data[0] << 3; + lchan->meas.l1_info[0] |= ((data[0] >> 5) & 1) << 2; + lchan->meas.l1_info[1] = data[1]; + lchan->meas.flags |= LC_UL_M_F_L1_VALID; + } else + le = &lchan->lapdm_ch.lapdm_dcch; + + /* if this is the first valid message after enabling Rx + * decryption, we have to enable Tx encryption */ + if (lchan->ciph_state == LCHAN_CIPH_RX_CONF) { + /* HACK: check if it's an I frame, in order to + * ignore some still buffered/queued UI frames received + * before decryption was enabled */ + if (data[0] == 0x01 && (data[1] & 0x01) == 0) { + l1sap_tx_ciph_req(trx, chan_nr, 1, 0); + } + } + + /* SDCCH, SACCH and FACCH all go to LAPDm */ + msgb_pull(msg, (msg->l2h - msg->data)); + msg->l1h = NULL; + lapdm_phsap_up(&l1sap->oph, le); + + /* don't free, because we forwarded data */ + return 1; }
/* TCH received from bts model */ diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index f17972b..6a6437e 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -464,7 +464,11 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, u32Fn = l1sap->u.data.fn; u8Tn = L1SAP_CHAN2TS(chan_nr); subCh = 0x1f; - if (L1SAP_IS_CHAN_TCHF(chan_nr)) { + if (L1SAP_IS_LINK_SACCH(link_id)) { + sapi = GsmL1_Sapi_Sacch; + if (!L1SAP_IS_CHAN_TCHF(chan_nr)) + subCh = l1sap_chan2ss(chan_nr); + } else if (L1SAP_IS_CHAN_TCHF(chan_nr)) { if (trx->ts[u8Tn].pchan == GSM_PCHAN_PDCH) { if (L1SAP_IS_PTCCH(u32Fn)) { sapi = GsmL1_Sapi_Ptcch; @@ -473,7 +477,20 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, sapi = GsmL1_Sapi_Pdtch; u8BlockNbr = L1SAP_FN2MACBLOCK(u32Fn); } + } else { + sapi = GsmL1_Sapi_FacchF; + u8BlockNbr = (u32Fn % 13) >> 2; } + } else if (L1SAP_IS_CHAN_TCHH(chan_nr)) { + subCh = L1SAP_CHAN2SS_TCHH(chan_nr); + sapi = GsmL1_Sapi_FacchH; + u8BlockNbr = (u32Fn % 26) >> 3; + } else if (L1SAP_IS_CHAN_SDCCH4(chan_nr)) { + subCh = L1SAP_CHAN2SS_SDCCH4(chan_nr); + sapi = GsmL1_Sapi_Sdcch; + } else if (L1SAP_IS_CHAN_SDCCH8(chan_nr)) { + subCh = L1SAP_CHAN2SS_SDCCH8(chan_nr); + sapi = GsmL1_Sapi_Sdcch; } else if (L1SAP_IS_CHAN_BCCH(chan_nr)) { sapi = GsmL1_Sapi_Bcch; } else if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr)) { @@ -603,12 +620,27 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, static int mph_info_req(struct gsm_bts_trx *trx, struct msgb *msg, struct osmo_phsap_prim *l1sap) { + struct femtol1_hdl *fl1 = trx_femtol1_hdl(trx); uint8_t u8Tn, ss; uint8_t chan_nr; struct gsm_lchan *lchan; int rc = 0;
switch (l1sap->u.info.type) { + case PRIM_INFO_ACT_CIPH: + chan_nr = l1sap->u.info.u.ciph_req.chan_nr; + u8Tn = L1SAP_CHAN2TS(chan_nr); + ss = l1sap_chan2ss(chan_nr); + lchan = &trx->ts[u8Tn].lchan[ss]; + if (l1sap->u.info.u.ciph_req.uplink) { + l1if_set_ciphering(fl1, lchan, 0); + lchan->ciph_state = LCHAN_CIPH_RX_REQ; + } + if (l1sap->u.info.u.ciph_req.downlink) { + l1if_set_ciphering(fl1, lchan, 1); + lchan->ciph_state = LCHAN_CIPH_TXRX_REQ; + } + break; case PRIM_INFO_ACTIVATE: case PRIM_INFO_DEACTIVATE: case PRIM_INFO_MODIFY: @@ -701,6 +733,40 @@ static uint8_t chan_nr_by_sapi(enum gsm_phys_chan_config pchan, case GsmL1_Sapi_Bcch: cbits = 0x10; break; + case GsmL1_Sapi_Sacch: + switch(pchan) { + case GSM_PCHAN_TCH_F: + cbits = 0x01; + break; + case GSM_PCHAN_TCH_H: + cbits = 0x02 + subCh; + break; + case GSM_PCHAN_CCCH_SDCCH4: + cbits = 0x04 + subCh; + break; + case GSM_PCHAN_SDCCH8_SACCH8C: + cbits = 0x08 + subCh; + break; + default: + LOGP(DL1C, LOGL_ERROR, "SACCH for pchan %d?\n", + pchan); + return 0; + } + break; + case GsmL1_Sapi_Sdcch: + switch(pchan) { + case GSM_PCHAN_CCCH_SDCCH4: + cbits = 0x04 + subCh; + break; + case GSM_PCHAN_SDCCH8_SACCH8C: + cbits = 0x08 + subCh; + break; + default: + LOGP(DL1C, LOGL_ERROR, "SDCCH for pchan %d?\n", + pchan); + return 0; + } + break; case GsmL1_Sapi_Agch: case GsmL1_Sapi_Pch: cbits = 0x12; @@ -723,6 +789,12 @@ static uint8_t chan_nr_by_sapi(enum gsm_phys_chan_config pchan, case GsmL1_Sapi_TchH: cbits = 0x02 + subCh; break; + case GsmL1_Sapi_FacchF: + cbits = 0x01; + break; + case GsmL1_Sapi_FacchH: + cbits = 0x02 + subCh; + break; case GsmL1_Sapi_Ptcch: if (!L1SAP_IS_PTCCH(u32Fn)) { LOGP(DL1C, LOGL_FATAL, "Not expecting PTCCH at frame " @@ -757,11 +829,8 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, struct msgb *resp_msg; GsmL1_PhDataReq_t *data_req; GsmL1_MsgUnitParam_t *msu_param; - struct lapdm_entity *le; - struct gsm_lchan *lchan; struct gsm_time g_time; uint32_t t3p; - struct osmo_phsap_prim pp; int rc; struct osmo_phsap_prim *l1sap; uint8_t chan_nr, link_id; @@ -772,7 +841,10 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, rts_ind->subCh, rts_ind->u8Tn, rts_ind->u32Fn); if (chan_nr) { fn = rts_ind->u32Fn; - link_id = 0; + if (rts_ind->sapi == GsmL1_Sapi_Sacch) + link_id = 0x40; + else + link_id = 0; rc = msgb_trim(l1p_msg, sizeof(*l1sap)); if (rc < 0) MSGB_ABORT(l1p_msg, "No room for primitive\n"); @@ -899,27 +971,6 @@ empty_frame: goto tx; }
-/* determine LAPDm entity inside LAPDm channel for given L1 sapi */ -static struct lapdm_entity *le_by_l1_sapi(struct lapdm_channel *lc, GsmL1_Sapi_t sapi) -{ - switch (sapi) { - case GsmL1_Sapi_Sacch: - return &lc->lapdm_acch; - default: - return &lc->lapdm_dcch; - } -} - -static uint8_t gen_link_id(GsmL1_Sapi_t l1_sapi, uint8_t lapdm_sapi) -{ - uint8_t c_bits = 0; - - if (l1_sapi == GsmL1_Sapi_Sacch) - c_bits = 0x40; - - return c_bits | (lapdm_sapi & 7); -} - static void dump_meas_res(int ll, GsmL1_MeasParam_t *m) { LOGPC(DL1C, ll, ", Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, " @@ -943,46 +994,11 @@ static int process_meas_res(struct gsm_lchan *lchan, GsmL1_MeasParam_t *m) return lchan_new_ul_meas(lchan, &ulm); }
-/* process radio link timeout counter S */ -static void radio_link_timeout(struct gsm_lchan *lchan, int bad_frame) -{ - struct gsm_bts_role_bts *btsb = lchan->ts->trx->bts->role; - - /* if link loss criterion already reached */ - if (lchan->s == 0) { - DEBUGP(DMEAS, "%s radio link counter S already 0.\n", - gsm_lchan_name(lchan)); - return; - } - - if (bad_frame) { - /* count down radio link counter S */ - lchan->s--; - DEBUGP(DMEAS, "%s counting down radio link counter S=%d\n", - gsm_lchan_name(lchan), lchan->s); - if (lchan->s == 0) - rsl_tx_conn_fail(lchan, RSL_ERR_RADIO_LINK_FAIL); - return; - } - - if (lchan->s < btsb->radio_link_timeout) { - /* count up radio link counter S */ - lchan->s += 2; - if (lchan->s > btsb->radio_link_timeout) - lchan->s = btsb->radio_link_timeout; - DEBUGP(DMEAS, "%s counting up radio link counter S=%d\n", - gsm_lchan_name(lchan), lchan->s); - } -} - static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_ind, struct msgb *l1p_msg) { struct gsm_bts_trx *trx = fl1->priv; - struct osmo_phsap_prim pp; struct gsm_lchan *lchan; - struct lapdm_entity *le; - struct msgb *msg; uint8_t chan_nr, link_id; struct osmo_phsap_prim *l1sap; uint32_t fn; @@ -1002,6 +1018,12 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
chan_nr = chan_nr_by_sapi(trx->ts[data_ind->u8Tn].pchan, data_ind->sapi, data_ind->subCh, data_ind->u8Tn, data_ind->u32Fn); + if (!chan_nr) { + LOGP(DL1C, LOGL_ERROR, "PH-DATA-INDICATION for unknown sapi " + "%d\n", data_ind->sapi); + msgb_free(l1p_msg); + return ENOTSUP; + } fn = data_ind->u32Fn; link_id = (data_ind->sapi == GsmL1_Sapi_Sacch) ? 0x40 : 0x00;
@@ -1023,84 +1045,15 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i if (lchan->ho.active == HANDOVER_WAIT_FRAME) handover_frame(lchan);
- switch (data_ind->sapi) { - case GsmL1_Sapi_Sacch: - radio_link_timeout(lchan, (data_ind->msgUnitParam.u8Size == 0)); - if (data_ind->msgUnitParam.u8Size == 0) - break; - /* save the SACCH L1 header in the lchan struct for RSL MEAS RES */ - if (data_ind->msgUnitParam.u8Size < 2) { - LOGP(DL1C, LOGL_NOTICE, "SACCH with size %u<2 !?!\n", - data_ind->msgUnitParam.u8Size); - break; - } - /* Some brilliant engineer decided that the ordering of - * fields on the Um interface is different from the - * order of fields in RLS. See TS 04.04 (Chapter 7.2) - * vs. TS 08.58 (Chapter 9.3.10). */ - lchan->meas.l1_info[0] = data_ind->msgUnitParam.u8Buffer[0] << 3; - lchan->meas.l1_info[0] |= ((data_ind->msgUnitParam.u8Buffer[0] >> 5) & 1) << 2; - lchan->meas.l1_info[1] = data_ind->msgUnitParam.u8Buffer[1]; - lchan->meas.flags |= LC_UL_M_F_L1_VALID; - /* fall-through */ - case GsmL1_Sapi_Sdcch: - case GsmL1_Sapi_FacchF: - case GsmL1_Sapi_FacchH: - /* Check and Re-check for the SACCH */ - if (data_ind->msgUnitParam.u8Size == 0) { - LOGP(DL1C, LOGL_NOTICE, "%s %s data is null.\n", - gsm_lchan_name(lchan), - get_value_string(femtobts_l1sapi_names, data_ind->sapi)); - break; - } - - check_for_first_ciphrd(fl1, &data_ind->msgUnitParam, lchan); - - /* SDCCH, SACCH and FACCH all go to LAPDm */ - le = le_by_l1_sapi(&lchan->lapdm_ch, data_ind->sapi); - /* allocate and fill LAPDm primitive */ - msg = msgb_alloc_headroom(128, 64, "PH-DATA.ind"); - osmo_prim_init(&pp.oph, SAP_GSM_PH, PRIM_PH_DATA, - PRIM_OP_INDICATION, msg); - - /* copy over actual MAC block */ - msg->l2h = msgb_put(msg, data_ind->msgUnitParam.u8Size); - memcpy(msg->l2h, data_ind->msgUnitParam.u8Buffer, - data_ind->msgUnitParam.u8Size); - - /* LAPDm requires those... */ - pp.u.data.chan_nr = gsm_lchan2chan_nr(lchan); - pp.u.data.link_id = gen_link_id(data_ind->sapi, 0); - - /* feed into the LAPDm code of libosmogsm */ - rc = lapdm_phsap_up(&pp.oph, le); - break; - case GsmL1_Sapi_TchF: - case GsmL1_Sapi_TchH: + /* check for TCH */ + if (data_ind->sapi == GsmL1_Sapi_TchF + || data_ind->sapi == GsmL1_Sapi_TchH) { /* TCH speech frame handling */ rc = l1if_tch_rx(trx, chan_nr, l1p_msg); - break; - case GsmL1_Sapi_Pdtch: - case GsmL1_Sapi_Pacch: - case GsmL1_Sapi_Ptcch: - break; - case GsmL1_Sapi_Idle: - /* nothing to send */ - break; - default: - LOGP(DL1C, LOGL_NOTICE, "Rx PH-DATA.ind for unknown L1 SAPI %s\n", - get_value_string(femtobts_l1sapi_names, data_ind->sapi)); - break; - } - - if (!chan_nr) { - /* message was handled by old code, not by L1SAP */ msgb_free(l1p_msg); return rc; }
- /* if we proceed to this point, the message has to be handled via L1SAP */ - /* get data pointer and length */ data = data_ind->msgUnitParam.u8Buffer; len = data_ind->msgUnitParam.u8Size;
--- src/osmo-bts-sysmo/l1_if.c | 55 ---------------------------------------------- 1 file changed, 55 deletions(-)
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 6a6437e..b62a2a3 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -892,61 +892,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_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; - msu_param->u8Buffer[1] = lchan->rqd_ta; - 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); - if (si) { - /* +2 to not overwrite the ms_power/ta values */ - memcpy(msu_param->u8Buffer+2, si, GSM_MACBLOCK_LEN-2); - } else { - /* +2 to not overwrite the ms_power/ta values */ - memcpy(msu_param->u8Buffer+2, fill_frame, GSM_MACBLOCK_LEN-2); - } - } else { - /* +2 to not overwrite the ms_power/ta values */ - memcpy(msu_param->u8Buffer+2, pp.oph.msg->data + 2, 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_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;
... introduced in 2cc37035d73191b71b9ba9c0d559a0da6a5f35e5 --- include/osmo-bts/l1sap.h | 2 ++ src/common/l1sap.c | 51 +++++++++++++++++++++++++++++++++--------- src/osmo-bts-sysmo/l1_if.c | 32 -------------------------- src/osmo-bts-sysmo/l1_if.h | 3 --- tests/sysmobts/sysmobts_test.c | 5 +++-- 5 files changed, 46 insertions(+), 47 deletions(-)
diff --git a/include/osmo-bts/l1sap.h b/include/osmo-bts/l1sap.h index dee430f..8165c81 100644 --- a/include/osmo-bts/l1sap.h +++ b/include/osmo-bts/l1sap.h @@ -68,4 +68,6 @@ extern uint8_t gsmtap_sapi_acch;
#define msgb_l1sap_prim(msg) ((struct osmo_phsap_prim *)(msg)->l1h)
+void bts_check_for_first_ciphrd(struct gsm_lchan *lchan, + uint8_t *data, int len, uint8_t chan_nr); #endif /* L1SAP_H */ diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 14dbde9..3f942e6 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -481,6 +481,46 @@ static void radio_link_timeout(struct gsm_lchan *lchan, int bad_frame) } }
+static inline void check_for_first_ciphrd(struct gsm_lchan *lchan, + uint8_t *data, int len, + uint8_t chan_nr) +{ + uint8_t n_s; + + /* 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) { + printf("ciph_State\n"); + return; + } + + /* HACK: check if it's an I frame, in order to + * ignore some still buffered/queued UI frames received + * before decryption was enabled */ + if (data[0] != 0x01) + return; + + if ((data[1] & 0x01) != 0) + return; + + n_s = data[1] >> 5; + if (lchan->ciph_ns != n_s) + return; + + lchan->ciph_state = LCHAN_CIPH_TXRX_REQ; + + /* this check is only introduced to make the test work :/ */ + if (lchan->ts && lchan->ts->trx) + l1sap_tx_ciph_req(lchan->ts->trx, chan_nr, 1, 0); +} + +/* public helper for the test */ +void bts_check_for_first_ciphrd(struct gsm_lchan *lchan, + uint8_t *data, int len, uint8_t chan_nr) +{ + return check_for_first_ciphrd(lchan, data, len, chan_nr); +} + /* 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) @@ -557,16 +597,7 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx, } else le = &lchan->lapdm_ch.lapdm_dcch;
- /* if this is the first valid message after enabling Rx - * decryption, we have to enable Tx encryption */ - if (lchan->ciph_state == LCHAN_CIPH_RX_CONF) { - /* HACK: check if it's an I frame, in order to - * ignore some still buffered/queued UI frames received - * before decryption was enabled */ - if (data[0] == 0x01 && (data[1] & 0x01) == 0) { - l1sap_tx_ciph_req(trx, chan_nr, 1, 0); - } - } + check_for_first_ciphrd(lchan, data, len, chan_nr);
/* SDCCH, SACCH and FACCH all go to LAPDm */ msgb_pull(msg, (msg->l2h - msg->data)); diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index b62a2a3..14efc2c 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -356,31 +356,6 @@ static int check_for_ciph_cmd(struct femtol1_hdl *fl1h, return 1; }
-static inline void check_for_first_ciphrd(struct femtol1_hdl *fl1h, - GsmL1_MsgUnitParam_t *msgUnitParam, - struct gsm_lchan *lchan) -{ - uint8_t n_s; - - /* 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) - return; - - /* HACK: check if it's an I frame, in order to - * ignore some still buffered/queued UI frames received - * before decryption was enabled */ - if (msgUnitParam->u8Buffer[0] != 0x01) - return; - if ((msgUnitParam->u8Buffer[1] & 0x01) != 0) - return; - n_s = msgUnitParam->u8Buffer[1] >> 5; - if (lchan->ciph_ns != n_s) - return; - lchan->ciph_state = LCHAN_CIPH_TXRX_REQ; - l1if_set_ciphering(fl1h, lchan, 1); -} - /* public helpers for the test */ int bts_check_for_ciph_cmd(struct femtol1_hdl *fl1h, struct msgb *msg, struct gsm_lchan *lchan) @@ -388,13 +363,6 @@ int bts_check_for_ciph_cmd(struct femtol1_hdl *fl1h, return check_for_ciph_cmd(fl1h, msg, lchan); }
-void bts_check_for_first_ciphrd(struct femtol1_hdl *fl1h, - GsmL1_MsgUnitParam_t *msgUnitParam, - struct gsm_lchan *lchan) -{ - return check_for_first_ciphrd(fl1h, msgUnitParam, 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, diff --git a/src/osmo-bts-sysmo/l1_if.h b/src/osmo-bts-sysmo/l1_if.h index 6f58e95..a425776 100644 --- a/src/osmo-bts-sysmo/l1_if.h +++ b/src/osmo-bts-sysmo/l1_if.h @@ -138,7 +138,4 @@ int l1if_rf_clock_info_correct(struct femtol1_hdl *fl1h); /* public helpers for test */ int bts_check_for_ciph_cmd(struct femtol1_hdl *fl1h, struct msgb *msg, struct gsm_lchan *lchan); -void bts_check_for_first_ciphrd(struct femtol1_hdl *fl1h, - GsmL1_MsgUnitParam_t *msgUnitParam, - struct gsm_lchan *lchan); #endif /* _FEMTO_L1_H */ diff --git a/tests/sysmobts/sysmobts_test.c b/tests/sysmobts/sysmobts_test.c index acbc09c..d5035bd 100644 --- a/tests/sysmobts/sysmobts_test.c +++ b/tests/sysmobts/sysmobts_test.c @@ -18,6 +18,7 @@ */
#include <osmo-bts/bts.h> +#include <osmo-bts/l1sap.h>
#include "femtobts.h" #include "l1_if.h" @@ -169,13 +170,13 @@ static void test_sysmobts_cipher(void) /* Handle message sent before ciphering was received */ memcpy(&unit.u8Buffer[0], too_early_classmark, ARRAY_SIZE(too_early_classmark)); unit.u8Size = ARRAY_SIZE(too_early_classmark); - bts_check_for_first_ciphrd(&fl1h, &unit, &lchan); + bts_check_for_first_ciphrd(&lchan, unit.u8Buffer, unit.u8Size, 0); OSMO_ASSERT(lchan.ciph_state == LCHAN_CIPH_RX_CONF);
/* Now send the first ciphered message */ memcpy(&unit.u8Buffer[0], first_ciphered_cipher_cmpl, ARRAY_SIZE(first_ciphered_cipher_cmpl)); unit.u8Size = ARRAY_SIZE(first_ciphered_cipher_cmpl); - bts_check_for_first_ciphrd(&fl1h, &unit, &lchan); + bts_check_for_first_ciphrd(&lchan, unit.u8Buffer, unit.u8Size, 0); OSMO_ASSERT(lchan.ciph_state == LCHAN_CIPH_TXRX_REQ); }
From: Andreas Eversberg jolly@eversberg.eu
This part moves processing of measurement infos from osmo-bts-sysmo to common part. --- include/osmo-bts/l1sap.h | 4 +-- src/common/l1sap.c | 64 +++++++++++++++++++++++++++++------------- src/osmo-bts-sysmo/l1_if.c | 26 ++++++++--------- tests/sysmobts/sysmobts_test.c | 9 ++++-- 4 files changed, 66 insertions(+), 37 deletions(-)
diff --git a/include/osmo-bts/l1sap.h b/include/osmo-bts/l1sap.h index 8165c81..e76aca6 100644 --- a/include/osmo-bts/l1sap.h +++ b/include/osmo-bts/l1sap.h @@ -68,6 +68,6 @@ extern uint8_t gsmtap_sapi_acch;
#define msgb_l1sap_prim(msg) ((struct osmo_phsap_prim *)(msg)->l1h)
-void bts_check_for_first_ciphrd(struct gsm_lchan *lchan, - uint8_t *data, int len, uint8_t chan_nr); +int bts_check_for_first_ciphrd(struct gsm_lchan *lchan, + uint8_t *data, int len); #endif /* L1SAP_H */ diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 3f942e6..f00c5d2 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -155,6 +155,35 @@ static int l1sap_info_time_ind(struct gsm_bts_trx *trx, return 0; }
+/* measurement information received from bts model */ +static int l1sap_info_meas_ind(struct gsm_bts_trx *trx, + struct osmo_phsap_prim *l1sap, + struct info_meas_ind_param *info_meas_ind) +{ + struct bts_ul_meas ulm; + struct gsm_lchan *lchan; + + DEBUGP(DL1P, "MPH_INFO meas ind chan_nr=%02x\n", + info_meas_ind->chan_nr); + + lchan = &trx->ts[L1SAP_CHAN2TS(info_meas_ind->chan_nr)] + .lchan[l1sap_chan2ss(info_meas_ind->chan_nr)]; + + /* 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; + + memset(&ulm, 0, sizeof(ulm)); + ulm.ta_offs_qbits = info_meas_ind->ta_offs_qbits; + ulm.ber10k = info_meas_ind->ber10k; + ulm.inv_rssi = info_meas_ind->inv_rssi; + + lchan_new_ul_meas(lchan, &ulm); + + return 0; +} + /* any L1 MPH_INFO indication prim recevied from bts model */ static int l1sap_mph_info_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap, struct mph_info_param *info) @@ -165,6 +194,9 @@ static int l1sap_mph_info_ind(struct gsm_bts_trx *trx, case PRIM_INFO_TIME: rc = l1sap_info_time_ind(trx, l1sap, &info->u.time_ind); break; + case PRIM_INFO_MEAS: + rc = l1sap_info_meas_ind(trx, l1sap, &info->u.meas_ind); + break; default: LOGP(DL1P, LOGL_NOTICE, "unknown MPH_INFO ind type %d\n", info->type); @@ -481,44 +513,37 @@ static void radio_link_timeout(struct gsm_lchan *lchan, int bad_frame) } }
-static inline void check_for_first_ciphrd(struct gsm_lchan *lchan, - uint8_t *data, int len, - uint8_t chan_nr) +static inline int check_for_first_ciphrd(struct gsm_lchan *lchan, + uint8_t *data, int len) { uint8_t n_s;
/* 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) { - printf("ciph_State\n"); - return; - } + if (lchan->ciph_state != LCHAN_CIPH_RX_CONF) + return 0;
/* HACK: check if it's an I frame, in order to * ignore some still buffered/queued UI frames received * before decryption was enabled */ if (data[0] != 0x01) - return; + return 0;
if ((data[1] & 0x01) != 0) - return; + return 0;
n_s = data[1] >> 5; if (lchan->ciph_ns != n_s) - return; - - lchan->ciph_state = LCHAN_CIPH_TXRX_REQ; + return 0;
- /* this check is only introduced to make the test work :/ */ - if (lchan->ts && lchan->ts->trx) - l1sap_tx_ciph_req(lchan->ts->trx, chan_nr, 1, 0); + return 1; }
/* public helper for the test */ -void bts_check_for_first_ciphrd(struct gsm_lchan *lchan, - uint8_t *data, int len, uint8_t chan_nr) +int bts_check_for_first_ciphrd(struct gsm_lchan *lchan, + uint8_t *data, int len) { - return check_for_first_ciphrd(lchan, data, len, chan_nr); + return check_for_first_ciphrd(lchan, data, len); }
/* DATA received from bts model */ @@ -597,7 +622,8 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx, } else le = &lchan->lapdm_ch.lapdm_dcch;
- check_for_first_ciphrd(lchan, data, len, chan_nr); + if (check_for_first_ciphrd(lchan, data, len)) + l1sap_tx_ciph_req(lchan->ts->trx, chan_nr, 0, 1);
/* SDCCH, SACCH and FACCH all go to LAPDm */ msgb_pull(msg, (msg->l2h - msg->data)); diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 14efc2c..38daa97 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -891,20 +891,20 @@ static void dump_meas_res(int ll, GsmL1_MeasParam_t *m) m->fBer, m->i16BurstTiming); }
-static int process_meas_res(struct gsm_lchan *lchan, GsmL1_MeasParam_t *m) +static int process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr, + 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); + 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 lchan_new_ul_meas(lchan, &ulm); + return l1sap_up(trx, &l1sap); }
static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_ind, @@ -940,7 +940,7 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i fn = data_ind->u32Fn; link_id = (data_ind->sapi == GsmL1_Sapi_Sacch) ? 0x40 : 0x00;
- process_meas_res(lchan, &data_ind->measParam); + process_meas_res(trx, chan_nr, &data_ind->measParam);
if (data_ind->measParam.fLinkQuality < fl1->min_qual_norm && data_ind->msgUnitParam.u8Size != 0) { diff --git a/tests/sysmobts/sysmobts_test.c b/tests/sysmobts/sysmobts_test.c index d5035bd..93fa0e9 100644 --- a/tests/sysmobts/sysmobts_test.c +++ b/tests/sysmobts/sysmobts_test.c @@ -170,14 +170,17 @@ static void test_sysmobts_cipher(void) /* Handle message sent before ciphering was received */ memcpy(&unit.u8Buffer[0], too_early_classmark, ARRAY_SIZE(too_early_classmark)); unit.u8Size = ARRAY_SIZE(too_early_classmark); - bts_check_for_first_ciphrd(&lchan, unit.u8Buffer, unit.u8Size, 0); + rc = bts_check_for_first_ciphrd(&lchan, unit.u8Buffer, unit.u8Size); + OSMO_ASSERT(rc == 0); OSMO_ASSERT(lchan.ciph_state == LCHAN_CIPH_RX_CONF);
/* Now send the first ciphered message */ memcpy(&unit.u8Buffer[0], first_ciphered_cipher_cmpl, ARRAY_SIZE(first_ciphered_cipher_cmpl)); unit.u8Size = ARRAY_SIZE(first_ciphered_cipher_cmpl); - bts_check_for_first_ciphrd(&lchan, unit.u8Buffer, unit.u8Size, 0); - OSMO_ASSERT(lchan.ciph_state == LCHAN_CIPH_TXRX_REQ); + rc = bts_check_for_first_ciphrd(&lchan, unit.u8Buffer, unit.u8Size); + OSMO_ASSERT(rc == 1); + /* we cannot test for lchan.ciph_state == LCHAN_CIPH_RX_CONF_TX_REQ, as + * this happens asynchronously on the other side of the l1sap queue */ }
int main(int argc, char **argv)
On Wed, Aug 27, 2014 at 11:54:46PM +0200, Harald Welte wrote:
+static inline int check_for_first_ciphrd(struct gsm_lchan *lchan,
uint8_t *data, int len)
{
- lchan->ciph_state = LCHAN_CIPH_TXRX_REQ;
this looks to belong to a different patch?!
Hi Holger,
On Thu, Aug 28, 2014 at 02:01:30PM +0200, Holger Hans Peter Freyther wrote:
- lchan->ciph_state = LCHAN_CIPH_TXRX_REQ;
this looks to belong to a different patch?!
Indeed, I accidentially squashed two wrong commits. I've fixed it. The two affected patcheas are patch 26 and 27 of the series, new commits are: 69eba91fdc97f042f72049a754f0162c9c289f45 and 0fa6dc976b41757c95c587989185b5bb55d17fdf
attached for your reference (rather than spamming the list with the entire series again).
From: Andreas Eversberg jolly@eversberg.eu
There are three transitions:
1. LCHAN_CIPH_NONE -> LCHAN_CIPH_RX_REQ -> LCHAN_CIPH_RX_CONF
It is used to enable ciphering in RX (uplink) direction only.
2. LCHAN_CIPH_RX_CONF -> LCHAN_CIPH_RX_CONF_TX_REQ -> LCHAN_CIPH_RXTX_CONF
It is used to additionally enable ciphering in TX (downlink) direction.
3. LCHAN_CIPH_NONE -> LCHAN_CIPH_RXTX_REQ -> LCHAN_CIPH_RX_CONF_TX_REQ -> LCHAN_CIPH_RXTX_CONF
It is used to enable ciphering in both TX and RX directions. This is used when the channel is activated with encryption already enabled. (assignment or handover)
In order to follow the order of these transitions, the RX direction must always be set before the TX direction.
If no cipher key is set (A5/0), ciphering is set to ALG 0, but lchan cipher state remains at LCHAN_CIPH_NONE. --- include/osmo-bts/gsm_data.h | 5 +++-- src/common/l1sap.c | 1 - src/osmo-bts-sysmo/l1_if.c | 5 ++++- src/osmo-bts-sysmo/oml.c | 19 +++++++++++++++---- 4 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h index c6866a3..bd726e2 100644 --- a/include/osmo-bts/gsm_data.h +++ b/include/osmo-bts/gsm_data.h @@ -91,8 +91,9 @@ enum lchan_ciph_state { LCHAN_CIPH_NONE, LCHAN_CIPH_RX_REQ, LCHAN_CIPH_RX_CONF, - LCHAN_CIPH_TXRX_REQ, - LCHAN_CIPH_TXRX_CONF, + LCHAN_CIPH_RXTX_REQ, + LCHAN_CIPH_RX_CONF_TX_REQ, + LCHAN_CIPH_RXTX_CONF, };
#define bts_role_bts(x) ((struct gsm_bts_role_bts *)(x)->role) diff --git a/src/common/l1sap.c b/src/common/l1sap.c index f00c5d2..3f099b0 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -96,7 +96,6 @@ static int check_for_ciph_cmd(struct msgb *msg, struct gsm_lchan *lchan, /* only do this if we are in the right state */ switch (lchan->ciph_state) { case LCHAN_CIPH_NONE: - case LCHAN_CIPH_RX_REQ: break; default: return 0; diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 38daa97..b4ae300 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -606,8 +606,11 @@ static int mph_info_req(struct gsm_bts_trx *trx, struct msgb *msg, } if (l1sap->u.info.u.ciph_req.downlink) { l1if_set_ciphering(fl1, lchan, 1); - lchan->ciph_state = LCHAN_CIPH_TXRX_REQ; + lchan->ciph_state = LCHAN_CIPH_RX_CONF_TX_REQ; } + if (l1sap->u.info.u.ciph_req.downlink + && l1sap->u.info.u.ciph_req.uplink) + lchan->ciph_state = LCHAN_CIPH_RXTX_REQ; break; case PRIM_INFO_ACTIVATE: case PRIM_INFO_DEACTIVATE: diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index f490195..dc8a625 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -980,8 +980,12 @@ static int sapi_activate_cb(struct gsm_lchan *lchan, int status) mph_info_chan_confirm(lchan, PRIM_INFO_ACTIVATE, 0);
/* set the initial ciphering parameters for both directions */ - l1if_set_ciphering(fl1h, lchan, 0); l1if_set_ciphering(fl1h, lchan, 1); + l1if_set_ciphering(fl1h, lchan, 0); + if (lchan->encr.alg_id) + lchan->ciph_state = LCHAN_CIPH_RXTX_REQ; + else + lchan->ciph_state = LCHAN_CIPH_NONE;
return 0; } @@ -1130,9 +1134,16 @@ static int chmod_modif_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg, LOGPC(DL1C, LOGL_INFO, "RX_REQ -> RX_CONF\n"); lchan->ciph_state = LCHAN_CIPH_RX_CONF; break; - case LCHAN_CIPH_TXRX_REQ: - LOGPC(DL1C, LOGL_INFO, "TX_REQ -> TX_CONF\n"); - lchan->ciph_state = LCHAN_CIPH_TXRX_CONF; + case LCHAN_CIPH_RX_CONF_TX_REQ: + LOGPC(DL1C, LOGL_INFO, "RX_CONF_TX_REQ -> RXTX_CONF\n"); + lchan->ciph_state = LCHAN_CIPH_RXTX_CONF; + break; + case LCHAN_CIPH_RXTX_REQ: + LOGPC(DL1C, LOGL_INFO, "RXTX_REQ -> RX_CONF_TX_REQ\n"); + lchan->ciph_state = LCHAN_CIPH_RX_CONF_TX_REQ; + break; + case LCHAN_CIPH_NONE: + LOGPC(DL1C, LOGL_INFO, "\n"); break; default: LOGPC(DL1C, LOGL_INFO, "unhandled state %u\n", lchan->ciph_state);
From: Andreas Eversberg jolly@eversberg.eu
--- src/common/l1sap.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 3f099b0..e006412 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -116,6 +116,167 @@ static int check_for_ciph_cmd(struct msgb *msg, struct gsm_lchan *lchan, return 1; }
+struct gsmtap_inst *gsmtap = NULL; +uint32_t gsmtap_sapi_mask = 0; +uint8_t gsmtap_sapi_acch = 0; + +const struct value_string gsmtap_sapi_names[] = { + { GSMTAP_CHANNEL_BCCH, "BCCH" }, + { GSMTAP_CHANNEL_CCCH, "CCCH" }, + { GSMTAP_CHANNEL_RACH, "RACH" }, + { GSMTAP_CHANNEL_AGCH, "AGCH" }, + { GSMTAP_CHANNEL_PCH, "PCH" }, + { GSMTAP_CHANNEL_SDCCH, "SDCCH" }, + { GSMTAP_CHANNEL_TCH_F, "TCH/F" }, + { GSMTAP_CHANNEL_TCH_H, "TCH/H" }, + { GSMTAP_CHANNEL_PACCH, "PACCH" }, + { GSMTAP_CHANNEL_PDCH, "PDTCH" }, + { GSMTAP_CHANNEL_PTCCH, "PTCCH" }, + { GSMTAP_CHANNEL_CBCH51,"CBCH" }, + { GSMTAP_CHANNEL_ACCH, "SACCH" }, + { 0, NULL } +}; + +/* send primitive as gsmtap */ +static int gsmtap_ph_data(struct osmo_phsap_prim *l1sap, uint8_t *chan_type, + uint8_t *tn, uint8_t *ss, uint32_t *fn, uint8_t **data, int *len) +{ + struct msgb *msg = l1sap->oph.msg; + uint8_t chan_nr, link_id; + + *data = msg->data + sizeof(struct osmo_phsap_prim); + *len = msg->len - sizeof(struct osmo_phsap_prim); + *fn = l1sap->u.data.fn; + *tn = L1SAP_CHAN2TS(l1sap->u.data.chan_nr); + chan_nr = l1sap->u.data.chan_nr; + link_id = l1sap->u.data.link_id; + + if (L1SAP_IS_CHAN_TCHF(chan_nr)) { + *chan_type = GSMTAP_CHANNEL_TCH_F; + } else if (L1SAP_IS_CHAN_TCHH(chan_nr)) { + *ss = L1SAP_CHAN2SS_TCHH(chan_nr); + *chan_type = GSMTAP_CHANNEL_TCH_H; + } else if (L1SAP_IS_CHAN_SDCCH4(chan_nr)) { + *ss = L1SAP_CHAN2SS_SDCCH4(chan_nr); + *chan_type = GSMTAP_CHANNEL_SDCCH; + } else if (L1SAP_IS_CHAN_SDCCH8(chan_nr)) { + *ss = L1SAP_CHAN2SS_SDCCH8(chan_nr); + *chan_type = GSMTAP_CHANNEL_SDCCH; + } else if (L1SAP_IS_CHAN_BCCH(chan_nr)) { + *chan_type = GSMTAP_CHANNEL_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. */ + if (L1SAP_FN2CCCHBLOCK(*fn) >= 1) + *chan_type = GSMTAP_CHANNEL_PCH; + else + *chan_type = GSMTAP_CHANNEL_AGCH; + } + if (L1SAP_IS_LINK_SACCH(link_id)) + *chan_type |= GSMTAP_CHANNEL_ACCH; + + return 0; +} + +static int gsmtap_pdch(struct osmo_phsap_prim *l1sap, uint8_t *chan_type, + uint8_t *tn, uint8_t *ss, uint32_t *fn, uint8_t **data, int *len) +{ + struct msgb *msg = l1sap->oph.msg; + + *data = msg->data + sizeof(struct osmo_phsap_prim); + *len = msg->len - sizeof(struct osmo_phsap_prim); + *fn = l1sap->u.data.fn; + *tn = L1SAP_CHAN2TS(l1sap->u.data.chan_nr); + + if (L1SAP_IS_PTCCH(*fn)) { + *chan_type = GSMTAP_CHANNEL_PTCCH; + *ss = L1SAP_FN2PTCCHBLOCK(*fn); + if (l1sap->oph.primitive + == PRIM_OP_INDICATION) { + if ((*data[0]) == 7) + return -EINVAL; + (*data)++; + (*len)--; + } + } else + *chan_type = GSMTAP_CHANNEL_PACCH; + + return 0; +} + +static int gsmtap_ph_rach(struct osmo_phsap_prim *l1sap, uint8_t *chan_type, + uint8_t *tn, uint8_t *ss, uint32_t *fn, uint8_t **data, int *len) +{ + uint8_t chan_nr; + + *chan_type = GSMTAP_CHANNEL_RACH; + *fn = l1sap->u.rach_ind.fn; + *tn = L1SAP_CHAN2TS(l1sap->u.rach_ind.chan_nr); + chan_nr = l1sap->u.rach_ind.chan_nr; + if (L1SAP_IS_CHAN_TCHH(chan_nr)) + *ss = L1SAP_CHAN2SS_TCHH(chan_nr); + else if (L1SAP_IS_CHAN_SDCCH4(chan_nr)) + *ss = L1SAP_CHAN2SS_SDCCH4(chan_nr); + else if (L1SAP_IS_CHAN_SDCCH8(chan_nr)) + *ss = L1SAP_CHAN2SS_SDCCH8(chan_nr); + *data = &l1sap->u.rach_ind.ra; + *len = 1; + + return 0; +} + +static int to_gsmtap(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) +{ + uint8_t *data; + int len; + uint8_t chan_type = 0, tn = 0, ss = 0; + uint32_t fn; + uint16_t uplink = GSMTAP_ARFCN_F_UPLINK; + int rc; + + if (!gsmtap) + return 0; + + switch (OSMO_PRIM_HDR(&l1sap->oph)) { + case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST): + uplink = 0; + /* fall through */ + case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_INDICATION): + if (trx->ts[tn].pchan == GSM_PCHAN_PDCH) + rc = gsmtap_pdch(l1sap, &chan_type, &tn, &ss, &fn, &data, + &len); + else + rc = gsmtap_ph_data(l1sap, &chan_type, &tn, &ss, &fn, + &data, &len); + break; + case OSMO_PRIM(PRIM_PH_RACH, PRIM_OP_INDICATION): + rc = gsmtap_ph_rach(l1sap, &chan_type, &tn, &ss, &fn, &data, + &len); + break; + default: + rc = -ENOTSUP; + } + + if (rc) + return rc; + + if (len == 0) + return 0; + if ((chan_type & GSMTAP_CHANNEL_ACCH)) { + if (!gsmtap_sapi_acch) + return 0; + } else { + if (!((1 << (chan_type & 31)) & gsmtap_sapi_mask)) + return 0; + } + + gsmtap_send(gsmtap, trx->arfcn | uplink, tn, chan_type, ss, fn, 0, 0, + data, len); + + return 0; +} + /* time information received from bts model */ static int l1sap_info_time_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap, @@ -743,12 +904,14 @@ int l1sap_up(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) rc = l1sap_tch_rts_ind(trx, l1sap, &l1sap->u.tch); break; case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_INDICATION): + to_gsmtap(trx, l1sap); 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): + to_gsmtap(trx, l1sap); rc = l1sap_ph_rach_ind(trx, l1sap, &l1sap->u.rach_ind); break; default: @@ -767,6 +930,10 @@ int l1sap_up(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) /* any L1 prim sent to bts model */ static int l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) { + if (OSMO_PRIM_HDR(&l1sap->oph) == + OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST)) + to_gsmtap(trx, l1sap); + return bts_model_l1sap_down(trx, l1sap); }
From: Andreas Eversberg jolly@eversberg.eu
--- include/osmo-bts/vty.h | 2 +- src/common/vty.c | 129 +++++++++++++++++++++++++++++++++++++- src/osmo-bts-sysmo/main.c | 4 +- src/osmo-bts-sysmo/sysmobts_vty.c | 80 ----------------------- 4 files changed, 130 insertions(+), 85 deletions(-)
diff --git a/include/osmo-bts/vty.h b/include/osmo-bts/vty.h index 1bc7e71..510abab 100644 --- a/include/osmo-bts/vty.h +++ b/include/osmo-bts/vty.h @@ -15,7 +15,7 @@ extern struct cmd_element ournode_end_cmd; enum node_type bts_vty_go_parent(struct vty *vty); int bts_vty_is_config_node(struct vty *vty, int node);
-int bts_vty_init(const struct log_info *cat); +int bts_vty_init(struct gsm_bts *bts, const struct log_info *cat);
extern struct vty_app_info bts_vty_info;
diff --git a/src/common/vty.c b/src/common/vty.c index 6b57b0b..37f75fc 100644 --- a/src/common/vty.c +++ b/src/common/vty.c @@ -24,12 +24,15 @@ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> +#include <ctype.h>
#include <osmocom/core/talloc.h> #include <osmocom/gsm/abis_nm.h> #include <osmocom/vty/vty.h> #include <osmocom/vty/command.h> #include <osmocom/vty/logging.h> +#include <osmocom/vty/misc.h> +#include <osmocom/core/gsmtap.h>
#include <osmocom/trau/osmo_ortp.h>
@@ -44,7 +47,7 @@ #include <osmo-bts/bts_model.h> #include <osmo-bts/measurement.h> #include <osmo-bts/vty.h> - +#include <osmo-bts/l1sap.h>
enum node_type bts_vty_go_parent(struct vty *vty) { @@ -158,10 +161,38 @@ DEFUN(cfg_bts_trx, cfg_bts_trx_cmd, return CMD_SUCCESS; }
+/* FIXME: move to libosmocore ? */ +static char buf_casecnvt[256]; +char *osmo_str_tolower(const char *in) +{ + int len, i; + + if (!in) + return NULL; + + len = strlen(in); + if (len > sizeof(buf_casecnvt)) + len = sizeof(buf_casecnvt); + + for (i = 0; i < len; i++) { + buf_casecnvt[i] = tolower(in[i]); + if (in[i] == '\0') + break; + } + if (i < sizeof(buf_casecnvt)) + buf_casecnvt[i] = '\0'; + + /* just to make sure we're always zero-terminated */ + buf_casecnvt[sizeof(buf_casecnvt)-1] = '\0'; + + return buf_casecnvt; +} + static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb = bts_role_bts(bts); struct gsm_bts_trx *trx; + int i;
vty_out(vty, "bts %u%s", bts->nr, VTY_NEWLINE); if (bts->description) @@ -183,6 +214,17 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) btsb->agch_queue_thresh_level, btsb->agch_queue_low_level, btsb->agch_queue_high_level, VTY_NEWLINE);
+ for (i = 0; i < 32; i++) { + if (gsmtap_sapi_mask & (1 << i)) { + const char *name = get_value_string(gsmtap_sapi_names, i); + vty_out(vty, " gsmtap-sapi %s%s", osmo_str_tolower(name), VTY_NEWLINE); + } + } + if (gsmtap_sapi_acch) { + const char *name = get_value_string(gsmtap_sapi_names, GSMTAP_CHANNEL_ACCH); + vty_out(vty, " gsmtap-sapi %s%s", osmo_str_tolower(name), VTY_NEWLINE); + } + bts_model_config_write_bts(vty, bts);
llist_for_each_entry(trx, &bts->trx_list, list) { @@ -588,6 +630,36 @@ static struct gsm_lchan *resolve_lchan(struct gsm_network *net, "logical channel commands\n" \ "logical channel number\n"
+DEFUN(cfg_trx_gsmtap_sapi, cfg_trx_gsmtap_sapi_cmd, + "HIDDEN", "HIDDEN") +{ + int sapi; + + sapi = get_string_value(gsmtap_sapi_names, argv[0]); + + if (sapi == GSMTAP_CHANNEL_ACCH) + gsmtap_sapi_acch = 1; + else + gsmtap_sapi_mask |= (1 << sapi); + + return CMD_SUCCESS; +} + +DEFUN(cfg_trx_no_gsmtap_sapi, cfg_trx_no_gsmtap_sapi_cmd, + "HIDDEN", "HIDDEN") +{ + int sapi; + + sapi = get_string_value(gsmtap_sapi_names, argv[0]); + + if (sapi == GSMTAP_CHANNEL_ACCH) + gsmtap_sapi_acch = 0; + else + gsmtap_sapi_mask &= ~(1 << sapi); + + return CMD_SUCCESS; +} + DEFUN(bts_t_t_l_jitter_buf, bts_t_t_l_jitter_buf_cmd, "bts <0-0> trx <0-0> ts <0-7> lchan <0-1> rtp jitter-buffer <0-10000>", @@ -614,8 +686,58 @@ DEFUN(bts_t_t_l_jitter_buf, return CMD_SUCCESS; }
-int bts_vty_init(const struct log_info *cat) +DEFUN(bts_t_t_l_loopback, + bts_t_t_l_loopback_cmd, + "bts <0-0> trx <0-0> ts <0-7> lchan <0-1> loopback", + BTS_T_T_L_STR "Set loopback\n") { + struct gsm_network *net = gsmnet_from_vty(vty); + struct gsm_lchan *lchan; + + lchan = resolve_lchan(net, argv, 0); + if (!lchan) { + vty_out(vty, "%% can't find BTS%s", VTY_NEWLINE); + return CMD_WARNING; + } + lchan->loopback = 1; + + return CMD_SUCCESS; +} + +DEFUN(no_bts_t_t_l_loopback, + no_bts_t_t_l_loopback_cmd, + "no bts <0-0> trx <0-0> ts <0-7> lchan <0-1> loopback", + NO_STR BTS_T_T_L_STR "Set loopback\n") +{ + struct gsm_network *net = gsmnet_from_vty(vty); + struct gsm_lchan *lchan; + + lchan = resolve_lchan(net, argv, 0); + if (!lchan) { + vty_out(vty, "%% can't find BTS%s", VTY_NEWLINE); + return CMD_WARNING; + } + lchan->loopback = 0; + + return CMD_SUCCESS; +} + +int bts_vty_init(struct gsm_bts *bts, const struct log_info *cat) +{ + cfg_trx_gsmtap_sapi_cmd.string = vty_cmd_string_from_valstr(bts, gsmtap_sapi_names, + "gsmtap-sapi (", + "|",")", VTY_DO_LOWER); + cfg_trx_gsmtap_sapi_cmd.doc = vty_cmd_string_from_valstr(bts, gsmtap_sapi_names, + "GSMTAP SAPI\n", + "\n", "", 0); + + cfg_trx_no_gsmtap_sapi_cmd.string = vty_cmd_string_from_valstr(bts, gsmtap_sapi_names, + "no gsmtap-sapi (", + "|",")", VTY_DO_LOWER); + cfg_trx_no_gsmtap_sapi_cmd.doc = vty_cmd_string_from_valstr(bts, gsmtap_sapi_names, + NO_STR "GSMTAP SAPI\n", + "\n", "", 0); + install_element_ve(&show_bts_cmd);
logging_vty_add_cmds(cat); @@ -635,6 +757,9 @@ int bts_vty_init(const struct log_info *cat) install_element(BTS_NODE, &cfg_bts_agch_queue_mgmt_default_cmd); install_element(BTS_NODE, &cfg_bts_agch_queue_mgmt_params_cmd);
+ install_element(BTS_NODE, &cfg_trx_gsmtap_sapi_cmd); + install_element(BTS_NODE, &cfg_trx_no_gsmtap_sapi_cmd); + /* add and link to TRX config node */ install_element(BTS_NODE, &cfg_bts_trx_cmd); install_node(&trx_node, config_write_dummy); diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index 51619ee..27b593b 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -310,8 +310,9 @@ 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_log_info); + bts_vty_init(bts, &bts_log_info);
handle_options(argc, argv);
@@ -327,7 +328,6 @@ int main(int argc, char **argv) } }
- bts = gsm_bts_alloc(tall_bts_ctx); if (bts_init(bts) < 0) { fprintf(stderr, "unable to open bts\n"); exit(1); diff --git a/src/osmo-bts-sysmo/sysmobts_vty.c b/src/osmo-bts-sysmo/sysmobts_vty.c index 8b617d7..cad29f5 100644 --- a/src/osmo-bts-sysmo/sysmobts_vty.c +++ b/src/osmo-bts-sysmo/sysmobts_vty.c @@ -84,34 +84,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_eeprom, cfg_trx_clkcal_eeprom_cmd, "clock-calibration eeprom", "Use the eeprom clock calibration value\n") @@ -497,37 +469,9 @@ void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " auto-band%s", VTY_NEWLINE); }
-/* FIXME: move to libosmocore ? */ -static char buf_casecnvt[256]; -char *osmo_str_tolower(const char *in) -{ - int len, i; - - if (!in) - return NULL; - - len = strlen(in); - if (len > sizeof(buf_casecnvt)) - len = sizeof(buf_casecnvt); - - for (i = 0; i < len; i++) { - buf_casecnvt[i] = tolower(in[i]); - if (in[i] == '\0') - break; - } - if (i < sizeof(buf_casecnvt)) - buf_casecnvt[i] = '\0'; - - /* just to make sure we're always zero-terminated */ - buf_casecnvt[sizeof(buf_casecnvt)-1] = '\0'; - - return buf_casecnvt; -} - void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) { struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); - int i;
if (fl1h->clk_use_eeprom) vty_out(vty, " clock-calibration eeprom%s", VTY_NEWLINE); @@ -549,14 +493,6 @@ void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) if (trx->nominal_power != sysmobts_get_nominal_power(trx)) vty_out(vty, " nominal-tx-power %d%s", trx->nominal_power, 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) @@ -578,20 +514,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); @@ -614,8 +536,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);
From: Andreas Eversberg jolly@eversberg.eu
--- src/osmo-bts-sysmo/main.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index 27b593b..8abff5f 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -38,6 +38,8 @@ #include <osmocom/vty/telnet_interface.h> #include <osmocom/vty/logging.h> #include <osmocom/vty/ports.h> +#include <osmocom/core/gsmtap_util.h> +#include <osmocom/core/gsmtap.h>
#include <osmo-bts/gsm_data.h> #include <osmo-bts/logging.h> @@ -47,6 +49,7 @@ #include <osmo-bts/bts_model.h> #include <osmo-bts/pcu_if.h> #include <osmo-bts/control_if.h> +#include <osmo-bts/l1sap.h>
#define SYSMOBTS_RF_LOCK_PATH "/var/lock/bts_rf_lock"
@@ -64,6 +67,7 @@ static const char *config_file = "osmo-bts.cfg"; static int daemonize = 0; static unsigned int dsp_trace = 0x71c00020; static int rt_prio = -1; +static char *gsmtap_ip = 0;
int bts_model_init(struct gsm_bts *bts) { @@ -167,6 +171,7 @@ static void print_help() " -w --hw-version Print the targeted HW Version\n" " -M --pcu-direct Force PCU to access message queue for " "PDCH dchannel directly\n" + " -i --gsmtap-ip The destination IP used for GSMTAP.\n" ); }
@@ -198,10 +203,11 @@ static void handle_options(int argc, char **argv) { "hw-version", 0, 0, 'w' }, { "pcu-direct", 0, 0, 'M' }, { "realtime", 1, 0, 'r' }, + { "gsmtap-ip", 1, 0, 'i' }, { 0, 0, 0, 0 } };
- c = getopt_long(argc, argv, "hc:d:Dc:sTVe:p:w:Mr:", + c = getopt_long(argc, argv, "hc:d:Dc:sTVe:p:w:Mr:i:", long_options, &option_idx); if (c == -1) break; @@ -246,6 +252,9 @@ static void handle_options(int argc, char **argv) case 'r': rt_prio = atoi(optarg); break; + case 'i': + gsmtap_ip = optarg; + break; default: break; } @@ -328,6 +337,15 @@ int main(int argc, char **argv) } }
+ if (gsmtap_ip) { + gsmtap = gsmtap_source_init(gsmtap_ip, GSMTAP_UDP_PORT, 1); + if (!gsmtap) { + fprintf(stderr, "Failed during gsmtap_init()\n"); + exit(1); + } + gsmtap_source_add_sink(gsmtap); + } + if (bts_init(bts) < 0) { fprintf(stderr, "unable to open bts\n"); exit(1);
From: Andreas Eversberg jolly@eversberg.eu
--- src/osmo-bts-sysmo/l1_if.c | 101 --------------------------------------------- src/osmo-bts-sysmo/l1_if.h | 3 -- 2 files changed, 104 deletions(-)
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index b4ae300..2ba7c3c 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -33,8 +33,6 @@ #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>
@@ -67,97 +65,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 */ @@ -872,8 +779,6 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, } tx:
- tx_to_gsmtap(fl1, resp_msg); - /* transmit */ osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], resp_msg);
@@ -921,8 +826,6 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i uint8_t *data, len; int rc = 0;
- ul_to_gsmtap(fl1, l1p_msg); - lchan = l1if_hLayer_to_lchan(fl1->priv, data_ind->hLayer2); if (!lchan) { LOGP(DL1C, LOGL_ERROR, @@ -1624,10 +1527,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; }
diff --git a/src/osmo-bts-sysmo/l1_if.h b/src/osmo-bts-sysmo/l1_if.h index a425776..dba608c 100644 --- a/src/osmo-bts-sysmo/l1_if.h +++ b/src/osmo-bts-sysmo/l1_if.h @@ -53,9 +53,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;
From: Andreas Eversberg jolly@eversberg.eu
--- src/common/l1sap.c | 4 ++++ src/osmo-bts-sysmo/l1_if.c | 13 ------------- 2 files changed, 4 insertions(+), 13 deletions(-)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index e006412..5318085 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -762,6 +762,10 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx, return -EINVAL; }
+ /* report first valid received frame to handover process */ + if (lchan->ho.active == HANDOVER_WAIT_FRAME) + handover_frame(lchan); + if (L1SAP_IS_LINK_SACCH(link_id)) { radio_link_timeout(lchan, 0); le = &lchan->lapdm_ch.lapdm_acch; diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 2ba7c3c..9707a22 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -819,22 +819,12 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i struct msgb *l1p_msg) { struct gsm_bts_trx *trx = fl1->priv; - struct gsm_lchan *lchan; uint8_t chan_nr, link_id; struct osmo_phsap_prim *l1sap; uint32_t fn; uint8_t *data, len; int rc = 0;
- lchan = l1if_hLayer_to_lchan(fl1->priv, data_ind->hLayer2); - if (!lchan) { - LOGP(DL1C, LOGL_ERROR, - "unable to resolve lchan by hLayer2 for 0x%x\n", - data_ind->hLayer2); - msgb_free(l1p_msg); - return -ENODEV; - } - 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) { @@ -861,9 +851,6 @@ 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);
- if (lchan->ho.active == HANDOVER_WAIT_FRAME) - handover_frame(lchan); - /* check for TCH */ if (data_ind->sapi == GsmL1_Sapi_TchF || data_ind->sapi == GsmL1_Sapi_TchH) {
Harald,
On Wed, Aug 27, 2014 at 5:54 PM, Harald Welte laforge@gnumonks.org wrote:
the valuable L1SAP abstraction has been sitting out of master for too long time. It is a pity that this has taken so long. I've finally been able to put some time into osmo-bts again and reviewed the following patch series. It consists of mostly Andreas' work, interspersed with smaller patches/fixups that I introduced after the respective original patch from Andreas.
Great news!
I didn't yet rebase the osmo-bts-trx interface on top of the L1SAP, as I don't have a hardware setup for it, and I will leave it to the owners of such hardware to publish/push the respective code after L1SAP is merged.
We'll look at that as soon as we have some free cycles.
We would be happy to send you a free UmTRX to make sure you're able to work with the osmo-bts-trx part of the code.
Hi Alexander,
On Wed, Aug 27, 2014 at 09:11:06PM -0400, Alexander Chemeris wrote:
We would be happy to send you a free UmTRX to make sure you're able to work with the osmo-bts-trx part of the code.
Thanks for the offer, but I really do not have the time for this, sorry.
I think it is fair that somebody who is a user / primary user of that platform/code is taking care of this. I don't mind if that person directly pushes code to master, as long as a) the code is not of general nature (which should go to src/common and be submitted for review) b) the code only makes modifications / additions to the src/osmo-bts-trx subdirectory
Regards, Harald
On Thu, Aug 28, 2014 at 5:10 AM, Harald Welte laforge@gnumonks.org wrote:
On Wed, Aug 27, 2014 at 09:11:06PM -0400, Alexander Chemeris wrote: I think it is fair that somebody who is a user / primary user of that platform/code is taking care of this. I don't mind if that person directly pushes code to master, as long as a) the code is not of general nature (which should go to src/common and be submitted for review) b) the code only makes modifications / additions to the src/osmo-bts-trx subdirectory
Seems like a good approach to me.
I have started a sysmobts between all of the major steps in this patch series and did a short manual tests involving registration (LU) of two MS, mobile-to-mobile call and vty-to-mobile SMS. So far I couldn't see any problems. What has not been tested yet is the PCU interface as well as encryption support. I plan to do this later this week.
You can use the zecke/hacks/stress-testing branch in OpenBSC. It adds a VTY command to allocate all channels. It has found breakage in the past.
Hi Holger,
On Thu, Aug 28, 2014 at 01:52:25PM +0200, Holger Hans Peter Freyther wrote:
I have started a sysmobts between all of the major steps in this patch series and did a short manual tests involving registration (LU) of two MS, mobile-to-mobile call and vty-to-mobile SMS. So far I couldn't see any problems. What has not been tested yet is the PCU interface as well as encryption support. I plan to do this later this week.
You can use the zecke/hacks/stress-testing branch in OpenBSC. It adds a VTY command to allocate all channels. It has found breakage in the past.
done that, the code survives multiple subsequent executions of 'allocate-all-channels' and shows no obvious memory leaks (neither in resident set size nor in the talloc report).