Split PCU global PCU object from BTS object

Currently the BTS object (and gprs_rlcmac_bts struct) are used to hold
both PCU global fields and BTS specific fields, all mangled together.
The BTS is even accessed in lots of places by means of a singleton.

This patch introduces a new struct gprs_pcu object aimed at holding all
global state, and several fields are already moved from BTS to it. The
new object can be accessed as global variable "the_pcu", reusing and
including an already exisitng "the_pcu" global variable only used for
bssgp related purposes so far.

This is only a first step towards having a complete split global pcu and
BTS, some fields are still kept in BTS and will be moved over follow-up
smaller patches in the future (since this patch is already quite big).
So far, the code still only supports one BTS, which can be accessed
using the_pcu->bts. In the future that field will be replaced with a
list, and the BTS singletons will be removed.

The cur_fn output changes in TbfTest are actually a side effect fix,
since the singleton main_bts() now points internally to the_pcu->bts,
hence the same we allocate and assign in the test. Beforehand, "the_bts"
was allocated in the stack while main_bts() still returned an unrelated
singleton BTS object instance.

Related: OS#4935
Change-Id: I88e3c6471b80245ce3798223f1a61190f14aa840
changes/62/22162/6
Pau Espin 2 years ago committed by pespin
parent 695ce77167
commit ac3fd12026
  1. 2
      src/Makefile.am
  2. 55
      src/bts.cpp
  3. 53
      src/bts.h
  4. 196
      src/gprs_bssgp_pcu.cpp
  5. 24
      src/gprs_bssgp_pcu.h
  6. 61
      src/gprs_pcu.c
  7. 97
      src/gprs_pcu.h
  8. 2
      src/gprs_rlcmac_ts_alloc.cpp
  9. 8
      src/osmobts_sock.cpp
  10. 40
      src/pcu_l1_if.cpp
  11. 3
      src/pcu_l1_if.h
  12. 27
      src/pcu_main.cpp
  13. 80
      src/pcu_vty.c
  14. 4
      src/tbf.cpp
  15. 32
      tests/alloc/AllocTest.cpp
  16. 12
      tests/alloc/MslotTest.cpp
  17. 6
      tests/app_info/AppInfoTest.cpp
  18. 10
      tests/edge/EdgeTest.cpp
  19. 20
      tests/emu/pcu_emu.cpp
  20. 6
      tests/fn/FnTest.cpp
  21. 20
      tests/ms/MsTest.cpp
  22. 450
      tests/tbf/TbfTest.cpp
  23. 564
      tests/tbf/TbfTest.err
  24. 22
      tests/types/TypesTest.cpp

@ -49,6 +49,7 @@ libgprs_la_SOURCES = \
gprs_rlcmac_ts_alloc.cpp \
gprs_ms.c \
gprs_ms_storage.cpp \
gprs_pcu.c \
gsm_timer.cpp \
pcu_l1_if.cpp \
pcu_vty.c \
@ -84,6 +85,7 @@ noinst_HEADERS = \
gprs_rlcmac.h \
gprs_ms.h \
gprs_ms_storage.h \
gprs_pcu.h \
pcu_l1_if.h \
gsm_timer.h \
pcu_vty.h \

@ -68,8 +68,6 @@ extern "C" {
}
}
static BTS s_bts;
static struct osmo_tdef T_defs_bts[] = {
{ .T=3142, .default_val=20, .unit=OSMO_TDEF_S, .desc="timer (s)", .val=0 },
{ .T=3169, .default_val=5, .unit=OSMO_TDEF_S, .desc="Reuse of USF and TFI(s) after the MS uplink TBF assignment is invalid (s)", .val=0 },
@ -218,10 +216,6 @@ static void bts_init(struct gprs_rlcmac_bts *bts, BTS* bts_obj)
bts->cs_adj_enabled = 1;
bts->cs_adj_upper_limit = 33; /* Decrease CS if the error rate is above */
bts->cs_adj_lower_limit = 10; /* Increase CS if the error rate is below */
bts->vty.max_cs_ul = MAX_GPRS_CS;
bts->vty.max_cs_dl = MAX_GPRS_CS;
bts->vty.max_mcs_ul = MAX_EDGE_MCS;
bts->vty.max_mcs_dl = MAX_EDGE_MCS;
/* CS-1 to CS-4 */
bts->cs_lqual_ranges[0].low = -256;
bts->cs_lqual_ranges[0].high = 6;
@ -294,7 +288,7 @@ static void bts_init(struct gprs_rlcmac_bts *bts, BTS* bts_obj)
BTS* BTS::main_bts()
{
return &s_bts;
return the_pcu->bts;
}
struct gprs_rlcmac_bts *BTS::bts_data()
@ -317,8 +311,9 @@ struct rate_ctr_group *bts_main_data_stats()
return BTS::main_bts()->rate_counters();
}
BTS::BTS()
: m_cur_fn(0)
BTS::BTS(struct gprs_pcu *pcu)
: pcu(pcu)
, m_cur_fn(0)
, m_cur_blk_fn(-1)
, m_max_cs_dl(MAX_GPRS_CS)
, m_max_cs_ul(MAX_GPRS_CS)
@ -540,7 +535,7 @@ void BTS::send_gsmtap_meas(enum pcu_gsmtap_category categ, bool uplink, uint8_t
uint16_t arfcn;
/* check if category is activated at all */
if (!(m_bts.gsmtap_categ_mask & (1 << categ)))
if (!(pcu->gsmtap_categ_mask & (1 << categ)))
return;
arfcn = m_bts.trx[trx_no].arfcn;
@ -550,7 +545,7 @@ void BTS::send_gsmtap_meas(enum pcu_gsmtap_category categ, bool uplink, uint8_t
/* GSMTAP needs the SNR here, but we only have C/I (meas->link_qual).
Those are not the same, but there is no known way to convert them,
let's pass C/I instead of nothing */
gsmtap_send(m_bts.gsmtap, arfcn, ts_no, channel, 0, fn,
gsmtap_send(pcu->gsmtap, arfcn, ts_no, channel, 0, fn,
meas->rssi, meas->link_qual, data, len);
}
@ -1147,6 +1142,24 @@ GprsMs *BTS::ms_alloc(uint8_t ms_class, uint8_t egprs_ms_class)
return ms;
}
static int bts_talloc_destructor(struct BTS* bts)
{
bts->~BTS();
return 0;
}
struct BTS* bts_alloc(struct gprs_pcu *pcu)
{
struct BTS* bts;
bts = talloc(pcu, struct BTS);
if (!bts)
return bts;
talloc_set_destructor(bts, bts_talloc_destructor);
new (bts) BTS(pcu);
return bts;
}
/* update TA based on TA provided by PH-DATA-IND */
void update_tbf_ta(struct gprs_rlcmac_ul_tbf *tbf, int8_t ta_delta)
{
@ -1224,22 +1237,22 @@ void bts_trx_unreserve_slots(struct gprs_rlcmac_trx *trx, enum gprs_rlcmac_tbf_d
trx->pdch[i].unreserve(dir);
}
void bts_set_max_cs(struct gprs_rlcmac_bts *bts, uint8_t cs_dl, uint8_t cs_ul)
void bts_recalc_max_cs(struct gprs_rlcmac_bts *bts)
{
int i;
uint8_t cs_dl, cs_ul;
struct gprs_pcu *pcu = bts->bts->pcu;
bts->vty.max_cs_dl = cs_dl;
cs_dl = 0;
for (i = bts->vty.max_cs_dl - 1; i >= 0; i--) {
for (i = pcu->vty.max_cs_dl - 1; i >= 0; i--) {
if (bts->cs_mask & (1 << i)) {
cs_dl = i + 1;
break;
}
}
bts->vty.max_cs_ul = cs_ul;
cs_ul = 0;
for (i = bts->vty.max_cs_ul - 1; i >= 0; i--) {
for (i = pcu->vty.max_cs_ul - 1; i >= 0; i--) {
if (bts->cs_mask & (1 << i)) {
cs_ul = i + 1;
break;
@ -1251,22 +1264,22 @@ void bts_set_max_cs(struct gprs_rlcmac_bts *bts, uint8_t cs_dl, uint8_t cs_ul)
bts->bts->set_max_cs_ul(cs_ul);
}
void bts_set_max_mcs(struct gprs_rlcmac_bts *bts, uint8_t mcs_dl, uint8_t mcs_ul)
void bts_recalc_max_mcs(struct gprs_rlcmac_bts *bts)
{
int i;
uint8_t mcs_dl, mcs_ul;
struct gprs_pcu *pcu = bts->bts->pcu;
bts->vty.max_mcs_dl = mcs_dl;
mcs_dl = 0;
for (i = bts->vty.max_mcs_dl - 1; i >= 0; i--) {
for (i = pcu->vty.max_mcs_dl - 1; i >= 0; i--) {
if (bts->mcs_mask & (1 << i)) {
mcs_dl = i + 1;
break;
}
}
bts->vty.max_mcs_ul = mcs_ul;
mcs_ul = 0;
for (i = bts->vty.max_mcs_ul - 1; i >= 0; i--) {
for (i = pcu->vty.max_mcs_ul - 1; i >= 0; i--) {
if (bts->mcs_mask & (1 << i)) {
mcs_ul = i + 1;
break;

@ -35,6 +35,7 @@ extern "C" {
#include <osmocom/gsm/gsm48.h>
#include "mslot_class.h"
#include "gsm_rlcmac.h"
#include "gprs_pcu.h"
#ifdef __cplusplus
}
#endif
@ -52,32 +53,6 @@ extern "C" {
#include <stdint.h>
#include <stdbool.h>
#define LLC_CODEL_DISABLE 0
#define LLC_CODEL_USE_DEFAULT (-1)
#define MAX_EDGE_MCS 9
#define MAX_GPRS_CS 4
/* see bts->gsmtap_categ_mask */
enum pcu_gsmtap_category {
PCU_GSMTAP_C_DL_UNKNOWN = 0, /* unknown or undecodable downlink blocks */
PCU_GSMTAP_C_DL_DUMMY = 1, /* downlink dummy blocks */
PCU_GSMTAP_C_DL_CTRL = 2, /* downlink control blocks */
PCU_GSMTAP_C_DL_DATA_GPRS = 3, /* downlink GPRS data blocks */
PCU_GSMTAP_C_DL_DATA_EGPRS = 4, /* downlink EGPRS data blocks */
PCU_GSMTAP_C_DL_PTCCH = 5, /* downlink PTCCH blocks */
PCU_GSMTAP_C_DL_AGCH = 6, /* downlink AGCH blocks */
PCU_GSMTAP_C_DL_PCH = 7, /* downlink PCH blocks */
PCU_GSMTAP_C_UL_UNKNOWN = 15, /* unknown or undecodable uplink blocks */
PCU_GSMTAP_C_UL_DUMMY = 16, /* uplink dummy blocks */
PCU_GSMTAP_C_UL_CTRL = 17, /* uplink control blocks */
PCU_GSMTAP_C_UL_DATA_GPRS = 18, /* uplink GPRS data blocks */
PCU_GSMTAP_C_UL_DATA_EGPRS = 19, /* uplink EGPRS data blocks */
PCU_GSMTAP_C_UL_RACH = 20, /* uplink RACH bursts */
PCU_GSMTAP_C_UL_PTCCH = 21, /* uplink PTCCH bursts */
};
struct BTS;
struct GprsMs;
@ -120,12 +95,6 @@ struct gprs_rlcmac_bts {
uint16_t mcs_mask; /* Allowed MCS mask from BTS */
uint8_t initial_cs_dl, initial_cs_ul;
uint8_t initial_mcs_dl, initial_mcs_ul;
struct { /* Config Values set by VTY */
bool force_initial_cs; /* false=use from BTS true=use from VTY */
bool force_initial_mcs; /* false=use from BTS true=use from VTY */
uint8_t max_cs_dl, max_cs_ul;
uint8_t max_mcs_dl, max_mcs_ul;
} vty;
uint16_t force_llc_lifetime; /* overrides lifetime from SGSN */
uint32_t llc_discard_csec;
uint32_t llc_idle_ack_csec;
@ -136,11 +105,7 @@ struct gprs_rlcmac_bts {
uint8_t n3101;
uint8_t n3103;
uint8_t n3105;
struct gsmtap_inst *gsmtap;
uint32_t gsmtap_categ_mask;
struct gprs_rlcmac_trx trx[8];
int (*alloc_algorithm)(struct gprs_rlcmac_bts *bts, struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf,
bool single, int8_t use_tbf);
uint8_t force_two_phase;
uint8_t alpha, gamma;
@ -171,9 +136,6 @@ struct gprs_rlcmac_bts {
*/
struct BTS *bts;
/* Path to be used for the pcu-bts socket */
char *pcu_sock_path;
/* Are we talking Gb with IP-SNS (true) or classic Gb? */
enum gprs_ns2_dialect ns_dialect;
@ -182,7 +144,6 @@ struct gprs_rlcmac_bts {
struct msgb *app_info;
uint32_t app_info_pending; /* Count of MS with active TBF, to which we did not send app_info yet */
struct gprs_ns2_inst *nsi;
/* main nsei */
struct gprs_ns2_nse *nse;
};
@ -304,7 +265,7 @@ struct chan_req_params {
*/
struct BTS {
public:
BTS();
BTS(struct gprs_pcu *pcu);
~BTS();
void cleanup();
@ -373,7 +334,11 @@ public:
LListHead<gprs_rlcmac_tbf>& dl_tbfs();
struct gprs_rlcmac_bts m_bts;
/* back pointer to PCU object */
struct gprs_pcu *pcu;
private:
int m_cur_fn;
int m_cur_blk_fn;
uint8_t m_max_cs_dl, m_max_cs_ul;
@ -453,6 +418,8 @@ inline void BTS::stat_item_add(unsigned int stat_id, int inc) {
osmo_stat_item_set(m_statg->items[stat_id], val + inc);
}
struct gprs_pcu;
struct BTS* bts_alloc(struct gprs_pcu *pcu);
#endif
#ifdef __cplusplus
@ -463,8 +430,8 @@ extern "C" {
struct gprs_rlcmac_bts *bts_main_data();
struct rate_ctr_group *bts_main_data_stats();
struct osmo_stat_item_group *bts_main_data_stat_items();
void bts_set_max_cs(struct gprs_rlcmac_bts *bts, uint8_t cs_dl, uint8_t cs_ul);
void bts_set_max_mcs(struct gprs_rlcmac_bts *bts, uint8_t mcs_dl, uint8_t mcs_ul);
void bts_recalc_max_cs(struct gprs_rlcmac_bts *bts);
void bts_recalc_max_mcs(struct gprs_rlcmac_bts *bts);
struct GprsMs *bts_ms_by_imsi(struct BTS *bts, const char *imsi);
uint8_t bts_max_cs_dl(const struct BTS *bts);
uint8_t bts_max_cs_ul(const struct BTS *bts);

@ -46,8 +46,6 @@ extern "C" {
#define FC_MAX_BUCKET_LEAK_RATE (6553500 / 8) /* Byte/s */
#define FC_MAX_BUCKET_SIZE 6553500 /* Octets */
static struct gprs_bssgp_pcu the_pcu = { 0, };
extern void *tall_pcu_ctx;
extern uint16_t spoof_mcc, spoof_mnc;
extern bool spoof_mnc_3_digits;
@ -167,7 +165,7 @@ static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
LOGP(DBSSGP, LOGL_INFO, "LLC [SGSN -> PCU] = TLLI: 0x%08x IMSI: %s len: %d\n", tlli, mi_imsi.imsi, len);
return gprs_rlcmac_dl_tbf::handle(the_pcu.bts, tlli, tlli_old, mi_imsi.imsi,
return gprs_rlcmac_dl_tbf::handle(the_pcu->bssgp.bts, tlli, tlli_old, mi_imsi.imsi,
ms_class, egprs_ms_class, delay_csec, data, len);
}
@ -270,8 +268,8 @@ static int gprs_bssgp_pcu_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, struct
break;
case BSSGP_PDUT_DL_UNITDATA:
LOGP(DBSSGP, LOGL_DEBUG, "Rx BSSGP BVCI=%d (PTP) DL_UNITDATA\n", bvci);
if (the_pcu.on_dl_unit_data)
the_pcu.on_dl_unit_data(&the_pcu, msg, tp);
if (the_pcu->bssgp.on_dl_unit_data)
the_pcu->bssgp.on_dl_unit_data(&the_pcu->bssgp, msg, tp);
gprs_bssgp_pcu_rx_dl_ud(msg, tp);
break;
case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK:
@ -340,10 +338,10 @@ static int gprs_bssgp_pcu_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struc
break;
case BSSGP_PDUT_BVC_RESET_ACK:
LOGP(DBSSGP, LOGL_NOTICE, "Rx BSSGP BVCI=%d (SIGN) BVC_RESET_ACK\n", bvci);
if (!the_pcu.bvc_sig_reset)
the_pcu.bvc_sig_reset = 1;
if (!the_pcu->bssgp.bvc_sig_reset)
the_pcu->bssgp.bvc_sig_reset = 1;
else
the_pcu.bvc_reset = 1;
the_pcu->bssgp.bvc_reset = 1;
bvc_timeout(NULL);
break;
case BSSGP_PDUT_PAGING_CS:
@ -354,9 +352,9 @@ static int gprs_bssgp_pcu_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struc
break;
case BSSGP_PDUT_BVC_UNBLOCK_ACK:
LOGP(DBSSGP, LOGL_NOTICE, "Rx BSSGP BVCI=%d (SIGN) BVC_UNBLOCK_ACK\n", bvci);
the_pcu.bvc_unblocked = 1;
if (the_pcu.on_unblock_ack)
the_pcu.on_unblock_ack(&the_pcu);
the_pcu->bssgp.bvc_unblocked = 1;
if (the_pcu->bssgp.on_unblock_ack)
the_pcu->bssgp.on_unblock_ack(&the_pcu->bssgp);
bvc_timeout(NULL);
break;
case BSSGP_PDUT_SUSPEND_NACK:
@ -516,15 +514,15 @@ static void handle_nm_status(struct osmo_bssgp_prim *bp)
switch (cause) {
case BSSGP_CAUSE_BVCI_BLOCKED:
if (the_pcu.bvc_unblocked) {
the_pcu.bvc_unblocked = 0;
if (the_pcu->bssgp.bvc_unblocked) {
the_pcu->bssgp.bvc_unblocked = 0;
bvc_timeout(NULL);
}
break;
case BSSGP_CAUSE_UNKNOWN_BVCI:
if (the_pcu.bvc_reset) {
the_pcu.bvc_reset = 0;
if (the_pcu->bssgp.bvc_reset) {
the_pcu->bssgp.bvc_reset = 0;
bvc_timeout(NULL);
}
break;
@ -557,21 +555,21 @@ void gprs_ns_prim_status_cb(struct osmo_gprs_ns2_prim *nsp)
break;
case NS_AFF_CAUSE_RECOVERY:
LOGP(DPCU, LOGL_NOTICE, "NS-NSE %d became available\n", nsp->nsei);
if (!the_pcu.nsvc_unblocked) {
the_pcu.bvc_sig_reset = 0;
the_pcu.bvc_reset = 0;
the_pcu.nsvc_unblocked = 1;
if (!the_pcu->bssgp.nsvc_unblocked) {
the_pcu->bssgp.bvc_sig_reset = 0;
the_pcu->bssgp.bvc_reset = 0;
the_pcu->bssgp.nsvc_unblocked = 1;
bvc_timeout(NULL);
}
break;
case NS_AFF_CAUSE_FAILURE:
LOGP(DPCU, LOGL_NOTICE, "NS-NSE %d became unavailable\n", nsp->nsei);
if (the_pcu.nsvc_unblocked) {
the_pcu.nsvc_unblocked = 0;
osmo_timer_del(&the_pcu.bvc_timer);
the_pcu.bvc_sig_reset = 0;
the_pcu.bvc_reset = 0;
the_pcu.bvc_unblocked = 0;
if (the_pcu->bssgp.nsvc_unblocked) {
the_pcu->bssgp.nsvc_unblocked = 0;
osmo_timer_del(&the_pcu->bssgp.bvc_timer);
the_pcu->bssgp.bvc_sig_reset = 0;
the_pcu->bssgp.bvc_reset = 0;
the_pcu->bssgp.bvc_unblocked = 0;
}
break;
case NS_AFF_CAUSE_SNS_FAILURE:
@ -700,17 +698,17 @@ static uint32_t compute_bucket_size(struct gprs_rlcmac_bts *bts,
static uint32_t get_and_reset_avg_queue_delay(void)
{
struct timespec *delay_sum = &the_pcu.queue_delay_sum;
struct timespec *delay_sum = &the_pcu->bssgp.queue_delay_sum;
uint32_t delay_sum_ms = delay_sum->tv_sec * 1000 +
delay_sum->tv_nsec / 1000000000;
uint32_t avg_delay_ms = 0;
if (the_pcu.queue_delay_count > 0)
avg_delay_ms = delay_sum_ms / the_pcu.queue_delay_count;
if (the_pcu->bssgp.queue_delay_count > 0)
avg_delay_ms = delay_sum_ms / the_pcu->bssgp.queue_delay_count;
/* Reset accumulator */
delay_sum->tv_sec = delay_sum->tv_nsec = 0;
the_pcu.queue_delay_count = 0;
the_pcu->bssgp.queue_delay_count = 0;
return avg_delay_ms;
}
@ -719,24 +717,24 @@ static int get_and_reset_measured_leak_rate(int *usage_by_1000, unsigned num_pdc
{
int rate; /* byte per second */
if (the_pcu.queue_frames_sent == 0)
if (the_pcu->bssgp.queue_frames_sent == 0)
return -1;
if (the_pcu.queue_frames_recv == 0)
if (the_pcu->bssgp.queue_frames_recv == 0)
return -1;
*usage_by_1000 = the_pcu.queue_frames_recv * 1000 /
the_pcu.queue_frames_sent;
*usage_by_1000 = the_pcu->bssgp.queue_frames_recv * 1000 /
the_pcu->bssgp.queue_frames_sent;
/* 20ms/num_pdch is the average RLC block duration, so the rate is
* calculated as:
* rate = bytes_recv / (block_dur * block_count) */
rate = the_pcu.queue_bytes_recv * 1000 * num_pdch /
(20 * the_pcu.queue_frames_recv);
rate = the_pcu->bssgp.queue_bytes_recv * 1000 * num_pdch /
(20 * the_pcu->bssgp.queue_frames_recv);
the_pcu.queue_frames_sent = 0;
the_pcu.queue_bytes_recv = 0;
the_pcu.queue_frames_recv = 0;
the_pcu->bssgp.queue_frames_sent = 0;
the_pcu->bssgp.queue_bytes_recv = 0;
the_pcu->bssgp.queue_frames_recv = 0;
return rate;
}
@ -805,7 +803,7 @@ static int gprs_bssgp_tx_fc_bvc(void)
int num_pdch = -1;
enum CodingScheme max_cs_dl;
if (!the_pcu.bctx) {
if (!the_pcu->bssgp.bctx) {
LOGP(DBSSGP, LOGL_ERROR, "No bctx\n");
return -EIO;
}
@ -896,7 +894,7 @@ static int gprs_bssgp_tx_fc_bvc(void)
avg_delay_ms = get_and_reset_avg_queue_delay();
/* Update tag */
the_pcu.fc_tag += 1;
the_pcu->bssgp.fc_tag += 1;
LOGP(DBSSGP, LOGL_DEBUG,
"Sending FLOW CONTROL BVC, Bmax = %d, R = %d, Bmax_MS = %d, "
@ -904,7 +902,7 @@ static int gprs_bssgp_tx_fc_bvc(void)
bucket_size, leak_rate, ms_bucket_size, ms_leak_rate,
avg_delay_ms);
return bssgp_tx_fc_bvc(the_pcu.bctx, the_pcu.fc_tag,
return bssgp_tx_fc_bvc(the_pcu->bssgp.bctx, the_pcu->bssgp.fc_tag,
bucket_size, leak_rate,
ms_bucket_size, ms_leak_rate,
NULL, &avg_delay_ms);
@ -913,36 +911,36 @@ static int gprs_bssgp_tx_fc_bvc(void)
static void bvc_timeout(void *_priv)
{
unsigned long secs;
if (!the_pcu.bvc_sig_reset) {
if (!the_pcu->bssgp.bvc_sig_reset) {
LOGP(DBSSGP, LOGL_INFO, "Sending reset on BVCI 0\n");
bssgp_tx_bvc_reset(the_pcu.bctx, 0, BSSGP_CAUSE_OML_INTERV);
secs = osmo_tdef_get(the_pcu.bts->T_defs_pcu, 2, OSMO_TDEF_S, -1);
osmo_timer_schedule(&the_pcu.bvc_timer, secs, 0);
bssgp_tx_bvc_reset(the_pcu->bssgp.bctx, 0, BSSGP_CAUSE_OML_INTERV);
secs = osmo_tdef_get(the_pcu->bssgp.bts->T_defs_pcu, 2, OSMO_TDEF_S, -1);
osmo_timer_schedule(&the_pcu->bssgp.bvc_timer, secs, 0);
return;
}
if (!the_pcu.bvc_reset) {
if (!the_pcu->bssgp.bvc_reset) {
LOGP(DBSSGP, LOGL_INFO, "Sending reset on BVCI %d\n",
the_pcu.bctx->bvci);
bssgp_tx_bvc_reset(the_pcu.bctx, the_pcu.bctx->bvci, BSSGP_CAUSE_OML_INTERV);
secs = osmo_tdef_get(the_pcu.bts->T_defs_pcu, 2, OSMO_TDEF_S, -1);
osmo_timer_schedule(&the_pcu.bvc_timer, secs, 0);
the_pcu->bssgp.bctx->bvci);
bssgp_tx_bvc_reset(the_pcu->bssgp.bctx, the_pcu->bssgp.bctx->bvci, BSSGP_CAUSE_OML_INTERV);
secs = osmo_tdef_get(the_pcu->bssgp.bts->T_defs_pcu, 2, OSMO_TDEF_S, -1);
osmo_timer_schedule(&the_pcu->bssgp.bvc_timer, secs, 0);
return;
}
if (!the_pcu.bvc_unblocked) {
if (!the_pcu->bssgp.bvc_unblocked) {
LOGP(DBSSGP, LOGL_INFO, "Sending unblock on BVCI %d\n",
the_pcu.bctx->bvci);
bssgp_tx_bvc_unblock(the_pcu.bctx);
secs = osmo_tdef_get(the_pcu.bts->T_defs_pcu, 1, OSMO_TDEF_S, -1);
osmo_timer_schedule(&the_pcu.bvc_timer, secs, 0);
the_pcu->bssgp.bctx->bvci);
bssgp_tx_bvc_unblock(the_pcu->bssgp.bctx);
secs = osmo_tdef_get(the_pcu->bssgp.bts->T_defs_pcu, 1, OSMO_TDEF_S, -1);
osmo_timer_schedule(&the_pcu->bssgp.bvc_timer, secs, 0);
return;
}
LOGP(DBSSGP, LOGL_DEBUG, "Sending flow control info on BVCI %d\n",
the_pcu.bctx->bvci);
the_pcu->bssgp.bctx->bvci);
gprs_bssgp_tx_fc_bvc();
osmo_timer_schedule(&the_pcu.bvc_timer, the_pcu.bts->fc_interval, 0);
osmo_timer_schedule(&the_pcu->bssgp.bvc_timer, the_pcu->bssgp.bts->fc_interval, 0);
}
static int ns_create_nsvc(struct gprs_rlcmac_bts *bts,
@ -966,9 +964,9 @@ static int ns_create_nsvc(struct gprs_rlcmac_bts *bts,
if (!(valid & (1 << i)))
continue;
if (!gprs_ns2_ip_bind_by_sockaddr(bts->nsi, &local[i])) {
if (!gprs_ns2_ip_bind_by_sockaddr(the_pcu->nsi, &local[i])) {
snprintf(name, sizeof(name), "pcu%d", i);
rc = gprs_ns2_ip_bind(bts->nsi, name, &local[i], 0, &bind[i]);
rc = gprs_ns2_ip_bind(the_pcu->nsi, name, &local[i], 0, &bind[i]);
if (rc < 0) {
LOGP(DBSSGP, LOGL_ERROR, "Failed to bind to %s\n", osmo_sockaddr_to_str(&local[i]));
continue;
@ -983,14 +981,14 @@ static int ns_create_nsvc(struct gprs_rlcmac_bts *bts,
return -1;
}
bts->nse = gprs_ns2_nse_by_nsei(bts->nsi, nsei);
bts->nse = gprs_ns2_nse_by_nsei(the_pcu->nsi, nsei);
if (!bts->nse)
bts->nse = gprs_ns2_create_nse(bts->nsi, nsei,
bts->nse = gprs_ns2_create_nse(the_pcu->nsi, nsei,
GPRS_NS2_LL_UDP, bts->ns_dialect);
if (!bts->nse) {
LOGP(DBSSGP, LOGL_ERROR, "Failed to create NSE\n");
gprs_ns2_free_binds(bts->nsi);
gprs_ns2_free_binds(the_pcu->nsi);
return 1;
}
@ -1060,13 +1058,13 @@ int gprs_ns_config(struct gprs_rlcmac_bts *bts, uint16_t nsei,
int rc = 0;
if (!bts->nse) {
/* there shouldn't any previous state. */
gprs_ns2_free_nses(bts->nsi);
gprs_ns2_free_binds(bts->nsi);
gprs_ns2_free_nses(the_pcu->nsi);
gprs_ns2_free_binds(the_pcu->nsi);
rc = ns_create_nsvc(bts, nsei, local, remote, nsvci, valid);
} else if (nsei != gprs_ns2_nse_nsei(bts->nse)) {
/* the NSEI has changed */
gprs_ns2_free_nses(bts->nsi);
gprs_ns2_free_binds(bts->nsi);
gprs_ns2_free_nses(the_pcu->nsi);
gprs_ns2_free_binds(the_pcu->nsi);
rc = ns_create_nsvc(bts, nsei, local, remote, nsvci, valid);
} else if (bts->ns_dialect == NS2_DIALECT_SNS) {
/* SNS: check if the initial nsvc is the same, if not recreate it */
@ -1080,8 +1078,8 @@ int gprs_ns_config(struct gprs_rlcmac_bts *bts, uint16_t nsei,
return 0;
}
gprs_ns2_free_nses(bts->nsi);
gprs_ns2_free_binds(bts->nsi);
gprs_ns2_free_nses(the_pcu->nsi);
gprs_ns2_free_binds(the_pcu->nsi);
rc = ns_create_nsvc(bts, nsei, local, remote, nsvci, valid);
} else {
/* check if all NSVC are still the same. */
@ -1119,75 +1117,75 @@ struct gprs_bssgp_pcu *gprs_bssgp_init(
{
/* if already created... return the current address */
if (the_pcu.bctx)
return &the_pcu;
if (the_pcu->bssgp.bctx)
return &the_pcu->bssgp;
the_pcu.bts = bts;
the_pcu.bctx = btsctx_alloc(bvci, nsei);
if (!the_pcu.bctx) {
the_pcu->bssgp.bts = bts;
the_pcu->bssgp.bctx = btsctx_alloc(bvci, nsei);
if (!the_pcu->bssgp.bctx) {
LOGP(DBSSGP, LOGL_ERROR, "Failed to create BSSGP context\n");
the_pcu.bts->nse = NULL;
the_pcu->bssgp.bts->nse = NULL;
return NULL;
}
the_pcu.bctx->ra_id.mcc = spoof_mcc ? : mcc;
the_pcu->bssgp.bctx->ra_id.mcc = spoof_mcc ? : mcc;
if (spoof_mnc) {
the_pcu.bctx->ra_id.mnc = spoof_mnc;
the_pcu.bctx->ra_id.mnc_3_digits = spoof_mnc_3_digits;
the_pcu->bssgp.bctx->ra_id.mnc = spoof_mnc;
the_pcu->bssgp.bctx->ra_id.mnc_3_digits = spoof_mnc_3_digits;
} else {
the_pcu.bctx->ra_id.mnc = mnc;
the_pcu.bctx->ra_id.mnc_3_digits = mnc_3_digits;
the_pcu->bssgp.bctx->ra_id.mnc = mnc;
the_pcu->bssgp.bctx->ra_id.mnc_3_digits = mnc_3_digits;
}
the_pcu.bctx->ra_id.lac = lac;
the_pcu.bctx->ra_id.rac = rac;
the_pcu.bctx->cell_id = cell_id;
the_pcu->bssgp.bctx->ra_id.lac = lac;
the_pcu->bssgp.bctx->ra_id.rac = rac;
the_pcu->bssgp.bctx->cell_id = cell_id;
osmo_timer_setup(&the_pcu.bvc_timer, bvc_timeout, bts);
osmo_timer_setup(&the_pcu->bssgp.bvc_timer, bvc_timeout, bts);
return &the_pcu;
return &the_pcu->bssgp;
}
void gprs_bssgp_destroy(struct gprs_rlcmac_bts *bts)
{
osmo_timer_del(&the_pcu.bvc_timer);
osmo_timer_del(&the_pcu->bssgp.bvc_timer);
/* FIXME: blocking... */
the_pcu.nsvc_unblocked = 0;
the_pcu.bvc_sig_reset = 0;
the_pcu.bvc_reset = 0;
the_pcu.bvc_unblocked = 0;
the_pcu->bssgp.nsvc_unblocked = 0;
the_pcu->bssgp.bvc_sig_reset = 0;
the_pcu->bssgp.bvc_reset = 0;
the_pcu->bssgp.bvc_unblocked = 0;
bssgp_bvc_ctx_free(the_pcu.bctx);
the_pcu.bctx = NULL;
bssgp_bvc_ctx_free(the_pcu->bssgp.bctx);
the_pcu->bssgp.bctx = NULL;
gprs_ns2_free(bts->nsi);
bts->nsi = NULL;
gprs_ns2_free(the_pcu->nsi);
the_pcu->nsi = NULL;
bts->nse = NULL;
}
struct bssgp_bvc_ctx *gprs_bssgp_pcu_current_bctx(void)
{
return the_pcu.bctx;
return the_pcu->bssgp.bctx;
}
void gprs_bssgp_update_frames_sent()
{
the_pcu.queue_frames_sent += 1;
the_pcu->bssgp.queue_frames_sent += 1;
}
void gprs_bssgp_update_bytes_received(unsigned bytes_recv, unsigned frames_recv)
{
the_pcu.queue_bytes_recv += bytes_recv;
the_pcu.queue_frames_recv += frames_recv;
the_pcu->bssgp.queue_bytes_recv += bytes_recv;
the_pcu->bssgp.queue_frames_recv += frames_recv;
}
void gprs_bssgp_update_queue_delay(const struct timespec *tv_recv,
const struct timespec *tv_now)
{
struct timespec *delay_sum = &the_pcu.queue_delay_sum;
struct timespec *delay_sum = &the_pcu->bssgp.queue_delay_sum;
struct timespec tv_delay;
timespecsub(tv_now, tv_recv, &tv_delay);
timespecadd(delay_sum, &tv_delay, delay_sum);
the_pcu.queue_delay_count += 1;
the_pcu->bssgp.queue_delay_count += 1;
}

@ -22,7 +22,9 @@
#define GPRS_BSSGP_PCU_H
#ifdef __cplusplus
extern "C" {
#endif
#include <osmocom/core/talloc.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/logging.h>
@ -34,7 +36,7 @@ extern "C" {
#include <osmocom/gprs/gprs_msgb.h>
struct bssgp_bvc_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei);
}
#include <gprs_debug.h>
#include <time.h>
@ -75,6 +77,14 @@ struct gprs_bssgp_pcu {
struct tlv_parsed *tp);
};
int gprs_gp_send_cb(void *ctx, struct msgb *msg);
struct bssgp_bvc_ctx *gprs_bssgp_pcu_current_bctx(void);
int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx);
void gprs_bssgp_update_queue_delay(const struct timespec *tv_recv,
const struct timespec *tv_now);
void gprs_bssgp_update_frames_sent();
void gprs_bssgp_update_bytes_received(unsigned bytes_recv, unsigned frames_recv);
struct gprs_bssgp_pcu *gprs_bssgp_init(
struct gprs_rlcmac_bts *bts,
uint16_t nsei, uint16_t bvci,
@ -86,16 +96,10 @@ int gprs_ns_config(struct gprs_rlcmac_bts *bts, uint16_t nsei,
const struct osmo_sockaddr *remote,
uint16_t *nsvci, uint16_t valid);
int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx);
int gprs_gp_send_cb(void *ctx, struct msgb *msg);
void gprs_bssgp_destroy(struct gprs_rlcmac_bts *bts);
struct bssgp_bvc_ctx *gprs_bssgp_pcu_current_bctx(void);
void gprs_bssgp_update_queue_delay(const struct timespec *tv_recv,
const struct timespec *tv_now);
void gprs_bssgp_update_frames_sent();
void gprs_bssgp_update_bytes_received(unsigned bytes_recv, unsigned frames_recv);
#ifdef __cplusplus
}
#endif
#endif // GPRS_BSSGP_PCU_H

@ -0,0 +1,61 @@
/*
* Copyright (C) 2013 by Holger Hans Peter Freyther
* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* 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 <osmocom/core/utils.h>
#include "gprs_pcu.h"
#include "bts.h"
struct gprs_pcu *the_pcu;
struct gprs_pcu *gprs_pcu_alloc(void *ctx)
{
struct gprs_pcu *pcu;
pcu = (struct gprs_pcu *)talloc_zero(ctx, struct gprs_pcu);
OSMO_ASSERT(pcu);
pcu->vty.max_cs_ul = MAX_GPRS_CS;
pcu->vty.max_cs_dl = MAX_GPRS_CS;
pcu->vty.max_mcs_ul = MAX_EDGE_MCS;
pcu->vty.max_mcs_dl = MAX_EDGE_MCS;
return pcu;
}
void gprs_pcu_set_max_cs(struct gprs_pcu *pcu, uint8_t cs_dl, uint8_t cs_ul)
{
the_pcu->vty.max_cs_dl = cs_dl;
the_pcu->vty.max_cs_ul = cs_ul;
/*TODO: once we support multiple bts, foreach(bts) apply */
struct gprs_rlcmac_bts *bts = bts_data(pcu->bts);
bts_recalc_max_cs(bts);
}
void gprs_pcu_set_max_mcs(struct gprs_pcu *pcu, uint8_t mcs_dl, uint8_t mcs_ul)
{
the_pcu->vty.max_mcs_dl = mcs_dl;
the_pcu->vty.max_mcs_ul = mcs_ul;
/* TODO: once we support multiple bts, foreach(bts) apply */
struct gprs_rlcmac_bts *bts = bts_data(pcu->bts);
bts_recalc_max_mcs(bts);
}

@ -0,0 +1,97 @@
/*
* Copyright (C) 2013 by Holger Hans Peter Freyther
* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* 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/>.
*
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <osmocom/core/gsmtap_util.h>
#include "gprs_bssgp_pcu.h"
#define LLC_CODEL_DISABLE 0
#define LLC_CODEL_USE_DEFAULT (-1)
#define MAX_EDGE_MCS 9
#define MAX_GPRS_CS 4
/* see bts->gsmtap_categ_mask */
enum pcu_gsmtap_category {
PCU_GSMTAP_C_DL_UNKNOWN = 0, /* unknown or undecodable downlink blocks */
PCU_GSMTAP_C_DL_DUMMY = 1, /* downlink dummy blocks */
PCU_GSMTAP_C_DL_CTRL = 2, /* downlink control blocks */
PCU_GSMTAP_C_DL_DATA_GPRS = 3, /* downlink GPRS data blocks */
PCU_GSMTAP_C_DL_DATA_EGPRS = 4, /* downlink EGPRS data blocks */
PCU_GSMTAP_C_DL_PTCCH = 5, /* downlink PTCCH blocks */
PCU_GSMTAP_C_DL_AGCH = 6, /* downlink AGCH blocks */
PCU_GSMTAP_C_DL_PCH = 7, /* downlink PCH blocks */
PCU_GSMTAP_C_UL_UNKNOWN = 15, /* unknown or undecodable uplink blocks */
PCU_GSMTAP_C_UL_DUMMY = 16, /* uplink dummy blocks */
PCU_GSMTAP_C_UL_CTRL = 17, /* uplink control blocks */
PCU_GSMTAP_C_UL_DATA_GPRS = 18, /* uplink GPRS data blocks */
PCU_GSMTAP_C_UL_DATA_EGPRS = 19, /* uplink EGPRS data blocks */
PCU_GSMTAP_C_UL_RACH = 20, /* uplink RACH bursts */
PCU_GSMTAP_C_UL_PTCCH = 21, /* uplink PTCCH bursts */
};
struct BTS;
struct gprs_rlcmac_bts;
struct GprsMs;
struct gprs_rlcmac_tbf;
typedef int (*alloc_algorithm_func_t)(struct gprs_rlcmac_bts *bts,
struct GprsMs *ms,
struct gprs_rlcmac_tbf *tbf,
bool single, int8_t use_tbf);
struct gprs_pcu {
/* Path to be used for the pcu-bts socket */
char *pcu_sock_path;
struct { /* Config Values set by VTY */
bool force_initial_cs; /* false=use from BTS true=use from VTY */
bool force_initial_mcs; /* false=use from BTS true=use from VTY */
uint8_t max_cs_dl, max_cs_ul;
uint8_t max_mcs_dl, max_mcs_ul;
} vty;
struct gsmtap_inst *gsmtap;
uint32_t gsmtap_categ_mask;
struct BTS *bts;
struct gprs_ns2_inst *nsi;
alloc_algorithm_func_t alloc_algorithm;
struct gprs_bssgp_pcu bssgp;
};
extern struct gprs_pcu *the_pcu;
struct gprs_pcu *gprs_pcu_alloc(void *ctx);
void gprs_pcu_set_max_cs(struct gprs_pcu *pcu, uint8_t cs_dl, uint8_t cs_ul);
void gprs_pcu_set_max_mcs(struct gprs_pcu *pcu, uint8_t mcs_dl, uint8_t mcs_ul);

@ -1018,7 +1018,7 @@ int gprs_alloc_max_dl_slots_per_ms(const struct gprs_rlcmac_bts *bts, uint8_t ms
if (rx == MS_NA)
rx = 4;
if (bts->alloc_algorithm == alloc_algorithm_a)
if (the_pcu->alloc_algorithm == alloc_algorithm_a)
return 1;
if (bts->multislot_disabled)

@ -206,18 +206,16 @@ static int pcu_sock_cb(struct osmo_fd *bfd, unsigned int flags)
int pcu_l1if_open(void)
{
int rc;
struct gprs_rlcmac_bts *bts = bts_main_data();
LOGP(DL1IF, LOGL_INFO, "Opening OsmoPCU L1 interface to OsmoBTS\n");
memset(&pcu_sock_state, 0x00, sizeof(pcu_sock_state));
INIT_LLIST_HEAD(&pcu_sock_state.upqueue);
rc = osmo_sock_unix_init_ofd(&pcu_sock_state.conn_bfd, SOCK_SEQPACKET, 0,
bts->pcu_sock_path, OSMO_SOCK_F_CONNECT);
the_pcu->pcu_sock_path, OSMO_SOCK_F_CONNECT);
if (rc < 0) {
LOGP(DL1IF, LOGL_ERROR, "Failed to connect to the BTS (%s). "
"Retrying...\n", bts->pcu_sock_path);
"Retrying...\n", the_pcu->pcu_sock_path);
osmo_timer_setup(&pcu_sock_state.timer, pcu_sock_timeout, NULL);
osmo_timer_schedule(&pcu_sock_state.timer, 5, 0);
return 0;
@ -227,7 +225,7 @@ int pcu_l1if_open(void)
pcu_sock_state.conn_bfd.data = NULL;
LOGP(DL1IF, LOGL_NOTICE, "osmo-bts PCU socket %s has been connected\n",
bts->pcu_sock_path);
the_pcu->pcu_sock_path);
pcu_tx_txt_ind(PCU_VERSION, "%s", PACKAGE_VERSION);

@ -214,14 +214,13 @@ void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
msgb_free(msg);
}
void pcu_l1if_tx_ptcch(uint8_t trx, uint8_t ts, uint16_t arfcn,
void pcu_l1if_tx_ptcch(struct gprs_rlcmac_bts *bts,
uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr,
uint8_t *data, size_t data_len)
{
struct gprs_rlcmac_bts *bts = bts_main_data();
if (bts->gsmtap_categ_mask & (1 << PCU_GSMTAP_C_DL_PTCCH))
gsmtap_send(bts->gsmtap, arfcn, ts, GSMTAP_CHANNEL_PTCCH, 0, fn, 0, 0, data, data_len);
if (the_pcu->gsmtap_categ_mask & (1 << PCU_GSMTAP_C_DL_PTCCH))
gsmtap_send(the_pcu->gsmtap, arfcn, ts, GSMTAP_CHANNEL_PTCCH, 0, fn, 0, 0, data, data_len);
#ifdef ENABLE_DIRECT_PHY
if (bts->trx[trx].fl1h) {
l1if_pdch_req(bts->trx[trx].fl1h, ts, 1, fn, arfcn, block_nr, data, data_len);
@ -233,22 +232,20 @@ void pcu_l1if_tx_ptcch(uint8_t trx, uint8_t ts, uint16_t arfcn,
void pcu_l1if_tx_agch(bitvec * block, int plen)
{
struct gprs_rlcmac_bts *bts = bts_main_data();
uint8_t data[GSM_MACBLOCK_LEN]; /* prefix PLEN */
/* FIXME: why does OpenBTS has no PLEN and no fill in message? */
bitvec_pack(block, data + 1);
data[0] = (plen << 2) | 0x01;
if (bts->gsmtap_categ_mask & (1 << PCU_GSMTAP_C_DL_AGCH))
gsmtap_send(bts->gsmtap, 0, 0, GSMTAP_CHANNEL_AGCH, 0, 0, 0, 0, data, GSM_MACBLOCK_LEN);
if (the_pcu->gsmtap_categ_mask & (1 << PCU_GSMTAP_C_DL_AGCH))
gsmtap_send(the_pcu->gsmtap, 0, 0, GSMTAP_CHANNEL_AGCH, 0, 0, 0, 0, data, GSM_MACBLOCK_LEN);
pcu_tx_data_req(0, 0, PCU_IF_SAPI_AGCH, 0, 0, 0, data, GSM_MACBLOCK_LEN);
}
void pcu_l1if_tx_pch(bitvec * block, int plen, uint16_t pgroup)
{
struct gprs_rlcmac_bts *bts = bts_main_data();
uint8_t data[PAGING_GROUP_LEN + GSM_MACBLOCK_LEN];
int i;
@ -266,8 +263,8 @@ void pcu_l1if_tx_pch(bitvec * block, int plen, uint16_t pgroup)
data[3] = (plen << 2) | 0x01;
bitvec_pack(block, data + PAGING_GROUP_LEN + 1);
if (bts->gsmtap_categ_mask & (1 << PCU_GSMTAP_C_DL_PCH))
gsmtap_send(bts->gsmtap, 0, 0, GSMTAP_CHANNEL_PCH, 0, 0, 0, 0, data + 3, GSM_MACBLOCK_LEN);
if (the_pcu->gsmtap_categ_mask & (1 << PCU_GSMTAP_C_DL_PCH))
gsmtap_send(the_pcu->gsmtap, 0, 0, GSMTAP_CHANNEL_PCH, 0, 0, 0, 0, data + 3, GSM_MACBLOCK_LEN);
pcu_tx_data_req(0, 0, PCU_IF_SAPI_PCH, 0, 0, 0, data, PAGING_GROUP_LEN + GSM_MACBLOCK_LEN);
}
@ -315,7 +312,6 @@ static int pcu_rx_data_ind_bcch(uint8_t *data, uint8_t len)
static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind)
{
struct gprs_rlcmac_bts *bts = bts_main_data();
int rc;
int current_fn = get_current_fn();
struct pcu_l1_meas meas = {0};
@ -353,8 +349,8 @@ static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind)
gsmtap_chantype = GSMTAP_CHANNEL_UNKNOWN;
}
if (rc < 0 && (bts->gsmtap_categ_mask & (1 <<PCU_GSMTAP_C_UL_UNKNOWN))) {
gsmtap_send(bts->gsmtap, data_ind->arfcn | GSMTAP_ARFCN_F_UPLINK, data_ind->ts_nr,
if (rc < 0 && (the_pcu->gsmtap_categ_mask & (1 <<PCU_GSMTAP_C_UL_UNKNOWN))) {
gsmtap_send(the_pcu->gsmtap, data_ind->arfcn | GSMTAP_ARFCN_F_UPLINK, data_ind->ts_nr,
gsmtap_chantype, 0, data_ind->fn, meas.rssi, meas.link_qual, data_ind->data, data_ind->len);
}
@ -405,7 +401,7 @@ extern "C" int pcu_rx_rts_req_ptcch(uint8_t trx, uint8_t ts,
if (!pdch->m_is_enabled)
return -EAGAIN;
pcu_l1if_tx_ptcch(trx, ts, bts->trx[trx].arfcn, fn, block_nr,
pcu_l1if_tx_ptcch(bts, trx, ts, bts->trx[trx].arfcn, fn, block_nr,
pdch->ptcch_msg, GSM_MACBLOCK_LEN);
return 0;
}
@ -621,7 +617,7 @@ bssgp_failed:
if (allowed)
LOGP(DL1IF, LOGL_DEBUG, " Use CS%d\n", i + 1);
}
bts_set_max_cs(bts, bts->vty.max_cs_dl, bts->vty.max_cs_ul); /* recalc max CS values */
bts_recalc_max_cs(bts);
bts->mcs_mask = 0;
for (i = 0; i < 9; i++) {
@ -631,11 +627,11 @@ bssgp_failed:
LOGP(DL1IF, LOGL_DEBUG, " Use MCS%d\n", i + 1);
}
bts_set_max_mcs(bts, bts->vty.max_mcs_dl, bts->vty.max_mcs_ul); /* recalc max MCS values */
bts_recalc_max_mcs(bts);
LOGP(DL1IF, LOGL_DEBUG, " initial_cs=%u%s\n", info_ind->initial_cs,
bts->vty.force_initial_cs ? " (VTY forced, ignoring)" : "");
if (!bts->vty.force_initial_cs) {
the_pcu->vty.force_initial_cs ? " (VTY forced, ignoring)" : "");
if (!the_pcu->vty.force_initial_cs) {
if (info_ind->initial_cs > bts->bts->max_cs_dl()) {
LOGP(DL1IF, LOGL_DEBUG, " downgrading initial_cs_dl to %d\n", bts->bts->max_cs_dl());
bts->initial_cs_dl = bts->bts->max_cs_dl();
@ -651,8 +647,8 @@ bssgp_failed:
}
LOGP(DL1IF, LOGL_DEBUG, " initial_mcs=%u%s\n", info_ind->initial_mcs,
bts->vty.force_initial_mcs ? " (VTY forced, ignoring)" : "");
if (!bts->vty.force_initial_mcs) {
the_pcu->vty.force_initial_mcs ? " (VTY forced, ignoring)" : "");
if (!the_pcu->vty.force_initial_mcs) {
if (info_ind->initial_mcs > bts->bts->max_mcs_dl()) {
LOGP(DL1IF, LOGL_DEBUG, " downgrading initial_mcs_dl to %d\n", bts->bts->max_mcs_dl());
bts->initial_mcs_dl = bts->bts->max_mcs_dl();
@ -705,7 +701,7 @@ bssgp_failed:
bts->trx[trx_nr].fl1h = l1if_open_pdch(
trx_nr,
info_ind->trx[trx_nr].hlayer1,
bts->gsmtap);
the_pcu->gsmtap);
if (!bts->trx[trx_nr].fl1h) {
LOGP(DL1IF, LOGL_FATAL, "Failed to open direct "
"DSP access for PDCH.\n");

@ -143,7 +143,8 @@ static inline void pcu_l1_meas_set_ms_i_level(struct pcu_l1_meas *m, size_t idx,
#ifdef __cplusplus
void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr);
void pcu_l1if_tx_ptcch(uint8_t trx, uint8_t ts, uint16_t arfcn,
void pcu_l1if_tx_ptcch(struct gprs_rlcmac_bts *bts,
uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr,
uint8_t *data, size_t data_len);
void pcu_l1if_tx_agch(bitvec * block, int len);

@ -224,7 +224,7 @@ void sighandler(int sigset)
int main(int argc, char *argv[])
{
struct sched_param param;
struct gprs_rlcmac_bts *bts;
struct gprs_pcu *pcu;
int rc;
/* tall_pcu_ctx may already have been initialized in bts.cpp during early_init(). */
@ -235,9 +235,12 @@ int main(int argc, char *argv[])
osmo_init_logging2(tall_pcu_ctx, &gprs_log_info);
}
bts = bts_main_data();
pcu = gprs_pcu_alloc(tall_pcu_ctx);
the_pcu = pcu; /* globally avaialable object */
bts->pcu_sock_path = talloc_strdup(tall_pcu_ctx, PCU_SOCK_DEFAULT);
pcu->bts = bts_alloc(pcu);
pcu->pcu_sock_path = talloc_strdup(tall_pcu_ctx, PCU_SOCK_DEFAULT);
msgb_talloc_ctx_init(tall_pcu_ctx, 0);
@ -257,20 +260,20 @@ int main(int argc, char *argv[])
exit(0);
}
bts->gsmtap = gsmtap_source_init(gsmtap_addr, GSMTAP_UDP_PORT, 1);
pcu->gsmtap = gsmtap_source_init(gsmtap_addr, GSMTAP_UDP_PORT, 1);
if (bts->gsmtap)
gsmtap_source_add_sink(bts->gsmtap);
if (pcu->gsmtap)
gsmtap_source_add_sink(pcu->gsmtap);
else
fprintf(stderr, "Failed to initialize GSMTAP for %s\n", gsmtap_addr);
bts->nsi = gprs_ns2_instantiate(tall_pcu_ctx, gprs_ns_prim_cb, NULL);
if (!bts->nsi) {
pcu->nsi = gprs_ns2_instantiate(tall_pcu_ctx, gprs_ns_prim_cb, NULL);
if (!pcu->nsi) {
LOGP(DBSSGP, LOGL_ERROR, "Failed to create NS instance\n");
exit(1);
}
bssgp_set_bssgp_callback(gprs_gp_send_cb, bts->nsi);
gprs_ns2_vty_init(bts->nsi, NULL);
bssgp_set_bssgp_callback(gprs_gp_send_cb, pcu->nsi);
gprs_ns2_vty_init(pcu->nsi, NULL);
rc = vty_read_config_file(config_file, NULL);
if (rc < 0 && config_given) {
@ -291,8 +294,8 @@ int main(int argc, char *argv[])
exit(1);
}
if (!bts->alloc_algorithm)
bts->alloc_algorithm = alloc_algorithm_dynamic;
if (!pcu->alloc_algorithm)
pcu->alloc_algorithm = alloc_algorithm_dynamic;
rc = pcu_l1if_open();

@ -70,28 +70,26 @@ static const struct value_string pcu_gsmtap_categ_help[] = {
DEFUN(cfg_pcu_gsmtap_categ, cfg_pcu_gsmtap_categ_cmd, "HIDDEN", "HIDDEN")
{
struct gprs_rlcmac_bts *bts = bts_main_data();
int categ;
categ = get_string_value(pcu_gsmtap_categ_names, argv[0]);
if (categ < 0)
return CMD_WARNING;
bts->gsmtap_categ_mask |= (1 << categ);
the_pcu->gsmtap_categ_mask |= (1 << categ);
return CMD_SUCCESS;
}
DEFUN(cfg_pcu_no_gsmtap_categ, cfg_pcu_no_gsmtap_categ_cmd, "HIDDEN", "HIDDEN")
{
struct gprs_rlcmac_bts *bts = bts_main_data();
int categ;
categ = get_string_value(pcu_gsmtap_categ_names, argv[0]);
if (categ < 0)
return CMD_WARNING;</