osmo-bts/src/common/l1sap.c

220 lines
5.9 KiB
C
Raw Normal View History

/* 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>
#include <osmo-bts/handover.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;
}
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 (!L1SAP_IS_CHAN_RACH(rach_ind->chan_nr))
return l1sap_handover_rach(trx, l1sap, rach_ind);
/* check for packet access */
2014-08-27 15:12:44 +00:00
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)
{
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;
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);
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);
}