aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2009-08-06 19:20:38 +0200
committerHarald Welte <laforge@gnumonks.org>2009-08-06 19:20:38 +0200
commitb90288c8caba5cc77c26332650a5739ac9cf2e86 (patch)
treedd78038f9437c1875cf0fe38f074c975fc173c67
parente211da49b98162cbf9653da7b80e30634f2b1637 (diff)
parent67ce073110b390997fd08c69b44c6b5d9f6a3cef (diff)
Merge branch 'master' into proxyproxy
-rw-r--r--openbsc/include/openbsc/Makefile.am2
-rw-r--r--openbsc/include/openbsc/abis_nm.h9
-rw-r--r--openbsc/include/openbsc/abis_rsl.h16
-rw-r--r--openbsc/include/openbsc/gsm_04_08.h46
-rw-r--r--openbsc/include/openbsc/gsm_data.h12
-rw-r--r--openbsc/include/openbsc/mncc.h13
-rw-r--r--openbsc/include/openbsc/rtp_proxy.h70
-rw-r--r--openbsc/src/Makefile.am2
-rw-r--r--openbsc/src/abis_nm.c70
-rw-r--r--openbsc/src/abis_rsl.c175
-rw-r--r--openbsc/src/bsc_hack.c195
-rw-r--r--openbsc/src/chan_alloc.c42
-rw-r--r--openbsc/src/e1_config.c85
-rw-r--r--openbsc/src/gsm_04_08.c158
-rw-r--r--openbsc/src/gsm_data.c14
-rw-r--r--openbsc/src/input/misdn.c18
-rw-r--r--openbsc/src/rtp_proxy.c446
-rw-r--r--openbsc/src/vty/command.c16
-rw-r--r--openbsc/src/vty_interface.c53
-rw-r--r--openbsc/tests/db/db_test.c12
20 files changed, 1202 insertions, 252 deletions
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index 86f056d26..adef573e5 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -2,4 +2,4 @@ noinst_HEADERS = abis_nm.h abis_rsl.h debug.h db.h gsm_04_08.h gsm_data.h \
gsm_subscriber.h linuxlist.h msgb.h select.h tlv.h gsm_04_11.h \
timer.h misdn.h chan_alloc.h telnet_interface.h paging.h \
subchan_demux.h trau_frame.h e1_input.h trau_mux.h signal.h \
- gsm_utils.h ipaccess.h rs232.h openbscdefines.h
+ gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h
diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h
index 47baafb55..3dc553144 100644
--- a/openbsc/include/openbsc/abis_nm.h
+++ b/openbsc/include/openbsc/abis_nm.h
@@ -482,6 +482,12 @@ enum abis_nm_chan_comb {
NM_CHANC_BCCH = 0x06,
NM_CHANC_BCCH_CBCH = 0x07,
NM_CHANC_SDCCH_CBCH = 0x08,
+ /* ip.access */
+ NM_CHANC_IPAC_bPDCH = 0x0b, /* PBCCH + PCCCH + PDTCH/F + PACCH/F + PTCCH/F */
+ NM_CHANC_IPAC_cPDCH = 0x0c, /* PBCCH + PDTCH/F + PACCH/F + PTCCH/F */
+ NM_CHANC_IPAC_PDCH = 0x0d, /* PDTCH/F + PACCH/F + PTCCH/F */
+ NM_CHANC_IPAC_TCHFull_PDCH = 0x80,
+ NM_CHANC_IPAC_TCHFull_TCHHalf = 0x81,
};
/* Section 9.4.16: Event Type */
@@ -672,6 +678,9 @@ int abis_nm_software_load_status(struct gsm_bts *bts);
int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
gsm_cbfn *cbfn, void *cb_data);
+int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
+ u_int8_t e1_port1, u_int8_t ts1);
+
/* Siemens / BS-11 specific */
int abis_nm_bs11_reset_resource(struct gsm_bts *bts);
int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin);
diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h
index 9e4d59078..201c77fbc 100644
--- a/openbsc/include/openbsc/abis_rsl.h
+++ b/openbsc/include/openbsc/abis_rsl.h
@@ -266,16 +266,23 @@ struct rsl_ie_chan_mode {
} __attribute__ ((packed));
#define RSL_CMOD_DTXu 0x01 /* uplink */
#define RSL_CMOD_DTXd 0x02 /* downlink */
-#define RSL_CMOD_SPD_SPEECH 0x01
-#define RSL_CMOD_SPD_DATA 0x02
-#define RSL_CMOD_SPD_SIGN 0x03
+enum rsl_cmod_spd {
+ RSL_CMOD_SPD_SPEECH = 0x01,
+ RSL_CMOD_SPD_DATA = 0x02,
+ RSL_CMOD_SPD_SIGN = 0x03,
+};
#define RSL_CMOD_CRT_SDCCH 0x01
#define RSL_CMOD_CRT_TCH_Bm 0x08 /* full-rate */
#define RSL_CMOD_CRT_TCH_Lm 0x09 /* half-rate */
/* FIXME: More CRT types */
+/* Speech */
#define RSL_CMOD_SP_GSM1 0x01
#define RSL_CMOD_SP_GSM2 0x11
#define RSL_CMOD_SP_GSM3 0x21
+/* Data */
+#define RSL_CMOD_SP_NT_14k5 0x58
+#define RSL_CMOD_SP_NT_12k0 0x50
+#define RSL_CMOD_SP_NT_6k0 0x51
/* Chapter 9.3.5 */
struct rsl_ie_chan_ident {
@@ -326,6 +333,7 @@ struct rsl_ie_chan_ident {
#define RSL_ERR_TALKER_ACC_FAIL 0x03
#define RSL_ERR_OM_INTERVENTION 0x07
#define RSL_ERR_NORMAL_UNSPEC 0x0f
+#define RSL_ERR_T_MSRFPCI_EXP 0x18
/* resource unavailable */
#define RSL_ERR_EQUIPMENT_FAIL 0x20
#define RSL_ERR_RR_UNAVAIL 0x21
@@ -459,7 +467,7 @@ int rsl_chan_activate(struct gsm_bts_trx *trx, u_int8_t chan_nr,
u_int8_t bs_power, u_int8_t ms_power,
u_int8_t ta);
int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
- u_int8_t ta, u_int8_t mode);
+ u_int8_t ta);
int rsl_chan_mode_modify_req(struct gsm_lchan *ts);
int rsl_paging_cmd(struct gsm_bts *bts, u_int8_t paging_group, u_int8_t len,
u_int8_t *ms_ident, u_int8_t chan_needed);
diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index 2ed95f326..c93540b14 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -48,14 +48,16 @@ struct gsm48_chan_mode_modify {
u_int8_t mode;
} __attribute__ ((packed));
-#define GSM48_CMODE_SIGN 0x00
-#define GSM48_CMODE_SPEECH_V1 0x01
-#define GSM48_CMODE_SPEECH_EFR 0x21
-#define GSM48_CMODE_SPEECH_AMR 0x41
-#define GSM48_CMODE_DATA_14k5 0x0f
-#define GSM48_CMODE_DATA_12k0 0x03
-#define GSM48_CMODE_DATA_6k0 0x0b
-#define GSM48_CMODE_DATA_3k6 0x23
+enum gsm48_chan_mode {
+ GSM48_CMODE_SIGN = 0x00,
+ GSM48_CMODE_SPEECH_V1 = 0x01,
+ GSM48_CMODE_SPEECH_EFR = 0x21,
+ GSM48_CMODE_SPEECH_AMR = 0x41,
+ GSM48_CMODE_DATA_14k5 = 0x0f,
+ GSM48_CMODE_DATA_12k0 = 0x03,
+ GSM48_CMODE_DATA_6k0 = 0x0b,
+ GSM48_CMODE_DATA_3k6 = 0x23,
+};
/* Chapter 9.1.18 */
struct gsm48_imm_ass {
@@ -642,6 +644,34 @@ enum chreq_type {
#define SBIT(a) (1 << a)
#define ALL_STATES 0xffffffff
+/* GSM 04.08 Bearer Capability: Information Transfer Capability */
+enum gsm48_bcap_itcap {
+ GSM48_BCAP_ITCAP_SPEECH = 0,
+ GSM48_BCAP_ITCAP_UNR_DIG_INF = 1,
+ GSM48_BCAP_ITCAP_3k1_AUDIO = 2,
+ GSM48_BCAP_ITCAP_FAX_G3 = 3,
+ GSM48_BCAP_ITCAP_OTHER = 5,
+ GSM48_BCAP_ITCAP_RESERVED = 7,
+};
+
+/* GSM 04.08 Bearer Capability: Transfer Mode */
+enum gsm48_bcap_tmod {
+ GSM48_BCAP_TMOD_CIRCUIT = 0,
+ GSM48_BCAP_TMOD_PACKET = 1,
+};
+
+/* GSM 04.08 Bearer Capability: Coding Standard */
+enum gsm48_bcap_coding {
+ GSM48_BCAP_CODING_GSM_STD = 0,
+};
+
+/* GSM 04.08 Bearer Capability: Radio Channel Requirements */
+enum gsm48_bcap_rrq {
+ GSM48_BCAP_RRQ_FR_ONLY = 1,
+ GSM48_BCAP_RRQ_DUAL_HR = 2,
+ GSM48_BCAP_RRQ_DUAL_FR = 3,
+};
+
struct msgb;
struct gsm_bts;
struct gsm_subscriber;
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 5eac8a7d1..700eb73fa 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -41,6 +41,7 @@ enum gsm_chreq_reason_t {
#include <openbsc/timer.h>
#include <openbsc/gsm_04_08.h>
+#include <openbsc/abis_rsl.h>
#include <openbsc/mncc.h>
#include <openbsc/tlv.h>
@@ -53,6 +54,11 @@ enum gsm_chreq_reason_t {
#define HARDCODED_TSC 7
#define HARDCODED_BSIC 0x3f /* NCC = 7 / BCC = 7 */
+/* for multi-drop config */
+#define HARDCODED_BTS0_TS 1
+#define HARDCODED_BTS1_TS 6
+#define HARDCODED_BTS2_TS 11
+
enum gsm_hooks {
GSM_HOOK_NM_SWLOAD,
GSM_HOOK_RR_PAGING,
@@ -98,6 +104,7 @@ struct gsm_bts_link {
struct gsm_lchan;
struct gsm_subscriber;
struct gsm_mncc;
+struct rtp_socket;
/* One transaction */
struct gsm_trans {
@@ -164,8 +171,10 @@ struct gsm_lchan {
u_int8_t nr;
/* The logical channel type */
enum gsm_chan_t type;
+ /* RSL channel mode */
+ enum rsl_cmod_spd rsl_cmode;
/* If TCH, traffic channel mode */
- enum gsm_chan_t tch_mode;
+ enum gsm48_chan_mode tch_mode;
/* Power levels for MS and BTS */
u_int8_t bs_power;
u_int8_t ms_power;
@@ -214,6 +223,7 @@ struct gsm_bts_trx_ts {
u_int16_t bound_port;
u_int8_t rtp_payload2;
u_int16_t conn_id;
+ struct rtp_socket *rtp_socket;
} abis_ip;
struct gsm_lchan lchan[TS_MAX_LCHAN];
diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h
index 6aa191703..68d76abf8 100644
--- a/openbsc/include/openbsc/mncc.h
+++ b/openbsc/include/openbsc/mncc.h
@@ -108,13 +108,14 @@ struct gsm_call {
#define MNCC_F_KEYPAD 0x1000
#define MNCC_F_SIGNAL 0x2000
+/* Expanded fields from GSM TS 04.08, Table 10.5.102 */
struct gsm_mncc_bearer_cap {
- int transfer;
- int mode;
- int coding;
- int radio;
- int speech_ctm;
- int speech_ver[8];
+ int transfer; /* Information Transfer Capability */
+ int mode; /* Transfer Mode */
+ int coding; /* Coding Standard */
+ int radio; /* Radio Channel Requirement */
+ int speech_ctm; /* CTM text telephony indication */
+ int speech_ver[8]; /* Speech version indication */
};
struct gsm_mncc_number {
diff --git a/openbsc/include/openbsc/rtp_proxy.h b/openbsc/include/openbsc/rtp_proxy.h
new file mode 100644
index 000000000..e9fc157cf
--- /dev/null
+++ b/openbsc/include/openbsc/rtp_proxy.h
@@ -0,0 +1,70 @@
+#ifndef _RTP_PROXY_H
+#define _RTP_PROXY_H
+
+/* RTP proxy handling for ip.access nanoBTS */
+
+/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+
+#include <netinet/in.h>
+
+#include <openbsc/linuxlist.h>
+#include <openbsc/select.h>
+
+enum rtp_rx_action {
+ RTP_NONE,
+ RTP_PROXY,
+ RTP_RECV_UPSTREAM,
+};
+
+struct rtp_sub_socket {
+ struct sockaddr_in sin_local;
+ struct sockaddr_in sin_remote;
+
+ struct bsc_fd bfd;
+ /* linked list of to-be-transmitted msgb's */
+ struct llist_head tx_queue;
+};
+
+struct rtp_socket {
+ struct llist_head list;
+
+ struct rtp_sub_socket rtp;
+ struct rtp_sub_socket rtcp;
+
+ /* what should we do on receive? */
+ enum rtp_rx_action rx_action;
+ union {
+ struct {
+ struct rtp_socket *other_sock;
+ } proxy;
+ struct {
+ void (*recv_cb)(struct msgb *msg);
+ } receive;
+ };
+};
+
+struct rtp_socket *rtp_socket_create(void);
+int rtp_socket_bind(struct rtp_socket *rs, u_int32_t ip);
+int rtp_socket_connect(struct rtp_socket *rs, u_int32_t ip, u_int16_t port);
+int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other);
+int rtp_socket_free(struct rtp_socket *rs);
+
+#endif /* _RTP_PROXY_H */
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index df34eb5eb..5ed5d8c44 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -12,7 +12,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_04_08.c gsm_data.c mncc.c \
gsm_04_11.c telnet_interface.c subchan_demux.c \
trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \
input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \
- transaction.c
+ transaction.c rtp_proxy.c
libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c
diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c
index dec4b2957..0eb8657db 100644
--- a/openbsc/src/abis_nm.c
+++ b/openbsc/src/abis_nm.c
@@ -357,18 +357,47 @@ static const struct tlv_definition nm_att_tlvdef = {
/* ip.access specifics */
[NM_ATT_IPACC_DST_IP] = { TLV_TYPE_FIXED, 4 },
[NM_ATT_IPACC_DST_IP_PORT] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_NV_FLAGS] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_STREAM_ID] = { TLV_TYPE_TV, },
+ [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_TV, },
[NM_ATT_IPACC_SEC_OML_CFG] = { TLV_TYPE_FIXED, 6 },
[NM_ATT_IPACC_IP_IF_CFG] = { TLV_TYPE_FIXED, 8 },
[NM_ATT_IPACC_IP_GW_CFG] = { TLV_TYPE_FIXED, 12 },
+ [NM_ATT_IPACC_IN_SERV_TIME] = { TLV_TYPE_FIXED, 4 },
[NM_ATT_IPACC_LOCATION] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_PAGING_CFG] = { TLV_TYPE_FIXED, 2 },
[NM_ATT_IPACC_UNIT_ID] = { TLV_TYPE_TL16V },
[NM_ATT_IPACC_UNIT_NAME] = { TLV_TYPE_TL16V },
[NM_ATT_IPACC_SNMP_CFG] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_NV_FLAGS] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_FIXED, 2 },
+ [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_CUR_SW_CFG] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_TIMING_BUS] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_CGI] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_RAC] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_OBJ_VERSION] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_GPRS_PAGING_CFG]= { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_NSEI] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_BVCI] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_NSVCI] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_NS_CFG] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_BSSGP_CFG] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_NS_LINK_CFG] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_RLC_CFG] = { TLV_TYPE_TL16V },
[NM_ATT_IPACC_ALM_THRESH_LIST]= { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_MONIT_VAL_LIST] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_TIB_CONTROL] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_SUPP_FEATURES] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_CODING_SCHEMES] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_RLC_CFG_2] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_HEARTB_TOUT] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_UPTIME] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_RLC_CFG_3] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_SSL_CFG] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_SEC_POSSIBLE] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_IML_SSL_STATE] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_REVOC_DATE] = { TLV_TYPE_TL16V },
//[0x95] = { TLV_TYPE_FIXED, 2 },
[0x85] = { TLV_TYPE_TV },
@@ -937,6 +966,9 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb)
case NM_MT_BS11_LMT_SESSION:
return abis_nm_rx_lmt_event(mb);
break;
+ case NM_MT_CONN_MDROP_LINK_ACK:
+ DEBUGP(DNM, "CONN MDROP LINK ACK\n");
+ break;
}
return 0;
@@ -1731,6 +1763,32 @@ int abis_nm_chg_adm_state(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0,
return abis_nm_sendmsg(bts, msg);
}
+int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
+ u_int8_t e1_port1, u_int8_t ts1)
+{
+ struct abis_om_hdr *oh;
+ struct msgb *msg = nm_msgb_alloc();
+ u_int8_t *attr;
+
+ DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
+ e1_port0, ts0, e1_port1, ts1);
+
+ oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
+ fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
+ NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
+
+ attr = msgb_put(msg, 3);
+ attr[0] = NM_ATT_MDROP_LINK;
+ attr[1] = e1_port0;
+ attr[2] = ts0;
+
+ attr = msgb_put(msg, 3);
+ attr[0] = NM_ATT_MDROP_NEXT;
+ attr[1] = e1_port1;
+ attr[2] = ts1;
+
+ return abis_nm_sendmsg(bts, msg);
+}
int abis_nm_event_reports(struct gsm_bts *bts, int on)
{
@@ -2121,7 +2179,7 @@ static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
bs11_sw->win_size,
bs11_sw->forced,
&bs11_swload_cbfn, bs11_sw);
- free(fle);
+ talloc_free(fle);
} else {
/* activate the SWL */
rc = abis_nm_software_activate(bs11_sw->bts,
@@ -2175,7 +2233,7 @@ int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
/* start download the next file of our file list */
rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
bs11_swload_cbfn, bs11_sw);
- free(fle);
+ talloc_free(fle);
return rc;
}
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index 56c3f711b..1a2c58b16 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -321,6 +321,7 @@ static const char *rsl_err_vals[0xff] = {
[RSL_ERR_TALKER_ACC_FAIL] = "Talker Access Failure",
[RSL_ERR_OM_INTERVENTION] = "O&M Intervention",
[RSL_ERR_NORMAL_UNSPEC] = "Normal event, unspecified",
+ [RSL_ERR_T_MSRFPCI_EXP] = "Siemens: T_MSRFPCI Expired",
[RSL_ERR_EQUIPMENT_FAIL] = "Equipment Failure",
[RSL_ERR_RR_UNAVAIL] = "Radio Resource not available",
[RSL_ERR_TERR_CH_FAIL] = "Terrestrial Channel Failure",
@@ -530,6 +531,62 @@ int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int dbm)
return abis_rsl_sendmsg(msg);
}
+static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm,
+ struct gsm_lchan *lchan)
+{
+ memset(cm, 0, sizeof(cm));
+
+ /* FIXME: what to do with data calls ? */
+ cm->dtx_dtu = 0x00;
+
+ /* set TCH Speech/Data */
+ cm->spd_ind = lchan->rsl_cmode;
+
+ switch (lchan->type) {
+ case GSM_LCHAN_SDCCH:
+ cm->chan_rt = RSL_CMOD_CRT_SDCCH;
+ break;
+ case GSM_LCHAN_TCH_F:
+ cm->chan_rt = RSL_CMOD_CRT_TCH_Bm;
+ break;
+ case GSM_LCHAN_TCH_H:
+ cm->chan_rt = RSL_CMOD_CRT_TCH_Lm;
+ break;
+ case GSM_LCHAN_NONE:
+ case GSM_LCHAN_UNKNOWN:
+ default:
+ return -EINVAL;
+ }
+
+ switch (lchan->tch_mode) {
+ case GSM48_CMODE_SIGN:
+ cm->chan_rate = 0;
+ break;
+ case GSM48_CMODE_SPEECH_V1:
+ cm->chan_rate = RSL_CMOD_SP_GSM1;
+ break;
+ case GSM48_CMODE_SPEECH_EFR:
+ cm->chan_rate = RSL_CMOD_SP_GSM2;
+ break;
+ case GSM48_CMODE_SPEECH_AMR:
+ cm->chan_rate = RSL_CMOD_SP_GSM3;
+ break;
+ case GSM48_CMODE_DATA_14k5:
+ cm->chan_rate = RSL_CMOD_SP_NT_14k5;
+ break;
+ case GSM48_CMODE_DATA_12k0:
+ cm->chan_rate = RSL_CMOD_SP_NT_12k0;
+ break;
+ case GSM48_CMODE_DATA_6k0:
+ cm->chan_rate = RSL_CMOD_SP_NT_6k0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/* Chapter 8.4.1 */
#if 0
int rsl_chan_activate(struct gsm_bts_trx *trx, u_int8_t chan_nr,
@@ -567,45 +624,20 @@ int rsl_chan_activate(struct gsm_bts_trx *trx, u_int8_t chan_nr,
#endif
int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
- u_int8_t ta, u_int8_t mode)
+ u_int8_t ta)
{
struct abis_rsl_dchan_hdr *dh;
struct msgb *msg;
+ int rc;
u_int8_t chan_nr = lchan2chan_nr(lchan);
u_int16_t arfcn = lchan->ts->trx->arfcn;
struct rsl_ie_chan_mode cm;
struct rsl_ie_chan_ident ci;
- memset(&cm, 0, sizeof(cm));
- /* FIXME: what to do with data calls ? */
- cm.dtx_dtu = 0x00;
- switch (lchan->type) {
- case GSM_LCHAN_SDCCH:
- cm.spd_ind = RSL_CMOD_SPD_SIGN;
- cm.chan_rt = RSL_CMOD_CRT_SDCCH;
- cm.chan_rate = 0x00;
- break;
- case GSM_LCHAN_TCH_F:
- cm.chan_rt = RSL_CMOD_CRT_TCH_Bm;
- switch (mode) {
- case RSL_CMOD_SPD_SIGN:
- cm.spd_ind = RSL_CMOD_SPD_SIGN;
- cm.chan_rate = 0x00;
- break;
- case RSL_CMOD_SPD_SPEECH:
- cm.spd_ind = RSL_CMOD_SPD_SPEECH;
- cm.chan_rate = RSL_CMOD_SP_GSM2;
- break;
- }
- break;
- case GSM_LCHAN_TCH_H:
- DEBUGP(DRSL, "Unimplemented TCH_H activation\n");
- return -1;
- case GSM_LCHAN_UNKNOWN:
- case GSM_LCHAN_NONE:
- return -1;
- }
+ rc = channel_mode_from_lchan(&cm, lchan);
+ if (rc < 0)
+ return rc;
memset(&ci, 0, sizeof(ci));
ci.chan_desc.iei = 0x64;
@@ -637,40 +669,19 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
return abis_rsl_sendmsg(msg);
}
-/* Chapter 8.4.9 */
+/* Chapter 8.4.9: Modify channel mode on BTS side */
int rsl_chan_mode_modify_req(struct gsm_lchan *lchan)
{
struct abis_rsl_dchan_hdr *dh;
struct msgb *msg;
+ int rc;
u_int8_t chan_nr = lchan2chan_nr(lchan);
struct rsl_ie_chan_mode cm;
- memset(&cm, 0, sizeof(cm));
-
- /* FIXME: what to do with data calls ? */
- cm.dtx_dtu = 0x00;
- switch (lchan->type) {
- /* todo more modes */
- case GSM_LCHAN_TCH_F:
- cm.spd_ind = RSL_CMOD_SPD_SPEECH;
- cm.chan_rt = RSL_CMOD_CRT_TCH_Bm;
- switch(lchan->tch_mode) {
- case GSM48_CMODE_SPEECH_V1:
- cm.chan_rate = RSL_CMOD_SP_GSM1;
- break;
- case GSM48_CMODE_SPEECH_EFR:
- cm.chan_rate = RSL_CMOD_SP_GSM2;
- break;
- default:
- DEBUGP(DRSL, "Unimplemented channel modification\n");
- return -1;
- }
- break;
- default:
- DEBUGP(DRSL, "Unimplemented channel modification\n");
- return -1;
- }
+ rc = channel_mode_from_lchan(&cm, lchan);
+ if (rc < 0)
+ return rc;
msg = rsl_msgb_alloc();
dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
@@ -1079,8 +1090,10 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
arfcn = lchan->ts->trx->arfcn;
subch = lchan->nr;
- lchan->ms_power = lchan->bs_power = 0x0f; /* 30dB reduction */
- rsl_chan_activate_lchan(lchan, 0x00, rqd_ta, RSL_CMOD_SPD_SIGN);
+ lchan->ms_power = ms_pwr_ctl_lvl(bts, 20 /* dBm == 100mW */);
+ lchan->bs_power = 0x0f; /* 30dB reduction */
+ lchan->rsl_cmode = RSL_CMOD_SPD_SIGN;
+ rsl_chan_activate_lchan(lchan, 0x00, rqd_ta);
/* create IMMEDIATE ASSIGN 04.08 messge */
memset(&ia, 0, sizeof(ia));
@@ -1177,7 +1190,7 @@ static int rsl_rx_rll_err_ind(struct msgb *msg)
struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
u_int8_t *rlm_cause = rllh->data;
- DEBUGPC(DRLL, "cause=0x%02x", rlm_cause[1]);
+ DEBUGPC(DRLL, "ERROR INDICATION cause=0x%02x\n", rlm_cause[1]);
if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED)
return rsl_chan_release(msg->lchan);
@@ -1221,30 +1234,27 @@ static int abis_rsl_rx_rll(struct msgb *msg)
}
break;
case RSL_MT_REL_IND:
- DEBUGPC(DRLL, "RELEASE INDICATION ");
+ DEBUGPC(DRLL, "RELEASE INDICATION\n");
break;
case RSL_MT_REL_CONF:
- DEBUGPC(DRLL, "RELEASE CONFIRMATION ");
+ DEBUGPC(DRLL, "RELEASE CONFIRMATION\n");
break;
case RSL_MT_ERROR_IND:
- DEBUGPC(DRLL, "ERROR INDICATION ");
rc = rsl_rx_rll_err_ind(msg);
break;
case RSL_MT_UNIT_DATA_IND:
- DEBUGPC(DRLL, "unimplemented Abis RLL message type 0x%02x ",
+ DEBUGPC(DRLL, "unimplemented Abis RLL message type 0x%02x\n",
rllh->c.msg_type);
break;
default:
- DEBUGPC(DRLL, "unknown Abis RLL message type 0x%02x ",
+ DEBUGPC(DRLL, "unknown Abis RLL message type 0x%02x\n",
rllh->c.msg_type);
}
- DEBUGPC(DRLL, "\n");
return rc;
}
static u_int8_t ipa_smod_s_for_tch_mode(u_int8_t tch_mode)
{
-#if 0
switch (tch_mode) {
case GSM48_CMODE_SPEECH_V1:
return 0x00;
@@ -1254,12 +1264,9 @@ static u_int8_t ipa_smod_s_for_tch_mode(u_int8_t tch_mode)
return 0x02;
/* FIXME: Type1 half-rate and type3 half-rate */
}
+ DEBUGPC(DRSL, "Cannot determine ip.access speech mode for "
+ "tch_mode == 0x%02x\n", tch_mode);
return 0;
-#else
- /* hard-code EFR for now, since tch_mode is not correct at this
- * point in time */
- return 0x01;
-#endif
}
/* ip.access specific RSL extensions */
@@ -1267,19 +1274,20 @@ int rsl_ipacc_bind(struct gsm_lchan *lchan)
{
struct msgb *msg = rsl_msgb_alloc();
struct abis_rsl_dchan_hdr *dh;
- u_int8_t speech_mode_s;
+ u_int8_t speech_mode;
dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
init_dchan_hdr(dh, RSL_MT_IPAC_BIND);
dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS;
dh->chan_nr = lchan2chan_nr(lchan);
- speech_mode_s = ipa_smod_s_for_tch_mode(lchan->tch_mode);
/* 0x1- == receive-only, 0x-1 == EFR codec */
- msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, 0x10 | speech_mode_s);
+ speech_mode = 0x10 | ipa_smod_s_for_tch_mode(lchan->tch_mode);
+ msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, speech_mode);
- DEBUGPC(DRSL, "channel=%s chan_nr=0x%02x IPAC_BIND\n",
- gsm_ts_name(lchan->ts), dh->chan_nr);
+ DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_BIND "
+ "speech_mode=0x%02x\n", gsm_ts_name(lchan->ts),
+ dh->chan_nr, speech_mode);
msg->trx = lchan->ts->trx;
@@ -1292,7 +1300,7 @@ int rsl_ipacc_connect(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port,
struct msgb *msg = rsl_msgb_alloc();
struct abis_rsl_dchan_hdr *dh;
u_int8_t *att_f8, *att_ip, *att_port;
- u_int8_t speech_mode_s;
+ u_int8_t speech_mode;
struct in_addr ia;
dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
@@ -1300,11 +1308,14 @@ int rsl_ipacc_connect(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port,
dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS;
dh->chan_nr = lchan2chan_nr(lchan);
+ /* 0x0- == both directions, 0x-1 == EFR codec */
+ speech_mode = 0x00 | ipa_smod_s_for_tch_mode(lchan->tch_mode);
+
ia.s_addr = htonl(ip);
- DEBUGP(DRSL, "IPAC_CONNECT channel=%s chan_nr=0x%02x "
- "IP=%s PORT=%d RTP_PAYLOAD2=%d CONN_ID=%d\n",
+ DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_CONNECT "
+ "IP=%s PORT=%d RTP_PAYLOAD2=%d CONN_ID=%d speech_mode=0x%02x\n",
gsm_ts_name(lchan->ts), dh->chan_nr,
- inet_ntoa(ia), port, rtp_payload2, conn_id);
+ inet_ntoa(ia), port, rtp_payload2, conn_id, speech_mode);
att_f8 = msgb_put(msg, sizeof(conn_id)+1);
att_f8[0] = RSL_IE_IPAC_CONN_ID;
@@ -1324,9 +1335,7 @@ int rsl_ipacc_connect(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port,
att_port[1] = port >> 8;
att_port[2] = port & 0xff;
- speech_mode_s = ipa_smod_s_for_tch_mode(lchan->tch_mode);
- /* 0x0- == both directions, 0x-1 == EFR codec */
- msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, 0x00 | speech_mode_s);
+ msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, speech_mode);
if (rtp_payload2)
msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, rtp_payload2);
diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c
index 1bfb7068b..82cb7886a 100644
--- a/openbsc/src/bsc_hack.c
+++ b/openbsc/src/bsc_hack.c
@@ -61,9 +61,12 @@ static int BSIC = HARDCODED_BSIC;
static int ARFCN = HARDCODED_ARFCN;
static int cardnr = 0;
static int release_l2 = 0;
+static int bs11_has_trx1 = 0;
+static int bs11_has_bts1 = 0;
static enum gsm_bts_type BTS_TYPE = GSM_BTS_TYPE_BS11;
static enum gsm_band BAND = GSM_BAND_900;
static const char *database_name = "hlr.sqlite3";
+extern int ipacc_rtp_direct;
struct nano_bts_id {
struct llist_head entry;
@@ -501,6 +504,23 @@ static void bootstrap_om_nanobts(struct gsm_bts *bts)
static void bootstrap_om_bs11(struct gsm_bts *bts)
{
struct gsm_bts_trx *trx = bts->c0;
+ int base_ts;
+
+ switch (bts->nr) {
+ case 0:
+ /* First BTS uses E1 TS 01,02,03,04,05 */
+ base_ts = HARDCODED_BTS0_TS - 1;
+ break;
+ case 1:
+ /* Second BTS uses E1 TS 06,07,08,09,10 */
+ base_ts = HARDCODED_BTS1_TS - 1;
+ break;
+ case 2:
+ /* Third BTS uses E1 TS 11,12,13,14,15 */
+ base_ts = HARDCODED_BTS2_TS - 1;
+ default:
+ return;
+ }
/* stop sending event reports */
abis_nm_event_reports(bts, 0);
@@ -523,54 +543,110 @@ static void bootstrap_om_bs11(struct gsm_bts *bts)
abis_nm_raw_msg(bts, sizeof(msg_4), msg_4); /* set BTS power control attr */
/* Connect signalling of bts0/trx0 to e1_0/ts1/64kbps */
- abis_nm_conn_terr_sign(trx, 0, 1, 0xff);
+ abis_nm_conn_terr_sign(trx, 0, base_ts+1, 0xff);
abis_nm_set_radio_attr(trx, bs11_attr_radio, sizeof(bs11_attr_radio));
/* Use TEI 1 for signalling */
- abis_nm_establish_tei(bts, 0, 0, 1, 0xff, 0x01);
+ abis_nm_establish_tei(bts, 0, 0, base_ts+1, 0xff, 0x01);
abis_nm_set_channel_attr(&trx->ts[0], NM_CHANC_SDCCH_CBCH);
-#ifdef HAVE_TRX1
- /* TRX 1 */
- abis_nm_conn_terr_sign(&bts->trx[1], 0, 1, 0xff);
- /* FIXME: TRX ATTRIBUTE */
- abis_nm_establish_tei(bts, 0, 0, 1, 0xff, 0x02);
-#endif
-
/* SET CHANNEL ATTRIBUTE TS1 */
abis_nm_set_channel_attr(&trx->ts[1], NM_CHANC_TCHFull);
/* Connect traffic of bts0/trx0/ts1 to e1_0/ts2/b */
- abis_nm_conn_terr_traf(&trx->ts[1], 0, 2, 1);
+ abis_nm_conn_terr_traf(&trx->ts[1], 0, base_ts+2, 1);
/* SET CHANNEL ATTRIBUTE TS2 */
abis_nm_set_channel_attr(&trx->ts[2], NM_CHANC_TCHFull);
/* Connect traffic of bts0/trx0/ts2 to e1_0/ts2/c */
- abis_nm_conn_terr_traf(&trx->ts[2], 0, 2, 2);
+ abis_nm_conn_terr_traf(&trx->ts[2], 0, base_ts+2, 2);
/* SET CHANNEL ATTRIBUTE TS3 */
abis_nm_set_channel_attr(&trx->ts[3], NM_CHANC_TCHFull);
/* Connect traffic of bts0/trx0/ts3 to e1_0/ts2/d */
- abis_nm_conn_terr_traf(&trx->ts[3], 0, 2, 3);
+ abis_nm_conn_terr_traf(&trx->ts[3], 0, base_ts+2, 3);
/* SET CHANNEL ATTRIBUTE TS4 */
abis_nm_set_channel_attr(&trx->ts[4], NM_CHANC_TCHFull);
/* Connect traffic of bts0/trx0/ts4 to e1_0/ts3/a */
- abis_nm_conn_terr_traf(&trx->ts[4], 0, 3, 0);
+ abis_nm_conn_terr_traf(&trx->ts[4], 0, base_ts+3, 0);
/* SET CHANNEL ATTRIBUTE TS5 */
abis_nm_set_channel_attr(&trx->ts[5], NM_CHANC_TCHFull);
/* Connect traffic of bts0/trx0/ts5 to e1_0/ts3/b */
- abis_nm_conn_terr_traf(&trx->ts[5], 0, 3, 1);
+ abis_nm_conn_terr_traf(&trx->ts[5], 0, base_ts+3, 1);
/* SET CHANNEL ATTRIBUTE TS6 */
abis_nm_set_channel_attr(&trx->ts[6], NM_CHANC_TCHFull);
/* Connect traffic of bts0/trx0/ts6 to e1_0/ts3/c */
- abis_nm_conn_terr_traf(&trx->ts[6], 0, 3, 2);
+ abis_nm_conn_terr_traf(&trx->ts[6], 0, base_ts+3, 2);
/* SET CHANNEL ATTRIBUTE TS7 */
abis_nm_set_channel_attr(&trx->ts[7], NM_CHANC_TCHFull);
/* Connect traffic of bts0/trx0/ts7 to e1_0/ts3/d */
- abis_nm_conn_terr_traf(&trx->ts[7], 0, 3, 3);
+ abis_nm_conn_terr_traf(&trx->ts[7], 0, base_ts+3, 3);
+
+ trx = gsm_bts_trx_num(bts, 1);
+ if (trx) {
+ u_int8_t trx1_attr_radio[sizeof(bs11_attr_radio)];
+ u_int8_t arfcn_low = trx->arfcn & 0xff;
+ u_int8_t arfcn_high = (trx->arfcn >> 8) & 0x0f;
+ memcpy(trx1_attr_radio, bs11_attr_radio,
+ sizeof(trx1_attr_radio));
+
+ /* patch ARFCN into TRX Attributes */
+ trx1_attr_radio[2] &= 0xf0;
+ trx1_attr_radio[2] |= arfcn_high;
+ trx1_attr_radio[3] = arfcn_low;
+
+ /* Connect signalling of TRX1 to e1_0/ts1/64kbps */
+ abis_nm_conn_terr_sign(trx, 0, base_ts+1, 0xff);
+ /* FIXME: TRX ATTRIBUTE */
+ abis_nm_set_radio_attr(trx, trx1_attr_radio,
+ sizeof(trx1_attr_radio));
+
+ /* Use TEI 2 for signalling */
+ abis_nm_establish_tei(bts, 1, 0, base_ts+1, 0xff, 0x02);
+
+ /* SET CHANNEL ATTRIBUTE TS0 */
+ abis_nm_set_channel_attr(&trx->ts[0], NM_CHANC_TCHFull);
+ /* Connect traffic of bts0/trx0/ts0 to e1_0/ts4/a */
+ abis_nm_conn_terr_traf(&trx->ts[0], 0, base_ts+4, 0);
+
+ /* SET CHANNEL ATTRIBUTE TS1 */
+ abis_nm_set_channel_attr(&trx->ts[1], NM_CHANC_TCHFull);
+ /* Connect traffic of bts0/trx0/ts1 to e1_0/ts4/b */
+ abis_nm_conn_terr_traf(&trx->ts[1], 0, base_ts+4, 1);
+
+ /* SET CHANNEL ATTRIBUTE TS2 */
+ abis_nm_set_channel_attr(&trx->ts[2], NM_CHANC_TCHFull);
+ /* Connect traffic of bts0/trx0/ts2 to e1_0/ts4/c */
+ abis_nm_conn_terr_traf(&trx->ts[2], 0, base_ts+4, 2);
+
+ /* SET CHANNEL ATTRIBUTE TS3 */
+ abis_nm_set_channel_attr(&trx->ts[3], NM_CHANC_TCHFull);
+ /* Connect traffic of bts0/trx0/ts3 to e1_0/ts4/d */
+ abis_nm_conn_terr_traf(&trx->ts[3], 0, base_ts+4, 3);
+
+ /* SET CHANNEL ATTRIBUTE TS4 */
+ abis_nm_set_channel_attr(&trx->ts[4], NM_CHANC_TCHFull);
+ /* Connect traffic of bts0/trx0/ts4 to e1_0/ts5/a */
+ abis_nm_conn_terr_traf(&trx->ts[4], 0, base_ts+5, 0);
+
+ /* SET CHANNEL ATTRIBUTE TS5 */
+ abis_nm_set_channel_attr(&trx->ts[5], NM_CHANC_TCHFull);
+ /* Connect traffic of bts0/trx0/ts5 to e1_0/ts5/b */
+ abis_nm_conn_terr_traf(&trx->ts[5], 0, base_ts+5, 1);
+
+ /* SET CHANNEL ATTRIBUTE TS6 */
+ abis_nm_set_channel_attr(&trx->ts[6], NM_CHANC_TCHFull);
+ /* Connect traffic of bts0/trx0/ts6 to e1_0/ts5/c */
+ abis_nm_conn_terr_traf(&trx->ts[6], 0, base_ts+5, 2);
+
+ /* SET CHANNEL ATTRIBUTE TS7 */
+ abis_nm_set_channel_attr(&trx->ts[7], NM_CHANC_TCHFull);
+ /* Connect traffic of bts0/trx0/ts7 to e1_0/ts5/d */
+ abis_nm_conn_terr_traf(&trx->ts[7], 0, base_ts+5, 3);
+ }
/* end DB transmission */
abis_nm_bs11_db_transmission(bts, 0);
@@ -601,6 +677,8 @@ static void bootstrap_om(struct gsm_bts *bts)
static int shutdown_om(struct gsm_bts *bts)
{
+ fprintf(stdout, "shutting down OML for BTS %u\n", bts->nr);
+
/* stop sending event reports */
abis_nm_event_reports(bts, 0);
@@ -832,10 +910,12 @@ static int set_system_infos(struct gsm_bts_trx *trx)
{
int i;
- for (i = 0; i < ARRAY_SIZE(bcch_infos); i++) {
- rsl_bcch_info(trx, bcch_infos[i].type,
- bcch_infos[i].data,
- bcch_infos[i].len);
+ if (trx == trx->bts->c0) {
+ for (i = 0; i < ARRAY_SIZE(bcch_infos); i++) {
+ rsl_bcch_info(trx, bcch_infos[i].type,
+ bcch_infos[i].data,
+ bcch_infos[i].len);
+ }
}
rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si5, sizeof(si5));
rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si6, sizeof(si6));
@@ -906,7 +986,7 @@ static void bootstrap_rsl(struct gsm_bts_trx *trx)
{
fprintf(stdout, "bootstrapping RSL for BTS/TRX (%u/%u) "
"using MCC=%u MNC=%u BSIC=%u TSC=%u\n",
- trx->nr, trx->bts->nr, MCC, MNC, BSIC, TSC);
+ trx->bts->nr, trx->nr, MCC, MNC, BSIC, TSC);
set_system_infos(trx);
}
@@ -961,18 +1041,20 @@ static int bootstrap_bts(struct gsm_bts *bts)
set_ts_e1link(&trx->ts[5], 0, 3, 1);
set_ts_e1link(&trx->ts[6], 0, 3, 2);
set_ts_e1link(&trx->ts[7], 0, 3, 3);
-#ifdef HAVE_TRX1
+
/* TRX 1 */
- trx = &bts->trx[1];
- set_ts_e1link(&trx->ts[0], 0, 1, 0xff);
- set_ts_e1link(&trx->ts[1], 0, 2, 1);
- set_ts_e1link(&trx->ts[2], 0, 2, 2);
- set_ts_e1link(&trx->ts[3], 0, 2, 3);
- set_ts_e1link(&trx->ts[4], 0, 3, 0);
- set_ts_e1link(&trx->ts[5], 0, 3, 1);
- set_ts_e1link(&trx->ts[6], 0, 3, 2);
- set_ts_e1link(&trx->ts[7], 0, 3, 3);
-#endif
+ trx = gsm_bts_trx_num(bts, 1);
+ if (trx) {
+ trx = gsm_bts_trx_num(bts, 1);
+ set_ts_e1link(&trx->ts[0], 0, 4, 0);
+ set_ts_e1link(&trx->ts[1], 0, 4, 1);
+ set_ts_e1link(&trx->ts[2], 0, 4, 2);
+ set_ts_e1link(&trx->ts[3], 0, 4, 3);
+ set_ts_e1link(&trx->ts[4], 0, 5, 0);
+ set_ts_e1link(&trx->ts[5], 0, 5, 1);
+ set_ts_e1link(&trx->ts[6], 0, 5, 2);
+ set_ts_e1link(&trx->ts[7], 0, 5, 3);
+ }
}
return 0;
@@ -980,6 +1062,8 @@ static int bootstrap_bts(struct gsm_bts *bts)
static int bootstrap_network(void)
{
+ int rc;
+
switch(BTS_TYPE) {
case GSM_BTS_TYPE_NANOBTS_1800:
if (ARFCN < 512 || ARFCN > 885) {
@@ -1027,10 +1111,32 @@ static int bootstrap_network(void)
/* E1 mISDN input setup */
if (BTS_TYPE == GSM_BTS_TYPE_BS11) {
struct gsm_bts *bts = gsm_bts_alloc(gsmnet, BTS_TYPE, TSC, BSIC);
+
+ if (bs11_has_trx1) {
+ struct gsm_bts_trx *trx1;
+ trx1 = gsm_bts_trx_alloc(bts);
+ trx1->arfcn = ARFCN + 2;
+ }
bootstrap_bts(bts);
+ rc = e1_config(bts, cardnr, release_l2);
+ if (rc < 0) {
+ fprintf(stderr, "Error during E1 config of BTS 0\n");
+ return rc;
+ }
- gsmnet->num_bts = 1;
- return e1_config(bts, cardnr, release_l2);
+ if (bs11_has_bts1) {
+ bts = gsm_bts_alloc(gsmnet, BTS_TYPE, TSC, BSIC);
+ if (bs11_has_trx1) {
+ struct gsm_bts_trx *trx1;
+ trx1 = gsm_bts_trx_alloc(bts);
+ trx1->arfcn = ARFCN + 2;
+ }
+ bootstrap_bts(bts);
+ rc = e1_config(bts, cardnr+1, release_l2);
+ if (rc < 0)
+ fprintf(stderr, "Error during E1 config of BTS 1\n");
+ }
+ return rc;
} else {
struct nano_bts_id *bts_id;
struct gsm_bts *bts;
@@ -1086,6 +1192,7 @@ static void print_help()
printf(" -i --bts-id=NUMBER The known nanoBTS device numbers. Can be specified multiple times.\n");
printf(" -C --cardnr number For bs11 select E1 card number other than 0\n");
printf(" -R --release-l2 Releases mISDN layer 2 after exit, to unload driver.\n");
+ printf(" -2 --second-bs11 Configure + Use a second BS-11\n");
printf(" -h --help this text\n");
}
@@ -1113,10 +1220,13 @@ static void handle_options(int argc, char** argv)
{"bts-id", 1, 0, 'i'},
{"tsc", 1, 0, 'S'},
{"bsic", 1, 0, 'B'},
+ {"rtp-proxy", 0, 0, 'P'},
+ {"trx1", 0, 0, '1'},
+ {"second-bs11", 0, 0, '2'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "hc:n:d:sar:p:f:t:C:RL:l:Tb:i:S:B:",
+ c = getopt_long(argc, argv, "hc:n:d:sar:p:f:t:C:RL:l:Tb:i:S:B:P12",
long_options, &option_index);
if (c == -1)
break;
@@ -1187,6 +1297,15 @@ static void handle_options(int argc, char** argv)
case 'B':
BSIC = atoi(optarg);
break;
+ case 'P':
+ ipacc_rtp_direct = 0;
+ break;
+ case '1':
+ bs11_has_trx1 = 1;
+ break;
+ case '2':
+ bs11_has_bts1 = 1;
+ break;
}
default:
/* ignore */
@@ -1200,9 +1319,11 @@ static void signal_handler(int signal)
fprintf(stdout, "signal %u received\n", signal);
switch (signal) {
- case SIGHUP:
+ case SIGINT:
case SIGABRT:
shutdown_net(gsmnet);
+ sleep(3);
+ exit(0);
break;
case SIGUSR1:
talloc_report_full(tall_bsc_ctx, stderr);
@@ -1228,7 +1349,7 @@ int main(int argc, char **argv)
if (rc < 0)
exit(1);
- signal(SIGHUP, &signal_handler);
+ signal(SIGINT, &signal_handler);
signal(SIGABRT, &signal_handler);
signal(SIGUSR1, &signal_handler);
diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c
index fe16815c6..e3d6ae67e 100644
--- a/openbsc/src/chan_alloc.c
+++ b/openbsc/src/chan_alloc.c
@@ -73,20 +73,34 @@ struct gsm_bts_trx_ts *ts_alloc(struct gsm_bts *bts,
/* the following constraints are pure policy,
* no requirement to put this restriction in place */
- switch (pchan) {
- case GSM_PCHAN_CCCH:
- case GSM_PCHAN_CCCH_SDCCH4:
- from = 0; to = 0;
- break;
- case GSM_PCHAN_SDCCH8_SACCH8C:
- from = 1; to = 1;
- break;
- case GSM_PCHAN_TCH_F:
- case GSM_PCHAN_TCH_H:
- from = 2; to = 7;
- break;
- default:
- return NULL;
+ if (trx == bts->c0) {
+ /* On the first TRX we run one CCCH and one SDCCH8 */
+ switch (pchan) {
+ case GSM_PCHAN_CCCH:
+ case GSM_PCHAN_CCCH_SDCCH4:
+ from = 0; to = 0;
+ break;
+ case GSM_PCHAN_SDCCH8_SACCH8C:
+ from = 1; to = 1;
+ break;
+ case GSM_PCHAN_TCH_F:
+ case GSM_PCHAN_TCH_H:
+ from = 2; to = 7;
+ break;
+ default:
+ return NULL;
+ }
+ } else {
+ /* Every secondary TRX is configured for TCH/F
+ * and TCH/H only */
+ switch (pchan) {
+ case GSM_PCHAN_TCH_F:
+ case GSM_PCHAN_TCH_H:
+ from = 0; to = 7;
+ break;
+ default:
+ return NULL;
+ }
}
for (j = from; j <= to; j++) {
diff --git a/openbsc/src/e1_config.c b/openbsc/src/e1_config.c
index 9c9f40cff..898780374 100644
--- a/openbsc/src/e1_config.c
+++ b/openbsc/src/e1_config.c
@@ -24,50 +24,81 @@ int e1_config(struct gsm_bts *bts, int cardnr, int release_l2)
struct e1inp_line *line;
struct e1inp_ts *sign_ts;
struct e1inp_sign_link *oml_link, *rsl_link;
+ struct gsm_bts_trx *trx = bts->c0;
+ int base_ts;
+
+ switch (bts->nr) {
+ case 0:
+ /* First BTS uses E1 TS 01,02,03,04,05 */
+ base_ts = HARDCODED_BTS0_TS - 1;
+ break;
+ case 1:
+ /* Second BTS uses E1 TS 06,07,08,09,10 */
+ base_ts = HARDCODED_BTS1_TS - 1;
+ break;
+ case 2:
+ /* Third BTS uses E1 TS 11,12,13,14,15 */
+ base_ts = HARDCODED_BTS2_TS - 1;
+ default:
+ return -EINVAL;
+ }
line = talloc_zero(tall_bsc_ctx, struct e1inp_line);
if (!line)
return -ENOMEM;
/* create E1 timeslots for signalling and TRAU frames */
- e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN);
- e1inp_ts_config(&line->ts[2-1], line, E1INP_TS_TYPE_TRAU);
- e1inp_ts_config(&line->ts[3-1], line, E1INP_TS_TYPE_TRAU);
+ e1inp_ts_config(&line->ts[base_ts+1-1], line, E1INP_TS_TYPE_SIGN);
+ e1inp_ts_config(&line->ts[base_ts+2-1], line, E1INP_TS_TYPE_TRAU);
+ e1inp_ts_config(&line->ts[base_ts+3-1], line, E1INP_TS_TYPE_TRAU);
/* create signalling links for TS1 */
- sign_ts = &line->ts[1-1];
+ sign_ts = &line->ts[base_ts+1-1];
oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML,
- bts->c0, TEI_OML, SAPI_OML);
+ trx, TEI_OML, SAPI_OML);
rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL,
- bts->c0, TEI_RSL, SAPI_RSL);
+ trx, TEI_RSL, SAPI_RSL);
/* create back-links from bts/trx */
bts->oml_link = oml_link;
- bts->c0->rsl_link = rsl_link;
+ trx->rsl_link = rsl_link;
/* enable subchannel demuxer on TS2 */
- subch_demux_activate(&line->ts[2-1].trau.demux, 1);
- subch_demux_activate(&line->ts[2-1].trau.demux, 2);
- subch_demux_activate(&line->ts[2-1].trau.demux, 3);
+ subch_demux_activate(&line->ts[base_ts+2-1].trau.demux, 1);
+ subch_demux_activate(&line->ts[base_ts+2-1].trau.demux, 2);
+ subch_demux_activate(&line->ts[base_ts+2-1].trau.demux, 3);
/* enable subchannel demuxer on TS3 */
- subch_demux_activate(&line->ts[3-1].trau.demux, 0);
- subch_demux_activate(&line->ts[3-1].trau.demux, 1);
- subch_demux_activate(&line->ts[3-1].trau.demux, 2);
- subch_demux_activate(&line->ts[3-1].trau.demux, 3);
-
-#ifdef HAVE_TRX1
- /* create E1 timeslots for TRAU frames of TRX1 */
- e1inp_ts_config(&line->ts[4-1], line, E1INP_TS_TYPE_TRAU);
- e1inp_ts_config(&line->ts[5-1], line, E1INP_TS_TYPE_TRAU);
-
- /* create RSL signalling link for TRX1 */
- sign_ts = &line->ts[1-1];
- rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL,
- &bts->trx[1], TEI_RSL+1, SAPI_RSL);
- /* create back-links from trx */
- bts->trx[1].rsl_link = rsl_link;
-#endif
+ subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 0);
+ subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 1);
+ subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 2);
+ subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 3);
+
+ trx = gsm_bts_trx_num(bts, 1);
+ if (trx) {
+ /* create E1 timeslots for TRAU frames of TRX1 */
+ e1inp_ts_config(&line->ts[base_ts+4-1], line, E1INP_TS_TYPE_TRAU);
+ e1inp_ts_config(&line->ts[base_ts+5-1], line, E1INP_TS_TYPE_TRAU);
+
+ /* create RSL signalling link for TRX1 */
+ sign_ts = &line->ts[base_ts+1-1];
+ rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL,
+ trx, TEI_RSL+1, SAPI_RSL);
+ /* create back-links from trx */
+ trx->rsl_link = rsl_link;
+
+ /* enable subchannel demuxer on TS2 */
+ subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 0);
+ subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 1);
+ subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 2);
+ subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 3);
+
+ /* enable subchannel demuxer on TS3 */
+ subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 0);
+ subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 1);
+ subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 2);
+ subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 3);
+ }
return mi_setup(cardnr, line, release_l2);
}
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index a9f2ebd8e..078e95f3b 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -44,6 +44,7 @@
#include <openbsc/signal.h>
#include <openbsc/trau_frame.h>
#include <openbsc/trau_mux.h>
+#include <openbsc/rtp_proxy.h>
#include <openbsc/talloc.h>
#include <openbsc/transaction.h>
@@ -56,6 +57,10 @@
static void *tall_locop_ctx;
+/* should ip.access BTS use direct RTP streams between each other (1),
+ * or should OpenBSC always act as RTP relay/proxy in between (0) ? */
+int ipacc_rtp_direct = 1;
+
static const struct tlv_definition rsl_att_tlvdef = {
.def = {
[GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV },
@@ -399,17 +404,6 @@ static int gsm0408_handle_lchan_signal(unsigned int subsys, unsigned int signal,
return 0;
}
-/*
- * This will be ran by the linker when loading the DSO. We use it to
- * do system initialization, e.g. registration of signal handlers.
- */
-static __attribute__((constructor)) void on_dso_load_0408(void)
-{
- tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1,
- "loc_updating_oper");
- register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
-}
-
static void to_bcd(u_int8_t *bcd, u_int16_t val)
{
bcd[2] = val % 10;
@@ -1284,7 +1278,7 @@ static int mm_rx_loc_upd_req(struct msgb *msg)
return gsm0408_authorize(lchan, msg);
}
-/* 9.1.5 Channel mode modify */
+/* 9.1.5 Channel mode modify: Modify the mode on the MS side */
int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode)
{
struct msgb *msg = gsm48_msgb_alloc();
@@ -1750,6 +1744,9 @@ static int gsm0408_rcv_rr(struct msgb *msg)
break;
case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n");
+ /* We've successfully modified the MS side of the channel,
+ * now go on to modify the BTS side of the channel */
+ msg->lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH;
rc = rsl_chan_mode_modify_req(msg->lchan);
break;
case GSM48_MT_RR_STATUS:
@@ -1954,8 +1951,6 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
}
/* send SETUP request to called party */
gsm48_cc_tx_setup(transt, &transt->cc.msg);
- if (is_ipaccess_bts(lchan->ts->trx->bts))
- rsl_ipacc_bind(lchan);
break;
case GSM_PAGING_EXPIRED:
DEBUGP(DCC, "Paging subscr %s expired!\n",
@@ -1973,12 +1968,80 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
return 0;
}
+/* some other part of the code sends us a signal */
+static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
+ void *handler_data, void *signal_data)
+{
+ struct gsm_lchan *lchan = signal_data;
+ struct gsm_bts_trx_ts *ts;
+ int rc;
+
+ if (subsys != SS_ABISIP)
+ return 0;
+
+ /* in case we use direct BTS-to-BTS RTP */
+ if (ipacc_rtp_direct)
+ return 0;
+
+ ts = lchan->ts;
+
+ switch (signal) {
+ case S_ABISIP_BIND_ACK:
+ /* the BTS has successfully bound a TCH to a local ip/port,
+ * which means we can connect our UDP socket to it */
+ if (ts->abis_ip.rtp_socket) {
+ rtp_socket_free(ts->abis_ip.rtp_socket);
+ ts->abis_ip.rtp_socket = NULL;
+ }
+
+ ts->abis_ip.rtp_socket = rtp_socket_create();
+ if (!ts->abis_ip.rtp_socket)
+ goto out_err;
+
+ rc = rtp_socket_connect(ts->abis_ip.rtp_socket,
+ ts->abis_ip.bound_ip,
+ ts->abis_ip.bound_port);
+ if (rc < 0)
+ goto out_err;
+ break;
+ case S_ABISIP_DISC_IND:
+ /* the BTS tells us a RTP stream has been disconnected */
+ if (ts->abis_ip.rtp_socket) {
+ rtp_socket_free(ts->abis_ip.rtp_socket);
+ ts->abis_ip.rtp_socket = NULL;
+ }
+ break;
+ }
+
+ return 0;
+out_err:
+ /* FIXME: do something */
+ return 0;
+}
+
+/* bind rtp proxy to local IP/port and tell BTS to connect to it */
+static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan)
+{
+ struct gsm_bts_trx_ts *ts = lchan->ts;
+ struct rtp_socket *rs = ts->abis_ip.rtp_socket;
+ int rc;
+
+ rc = rsl_ipacc_connect(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr),
+ ntohs(rs->rtp.sin_local.sin_port),
+ ts->abis_ip.conn_id,
+ /* FIXME: use RTP payload of bound socket, not BTS*/
+ ts->abis_ip.rtp_payload2);
+
+ return rc;
+}
+
/* map two ipaccess RTP streams onto each other */
static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
{
struct gsm_bts *bts = lchan->ts->trx->bts;
struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
struct gsm_bts_trx_ts *ts;
+ int rc;
DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n",
bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
@@ -1992,23 +2055,38 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
switch (bts->type) {
case GSM_BTS_TYPE_NANOBTS_900:
case GSM_BTS_TYPE_NANOBTS_1800:
- ts = remote_lchan->ts;
- rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip,
- ts->abis_ip.bound_port,
- lchan->ts->abis_ip.conn_id,
- ts->abis_ip.rtp_payload2);
-
- ts = lchan->ts;
- rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip,
- ts->abis_ip.bound_port,
- remote_lchan->ts->abis_ip.conn_id,
- ts->abis_ip.rtp_payload2);
+ if (!ipacc_rtp_direct) {
+ /* connect the TCH's to our RTP proxy */
+ rc = ipacc_connect_proxy_bind(lchan);
+ if (rc < 0)
+ return rc;
+ rc = ipacc_connect_proxy_bind(remote_lchan);
+
+ /* connect them with each other */
+ rtp_socket_proxy(lchan->ts->abis_ip.rtp_socket,
+ remote_lchan->ts->abis_ip.rtp_socket);
+ } else {
+ /* directly connect TCH RTP streams to each other */
+ ts = remote_lchan->ts;
+ rc = rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip,
+ ts->abis_ip.bound_port,
+ lchan->ts->abis_ip.conn_id,
+ ts->abis_ip.rtp_payload2);
+ if (rc < 0)
+ return rc;
+ ts = lchan->ts;
+ rc = rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip,
+ ts->abis_ip.bound_port,
+ remote_lchan->ts->abis_ip.conn_id,
+ ts->abis_ip.rtp_payload2);
+ }
break;
case GSM_BTS_TYPE_BS11:
trau_mux_map_lchan(lchan, remote_lchan);
break;
default:
DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
+ rc = -EINVAL;
break;
}
@@ -2240,14 +2318,14 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
}
- if (is_ipaccess_bts(msg->trx->bts))
- rsl_ipacc_bind(msg->lchan);
-
new_cc_state(trans, GSM_CSTATE_INITIATED);
/* indicate setup to MNCC */
mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_IND, &setup);
+ /* MNCC code will modify the channel asynchronously, we should
+ * ipaccess-bind only after the modification has been made to the
+ * lchan->tch_mode */
return 0;
}
@@ -3217,8 +3295,19 @@ static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg)
static int gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
{
struct gsm_mncc *mode = arg;
+ int rc;
+
+ rc = gsm48_tx_chan_mode_modify(trans->lchan, mode->lchan_mode);
+ if (rc < 0)
+ return rc;
+
+ /* FIXME: we not only need to do this after mode modify, but
+ * also after channel activation */
+ if (is_ipaccess_bts(trans->lchan->ts->trx->bts) &&
+ mode->lchan_mode != GSM48_CMODE_SIGN)
+ rc = rsl_ipacc_bind(trans->lchan);
- return gsm48_tx_chan_mode_modify(trans->lchan, mode->lchan_mode);
+ return rc;
}
static struct downstate {
@@ -3732,3 +3821,14 @@ int bsc_upqueue(struct gsm_network *net)
return work;
}
+/*
+ * This will be ran by the linker when loading the DSO. We use it to
+ * do system initialization, e.g. registration of signal handlers.
+ */
+static __attribute__((constructor)) void on_dso_load_0408(void)
+{
+ tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1,
+ "loc_updating_oper");
+ register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
+ register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
+}
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index c21c6b4f5..285b75825 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -117,7 +117,7 @@ struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)
}
}
- llist_add(&trx->list, &bts->trx_list);
+ llist_add_tail(&trx->list, &bts->trx_list);
return trx;
}
@@ -147,7 +147,7 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type,
}
bts->c0->ts[0].pchan = GSM_PCHAN_CCCH_SDCCH4;
- llist_add(&bts->list, &net->bts_list);
+ llist_add_tail(&bts->list, &net->bts_list);
return bts;
}
@@ -270,15 +270,15 @@ char *gsm_band_name(enum gsm_band band)
{
switch (band) {
case GSM_BAND_400:
- return "GSM 400";
+ return "GSM400";
case GSM_BAND_850:
- return "GSM 850";
+ return "GSM850";
case GSM_BAND_900:
- return "GSM 900";
+ return "GSM900";
case GSM_BAND_1800:
- return "DCS 1800";
+ return "DCS1800";
case GSM_BAND_1900:
- return "PCS 1900";
+ return "PCS1900";
}
return "invalid";
}
diff --git a/openbsc/src/input/misdn.c b/openbsc/src/input/misdn.c
index a04c2abd7..2ec74b8ea 100644
--- a/openbsc/src/input/misdn.c
+++ b/openbsc/src/input/misdn.c
@@ -477,14 +477,7 @@ int mi_setup(int cardnr, struct e1inp_line *line, int release_l2)
int sk, ret, cnt;
struct mISDN_devinfo devinfo;
- /* register the driver with the core */
- /* FIXME: do this in the plugin initializer function */
- ret = e1inp_driver_register(&misdn_driver);
- if (ret)
- return ret;
-
/* create the actual line instance */
- /* FIXME: do this independent of driver registration */
e1h = talloc(tall_bsc_ctx, struct mi_e1_handle);
memset(e1h, 0, sizeof(*e1h));
@@ -531,14 +524,15 @@ int mi_setup(int cardnr, struct e1inp_line *line, int release_l2)
return -EINVAL;
}
- if (devinfo.nrbchan != 30) {
- fprintf(stderr, "error: E1 card has no 30 B-channels\n");
- return -EINVAL;
- }
-
ret = mi_e1_setup(line, release_l2);
if (ret)
return ret;
return e1inp_line_register(line);
}
+
+static __attribute__((constructor)) void on_dso_load_sms(void)
+{
+ /* register the driver with the core */
+ e1inp_driver_register(&misdn_driver);
+}
diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c
new file mode 100644
index 000000000..a581b9fdf
--- /dev/null
+++ b/openbsc/src/rtp_proxy.c
@@ -0,0 +1,446 @@
+/* RTP proxy handling for ip.access nanoBTS */
+
+/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <openbsc/talloc.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/msgb.h>
+#include <openbsc/select.h>
+#include <openbsc/debug.h>
+#include <openbsc/rtp_proxy.h>
+
+static LLIST_HEAD(rtp_sockets);
+
+/* should we mangle the CNAME inside SDES of RTCP packets? We disable
+ * this by default, as it seems to be not needed */
+static int mangle_rtcp_cname = 0;
+
+enum rtp_bfd_priv {
+ RTP_PRIV_NONE,
+ RTP_PRIV_RTP,
+ RTP_PRIV_RTCP
+};
+
+#define RTP_ALLOC_SIZE 1500
+
+/* according to RFC 1889 */
+struct rtcp_hdr {
+ u_int8_t byte0;
+ u_int8_t type;
+ u_int16_t length;
+} __attribute__((packed));
+
+#define RTCP_TYPE_SDES 202
+
+#define RTCP_IE_CNAME 1
+
+/* iterate over all chunks in one RTCP message, look for CNAME IEs and
+ * replace all of those with 'new_cname' */
+static int rtcp_sdes_cname_mangle(struct msgb *msg, struct rtcp_hdr *rh,
+ u_int16_t *rtcp_len, const char *new_cname)
+{
+ u_int8_t *rtcp_end;
+ u_int8_t *cur = (u_int8_t *) rh;
+ u_int8_t tag, len = 0;
+
+ rtcp_end = cur + *rtcp_len;
+ /* move cur to end of RTP header */
+ cur += sizeof(*rh);
+
+ /* iterate over Chunks */
+ while (cur+4 < rtcp_end) {
+ /* skip four bytes SSRC/CSRC */
+ cur += 4;
+
+ /* iterate over IE's inside the chunk */
+ while (cur+1 < rtcp_end) {
+ tag = *cur++;
+ if (tag == 0) {
+ /* end of chunk, skip additional zero */
+ while (*cur++ == 0) { }
+ break;
+ }
+ len = *cur++;
+
+ if (tag == RTCP_IE_CNAME) {
+ /* we've found the CNAME, lets mangle it */
+ if (len < strlen(new_cname)) {
+ /* we need to make more space */
+ int increase = strlen(new_cname) - len;
+
+ msgb_push(msg, increase);
+ memmove(cur+len+increase, cur+len,
+ rtcp_end - (cur+len));
+ /* FIXME: we have to respect RTCP
+ * padding/alignment rules! */
+ len += increase;
+ *(cur-1) += increase;
+ rtcp_end += increase;
+ *rtcp_len += increase;
+ }
+ /* copy new CNAME into message */
+ memcpy(cur, new_cname, strlen(new_cname));
+ /* FIXME: zero the padding in case new CNAME
+ * is smaller than old one !!! */
+ }
+ cur += len;
+ }
+ }
+
+ return 0;
+}
+
+static int rtcp_mangle(struct msgb *msg, struct rtp_socket *rs)
+{
+ struct rtp_sub_socket *rss = &rs->rtcp;
+ struct rtcp_hdr *rtph;
+ u_int16_t old_len;
+ int rc;
+
+ if (!mangle_rtcp_cname)
+ return 0;
+
+ /* iterate over list of RTCP messages */
+ rtph = (struct rtcp_hdr *)msg->data;
+ while ((void *)rtph + sizeof(*rtph) < (void *)msg->data + msg->len) {
+ old_len = (ntohs(rtph->length) + 1) * 4;
+ if (rtph->type == RTCP_TYPE_SDES) {
+ char new_cname[255];
+ strncpy(new_cname, inet_ntoa(rss->sin_local.sin_addr),
+ sizeof(new_cname));
+ new_cname[sizeof(new_cname)-1] = '\0';
+ rc = rtcp_sdes_cname_mangle(msg, rtph, &old_len,
+ new_cname);
+ if (rc < 0)
+ return rc;
+ }
+ rtph = (void *)rtph + old_len;
+ }
+
+ return 0;
+}
+
+/* read from incoming RTP/RTCP socket */
+static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
+{
+ int rc;
+ struct msgb *msg = msgb_alloc(RTP_ALLOC_SIZE, "RTP/RTCP");
+ struct rtp_sub_socket *other_rss;
+
+ if (!msg)
+ return -ENOMEM;
+
+ rc = read(rss->bfd.fd, msg->data, RTP_ALLOC_SIZE);
+ if (rc <= 0) {
+ rss->bfd.when &= ~BSC_FD_READ;
+ return rc;
+ }
+
+ msgb_put(msg, rc);
+
+ switch (rs->rx_action) {
+ case RTP_PROXY:
+ if (!rs->proxy.other_sock) {
+ rc = -EIO;
+ goto out_free;
+ }
+ if (rss->bfd.priv_nr == RTP_PRIV_RTP)
+ other_rss = &rs->proxy.other_sock->rtp;
+ else if (rss->bfd.priv_nr == RTP_PRIV_RTCP) {
+ other_rss = &rs->proxy.other_sock->rtcp;
+ /* modify RTCP SDES CNAME */
+ rc = rtcp_mangle(msg, rs);
+ if (rc < 0)
+ goto out_free;
+ } else {
+ rc = -EINVAL;
+ goto out_free;
+ }
+ msgb_enqueue(&other_rss->tx_queue, msg);
+ other_rss->bfd.when |= BSC_FD_WRITE;
+ break;
+ /* FIXME: other cases */
+ }
+
+ return rc;
+
+out_free:
+ msgb_free(msg);
+ return rc;
+}
+
+/* write from tx_queue to RTP/RTCP socket */
+static int rtp_socket_write(struct rtp_socket *rs, struct rtp_sub_socket *rss)
+{
+ struct msgb *msg;
+ int written;
+
+ msg = msgb_dequeue(&rss->tx_queue);
+ if (!msg) {
+ rss->bfd.when &= ~BSC_FD_WRITE;
+ return 0;
+ }
+
+ written = write(rss->bfd.fd, msg->data, msg->len);
+ if (written < msg->len) {
+ perror("short write");
+ msgb_free(msg);
+ return -EIO;
+ }
+
+ msgb_free(msg);
+
+ return 0;
+}
+
+
+/* callback for the select.c:bfd_* layer */
+static int rtp_bfd_cb(struct bsc_fd *bfd, unsigned int flags)
+{
+ struct rtp_socket *rs = bfd->data;
+ struct rtp_sub_socket *rss;
+
+ switch (bfd->priv_nr) {
+ case RTP_PRIV_RTP:
+ rss = &rs->rtp;
+ break;
+ case RTP_PRIV_RTCP:
+ rss = &rs->rtcp;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (flags & BSC_FD_READ)
+ rtp_socket_read(rs, rss);
+
+ if (flags & BSC_FD_WRITE)
+ rtp_socket_write(rs, rss);
+
+ return 0;
+}
+
+static void init_rss(struct rtp_sub_socket *rss,
+ struct rtp_socket *rs, int fd, int priv_nr)
+{
+ /* initialize bfd */
+ rss->bfd.fd = fd;
+ rss->bfd.data = rs;
+ rss->bfd.priv_nr = priv_nr;
+ rss->bfd.cb = rtp_bfd_cb;
+}
+
+struct rtp_socket *rtp_socket_create(void)
+{
+ int rc;
+ struct rtp_socket *rs;
+
+ DEBUGP(DMUX, "rtp_socket_create(): ");
+
+ rs = talloc_zero(tall_bsc_ctx, struct rtp_socket);
+ if (!rs)
+ return NULL;
+
+ INIT_LLIST_HEAD(&rs->rtp.tx_queue);
+ INIT_LLIST_HEAD(&rs->rtcp.tx_queue);
+
+ rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (rc < 0)
+ goto out_free;
+
+ init_rss(&rs->rtp, rs, rc, RTP_PRIV_RTP);
+ rc = bsc_register_fd(&rs->rtp.bfd);
+ if (rc < 0)
+ goto out_rtp_socket;
+
+ rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (rc < 0)
+ goto out_rtp_bfd;
+
+ init_rss(&rs->rtcp, rs, rc, RTP_PRIV_RTCP);
+ rc = bsc_register_fd(&rs->rtcp.bfd);
+ if (rc < 0)
+ goto out_rtcp_socket;
+
+ DEBUGPC(DMUX, "success\n");
+
+ rc = rtp_socket_bind(rs, INADDR_ANY);
+ if (rc < 0)
+ goto out_rtcp_bfd;
+
+ return rs;
+
+out_rtcp_bfd:
+ bsc_unregister_fd(&rs->rtcp.bfd);
+out_rtcp_socket:
+ close(rs->rtcp.bfd.fd);
+out_rtp_bfd:
+ bsc_unregister_fd(&rs->rtp.bfd);
+out_rtp_socket:
+ close(rs->rtp.bfd.fd);
+out_free:
+ talloc_free(rs);
+ DEBUGPC(DMUX, "failed\n");
+ return NULL;
+}
+
+static int rtp_sub_socket_bind(struct rtp_sub_socket *rss, u_int32_t ip,
+ u_int16_t port)
+{
+ int rc;
+ socklen_t alen = sizeof(rss->sin_local);
+
+ rss->sin_local.sin_family = AF_INET;
+ rss->sin_local.sin_addr.s_addr = htonl(ip);
+ rss->sin_local.sin_port = htons(port);
+ rss->bfd.when |= BSC_FD_READ;
+
+ rc = bind(rss->bfd.fd, (struct sockaddr *)&rss->sin_local,
+ sizeof(rss->sin_local));
+ if (rc < 0)
+ return rc;
+
+ /* retrieve the address we actually bound to, in case we
+ * passed INADDR_ANY as IP address */
+ return getsockname(rss->bfd.fd, (struct sockaddr *)&rss->sin_local,
+ &alen);
+}
+
+#define RTP_PORT_BASE 30000
+static unsigned int next_udp_port = RTP_PORT_BASE;
+
+/* bind a RTP socket to a local address */
+int rtp_socket_bind(struct rtp_socket *rs, u_int32_t ip)
+{
+ int rc = -EIO;
+ struct in_addr ia;
+
+ ia.s_addr = htonl(ip);
+ DEBUGP(DMUX, "rtp_socket_bind(rs=%p, IP=%s): ", rs,
+ inet_ntoa(ia));
+
+ /* try to bind to a consecutive pair of ports */
+ for (next_udp_port = next_udp_port % 0xffff;
+ next_udp_port < 0xffff; next_udp_port += 2) {
+ rc = rtp_sub_socket_bind(&rs->rtp, ip, next_udp_port);
+ if (rc != 0)
+ continue;
+
+ rc = rtp_sub_socket_bind(&rs->rtcp, ip, next_udp_port+1);
+ if (rc == 0)
+ break;
+ }
+ if (rc < 0) {
+ DEBUGPC(DMUX, "failed\n");
+ return rc;
+ }
+
+ ia.s_addr = rs->rtp.sin_local.sin_addr.s_addr;
+ DEBUGPC(DMUX, "BOUND_IP=%s, BOUND_PORT=%u\n",
+ inet_ntoa(ia), ntohs(rs->rtp.sin_local.sin_port));
+ return ntohs(rs->rtp.sin_local.sin_port);
+}
+
+static int rtp_sub_socket_connect(struct rtp_sub_socket *rss,
+ u_int32_t ip, u_int16_t port)
+{
+ int rc;
+ socklen_t alen = sizeof(rss->sin_local);
+
+ rss->sin_remote.sin_family = AF_INET;
+ rss->sin_remote.sin_addr.s_addr = htonl(ip);
+ rss->sin_remote.sin_port = htons(port);
+
+ rc = connect(rss->bfd.fd, (struct sockaddr *) &rss->sin_remote,
+ sizeof(rss->sin_remote));
+ if (rc < 0)
+ return rc;
+
+ return getsockname(rss->bfd.fd, (struct sockaddr *)&rss->sin_local,
+ &alen);
+}
+
+/* 'connect' a RTP socket to a remote peer */
+int rtp_socket_connect(struct rtp_socket *rs, u_int32_t ip, u_int16_t port)
+{
+ int rc;
+ struct in_addr ia;
+
+ ia.s_addr = htonl(ip);
+ DEBUGP(DMUX, "rtp_socket_connect(rs=%p, ip=%s, port=%u)\n",
+ rs, inet_ntoa(ia), port);
+
+ rc = rtp_sub_socket_connect(&rs->rtp, ip, port);
+ if (rc < 0)
+ return rc;
+
+ return rtp_sub_socket_connect(&rs->rtcp, ip, port+1);
+}
+
+/* bind two RTP/RTCP sockets together */
+int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other)
+{
+ DEBUGP(DMUX, "rtp_socket_proxy(this=%p, other=%p)\n",
+ this, other);
+
+ this->rx_action = RTP_PROXY;
+ this->proxy.other_sock = other;
+
+ other->rx_action = RTP_PROXY;
+ other->proxy.other_sock = this;
+
+ return 0;
+}
+
+static void free_tx_queue(struct rtp_sub_socket *rss)
+{
+ struct msgb *msg;
+
+ while ((msg = msgb_dequeue(&rss->tx_queue)))
+ msgb_free(msg);
+}
+
+int rtp_socket_free(struct rtp_socket *rs)
+{
+ DEBUGP(DMUX, "rtp_socket_free(rs=%p)\n", rs);
+
+ /* make sure we don't leave references dangling to us */
+ if (rs->rx_action == RTP_PROXY &&
+ rs->proxy.other_sock)
+ rs->proxy.other_sock->proxy.other_sock = NULL;
+
+ bsc_unregister_fd(&rs->rtp.bfd);
+ close(rs->rtp.bfd.fd);
+ free_tx_queue(&rs->rtp);
+
+ bsc_unregister_fd(&rs->rtcp.bfd);
+ close(rs->rtcp.bfd.fd);
+ free_tx_queue(&rs->rtcp);
+
+ talloc_free(rs);
+
+ return 0;
+}
diff --git a/openbsc/src/vty/command.c b/openbsc/src/vty/command.c
index 94a5c2af2..44bdf26e4 100644
--- a/openbsc/src/vty/command.c
+++ b/openbsc/src/vty/command.c
@@ -34,6 +34,7 @@ Boston, MA 02111-1307, USA. */
#include <ctype.h>
#include <time.h>
#include <sys/time.h>
+#include <sys/stat.h>
//#include "memory.h"
//#include "log.h"
@@ -45,6 +46,7 @@ Boston, MA 02111-1307, USA. */
//#include "workqueue.h"
#include <openbsc/gsm_data.h>
+#include <openbsc/gsm_subscriber.h>
/* Command vector which includes some level of command lists. Normally
each daemon maintains each own cmdvec. */
@@ -473,6 +475,7 @@ void install_element(enum node_type ntype, struct cmd_element *cmd)
cmd->cmdsize = cmd_cmdsize(cmd->strvec);
}
+#ifdef VTY_CRYPT_PW
static unsigned char itoa64[] =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@@ -498,6 +501,7 @@ static char *zencrypt(const char *passwd)
return crypt(passwd, salt);
}
+#endif
/* This function write configuration of this host. */
static int config_write_host(struct vty *vty)
@@ -2215,7 +2219,6 @@ cmd_execute_command_strict(vector vline, struct vty *vty,
return (*matched_element->func) (matched_element, vty, argc, argv);
}
-#if 0
/* Configration make from file. */
int config_from_file(struct vty *vty, FILE * fp)
{
@@ -2247,7 +2250,6 @@ int config_from_file(struct vty *vty, FILE * fp)
}
return CMD_SUCCESS;
}
-#endif
/* Configration from terminal */
DEFUN(config_terminal,
@@ -2444,7 +2446,6 @@ DEFUN(config_list, config_list_cmd, "list", "Print command list\n")
return CMD_SUCCESS;
}
-#if 0
/* Write current configuration into file. */
DEFUN(config_write_file,
config_write_file_cmd,
@@ -2548,7 +2549,7 @@ DEFUN(config_write_file,
if (chmod(config_file, CONFIGFILE_MASK) != 0) {
vty_out(vty, "Can't chmod configuration file %s: %s (%d).%s",
- config_file, safe_strerror(errno), errno, VTY_NEWLINE);
+ config_file, strerror(errno), errno, VTY_NEWLINE);
return CMD_WARNING;
}
@@ -2639,7 +2640,6 @@ ALIAS(config_write_terminal,
return CMD_SUCCESS;
}
-#endif
/* Hostname configuration */
DEFUN(config_hostname,
@@ -3328,13 +3328,11 @@ void install_default(enum node_type node)
install_element(node, &config_help_cmd);
install_element(node, &config_list_cmd);
-#if 0
install_element(node, &config_write_terminal_cmd);
install_element(node, &config_write_file_cmd);
install_element(node, &config_write_memory_cmd);
install_element(node, &config_write_cmd);
install_element(node, &show_running_config_cmd);
-#endif
}
/* Initialize command interface. Install basic nodes and commands. */
@@ -3378,9 +3376,9 @@ void cmd_init(int terminal)
install_default(ENABLE_NODE);
install_element(ENABLE_NODE, &config_disable_cmd);
install_element(ENABLE_NODE, &config_terminal_cmd);
- //install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
+ install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
}
- //install_element (ENABLE_NODE, &show_startup_config_cmd);
+ install_element (ENABLE_NODE, &show_startup_config_cmd);
install_element(ENABLE_NODE, &show_version_cmd);
if (terminal) {
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index 11b2ff60b..b480c3d63 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -157,6 +157,56 @@ DEFUN(show_bts, show_bts_cmd, "show bts [number]",
return CMD_SUCCESS;
}
+static void config_write_ts_single(struct vty *vty, struct gsm_bts_trx_ts *ts)
+{
+ vty_out(vty, "\t\tts %u%s", ts->nr, VTY_NEWLINE);
+ vty_out(vty, "\t\t\tphys_chan_config %s%s", gsm_pchan_name(ts->pchan),
+ VTY_NEWLINE);
+ vty_out(vty, "\t\t\te1_subslot %u %u %u%s", ts->e1_link.e1_nr,
+ ts->e1_link.e1_ts, ts->e1_link.e1_ts_ss, VTY_NEWLINE);
+}
+
+static void config_write_trx_single(struct vty *vty, struct gsm_bts_trx *trx)
+{
+ int i;
+
+ vty_out(vty, "\ttrx %u%s", trx->nr, VTY_NEWLINE);
+ vty_out(vty, "\t\tarfcn %u%s", trx->arfcn, VTY_NEWLINE);
+ vty_out(vty, "\t\tmax_power_red %u%s", trx->max_power_red, VTY_NEWLINE);
+
+ for (i = 0; i < TRX_NR_TS; i++)
+ config_write_ts_single(vty, &trx->ts[i]);
+}
+
+static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
+{
+ struct gsm_bts_trx *trx;
+
+ vty_out(vty, "bts %u%s", bts->nr, VTY_NEWLINE);
+ vty_out(vty, "\ttype %s%s", btstype2str(bts->type), VTY_NEWLINE);
+ vty_out(vty, "\tband %s%s", gsm_band_name(bts->band), VTY_NEWLINE);
+ vty_out(vty, "\tlocation_area_code %u%s", bts->location_area_code,
+ VTY_NEWLINE);
+ vty_out(vty, "\ttraining_sequence_code %u%s", bts->tsc, VTY_NEWLINE);
+ vty_out(vty, "\tbase_station_id_code %u%s", bts->bsic, VTY_NEWLINE);
+ vty_out(vty, "\tunit_id %u %u%s",
+ bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE);
+
+ llist_for_each_entry(trx, &bts->trx_list, list)
+ config_write_trx_single(vty, trx);
+}
+
+static int config_write_bts(struct vty *v)
+{
+ struct gsm_bts *bts;
+
+ llist_for_each_entry(bts, &gsmnet->bts_list, list)
+ config_write_bts_single(v, bts);
+
+ return CMD_SUCCESS;
+}
+
+
static void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx)
{
vty_out(vty, "TRX %u of BTS %u is on ARFCN %u%s",
@@ -224,6 +274,7 @@ DEFUN(show_trx,
return CMD_SUCCESS;
}
+
static void ts_dump_vty(struct vty *vty, struct gsm_bts_trx_ts *ts)
{
struct in_addr ia;
@@ -942,7 +993,7 @@ int bsc_vty_init(struct gsm_network *net)
install_element(VIEW_NODE, &show_subscr_cmd);
install_element(CONFIG_NODE, &cfg_bts_cmd);
- install_node(&bts_node, dummy_config_write);
+ install_node(&bts_node, config_write_bts);
install_default(BTS_NODE);
install_element(BTS_NODE, &cfg_bts_type_cmd);
install_element(BTS_NODE, &cfg_bts_band_cmd);
diff --git a/openbsc/tests/db/db_test.c b/openbsc/tests/db/db_test.c
index 6962aa3bf..a248e6025 100644
--- a/openbsc/tests/db/db_test.c
+++ b/openbsc/tests/db/db_test.c
@@ -66,32 +66,32 @@ int main() {
struct gsm_subscriber *alice_db;
char *alice_imsi = "3243245432345";
- alice = db_create_subscriber(alice_imsi);
+ alice = db_create_subscriber(NULL, alice_imsi);
db_sync_subscriber(alice);
- alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice->imsi);
+ alice_db = db_get_subscriber(NULL, GSM_SUBSCRIBER_IMSI, alice->imsi);
COMPARE(alice, alice_db);
subscr_put(alice_db);
subscr_put(alice);
alice_imsi = "3693245423445";
- alice = db_create_subscriber(alice_imsi);
+ alice = db_create_subscriber(NULL, alice_imsi);
db_subscriber_assoc_imei(alice, "1234567890");
db_subscriber_alloc_tmsi(alice);
alice->lac=42;
db_sync_subscriber(alice);
- alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice_imsi);
+ alice_db = db_get_subscriber(NULL, GSM_SUBSCRIBER_IMSI, alice_imsi);
COMPARE(alice, alice_db);
subscr_put(alice);
subscr_put(alice_db);
alice_imsi = "9993245423445";
- alice = db_create_subscriber(alice_imsi);
+ alice = db_create_subscriber(NULL, alice_imsi);
db_subscriber_alloc_tmsi(alice);
alice->lac=42;
db_sync_subscriber(alice);
db_subscriber_assoc_imei(alice, "1234567890");
db_subscriber_assoc_imei(alice, "6543560920");
- alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice_imsi);
+ alice_db = db_get_subscriber(NULL, GSM_SUBSCRIBER_IMSI, alice_imsi);
COMPARE(alice, alice_db);
subscr_put(alice);
subscr_put(alice_db);