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)
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 | 3 +- include/osmo-bts/l1sap.h | 71 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 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 456d416..d8c0002 100644 --- a/include/osmo-bts/Makefile.am +++ b/include/osmo-bts/Makefile.am @@ -1,2 +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 + oml.h paging.h rsl.h signal.h vty.h amr.h pcu_if.h \ + pcuif_proto.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 */
It would be great to add pointers to the exact parts of the GSM standard which describe all this, but otherwise the patch looks good to me from the code structure perspective.
On Thu, Sep 19, 2013 at 2:11 PM, Andreas Eversberg jolly@eversberg.eu wrote:
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 | 3 +- include/osmo-bts/l1sap.h | 71 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 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 456d416..d8c0002 100644 --- a/include/osmo-bts/Makefile.am +++ b/include/osmo-bts/Makefile.am @@ -1,2 +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
oml.h paging.h rsl.h signal.h vty.h amr.h pcu_if.h \pcuif_proto.h l1sap.hdiff --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 */
1.8.1.5
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.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 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); - 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); @@ -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)
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
This part moves RACH message primitives from osmo-bts-sysmo to common part. --- src/common/l1sap.c | 42 +++++++++++++++++++++++++++++++ src/osmo-bts-sysmo/l1_if.c | 61 +++++++++++++++++++++------------------------- 2 files changed, 70 insertions(+), 33 deletions(-)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index f4f3246..996a589 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -119,6 +119,45 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx, return 1; }
+/* 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; + + DEBUGP(DL1P, "Rx PH-RA.ind"); + + lc = &trx->ts[0].lchan[4].lapdm_ch; + if (!lc) { + LOGP(DL1P, LOGL_ERROR, "unable to resolve LAPD channel\n"); + return -ENODEV; + } + + /* check for under/overflow / sign */ + if (rach_ind->acc_delay > btsb->max_ta) { + LOGP(DL1P, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n", + rach_ind->acc_delay, btsb->max_ta); + return 0; + } + + /* 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 +168,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 93b4de7..874ec15 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -954,63 +954,58 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i }
-static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind) +static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind, + struct msgb *l1p_msg) { struct gsm_bts_trx *trx = fl1->priv; struct gsm_bts *bts = trx->bts; struct gsm_bts_role_bts *btsb = bts->role; - struct osmo_phsap_prim pp; - struct lapdm_channel *lc; - uint8_t acc_delay; + struct osmo_phsap_prim *l1sap; + uint32_t fn; + uint8_t ra, acc_delay; + int rc;
/* increment number of busy RACH slots, if required */ if (trx == bts->c0 && ra_ind->measParam.fRssi >= btsb->load.rach.busy_thresh) btsb->load.rach.busy++;
- if (ra_ind->measParam.fLinkQuality < fl1->min_qual_rach) + if (ra_ind->measParam.fLinkQuality < fl1->min_qual_rach) { + msgb_free(l1p_msg); return 0; + }
/* increment number of RACH slots with valid RACH burst */ if (trx == bts->c0) btsb->load.rach.access++;
- DEBUGP(DL1C, "Rx PH-RA.ind"); dump_meas_res(LOGL_DEBUG, &ra_ind->measParam);
- lc = get_lapdm_chan_by_hl2(fl1->priv, ra_ind->hLayer2); - if (!lc) { - LOGP(DL1C, LOGL_ERROR, "unable to resolve LAPD channel by hLayer2\n"); - return -ENODEV; + if (ra_ind->msgUnitParam.u8Size != 1) { + LOGP(DL1C, LOGL_ERROR, "PH-RACH-INDICATION has %d bits\n", + ra_ind->sapi); + msgb_free(l1p_msg); + return 0; }
+ fn = ra_ind->u32Fn; + ra = ra_ind->msgUnitParam.u8Buffer[0]; /* check for under/overflow / sign */ if (ra_ind->measParam.i16BurstTiming < 0) acc_delay = 0; else acc_delay = ra_ind->measParam.i16BurstTiming >> 2; - if (acc_delay > btsb->max_ta) { - LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n", - acc_delay, btsb->max_ta); - return 0; - } - - /* check for packet access */ - if (trx == bts->c0 - && (ra_ind->msgUnitParam.u8Buffer[0] & 0xf0) == 0x70) { - LOGP(DL1C, LOGL_INFO, "RACH for packet access\n"); - return pcu_tx_rach_ind(bts, ra_ind->measParam.i16BurstTiming, - ra_ind->msgUnitParam.u8Buffer[0], ra_ind->u32Fn); - } - - osmo_prim_init(&pp.oph, SAP_GSM_PH, PRIM_PH_RACH, - PRIM_OP_INDICATION, NULL); - - pp.u.rach_ind.ra = ra_ind->msgUnitParam.u8Buffer[0]; - pp.u.rach_ind.fn = ra_ind->u32Fn; - pp.u.rach_ind.acc_delay = acc_delay; - - return lapdm_phsap_up(&pp.oph, &lc->lapdm_dcch); + rc = msgb_trim(l1p_msg, sizeof(*l1sap)); + if (rc < 0) + MSGB_ABORT(l1p_msg, "No room for primitive data\n"); + l1sap = msgb_l1sap_prim(l1p_msg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RACH, PRIM_OP_INDICATION, + l1p_msg); + l1sap->u.rach_ind.ra = ra; + l1sap->u.rach_ind.acc_delay = acc_delay; + l1sap->u.rach_ind.fn = fn; + + return l1sap_up(trx, l1sap); }
/* handle any random indication from the L1 */ @@ -1034,7 +1029,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;
Holger Hans Peter Freyther wrote:
On Thu, Sep 19, 2013 at 02:11:49PM +0200, Andreas Eversberg wrote:
- lc = &trx->ts[0].lchan[4].lapdm_ch;
- if (!lc) {
how can this ever be null?
lc was a return vale from a function before, but you are right. this check is now obsolete, so i removed it.
thanx!
On Thu, Sep 19, 2013 at 2:11 PM, Andreas Eversberg jolly@eversberg.eu wrote:
lc = &trx->ts[0].lchan[4].lapdm_ch;
I would recommend to move "trx->ts[0].lchan[4].lapdm_ch" to a macros and document why do we refer to TS0, lchan 4 here (some references to the would be helpful).
Otherwise this patch looks good to me from the code structure perspective.
This part moves PCH and AGCH message primitives from osmo-bts-sysmo to common part. --- src/common/l1sap.c | 17 +++++++++++++++++ src/osmo-bts-sysmo/l1_if.c | 28 ++++++++++++---------------- 2 files changed, 29 insertions(+), 16 deletions(-)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 996a589..16e1af8 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -108,6 +108,23 @@ 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 (L1SAP_FN2CCCHBLOCK(fn) >= 1) { + /* PCH */ + struct gsm_bts_role_bts *btsb = trx->bts->role; + paging_gen_msg(btsb->paging_state, p, &g_time); + } else { + /* AGCH */ + /* special queue of messages from IMM ASS CMD */ + struct msgb *amsg = bts_agch_dequeue(trx->bts); + if (!amsg) + memcpy(p, fill_frame, GSM_MACBLOCK_LEN); + else { + memcpy(p, amsg->data, amsg->len); + msgb_free(amsg); + } + } }
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 874ec15..511b466 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -389,6 +389,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, @@ -486,6 +494,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; } @@ -499,7 +511,6 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, { struct gsm_bts_trx *trx = fl1->priv; struct gsm_bts *bts = trx->bts; - struct gsm_bts_role_bts *btsb = bts->role; struct msgb *resp_msg; GsmL1_PhDataReq_t *data_req; GsmL1_MsgUnitParam_t *msu_param; @@ -647,21 +658,6 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, msgb_free(pp.oph.msg); } break; - case GsmL1_Sapi_Agch: - /* special queue of messages from IMM ASS CMD */ - { - struct msgb *msg = bts_agch_dequeue(bts); - if (!msg) - memcpy(msu_param->u8Buffer, fill_frame, GSM_MACBLOCK_LEN); - else { - memcpy(msu_param->u8Buffer, msg->data, msg->len); - msgb_free(msg); - } - } - break; - case GsmL1_Sapi_Pch: - rc = paging_gen_msg(btsb->paging_state, msu_param->u8Buffer, &g_time); - break; case GsmL1_Sapi_TchF: case GsmL1_Sapi_TchH: /* only hit in case we have a RTP underflow, as real TCH
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 part moves PCH and AGCH message primitives from osmo-bts-sysmo to common part.
src/common/l1sap.c | 17 +++++++++++++++++ src/osmo-bts-sysmo/l1_if.c | 28 ++++++++++++---------------- 2 files changed, 29 insertions(+), 16 deletions(-)
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 996a589..16e1af8 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -108,6 +108,23 @@ 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 (L1SAP_FN2CCCHBLOCK(fn) >= 1) {/* PCH */struct gsm_bts_role_bts *btsb = trx->bts->role;paging_gen_msg(btsb->paging_state, p, &g_time);} else {/* AGCH *//* special queue of messages from IMM ASS CMD */struct msgb *amsg = bts_agch_dequeue(trx->bts);if (!amsg)memcpy(p, fill_frame, GSM_MACBLOCK_LEN);else {memcpy(p, amsg->data, amsg->len);msgb_free(amsg);}} } 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 874ec15..511b466 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -389,6 +389,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;elsesapi = GsmL1_Sapi_Agch; } else { LOGP(DL1C, LOGL_NOTICE, "unknown prim %d op %d " "chan_nr %d link_id %d\n", l1sap->oph.primitive,@@ -486,6 +494,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; }@@ -499,7 +511,6 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, { struct gsm_bts_trx *trx = fl1->priv; struct gsm_bts *bts = trx->bts;
struct gsm_bts_role_bts *btsb = bts->role; struct msgb *resp_msg; GsmL1_PhDataReq_t *data_req; GsmL1_MsgUnitParam_t *msu_param;@@ -647,21 +658,6 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, msgb_free(pp.oph.msg); } break;
case GsmL1_Sapi_Agch:/* special queue of messages from IMM ASS CMD */{struct msgb *msg = bts_agch_dequeue(bts);if (!msg)memcpy(msu_param->u8Buffer, fill_frame, GSM_MACBLOCK_LEN);else {memcpy(msu_param->u8Buffer, msg->data, msg->len);msgb_free(msg);}}break;case GsmL1_Sapi_Pch:rc = paging_gen_msg(btsb->paging_state, msu_param->u8Buffer, &g_time);break; case GsmL1_Sapi_TchF: case GsmL1_Sapi_TchH: /* only hit in case we have a RTP underflow, as real TCH-- 1.8.1.5
Good catch. Using msg->head is a fragile business.
On Thu, Sep 19, 2013 at 2:11 PM, Andreas Eversberg jolly@eversberg.eu wrote:
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)
1.8.1.5