Looks good to me from the code structure perspective.
On Thu, Sep 19, 2013 at 2:11 PM, Andreas Eversberg jolly@eversberg.eu wrote:
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 bfa6bd8..f6545cc 100644 --- a/include/osmo-bts/bts_model.h +++ b/include/osmo-bts/bts_model.h @@ -43,4 +43,6 @@ int bts_model_vty_init(struct gsm_bts *bts); void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts); void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx);
+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 b2f6f8e..1c6ff9e 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -5,4 +5,4 @@ LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOTRAU_LIBS) noinst_LIBRARIES = libbts.a 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
load_indication.c pcu_sock.c l1sap.cdiff --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);elsememcpy(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 e16bb49..93b4de7 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -47,6 +47,7 @@ #include <osmo-bts/paging.h> #include <osmo-bts/measurement.h> #include <osmo-bts/pcu_if.h> +#include <osmo-bts/l1sap.h>
#include <sysmocom/femtobts/superfemto.h> #include <sysmocom/femtobts/gsml1prim.h> @@ -366,8 +367,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; @@ -379,9 +507,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);@@ -460,14 +610,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);elsememcpy(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);@@ -555,6 +697,7 @@ tx: /* transmit */ osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], resp_msg);
msgb_free(l1p_msg); return 0;empty_frame: @@ -885,8 +1028,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 c46bb4a..64b30c0 100644 --- a/tests/stubs.c +++ b/tests/stubs.c @@ -39,6 +39,8 @@ int bts_model_rsl_mode_modify(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) -- 1.8.1.5