Merge branch '201509-l1sap'

This commit is contained in:
Harald Welte 2015-09-22 16:39:55 +02:00
commit 329085a8ff
24 changed files with 2065 additions and 963 deletions

View File

@ -1,3 +1,4 @@
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 cbch.h l1sap.h
handover.h msg_utils.h tx_power.h control_if.h cbch.h l1sap.h \
power_control.h

View File

@ -41,6 +41,7 @@ void bts_update_status(enum bts_global_status which, int on);
int trx_ms_pwr_ctrl_is_osmo(struct gsm_bts_trx *trx);
struct gsm_time *get_time(struct gsm_bts *bts);
#endif /* _BTS_H */

View File

@ -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);
@ -27,18 +25,9 @@ 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);
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);
@ -49,4 +38,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_adjst_ms_pwr(struct gsm_lchan *lchan);
int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap);
#endif

View File

@ -81,8 +81,11 @@ struct gsm_bts_role_bts {
struct {
uint8_t tc4_ctr;
} si;
struct gsm_time gsm_time;
uint8_t radio_link_timeout;
int ul_power_target; /* Uplink Rx power target */
/* used by the sysmoBTS to adjust band */
uint8_t auto_band;
@ -96,8 +99,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)

View File

@ -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);
@ -68,4 +68,6 @@ extern uint8_t gsmtap_sapi_acch;
#define msgb_l1sap_prim(msg) ((struct osmo_phsap_prim *)(msg)->l1h)
int bts_check_for_first_ciphrd(struct gsm_lchan *lchan,
uint8_t *data, int len);
#endif /* L1SAP_H */

View File

@ -0,0 +1,7 @@
#pragma once
#include <stdint.h>
#include <osmo-bts/gsm_data.h>
int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan,
const uint8_t ms_power, const int rxLevel);

View File

@ -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);

View File

@ -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;

View File

@ -8,4 +8,4 @@ libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.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 \
cbch.c
l1sap.c cbch.c power_control.c

View File

@ -99,6 +99,7 @@ int bts_init(struct gsm_bts *bts)
/* configurable via VTY */
btsb->paging_state = paging_init(btsb, 200, 0);
btsb->ul_power_target = -75; /* dBm default */
/* configurable via OML */
btsb->load.ccch.load_ind_period = 112;
@ -611,3 +612,10 @@ int trx_ms_pwr_ctrl_is_osmo(struct gsm_bts_trx *trx)
{
return trx->ms_power_control == 1;
}
struct gsm_time *get_time(struct gsm_bts *bts)
{
struct gsm_bts_role_bts *btsb = bts->role;
return &btsb->gsm_time;
}

View File

@ -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));

1082
src/common/l1sap.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -39,7 +39,7 @@
#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);
@ -57,10 +57,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 +508,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:
@ -546,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;
}
@ -653,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));
}
}
}

View File

@ -0,0 +1,99 @@
/* MS Power Control Loop L1 */
/* (C) 2014 by Holger Hans Peter Freyther
*
* 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 <osmo-bts/logging.h>
#include <osmo-bts/bts.h>
#include <osmo-bts/gsm_data.h>
#include <osmo-bts/measurement.h>
#include <osmo-bts/bts_model.h>
#include <osmo-bts/l1sap.h>
/*
* Check if manual power control is needed
* Check if fixed power was selected
* Check if the MS is already using our level if not
* the value is bogus..
* TODO: Add a timeout.. e.g. if the ms is not capable of reaching
* the value we have set.
*/
int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan,
const uint8_t ms_power, const int rxLevel)
{
int rx;
int cur_dBm, new_dBm, new_pwr;
struct gsm_bts *bts = lchan->ts->trx->bts;
struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
const enum gsm_band band = bts->band;
if (!trx_ms_pwr_ctrl_is_osmo(lchan->ts->trx))
return 0;
if (lchan->ms_power_ctrl.fixed)
return 0;
/* The phone hasn't reached the power level yet */
if (lchan->ms_power_ctrl.current != ms_power)
return 0;
/*
* What is the difference between what we want and received?
* Ignore a margin that is within the range of measurement
* and MS output issues.
*/
rx = btsb->ul_power_target - rxLevel;
if (rx >= 0 && rx < 1)
return 0;
if (rx < 0 && rx > -1)
return 0;
/* We don't really care about the truncation of int + float */
cur_dBm = ms_pwr_dbm(band, ms_power);
new_dBm = cur_dBm + rx;
/* Clamp negative values and do it depending on the band */
if (new_dBm < 0)
new_dBm = 0;
switch (band) {
case GSM_BAND_1800:
/* If MS_TX_PWR_MAX_CCH is set the values 29,
* 30, 31 are not used. Avoid specifying a dBm
* that would lead to these power levels. The
* phone might not be able to reach them. */
if (new_dBm > 30)
new_dBm = 30;
break;
default:
break;
}
new_pwr = ms_pwr_ctl_lvl(band, new_dBm);
if (lchan->ms_power_ctrl.current != new_pwr) {
lchan->ms_power_ctrl.current = new_pwr;
bts_model_adjst_ms_pwr(lchan);
return 1;
}
return 0;
}

View File

@ -42,11 +42,11 @@
#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>
#include <osmo-bts/cbch.h>
#include <osmo-bts/l1sap.h>
//#define FAKE_CIPH_MODE_COMPL
@ -543,8 +543,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];
@ -856,7 +857,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);
@ -864,10 +865,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);
@ -879,9 +878,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);
return rc;
lapdm_channel_exit(&lchan->lapdm_ch);
return 0;
}
#ifdef FAKE_CIPH_MODE_COMPL
@ -1064,10 +1065,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));
@ -1108,12 +1109,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.15 MS POWER CONTROL */
@ -1479,7 +1480,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()
@ -1824,13 +1825,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);

View File

@ -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)
@ -176,6 +207,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
VTY_NEWLINE);
vty_out(vty, " paging lifetime %u%s", paging_get_lifetime(btsb->paging_state),
VTY_NEWLINE);
vty_out(vty, " uplink-power-target %d%s", btsb->ul_power_target, VTY_NEWLINE);
if (btsb->agch_queue_thresh_level != GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DEFAULT
|| btsb->agch_queue_low_level != GSM_BTS_AGCH_QUEUE_LOW_LEVEL_DEFAULT
|| btsb->agch_queue_high_level != GSM_BTS_AGCH_QUEUE_HIGH_LEVEL_DEFAULT)
@ -183,6 +215,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) {
@ -399,6 +442,19 @@ DEFUN(cfg_bts_agch_queue_mgmt_default,
return CMD_SUCCESS;
}
DEFUN(cfg_bts_ul_power_target, cfg_bts_ul_power_target_cmd,
"uplink-power-target <-110-0>",
"Set the nominal target Rx Level for uplink power control loop\n"
"Target uplink Rx level in dBm\n")
{
struct gsm_bts *bts = vty->index;
struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
btsb->ul_power_target = atoi(argv[0]);
return CMD_SUCCESS;
}
#define DB_DBM_STR \
"Unit is dB (decibels)\n" \
"Unit is mdB (milli-decibels, or rather 1/10000 bel)\n"
@ -614,6 +670,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>",
@ -640,8 +726,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);
@ -660,6 +796,10 @@ int bts_vty_init(const struct log_info *cat)
install_element(BTS_NODE, &cfg_bts_paging_lifetime_cmd);
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_bts_ul_power_target_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);

File diff suppressed because it is too large Load Diff

View File

@ -46,16 +46,12 @@ struct femtol1_hdl {
uint32_t dsp_trace_f;
uint8_t clk_use_eeprom;
int clk_cal;
int ul_power_target;
uint8_t clk_src;
float min_qual_rach;
float min_qual_norm;
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;
@ -110,7 +106,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);
@ -119,6 +117,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);
@ -129,9 +134,6 @@ 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);
inline int l1if_ms_pwr_ctrl(struct gsm_lchan *lchan, const int uplink_target,
const uint8_t ms_power, const float rxLevel);
#endif /* _FEMTO_L1_H */

View File

@ -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"
@ -62,6 +65,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)
{
@ -165,6 +169,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"
);
}
@ -196,10 +201,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;
@ -244,6 +250,9 @@ static void handle_options(int argc, char **argv)
case 'r':
rt_prio = atoi(optarg);
break;
case 'i':
gsmtap_ip = optarg;
break;
default:
break;
}
@ -308,8 +317,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);
@ -325,7 +335,15 @@ int main(int argc, char **argv)
}
}
bts = gsm_bts_alloc(tall_bts_ctx);
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);

View File

@ -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,
@ -308,6 +324,7 @@ static const uint8_t trx_rqd_attr[] = { NM_ATT_RF_MAXPOWR_R };
static int trx_init(struct gsm_bts_trx *trx)
{
struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
struct gsm_bts_role_bts *btsb = bts_role_bts(trx->bts);
struct msgb *msg;
GsmL1_MphInitReq_t *mi_req;
GsmL1_DeviceParam_t *dev_par;
@ -336,7 +353,7 @@ static int trx_init(struct gsm_bts_trx *trx)
dev_par->u16BcchArfcn = trx->bts->c0->arfcn;
dev_par->u8NbTsc = trx->bts->bsic & 7;
dev_par->fRxPowerLevel = trx_ms_pwr_ctrl_is_osmo(trx)
? 0.0 : fl1h->ul_power_target;
? 0.0 : btsb->ul_power_target;
dev_par->fTxPowerLevel = 0.0;
LOGP(DL1C, LOGL_NOTICE, "Init TRX (ARFCN %u, TSC %u, RxPower % 2f dBm, "
@ -974,7 +991,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;
}
@ -984,14 +1001,16 @@ 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);
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;
}
@ -1009,7 +1028,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;
@ -1043,8 +1061,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;
}
@ -1143,9 +1159,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);
@ -1319,7 +1342,7 @@ int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan)
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;
@ -1429,7 +1452,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;
}
@ -1441,7 +1464,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;
}
@ -1516,7 +1539,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;
@ -1556,13 +1579,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,
@ -1686,30 +1702,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;
}
@ -1718,7 +1715,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;
@ -1742,7 +1739,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) {
@ -1755,7 +1752,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)

View File

@ -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")
@ -203,15 +175,15 @@ DEFUN(cfg_trx_cal_path, cfg_trx_cal_path_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_trx_ul_power_target, cfg_trx_ul_power_target_cmd,
DEFUN_DEPRECATED(cfg_trx_ul_power_target, cfg_trx_ul_power_target_cmd,
"uplink-power-target <-110-0>",
"Set the nominal target Rx Level for uplink power control loop\n"
"Obsolete alias for bts uplink-power-target\n"
"Target uplink Rx level in dBm\n")
{
struct gsm_bts_trx *trx = vty->index;
struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
struct gsm_bts_role_bts *btsb = bts_role_bts(trx->bts);
fl1h->ul_power_target = atoi(argv[0]);
btsb->ul_power_target = atoi(argv[0]);
return CMD_SUCCESS;
}
@ -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);
@ -540,8 +484,6 @@ void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
vty_out(vty, " clock-source %s%s",
get_value_string(femtobts_clksrc_names, fl1h->clk_src),
VTY_NEWLINE);
vty_out(vty, " uplink-power-target %d%s", fl1h->ul_power_target,
VTY_NEWLINE);
vty_out(vty, " min-qual-rach %.0f%s", fl1h->min_qual_rach * 10.0f,
VTY_NEWLINE);
vty_out(vty, " min-qual-norm %.0f%s", fl1h->min_qual_norm * 10.0f,
@ -549,14 +491,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 +512,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,9 +534,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);
install_element(TRX_NODE, &cfg_trx_nominal_power_cmd);

View File

@ -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>
@ -425,7 +426,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
@ -437,34 +438,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;
DEBUGP(DRTP, "%s RTP IN: %s\n", gsm_lchan_name(lchan),
osmo_hexdump(rtp_pl, rtp_pl_len));
msg = l1p_msgb_alloc();
if (!msg) {
LOGP(DRTP, LOGL_ERROR, "%s: Failed to allocate Rx payload.\n",
gsm_lchan_name(lchan));
return;
}
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:
@ -499,34 +484,13 @@ 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));
}
static int is_recv_only(uint8_t speech_mode)
@ -535,7 +499,7 @@ static int is_recv_only(uint8_t speech_mode)
}
/*! \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;
@ -543,53 +507,18 @@ 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 (is_recv_only(lchan->abis_ip.speech_mode))
return -EAGAIN;
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)
@ -633,11 +562,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;

View File

@ -40,6 +40,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)

View File

@ -18,6 +18,8 @@
*/
#include <osmo-bts/bts.h>
#include <osmo-bts/l1sap.h>
#include <osmo-bts/power_control.h>
#include "femtobts.h"
#include "l1_if.h"
@ -169,25 +171,30 @@ 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);
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(&fl1h, &unit, &lchan);
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 */
}
static void test_sysmobts_loop(void)
{
struct gsm_bts bts;
struct gsm_bts_role_bts btsb;
struct gsm_bts_trx trx;
struct gsm_bts_trx_ts ts;
struct gsm_lchan *lchan;
int ret;
memset(&bts, 0, sizeof(bts));
memset(&btsb, 0, sizeof(btsb));
memset(&trx, 0, sizeof(trx));
memset(&ts, 0, sizeof(ts));
@ -195,8 +202,10 @@ static void test_sysmobts_loop(void)
lchan->ts = &ts;
ts.trx = &trx;
trx.bts = &bts;
bts.role = &btsb;
bts.band = GSM_BAND_1800;
trx.ms_power_control = 1;
btsb.ul_power_target = -75;
printf("Testing sysmobts power control\n");
@ -204,7 +213,7 @@ static void test_sysmobts_loop(void)
lchan->state = LCHAN_S_NONE;
lchan->ms_power_ctrl.current = ms_pwr_ctl_lvl(GSM_BAND_1800, 0);
OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
ret = l1if_ms_pwr_ctrl(lchan, -75, lchan->ms_power_ctrl.current, -60);
ret = lchan_ms_pwr_ctrl(lchan, lchan->ms_power_ctrl.current, -60);
OSMO_ASSERT(ret == 0);
OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
@ -213,24 +222,24 @@ static void test_sysmobts_loop(void)
* Now 15 dB too little and we should power it up. Could be a
* power level of 7 or 8 for 15 dBm
*/
ret = l1if_ms_pwr_ctrl(lchan, -75, lchan->ms_power_ctrl.current, -90);
ret = lchan_ms_pwr_ctrl(lchan, lchan->ms_power_ctrl.current, -90);
OSMO_ASSERT(ret == 1);
OSMO_ASSERT(lchan->ms_power_ctrl.current == 7);
/* It should be clamped to level 0 and 30 dBm */
ret = l1if_ms_pwr_ctrl(lchan, -75, lchan->ms_power_ctrl.current, -100);
ret = lchan_ms_pwr_ctrl(lchan, lchan->ms_power_ctrl.current, -100);
OSMO_ASSERT(ret == 1);
OSMO_ASSERT(lchan->ms_power_ctrl.current == 0);
/* Fix it and jump down */
lchan->ms_power_ctrl.fixed = 1;
ret = l1if_ms_pwr_ctrl(lchan, -75, lchan->ms_power_ctrl.current, -60);
ret = lchan_ms_pwr_ctrl(lchan, lchan->ms_power_ctrl.current, -60);
OSMO_ASSERT(ret == 0);
OSMO_ASSERT(lchan->ms_power_ctrl.current == 0);
/* And leave it again */
lchan->ms_power_ctrl.fixed = 0;
ret = l1if_ms_pwr_ctrl(lchan, -75, lchan->ms_power_ctrl.current, -40);
ret = lchan_ms_pwr_ctrl(lchan, lchan->ms_power_ctrl.current, -40);
OSMO_ASSERT(ret == 1);
OSMO_ASSERT(lchan->ms_power_ctrl.current == 15);
}