mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-10-23 08:12:01 +00:00
Merge branch 'master' of git.osmocom.org:openbsc
This commit is contained in:
118
openbsc/doc/examples/osmo-nitb/nokia/openbsc_nokia_3trx.cfg
Normal file
118
openbsc/doc/examples/osmo-nitb/nokia/openbsc_nokia_3trx.cfg
Normal file
@@ -0,0 +1,118 @@
|
||||
!
|
||||
! OpenBSC configuration saved from vty
|
||||
! !
|
||||
password foo
|
||||
!
|
||||
line vty
|
||||
no login
|
||||
!
|
||||
e1_input
|
||||
e1_line 0 driver misdn
|
||||
network
|
||||
network country code 1
|
||||
mobile network code 1
|
||||
short name OpenBSC
|
||||
long name OpenBSC
|
||||
auth policy accept-all
|
||||
timer t3101 10
|
||||
timer t3113 60
|
||||
bts 0
|
||||
type nokia_site
|
||||
band GSM1800
|
||||
cell_identity 1
|
||||
location_area_code 1
|
||||
base_station_id_code 63
|
||||
training_sequence_code 7
|
||||
|
||||
oml e1 line 0 timeslot 1 sub-slot full
|
||||
oml e1 tei 1
|
||||
|
||||
trx 0
|
||||
arfcn 866
|
||||
max_power_red 24
|
||||
rsl e1 line 0 timeslot 2 sub-slot full
|
||||
rsl e1 tei 1
|
||||
timeslot 0
|
||||
phys_chan_config CCCH+SDCCH4
|
||||
e1 line 0 timeslot 6 sub-slot full
|
||||
timeslot 1
|
||||
phys_chan_config SDCCH8
|
||||
e1 line 0 timeslot 6 sub-slot 1
|
||||
timeslot 2
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 6 sub-slot 2
|
||||
timeslot 3
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 6 sub-slot 3
|
||||
timeslot 4
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 7 sub-slot 0
|
||||
timeslot 5
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 7 sub-slot 1
|
||||
timeslot 6
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 7 sub-slot 2
|
||||
timeslot 7
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 7 sub-slot 3
|
||||
|
||||
trx 1
|
||||
arfcn 870
|
||||
max_power_red 24
|
||||
rsl e1 line 0 timeslot 3 sub-slot full
|
||||
rsl e1 tei 2
|
||||
timeslot 0
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 8 sub-slot 0
|
||||
timeslot 1
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 8 sub-slot 1
|
||||
timeslot 2
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 8 sub-slot 2
|
||||
timeslot 3
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 8 sub-slot 3
|
||||
timeslot 4
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 9 sub-slot 0
|
||||
timeslot 5
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 9 sub-slot 1
|
||||
timeslot 6
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 9 sub-slot 2
|
||||
timeslot 7
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 9 sub-slot 3
|
||||
|
||||
trx 2
|
||||
arfcn 874
|
||||
max_power_red 24
|
||||
rsl e1 line 0 timeslot 4 sub-slot full
|
||||
rsl e1 tei 3
|
||||
timeslot 0
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 10 sub-slot 0
|
||||
timeslot 1
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 10 sub-slot 1
|
||||
timeslot 2
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 10 sub-slot 2
|
||||
timeslot 3
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 10 sub-slot 3
|
||||
timeslot 4
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 11 sub-slot 0
|
||||
timeslot 5
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 11 sub-slot 1
|
||||
timeslot 6
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 11 sub-slot 2
|
||||
timeslot 7
|
||||
phys_chan_config TCH/F
|
||||
e1 line 0 timeslot 11 sub-slot 3
|
@@ -90,5 +90,12 @@ int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int dbm);
|
||||
int rsl_sms_cb_command(struct gsm_bts *bts, uint8_t chan_number,
|
||||
uint8_t cb_command, const uint8_t *data, int len);
|
||||
|
||||
/* some Nokia specific stuff */
|
||||
int rsl_nokia_si_begin(struct gsm_bts_trx *trx);
|
||||
int rsl_nokia_si_end(struct gsm_bts_trx *trx);
|
||||
|
||||
/* required for Nokia BTS power control */
|
||||
int rsl_bs_power_control(struct gsm_bts_trx *trx, uint8_t channel, uint8_t reduction);
|
||||
|
||||
#endif /* RSL_MT_H */
|
||||
|
||||
|
@@ -14,4 +14,5 @@ extern int bts_model_bs11_init(void);
|
||||
extern int bts_model_rbs2k_init(void);
|
||||
extern int bts_model_nanobts_init(void);
|
||||
extern int bts_model_hslfemto_init(void);
|
||||
extern int bts_model_nokia_site_init(void);
|
||||
#endif
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <openbsc/subchan_demux.h>
|
||||
|
||||
#define NUM_E1_TS 32
|
||||
@@ -19,6 +20,14 @@ enum e1inp_sign_type {
|
||||
};
|
||||
const char *e1inp_signtype_name(enum e1inp_sign_type tp);
|
||||
|
||||
enum e1inp_ctr {
|
||||
E1I_CTR_HDLC_ABORT,
|
||||
E1I_CTR_HDLC_BADFCS,
|
||||
E1I_CTR_HDLC_OVERR,
|
||||
E1I_CTR_ALARM,
|
||||
E1I_CTR_REMOVED,
|
||||
};
|
||||
|
||||
struct e1inp_ts;
|
||||
|
||||
struct e1inp_sign_link {
|
||||
@@ -107,6 +116,7 @@ struct e1inp_line {
|
||||
struct llist_head list;
|
||||
unsigned int num;
|
||||
const char *name;
|
||||
struct rate_ctr_group *rate_ctr;
|
||||
|
||||
/* array of timestlots */
|
||||
struct e1inp_ts ts[NUM_E1_TS];
|
||||
|
@@ -182,6 +182,7 @@ struct gsm_lchan {
|
||||
struct osmo_timer_list T3101;
|
||||
struct osmo_timer_list T3111;
|
||||
struct osmo_timer_list error_timer;
|
||||
struct osmo_timer_list act_timer;
|
||||
|
||||
/* table of neighbor cell measurements */
|
||||
struct neigh_meas_proc neigh_meas[MAX_NEIGH_MEAS];
|
||||
@@ -325,6 +326,7 @@ enum gsm_bts_type {
|
||||
GSM_BTS_TYPE_NANOBTS,
|
||||
GSM_BTS_TYPE_RBS2000,
|
||||
GSM_BTS_TYPE_HSL_FEMTO,
|
||||
GSM_BTS_TYPE_NOKIA_SITE,
|
||||
};
|
||||
|
||||
struct vty;
|
||||
@@ -487,6 +489,13 @@ struct gsm_bts {
|
||||
struct {
|
||||
unsigned long serno;
|
||||
} hsl;
|
||||
struct {
|
||||
uint8_t bts_type;
|
||||
int configured:1,
|
||||
do_reset:1,
|
||||
wait_reset:1;
|
||||
struct osmo_timer_list reset_timer;
|
||||
} nokia;
|
||||
};
|
||||
|
||||
/* Not entirely sure how ip.access specific this is */
|
||||
|
@@ -145,6 +145,7 @@ enum signal_input {
|
||||
S_INP_NONE,
|
||||
S_INP_TEI_UP,
|
||||
S_INP_TEI_DN,
|
||||
S_INP_TEI_UNKNOWN,
|
||||
S_INP_LINE_INIT,
|
||||
S_INP_LINE_ALARM,
|
||||
S_INP_LINE_NOALARM,
|
||||
|
@@ -867,7 +867,7 @@ static int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause)
|
||||
}
|
||||
|
||||
static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx,
|
||||
uint16_t pdp_status)
|
||||
uint8_t *pdp_status)
|
||||
{
|
||||
struct sgsn_pdp_ctx *pdp, *pdp2;
|
||||
/* 24.008 4.7.5.1.3: If the PDP context status information element is
|
||||
@@ -878,11 +878,20 @@ static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx,
|
||||
* being in state PDP-INACTIVE. */
|
||||
|
||||
llist_for_each_entry_safe(pdp, pdp2, &mmctx->pdp_list, list) {
|
||||
if (!(pdp_status & (1 << pdp->nsapi))) {
|
||||
LOGP(DMM, LOGL_NOTICE, "Dropping PDP context for NSAPI=%u "
|
||||
"due to PDP CTX STATUS IE= 0x%04x\n",
|
||||
pdp->nsapi, pdp_status);
|
||||
sgsn_delete_pdp_ctx(pdp);
|
||||
if (pdp->nsapi < 8) {
|
||||
if (!(pdp_status[0] & (1 << pdp->nsapi))) {
|
||||
LOGP(DMM, LOGL_NOTICE, "Dropping PDP context for NSAPI=%u "
|
||||
"due to PDP CTX STATUS IE= 0x%02x%02x\n",
|
||||
pdp->nsapi, pdp_status[1], pdp_status[0]);
|
||||
sgsn_delete_pdp_ctx(pdp);
|
||||
}
|
||||
} else {
|
||||
if (!(pdp_status[1] & (1 << (pdp->nsapi - 8)))) {
|
||||
LOGP(DMM, LOGL_NOTICE, "Dropping PDP context for NSAPI=%u "
|
||||
"due to PDP CTX STATUS IE= 0x%02x%02x\n",
|
||||
pdp->nsapi, pdp_status[1], pdp_status[0]);
|
||||
sgsn_delete_pdp_ctx(pdp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -975,8 +984,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
/* Look at PDP Context Status IE and see if MS's view of
|
||||
* activated/deactivated NSAPIs agrees with our view */
|
||||
if (TLVP_PRESENT(&tp, GSM48_IE_GMM_PDP_CTX_STATUS)) {
|
||||
uint16_t pdp_status = ntohs(*(uint16_t *)
|
||||
TLVP_VAL(&tp, GSM48_IE_GMM_PDP_CTX_STATUS));
|
||||
uint8_t *pdp_status = TLVP_VAL(&tp, GSM48_IE_GMM_PDP_CTX_STATUS);
|
||||
process_ms_ctx_status(mmctx, pdp_status);
|
||||
}
|
||||
|
||||
|
@@ -39,17 +39,19 @@
|
||||
#endif
|
||||
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/e1_input.h>
|
||||
#include <openbsc/abis_nm.h>
|
||||
#include <openbsc/abis_rsl.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <openbsc/subchan_demux.h>
|
||||
#include <openbsc/trau_frame.h>
|
||||
#include <openbsc/trau_mux.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <openbsc/signal.h>
|
||||
#include <openbsc/misdn.h>
|
||||
|
||||
@@ -65,6 +67,31 @@ LLIST_HEAD(e1inp_line_list);
|
||||
|
||||
static void *tall_sigl_ctx;
|
||||
|
||||
static const struct rate_ctr_desc e1inp_ctr_d[] = {
|
||||
[E1I_CTR_HDLC_ABORT] = {
|
||||
"hdlc.abort", "HDLC abort"
|
||||
},
|
||||
[E1I_CTR_HDLC_BADFCS] = {
|
||||
"hdlc.bad_fcs", "HLDC Bad FCS"
|
||||
},
|
||||
[E1I_CTR_HDLC_OVERR] = {
|
||||
"hdlc.overrun", "HDLC Overrun"
|
||||
},
|
||||
[E1I_CTR_ALARM] = {
|
||||
"alarm", "Alarm"
|
||||
},
|
||||
[E1I_CTR_REMOVED] = {
|
||||
"removed", "Line removed"
|
||||
},
|
||||
};
|
||||
|
||||
static const struct rate_ctr_group_desc e1inp_ctr_g_d = {
|
||||
.group_name_prefix = "e1inp",
|
||||
.group_description = "E1 Input subsystem",
|
||||
.num_ctr = ARRAY_SIZE(e1inp_ctr_d),
|
||||
.ctr_desc = e1inp_ctr_d,
|
||||
};
|
||||
|
||||
/*
|
||||
* pcap writing of the misdn load
|
||||
* pcap format is from http://wiki.wireshark.org/Development/LibpcapFileFormat
|
||||
@@ -360,8 +387,10 @@ struct e1inp_line *e1inp_line_create(uint8_t e1_nr, const char *driver_name)
|
||||
return NULL;
|
||||
|
||||
line->driver = driver;
|
||||
|
||||
line->num = e1_nr;
|
||||
|
||||
line->rate_ctr = rate_ctr_group_alloc(line, &e1inp_ctr_g_d, line->num);
|
||||
|
||||
for (i = 0; i < NUM_E1_TS; i++) {
|
||||
line->ts[i].num = i+1;
|
||||
line->ts[i].line = line;
|
||||
@@ -570,6 +599,7 @@ int e1inp_event(struct e1inp_ts *ts, int evt, uint8_t tei, uint8_t sapi)
|
||||
if (!link)
|
||||
return -EINVAL;
|
||||
|
||||
isd.line = ts->line;
|
||||
isd.link_type = link->type;
|
||||
isd.trx = link->trx;
|
||||
isd.tei = tei;
|
||||
|
@@ -20,30 +20,36 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
|
||||
#include <osmocom/vty/command.h>
|
||||
#include <osmocom/vty/buffer.h>
|
||||
#include <osmocom/vty/vty.h>
|
||||
#include <osmocom/vty/logging.h>
|
||||
#include <osmocom/vty/misc.h>
|
||||
#include <osmocom/vty/telnet_interface.h>
|
||||
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/e1_input.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <openbsc/vty.h>
|
||||
#include <openbsc/debug.h>
|
||||
|
||||
#include "../../bscconfig.h"
|
||||
|
||||
/* CONFIG */
|
||||
|
||||
#define E1_DRIVER_NAMES "(misdn|dahdi)"
|
||||
#define E1_DRIVER_HELP "mISDN supported E1 Card\n" \
|
||||
"DAHDI supported E1/T1/J1 Card\n"
|
||||
|
||||
#define E1_LINE_HELP "Configure E1/T1/J1 Line\n" "Line Number\n"
|
||||
|
||||
DEFUN(cfg_e1line_driver, cfg_e1_line_driver_cmd,
|
||||
"e1_line <0-255> driver " E1_DRIVER_NAMES,
|
||||
"Configure E1/T1/J1 Line\n" "Line Number\n" "Set driver for this line\n"
|
||||
E1_LINE_HELP "Set driver for this line\n"
|
||||
E1_DRIVER_HELP)
|
||||
{
|
||||
struct e1inp_line *line;
|
||||
@@ -63,6 +69,27 @@ DEFUN(cfg_e1line_driver, cfg_e1_line_driver_cmd,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_e1line_name, cfg_e1_line_name_cmd,
|
||||
"e1_line <0-255> name .LINE",
|
||||
E1_LINE_HELP "Set name for this line\n" "Human readable name\n")
|
||||
{
|
||||
struct e1inp_line *line;
|
||||
int e1_nr = atoi(argv[0]);
|
||||
|
||||
line = e1inp_line_get(e1_nr);
|
||||
if (!line) {
|
||||
vty_out(vty, "%% Line %d doesn't exist%s", e1_nr, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (line->name) {
|
||||
talloc_free((void *)line->name);
|
||||
line->name = NULL;
|
||||
}
|
||||
line->name = talloc_strdup(line, argv[1]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_e1inp, cfg_e1inp_cmd,
|
||||
"e1_input",
|
||||
"Configure E1/T1/J1 TDM input\n")
|
||||
@@ -84,10 +111,138 @@ static int e1inp_config_write(struct vty *vty)
|
||||
llist_for_each_entry(line, &e1inp_line_list, list) {
|
||||
vty_out(vty, " e1_line %u driver %s%s", line->num,
|
||||
line->driver->name, VTY_NEWLINE);
|
||||
if (line->name)
|
||||
vty_out(vty, " e1_line %u name %s%s", line->num,
|
||||
line->name, VTY_NEWLINE);
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* SHOW */
|
||||
|
||||
static void e1drv_dump_vty(struct vty *vty, struct e1inp_driver *drv)
|
||||
{
|
||||
vty_out(vty, "E1 Input Driver %s%s", drv->name, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
DEFUN(show_e1drv,
|
||||
show_e1drv_cmd,
|
||||
"show e1_driver",
|
||||
SHOW_STR "Display information about available E1 drivers\n")
|
||||
{
|
||||
struct e1inp_driver *drv;
|
||||
|
||||
llist_for_each_entry(drv, &e1inp_driver_list, list)
|
||||
e1drv_dump_vty(vty, drv);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void e1line_dump_vty(struct vty *vty, struct e1inp_line *line,
|
||||
int stats)
|
||||
{
|
||||
vty_out(vty, "E1 Line Number %u, Name %s, Driver %s%s",
|
||||
line->num, line->name ? line->name : "",
|
||||
line->driver->name, VTY_NEWLINE);
|
||||
if (stats)
|
||||
vty_out_rate_ctr_group(vty, " ", line->rate_ctr);
|
||||
}
|
||||
|
||||
DEFUN(show_e1line,
|
||||
show_e1line_cmd,
|
||||
"show e1_line [line_nr] [stats]",
|
||||
SHOW_STR "Display information about a E1 line\n"
|
||||
"E1 Line Number\n")
|
||||
{
|
||||
struct e1inp_line *line;
|
||||
int stats = 0;
|
||||
|
||||
if (argc >= 1 && strcmp(argv[0], "stats")) {
|
||||
int num = atoi(argv[0]);
|
||||
if (argc >= 2)
|
||||
stats = 1;
|
||||
llist_for_each_entry(line, &e1inp_line_list, list) {
|
||||
if (line->num == num) {
|
||||
e1line_dump_vty(vty, line, stats);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
}
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (argc >= 1 && !strcmp(argv[0], "stats"))
|
||||
stats = 1;
|
||||
|
||||
llist_for_each_entry(line, &e1inp_line_list, list)
|
||||
e1line_dump_vty(vty, line, stats);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void e1ts_dump_vty(struct vty *vty, struct e1inp_ts *ts)
|
||||
{
|
||||
if (ts->type == E1INP_TS_TYPE_NONE)
|
||||
return;
|
||||
vty_out(vty, "E1 Timeslot %2u of Line %u is Type %s%s",
|
||||
ts->num, ts->line->num, e1inp_tstype_name(ts->type),
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
DEFUN(show_e1ts,
|
||||
show_e1ts_cmd,
|
||||
"show e1_timeslot [line_nr] [ts_nr]",
|
||||
SHOW_STR "Display information about a E1 timeslot\n"
|
||||
"E1 Line Number\n" "E1 Timeslot Number\n")
|
||||
{
|
||||
struct e1inp_line *line = NULL;
|
||||
struct e1inp_ts *ts;
|
||||
int ts_nr;
|
||||
|
||||
if (argc == 0) {
|
||||
llist_for_each_entry(line, &e1inp_line_list, list) {
|
||||
for (ts_nr = 0; ts_nr < NUM_E1_TS; ts_nr++) {
|
||||
ts = &line->ts[ts_nr];
|
||||
e1ts_dump_vty(vty, ts);
|
||||
}
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
if (argc >= 1) {
|
||||
int num = atoi(argv[0]);
|
||||
struct e1inp_line *l;
|
||||
llist_for_each_entry(l, &e1inp_line_list, list) {
|
||||
if (l->num == num) {
|
||||
line = l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!line) {
|
||||
vty_out(vty, "E1 line %s is invalid%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
}
|
||||
if (argc >= 2) {
|
||||
ts_nr = atoi(argv[1]);
|
||||
if (ts_nr >= NUM_E1_TS) {
|
||||
vty_out(vty, "E1 timeslot %s is invalid%s",
|
||||
argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
ts = &line->ts[ts_nr];
|
||||
e1ts_dump_vty(vty, ts);
|
||||
return CMD_SUCCESS;
|
||||
} else {
|
||||
for (ts_nr = 0; ts_nr < NUM_E1_TS; ts_nr++) {
|
||||
ts = &line->ts[ts_nr];
|
||||
e1ts_dump_vty(vty, ts);
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
struct cmd_node e1inp_node = {
|
||||
E1INP_NODE,
|
||||
"%s(e1_input)#",
|
||||
@@ -99,6 +254,11 @@ int e1inp_vty_init(void)
|
||||
install_element(CONFIG_NODE, &cfg_e1inp_cmd);
|
||||
install_node(&e1inp_node, e1inp_config_write);
|
||||
install_element(E1INP_NODE, &cfg_e1_line_driver_cmd);
|
||||
install_element(E1INP_NODE, &cfg_e1_line_name_cmd);
|
||||
|
||||
install_element_ve(&show_e1drv_cmd);
|
||||
install_element_ve(&show_e1line_cmd);
|
||||
install_element_ve(&show_e1ts_cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -40,6 +40,8 @@
|
||||
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/abis_nm.h>
|
||||
@@ -68,6 +70,7 @@ static const struct value_string dahdi_evt_names[] = {
|
||||
static void handle_dahdi_exception(struct e1inp_ts *ts)
|
||||
{
|
||||
int rc, evt;
|
||||
struct e1inp_line *line = ts->line;
|
||||
struct input_signal_data isd;
|
||||
|
||||
rc = ioctl(ts->driver.dahdi.fd.fd, DAHDI_GETEVENT, &evt);
|
||||
@@ -84,11 +87,24 @@ static void handle_dahdi_exception(struct e1inp_ts *ts)
|
||||
case DAHDI_EVENT_ALARM:
|
||||
/* we should notify the code that the line is gone */
|
||||
osmo_signal_dispatch(SS_INPUT, S_INP_LINE_ALARM, &isd);
|
||||
rate_ctr_inc(&line->rate_ctr->ctr[E1I_CTR_ALARM]);
|
||||
break;
|
||||
case DAHDI_EVENT_NOALARM:
|
||||
/* alarm has gone, we should re-start the SABM requests */
|
||||
osmo_signal_dispatch(SS_INPUT, S_INP_LINE_NOALARM, &isd);
|
||||
break;
|
||||
case DAHDI_EVENT_ABORT:
|
||||
rate_ctr_inc(&line->rate_ctr->ctr[E1I_CTR_HDLC_ABORT]);
|
||||
break;
|
||||
case DAHDI_EVENT_OVERRUN:
|
||||
rate_ctr_inc(&line->rate_ctr->ctr[E1I_CTR_HDLC_OVERR]);
|
||||
break;
|
||||
case DAHDI_EVENT_BADFCS:
|
||||
rate_ctr_inc(&line->rate_ctr->ctr[E1I_CTR_HDLC_BADFCS]);
|
||||
break;
|
||||
case DAHDI_EVENT_REMOVED:
|
||||
rate_ctr_inc(&line->rate_ctr->ctr[E1I_CTR_REMOVED]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +116,7 @@ static int handle_ts1_read(struct osmo_fd *bfd)
|
||||
struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "DAHDI TS1");
|
||||
lapd_mph_type prim;
|
||||
unsigned int sapi, tei;
|
||||
int ilen, ret;
|
||||
int ilen, ret, error = 0;
|
||||
uint8_t *idata;
|
||||
|
||||
if (!msg)
|
||||
@@ -122,9 +138,21 @@ static int handle_ts1_read(struct osmo_fd *bfd)
|
||||
|
||||
DEBUGP(DMI, "<= len = %d, sapi(%d) tei(%d)", ret, sapi, tei);
|
||||
|
||||
idata = lapd_receive(e1i_ts->driver.dahdi.lapd, msg->data, msg->len, &ilen, &prim);
|
||||
if (!idata && prim == 0)
|
||||
return -EIO;
|
||||
idata = lapd_receive(e1i_ts->driver.dahdi.lapd, msg->data, msg->len, &ilen, &prim, &error);
|
||||
if (!idata) {
|
||||
switch(error) {
|
||||
case LAPD_ERR_UNKNOWN_TEI:
|
||||
/* We don't know about this TEI, probably the BSC
|
||||
* lost local states (it crashed or it was stopped),
|
||||
* notify the driver to see if it can do anything to
|
||||
* recover the existing signalling links with the BTS.
|
||||
*/
|
||||
e1inp_event(e1i_ts, S_INP_TEI_UNKNOWN, tei, sapi);
|
||||
return -EIO;
|
||||
}
|
||||
if (prim == 0)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
msgb_pull(msg, 2);
|
||||
|
||||
@@ -421,11 +449,17 @@ static int dahdi_e1_setup(struct e1inp_line *line)
|
||||
char openstr[128];
|
||||
struct e1inp_ts *e1i_ts = &line->ts[idx];
|
||||
struct osmo_fd *bfd = &e1i_ts->driver.dahdi.fd;
|
||||
int dev_nr;
|
||||
|
||||
/* DAHDI device names/numbers just keep incrementing
|
||||
* even over multiple boards. So TS1 of the second
|
||||
* board will be 32 */
|
||||
dev_nr = line->num * (NUM_E1_TS-1) + ts;
|
||||
|
||||
bfd->data = line;
|
||||
bfd->priv_nr = ts;
|
||||
bfd->cb = dahdi_fd_cb;
|
||||
snprintf(openstr, sizeof(openstr), "/dev/dahdi/%d", ts);
|
||||
snprintf(openstr, sizeof(openstr), "/dev/dahdi/%d", dev_nr);
|
||||
|
||||
switch (e1i_ts->type) {
|
||||
case E1INP_TS_TYPE_NONE:
|
||||
|
@@ -31,7 +31,6 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "lapd.h"
|
||||
@@ -190,7 +189,7 @@ static struct lapd_tei *teip_from_tei(struct lapd_instance *li, uint8_t tei)
|
||||
|
||||
static void lapd_tei_set_state(struct lapd_tei *teip, int newstate)
|
||||
{
|
||||
DEBUGP(DMI, "state change on TEI %d: %s -> %s\n", teip->tei,
|
||||
LOGP(DMI, LOGL_INFO, "LAPD state change on TEI %d: %s -> %s\n", teip->tei,
|
||||
lapd_tei_states[teip->state], lapd_tei_states[newstate]);
|
||||
teip->state = newstate;
|
||||
};
|
||||
@@ -234,7 +233,7 @@ static struct lapd_sap *lapd_sap_alloc(struct lapd_tei *teip, uint8_t sapi)
|
||||
{
|
||||
struct lapd_sap *sap = talloc_zero(teip, struct lapd_sap);
|
||||
|
||||
LOGP(DMI, LOGL_INFO, "Allocating SAP for SAPI=%u / TEI=%u\n",
|
||||
LOGP(DMI, LOGL_INFO, "LAPD Allocating SAP for SAPI=%u / TEI=%u\n",
|
||||
sapi, teip->tei);
|
||||
|
||||
sap->sapi = sapi;
|
||||
@@ -254,8 +253,9 @@ static void lapd_sap_set_state(struct lapd_tei *teip, uint8_t sapi,
|
||||
if (!sap)
|
||||
return;
|
||||
|
||||
DEBUGP(DMI, "state change on TEI %u / SAPI %u: %s -> %s\n", teip->tei,
|
||||
sapi, lapd_sap_states[sap->state], lapd_sap_states[newstate]);
|
||||
LOGP(DMI, LOGL_INFO, "LAPD state change on TEI %u / SAPI %u: "
|
||||
"%s -> %s\n", teip->tei, sapi,
|
||||
lapd_sap_states[sap->state], lapd_sap_states[newstate]);
|
||||
switch (sap->state) {
|
||||
case SAP_STATE_SABM_RETRANS:
|
||||
if (newstate != SAP_STATE_SABM_RETRANS)
|
||||
@@ -281,11 +281,12 @@ static void lapd_tei_receive(struct lapd_instance *li, uint8_t *data, int len)
|
||||
uint8_t resp[8];
|
||||
struct lapd_tei *teip;
|
||||
|
||||
DEBUGP(DMI, "TEIMGR: entity %x, ref %x, mt %x, action %x, e %x\n", entity, ref, mt, action, e);
|
||||
DEBUGP(DMI, "LAPD TEIMGR: entity %x, ref %x, mt %x, action %x, e %x\n",
|
||||
entity, ref, mt, action, e);
|
||||
|
||||
switch (mt) {
|
||||
case 0x01: /* IDENTITY REQUEST */
|
||||
DEBUGP(DMI, "TEIMGR: identity request for TEI %u\n", action);
|
||||
DEBUGP(DMI, "LAPD TEIMGR: identity request for TEI %u\n", action);
|
||||
|
||||
teip = teip_from_tei(li, action);
|
||||
if (!teip) {
|
||||
@@ -302,15 +303,16 @@ static void lapd_tei_receive(struct lapd_instance *li, uint8_t *data, int len)
|
||||
lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED);
|
||||
break;
|
||||
default:
|
||||
LOGP(DMI, LOGL_NOTICE, "TEIMGR: unknown mt %x action %x\n",
|
||||
LOGP(DMI, LOGL_NOTICE, "LAPD TEIMGR: unknown mt %x action %x\n",
|
||||
mt, action);
|
||||
break;
|
||||
};
|
||||
};
|
||||
|
||||
/* General input function for any data received for this LAPD instance */
|
||||
uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len,
|
||||
int *ilen, lapd_mph_type *prim)
|
||||
uint8_t *
|
||||
lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len,
|
||||
int *ilen, lapd_mph_type *prim, int *error)
|
||||
{
|
||||
uint8_t sapi, cr, tei, command;
|
||||
int pf, ns, nr;
|
||||
@@ -325,13 +327,15 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
|
||||
*prim = 0;
|
||||
|
||||
if (len < 2) {
|
||||
DEBUGP(DMI, "len %d < 2\n", len);
|
||||
LOGP(DMI, LOGL_ERROR, "LAPD receive len %d < 2, ignoring\n", len);
|
||||
*error = LAPD_ERR_BAD_LEN;
|
||||
return NULL;
|
||||
};
|
||||
|
||||
if ((data[0] & 1) != 0 || (data[1] & 1) != 1) {
|
||||
DEBUGP(DMI, "address field %x/%x not well formed\n", data[0],
|
||||
data[1]);
|
||||
LOGP(DMI, LOGL_ERROR, "LAPD address field %x/%x not well formed\n",
|
||||
data[0], data[1]);
|
||||
*error = LAPD_ERR_BAD_ADDR;
|
||||
return NULL;
|
||||
};
|
||||
|
||||
@@ -342,7 +346,8 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
|
||||
//DEBUGP(DMI, " address sapi %x tei %d cmd %d cr %d\n", sapi, tei, command, cr);
|
||||
|
||||
if (len < 3) {
|
||||
DEBUGP(DMI, "len %d < 3\n", len);
|
||||
LOGP(DMI, LOGL_ERROR, "LAPD receive len %d < 3, ignoring\n", len);
|
||||
*error = LAPD_ERR_BAD_LEN;
|
||||
return NULL;
|
||||
};
|
||||
|
||||
@@ -353,14 +358,22 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
|
||||
nr = -1;
|
||||
if ((data[2] & 1) == 0) {
|
||||
typ = LAPD_TYPE_I;
|
||||
assert(len >= 4);
|
||||
if (len < 4) {
|
||||
LOGP(DMI, LOGL_ERROR, "LAPD I frame, len %d < 4\n", len);
|
||||
*error = LAPD_ERR_BAD_LEN;
|
||||
return NULL;
|
||||
}
|
||||
ns = data[2] >> 1;
|
||||
nr = data[3] >> 1;
|
||||
pf = data[3] & 1;
|
||||
cmd = LAPD_CMD_I;
|
||||
} else if ((data[2] & 3) == 1) {
|
||||
typ = LAPD_TYPE_S;
|
||||
assert(len >= 4);
|
||||
if (len < 4) {
|
||||
LOGP(DMI, LOGL_ERROR, "LAPD S frame, len %d < 4\n", len);
|
||||
*error = LAPD_ERR_BAD_LEN;
|
||||
return NULL;
|
||||
}
|
||||
nr = data[3] >> 1;
|
||||
pf = data[3] & 1;
|
||||
switch (data[2]) {
|
||||
@@ -374,7 +387,8 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
|
||||
cmd = LAPD_CMD_REJ;
|
||||
break;
|
||||
default:
|
||||
LOGP(DMI, LOGL_ERROR, "unknown LAPD S cmd %x\n", data[2]);
|
||||
LOGP(DMI, LOGL_ERROR, "LAPD unknown S cmd %x\n", data[2]);
|
||||
*error = LAPD_ERR_UNKNOWN_S_CMD;
|
||||
return NULL;
|
||||
};
|
||||
} else if ((data[2] & 3) == 3) {
|
||||
@@ -405,8 +419,9 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGP(DMI, LOGL_ERROR, "unknown U cmd %x "
|
||||
LOGP(DMI, LOGL_ERROR, "LAPD unknown U cmd %x "
|
||||
"(pf %x data %x)\n", val, pf, data[2]);
|
||||
*error = LAPD_ERR_UNKNOWN_U_CMD;
|
||||
return NULL;
|
||||
};
|
||||
};
|
||||
@@ -421,13 +436,14 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
|
||||
|
||||
teip = teip_from_tei(li, tei);
|
||||
if (!teip) {
|
||||
LOGP(DMI, LOGL_NOTICE, "Unknown TEI %u\n", tei);
|
||||
LOGP(DMI, LOGL_NOTICE, "LAPD Unknown TEI %u\n", tei);
|
||||
*error = LAPD_ERR_UNKNOWN_TEI;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sap = lapd_sap_find(teip, sapi);
|
||||
if (!sap) {
|
||||
LOGP(DMI, LOGL_INFO, "No SAP for TEI=%u / SAPI=%u, "
|
||||
LOGP(DMI, LOGL_INFO, "LAPD No SAP for TEI=%u / SAPI=%u, "
|
||||
"allocating\n", tei, sapi);
|
||||
sap = lapd_sap_alloc(teip, sapi);
|
||||
}
|
||||
@@ -440,12 +456,15 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
|
||||
switch (cmd) {
|
||||
case LAPD_CMD_I:
|
||||
if (ns != sap->vr) {
|
||||
DEBUGP(DMI, "ns %d != vr %d\n", ns, sap->vr);
|
||||
DEBUGP(DMI, "LAPD ns %d != vr %d\n", ns, sap->vr);
|
||||
if (ns == ((sap->vr - 1) & 0x7f)) {
|
||||
DEBUGP(DMI, "DOUBLE FRAME, ignoring\n");
|
||||
LOGP(DMI, LOGL_NOTICE, "LAPD double frame, "
|
||||
"ignoring\n");
|
||||
cmd = 0; // ignore
|
||||
} else {
|
||||
assert(0);
|
||||
LOGP(DMI, LOGL_ERROR, "LAPD Out of order "
|
||||
"ns %d != vr %d, ignoring\n", ns, sap->vr);
|
||||
return NULL;
|
||||
};
|
||||
} else {
|
||||
//printf("IN SEQUENCE\n");
|
||||
@@ -560,7 +579,7 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
|
||||
*/
|
||||
|
||||
/* interrogating us, send rr */
|
||||
DEBUGP(DMI, "Sending RR response\n");
|
||||
DEBUGP(DMI, "LAPD Sending RR response\n");
|
||||
resp[l++] = data[0];
|
||||
resp[l++] = (tei << 1) | 1;
|
||||
resp[l++] = 0x01; // rr
|
||||
@@ -577,6 +596,7 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len
|
||||
return contents;
|
||||
}
|
||||
|
||||
*error = LAPD_ERR_BAD_CMD;
|
||||
return NULL;
|
||||
};
|
||||
|
||||
@@ -587,7 +607,7 @@ static int lapd_send_sabm(struct lapd_instance *li, uint8_t tei, uint8_t sapi)
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
DEBUGP(DMI, "Sending SABM for TEI=%u, SAPI=%u\n", tei, sapi);
|
||||
LOGP(DMI, LOGL_INFO, "LAPD Sending SABM for TEI=%u, SAPI=%u\n", tei, sapi);
|
||||
|
||||
msgb_put_u8(msg, (sapi << 2) | (li->network_side ? 2 : 0));
|
||||
msgb_put_u8(msg, (tei << 1) | 1);
|
||||
@@ -662,15 +682,15 @@ void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi,
|
||||
struct lapd_sap *sap;
|
||||
|
||||
if (!teip) {
|
||||
LOGP(DMI, LOGL_ERROR, "Cannot transmit on non-existing "
|
||||
"TEI %u\n", tei);
|
||||
LOGP(DMI, LOGL_ERROR, "LAPD Cannot transmit on "
|
||||
"non-existing TEI %u\n", tei);
|
||||
return;
|
||||
}
|
||||
|
||||
sap = lapd_sap_find(teip, sapi);
|
||||
if (!sap) {
|
||||
LOGP(DMI, LOGL_INFO, "Tx on unknown SAPI=%u in TEI=%u, "
|
||||
"allocating\n", sapi, tei);
|
||||
LOGP(DMI, LOGL_INFO, "LAPD Tx on unknown SAPI=%u "
|
||||
"in TEI=%u, allocating\n", sapi, tei);
|
||||
sap = lapd_sap_alloc(teip, sapi);
|
||||
}
|
||||
|
||||
|
@@ -26,8 +26,20 @@ struct lapd_instance {
|
||||
struct llist_head tei_list; /* list of TEI in this LAPD instance */
|
||||
};
|
||||
|
||||
extern uint8_t *lapd_receive(struct lapd_instance *li, uint8_t *data, unsigned int len,
|
||||
int *ilen, lapd_mph_type *prim);
|
||||
enum lapd_recv_errors {
|
||||
LAPD_ERR_NONE = 0,
|
||||
LAPD_ERR_BAD_LEN,
|
||||
LAPD_ERR_BAD_ADDR,
|
||||
LAPD_ERR_UNKNOWN_S_CMD,
|
||||
LAPD_ERR_UNKNOWN_U_CMD,
|
||||
LAPD_ERR_UNKNOWN_TEI,
|
||||
LAPD_ERR_BAD_CMD,
|
||||
__LAPD_ERR_MAX
|
||||
};
|
||||
|
||||
extern uint8_t *lapd_receive(struct lapd_instance *li, uint8_t *data,
|
||||
unsigned int len, int *ilen, lapd_mph_type *prim,
|
||||
int *error);
|
||||
|
||||
extern void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi,
|
||||
uint8_t *data, unsigned int len);
|
||||
|
@@ -11,6 +11,7 @@ libbsc_a_SOURCES = abis_nm.c abis_nm_vty.c \
|
||||
bts_ericsson_rbs2000.c \
|
||||
bts_ipaccess_nanobts.c \
|
||||
bts_siemens_bs11.c \
|
||||
bts_nokia_site.c \
|
||||
bts_hsl_femtocell.c \
|
||||
bts_unknown.c \
|
||||
chan_alloc.c \
|
||||
|
@@ -178,6 +178,29 @@ static void print_rsl_cause(int lvl, const uint8_t *cause_v, uint8_t cause_len)
|
||||
LOGPC(DRSL, lvl, "%02x ", cause_v[i]);
|
||||
}
|
||||
|
||||
static void lchan_act_tmr_cb(void *data)
|
||||
{
|
||||
struct gsm_lchan *lchan = data;
|
||||
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s Timeout during activation!\n",
|
||||
gsm_lchan_name(lchan));
|
||||
|
||||
rsl_lchan_set_state(lchan, LCHAN_S_NONE);
|
||||
lchan_free(lchan);
|
||||
}
|
||||
|
||||
static void lchan_deact_tmr_cb(void *data)
|
||||
{
|
||||
struct gsm_lchan *lchan = data;
|
||||
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s Timeout during deactivation!\n",
|
||||
gsm_lchan_name(lchan));
|
||||
|
||||
rsl_lchan_set_state(lchan, LCHAN_S_NONE);
|
||||
lchan_free(lchan);
|
||||
}
|
||||
|
||||
|
||||
/* Send a BCCH_INFO message as per Chapter 8.5.1 */
|
||||
int rsl_bcch_info(struct gsm_bts_trx *trx, uint8_t type,
|
||||
const uint8_t *data, int len)
|
||||
@@ -609,6 +632,11 @@ static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error)
|
||||
msg->trx->bts->network->T3111 + 2, 0);
|
||||
}
|
||||
|
||||
/* Start another timer or assume the BTS sends a ACK/NACK? */
|
||||
lchan->act_timer.cb = lchan_deact_tmr_cb;
|
||||
lchan->act_timer.data = lchan;
|
||||
osmo_timer_schedule(&lchan->act_timer, 4, 0);
|
||||
|
||||
rc = abis_rsl_sendmsg(msg);
|
||||
|
||||
/* BTS will respond by RF CHAN REL ACK */
|
||||
@@ -626,6 +654,8 @@ static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan)
|
||||
|
||||
DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", gsm_lchan_name(lchan));
|
||||
|
||||
osmo_timer_del(&lchan->act_timer);
|
||||
|
||||
if (lchan->state != LCHAN_S_REL_REQ && lchan->state != LCHAN_S_REL_ERR)
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s CHAN REL ACK but state %s\n",
|
||||
gsm_lchan_name(lchan),
|
||||
@@ -791,6 +821,8 @@ static int rsl_rx_chan_act_ack(struct msgb *msg)
|
||||
if (rslh->ie_chan != RSL_IE_CHAN_NR)
|
||||
return -EINVAL;
|
||||
|
||||
osmo_timer_del(&msg->lchan->act_timer);
|
||||
|
||||
if (msg->lchan->state != LCHAN_S_ACT_REQ)
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK, but state %s\n",
|
||||
gsm_lchan_name(msg->lchan),
|
||||
@@ -815,7 +847,9 @@ static int rsl_rx_chan_act_nack(struct msgb *msg)
|
||||
struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);
|
||||
struct tlv_parsed tp;
|
||||
|
||||
LOGP(DRSL, LOGL_ERROR, "%s CHANNEL ACTIVATE NACK",
|
||||
osmo_timer_del(&msg->lchan->act_timer);
|
||||
|
||||
LOGP(DRSL, LOGL_ERROR, "%s CHANNEL ACTIVATE NACK ",
|
||||
gsm_lchan_name(msg->lchan));
|
||||
|
||||
/* BTS has rejected channel activation ?!? */
|
||||
@@ -829,6 +863,9 @@ static int rsl_rx_chan_act_nack(struct msgb *msg)
|
||||
TLVP_LEN(&tp, RSL_IE_CAUSE));
|
||||
if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC)
|
||||
rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
|
||||
else
|
||||
rsl_rf_chan_release(msg->lchan, 1);
|
||||
|
||||
} else
|
||||
rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
|
||||
|
||||
@@ -1108,6 +1145,12 @@ static int abis_rsl_rx_trx(struct msgb *msg)
|
||||
LOGP(DRSL, LOGL_ERROR, "%s CCCH/ACCH/CPU Overload\n",
|
||||
gsm_trx_name(msg->trx));
|
||||
break;
|
||||
case 0x42: /* Nokia specific: SI End ACK */
|
||||
LOGP(DRSL, LOGL_INFO, "Nokia SI End ACK\n");
|
||||
break;
|
||||
case 0x43: /* Nokia specific: SI End NACK */
|
||||
LOGP(DRSL, LOGL_INFO, "Nokia SI End NACK\n");
|
||||
break;
|
||||
default:
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s Unknown Abis RSL TRX message "
|
||||
"type 0x%02x\n", gsm_trx_name(msg->trx), rslh->msg_type);
|
||||
@@ -1251,7 +1294,11 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
|
||||
lchan->rsl_cmode = RSL_CMOD_SPD_SIGN;
|
||||
lchan->tch_mode = GSM48_CMODE_SIGN;
|
||||
|
||||
/* FIXME: Start another timer or assume the BTS sends a ACK/NACK? */
|
||||
/* Start another timer or assume the BTS sends a ACK/NACK? */
|
||||
lchan->act_timer.cb = lchan_act_tmr_cb;
|
||||
lchan->act_timer.data = lchan;
|
||||
osmo_timer_schedule(&lchan->act_timer, 4, 0);
|
||||
|
||||
rsl_chan_activate_lchan(lchan, 0x00, rqd_ta, 0);
|
||||
|
||||
DEBUGP(DRSL, "%s Activating ARFCN(%u) SS(%u) lctype %s "
|
||||
@@ -1892,3 +1939,50 @@ int rsl_sms_cb_command(struct gsm_bts *bts, uint8_t chan_number,
|
||||
|
||||
return abis_rsl_sendmsg(cb_cmd);
|
||||
}
|
||||
|
||||
int rsl_nokia_si_begin(struct gsm_bts_trx *trx)
|
||||
{
|
||||
struct abis_rsl_common_hdr *ch;
|
||||
struct msgb *msg = rsl_msgb_alloc();
|
||||
|
||||
ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch));
|
||||
ch->msg_discr = ABIS_RSL_MDISC_TRX;
|
||||
ch->msg_type = 0x40; /* Nokia SI Begin */
|
||||
|
||||
msg->trx = trx;
|
||||
|
||||
return abis_rsl_sendmsg(msg);
|
||||
}
|
||||
|
||||
int rsl_nokia_si_end(struct gsm_bts_trx *trx)
|
||||
{
|
||||
struct abis_rsl_common_hdr *ch;
|
||||
struct msgb *msg = rsl_msgb_alloc();
|
||||
|
||||
ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch));
|
||||
ch->msg_discr = ABIS_RSL_MDISC_TRX;
|
||||
ch->msg_type = 0x41; /* Nokia SI End */
|
||||
|
||||
msgb_tv_put(msg, 0xFD, 0x00); /* Nokia Pagemode Info, No paging reorganisation required */
|
||||
|
||||
msg->trx = trx;
|
||||
|
||||
return abis_rsl_sendmsg(msg);
|
||||
}
|
||||
|
||||
int rsl_bs_power_control(struct gsm_bts_trx *trx, uint8_t channel, uint8_t reduction)
|
||||
{
|
||||
struct abis_rsl_common_hdr *ch;
|
||||
struct msgb *msg = rsl_msgb_alloc();
|
||||
|
||||
ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch));
|
||||
ch->msg_discr = ABIS_RSL_MDISC_DED_CHAN;
|
||||
ch->msg_type = RSL_MT_BS_POWER_CONTROL;
|
||||
|
||||
msgb_tv_put(msg, RSL_IE_CHAN_NR, channel);
|
||||
msgb_tv_put(msg, RSL_IE_BS_POWER, reduction); /* reduction in 2dB steps */
|
||||
|
||||
msg->trx = trx;
|
||||
|
||||
return abis_rsl_sendmsg(msg);
|
||||
}
|
||||
|
@@ -137,7 +137,11 @@ static void assignment_t10_timeout(void *_conn)
|
||||
LOGP(DMSC, LOGL_ERROR, "Assigment T10 timeout on %p\n", conn);
|
||||
|
||||
/* normal release on the secondary channel */
|
||||
lchan_release(conn->secondary_lchan, 0, 1);
|
||||
if (conn->secondary_lchan) {
|
||||
lchan_release(conn->secondary_lchan, 0, 1);
|
||||
} else {
|
||||
LOGP(DMSC, LOGL_NOTICE, "Secondary lchan is NULL, not releasing\n");
|
||||
}
|
||||
conn->secondary_lchan = NULL;
|
||||
|
||||
/* inform them about the failure */
|
||||
@@ -367,7 +371,8 @@ static void handle_ass_compl(struct gsm_subscriber_connection *conn,
|
||||
if (is_ipaccess_bts(conn->bts) && conn->lchan->tch_mode != GSM48_CMODE_SIGN)
|
||||
rsl_ipacc_crcx(conn->lchan);
|
||||
|
||||
api->assign_compl(conn, gh->data[0],
|
||||
if (api->assign_compl)
|
||||
api->assign_compl(conn, gh->data[0],
|
||||
lchan_to_chosen_channel(conn->lchan),
|
||||
conn->lchan->encr.alg_id,
|
||||
chan_mode_to_speech(conn->lchan));
|
||||
|
@@ -249,8 +249,19 @@ static void bootstrap_rsl(struct gsm_bts_trx *trx)
|
||||
trx->bts->nr, trx->nr, trx->arfcn, bsc_gsmnet->country_code,
|
||||
bsc_gsmnet->network_code, trx->bts->location_area_code,
|
||||
trx->bts->cell_identity, trx->bts->bsic, trx->bts->tsc);
|
||||
|
||||
if (trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE) {
|
||||
rsl_nokia_si_begin(trx);
|
||||
}
|
||||
|
||||
set_system_infos(trx);
|
||||
|
||||
if (trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE) {
|
||||
/* channel unspecific, power reduction in 2 dB steps */
|
||||
rsl_bs_power_control(trx, 0xFF, trx->max_power_red / 2);
|
||||
rsl_nokia_si_end(trx);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(trx->ts); i++)
|
||||
generate_ma_for_ts(&trx->ts[i]);
|
||||
}
|
||||
@@ -268,6 +279,24 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
|
||||
|
||||
switch (signal) {
|
||||
case S_INP_TEI_UP:
|
||||
if (isd->link_type == E1INP_SIGN_OML) {
|
||||
/* TODO: this is required for the Nokia BTS, hopping is configured
|
||||
during OML, other MA is not set. */
|
||||
struct gsm_bts_trx *cur_trx;
|
||||
/* was static in system_information.c */
|
||||
extern int generate_cell_chan_list(uint8_t *chan_list, struct gsm_bts *bts);
|
||||
uint8_t ca[20];
|
||||
/* has to be called before generate_ma_for_ts to
|
||||
set bts->si_common.cell_alloc */
|
||||
generate_cell_chan_list(ca, trx->bts);
|
||||
|
||||
llist_for_each_entry(cur_trx, &trx->bts->trx_list, list) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cur_trx->ts); i++)
|
||||
generate_ma_for_ts(&cur_trx->ts[i]);
|
||||
}
|
||||
}
|
||||
if (isd->link_type == E1INP_SIGN_RSL)
|
||||
bootstrap_rsl(trx);
|
||||
break;
|
||||
|
@@ -942,7 +942,7 @@ static int lchan_summary(struct vty *vty, int argc, const char **argv,
|
||||
for (lchan_nr = 0; lchan_nr < TS_MAX_LCHAN;
|
||||
lchan_nr++) {
|
||||
lchan = &ts->lchan[lchan_nr];
|
||||
if (lchan->type == GSM_LCHAN_NONE)
|
||||
if ((lchan->type == GSM_LCHAN_NONE) && (lchan->state == LCHAN_S_NONE))
|
||||
continue;
|
||||
dump_cb(vty, lchan);
|
||||
}
|
||||
@@ -975,119 +975,6 @@ DEFUN(show_lchan_summary,
|
||||
return lchan_summary(vty, argc, argv, lchan_dump_short_vty);
|
||||
}
|
||||
|
||||
static void e1drv_dump_vty(struct vty *vty, struct e1inp_driver *drv)
|
||||
{
|
||||
vty_out(vty, "E1 Input Driver %s%s", drv->name, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
DEFUN(show_e1drv,
|
||||
show_e1drv_cmd,
|
||||
"show e1_driver",
|
||||
SHOW_STR "Display information about available E1 drivers\n")
|
||||
{
|
||||
struct e1inp_driver *drv;
|
||||
|
||||
llist_for_each_entry(drv, &e1inp_driver_list, list)
|
||||
e1drv_dump_vty(vty, drv);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void e1line_dump_vty(struct vty *vty, struct e1inp_line *line)
|
||||
{
|
||||
vty_out(vty, "E1 Line Number %u, Name %s, Driver %s%s",
|
||||
line->num, line->name ? line->name : "",
|
||||
line->driver->name, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
DEFUN(show_e1line,
|
||||
show_e1line_cmd,
|
||||
"show e1_line [line_nr]",
|
||||
SHOW_STR "Display information about a E1 line\n"
|
||||
"E1 Line Number\n")
|
||||
{
|
||||
struct e1inp_line *line;
|
||||
|
||||
if (argc >= 1) {
|
||||
int num = atoi(argv[0]);
|
||||
llist_for_each_entry(line, &e1inp_line_list, list) {
|
||||
if (line->num == num) {
|
||||
e1line_dump_vty(vty, line);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
}
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
llist_for_each_entry(line, &e1inp_line_list, list)
|
||||
e1line_dump_vty(vty, line);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void e1ts_dump_vty(struct vty *vty, struct e1inp_ts *ts)
|
||||
{
|
||||
if (ts->type == E1INP_TS_TYPE_NONE)
|
||||
return;
|
||||
vty_out(vty, "E1 Timeslot %2u of Line %u is Type %s%s",
|
||||
ts->num, ts->line->num, e1inp_tstype_name(ts->type),
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
DEFUN(show_e1ts,
|
||||
show_e1ts_cmd,
|
||||
"show e1_timeslot [line_nr] [ts_nr]",
|
||||
SHOW_STR "Display information about a E1 timeslot\n"
|
||||
"E1 Line Number\n" "E1 Timeslot Number\n")
|
||||
{
|
||||
struct e1inp_line *line = NULL;
|
||||
struct e1inp_ts *ts;
|
||||
int ts_nr;
|
||||
|
||||
if (argc == 0) {
|
||||
llist_for_each_entry(line, &e1inp_line_list, list) {
|
||||
for (ts_nr = 0; ts_nr < NUM_E1_TS; ts_nr++) {
|
||||
ts = &line->ts[ts_nr];
|
||||
e1ts_dump_vty(vty, ts);
|
||||
}
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
if (argc >= 1) {
|
||||
int num = atoi(argv[0]);
|
||||
struct e1inp_line *l;
|
||||
llist_for_each_entry(l, &e1inp_line_list, list) {
|
||||
if (l->num == num) {
|
||||
line = l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!line) {
|
||||
vty_out(vty, "E1 line %s is invalid%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
}
|
||||
if (argc >= 2) {
|
||||
ts_nr = atoi(argv[1]);
|
||||
if (ts_nr >= NUM_E1_TS) {
|
||||
vty_out(vty, "E1 timeslot %s is invalid%s",
|
||||
argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
ts = &line->ts[ts_nr];
|
||||
e1ts_dump_vty(vty, ts);
|
||||
return CMD_SUCCESS;
|
||||
} else {
|
||||
for (ts_nr = 0; ts_nr < NUM_E1_TS; ts_nr++) {
|
||||
ts = &line->ts[ts_nr];
|
||||
e1ts_dump_vty(vty, ts);
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void paging_dump_vty(struct vty *vty, struct gsm_paging_request *pag)
|
||||
{
|
||||
vty_out(vty, "Paging on BTS %u%s", pag->bts->nr, VTY_NEWLINE);
|
||||
@@ -2678,10 +2565,6 @@ int bsc_vty_init(const struct log_info *cat)
|
||||
install_element_ve(&show_lchan_summary_cmd);
|
||||
install_element_ve(&logging_fltr_imsi_cmd);
|
||||
|
||||
install_element_ve(&show_e1drv_cmd);
|
||||
install_element_ve(&show_e1line_cmd);
|
||||
install_element_ve(&show_e1ts_cmd);
|
||||
|
||||
install_element_ve(&show_paging_cmd);
|
||||
|
||||
logging_vty_add_cmds(cat);
|
||||
|
@@ -24,6 +24,7 @@ int bts_init(void)
|
||||
bts_model_rbs2k_init();
|
||||
bts_model_nanobts_init();
|
||||
bts_model_hslfemto_init();
|
||||
bts_model_nokia_site_init();
|
||||
/* Your new BTS here. */
|
||||
return 0;
|
||||
}
|
||||
|
1727
openbsc/src/libbsc/bts_nokia_site.c
Normal file
1727
openbsc/src/libbsc/bts_nokia_site.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -299,6 +299,10 @@ void lchan_free(struct gsm_lchan *lchan)
|
||||
sig.type = lchan->type;
|
||||
lchan->type = GSM_LCHAN_NONE;
|
||||
|
||||
if (lchan->state != LCHAN_S_NONE) {
|
||||
LOGP(DRLL, LOGL_NOTICE, "Freeing lchan with state %s - setting to NONE\n", gsm_lchans_name(lchan->state));
|
||||
lchan->state = LCHAN_S_NONE;
|
||||
}
|
||||
|
||||
if (lchan->conn) {
|
||||
struct lchan_signal_data sig;
|
||||
|
@@ -154,7 +154,7 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv,
|
||||
}
|
||||
|
||||
/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */
|
||||
static int generate_cell_chan_list(uint8_t *chan_list, struct gsm_bts *bts)
|
||||
/* static*/ int generate_cell_chan_list(uint8_t *chan_list, struct gsm_bts *bts)
|
||||
{
|
||||
struct gsm_bts_trx *trx;
|
||||
struct bitvec *bv = &bts->si_common.cell_alloc;
|
||||
|
@@ -193,6 +193,7 @@ static const struct value_string bts_types[] = {
|
||||
{ GSM_BTS_TYPE_NANOBTS, "nanobts" },
|
||||
{ GSM_BTS_TYPE_RBS2000, "rbs2000" },
|
||||
{ GSM_BTS_TYPE_HSL_FEMTO, "hsl_femto" },
|
||||
{ GSM_BTS_TYPE_NOKIA_SITE, "nokia_site" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
@@ -1602,7 +1602,7 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
|
||||
remote_bts->nr, remote_lchan->ts->trx->nr, remote_lchan->ts->nr);
|
||||
|
||||
if (bts->type != remote_bts->type) {
|
||||
DEBUGP(DCC, "Cannot switch calls between different BTS types yet\n");
|
||||
LOGP(DCC, LOGL_ERROR, "Cannot switch calls between different BTS types yet\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1634,10 +1634,11 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
|
||||
break;
|
||||
case GSM_BTS_TYPE_BS11:
|
||||
case GSM_BTS_TYPE_RBS2000:
|
||||
case GSM_BTS_TYPE_NOKIA_SITE:
|
||||
trau_mux_map_lchan(lchan, remote_lchan);
|
||||
break;
|
||||
default:
|
||||
DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
|
||||
LOGP(DCC, LOGL_ERROR, "Unknown BTS type %u\n", bts->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1680,7 +1681,7 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable)
|
||||
switch (bts->type) {
|
||||
case GSM_BTS_TYPE_NANOBTS:
|
||||
if (ipacc_rtp_direct) {
|
||||
DEBUGP(DCC, "Error: RTP proxy is disabled\n");
|
||||
LOGP(DCC, LOGL_ERROR, "Error: RTP proxy is disabled\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
/* in case, we don't have a RTP socket yet, we note this
|
||||
@@ -1704,12 +1705,13 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable)
|
||||
break;
|
||||
case GSM_BTS_TYPE_BS11:
|
||||
case GSM_BTS_TYPE_RBS2000:
|
||||
case GSM_BTS_TYPE_NOKIA_SITE:
|
||||
if (enable)
|
||||
return trau_recv_lchan(lchan, callref);
|
||||
return trau_mux_unmap(NULL, callref);
|
||||
break;
|
||||
default:
|
||||
DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
|
||||
LOGP(DCC, LOGL_ERROR, "Unknown BTS type %u\n", bts->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -2989,9 +2991,10 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
|
||||
return rtp_send_frame(trans->conn->lchan->abis_ip.rtp_socket, arg);
|
||||
case GSM_BTS_TYPE_BS11:
|
||||
case GSM_BTS_TYPE_RBS2000:
|
||||
case GSM_BTS_TYPE_NOKIA_SITE:
|
||||
return trau_send_frame(trans->conn->lchan, arg);
|
||||
default:
|
||||
DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
|
||||
LOGP(DCC, LOGL_ERROR, "Unknown BTS type %u\n", bts->type);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@@ -165,6 +165,13 @@ static int mncc_sock_write(struct osmo_fd *bfd)
|
||||
|
||||
bfd->when &= ~BSC_FD_WRITE;
|
||||
|
||||
/* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
|
||||
if (!msgb_length(msg)) {
|
||||
LOGP(DMNCC, LOGL_ERROR, "message type (%d) with ZERO "
|
||||
"bytes!\n", mncc_prim->msg_type);
|
||||
goto dontsend;
|
||||
}
|
||||
|
||||
/* try to send it over the socket */
|
||||
rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
|
||||
if (rc == 0)
|
||||
@@ -176,6 +183,8 @@ static int mncc_sock_write(struct osmo_fd *bfd)
|
||||
}
|
||||
goto close;
|
||||
}
|
||||
|
||||
dontsend:
|
||||
/* _after_ we send it, we can deueue */
|
||||
msg2 = msgb_dequeue(&net->upqueue);
|
||||
assert(msg == msg2);
|
||||
|
@@ -214,6 +214,7 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
|
||||
}
|
||||
frame->msg_type = GSM_TCHF_FRAME;
|
||||
frame->callref = ue->callref;
|
||||
msgb_put(msg, sizeof(struct gsm_data_frame) + 33);
|
||||
trau_tx_to_mncc(ue->net, msg);
|
||||
|
||||
return 0;
|
||||
|
Reference in New Issue
Block a user