From patchwork Wed Aug 27 21:54:22 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Harald Welte X-Patchwork-Id: 383611 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from ganesha.gnumonks.org (ganesha.gnumonks.org [IPv6:2001:780:45:1d:225:90ff:fe52:c662]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 238E314009C for ; Thu, 28 Aug 2014 08:52:24 +1000 (EST) Received: from localhost ([127.0.0.1] helo=ganesha.gnumonks.org) by ganesha.gnumonks.org with esmtp (Exim 4.72) (envelope-from ) id 1XMlRV-0006tm-GO; Thu, 28 Aug 2014 00:11:49 +0200 Received: from uucp by ganesha.gnumonks.org with local-bsmtp (Exim 4.72) (envelope-from ) id 1XMlC5-0004NB-Tx; Wed, 27 Aug 2014 23:55:54 +0200 Received: from laforge by localhost.localdomain with local (Exim 4.84) (envelope-from ) id 1XMlBH-0003UW-6n; Wed, 27 Aug 2014 23:55:03 +0200 From: Harald Welte To: openbsc@lists.osmocom.org Subject: [PATCH 03/33] Add BCCH message to PH-/MPH-/TCH-SAP interface Date: Wed, 27 Aug 2014 23:54:22 +0200 Message-Id: <1409176492-13269-4-git-send-email-laforge@gnumonks.org> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1409176492-13269-1-git-send-email-laforge@gnumonks.org> References: <1409176492-13269-1-git-send-email-laforge@gnumonks.org> Cc: Andreas Eversberg X-BeenThere: openbsc@lists.osmocom.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Development of the OpenBSC GSM base station controller List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: openbsc-bounces@lists.osmocom.org Errors-To: openbsc-bounces@lists.osmocom.org From: Andreas Eversberg 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 + * (C) 2013 by Andreas Eversberg + * + * 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 . + * + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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 #include #include +#include #include #include @@ -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)