aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2010-03-22 03:25:11 +0100
committerHolger Hans Peter Freyther <zecke@selfish.org>2010-03-24 06:16:04 +0100
commit22481bf76d129d3c41d20b96b6587ef085be485b (patch)
tree8c8de852e945dd5422a83bc7e0c37548d2911fe2 /openbsc
parentb973955295b720b8ba7c556d0165750ed9bfb381 (diff)
parent61b4232c6363ff9d78ef73b9dbf47ec16c94d610 (diff)
Merge remote branch 'origin/master' into on-waves/bsc-master
* Move to libosmocore * Move to new debugging architecture * Register the BTS types * Has only been compile tested Conflicts: openbsc/include/openbsc/Makefile.am openbsc/include/openbsc/gsm_data.h openbsc/include/openbsc/ipaccess.h openbsc/include/openbsc/mgcp.h openbsc/include/openbsc/msgb.h openbsc/include/openbsc/tlv.h openbsc/src/Makefile.am openbsc/src/abis_rsl.c openbsc/src/bsc_init.c openbsc/src/bsc_mgcp.c openbsc/src/chan_alloc.c openbsc/src/debug.c openbsc/src/gsm_subscriber_base.c openbsc/src/msgb.c openbsc/src/rest_octets.c openbsc/src/sccp/sccp.c openbsc/src/vty/command.c openbsc/src/vty_interface.c openbsc/tests/Makefile.am
Diffstat (limited to 'openbsc')
-rw-r--r--openbsc/.gitignore6
-rw-r--r--openbsc/AUTHORS2
-rw-r--r--openbsc/Makefile.am2
-rw-r--r--openbsc/README28
-rw-r--r--openbsc/configure.in5
-rw-r--r--openbsc/include/openbsc/Makefile.am20
-rw-r--r--openbsc/include/openbsc/abis_nm.h671
-rw-r--r--openbsc/include/openbsc/abis_rsl.h484
-rw-r--r--openbsc/include/openbsc/bitvec.h65
-rw-r--r--openbsc/include/openbsc/bsc_msc.h2
-rw-r--r--openbsc/include/openbsc/bsc_nat.h6
-rw-r--r--openbsc/include/openbsc/bssap.h2
-rw-r--r--openbsc/include/openbsc/chan_alloc.h14
-rw-r--r--openbsc/include/openbsc/db.h15
-rw-r--r--openbsc/include/openbsc/debug.h133
-rw-r--r--openbsc/include/openbsc/e1_input.h6
-rw-r--r--openbsc/include/openbsc/gsm_04_08.h746
-rw-r--r--openbsc/include/openbsc/gsm_04_11.h182
-rw-r--r--openbsc/include/openbsc/gsm_04_80.h125
-rw-r--r--openbsc/include/openbsc/gsm_data.h129
-rw-r--r--openbsc/include/openbsc/gsm_subscriber.h4
-rw-r--r--openbsc/include/openbsc/ipaccess.h55
-rw-r--r--openbsc/include/openbsc/linuxlist.h360
-rw-r--r--openbsc/include/openbsc/meas_rep.h1
-rw-r--r--openbsc/include/openbsc/mgcp.h81
-rw-r--r--openbsc/include/openbsc/mgcp_internal.h64
-rw-r--r--openbsc/include/openbsc/mncc.h66
-rw-r--r--openbsc/include/openbsc/msgb.h115
-rw-r--r--openbsc/include/openbsc/paging.h4
-rw-r--r--openbsc/include/openbsc/rtp_proxy.h4
-rw-r--r--openbsc/include/openbsc/select.h22
-rw-r--r--openbsc/include/openbsc/signal.h21
-rw-r--r--openbsc/include/openbsc/silent_call.h5
-rw-r--r--openbsc/include/openbsc/subchan_demux.h2
-rw-r--r--openbsc/include/openbsc/talloc.h192
-rw-r--r--openbsc/include/openbsc/telnet_interface.h5
-rw-r--r--openbsc/include/openbsc/timer.h72
-rw-r--r--openbsc/include/openbsc/tlv.h234
-rw-r--r--openbsc/include/openbsc/transaction.h2
-rw-r--r--openbsc/include/openbsc/ussd.h2
-rw-r--r--openbsc/include/sccp/Makefile.am3
-rw-r--r--openbsc/include/sccp/sccp.h4
-rw-r--r--openbsc/include/sccp/sccp_types.h20
-rw-r--r--openbsc/include/vty/command.h2
-rw-r--r--openbsc/include/vty/vector.h2
-rw-r--r--openbsc/libsccp.pc.in10
-rw-r--r--openbsc/openbsc.pc.in2
-rw-r--r--openbsc/src/Makefile.am37
-rw-r--r--openbsc/src/abis_nm.c364
-rw-r--r--openbsc/src/abis_rsl.c417
-rw-r--r--openbsc/src/bitvec.c170
-rw-r--r--openbsc/src/bs11_config.c74
-rw-r--r--openbsc/src/bsc_hack.c57
-rw-r--r--openbsc/src/bsc_init.c31
-rw-r--r--openbsc/src/bsc_mgcp.c1237
-rw-r--r--openbsc/src/bsc_msc_ip.c27
-rw-r--r--openbsc/src/bsc_rll.c6
-rw-r--r--openbsc/src/bssap.c13
-rw-r--r--openbsc/src/bts_ipaccess_nanobts.c84
-rw-r--r--openbsc/src/bts_siemens_bs11.c66
-rw-r--r--openbsc/src/bts_unknown.c (renamed from openbsc/include/openbsc/gsm_utils.h)35
-rw-r--r--openbsc/src/chan_alloc.c91
-rw-r--r--openbsc/src/db.c466
-rw-r--r--openbsc/src/debug.c329
-rw-r--r--openbsc/src/e1_config.c2
-rw-r--r--openbsc/src/e1_input.c20
-rw-r--r--openbsc/src/gsm_04_08.c903
-rw-r--r--openbsc/src/gsm_04_08_utils.c230
-rw-r--r--openbsc/src/gsm_04_11.c137
-rw-r--r--openbsc/src/gsm_04_80.c6
-rw-r--r--openbsc/src/gsm_data.c195
-rw-r--r--openbsc/src/gsm_subscriber.c11
-rw-r--r--openbsc/src/gsm_subscriber_base.c7
-rw-r--r--openbsc/src/gsm_utils.c202
-rw-r--r--openbsc/src/handover_decision.c6
-rw-r--r--openbsc/src/handover_logic.c28
-rw-r--r--openbsc/src/input/ipaccess.c60
-rw-r--r--openbsc/src/input/misdn.c6
-rw-r--r--openbsc/src/ipaccess-config.c381
-rw-r--r--openbsc/src/ipaccess/ipaccess-config.c667
-rw-r--r--openbsc/src/ipaccess/ipaccess-find.c (renamed from openbsc/src/ipaccess-find.c)4
-rw-r--r--openbsc/src/ipaccess/ipaccess-firmware.c123
-rw-r--r--openbsc/src/ipaccess/ipaccess-proxy.c1127
-rw-r--r--openbsc/src/mgcp/mgcp_main.c216
-rw-r--r--openbsc/src/mgcp/mgcp_network.c255
-rw-r--r--openbsc/src/mgcp/mgcp_protocol.c745
-rw-r--r--openbsc/src/mgcp/mgcp_vty.c339
-rw-r--r--openbsc/src/mncc.c2
-rw-r--r--openbsc/src/msgb.c104
-rw-r--r--openbsc/src/nat/bsc_filter.c3
-rw-r--r--openbsc/src/nat/bsc_nat.c18
-rw-r--r--openbsc/src/nat/bsc_nat_vty.c3
-rw-r--r--openbsc/src/paging.c15
-rw-r--r--openbsc/src/rest_octets.c12
-rw-r--r--openbsc/src/rrlp.c8
-rw-r--r--openbsc/src/rs232.c4
-rw-r--r--openbsc/src/rtp_proxy.c19
-rw-r--r--openbsc/src/sccp/sccp.c35
-rw-r--r--openbsc/src/select.c118
-rw-r--r--openbsc/src/signal.c83
-rw-r--r--openbsc/src/silent_call.c56
-rw-r--r--openbsc/src/subchan_demux.c2
-rw-r--r--openbsc/src/system_information.c63
-rw-r--r--openbsc/src/talloc.c1805
-rw-r--r--openbsc/src/talloc_ctx.c6
-rw-r--r--openbsc/src/telnet_interface.c14
-rw-r--r--openbsc/src/timer.c185
-rw-r--r--openbsc/src/tlv_parser.c157
-rw-r--r--openbsc/src/token_auth.c6
-rw-r--r--openbsc/src/transaction.c13
-rw-r--r--openbsc/src/trau_mux.c2
-rw-r--r--openbsc/src/vty/buffer.c2
-rw-r--r--openbsc/src/vty/command.c46
-rw-r--r--openbsc/src/vty/vector.c14
-rw-r--r--openbsc/src/vty/vty.c4
-rw-r--r--openbsc/src/vty_interface.c447
-rw-r--r--openbsc/src/vty_interface_layer3.c204
-rw-r--r--openbsc/tests/Makefile.am2
-rw-r--r--openbsc/tests/bsc-nat/Makefile.am4
-rw-r--r--openbsc/tests/channel/Makefile.am10
-rw-r--r--openbsc/tests/channel/channel_test.c4
-rw-r--r--openbsc/tests/db/Makefile.am4
-rw-r--r--openbsc/tests/debug/Makefile.am4
-rw-r--r--openbsc/tests/debug/debug_test.c21
-rw-r--r--openbsc/tests/gsm0408/Makefile.am3
-rw-r--r--openbsc/tests/gsm0408/gsm0408_test.c8
-rw-r--r--openbsc/tests/sccp/Makefile.am4
-rw-r--r--openbsc/tests/sccp/sccp_test.c108
-rw-r--r--openbsc/tests/sms/Makefile.am5
-rw-r--r--openbsc/tests/sms/sms_test.c53
-rw-r--r--openbsc/tests/timer/Makefile.am5
-rw-r--r--openbsc/tests/timer/timer_test.c70
-rwxr-xr-xopenbsc/tools/hlrstat.pl25
133 files changed, 6946 insertions, 10005 deletions
diff --git a/openbsc/.gitignore b/openbsc/.gitignore
index 7b7b11a1e..267c906ec 100644
--- a/openbsc/.gitignore
+++ b/openbsc/.gitignore
@@ -3,8 +3,12 @@
.deps
Makefile
Makefile.in
+bscconfig.h
+bscconfig.h.in
+openbsc.pc
bsc_hack
bsc_msc_ip
+bsc_mgcp
*.*~
*.sw?
@@ -26,6 +30,8 @@ hlr.sqlite3
bs11_config
ipaccess-config
ipaccess-find
+ipaccess-firmware
+ipaccess-proxy
isdnsync
#tests
diff --git a/openbsc/AUTHORS b/openbsc/AUTHORS
index 1a74f5102..daf60e447 100644
--- a/openbsc/AUTHORS
+++ b/openbsc/AUTHORS
@@ -3,3 +3,5 @@ Holger Freyther <zecke@selfish.org>
Jan Luebbe <jluebbe@debian.org>
Stefan Schmidt <stefan@datenfreihafen.org>
Daniel Willmann <daniel@totalueberwachung.de>
+Andreas Eversberg <Andreas.Eversberg@versatel.de>
+Sylvain Munaut <246tnt@gmail.com>
diff --git a/openbsc/Makefile.am b/openbsc/Makefile.am
index deaba0fa1..7acae7512 100644
--- a/openbsc/Makefile.am
+++ b/openbsc/Makefile.am
@@ -4,7 +4,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include
SUBDIRS = include src tests
pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = openbsc.pc
+pkgconfig_DATA = openbsc.pc libsccp.pc
#dist-hook:
# rm -rf `find $(distdir) -name .svn`
diff --git a/openbsc/README b/openbsc/README
index 88715f50a..51807bb44 100644
--- a/openbsc/README
+++ b/openbsc/README
@@ -1,18 +1,30 @@
About OpenBSC
=============
-OpenBSC is a minimalistic implementation of the GSM Network, with particular
-emphasis on the functionality typically provided by the BSC, MSC, HLR, VLR.
+OpenBSC is a minimalistic implementation of the GSM Network, with
+particular emphasis on the functionality typically provided by the BSC,
+MSC, HLR, VLR and SMSC.
-Its only current interface is a mISDN based E1 interface utilizing the A-bis
-protocol between BSC and BTS. In other words, you can connect an existing
-GSM Base Transceiver Station (BTS) through E1 to OpenBSC.
+Its currently supported interfaces towards the BTS are:
-So far, it has only been tested with the Siemens microBTS BS-11. Test reports
-with other BTS are appreciated!
+ * Classic A-bis over E1 using a mISDN based E1 interface. In other
+ words, you can connect existing GSM Base Transceiver Station (BTS)
+ through E1 to OpenBSC. So far, we have only tested the Siemens BS-11
+ Test reports with other BTS are much appreciated!
+
+ * A-bis over IP as used by the ip.access nanoBTS product family
This project is still in its early days, and there are lots of areas where it
doesn't behave as per GSM spec.
-December 29, 2008
Harald Welte <laforge@gnumonks.org>
+
+
+libosmocore
+===========
+
+Please note that as of March 2010, OpenBSC has a dependency to a library
+called "libosmocore". You can obtain that library from
+
+ git://git.osmocom.org/libosmocore.git
+
diff --git a/openbsc/configure.in b/openbsc/configure.in
index c9ae025aa..a8dbb72ef 100644
--- a/openbsc/configure.in
+++ b/openbsc/configure.in
@@ -16,6 +16,8 @@ dnl checks for libraries
AC_SEARCH_LIBS(crypt, crypt,
[LIBCRYPT="-lcrypt"; AC_DEFINE([VTY_CRYPT_PW], [], [Use crypt functionality of vty.])])
+PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore)
+
dnl checks for header files
AC_HEADER_STDC
@@ -38,6 +40,7 @@ AM_CONFIG_HEADER(bscconfig.h)
AC_OUTPUT(
openbsc.pc
+ libsccp.pc
include/openbsc/Makefile
include/vty/Makefile
include/sccp/Makefile
@@ -45,8 +48,6 @@ AC_OUTPUT(
src/Makefile
tests/Makefile
tests/debug/Makefile
- tests/timer/Makefile
- tests/sms/Makefile
tests/gsm0408/Makefile
tests/db/Makefile
tests/channel/Makefile
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index f5cf63941..eb9007f51 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -1,8 +1,12 @@
-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 rtp_proxy.h \
- bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h \
- silent_call.h mgcp.h meas_rep.h bitvec.h rest_octets.h \
- system_information.h handover.h bssap.h bsc_msc.h bsc_nat.h
+noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \
+ gsm_subscriber.h gsm_04_11.h debug.h signal.h \
+ misdn.h chan_alloc.h telnet_interface.h paging.h \
+ subchan_demux.h trau_frame.h e1_input.h trau_mux.h \
+ ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \
+ bsc_rll.h mncc.h transaction.h ussd.h gsm_04_80.h \
+ silent_call.h mgcp.h meas_rep.h rest_octets.h \
+ system_information.h handover.h mgcp_internal.h \
+ bssap.h bsc_msc.h bsc_nat.h
+
+openbsc_HEADERS = gsm_04_08.h meas_rep.h
+openbscdir = $(includedir)/openbsc
diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h
index 00697a384..cff91e0a0 100644
--- a/openbsc/include/openbsc/abis_nm.h
+++ b/openbsc/include/openbsc/abis_nm.h
@@ -24,665 +24,8 @@
#define _NM_H
#include <sys/types.h>
-
-#include <openbsc/tlv.h>
-
-/* PRIVATE */
-
-/* generic header in front of every OML message according to TS 08.59 */
-struct abis_om_hdr {
- u_int8_t mdisc;
- u_int8_t placement;
- u_int8_t sequence;
- u_int8_t length;
- u_int8_t data[0];
-} __attribute__ ((packed));
-
-#define ABIS_OM_MDISC_FOM 0x80
-#define ABIS_OM_MDISC_MMI 0x40
-#define ABIS_OM_MDISC_TRAU 0x20
-#define ABIS_OM_MDISC_MANUF 0x10
-#define ABIS_OM_PLACEMENT_ONLY 0x80
-#define ABIS_OM_PLACEMENT_FIRST 0x40
-#define ABIS_OM_PLACEMENT_MIDDLE 0x20
-#define ABIS_OM_PLACEMENT_LAST 0x10
-
-struct abis_om_obj_inst {
- u_int8_t bts_nr;
- u_int8_t trx_nr;
- u_int8_t ts_nr;
-} __attribute__ ((packed));
-
-struct abis_om_fom_hdr {
- u_int8_t msg_type;
- u_int8_t obj_class;
- struct abis_om_obj_inst obj_inst;
- u_int8_t data[0];
-} __attribute__ ((packed));
-
-#define ABIS_OM_FOM_HDR_SIZE (sizeof(struct abis_om_hdr) + sizeof(struct abis_om_fom_hdr))
-
-/* Section 9.1: Message Types */
-enum abis_nm_msgtype {
- /* SW Download Management Messages */
- NM_MT_LOAD_INIT = 0x01,
- NM_MT_LOAD_INIT_ACK,
- NM_MT_LOAD_INIT_NACK,
- NM_MT_LOAD_SEG,
- NM_MT_LOAD_SEG_ACK,
- NM_MT_LOAD_ABORT,
- NM_MT_LOAD_END,
- NM_MT_LOAD_END_ACK,
- NM_MT_LOAD_END_NACK,
- NM_MT_SW_ACT_REQ, /* BTS->BSC */
- NM_MT_SW_ACT_REQ_ACK,
- NM_MT_SW_ACT_REQ_NACK,
- NM_MT_ACTIVATE_SW, /* BSC->BTS */
- NM_MT_ACTIVATE_SW_ACK,
- NM_MT_ACTIVATE_SW_NACK,
- NM_MT_SW_ACTIVATED_REP, /* 0x10 */
- /* A-bis Interface Management Messages */
- NM_MT_ESTABLISH_TEI = 0x21,
- NM_MT_ESTABLISH_TEI_ACK,
- NM_MT_ESTABLISH_TEI_NACK,
- NM_MT_CONN_TERR_SIGN,
- NM_MT_CONN_TERR_SIGN_ACK,
- NM_MT_CONN_TERR_SIGN_NACK,
- NM_MT_DISC_TERR_SIGN,
- NM_MT_DISC_TERR_SIGN_ACK,
- NM_MT_DISC_TERR_SIGN_NACK,
- NM_MT_CONN_TERR_TRAF,
- NM_MT_CONN_TERR_TRAF_ACK,
- NM_MT_CONN_TERR_TRAF_NACK,
- NM_MT_DISC_TERR_TRAF,
- NM_MT_DISC_TERR_TRAF_ACK,
- NM_MT_DISC_TERR_TRAF_NACK,
- /* Transmission Management Messages */
- NM_MT_CONN_MDROP_LINK = 0x31,
- NM_MT_CONN_MDROP_LINK_ACK,
- NM_MT_CONN_MDROP_LINK_NACK,
- NM_MT_DISC_MDROP_LINK,
- NM_MT_DISC_MDROP_LINK_ACK,
- NM_MT_DISC_MDROP_LINK_NACK,
- /* Air Interface Management Messages */
- NM_MT_SET_BTS_ATTR = 0x41,
- NM_MT_SET_BTS_ATTR_ACK,
- NM_MT_SET_BTS_ATTR_NACK,
- NM_MT_SET_RADIO_ATTR,
- NM_MT_SET_RADIO_ATTR_ACK,
- NM_MT_SET_RADIO_ATTR_NACK,
- NM_MT_SET_CHAN_ATTR,
- NM_MT_SET_CHAN_ATTR_ACK,
- NM_MT_SET_CHAN_ATTR_NACK,
- /* Test Management Messages */
- NM_MT_PERF_TEST = 0x51,
- NM_MT_PERF_TEST_ACK,
- NM_MT_PERF_TEST_NACK,
- NM_MT_TEST_REP,
- NM_MT_SEND_TEST_REP,
- NM_MT_SEND_TEST_REP_ACK,
- NM_MT_SEND_TEST_REP_NACK,
- NM_MT_STOP_TEST,
- NM_MT_STOP_TEST_ACK,
- NM_MT_STOP_TEST_NACK,
- /* State Management and Event Report Messages */
- NM_MT_STATECHG_EVENT_REP = 0x61,
- NM_MT_FAILURE_EVENT_REP,
- NM_MT_STOP_EVENT_REP,
- NM_MT_STOP_EVENT_REP_ACK,
- NM_MT_STOP_EVENT_REP_NACK,
- NM_MT_REST_EVENT_REP,
- NM_MT_REST_EVENT_REP_ACK,
- NM_MT_REST_EVENT_REP_NACK,
- NM_MT_CHG_ADM_STATE,
- NM_MT_CHG_ADM_STATE_ACK,
- NM_MT_CHG_ADM_STATE_NACK,
- NM_MT_CHG_ADM_STATE_REQ,
- NM_MT_CHG_ADM_STATE_REQ_ACK,
- NM_MT_CHG_ADM_STATE_REQ_NACK,
- NM_MT_REP_OUTST_ALARMS = 0x93,
- NM_MT_REP_OUTST_ALARMS_ACK,
- NM_MT_REP_OUTST_ALARMS_NACK,
- /* Equipment Management Messages */
- NM_MT_CHANGEOVER = 0x71,
- NM_MT_CHANGEOVER_ACK,
- NM_MT_CHANGEOVER_NACK,
- NM_MT_OPSTART,
- NM_MT_OPSTART_ACK,
- NM_MT_OPSTART_NACK,
- NM_MT_REINIT,
- NM_MT_REINIT_ACK,
- NM_MT_REINIT_NACK,
- NM_MT_SET_SITE_OUT, /* BS11: get alarm ?!? */
- NM_MT_SET_SITE_OUT_ACK,
- NM_MT_SET_SITE_OUT_NACK,
- NM_MT_CHG_HW_CONF = 0x90,
- NM_MT_CHG_HW_CONF_ACK,
- NM_MT_CHG_HW_CONF_NACK,
- /* Measurement Management Messages */
- NM_MT_MEAS_RES_REQ = 0x8a,
- NM_MT_MEAS_RES_RESP,
- NM_MT_STOP_MEAS,
- NM_MT_START_MEAS,
- /* Other Messages */
- NM_MT_GET_ATTR = 0x81,
- NM_MT_GET_ATTR_RESP,
- NM_MT_GET_ATTR_NACK,
- NM_MT_SET_ALARM_THRES,
- NM_MT_SET_ALARM_THRES_ACK,
- NM_MT_SET_ALARM_THRES_NACK,
-};
-
-enum abis_nm_msgtype_bs11 {
- NM_MT_BS11_RESET_RESOURCE = 0x74,
-
- NM_MT_BS11_BEGIN_DB_TX = 0xa3,
- NM_MT_BS11_BEGIN_DB_TX_ACK,
- NM_MT_BS11_BEGIN_DB_TX_NACK,
- NM_MT_BS11_END_DB_TX = 0xa6,
- NM_MT_BS11_END_DB_TX_ACK,
- NM_MT_BS11_END_DB_TX_NACK,
- NM_MT_BS11_CREATE_OBJ = 0xa9,
- NM_MT_BS11_CREATE_OBJ_ACK,
- NM_MT_BS11_CREATE_OBJ_NACK,
- NM_MT_BS11_DELETE_OBJ = 0xac,
- NM_MT_BS11_DELETE_OBJ_ACK,
- NM_MT_BS11_DELETE_OBJ_NACK,
-
- NM_MT_BS11_SET_ATTR = 0xd0,
- NM_MT_BS11_SET_ATTR_ACK,
- NM_MT_BS11_SET_ATTR_NACK,
- NM_MT_BS11_LMT_SESSION = 0xdc,
-
- NM_MT_BS11_GET_STATE = 0xe3,
- NM_MT_BS11_GET_STATE_ACK,
- NM_MT_BS11_LMT_LOGON = 0xe5,
- NM_MT_BS11_LMT_LOGON_ACK,
- NM_MT_BS11_RESTART = 0xe7,
- NM_MT_BS11_RESTART_ACK,
- NM_MT_BS11_DISCONNECT = 0xe9,
- NM_MT_BS11_DISCONNECT_ACK,
- NM_MT_BS11_LMT_LOGOFF = 0xec,
- NM_MT_BS11_LMT_LOGOFF_ACK,
- NM_MT_BS11_RECONNECT = 0xf1,
- NM_MT_BS11_RECONNECT_ACK,
-};
-
-enum abis_nm_msgtype_ipacc {
- NM_MT_IPACC_RESTART = 0x87,
- NM_MT_IPACC_RESTART_ACK,
- NM_MT_IPACC_RSL_CONNECT = 0xe0,
- NM_MT_IPACC_RSL_CONNECT_ACK,
- NM_MT_IPACC_RSL_CONNECT_NACK,
- NM_MT_IPACC_RSL_DISCONNECT = 0xe3,
- NM_MT_IPACC_RSL_DISCONNECT_ACK,
- NM_MT_IPACC_RSL_DISCONNECT_NACK,
- NM_MT_IPACC_CONN_TRAF = 0xe6,
- NM_MT_IPACC_CONN_TRAF_ACK,
- NM_MT_IPACC_CONN_TRAF_NACK,
- NM_MT_IPACC_DEF_BOOT_SW = 0xec,
- NM_MT_IPACC_DEF_BOOT_SW_ACK,
- MN_MT_IPACC_DEF_BOOT_SW_NACK,
- NM_MT_IPACC_SET_NVATTR = 0xef,
- NM_MT_IPACC_SET_NVATTR_ACK,
- NM_MT_IPACC_SET_NVATTR_NACK,
- NM_MT_IPACC_GET_NVATTR = 0xf2,
- NM_MT_IPACC_GET_NVATTR_ACK,
- NM_MT_IPACC_GET_NVATTR_NACK,
- NM_MT_IPACC_SET_ATTR = 0xf5,
- NM_MT_IPACC_SET_ATTR_ACK,
- NM_MT_IPACC_SET_ATTR_NACK,
-};
-
-enum abis_nm_bs11_cell_alloc {
- NM_BS11_CANR_GSM = 0x00,
- NM_BS11_CANR_DCS1800 = 0x01,
-};
-
-/* Section 9.2: Object Class */
-enum abis_nm_obj_class {
- NM_OC_SITE_MANAGER = 0x00,
- NM_OC_BTS,
- NM_OC_RADIO_CARRIER,
- NM_OC_CHANNEL,
- NM_OC_BASEB_TRANSC,
- /* RFU: 05-FE */
-
- NM_OC_IPAC_E1_TRUNK = 0x0e,
- NM_OC_IPAC_E1_PORT = 0x0f,
- NM_OC_IPAC_E1_CHAN = 0x10,
- NM_OC_IPAC_CLK_MODULE = 0x22,
-
- NM_OC_BS11_ADJC = 0xa0,
- NM_OC_BS11_HANDOVER = 0xa1,
- NM_OC_BS11_PWR_CTRL = 0xa2,
- NM_OC_BS11_BTSE = 0xa3, /* LMT? */
- NM_OC_BS11_RACK = 0xa4,
- NM_OC_BS11 = 0xa5, /* 01: ALCO */
- NM_OC_BS11_TEST = 0xa6,
- NM_OC_BS11_ENVABTSE = 0xa8,
- NM_OC_BS11_BPORT = 0xa9,
-
- NM_OC_GPRS_NSE = 0xf0,
- NM_OC_GPRS_CELL = 0xf1,
- NM_OC_GPRS_NSVC = 0xf2,
-
- NM_OC_NULL = 0xff,
-};
-
-/* Section 9.4: Attributes */
-enum abis_nm_attr {
- NM_ATT_ABIS_CHANNEL = 0x01,
- NM_ATT_ADD_INFO,
- NM_ATT_ADD_TEXT,
- NM_ATT_ADM_STATE,
- NM_ATT_ARFCN_LIST,
- NM_ATT_AUTON_REPORT,
- NM_ATT_AVAIL_STATUS,
- NM_ATT_BCCH_ARFCN,
- NM_ATT_BSIC,
- NM_ATT_BTS_AIR_TIMER,
- NM_ATT_CCCH_L_I_P,
- NM_ATT_CCCH_L_T,
- NM_ATT_CHAN_COMB,
- NM_ATT_CONN_FAIL_CRIT,
- NM_ATT_DEST,
- /* res */
- NM_ATT_EVENT_TYPE = 0x11, /* BS11: file data ?!? */
- NM_ATT_FILE_ID,
- NM_ATT_FILE_VERSION,
- NM_ATT_GSM_TIME,
- NM_ATT_HSN,
- NM_ATT_HW_CONFIG,
- NM_ATT_HW_DESC,
- NM_ATT_INTAVE_PARAM,
- NM_ATT_INTERF_BOUND,
- NM_ATT_LIST_REQ_ATTR,
- NM_ATT_MAIO,
- NM_ATT_MANUF_STATE,
- NM_ATT_MANUF_THRESH,
- NM_ATT_MANUF_ID,
- NM_ATT_MAX_TA,
- NM_ATT_MDROP_LINK, /* 0x20 */
- NM_ATT_MDROP_NEXT,
- NM_ATT_NACK_CAUSES,
- NM_ATT_NY1,
- NM_ATT_OPER_STATE,
- NM_ATT_OVERL_PERIOD,
- NM_ATT_PHYS_CONF,
- NM_ATT_POWER_CLASS,
- NM_ATT_POWER_THRESH,
- NM_ATT_PROB_CAUSE,
- NM_ATT_RACH_B_THRESH,
- NM_ATT_LDAVG_SLOTS,
- NM_ATT_RAD_SUBC,
- NM_ATT_RF_MAXPOWR_R,
- NM_ATT_SITE_INPUTS,
- NM_ATT_SITE_OUTPUTS,
- NM_ATT_SOURCE, /* 0x30 */
- NM_ATT_SPEC_PROB,
- NM_ATT_START_TIME,
- NM_ATT_T200,
- NM_ATT_TEI,
- NM_ATT_TEST_DUR,
- NM_ATT_TEST_NO,
- NM_ATT_TEST_REPORT,
- NM_ATT_VSWR_THRESH,
- NM_ATT_WINDOW_SIZE,
- /* Res */
- NM_ATT_BS11_RSSI_OFFS = 0x3d,
- NM_ATT_BS11_TXPWR = 0x3e,
- NM_ATT_BS11_DIVERSITY = 0x3f,
- /* Res */
- NM_ATT_TSC = 0x40,
- NM_ATT_SW_CONFIG,
- NM_ATT_SW_DESCR,
- NM_ATT_SEVERITY,
- NM_ATT_GET_ARI,
- NM_ATT_HW_CONF_CHG,
- NM_ATT_OUTST_ALARM,
- NM_ATT_FILE_DATA,
- NM_ATT_MEAS_RES,
- NM_ATT_MEAS_TYPE,
-
- NM_ATT_BS11_ESN_FW_CODE_NO = 0x4c,
- NM_ATT_BS11_ESN_HW_CODE_NO = 0x4f,
-
- NM_ATT_BS11_ESN_PCB_SERIAL = 0x55,
- NM_ATT_BS11_EXCESSIVE_DISTANCE = 0x58,
-
- NM_ATT_BS11_ALL_TEST_CATG = 0x60,
- NM_ATT_BS11_BTSLS_HOPPING,
- NM_ATT_BS11_CELL_ALLOC_NR,
- NM_ATT_BS11_CELL_GLOBAL_ID,
- NM_ATT_BS11_ENA_INTERF_CLASS = 0x66,
- NM_ATT_BS11_ENA_INT_INTEC_HANDO = 0x67,
- NM_ATT_BS11_ENA_INT_INTRC_HANDO = 0x68,
- NM_ATT_BS11_ENA_MS_PWR_CTRL = 0x69,
- NM_ATT_BS11_ENA_PWR_BDGT_HO = 0x6a,
- NM_ATT_BS11_ENA_PWR_CTRL_RLFW = 0x6b,
- NM_ATT_BS11_ENA_RXLEV_HO = 0x6c,
- NM_ATT_BS11_ENA_RXQUAL_HO = 0x6d,
- NM_ATT_BS11_FACCH_QUAL = 0x6e,
-
- NM_ATT_IPACC_DST_IP = 0x80,
- NM_ATT_IPACC_DST_IP_PORT = 0x81,
- NM_ATT_IPACC_SSRC = 0x82,
- NM_ATT_IPACC_RTP_PAYLD_TYPE = 0x83,
- NM_ATT_IPACC_BASEB_ID = 0x84,
- NM_ATT_IPACC_STREAM_ID = 0x85,
- NM_ATT_IPACC_NV_FLAGS = 0x86,
- NM_ATT_IPACC_FREQ_CTRL = 0x87,
- NM_ATT_IPACC_PRIM_OML_CFG = 0x88,
- NM_ATT_IPACC_SEC_OML_CFG = 0x89,
- NM_ATT_IPACC_IP_IF_CFG = 0x8a, /* IP interface */
- NM_ATT_IPACC_IP_GW_CFG = 0x8b, /* IP gateway */
- NM_ATT_IPACC_IN_SERV_TIME = 0x8c,
- NM_ATT_IPACC_TRX_BTS_ASS = 0x8d,
- NM_ATT_IPACC_LOCATION = 0x8e, /* string describing location */
- NM_ATT_IPACC_PAGING_CFG = 0x8f,
- NM_ATT_IPACC_FILE_DATA = 0x90,
- NM_ATT_IPACC_UNIT_ID = 0x91, /* Site/BTS/TRX */
- NM_ATT_IPACC_PARENT_UNIT_ID = 0x92,
- NM_ATT_IPACC_UNIT_NAME = 0x93, /* default: nbts-<mac-as-string> */
- NM_ATT_IPACC_SNMP_CFG = 0x94,
- NM_ATT_IPACC_PRIM_OML_CFG_LIST = 0x95,
- NM_ATT_IPACC_PRIM_OML_FB_TOUT = 0x96,
- NM_ATT_IPACC_CUR_SW_CFG = 0x97,
- NM_ATT_IPACC_TIMING_BUS = 0x98,
- NM_ATT_IPACC_CGI = 0x99,
- NM_ATT_IPACC_RAC = 0x9a,
- NM_ATT_IPACC_OBJ_VERSION = 0x9b,
- NM_ATT_IPACC_GPRS_PAGING_CFG = 0x9c,
- NM_ATT_IPACC_NSEI = 0x9d,
- NM_ATT_IPACC_BVCI = 0x9e,
- NM_ATT_IPACC_NSVCI = 0x9f,
- NM_ATT_IPACC_NS_CFG = 0xa0,
- NM_ATT_IPACC_BSSGP_CFG = 0xa1,
- NM_ATT_IPACC_NS_LINK_CFG = 0xa2,
- NM_ATT_IPACC_RLC_CFG = 0xa3,
- NM_ATT_IPACC_ALM_THRESH_LIST = 0xa4,
- NM_ATT_IPACC_MONIT_VAL_LIST = 0xa5,
- NM_ATT_IPACC_TIB_CONTROL = 0xa6,
- NM_ATT_IPACC_SUPP_FEATURES = 0xa7,
- NM_ATT_IPACC_CODING_SCHEMES = 0xa8,
- NM_ATT_IPACC_RLC_CFG_2 = 0xa9,
- NM_ATT_IPACC_HEARTB_TOUT = 0xaa,
- NM_ATT_IPACC_UPTIME = 0xab,
- NM_ATT_IPACC_RLC_CFG_3 = 0xac,
- NM_ATT_IPACC_SSL_CFG = 0xad,
- NM_ATT_IPACC_SEC_POSSIBLE = 0xae,
- NM_ATT_IPACC_IML_SSL_STATE = 0xaf,
- NM_ATT_IPACC_REVOC_DATE = 0xb0,
-
-
- NM_ATT_BS11_RF_RES_IND_PER = 0x8f,
-
- NM_ATT_BS11_RX_LEV_MIN_CELL = 0x90,
- NM_ATT_BS11_ABIS_EXT_TIME = 0x91,
- NM_ATT_BS11_TIMER_HO_REQUEST = 0x92,
- NM_ATT_BS11_TIMER_NCELL = 0x93,
- NM_ATT_BS11_TSYNC = 0x94,
- NM_ATT_BS11_TTRAU = 0x95,
- NM_ATT_BS11_EMRG_CFG_MEMBER = 0x9b,
- NM_ATT_BS11_TRX_AREA = 0x9f,
-
- NM_ATT_BS11_BCCH_RECONF = 0xd7,
- NM_ATT_BS11_BIT_ERR_THESH = 0xa0,
- NM_ATT_BS11_BOOT_SW_VERS = 0xa1,
- NM_ATT_BS11_CCLK_ACCURACY = 0xa3,
- NM_ATT_BS11_CCLK_TYPE = 0xa4,
- NM_ATT_BS11_INP_IMPEDANCE = 0xaa,
- NM_ATT_BS11_L1_PROT_TYPE = 0xab,
- NM_ATT_BS11_LINE_CFG = 0xac,
- NM_ATT_BS11_LI_PORT_1 = 0xad,
- NM_ATT_BS11_LI_PORT_2 = 0xae,
-
- NM_ATT_BS11_L1_REM_ALM_TYPE = 0xb0,
- NM_ATT_BS11_SW_LOAD_INTENDED = 0xbb,
- NM_ATT_BS11_SW_LOAD_SAFETY = 0xbc,
- NM_ATT_BS11_SW_LOAD_STORED = 0xbd,
-
- NM_ATT_BS11_VENDOR_NAME = 0xc1,
- NM_ATT_BS11_HOPPING_MODE = 0xc5,
- NM_ATT_BS11_LMT_LOGON_SESSION = 0xc6,
- NM_ATT_BS11_LMT_LOGIN_TIME = 0xc7,
- NM_ATT_BS11_LMT_USER_ACC_LEV = 0xc8,
- NM_ATT_BS11_LMT_USER_NAME = 0xc9,
-
- NM_ATT_BS11_L1_CONTROL_TS = 0xd8,
- NM_ATT_BS11_RADIO_MEAS_GRAN = 0xdc, /* in SACCH multiframes */
- NM_ATT_BS11_RADIO_MEAS_REP = 0xdd,
-
- NM_ATT_BS11_SH_LAPD_INT_TIMER = 0xe8,
-
- NM_ATT_BS11_BTS_STATE = 0xf0,
- NM_ATT_BS11_E1_STATE = 0xf1,
- NM_ATT_BS11_PLL = 0xf2,
- NM_ATT_BS11_RX_OFFSET = 0xf3,
- NM_ATT_BS11_ANT_TYPE = 0xf4,
- NM_ATT_BS11_PLL_MODE = 0xfc,
- NM_ATT_BS11_PASSWORD = 0xfd,
-};
-#define NM_ATT_BS11_FILE_DATA NM_ATT_EVENT_TYPE
-
-/* Section 9.4.4: Administrative State */
-enum abis_nm_adm_state {
- NM_STATE_LOCKED = 0x01,
- NM_STATE_UNLOCKED = 0x02,
- NM_STATE_SHUTDOWN = 0x03,
- NM_STATE_NULL = 0xff,
-};
-
-/* Section 9.4.7: Administrative State */
-enum abis_nm_avail_state {
- NM_AVSTATE_IN_TEST = 1,
- NM_AVSTATE_POWER_OFF = 2,
- NM_AVSTATE_OFF_LINE = 3,
- NM_AVSTATE_DEPENDENCY = 5,
- NM_AVSTATE_DEGRADED = 6,
- NM_AVSTATE_NOT_INSTALLED= 7,
- NM_AVSTATE_OK = 0xff,
-};
-
-/* Section 9.4.13: Channel Combination */
-enum abis_nm_chan_comb {
- NM_CHANC_TCHFull = 0x00, /* TCH/F + TCH/H + SACCH/TF */
- NM_CHANC_TCHHalf = 0x01, /* TCH/H(0,1) + FACCH/H(0,1) +
- SACCH/TH(0,1) */
- NM_CHANC_TCHHalf2 = 0x02, /* TCH/H(0) + FACCH/H(0) + SACCH/TH(0) +
- TCH/H(1) */
- NM_CHANC_SDCCH = 0x03, /* SDCCH/8 + SACCH/8 */
- NM_CHANC_mainBCCH = 0x04, /* FCCH + SCH + BCCH + CCCH */
- NM_CHANC_BCCHComb = 0x05, /* FCCH + SCH + BCCH + CCCH + SDCCH/4 +
- SACCH/C4 */
- NM_CHANC_BCCH = 0x06, /* BCCH + CCCH */
- NM_CHANC_BCCH_CBCH = 0x07, /* CHANC_BCCHComb + CBCH */
- NM_CHANC_SDCCH_CBCH = 0x08, /* CHANC_SDCCH8 + CBCH */
- /* 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 */
-enum abis_nm_event_type {
- NM_EVT_COMM_FAIL = 0x00,
- NM_EVT_QOS_FAIL = 0x01,
- NM_EVT_PROC_FAIL = 0x02,
- NM_EVT_EQUIP_FAIL = 0x03,
- NM_EVT_ENV_FAIL = 0x04,
-};
-
-/* Section: 9.4.63: Perceived Severity */
-enum abis_nm_severity {
- NM_SEVER_CEASED = 0x00,
- NM_SEVER_CRITICAL = 0x01,
- NM_SEVER_MAJOR = 0x02,
- NM_SEVER_MINOR = 0x03,
- NM_SEVER_WARNING = 0x04,
- NM_SEVER_INDETERMINATE = 0x05,
-};
-
-/* Section 9.4.43: Probable Cause Type */
-enum abis_nm_pcause_type {
- NM_PCAUSE_T_X721 = 0x01,
- NM_PCAUSE_T_GSM = 0x02,
- NM_PCAUSE_T_MANUF = 0x03,
-};
-
-/* Section 9.4.36: NACK Causes */
-enum abis_nm_nack_cause {
- /* General Nack Causes */
- NM_NACK_INCORR_STRUCT = 0x01,
- NM_NACK_MSGTYPE_INVAL = 0x02,
- NM_NACK_OBJCLASS_INVAL = 0x05,
- NM_NACK_OBJCLASS_NOTSUPP = 0x06,
- NM_NACK_BTSNR_UNKN = 0x07,
- NM_NACK_TRXNR_UNKN = 0x08,
- NM_NACK_OBJINST_UNKN = 0x09,
- NM_NACK_ATTRID_INVAL = 0x0c,
- NM_NACK_ATTRID_NOTSUPP = 0x0d,
- NM_NACK_PARAM_RANGE = 0x0e,
- NM_NACK_ATTRLIST_INCONSISTENT = 0x0f,
- NM_NACK_SPEC_IMPL_NOTSUPP = 0x10,
- NM_NACK_CANT_PERFORM = 0x11,
- /* Specific Nack Causes */
- NM_NACK_RES_NOTIMPL = 0x19,
- NM_NACK_RES_NOTAVAIL = 0x1a,
- NM_NACK_FREQ_NOTAVAIL = 0x1b,
- NM_NACK_TEST_NOTSUPP = 0x1c,
- NM_NACK_CAPACITY_RESTR = 0x1d,
- NM_NACK_PHYSCFG_NOTPERFORM = 0x1e,
- NM_NACK_TEST_NOTINIT = 0x1f,
- NM_NACK_PHYSCFG_NOTRESTORE = 0x20,
- NM_NACK_TEST_NOSUCH = 0x21,
- NM_NACK_TEST_NOSTOP = 0x22,
- NM_NACK_MSGINCONSIST_PHYSCFG = 0x23,
- NM_NACK_FILE_INCOMPLETE = 0x25,
- NM_NACK_FILE_NOTAVAIL = 0x26,
- NM_NACK_FILE_NOTACTIVATE = 0x27,
- NM_NACK_REQ_NOT_GRANT = 0x28,
- NM_NACK_WAIT = 0x29,
- NM_NACK_NOTH_REPORT_EXIST = 0x2a,
- NM_NACK_MEAS_NOTSUPP = 0x2b,
- NM_NACK_MEAS_NOTSTART = 0x2c,
-};
-
-/* Section 9.4.1 */
-struct abis_nm_channel {
- u_int8_t attrib;
- u_int8_t bts_port;
- u_int8_t timeslot;
- u_int8_t subslot;
-} __attribute__ ((packed));
-
-/* Siemens BS-11 specific objects in the SienemsHW (0xA5) object class */
-enum abis_bs11_objtype {
- BS11_OBJ_ALCO = 0x01,
- BS11_OBJ_BBSIG = 0x02, /* obj_class: 0,1 */
- BS11_OBJ_TRX1 = 0x03, /* only DEACTIVATE TRX1 */
- BS11_OBJ_CCLK = 0x04,
- BS11_OBJ_GPSU = 0x06,
- BS11_OBJ_LI = 0x07,
- BS11_OBJ_PA = 0x09, /* obj_class: 0, 1*/
-};
-
-enum abis_bs11_trx_power {
- BS11_TRX_POWER_GSM_2W = 0x06,
- BS11_TRX_POWER_GSM_250mW= 0x07,
- BS11_TRX_POWER_GSM_80mW = 0x08,
- BS11_TRX_POWER_GSM_30mW = 0x09,
- BS11_TRX_POWER_DCS_3W = 0x0a,
- BS11_TRX_POWER_DCS_1W6 = 0x0b,
- BS11_TRX_POWER_DCS_500mW= 0x0c,
- BS11_TRX_POWER_DCS_160mW= 0x0d,
-};
-
-enum abis_bs11_li_pll_mode {
- BS11_LI_PLL_LOCKED = 2,
- BS11_LI_PLL_STANDALONE = 3,
-};
-
-enum abis_bs11_line_cfg {
- BS11_LINE_CFG_STAR = 0x00,
- BS11_LINE_CFG_MULTIDROP = 0x01,
- BS11_LINE_CFG_LOOP = 0x02,
-};
-
-enum abis_bs11_phase {
- BS11_STATE_SOFTWARE_RQD = 0x01,
- BS11_STATE_LOAD_SMU_INTENDED = 0x11,
- BS11_STATE_LOAD_SMU_SAFETY = 0x21,
- BS11_STATE_LOAD_FAILED = 0x31,
- BS11_STATE_LOAD_DIAGNOSTIC = 0x41,
- BS11_STATE_WARM_UP = 0x51,
- BS11_STATE_WARM_UP_2 = 0x52,
- BS11_STATE_WAIT_MIN_CFG = 0x62,
- BS11_STATE_MAINTENANCE = 0x72,
- BS11_STATE_LOAD_MBCCU = 0x92,
- BS11_STATE_WAIT_MIN_CFG_2 = 0xA2,
- BS11_STATE_NORMAL = 0x03,
- BS11_STATE_ABIS_LOAD = 0x13,
-};
-
-enum abis_nm_ipacc_test_no {
- NM_IPACC_TESTNO_RLOOP_ANT = 0x01,
- NM_IPACC_TESTNO_RLOOP_XCVR = 0x02,
- NM_IPACC_TESTNO_FUNC_OBJ = 0x03,
- NM_IPACC_TESTNO_CHAN_USAGE = 0x40,
- NM_IPACC_TESTNO_BCCH_CHAN_USAGE = 0x41,
- NM_IPACC_TESTNO_FREQ_SYNC = 0x42,
- NM_IPACC_TESTNO_BCCH_INFO = 0x43,
- NM_IPACC_TESTNO_TX_BEACON = 0x44,
- NM_IPACC_TESTNO_SYSINFO_MONITOR = 0x45,
- NM_IPACC_TESTNO_BCCCH_MONITOR = 0x46,
-};
-
-/* first byte after length inside NM_ATT_TEST_REPORT */
-enum abis_nm_ipacc_test_res {
- NM_IPACC_TESTRES_SUCCESS = 0,
- NM_IPACC_TESTRES_TIMEOUT = 1,
- NM_IPACC_TESTRES_NO_CHANS = 2,
- NM_IPACC_TESTRES_PARTIAL = 3,
- NM_IPACC_TESTRES_STOPPED = 4,
-};
-
-/* internal IE inside NM_ATT_TEST_REPORT */
-enum abis_nm_ipacc_testres_ie {
- NM_IPACC_TR_IE_FREQ_ERR_LIST = 3,
- NM_IPACC_TR_IE_CHAN_USAGE = 4,
- NM_IPACC_TR_IE_BCCH_INFO = 6,
- NM_IPACC_TR_IE_RESULT_DETAILS = 8,
- NM_IPACC_TR_IE_FREQ_ERR = 18,
-};
-
-enum ipac_eie {
- NM_IPAC_EIE_ARFCN_WHITE = 0x01,
- NM_IPAC_EIE_ARFCH_BLACK = 0x02,
- NM_IPAC_EIE_FREQ_ERR_LIST = 0x03,
- NM_IPAC_EIE_CHAN_USE_LIST = 0x04,
- NM_IPAC_EIE_BCCH_INFO_TYPE = 0x05,
- NM_IPAC_EIE_BCCH_INFO = 0x06,
- /* FIXME */
-};
-
-enum ipac_bcch_info_type {
- IPAC_BINF_RXLEV = (1 << 8),
- IPAC_BINF_RXQUAL = (1 << 9),
- IPAC_BINF_FREQ_ERR_QUAL = (1 << 10),
- IPAC_BINF_FRAME_OFFSET = (1 << 11),
- IPAC_BINF_FRAME_NR_OFFSET = (1 << 12),
- IPAC_BINF_BSIC = (1 << 13),
- IPAC_BINF_CGI = (1 << 14),
- IPAC_BINF_NEIGH_BA_SI2 = (1 << 15),
- IPAC_BINF_NEIGH_BA_SI2bis = (1 << 0),
- IPAC_BINF_NEIGH_BA_SI2ter = (1 << 1),
- IPAC_BINF_CELL_ALLOC = (1 << 2),
-};
+#include <osmocore/tlv.h>
+#include <osmocore/protocol/gsm_12_21.h>
struct cell_global_id {
u_int16_t mcc;
@@ -712,6 +55,8 @@ struct ipac_bcch_info {
u_int8_t ca_list_si1[16];
};
+extern const struct tlv_definition nm_att_tlvdef;
+
/* PUBLIC */
struct msgb;
@@ -726,7 +71,7 @@ struct abis_nm_cfg {
extern int abis_nm_rcvmsg(struct msgb *msg);
-int abis_nm_tlv_parse(struct tlv_parsed *tp, const u_int8_t *buf, int len);
+int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len);
int abis_nm_rx(struct msgb *msg);
int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2);
int abis_nm_chg_adm_state(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0,
@@ -780,10 +125,13 @@ int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts);
int abis_nm_bs11_get_serno(struct gsm_bts *bts);
int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level);
int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx);
+int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on);
int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on);
+int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on);
int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password);
int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked);
int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts);
+int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value);
int abis_nm_bs11_get_cclk(struct gsm_bts *bts);
int abis_nm_bs11_get_state(struct gsm_bts *bts);
int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
@@ -798,7 +146,7 @@ int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
u_int8_t obj_class, u_int8_t bts_nr,
u_int8_t trx_nr, u_int8_t ts_nr,
u_int8_t *attr, int attr_len);
-int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr,
+int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
int attr_len);
int abis_nm_ipaccess_restart(struct gsm_bts *bts);
int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
@@ -819,4 +167,5 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
const char *nm_opstate_name(u_int8_t os);
const char *nm_avail_name(u_int8_t avail);
+int nm_is_running(struct gsm_nm_state *s);
#endif /* _NM_H */
diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h
index 797b2f349..b280184e0 100644
--- a/openbsc/include/openbsc/abis_rsl.h
+++ b/openbsc/include/openbsc/abis_rsl.h
@@ -23,468 +23,9 @@
#ifndef _RSL_H
#define _RSL_H
-struct abis_rsl_common_hdr {
- u_int8_t msg_discr;
- u_int8_t msg_type;
- u_int8_t data[0];
-} __attribute__ ((packed));
+#include <osmocore/protocol/gsm_08_58.h>
-/* Chapter 8.3 */
-struct abis_rsl_rll_hdr {
- struct abis_rsl_common_hdr c;
- u_int8_t ie_chan;
- u_int8_t chan_nr;
- u_int8_t ie_link_id;
- u_int8_t link_id;
- u_int8_t data[0];
-} __attribute__ ((packed));
-
-/* Chapter 8.3 and 8.4 */
-struct abis_rsl_dchan_hdr {
- struct abis_rsl_common_hdr c;
- u_int8_t ie_chan;
- u_int8_t chan_nr;
- u_int8_t data[0];
-} __attribute__ ((packed));
-
-
-/* Chapter 9.1 */
-#define ABIS_RSL_MDISC_RLL 0x02
-#define ABIS_RSL_MDISC_DED_CHAN 0x08
-#define ABIS_RSL_MDISC_COM_CHAN 0x0c
-#define ABIS_RSL_MDISC_TRX 0x10
-#define ABIS_RSL_MDISC_LOC 0x20
-#define ABIS_RSL_MDISC_IPACCESS 0x7e
-#define ABIS_RSL_MDISC_TRANSP 0x01
-
-#define ABIS_RSL_MDISC_IS_TRANSP(x) (x & 0x01)
-
-/* Chapter 9.1 */
-enum abis_rsl_msgtype {
- /* Radio Link Layer Management */
- RSL_MT_DATA_REQ = 0x01,
- RSL_MT_DATA_IND,
- RSL_MT_ERROR_IND,
- RSL_MT_EST_REQ,
- RSL_MT_EST_CONF,
- RSL_MT_EST_IND,
- RSL_MT_REL_REQ,
- RSL_MT_REL_CONF,
- RSL_MT_REL_IND,
- RSL_MT_UNIT_DATA_REQ,
- RSL_MT_UNIT_DATA_IND, /* 0x0b */
-
- /* Common Channel Management / TRX Management */
- RSL_MT_BCCH_INFO = 0x11,
- RSL_MT_CCCH_LOAD_IND,
- RSL_MT_CHAN_RQD,
- RSL_MT_DELETE_IND,
- RSL_MT_PAGING_CMD,
- RSL_MT_IMMEDIATE_ASSIGN_CMD,
- RSL_MT_SMS_BC_REQ,
- /* empty */
- RSL_MT_RF_RES_IND = 0x19,
- RSL_MT_SACCH_FILL,
- RSL_MT_OVERLOAD,
- RSL_MT_ERROR_REPORT,
- RSL_MT_SMS_BC_CMD,
- RSL_MT_CBCH_LOAD_IND,
- RSL_MT_NOT_CMD, /* 0x1f */
-
- /* Dedicate Channel Management */
- RSL_MT_CHAN_ACTIV = 0x21,
- RSL_MT_CHAN_ACTIV_ACK,
- RSL_MT_CHAN_ACTIV_NACK,
- RSL_MT_CONN_FAIL,
- RSL_MT_DEACTIVATE_SACCH,
- RSL_MT_ENCR_CMD,
- RSL_MT_HANDO_DET,
- RSL_MT_MEAS_RES,
- RSL_MT_MODE_MODIFY_REQ,
- RSL_MT_MODE_MODIFY_ACK,
- RSL_MT_MODE_MODIFY_NACK,
- RSL_MT_PHY_CONTEXT_REQ,
- RSL_MT_PHY_CONTEXT_CONF,
- RSL_MT_RF_CHAN_REL,
- RSL_MT_MS_POWER_CONTROL,
- RSL_MT_BS_POWER_CONTROL, /* 0x30 */
- RSL_MT_PREPROC_CONFIG,
- RSL_MT_PREPROC_MEAS_RES,
- RSL_MT_RF_CHAN_REL_ACK,
- RSL_MT_SACCH_INFO_MODIFY,
- RSL_MT_TALKER_DET,
- RSL_MT_LISTENER_DET,
- RSL_MT_REMOTE_CODEC_CONF_REP,
- RSL_MT_RTD_REP,
- RSL_MT_PRE_HANDO_NOTIF,
- RSL_MT_MR_CODEC_MOD_REQ,
- RSL_MT_MR_CODEC_MOD_ACK,
- RSL_MT_MR_CODEC_MOD_NACK,
- RSL_MT_MR_CODEC_MOD_PER,
- RSL_MT_TFO_REP,
- RSL_MT_TFO_MOD_REQ, /* 0x3f */
- RSL_MT_LOCATION_INFO = 0x41,
-
- /* ip.access specific RSL message types */
- RSL_MT_IPAC_DIR_RETR_ENQ = 0x40,
- RSL_MT_IPAC_PDCH_ACT = 0x48,
- RSL_MT_IPAC_PDCH_ACT_ACK,
- RSL_MT_IPAC_PDCH_ACT_NACK,
- RSL_MT_IPAC_PDCH_DEACT = 0x4b,
- RSL_MT_IPAC_PDCH_DEACT_ACK,
- RSL_MT_IPAC_PDCH_DEACT_NACK,
- RSL_MT_IPAC_CONNECT_MUX = 0x50,
- RSL_MT_IPAC_CONNECT_MUX_ACK,
- RSL_MT_IPAC_CONNECT_MUX_NACK,
- RSL_MT_IPAC_BIND_MUX = 0x53,
- RSL_MT_IPAC_BIND_MUX_ACK,
- RSL_MT_IPAC_BIND_MUX_NACK,
- RSL_MT_IPAC_DISC_MUX = 0x56,
- RSL_MT_IPAC_DISC_MUX_ACK,
- RSL_MT_IPAC_DISC_MUX_NACK,
- RSL_MT_IPAC_CRCX = 0x70, /* Bind to local BTS RTP port */
- RSL_MT_IPAC_CRCX_ACK,
- RSL_MT_IPAC_CRCX_NACK,
- RSL_MT_IPAC_MDCX = 0x73,
- RSL_MT_IPAC_MDCX_ACK,
- RSL_MT_IPAC_MDCX_NACK,
- RSL_MT_IPAC_DLCX_IND = 0x76,
- RSL_MT_IPAC_DLCX = 0x77,
- RSL_MT_IPAC_DLCX_ACK,
- RSL_MT_IPAC_DLCX_NACK,
-};
-
-/* Siemens vendor-specific */
-enum abis_rsl_msgtype_siemens {
- RSL_MT_SIEMENS_MRPCI = 0x41,
- RSL_MT_SIEMENS_INTRAC_HO_COND_IND = 0x42,
- RSL_MT_SIEMENS_INTERC_HO_COND_IND = 0x43,
- RSL_MT_SIEMENS_FORCED_HO_REQ = 0x44,
- RSL_MT_SIEMENS_PREF_AREA_REQ = 0x45,
- RSL_MT_SIEMENS_PREF_AREA = 0x46,
- RSL_MT_SIEMENS_START_TRACE = 0x47,
- RSL_MT_SIEMENS_START_TRACE_ACK = 0x48,
- RSL_MT_SIEMENS_STOP_TRACE = 0x49,
- RSL_MT_SIEMENS_TRMR = 0x4a,
- RSL_MT_SIEMENS_HO_FAIL_IND = 0x4b,
- RSL_MT_SIEMENS_STOP_TRACE_ACK = 0x4c,
- RSL_MT_SIEMENS_UPLF = 0x4d,
- RSL_MT_SIEMENS_UPLB = 0x4e,
- RSL_MT_SIEMENS_SET_SYS_INFO_10 = 0x4f,
- RSL_MT_SIEMENS_MODIF_COND_IND = 0x50,
-};
-
-/* Chapter 9.3 */
-enum abis_rsl_ie {
- RSL_IE_CHAN_NR = 0x01,
- RSL_IE_LINK_IDENT,
- RSL_IE_ACT_TYPE,
- RSL_IE_BS_POWER,
- RSL_IE_CHAN_IDENT,
- RSL_IE_CHAN_MODE,
- RSL_IE_ENCR_INFO,
- RSL_IE_FRAME_NUMBER,
- RSL_IE_HANDO_REF,
- RSL_IE_L1_INFO,
- RSL_IE_L3_INFO,
- RSL_IE_MS_IDENTITY,
- RSL_IE_MS_POWER,
- RSL_IE_PAGING_GROUP,
- RSL_IE_PAGING_LOAD,
- RSL_IE_PYHS_CONTEXT = 0x10,
- RSL_IE_ACCESS_DELAY,
- RSL_IE_RACH_LOAD,
- RSL_IE_REQ_REFERENCE,
- RSL_IE_RELEASE_MODE,
- RSL_IE_RESOURCE_INFO,
- RSL_IE_RLM_CAUSE,
- RSL_IE_STARTNG_TIME,
- RSL_IE_TIMING_ADVANCE,
- RSL_IE_UPLINK_MEAS,
- RSL_IE_CAUSE,
- RSL_IE_MEAS_RES_NR,
- RSL_IE_MSG_ID,
- /* reserved */
- RSL_IE_SYSINFO_TYPE = 0x1e,
- RSL_IE_MS_POWER_PARAM,
- RSL_IE_BS_POWER_PARAM,
- RSL_IE_PREPROC_PARAM,
- RSL_IE_PREPROC_MEAS,
- RSL_IE_IMM_ASS_INFO, /* Phase 1 (3.6.0), later Full below */
- RSL_IE_SMSCB_INFO = 0x24,
- RSL_IE_MS_TIMING_OFFSET,
- RSL_IE_ERR_MSG,
- RSL_IE_FULL_BCCH_INFO,
- RSL_IE_CHAN_NEEDED,
- RSL_IE_CB_CMD_TYPE,
- RSL_IE_SMSCB_MSG,
- RSL_IE_FULL_IMM_ASS_INFO,
- RSL_IE_SACCH_INFO,
- RSL_IE_CBCH_LOAD_INFO,
- RSL_IE_SMSCB_CHAN_INDICATOR,
- RSL_IE_GROUP_CALL_REF,
- RSL_IE_CHAN_DESC = 0x30,
- RSL_IE_NCH_DRX_INFO,
- RSL_IE_CMD_INDICATOR,
- RSL_IE_EMLPP_PRIO,
- RSL_IE_UIC,
- RSL_IE_MAIN_CHAN_REF,
- RSL_IE_MR_CONFIG,
- RSL_IE_MR_CONTROL,
- RSL_IE_SUP_CODEC_TYPES,
- RSL_IE_CODEC_CONFIG,
- RSL_IE_RTD,
- RSL_IE_TFO_STATUS,
- RSL_IE_LLP_APDU,
- /* Siemens vendor-specific */
- RSL_IE_SIEMENS_MRPCI = 0x40,
- RSL_IE_SIEMENS_PREF_AREA_TYPE = 0x43,
- RSL_IE_SIEMENS_ININ_CELL_HO_PAR = 0x45,
- RSL_IE_SIEMENS_TRACE_REF_NR = 0x46,
- RSL_IE_SIEMENS_INT_TRACE_IDX = 0x47,
- RSL_IE_SIEMENS_L2_HDR_INFO = 0x48,
- RSL_IE_SIEMENS_HIGHEST_RATE = 0x4e,
- RSL_IE_SIEMENS_SUGGESTED_RATE = 0x4f,
-
- /* ip.access */
- RSL_IE_IPAC_SRTP_CONFIG = 0xe0,
- RSL_IE_IPAC_PROXY_UDP = 0xe1,
- RSL_IE_IPAC_BSCMPL_TOUT = 0xe2,
- RSL_IE_IPAC_REMOTE_IP = 0xf0,
- RSL_IE_IPAC_REMOTE_PORT = 0xf1,
- RSL_IE_IPAC_RTP_PAYLOAD = 0xf2,
- RSL_IE_IPAC_LOCAL_PORT = 0xf3,
- RSL_IE_IPAC_SPEECH_MODE = 0xf4,
- RSL_IE_IPAC_LOCAL_IP = 0xf5,
- RSL_IE_IPAC_CONN_STAT = 0xf6,
- RSL_IE_IPAC_HO_C_PARMS = 0xf7,
- RSL_IE_IPAC_CONN_ID = 0xf8,
- RSL_IE_IPAC_RTP_CSD_FMT = 0xf9,
- RSL_IE_IPAC_RTP_JIT_BUF = 0xfa,
- RSL_IE_IPAC_RTP_COMPR = 0xfb,
- RSL_IE_IPAC_RTP_PAYLOAD2= 0xfc,
- RSL_IE_IPAC_RTP_MPLEX = 0xfd,
- RSL_IE_IPAC_RTP_MPLEX_ID= 0xfe,
-};
-
-/* Chapter 9.3.1 */
-#define RSL_CHAN_NR_MASK 0xf8
-#define RSL_CHAN_Bm_ACCHs 0x08
-#define RSL_CHAN_Lm_ACCHs 0x10 /* .. 0x18 */
-#define RSL_CHAN_SDCCH4_ACCH 0x20 /* .. 0x38 */
-#define RSL_CHAN_SDCCH8_ACCH 0x40 /* ...0x78 */
-#define RSL_CHAN_BCCH 0x80
-#define RSL_CHAN_RACH 0x88
-#define RSL_CHAN_PCH_AGCH 0x90
-
-/* Chapter 9.3.3 */
-#define RSL_ACT_TYPE_INITIAL 0x00
-#define RSL_ACT_TYPE_REACT 0x80
-#define RSL_ACT_INTRA_IMM_ASS 0x00
-#define RSL_ACT_INTRA_NORM_ASS 0x01
-#define RSL_ACT_INTER_ASYNC 0x02
-#define RSL_ACT_INTER_SYNC 0x03
-#define RSL_ACT_SECOND_ADD 0x04
-#define RSL_ACT_SECOND_MULTI 0x05
-
-/* Chapter 9.3.6 */
-struct rsl_ie_chan_mode {
- u_int8_t dtx_dtu;
- u_int8_t spd_ind;
- u_int8_t chan_rt;
- u_int8_t chan_rate;
-} __attribute__ ((packed));
-#define RSL_CMOD_DTXu 0x01 /* uplink */
-#define RSL_CMOD_DTXd 0x02 /* downlink */
-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 {
- /* GSM 04.08 10.5.2.5 */
- struct {
- u_int8_t iei;
- u_int8_t chan_nr; /* enc_chan_nr */
- u_int8_t oct3;
- u_int8_t oct4;
- } chan_desc;
-#if 0 /* spec says we need this but Abissim doesn't use it */
- struct {
- u_int8_t tag;
- u_int8_t len;
- } mobile_alloc;
-#endif
-} __attribute__ ((packed));
-
-/* Chapter 9.3.22 */
-#define RLL_CAUSE_T200_EXPIRED 0x01
-#define RLL_CAUSE_REEST_REQ 0x02
-#define RLL_CAUSE_UNSOL_UA_RESP 0x03
-#define RLL_CAUSE_UNSOL_DM_RESP 0x04
-#define RLL_CAUSE_UNSOL_DM_RESP_MF 0x05
-#define RLL_CAUSE_UNSOL_SPRV_RESP 0x06
-#define RLL_CAUSE_SEQ_ERR 0x07
-#define RLL_CAUSE_UFRM_INC_PARAM 0x08
-#define RLL_CAUSE_SFRM_INC_PARAM 0x09
-#define RLL_CAUSE_IFRM_INC_MBITS 0x0a
-#define RLL_CAUSE_IFRM_INC_LEN 0x0b
-#define RLL_CAUSE_FRM_UNIMPL 0x0c
-#define RLL_CAUSE_SABM_MF 0x0d
-#define RLL_CAUSE_SABM_INFO_NOTALL 0x0e
-
-/* Chapter 9.3.26 */
-#define RSL_ERRCLS_NORMAL 0x00
-#define RSL_ERRCLS_RESOURCE_UNAVAIL 0x20
-#define RSL_ERRCLS_SERVICE_UNAVAIL 0x30
-#define RSL_ERRCLS_SERVICE_UNIMPL 0x40
-#define RSL_ERRCLS_INVAL_MSG 0x50
-#define RSL_ERRCLS_PROTO_ERROR 0x60
-#define RSL_ERRCLS_INTERWORKING 0x70
-
-/* normal event */
-#define RSL_ERR_RADIO_IF_FAIL 0x00
-#define RSL_ERR_RADIO_LINK_FAIL 0x01
-#define RSL_ERR_HANDOVER_ACC_FAIL 0x02
-#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
-#define RSL_ERR_TERR_CH_FAIL 0x22
-#define RSL_ERR_CCCH_OVERLOAD 0x23
-#define RSL_ERR_ACCH_OVERLOAD 0x24
-#define RSL_ERR_PROCESSOR_OVERLOAD 0x25
-#define RSL_ERR_RES_UNAVAIL 0x2f
-/* service or option not available */
-#define RSL_ERR_TRANSC_UNAVAIL 0x30
-#define RSL_ERR_SERV_OPT_UNAVAIL 0x3f
-/* service or option not implemented */
-#define RSL_ERR_ENCR_UNIMPL 0x40
-#define RSL_ERR_SERV_OPT_UNIMPL 0x4f
-/* invalid message */
-#define RSL_ERR_RCH_ALR_ACTV_ALLOC 0x50
-#define RSL_ERR_INVALID_MESSAGE 0x5f
-/* protocol error */
-#define RSL_ERR_MSG_DISCR 0x60
-#define RSL_ERR_MSG_TYPE 0x61
-#define RSL_ERR_MSG_SEQ 0x62
-#define RSL_ERR_IE_ERROR 0x63
-#define RSL_ERR_MAND_IE_ERROR 0x64
-#define RSL_ERR_OPT_IE_ERROR 0x65
-#define RSL_ERR_IE_NONEXIST 0x66
-#define RSL_ERR_IE_LENGTH 0x67
-#define RSL_ERR_IE_CONTENT 0x68
-#define RSL_ERR_PROTO 0x6f
-/* interworking */
-#define RSL_ERR_INTERWORKING 0x7f
-
-/* Chapter 9.3.30 */
-#define RSL_SYSTEM_INFO_8 0x00
-#define RSL_SYSTEM_INFO_1 0x01
-#define RSL_SYSTEM_INFO_2 0x02
-#define RSL_SYSTEM_INFO_3 0x03
-#define RSL_SYSTEM_INFO_4 0x04
-#define RSL_SYSTEM_INFO_5 0x05
-#define RSL_SYSTEM_INFO_6 0x06
-#define RSL_SYSTEM_INFO_7 0x07
-#define RSL_SYSTEM_INFO_16 0x08
-#define RSL_SYSTEM_INFO_17 0x09
-#define RSL_SYSTEM_INFO_2bis 0x0a
-#define RSL_SYSTEM_INFO_2ter 0x0b
-#define RSL_SYSTEM_INFO_5bis 0x0d
-#define RSL_SYSTEM_INFO_5ter 0x0e
-#define RSL_SYSTEM_INFO_10 0x0f
-#define REL_EXT_MEAS_ORDER 0x47
-#define RSL_MEAS_INFO 0x48
-#define RSL_SYSTEM_INFO_13 0x28
-#define RSL_SYSTEM_INFO_2quater 0x29
-#define RSL_SYSTEM_INFO_9 0x2a
-#define RSL_SYSTEM_INFO_18 0x2b
-#define RSL_SYSTEM_INFO_19 0x2c
-#define RSL_SYSTEM_INFO_20 0x2d
-
-/* Chapter 9.3.40 */
-#define RSL_CHANNEED_ANY 0x00
-#define RSL_CHANNEED_SDCCH 0x01
-#define RSL_CHANNEED_TCH_F 0x02
-#define RSL_CHANNEED_TCH_ForH 0x03
-
-/* Chapter 3.3.2.3 Brocast control channel */
-/* CCCH-CONF, NC is not combined */
-#define RSL_BCCH_CCCH_CONF_1_NC 0x00
-#define RSL_BCCH_CCCH_CONF_1_C 0x01
-#define RSL_BCCH_CCCH_CONF_2_NC 0x02
-#define RSL_BCCH_CCCH_CONF_3_NC 0x04
-#define RSL_BCCH_CCCH_CONF_4_NC 0x06
-
-/* BS-PA-MFRMS */
-#define RSL_BS_PA_MFRMS_2 0x00
-#define RSL_BS_PA_MFRMS_3 0x01
-#define RSL_BS_PA_MFRMS_4 0x02
-#define RSL_BS_PA_MFRMS_5 0x03
-#define RSL_BS_PA_MFRMS_6 0x04
-#define RSL_BS_PA_MFRMS_7 0x05
-#define RSL_BS_PA_MFRMS_8 0x06
-#define RSL_BS_PA_MFRMS_9 0x07
-
-/* RSL_IE_IPAC_RTP_PAYLOAD[2] */
-enum rsl_ipac_rtp_payload {
- RSL_IPAC_RTP_GSM = 1,
- RSL_IPAC_RTP_EFR,
- RSL_IPAC_RTP_AMR,
- RSL_IPAC_RTP_CSD,
- RSL_IPAC_RTP_MUX,
-};
-
-/* RSL_IE_IPAC_SPEECH_MODE, lower four bits */
-enum rsl_ipac_speech_mode_s {
- RSL_IPAC_SPEECH_GSM_FR = 0, /* GSM FR (Type 1, FS) */
- RSL_IPAC_SPEECH_GSM_EFR = 1, /* GSM EFR (Type 2, FS) */
- RSL_IPAC_SPEECH_GSM_AMR_FR = 2, /* GSM AMR/FR (Type 3, FS) */
- RSL_IPAC_SPEECH_GSM_HR = 3, /* GSM HR (Type 1, HS) */
- RSL_IPAC_SPEECH_GSM_AMR_HR = 5, /* GSM AMR/hr (Type 3, HS) */
- RSL_IPAC_SPEECH_AS_RTP = 0xf, /* As specified by RTP Payload IE */
-};
-/* RSL_IE_IPAC_SPEECH_MODE, upper four bits */
-enum rsl_ipac_speech_mode_m {
- RSL_IPAC_SPEECH_M_RXTX = 0, /* Send and Receive */
- RSL_IPAC_SPEECH_M_RX = 1, /* Receive only */
- RSL_IPAC_SPEECH_M_TX = 2, /* Send only */
-};
-
-/* RSL_IE_IPAC_RTP_CSD_FMT, lower four bits */
-enum rsl_ipac_rtp_csd_format_d {
- RSL_IPAC_RTP_CSD_EXT_TRAU = 0,
- RSL_IPAC_RTP_CSD_NON_TRAU = 1,
- RSL_IPAC_RTP_CSD_TRAU_BTS = 2,
- RSL_IPAC_RTP_CSD_IWF_FREE = 3,
-};
-/* RSL_IE_IPAC_RTP_CSD_FMT, upper four bits */
-enum rsl_ipac_rtp_csd_format_ir {
- RSL_IPAC_RTP_CSD_IR_8k = 0,
- RSL_IPAC_RTP_CSD_IR_16k = 1,
- RSL_IPAC_RTP_CSD_IR_32k = 2,
- RSL_IPAC_RTP_CSD_IR_64k = 3,
-};
-
-#include "msgb.h"
+#include <osmocore/msgb.h>
int rsl_bcch_info(struct gsm_bts_trx *trx, u_int8_t type,
const u_int8_t *data, int len);
@@ -511,27 +52,6 @@ int rsl_establish_request(struct gsm_lchan *lchan, u_int8_t link_id);
int rsl_relase_request(struct gsm_lchan *lchan, u_int8_t link_id);
/* Siemens vendor-specific RSL extensions */
-struct rsl_mrpci {
- u_int8_t power_class:3,
- vgcs_capable:1,
- vbs_capable:1,
- gsm_phase:2;
-} __attribute__ ((packed));
-
-enum rsl_mrpci_pwrclass {
- RSL_MRPCI_PWRC_1 = 0,
- RSL_MRPCI_PWRC_2 = 1,
- RSL_MRPCI_PWRC_3 = 2,
- RSL_MRPCI_PWRC_4 = 3,
- RSL_MRPCI_PWRC_5 = 4,
-};
-enum rsl_mrpci_phase {
- RSL_MRPCI_PHASE_1 = 0,
- /* reserved */
- RSL_MRPCI_PHASE_2 = 2,
- RSL_MRPCI_PHASE_2PLUS = 3,
-};
-
int rsl_siemens_mrpci(struct gsm_lchan *lchan, struct rsl_mrpci *mrpci);
/* ip.access specfic RSL extensions */
diff --git a/openbsc/include/openbsc/bitvec.h b/openbsc/include/openbsc/bitvec.h
deleted file mode 100644
index b35aebf16..000000000
--- a/openbsc/include/openbsc/bitvec.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef _BITVEC_H
-#define _BITVEC_H
-
-/* bit vector utility routines */
-
-/* (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.
- *
- */
-
-
-/* In GSM mac blocks, every bit can be 0 or 1, or L or H. L/H are
- * defined relative to the 0x2b padding pattern */
-enum bit_value {
- ZERO = 0,
- ONE = 1,
- L = 2,
- H = 3,
-};
-
-struct bitvec {
- unsigned int cur_bit; /* curser to the next unused bit */
- unsigned int data_len; /* length of data array in bytes */
- u_int8_t *data; /* pointer to data array */
-};
-
-/* check if the bit is 0 or 1 for a given position inside a bitvec */
-enum bit_value bitvec_get_bit_pos(struct bitvec *bv, unsigned int bitnr);
-
-/* get the Nth set bit inside the bit vector */
-unsigned int bitvec_get_nth_set_bit(struct bitvec *bv, unsigned int n);
-
-/* Set a bit at given position */
-int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnum,
- enum bit_value bit);
-
-/* Set the next bit in the vector */
-int bitvec_set_bit(struct bitvec *bv, enum bit_value bit);
-
-/* Set multiple bits at the current position */
-int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count);
-
-/* Add an unsigned integer (of length count bits) to current position */
-int bitvec_set_uint(struct bitvec *bv, unsigned int in, int count);
-
-
-/* Pad the bit vector up to a certain bit position */
-int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit);
-
-#endif /* _BITVEC_H */
diff --git a/openbsc/include/openbsc/bsc_msc.h b/openbsc/include/openbsc/bsc_msc.h
index 9b523c749..9454e07ce 100644
--- a/openbsc/include/openbsc/bsc_msc.h
+++ b/openbsc/include/openbsc/bsc_msc.h
@@ -23,7 +23,7 @@
#ifndef BSC_MSC_H
#define BSC_MSC_H
-#include "select.h"
+#include <osmocore/select.h>
int connect_to_msc(struct bsc_fd *fd, const char *ip, int port);
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h
index 1da58bcba..9dd5b8f3d 100644
--- a/openbsc/include/openbsc/bsc_nat.h
+++ b/openbsc/include/openbsc/bsc_nat.h
@@ -25,9 +25,9 @@
#include <sys/types.h>
#include <sccp/sccp_types.h>
-#include "select.h"
-#include "msgb.h"
-#include "timer.h"
+#include <osmocore/select.h>
+#include <osmocore/msgb.h>
+#include <osmocore/timer.h>
#define DIR_BSC 1
#define DIR_MSC 2
diff --git a/openbsc/include/openbsc/bssap.h b/openbsc/include/openbsc/bssap.h
index e873dfad1..3b06fb5c3 100644
--- a/openbsc/include/openbsc/bssap.h
+++ b/openbsc/include/openbsc/bssap.h
@@ -5,7 +5,7 @@
#include <stdlib.h>
-#include <openbsc/msgb.h>
+#include <osmocore/msgb.h>
#include <openbsc/gsm_data.h>
/*
diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h
index ef42fe1c5..346b43147 100644
--- a/openbsc/include/openbsc/chan_alloc.h
+++ b/openbsc/include/openbsc/chan_alloc.h
@@ -71,4 +71,18 @@ void lchan_free(struct gsm_lchan *lchan);
/* internal.. do not use */
int _lchan_release(struct gsm_lchan *lchan);
+struct load_counter {
+ unsigned int total;
+ unsigned int used;
+};
+
+struct pchan_load {
+ struct load_counter pchan[GSM_PCHAN_UNKNOWN];
+};
+
+void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts);
+void network_chan_load(struct pchan_load *pl, struct gsm_network *net);
+
+int trx_is_usable(struct gsm_bts_trx *trx);
+
#endif /* _CHAN_ALLOC_H */
diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h
index 07135937b..df664dbc1 100644
--- a/openbsc/include/openbsc/db.h
+++ b/openbsc/include/openbsc/db.h
@@ -43,9 +43,20 @@ int db_subscriber_alloc_token(struct gsm_subscriber* subscriber, u_int32_t* toke
int db_subscriber_assoc_imei(struct gsm_subscriber* subscriber, char *imei);
int db_sync_equipment(struct gsm_equipment *equip);
+/* auth info */
+int get_authinfo_by_subscr(struct gsm_auth_info *ainfo,
+ struct gsm_subscriber *subscr);
+int set_authinfo_for_subscr(struct gsm_auth_info *ainfo,
+ struct gsm_subscriber *subscr);
+int get_authtuple_by_subscr(struct gsm_auth_tuple *atuple,
+ struct gsm_subscriber *subscr);
+int set_authtuple_for_subscr(struct gsm_auth_tuple *atuple,
+ struct gsm_subscriber *subscr);
+
/* SMS store-and-forward */
int db_sms_store(struct gsm_sms *sms);
struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id);
+struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, int min_subscr_id);
struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr);
int db_sms_mark_sent(struct gsm_sms *sms);
@@ -53,4 +64,8 @@ int db_sms_mark_sent(struct gsm_sms *sms);
int db_apdu_blob_store(struct gsm_subscriber *subscr,
u_int8_t apdu_id_flags, u_int8_t len,
u_int8_t *apdu);
+
+/* Statistics counter storage */
+int db_store_counter(struct counter *ctr);
+
#endif /* _DB_H */
diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h
index 1c2d75811..d9de61a73 100644
--- a/openbsc/include/openbsc/debug.h
+++ b/openbsc/include/openbsc/debug.h
@@ -1,31 +1,35 @@
#ifndef _DEBUG_H
#define _DEBUG_H
-#define DEBUG
-
-#define DRLL 0x0001
-#define DCC 0x0002
-#define DMM 0x0004
-#define DRR 0x0008
-#define DRSL 0x0010
-#define DNM 0x0020
-
-#define DMNCC 0x0080
-#define DSMS 0x0100
-#define DPAG 0x0200
-#define DMEAS 0x0400
+#include <stdio.h>
+#include <osmocore/linuxlist.h>
-#define DMI 0x1000
-#define DMIB 0x2000
-#define DMUX 0x4000
-#define DINP 0x8000
-
-#define DSCCP 0x10000
-#define DMSC 0x20000
-
-#define DMGCP 0x40000
+#define DEBUG
-#define DHO 0x80000
+/* Debug Areas of the code */
+enum {
+ DRLL,
+ DCC,
+ DMM,
+ DRR,
+ DRSL,
+ DNM,
+ DMNCC,
+ DSMS,
+ DPAG,
+ DMEAS,
+ DMI,
+ DMIB,
+ DMUX,
+ DINP,
+ DSCCP,
+ DMSC,
+ DMGCP,
+ DHO,
+ DDB,
+ DREF,
+ Debug_LastEntry,
+};
#define DNAT 0x100000
@@ -33,22 +37,19 @@
#define DEBUGP(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 0, fmt, ## args)
#define DEBUGPC(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 1, fmt, ## args)
#else
-#define DEBUGP(xss, fmt, args...)
+#define DEBUGP(xss, fmt, args...)
#define DEBUGPC(ss, fmt, args...)
#endif
+
#define static_assert(exp, name) typedef int dummy##name [(exp) ? 1 : -1];
char *hexdump(const unsigned char *buf, int len);
void debugp(unsigned int subsys, char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
-void debug_parse_category_mask(const char* mask);
-void debug_use_color(int use_color);
-void debug_timestamp(int enable);
-extern unsigned int debug_mask;
/* new logging interface */
-#define LOGP(ss, level, fmt, args...) debugp(ss, __FILE__, __LINE__, 0, fmt, ##args)
-#define LOGPC(ss, level, fmt, args...) debugp(ss, __FILE__, __LINE__, 1, fmt, ##args)
+#define LOGP(ss, level, fmt, args...) debugp2(ss, level, __FILE__, __LINE__, 0, fmt, ##args)
+#define LOGPC(ss, level, fmt, args...) debugp2(ss, level, __FILE__, __LINE__, 1, fmt, ##args)
/* different levels */
#define LOGL_DEBUG 1 /* debugging information */
@@ -57,4 +58,76 @@ extern unsigned int debug_mask;
#define LOGL_ERROR 7 /* error condition, requires user action */
#define LOGL_FATAL 8 /* fatal, program aborted */
+/* context */
+#define BSC_CTX_LCHAN 0
+#define BSC_CTX_SUBSCR 1
+#define BSC_CTX_BTS 2
+#define BSC_CTX_SCCP 3
+
+/* target */
+
+enum {
+ DEBUG_FILTER_IMSI = 1 << 0,
+ DEBUG_FILTER_ALL = 1 << 1,
+};
+
+struct debug_category {
+ int enabled;
+ int loglevel;
+};
+
+struct debug_target {
+ int filter_map;
+ char *imsi_filter;
+
+
+ struct debug_category categories[Debug_LastEntry];
+ int use_color;
+ int print_timestamp;
+ int loglevel;
+
+ union {
+ struct {
+ FILE *out;
+ } tgt_stdout;
+
+ struct {
+ int priority;
+ } tgt_syslog;
+
+ struct {
+ void *vty;
+ } tgt_vty;
+ };
+
+ void (*output) (struct debug_target *target, const char *string);
+
+ struct llist_head entry;
+};
+
+/* use the above macros */
+void debugp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 6, 7)));
+void debug_init(void);
+
+/* context management */
+void debug_reset_context(void);
+void debug_set_context(int ctx, void *value);
+
+/* filter on the targets */
+void debug_set_imsi_filter(struct debug_target *target, const char *imsi);
+void debug_set_all_filter(struct debug_target *target, int);
+void debug_set_use_color(struct debug_target *target, int);
+void debug_set_print_timestamp(struct debug_target *target, int);
+void debug_set_log_level(struct debug_target *target, int log_level);
+void debug_parse_category_mask(struct debug_target *target, const char* mask);
+int debug_parse_level(const char *lvl);
+int debug_parse_category(const char *category);
+void debug_set_category_filter(struct debug_target *target, int category, int enable, int level);
+
+
+/* management of the targets */
+struct debug_target *debug_target_create(void);
+struct debug_target *debug_target_create_stderr(void);
+void debug_add_target(struct debug_target *target);
+void debug_del_target(struct debug_target *target);
#endif /* _DEBUG_H */
diff --git a/openbsc/include/openbsc/e1_input.h b/openbsc/include/openbsc/e1_input.h
index 64e0b4f7d..1a3d9d6ad 100644
--- a/openbsc/include/openbsc/e1_input.h
+++ b/openbsc/include/openbsc/e1_input.h
@@ -4,10 +4,10 @@
#include <stdlib.h>
#include <netinet/in.h>
-#include <openbsc/linuxlist.h>
+#include <osmocore/linuxlist.h>
#include <openbsc/gsm_data.h>
-#include <openbsc/msgb.h>
-#include <openbsc/select.h>
+#include <osmocore/msgb.h>
+#include <osmocore/select.h>
#include <openbsc/subchan_demux.h>
#define NUM_E1_TS 32
diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index 20de1b648..c4018cd11 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -3,742 +3,8 @@
#include <openbsc/meas_rep.h>
-/* GSM TS 04.08 definitions */
-struct gsm_lchan;
-
-struct gsm48_classmark1 {
- u_int8_t spare:1,
- rev_level:2,
- es_ind:1,
- a5_1:1,
- pwr_lev:3;
-} __attribute__ ((packed));
-
-/* Chapter 10.5.2.5 */
-struct gsm48_chan_desc {
- u_int8_t chan_nr;
- union {
- struct {
- u_int8_t maio_high:4,
- h:1,
- tsc:3;
- u_int8_t hsn:6,
- maio_low:2;
- } h1;
- struct {
- u_int8_t arfcn_high:2,
- spare:2,
- h:1,
- tsc:3;
- u_int8_t arfcn_low;
- } h0;
- };
-} __attribute__ ((packed));
-
-/* Chapter 10.5.2.21aa */
-struct gsm48_multi_rate_conf {
- u_int8_t smod : 2,
- spare: 1,
- icmi : 1,
- nscb : 1,
- ver : 3;
- u_int8_t m4_75 : 1,
- m5_15 : 1,
- m5_90 : 1,
- m6_70 : 1,
- m7_40 : 1,
- m7_95 : 1,
- m10_2 : 1,
- m12_2 : 1;
-} __attribute__((packed));
-
-/* Chapter 10.5.2.30 */
-struct gsm48_req_ref {
- u_int8_t ra;
- u_int8_t t3_high:3,
- t1_:5;
- u_int8_t t2:5,
- t3_low:3;
-} __attribute__ ((packed));
-
-/*
- * Chapter 9.1.5/9.1.6
- *
- * For 9.1.6 the chan_desc has the meaning of 10.5.2.5a
- */
-struct gsm48_chan_mode_modify {
- struct gsm48_chan_desc chan_desc;
- u_int8_t mode;
-} __attribute__ ((packed));
-
-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.2 */
-struct gsm48_ass_cmd {
- /* Semantic is from 10.5.2.5a */
- struct gsm48_chan_desc chan_desc;
- u_int8_t power_command;
- u_int8_t data[0];
-} __attribute__((packed));
-
-/* Chapter 10.5.2.2 */
-struct gsm48_cell_desc {
- u_int8_t bcc:3,
- ncc:3,
- arfcn_hi:2;
- u_int8_t arfcn_lo;
-} __attribute__((packed));
-
-/* Chapter 9.1.15 */
-struct gsm48_ho_cmd {
- struct gsm48_cell_desc cell_desc;
- struct gsm48_chan_desc chan_desc;
- u_int8_t ho_ref;
- u_int8_t power_command;
- u_int8_t data[0];
-} __attribute__((packed));
-
-/* Chapter 9.1.18 */
-struct gsm48_imm_ass {
- u_int8_t l2_plen;
- u_int8_t proto_discr;
- u_int8_t msg_type;
- u_int8_t page_mode;
- struct gsm48_chan_desc chan_desc;
- struct gsm48_req_ref req_ref;
- u_int8_t timing_advance;
- u_int8_t mob_alloc_len;
- u_int8_t mob_alloc[0];
-} __attribute__ ((packed));
-
-/* Chapter 10.5.1.3 */
-struct gsm48_loc_area_id {
- u_int8_t digits[3]; /* BCD! */
- u_int16_t lac;
-} __attribute__ ((packed));
-
-/* Section 9.2.2 */
-struct gsm48_auth_req {
- u_int8_t key_seq:4,
- spare:4;
- u_int8_t rand[16];
-} __attribute__ ((packed));
-
-/* Section 9.2.15 */
-struct gsm48_loc_upd_req {
- u_int8_t type:4,
- key_seq:4;
- struct gsm48_loc_area_id lai;
- struct gsm48_classmark1 classmark1;
- u_int8_t mi_len;
- u_int8_t mi[0];
-} __attribute__ ((packed));
-
-/* Section 10.1 */
-struct gsm48_hdr {
- u_int8_t proto_discr;
- u_int8_t msg_type;
- u_int8_t data[0];
-} __attribute__ ((packed));
-
-/* Section 9.1.3x System information Type header */
-struct gsm48_system_information_type_header {
- u_int8_t l2_plen;
- u_int8_t rr_protocol_discriminator :4,
- skip_indicator:4;
- u_int8_t system_information;
-} __attribute__ ((packed));
-
-struct gsm48_rach_control {
- u_int8_t re :1,
- cell_bar :1,
- tx_integer :4,
- max_trans :2;
- u_int8_t t2;
- u_int8_t t3;
-} __attribute__ ((packed));
-
-/* Section 10.5.2.4 Cell Selection Parameters */
-struct gsm48_cell_sel_par {
- u_int8_t ms_txpwr_max_ccch:5, /* GSM 05.08 MS-TXPWR-MAX-CCCH */
- cell_resel_hyst:3; /* GSM 05.08 CELL-RESELECT-HYSTERESIS */
- u_int8_t rxlev_acc_min:6, /* GSM 05.08 RXLEV-ACCESS-MIN */
- neci:1,
- acs:1;
-} __attribute__ ((packed));
-
-/* Section 10.5.2.11 Control Channel Description , Figure 10.5.33 */
-struct gsm48_control_channel_descr {
- u_int8_t ccch_conf :3,
- bs_ag_blks_res :3,
- att :1,
- spare1 :1;
- u_int8_t bs_pa_mfrms : 3,
- spare2 :5;
- u_int8_t t3212;
-} __attribute__ ((packed));
-
-struct gsm48_cell_options {
- u_int8_t radio_link_timeout:4,
- dtx:2,
- pwrc:1,
- spare:1;
-} __attribute__ ((packed));
-
-/* Section 9.2.9 CM service request */
-struct gsm48_service_request {
- u_int8_t cm_service_type : 4,
- cipher_key_seq : 4;
- /* length + 3 bytes */
- u_int32_t classmark;
- u_int8_t mi_len;
- u_int8_t mi[0];
- /* optional priority level */
-} __attribute__ ((packed));
-
-/* Section 9.1.31 System information Type 1 */
-struct gsm48_system_information_type_1 {
- struct gsm48_system_information_type_header header;
- u_int8_t cell_channel_description[16];
- struct gsm48_rach_control rach_control;
- u_int8_t rest_octets[0]; /* NCH position on the CCCH */
-} __attribute__ ((packed));
-
-/* Section 9.1.32 System information Type 2 */
-struct gsm48_system_information_type_2 {
- struct gsm48_system_information_type_header header;
- u_int8_t bcch_frequency_list[16];
- u_int8_t ncc_permitted;
- struct gsm48_rach_control rach_control;
-} __attribute__ ((packed));
-
-/* Section 9.1.35 System information Type 3 */
-struct gsm48_system_information_type_3 {
- struct gsm48_system_information_type_header header;
- u_int16_t cell_identity;
- struct gsm48_loc_area_id lai;
- struct gsm48_control_channel_descr control_channel_desc;
- struct gsm48_cell_options cell_options;
- struct gsm48_cell_sel_par cell_sel_par;
- struct gsm48_rach_control rach_control;
- u_int8_t rest_octets[0];
-} __attribute__ ((packed));
-
-/* Section 9.1.36 System information Type 4 */
-struct gsm48_system_information_type_4 {
- struct gsm48_system_information_type_header header;
- struct gsm48_loc_area_id lai;
- struct gsm48_cell_sel_par cell_sel_par;
- struct gsm48_rach_control rach_control;
- /* optional CBCH conditional CBCH... followed by
- mandantory SI 4 Reset Octets
- */
- u_int8_t data[0];
-} __attribute__ ((packed));
-
-/* Section 9.1.37 System information Type 5 */
-struct gsm48_system_information_type_5 {
- u_int8_t rr_protocol_discriminator :4,
- skip_indicator:4;
- u_int8_t system_information;
- u_int8_t bcch_frequency_list[16];
-} __attribute__ ((packed));
-
-/* Section 9.1.40 System information Type 6 */
-struct gsm48_system_information_type_6 {
- u_int8_t rr_protocol_discriminator :4,
- skip_indicator:4;
- u_int8_t system_information;
- u_int16_t cell_identity;
- struct gsm48_loc_area_id lai;
- struct gsm48_cell_options cell_options;
- u_int8_t ncc_permitted;
- u_int8_t rest_octets[0];
-} __attribute__ ((packed));
-
-/* Section 9.1.43a System Information type 13 */
-struct gsm48_system_information_type_13 {
- struct gsm48_system_information_type_header header;
- u_int8_t rest_octets[0];
-} __attribute__ ((packed));
-
-/* Section 9.2.12 IMSI Detach Indication */
-struct gsm48_imsi_detach_ind {
- struct gsm48_classmark1 classmark1;
- u_int8_t mi_len;
- u_int8_t mi[0];
-} __attribute__ ((packed));
-
-/* Section 10.2 + GSM 04.07 12.2.3.1.1 */
-#define GSM48_PDISC_GROUP_CC 0x00
-#define GSM48_PDISC_BCAST_CC 0x01
-#define GSM48_PDISC_PDSS1 0x02
-#define GSM48_PDISC_CC 0x03
-#define GSM48_PDISC_PDSS2 0x04
-#define GSM48_PDISC_MM 0x05
-#define GSM48_PDISC_RR 0x06
-#define GSM48_PDISC_MM_GPRS 0x08
-#define GSM48_PDISC_SMS 0x09
-#define GSM48_PDISC_SM_GPRS 0x0a
-#define GSM48_PDISC_NC_SS 0x0b
-#define GSM48_PDISC_LOC 0x0c
-#define GSM48_PDISC_MASK 0x0f
-#define GSM48_PDISC_USSD 0x11
-
-/* Section 10.4 */
-#define GSM48_MT_RR_INIT_REQ 0x3c
-#define GSM48_MT_RR_ADD_ASS 0x3b
-#define GSM48_MT_RR_IMM_ASS 0x3f
-#define GSM48_MT_RR_IMM_ASS_EXT 0x39
-#define GSM48_MT_RR_IMM_ASS_REJ 0x3a
-
-#define GSM48_MT_RR_CIPH_M_CMD 0x35
-#define GSM48_MT_RR_CIPH_M_COMPL 0x32
-
-#define GSM48_MT_RR_CFG_CHG_CMD 0x30
-#define GSM48_MT_RR_CFG_CHG_ACK 0x31
-#define GSM48_MT_RR_CFG_CHG_REJ 0x33
-
-#define GSM48_MT_RR_ASS_CMD 0x2e
-#define GSM48_MT_RR_ASS_COMPL 0x29
-#define GSM48_MT_RR_ASS_FAIL 0x2f
-#define GSM48_MT_RR_HANDO_CMD 0x2b
-#define GSM48_MT_RR_HANDO_COMPL 0x2c
-#define GSM48_MT_RR_HANDO_FAIL 0x28
-#define GSM48_MT_RR_HANDO_INFO 0x2d
-
-#define GSM48_MT_RR_CELL_CHG_ORDER 0x08
-#define GSM48_MT_RR_PDCH_ASS_CMD 0x23
-
-#define GSM48_MT_RR_CHAN_REL 0x0d
-#define GSM48_MT_RR_PART_REL 0x0a
-#define GSM48_MT_RR_PART_REL_COMP 0x0f
-
-#define GSM48_MT_RR_PAG_REQ_1 0x21
-#define GSM48_MT_RR_PAG_REQ_2 0x22
-#define GSM48_MT_RR_PAG_REQ_3 0x24
-#define GSM48_MT_RR_PAG_RESP 0x27
-#define GSM48_MT_RR_NOTIF_NCH 0x20
-#define GSM48_MT_RR_NOTIF_FACCH 0x25
-#define GSM48_MT_RR_NOTIF_RESP 0x26
-
-#define GSM48_MT_RR_SYSINFO_8 0x18
-#define GSM48_MT_RR_SYSINFO_1 0x19
-#define GSM48_MT_RR_SYSINFO_2 0x1a
-#define GSM48_MT_RR_SYSINFO_3 0x1b
-#define GSM48_MT_RR_SYSINFO_4 0x1c
-#define GSM48_MT_RR_SYSINFO_5 0x1d
-#define GSM48_MT_RR_SYSINFO_6 0x1e
-#define GSM48_MT_RR_SYSINFO_7 0x1f
-
-#define GSM48_MT_RR_SYSINFO_2bis 0x02
-#define GSM48_MT_RR_SYSINFO_2ter 0x03
-#define GSM48_MT_RR_SYSINFO_5bis 0x05
-#define GSM48_MT_RR_SYSINFO_5ter 0x06
-#define GSM48_MT_RR_SYSINFO_9 0x04
-#define GSM48_MT_RR_SYSINFO_13 0x00
-
-#define GSM48_MT_RR_SYSINFO_16 0x3d
-#define GSM48_MT_RR_SYSINFO_17 0x3e
-
-#define GSM48_MT_RR_CHAN_MODE_MODIF 0x10
-#define GSM48_MT_RR_STATUS 0x12
-#define GSM48_MT_RR_CHAN_MODE_MODIF_ACK 0x17
-#define GSM48_MT_RR_FREQ_REDEF 0x14
-#define GSM48_MT_RR_MEAS_REP 0x15
-#define GSM48_MT_RR_CLSM_CHG 0x16
-#define GSM48_MT_RR_CLSM_ENQ 0x13
-#define GSM48_MT_RR_EXT_MEAS_REP 0x36
-#define GSM48_MT_RR_EXT_MEAS_REP_ORD 0x37
-#define GSM48_MT_RR_GPRS_SUSP_REQ 0x34
-
-#define GSM48_MT_RR_VGCS_UPL_GRANT 0x08
-#define GSM48_MT_RR_UPLINK_RELEASE 0x0e
-#define GSM48_MT_RR_UPLINK_FREE 0x0c
-#define GSM48_MT_RR_UPLINK_BUSY 0x2a
-#define GSM48_MT_RR_TALKER_IND 0x11
-
-#define GSM48_MT_RR_APP_INFO 0x38
-
-/* Table 10.2/3GPP TS 04.08 */
-#define GSM48_MT_MM_IMSI_DETACH_IND 0x01
-#define GSM48_MT_MM_LOC_UPD_ACCEPT 0x02
-#define GSM48_MT_MM_LOC_UPD_REJECT 0x04
-#define GSM48_MT_MM_LOC_UPD_REQUEST 0x08
-
-#define GSM48_MT_MM_AUTH_REJ 0x11
-#define GSM48_MT_MM_AUTH_REQ 0x12
-#define GSM48_MT_MM_AUTH_RESP 0x14
-#define GSM48_MT_MM_ID_REQ 0x18
-#define GSM48_MT_MM_ID_RESP 0x19
-#define GSM48_MT_MM_TMSI_REALL_CMD 0x1a
-#define GSM48_MT_MM_TMSI_REALL_COMPL 0x1b
-
-#define GSM48_MT_MM_CM_SERV_ACC 0x21
-#define GSM48_MT_MM_CM_SERV_REJ 0x22
-#define GSM48_MT_MM_CM_SERV_ABORT 0x23
-#define GSM48_MT_MM_CM_SERV_REQ 0x24
-#define GSM48_MT_MM_CM_SERV_PROMPT 0x25
-#define GSM48_MT_MM_CM_REEST_REQ 0x28
-#define GSM48_MT_MM_ABORT 0x29
-
-#define GSM48_MT_MM_NULL 0x30
-#define GSM48_MT_MM_STATUS 0x31
-#define GSM48_MT_MM_INFO 0x32
-
-/* Table 10.3/3GPP TS 04.08 */
-#define GSM48_MT_CC_ALERTING 0x01
-#define GSM48_MT_CC_CALL_CONF 0x08
-#define GSM48_MT_CC_CALL_PROC 0x02
-#define GSM48_MT_CC_CONNECT 0x07
-#define GSM48_MT_CC_CONNECT_ACK 0x0f
-#define GSM48_MT_CC_EMERG_SETUP 0x0e
-#define GSM48_MT_CC_PROGRESS 0x03
-#define GSM48_MT_CC_ESTAB 0x04
-#define GSM48_MT_CC_ESTAB_CONF 0x06
-#define GSM48_MT_CC_RECALL 0x0b
-#define GSM48_MT_CC_START_CC 0x09
-#define GSM48_MT_CC_SETUP 0x05
-
-#define GSM48_MT_CC_MODIFY 0x17
-#define GSM48_MT_CC_MODIFY_COMPL 0x1f
-#define GSM48_MT_CC_MODIFY_REJECT 0x13
-#define GSM48_MT_CC_USER_INFO 0x10
-#define GSM48_MT_CC_HOLD 0x18
-#define GSM48_MT_CC_HOLD_ACK 0x19
-#define GSM48_MT_CC_HOLD_REJ 0x1a
-#define GSM48_MT_CC_RETR 0x1c
-#define GSM48_MT_CC_RETR_ACK 0x1d
-#define GSM48_MT_CC_RETR_REJ 0x1e
-
-#define GSM48_MT_CC_DISCONNECT 0x25
-#define GSM48_MT_CC_RELEASE 0x2d
-#define GSM48_MT_CC_RELEASE_COMPL 0x2a
-
-#define GSM48_MT_CC_CONG_CTRL 0x39
-#define GSM48_MT_CC_NOTIFY 0x3e
-#define GSM48_MT_CC_STATUS 0x3d
-#define GSM48_MT_CC_STATUS_ENQ 0x34
-#define GSM48_MT_CC_START_DTMF 0x35
-#define GSM48_MT_CC_STOP_DTMF 0x31
-#define GSM48_MT_CC_STOP_DTMF_ACK 0x32
-#define GSM48_MT_CC_START_DTMF_ACK 0x36
-#define GSM48_MT_CC_START_DTMF_REJ 0x37
-#define GSM48_MT_CC_FACILITY 0x3a
-
-/* FIXME: Table 10.4 / 10.4a (GPRS) */
-
-/* Section 10.5.2.26, Table 10.5.64 */
-#define GSM48_PM_MASK 0x03
-#define GSM48_PM_NORMAL 0x00
-#define GSM48_PM_EXTENDED 0x01
-#define GSM48_PM_REORG 0x02
-#define GSM48_PM_SAME 0x03
-
-/* Chapter 10.5.3.5 / Table 10.5.93 */
-#define GSM48_LUPD_NORMAL 0x0
-#define GSM48_LUPD_PERIODIC 0x1
-#define GSM48_LUPD_IMSI_ATT 0x2
-#define GSM48_LUPD_RESERVED 0x3
-
-/* Table 10.5.4 */
-#define GSM_MI_TYPE_MASK 0x07
-#define GSM_MI_TYPE_NONE 0x00
-#define GSM_MI_TYPE_IMSI 0x01
-#define GSM_MI_TYPE_IMEI 0x02
-#define GSM_MI_TYPE_IMEISV 0x03
-#define GSM_MI_TYPE_TMSI 0x04
-#define GSM_MI_ODD 0x08
-
-#define GSM48_IE_MUL_RATE_CFG 0x03 /* 10.5.2.21aa */
-#define GSM48_IE_MOBILE_ID 0x17
-#define GSM48_IE_NAME_LONG 0x43 /* 10.5.3.5a */
-#define GSM48_IE_NAME_SHORT 0x45 /* 10.5.3.5a */
-#define GSM48_IE_UTC 0x46 /* 10.5.3.8 */
-#define GSM48_IE_NET_TIME_TZ 0x47 /* 10.5.3.9 */
-#define GSM48_IE_LSA_IDENT 0x48 /* 10.5.3.11 */
-
-#define GSM48_IE_BEARER_CAP 0x04 /* 10.5.4.5 */
-#define GSM48_IE_CAUSE 0x08 /* 10.5.4.11 */
-#define GSM48_IE_CC_CAP 0x15 /* 10.5.4.5a */
-#define GSM48_IE_ALERT 0x19 /* 10.5.4.26 */
-#define GSM48_IE_FACILITY 0x1c /* 10.5.4.15 */
-#define GSM48_IE_PROGR_IND 0x1e /* 10.5.4.21 */
-#define GSM48_IE_AUX_STATUS 0x24 /* 10.5.4.4 */
-#define GSM48_IE_NOTIFY 0x27 /* 10.5.4.20 */
-#define GSM48_IE_KPD_FACILITY 0x2c /* 10.5.4.17 */
-#define GSM48_IE_SIGNAL 0x34 /* 10.5.4.23 */
-#define GSM48_IE_CONN_BCD 0x4c /* 10.5.4.13 */
-#define GSM48_IE_CONN_SUB 0x4d /* 10.5.4.14 */
-#define GSM48_IE_CALLING_BCD 0x5c /* 10.5.4.9 */
-#define GSM48_IE_CALLING_SUB 0x5d /* 10.5.4.10 */
-#define GSM48_IE_CALLED_BCD 0x5e /* 10.5.4.7 */
-#define GSM48_IE_CALLED_SUB 0x6d /* 10.5.4.8 */
-#define GSM48_IE_REDIR_BCD 0x74 /* 10.5.4.21a */
-#define GSM48_IE_REDIR_SUB 0x75 /* 10.5.4.21b */
-#define GSM48_IE_LOWL_COMPAT 0x7c /* 10.5.4.18 */
-#define GSM48_IE_HIGHL_COMPAT 0x7d /* 10.5.4.16 */
-#define GSM48_IE_USER_USER 0x7e /* 10.5.4.25 */
-#define GSM48_IE_SS_VERS 0x7f /* 10.5.4.24 */
-#define GSM48_IE_MORE_DATA 0xa0 /* 10.5.4.19 */
-#define GSM48_IE_CLIR_SUPP 0xa1 /* 10.5.4.11a */
-#define GSM48_IE_CLIR_INVOC 0xa2 /* 10.5.4.11b */
-#define GSM48_IE_REV_C_SETUP 0xa3 /* 10.5.4.22a */
-#define GSM48_IE_REPEAT_CIR 0xd1 /* 10.5.4.22 */
-#define GSM48_IE_REPEAT_SEQ 0xd3 /* 10.5.4.22 */
-
-/* Section 10.5.4.11 / Table 10.5.122 */
-#define GSM48_CAUSE_CS_GSM 0x60
-
-/* Section 9.1.2 / Table 9.3 */
-#define GSM48_IE_FRQLIST_AFTER 0x05
-#define GSM48_IE_CELL_CH_DESC 0x62
-#define GSM48_IE_MSLOT_DESC 0x10
-#define GSM48_IE_CHANMODE_1 0x63
-#define GSM48_IE_CHANMODE_2 0x11
-#define GSM48_IE_CHANMODE_3 0x13
-#define GSM48_IE_CHANMODE_4 0x14
-#define GSM48_IE_CHANMODE_5 0x15
-#define GSM48_IE_CHANMODE_6 0x16
-#define GSM48_IE_CHANMODE_7 0x17
-#define GSM48_IE_CHANMODE_8 0x18
-#define GSM48_IE_CHANDESC_2 0x64
-/* FIXME */
-
-/* Section 10.5.4.23 / Table 10.5.130 */
-enum gsm48_signal_val {
- GSM48_SIGNAL_DIALTONE = 0x00,
- GSM48_SIGNAL_RINGBACK = 0x01,
- GSM48_SIGNAL_INTERCEPT = 0x02,
- GSM48_SIGNAL_NET_CONG = 0x03,
- GSM48_SIGNAL_BUSY = 0x04,
- GSM48_SIGNAL_CONFIRM = 0x05,
- GSM48_SIGNAL_ANSWER = 0x06,
- GSM48_SIGNAL_CALL_WAIT = 0x07,
- GSM48_SIGNAL_OFF_HOOK = 0x08,
- GSM48_SIGNAL_OFF = 0x3f,
- GSM48_SIGNAL_ALERT_OFF = 0x4f,
-};
-
-enum gsm48_cause_loc {
- GSM48_CAUSE_LOC_USER = 0x00,
- GSM48_CAUSE_LOC_PRN_S_LU = 0x01,
- GSM48_CAUSE_LOC_PUN_S_LU = 0x02,
- GSM48_CAUSE_LOC_TRANS_NET = 0x03,
- GSM48_CAUSE_LOC_PUN_S_RU = 0x04,
- GSM48_CAUSE_LOC_PRN_S_RU = 0x05,
- /* not defined */
- GSM48_CAUSE_LOC_INN_NET = 0x07,
- GSM48_CAUSE_LOC_NET_BEYOND = 0x0a,
-};
-
-/* Section 10.5.2.31 RR Cause / Table 10.5.70 */
-enum gsm48_rr_cause {
- GSM48_RR_CAUSE_NORMAL = 0x00,
- GSM48_RR_CAUSE_ABNORMAL_UNSPEC = 0x01,
- GSM48_RR_CAUSE_ABNORMAL_UNACCT = 0x02,
- GSM48_RR_CAUSE_ABNORMAL_TIMER = 0x03,
- GSM48_RR_CAUSE_ABNORMAL_NOACT = 0x04,
- GSM48_RR_CAUSE_PREMPTIVE_REL = 0x05,
- GSM48_RR_CAUSE_HNDOVER_IMP = 0x06,
- GSM48_RR_CAUSE_CHAN_MODE_UNACCT = 0x07,
- GSM48_RR_CAUSE_FREQ_NOT_IMPL = 0x08,
- GSM48_RR_CAUSE_CALL_CLEARED = 0x41,
- GSM48_RR_CAUSE_SEMANT_INCORR = 0x5f,
- GSM48_RR_CAUSE_INVALID_MAND_INF = 0x60,
- GSM48_RR_CAUSE_MSG_TYPE_N = 0x61,
- GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT= 0x62,
- GSM48_RR_CAUSE_COND_IE_ERROR = 0x64,
- GSM48_RR_CAUSE_NO_CELL_ALLOC_A = 0x65,
- GSM48_RR_CAUSE_PROT_ERROR_UNSPC = 0x6f,
-};
-
-/* Section 10.5.4.11 CC Cause / Table 10.5.123 */
-enum gsm48_cc_cause {
- GSM48_CC_CAUSE_UNASSIGNED_NR = 1,
- GSM48_CC_CAUSE_NO_ROUTE = 3,
- GSM48_CC_CAUSE_CHAN_UNACCEPT = 6,
- GSM48_CC_CAUSE_OP_DET_BARRING = 8,
- GSM48_CC_CAUSE_NORM_CALL_CLEAR = 16,
- GSM48_CC_CAUSE_USER_BUSY = 17,
- GSM48_CC_CAUSE_USER_NOTRESPOND = 18,
- GSM48_CC_CAUSE_USER_ALERTING_NA = 19,
- GSM48_CC_CAUSE_CALL_REJECTED = 21,
- GSM48_CC_CAUSE_NUMBER_CHANGED = 22,
- GSM48_CC_CAUSE_PRE_EMPTION = 25,
- GSM48_CC_CAUSE_NONSE_USER_CLR = 26,
- GSM48_CC_CAUSE_DEST_OOO = 27,
- GSM48_CC_CAUSE_INV_NR_FORMAT = 28,
- GSM48_CC_CAUSE_FACILITY_REJ = 29,
- GSM48_CC_CAUSE_RESP_STATUS_INQ = 30,
- GSM48_CC_CAUSE_NORMAL_UNSPEC = 31,
- GSM48_CC_CAUSE_NO_CIRCUIT_CHAN = 34,
- GSM48_CC_CAUSE_NETWORK_OOO = 38,
- GSM48_CC_CAUSE_TEMP_FAILURE = 41,
- GSM48_CC_CAUSE_SWITCH_CONG = 42,
- GSM48_CC_CAUSE_ACC_INF_DISCARD = 43,
- GSM48_CC_CAUSE_REQ_CHAN_UNAVAIL = 44,
- GSM48_CC_CAUSE_RESOURCE_UNAVAIL = 47,
- GSM48_CC_CAUSE_QOS_UNAVAIL = 49,
- GSM48_CC_CAUSE_REQ_FAC_NOT_SUBSC= 50,
- GSM48_CC_CAUSE_INC_BARRED_CUG = 55,
- GSM48_CC_CAUSE_BEARER_CAP_UNAUTH= 57,
- GSM48_CC_CAUSE_BEARER_CA_UNAVAIL= 58,
- GSM48_CC_CAUSE_SERV_OPT_UNAVAIL = 63,
- GSM48_CC_CAUSE_BEARERSERV_UNIMPL= 65,
- GSM48_CC_CAUSE_ACM_GE_ACM_MAX = 68,
- GSM48_CC_CAUSE_REQ_FAC_NOTIMPL = 69,
- GSM48_CC_CAUSE_RESTR_BCAP_AVAIL = 70,
- GSM48_CC_CAUSE_SERV_OPT_UNIMPL = 79,
- GSM48_CC_CAUSE_INVAL_TRANS_ID = 81,
- GSM48_CC_CAUSE_USER_NOT_IN_CUG = 87,
- GSM48_CC_CAUSE_INCOMPAT_DEST = 88,
- GSM48_CC_CAUSE_INVAL_TRANS_NET = 91,
- GSM48_CC_CAUSE_SEMANTIC_INCORR = 95,
- GSM48_CC_CAUSE_INVAL_MAND_INF = 96,
- GSM48_CC_CAUSE_MSGTYPE_NOTEXIST = 97,
- GSM48_CC_CAUSE_MSGTYPE_INCOMPAT = 98,
- GSM48_CC_CAUSE_IE_NOTEXIST = 99,
- GSM48_CC_CAUSE_COND_IE_ERR = 100,
- GSM48_CC_CAUSE_MSG_INCOMP_STATE = 101,
- GSM48_CC_CAUSE_RECOVERY_TIMER = 102,
- GSM48_CC_CAUSE_PROTO_ERR = 111,
- GSM48_CC_CAUSE_INTERWORKING = 127,
-};
-
-/* Annex G, GSM specific cause values for mobility management */
-enum gsm48_reject_value {
- GSM48_REJECT_IMSI_UNKNOWN_IN_HLR = 2,
- GSM48_REJECT_ILLEGAL_MS = 3,
- GSM48_REJECT_IMSI_UNKNOWN_IN_VLR = 4,
- GSM48_REJECT_IMEI_NOT_ACCEPTED = 5,
- GSM48_REJECT_ILLEGAL_ME = 6,
- GSM48_REJECT_PLMN_NOT_ALLOWED = 11,
- GSM48_REJECT_LOC_NOT_ALLOWED = 12,
- GSM48_REJECT_ROAMING_NOT_ALLOWED = 13,
- GSM48_REJECT_NETWORK_FAILURE = 17,
- GSM48_REJECT_CONGESTION = 22,
- GSM48_REJECT_SRV_OPT_NOT_SUPPORTED = 32,
- GSM48_REJECT_RQD_SRV_OPT_NOT_SUPPORTED = 33,
- GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER = 34,
- GSM48_REJECT_CALL_CAN_NOT_BE_IDENTIFIED = 38,
- GSM48_REJECT_INCORRECT_MESSAGE = 95,
- GSM48_REJECT_INVALID_MANDANTORY_INF = 96,
- GSM48_REJECT_MSG_TYPE_NOT_IMPLEMENTED = 97,
- GSM48_REJECT_MSG_TYPE_NOT_COMPATIBLE = 98,
- GSM48_REJECT_INF_ELEME_NOT_IMPLEMENTED = 99,
- GSM48_REJECT_CONDTIONAL_IE_ERROR = 100,
- GSM48_REJECT_MSG_NOT_COMPATIBLE = 101,
- GSM48_REJECT_PROTOCOL_ERROR = 111,
-
- /* according to G.6 Additional cause codes for GMM */
- GSM48_REJECT_GPRS_NOT_ALLOWED = 7,
- GSM48_REJECT_SERVICES_NOT_ALLOWED = 8,
- GSM48_REJECT_MS_IDENTITY_NOT_DERVIVABLE = 9,
- GSM48_REJECT_IMPLICITLY_DETACHED = 10,
- GSM48_REJECT_GPRS_NOT_ALLOWED_IN_PLMN = 14,
- GSM48_REJECT_MSC_TMP_NOT_REACHABLE = 16,
-};
-
-enum chreq_type {
- CHREQ_T_EMERG_CALL,
- CHREQ_T_CALL_REEST_TCH_F,
- CHREQ_T_CALL_REEST_TCH_H,
- CHREQ_T_CALL_REEST_TCH_H_DBL,
- CHREQ_T_SDCCH,
- CHREQ_T_TCH_F,
- CHREQ_T_VOICE_CALL_TCH_H,
- CHREQ_T_DATA_CALL_TCH_H,
- CHREQ_T_LOCATION_UPD,
- CHREQ_T_PAG_R_ANY_NECI0,
- CHREQ_T_PAG_R_ANY_NECI1,
- CHREQ_T_PAG_R_TCH_F,
- CHREQ_T_PAG_R_TCH_FH,
- CHREQ_T_LMU,
- CHREQ_T_RESERVED_SDCCH,
- CHREQ_T_RESERVED_IGNORE,
-};
-
-/* Chapter 11.3 */
-#define GSM48_T301 180, 0
-#define GSM48_T303 30, 0
-#define GSM48_T305 30, 0
-#define GSM48_T306 30, 0
-#define GSM48_T308 10, 0
-#define GSM48_T310 180, 0
-#define GSM48_T313 30, 0
-#define GSM48_T323 30, 0
-#define GSM48_T331 30, 0
-#define GSM48_T333 30, 0
-#define GSM48_T334 25, 0 /* min 15 */
-#define GSM48_T338 30, 0
-
-/* Chapter 5.1.2.2 */
-#define GSM_CSTATE_NULL 0
-#define GSM_CSTATE_INITIATED 1
-#define GSM_CSTATE_MO_CALL_PROC 3
-#define GSM_CSTATE_CALL_DELIVERED 4
-#define GSM_CSTATE_CALL_PRESENT 6
-#define GSM_CSTATE_CALL_RECEIVED 7
-#define GSM_CSTATE_CONNECT_REQUEST 8
-#define GSM_CSTATE_MO_TERM_CALL_CONF 9
-#define GSM_CSTATE_ACTIVE 10
-#define GSM_CSTATE_DISCONNECT_REQ 12
-#define GSM_CSTATE_DISCONNECT_IND 12
-#define GSM_CSTATE_RELEASE_REQ 19
-#define GSM_CSTATE_MO_ORIG_MODIFY 26
-#define GSM_CSTATE_MO_TERM_MODIFY 27
-#define GSM_CSTATE_CONNECT_IND 28
-
-#define SBIT(a) (1 << a)
-#define ALL_STATES 0xffffffff
-
-/* Table 10.5.3/3GPP TS 04.08: Location Area Identification information element */
-#define GSM_LAC_RESERVED_DETACHED 0x0
-#define GSM_LAC_RESERVED_ALL_BTS 0xfffe
-
-/* 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,
-};
-
-
-#define GSM48_TMSI_LEN 5
-#define GSM48_MID_TMSI_LEN (GSM48_TMSI_LEN + 2)
-#define GSM48_MI_SIZE 32
-
+#include <osmocore/protocol/gsm_04_08.h>
+#include <osmocore/gsm48.h>
struct msgb;
struct gsm_bts;
@@ -750,18 +16,14 @@ struct gsm_trans;
void gsm0408_allow_everyone(int allow);
int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id);
-void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
- u_int16_t mnc, u_int16_t lac);
enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci);
enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci);
int gsm48_tx_mm_info(struct gsm_lchan *lchan);
-int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand);
+int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand, int key_seq);
int gsm48_tx_mm_auth_rej(struct gsm_lchan *lchan);
struct msgb *gsm48_msgb_alloc(void);
int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans);
-int gsm48_generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi);
-int gsm48_generate_mid_from_imsi(u_int8_t *buf, const char* imsi);
int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, const int mi_len);
int gsm48_send_rr_release(struct gsm_lchan *lchan);
@@ -782,8 +44,6 @@ int encode_bcd_number(u_int8_t *bcd_lv, u_int8_t max_len,
int decode_bcd_number(char *output, int output_len, const u_int8_t *bcd_lv,
int h_len);
-extern const char *gsm0408_cc_msg_names[];
-
int send_siemens_mrpci(struct gsm_lchan *lchan, u_int8_t *classmark2_lv);
int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type);
int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr);
diff --git a/openbsc/include/openbsc/gsm_04_11.h b/openbsc/include/openbsc/gsm_04_11.h
index 1851bba53..9badd3659 100644
--- a/openbsc/include/openbsc/gsm_04_11.h
+++ b/openbsc/include/openbsc/gsm_04_11.h
@@ -1,187 +1,7 @@
#ifndef _GSM_04_11_H
#define _GSM_04_11_H
-/* GSM TS 04.11 definitions */
-
-/* Chapter 5.2.3: SMC-CS states at the network side */
-enum gsm411_cp_state {
- GSM411_CPS_IDLE = 0,
- GSM411_CPS_MM_CONN_PENDING = 1, /* only MT ! */
- GSM411_CPS_WAIT_CP_ACK = 2,
- GSM411_CPS_MM_ESTABLISHED = 3,
-};
-
-/* Chapter 6.2.2: SMR states at the network side */
-enum gsm411_rp_state {
- GSM411_RPS_IDLE = 0,
- GSM411_RPS_WAIT_FOR_RP_ACK = 1,
- GSM411_RPS_WAIT_TO_TX_RP_ACK = 3,
-};
-
-/* Chapter 8.1.2 (refers to GSM 04.07 Chapter 11.2.3.1.1 */
-#define GSM411_PDISC_SMS 0x09
-
-/* Chapter 8.1.3 */
-#define GSM411_MT_CP_DATA 0x01
-#define GSM411_MT_CP_ACK 0x04
-#define GSM411_MT_CP_ERROR 0x10
-
-enum gsm411_cp_ie {
- GSM411_CP_IE_USER_DATA = 0x01, /* 8.1.4.1 */
- GSM411_CP_IE_CAUSE = 0x02, /* 8.1.4.2. */
-};
-
-/* Section 8.1.4.2 / Table 8.2 */
-enum gsm411_cp_cause {
- GSM411_CP_CAUSE_NET_FAIL = 17,
- GSM411_CP_CAUSE_CONGESTION = 22,
- GSM411_CP_CAUSE_INV_TRANS_ID = 81,
- GSM411_CP_CAUSE_SEMANT_INC_MSG = 95,
- GSM411_CP_CAUSE_INV_MAND_INF = 96,
- GSM411_CP_CAUSE_MSGTYPE_NOTEXIST= 97,
- GSM411_CP_CAUSE_MSG_INCOMP_STATE= 98,
- GSM411_CP_CAUSE_IE_NOTEXIST = 99,
- GSM411_CP_CAUSE_PROTOCOL_ERR = 111,
-};
-
-/* Chapter 8.2.2 */
-#define GSM411_MT_RP_DATA_MO 0x00
-#define GSM411_MT_RP_DATA_MT 0x01
-#define GSM411_MT_RP_ACK_MO 0x02
-#define GSM411_MT_RP_ACK_MT 0x03
-#define GSM411_MT_RP_ERROR_MO 0x04
-#define GSM411_MT_RP_ERROR_MT 0x05
-#define GSM411_MT_RP_SMMA_MO 0x06
-
-enum gsm411_rp_ie {
- GSM411_IE_RP_USER_DATA = 0x41, /* 8.2.5.3 */
- GSM411_IE_RP_CAUSE = 0x42, /* 8.2.5.4 */
-};
-
-/* Chapter 8.2.5.4 Table 8.4 */
-enum gsm411_rp_cause {
- /* valid only for MO */
- GSM411_RP_CAUSE_MO_NUM_UNASSIGNED = 1,
- GSM411_RP_CAUSE_MO_OP_DET_BARR = 8,
- GSM411_RP_CAUSE_MO_CALL_BARRED = 10,
- GSM411_RP_CAUSE_MO_SMS_REJECTED = 21,
- GSM411_RP_CAUSE_MO_DEST_OUT_OF_ORDER = 27,
- GSM411_RP_CAUSE_MO_UNIDENTIFIED_SUBSCR = 28,
- GSM411_RP_CAUSE_MO_FACILITY_REJ = 29,
- GSM411_RP_CAUSE_MO_UNKNOWN_SUBSCR = 30,
- GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER = 38,
- GSM411_RP_CAUSE_MO_TEMP_FAIL = 41,
- GSM411_RP_CAUSE_MO_CONGESTION = 42,
- GSM411_RP_CAUSE_MO_RES_UNAVAIL = 47,
- GSM411_RP_CAUSE_MO_REQ_FAC_NOTSUBSCR = 50,
- GSM411_RP_CAUSE_MO_REQ_FAC_NOTIMPL = 69,
- GSM411_RP_CAUSE_MO_INTERWORKING = 127,
- /* valid only for MT */
- GSM411_RP_CAUSE_MT_MEM_EXCEEDED = 22,
- /* valid for both directions */
- GSM411_RP_CAUSE_INV_TRANS_REF = 81,
- GSM411_RP_CAUSE_SEMANT_INC_MSG = 95,
- GSM411_RP_CAUSE_INV_MAND_INF = 96,
- GSM411_RP_CAUSE_MSGTYPE_NOTEXIST = 97,
- GSM411_RP_CAUSE_MSG_INCOMP_STATE = 98,
- GSM411_RP_CAUSE_IE_NOTEXIST = 99,
- GSM411_RP_CAUSE_PROTOCOL_ERR = 111,
-};
-
-/* Chapter 10: Timers */
-#define GSM411_TMR_TR1M 40, 0 /* 35 < x < 45 seconds */
-#define GSM411_TMR_TRAM 30, 0 /* 25 < x < 35 seconds */
-#define GSM411_TMR_TR2M 15, 0 /* 12 < x < 20 seconds */
-
-#define GSM411_TMR_TC1A 30, 0
-
-/* Chapter 8.2.1 */
-struct gsm411_rp_hdr {
- u_int8_t len;
- u_int8_t msg_type;
- u_int8_t msg_ref;
- u_int8_t data[0];
-} __attribute__ ((packed));
-
-/* our own enum, not related to on-air protocol */
-enum sms_alphabet {
- DCS_NONE,
- DCS_7BIT_DEFAULT,
- DCS_UCS2,
- DCS_8BIT_DATA,
-};
-
-/* GSM 03.40 / Chapter 9.2.3.1: TP-Message-Type-Indicator */
-#define GSM340_SMS_DELIVER_SC2MS 0x00
-#define GSM340_SMS_DELIVER_REP_MS2SC 0x00
-#define GSM340_SMS_STATUS_REP_SC2MS 0x02
-#define GSM340_SMS_COMMAND_MS2SC 0x02
-#define GSM340_SMS_SUBMIT_MS2SC 0x01
-#define GSM340_SMS_SUBMIT_REP_SC2MS 0x01
-#define GSM340_SMS_RESSERVED 0x03
-
-/* GSM 03.40 / Chapter 9.2.3.2: TP-More-Messages-to-Send */
-#define GSM340_TP_MMS_MORE 0
-#define GSM340_TP_MMS_NO_MORE 1
-
-/* GSM 03.40 / Chapter 9.2.3.3: TP-Validity-Period-Format */
-#define GSM340_TP_VPF_NONE 0
-#define GSM340_TP_VPF_RELATIVE 2
-#define GSM340_TP_VPF_ENHANCED 1
-#define GSM340_TP_VPF_ABSOLUTE 3
-
-/* GSM 03.40 / Chapter 9.2.3.4: TP-Status-Report-Indication */
-#define GSM340_TP_SRI_NONE 0
-#define GSM340_TP_SRI_PRESENT 1
-
-/* GSM 03.40 / Chapter 9.2.3.5: TP-Status-Report-Request */
-#define GSM340_TP_SRR_NONE 0
-#define GSM340_TP_SRR_REQUESTED 1
-
-/* GSM 03.40 / Chapter 9.2.3.9: TP-Protocol-Identifier */
-/* telematic interworking (001 or 111 in bits 7-5) */
-#define GSM340_TP_PID_IMPLICIT 0x00
-#define GSM340_TP_PID_TELEX 0x01
-#define GSM340_TP_PID_FAX_G3 0x02
-#define GSM340_TP_PID_FAX_G4 0x03
-#define GSM340_TP_PID_VOICE 0x04
-#define GSM430_TP_PID_ERMES 0x05
-#define GSM430_TP_PID_NATIONAL_PAGING 0x06
-#define GSM430_TP_PID_VIDEOTEX 0x07
-#define GSM430_TP_PID_TELETEX_UNSPEC 0x08
-#define GSM430_TP_PID_TELETEX_PSPDN 0x09
-#define GSM430_TP_PID_TELETEX_CSPDN 0x0a
-#define GSM430_TP_PID_TELETEX_PSTN 0x0b
-#define GSM430_TP_PID_TELETEX_ISDN 0x0c
-#define GSM430_TP_PID_TELETEX_UCI 0x0d
-#define GSM430_TP_PID_MSG_HANDLING 0x10
-#define GSM430_TP_PID_MSG_X400 0x11
-#define GSM430_TP_PID_EMAIL 0x12
-#define GSM430_TP_PID_GSM_MS 0x1f
-/* if bit 7 = 0 and bit 6 = 1 */
-#define GSM430_TP_PID_SMS_TYPE_0 0
-#define GSM430_TP_PID_SMS_TYPE_1 1
-#define GSM430_TP_PID_SMS_TYPE_2 2
-#define GSM430_TP_PID_SMS_TYPE_3 3
-#define GSM430_TP_PID_SMS_TYPE_4 4
-#define GSM430_TP_PID_SMS_TYPE_5 5
-#define GSM430_TP_PID_SMS_TYPE_6 6
-#define GSM430_TP_PID_SMS_TYPE_7 7
-#define GSM430_TP_PID_RETURN_CALL_MSG 0x1f
-#define GSM430_TP_PID_ME_DATA_DNLOAD 0x3d
-#define GSM430_TP_PID_ME_DE_PERSONAL 0x3e
-#define GSM430_TP_PID_ME_SIM_DNLOAD 0x3f
-
-/* GSM 03.38 Chapter 4: SMS Data Coding Scheme */
-#define GSM338_DCS_00_
-
-#define GSM338_DCS_1110_7BIT (0 << 2)
-#define GSM338_DCS_1111_7BIT (0 << 2)
-#define GSM338_DCS_1111_8BIT_DATA (1 << 2)
-#define GSM338_DCS_1111_CLASS0 0
-#define GSM338_DCS_1111_CLASS1_ME 1
-#define GSM338_DCS_1111_CLASS2_SIM 2
-#define GSM338_DCS_1111_CLASS3_TE 3 /* See TS 07.05 */
+#include <osmocore/protocol/gsm_04_11.h>
/* SMS deliver PDU */
struct sms_deliver {
diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h
index c240bbe94..b5ab1c6ea 100644
--- a/openbsc/include/openbsc/gsm_04_80.h
+++ b/openbsc/include/openbsc/gsm_04_80.h
@@ -1,129 +1,8 @@
#ifndef _GSM_04_80_H
#define _GSM_04_80_H
-/* GSM TS 04.80 definitions (Supplementary Services Specification, Formats and Coding) */
-
-/* Section 3.4 */
-#define GSM0480_MTYPE_RELEASE_COMPLETE 0x2A
-#define GSM0480_MTYPE_FACILITY 0x3A
-#define GSM0480_MTYPE_REGISTER 0x3B
-
-/* Section 3.5 */
-#define GSM0480_IE_FACILITY 0x1C
-#define GSM0480_IE_SS_VERSION 0x7F
-
-/* Section 3.6.2 */
-#define GSM0480_CTYPE_INVOKE 0xA1
-#define GSM0480_CTYPE_RETURN_RESULT 0xA2
-#define GSM0480_CTYPE_RETURN_ERROR 0xA3
-#define GSM0480_CTYPE_REJECT 0xA4
-
-/* Section 3.6.3 */
-#define GSM0480_COMPIDTAG_INVOKE_ID 0x02
-#define GSM0480_COMPIDTAG_LINKED_ID 0x80
-
-/* Section 3.6.4 */
-#define GSM0480_OPERATION_CODE 0x02
-
-/* Section 3.6.5 */
-#define GSM_0480_SEQUENCE_TAG 0x30
-#define GSM_0480_SET_TAG 0x31
-
-/* Section 3.6.6 */
-#define GSM_0480_ERROR_CODE_TAG 0x02
-
-/* Section 3.6.7 */
-/* Table 3.13 */
-#define GSM_0480_PROBLEM_CODE_TAG_GENERAL 0x80
-#define GSM_0480_PROBLEM_CODE_TAG_INVOKE 0x81
-#define GSM_0480_PROBLEM_CODE_TAG_RETURN_RESULT 0x82
-#define GSM_0480_PROBLEM_CODE_TAG_RETURN_ERROR 0x83
-
-/* Table 3.14 */
-#define GSM_0480_GEN_PROB_CODE_UNRECOGNISED 0x00
-#define GSM_0480_GEN_PROB_CODE_MISTYPED 0x01
-#define GSM_0480_GEN_PROB_CODE_BAD_STRUCTURE 0x02
-
-/* Table 3.15 */
-#define GSM_0480_INVOKE_PROB_CODE_DUPLICATE_INVOKE_ID 0x00
-#define GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_OPERATION 0x01
-#define GSM_0480_INVOKE_PROB_CODE_MISTYPED_PARAMETER 0x02
-#define GSM_0480_INVOKE_PROB_CODE_RESOURCE_LIMITATION 0x03
-#define GSM_0480_INVOKE_PROB_CODE_INITIATING_RELEASE 0x04
-#define GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_LINKED_ID 0x05
-#define GSM_0480_INVOKE_PROB_CODE_UNEXPECTED_LINKED_RESPONSE 0x06
-#define GSM_0480_INVOKE_PROB_CODE_UNEXPECTED_LINKED_OPERATION 0x07
-
-/* Table 3.16 */
-#define GSM_0480_RESULT_PROB_CODE_UNRECOGNISED_INVOKE_ID 0x00
-#define GSM_0480_RESULT_PROB_CODE_RETURN_RESULT_UNEXPECTED 0x01
-#define GSM_0480_RESULT_PROB_CODE_MISTYPED_PARAMETER 0x02
-
-/* Table 3.17 */
-#define GSM_0480_ERROR_PROB_CODE_UNRECOGNISED_INVOKE_ID 0x00
-#define GSM_0480_ERROR_PROB_CODE_RETURN_ERROR_UNEXPECTED 0x01
-#define GSM_0480_ERROR_PROB_CODE_UNRECOGNISED_ERROR 0x02
-#define GSM_0480_ERROR_PROB_CODE_UNEXPECTED_ERROR 0x03
-#define GSM_0480_ERROR_PROB_CODE_MISTYPED_PARAMETER 0x04
-
-/* Section 4.5 */
-#define GSM0480_OP_CODE_REGISTER_SS 0x0A
-#define GSM0480_OP_CODE_ERASE_SS 0x0B
-#define GSM0480_OP_CODE_ACTIVATE_SS 0x0C
-#define GSM0480_OP_CODE_DEACTIVATE_SS 0x0D
-#define GSM0480_OP_CODE_INTERROGATE_SS 0x0E
-#define GSM0480_OP_CODE_NOTIFY_SS 0x10
-#define GSM0480_OP_CODE_REGISTER_PASSWORD 0x11
-#define GSM0480_OP_CODE_GET_PASSWORD 0x12
-#define GSM0480_OP_CODE_PROCESS_USS_DATA 0x13
-#define GSM0480_OP_CODE_FORWARD_CHECK_SS_IND 0x26
-#define GSM0480_OP_CODE_PROCESS_USS_REQ 0x3B
-#define GSM0480_OP_CODE_USS_REQUEST 0x3C
-#define GSM0480_OP_CODE_USS_NOTIFY 0x3D
-#define GSM0480_OP_CODE_FORWARD_CUG_INFO 0x78
-#define GSM0480_OP_CODE_SPLIT_MPTY 0x79
-#define GSM0480_OP_CODE_RETRIEVE_MPTY 0x7A
-#define GSM0480_OP_CODE_HOLD_MPTY 0x7B
-#define GSM0480_OP_CODE_BUILD_MPTY 0x7C
-#define GSM0480_OP_CODE_FORWARD_CHARGE_ADVICE 0x7D
-
-#define GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER 0x01
-#define GSM0480_ERR_CODE_ILLEGAL_SUBSCRIBER 0x09
-#define GSM0480_ERR_CODE_BEARER_SERVICE_NOT_PROVISIONED 0x0A
-#define GSM0480_ERR_CODE_TELESERVICE_NOT_PROVISIONED 0x0B
-#define GSM0480_ERR_CODE_ILLEGAL_EQUIPMENT 0x0C
-#define GSM0480_ERR_CODE_CALL_BARRED 0x0D
-#define GSM0480_ERR_CODE_ILLEGAL_SS_OPERATION 0x10
-#define GSM0480_ERR_CODE_SS_ERROR_STATUS 0x11
-#define GSM0480_ERR_CODE_SS_NOT_AVAILABLE 0x12
-#define GSM0480_ERR_CODE_SS_SUBSCRIPTION_VIOLATION 0x13
-#define GSM0480_ERR_CODE_SS_INCOMPATIBILITY 0x14
-#define GSM0480_ERR_CODE_FACILITY_NOT_SUPPORTED 0x15
-#define GSM0480_ERR_CODE_ABSENT_SUBSCRIBER 0x1B
-#define GSM0480_ERR_CODE_SYSTEM_FAILURE 0x22
-#define GSM0480_ERR_CODE_DATA_MISSING 0x23
-#define GSM0480_ERR_CODE_UNEXPECTED_DATA_VALUE 0x24
-#define GSM0480_ERR_CODE_PW_REGISTRATION_FAILURE 0x25
-#define GSM0480_ERR_CODE_NEGATIVE_PW_CHECK 0x26
-#define GSM0480_ERR_CODE_NUM_PW_ATTEMPTS_VIOLATION 0x2B
-#define GSM0480_ERR_CODE_UNKNOWN_ALPHABET 0x47
-#define GSM0480_ERR_CODE_USSD_BUSY 0x48
-#define GSM0480_ERR_CODE_MAX_MPTY_PARTICIPANTS 0x7E
-#define GSM0480_ERR_CODE_RESOURCES_NOT_AVAILABLE 0x7F
-
-/* ASN.1 type-tags */
-#define ASN1_BOOLEAN_TAG 0x01
-#define ASN1_INTEGER_TAG 0x02
-#define ASN1_BIT_STRING_TAG 0x03
-#define ASN1_OCTET_STRING_TAG 0x04
-#define ASN1_NULL_TYPE_TAG 0x05
-#define ASN1_OBJECT_ID_TAG 0x06
-#define ASN1_UTF8_STRING_TAG 0x0C
-#define ASN1_PRINTABLE_STRING_TAG 0x13
-#define ASN1_IA5_STRING_TAG 0x16
-#define ASN1_UNICODE_STRING_TAG 0x1E
-
-#include <openbsc/msgb.h>
+#include <osmocore/msgb.h>
+#include <osmocore/protocol/gsm_04_80.h>
#define MAX_LEN_USSD_STRING 31
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index d42e8efe3..dd7f6c11e 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -3,21 +3,6 @@
#include <sys/types.h>
-struct value_string {
- unsigned int value;
- const char *str;
-};
-
-const char *get_value_string(const struct value_string *vs, u_int32_t val);
-
-enum gsm_band {
- GSM_BAND_400,
- GSM_BAND_850,
- GSM_BAND_900,
- GSM_BAND_1800,
- GSM_BAND_1900,
-};
-
enum gsm_phys_chan_config {
GSM_PCHAN_NONE,
GSM_PCHAN_CCCH,
@@ -55,14 +40,15 @@ enum gsm_chreq_reason_t {
GSM_CHREQ_REASON_OTHER,
};
-#include <openbsc/timer.h>
+#include <osmocore/timer.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/mncc.h>
-#include <openbsc/tlv.h>
-#include <openbsc/bitvec.h>
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#include <osmocore/tlv.h>
+#include <osmocore/bitvec.h>
+#include <osmocore/statistics.h>
+#include <osmocore/gsm_utils.h>
+#include <osmocore/utils.h>
#define TRX_NR_TS 8
#define TS_MAX_LCHAN 8
@@ -99,6 +85,29 @@ struct gsm_bts_link {
};
struct sccp_connection;
+
+/* Real authentication information containing Ki */
+enum gsm_auth_algo {
+ AUTH_ALGO_NONE,
+ AUTH_ALGO_XOR,
+ AUTH_ALGO_COMP128v1,
+};
+
+struct gsm_auth_info {
+ enum gsm_auth_algo auth_algo;
+ unsigned int a3a8_ki_len;
+ u_int8_t a3a8_ki[16];
+};
+
+struct gsm_auth_tuple {
+ int use_count;
+ int key_seq;
+ u_int8_t rand[16];
+ u_int8_t sres[4];
+ u_int8_t kc[8];
+};
+
+
struct gsm_lchan;
struct gsm_subscriber;
struct gsm_mncc;
@@ -183,7 +192,9 @@ struct neigh_meas_proc {
/* state of a logical channel */
enum gsm_lchan_state {
LCHAN_S_NONE, /* channel is not active */
+ LCHAN_S_ACT_REQ, /* channel activatin requested */
LCHAN_S_ACTIVE, /* channel is active and operational */
+ LCHAN_S_REL_REQ, /* channel release has been requested */
LCHAN_S_INACTIVE, /* channel is set inactive */
};
@@ -209,6 +220,8 @@ struct gsm_lchan {
u_int8_t key_len;
u_int8_t key[MAX_A5_KEY_LEN];
} encr;
+ /* Are we part of a special "silent" call */
+ int silent_call;
/* AMR bits */
struct gsm48_multi_rate_conf mr_conf;
@@ -317,9 +330,6 @@ struct gsm_bts_trx {
} bs11;
};
struct gsm_bts_trx_ts ts[TRX_NR_TS];
-
- /* NM state */
- int rf_locked;
};
enum gsm_bts_type {
@@ -328,6 +338,15 @@ enum gsm_bts_type {
GSM_BTS_TYPE_NANOBTS,
};
+struct gsm_bts_model {
+ struct llist_head list;
+
+ enum gsm_bts_type type;
+ const char *name;
+
+ struct tlv_definition nm_att_tlvdef;
+};
+
/**
* A pending paging request
*/
@@ -395,6 +414,7 @@ struct gsm_bts {
u_int8_t bsic;
/* type of BTS */
enum gsm_bts_type type;
+ struct gsm_bts_model *model;
enum gsm_band band;
/* should the channel allocator allocate channels from high TRX to TRX0,
* rather than starting from TRX0 and go upwards? */
@@ -478,43 +498,43 @@ struct gsm_bts {
/* Some statistics of our network */
struct gsmnet_stats {
struct {
- unsigned long total;
- unsigned long no_channel;
+ struct counter *total;
+ struct counter *no_channel;
} chreq;
struct {
- unsigned long attempted;
- unsigned long no_channel; /* no channel available */
- unsigned long timeout; /* T3103 timeout */
- unsigned long completed; /* HO COMPL received */
- unsigned long failed; /* HO FAIL received */
+ struct counter *attempted;
+ struct counter *no_channel; /* no channel available */
+ struct counter *timeout; /* T3103 timeout */
+ struct counter *completed; /* HO COMPL received */
+ struct counter *failed; /* HO FAIL received */
} handover;
struct {
- unsigned long attach;
- unsigned long normal;
- unsigned long periodic;
- unsigned long detach;
+ struct counter *attach;
+ struct counter *normal;
+ struct counter *periodic;
+ struct counter *detach;
} loc_upd_type;
struct {
- unsigned long reject;
- unsigned long accept;
+ struct counter *reject;
+ struct counter *accept;
} loc_upd_resp;
struct {
- unsigned long attempted;
- unsigned long detached;
- unsigned long completed;
- unsigned long expired;
+ struct counter *attempted;
+ struct counter *detached;
+ struct counter *completed;
+ struct counter *expired;
} paging;
struct {
- unsigned long submitted; /* MO SMS submissions */
- unsigned long no_receiver;
- unsigned long delivered; /* MT SMS deliveries */
- unsigned long rp_err_mem;
- unsigned long rp_err_other;
+ struct counter *submitted; /* MO SMS submissions */
+ struct counter *no_receiver;
+ struct counter *delivered; /* MT SMS deliveries */
+ struct counter *rp_err_mem;
+ struct counter *rp_err_other;
} sms;
struct {
- unsigned long dialled; /* total number of dialled calls */
- unsigned long alerted; /* we alerted the other end */
- unsigned long connected;/* how many calls were accepted */
+ struct counter *dialled; /* total number of dialled calls */
+ struct counter *alerted; /* we alerted the other end */
+ struct counter *connected;/* how many calls were accepted */
} call;
};
@@ -626,11 +646,13 @@ struct gsm_sms {
char text[SMS_TEXT_SIZE];
};
+
struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_code,
int (*mncc_recv)(struct gsm_network *, int, void *));
struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type,
u_int8_t tsc, u_int8_t bsic);
struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts);
+int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type);
struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num);
@@ -642,9 +664,12 @@ struct gsm_bts_trx *gsm_bts_trx_num(struct gsm_bts *bts, int num);
const char *gsm_pchan_name(enum gsm_phys_chan_config c);
enum gsm_phys_chan_config gsm_pchan_parse(const char *name);
-const char *gsm_lchan_name(enum gsm_chan_t c);
+const char *gsm_lchant_name(enum gsm_chan_t c);
const char *gsm_chreq_name(enum gsm_chreq_reason_t c);
+char *gsm_trx_name(struct gsm_bts_trx *trx);
char *gsm_ts_name(struct gsm_bts_trx_ts *ts);
+char *gsm_lchan_name(struct gsm_lchan *lchan);
+const char *gsm_lchans_name(enum gsm_lchan_state s);
enum gsm_e1_event {
EVT_E1_NONE,
@@ -656,12 +681,10 @@ void set_ts_e1link(struct gsm_bts_trx_ts *ts, u_int8_t e1_nr,
u_int8_t e1_ts, u_int8_t e1_ts_ss);
enum gsm_bts_type parse_btstype(const char *arg);
const char *btstype2str(enum gsm_bts_type type);
+struct gsm_bts_trx *gsm_bts_trx_by_nr(struct gsm_bts *bts, int nr);
struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac,
struct gsm_bts *start_bts);
-char *gsm_band_name(enum gsm_band band);
-enum gsm_band gsm_band_parse(const char *mhz);
-
extern void *tall_bsc_ctx;
extern int ipacc_rtp_direct;
@@ -699,4 +722,6 @@ void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked);
struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan);
+int gsm_bts_model_register(struct gsm_bts_model *model);
+
#endif
diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h
index eac0ae2a9..a7dac8df8 100644
--- a/openbsc/include/openbsc/gsm_subscriber.h
+++ b/openbsc/include/openbsc/gsm_subscriber.h
@@ -3,7 +3,7 @@
#include <sys/types.h>
#include "gsm_data.h"
-#include "linuxlist.h"
+#include <osmocore/linuxlist.h>
#define GSM_IMEI_LENGTH 17
#define GSM_IMSI_LENGTH 17
@@ -88,6 +88,8 @@ void subscr_put_channel(struct gsm_lchan *lchan);
void subscr_get_channel(struct gsm_subscriber *subscr,
int type, gsm_cbfn *cbfn, void *param);
+char *subscr_name(struct gsm_subscriber *subscr);
+
/* internal */
struct gsm_subscriber *subscr_alloc(void);
extern struct llist_head active_subscribers;
diff --git a/openbsc/include/openbsc/ipaccess.h b/openbsc/include/openbsc/ipaccess.h
index 9335bfab7..904a9627b 100644
--- a/openbsc/include/openbsc/ipaccess.h
+++ b/openbsc/include/openbsc/ipaccess.h
@@ -2,6 +2,10 @@
#define _IPACCESS_H
#include "e1_input.h"
+#include <osmocore/linuxlist.h>
+
+#define IPA_TCP_PORT_OML 3002
+#define IPA_TCP_PORT_RSL 3003
struct ipaccess_head {
u_int16_t len; /* network byte order */
@@ -49,4 +53,55 @@ int ipaccess_send_id_req(int fd);
int ipaccess_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len);
+
+/*
+ * Firmware specific header
+ */
+struct sdp_firmware {
+ char magic[4];
+ char more_magic[2];
+ u_int16_t more_more_magic;
+ u_int32_t header_length;
+ u_int32_t file_length;
+ char sw_part[20];
+ char text1[64];
+ char time[12];
+ char date[14];
+ char text2[10];
+ char version[20];
+ u_int8_t dummy[2];
+ u_int16_t part_length;
+ /* stuff i don't know */
+} __attribute__((packed));
+
+struct sdp_header_entry {
+ u_int16_t something1;
+ char text1[64];
+ char time[12];
+ char date[14];
+ char text2[10];
+ char version[20];
+ u_int32_t length;
+ u_int32_t addr1;
+ u_int32_t addr2;
+ u_int32_t start;
+} __attribute__((packed));
+
+struct sdp_header_item {
+ struct sdp_header_entry header_entry;
+ struct llist_head entry;
+};
+
+struct sdp_header {
+ struct sdp_firmware firmware_info;
+
+ /* for more_magic a list of sdp_header_entry_list */
+ struct llist_head header_list;
+
+ /* the entry of the sdp_header */
+ struct llist_head entry;
+};
+
+int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned base_offset, struct llist_head *list);
+
#endif /* _IPACCESS_H */
diff --git a/openbsc/include/openbsc/linuxlist.h b/openbsc/include/openbsc/linuxlist.h
deleted file mode 100644
index fb99c5ec8..000000000
--- a/openbsc/include/openbsc/linuxlist.h
+++ /dev/null
@@ -1,360 +0,0 @@
-#ifndef _LINUX_LLIST_H
-#define _LINUX_LLIST_H
-
-#include <stddef.h>
-
-#ifndef inline
-#define inline __inline__
-#endif
-
-static inline void prefetch(const void *x) {;}
-
-/**
- * container_of - cast a member of a structure out to the containing structure
- *
- * @ptr: the pointer to the member.
- * @type: the type of the container struct this is embedded in.
- * @member: the name of the member within the struct.
- *
- */
-#define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (typeof( ((type *)0)->member ) *)(ptr); \
- (type *)( (char *)__mptr - offsetof(type, member) );})
-
-
-/*
- * These are non-NULL pointers that will result in page faults
- * under normal circumstances, used to verify that nobody uses
- * non-initialized llist entries.
- */
-#define LLIST_POISON1 ((void *) 0x00100100)
-#define LLIST_POISON2 ((void *) 0x00200200)
-
-/*
- * Simple doubly linked llist implementation.
- *
- * Some of the internal functions ("__xxx") are useful when
- * manipulating whole llists rather than single entries, as
- * sometimes we already know the next/prev entries and we can
- * generate better code by using them directly rather than
- * using the generic single-entry routines.
- */
-
-struct llist_head {
- struct llist_head *next, *prev;
-};
-
-#define LLIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LLIST_HEAD(name) \
- struct llist_head name = LLIST_HEAD_INIT(name)
-
-#define INIT_LLIST_HEAD(ptr) do { \
- (ptr)->next = (ptr); (ptr)->prev = (ptr); \
-} while (0)
-
-/*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal llist manipulation where we know
- * the prev/next entries already!
- */
-static inline void __llist_add(struct llist_head *_new,
- struct llist_head *prev,
- struct llist_head *next)
-{
- next->prev = _new;
- _new->next = next;
- _new->prev = prev;
- prev->next = _new;
-}
-
-/**
- * llist_add - add a new entry
- * @new: new entry to be added
- * @head: llist head to add it after
- *
- * Insert a new entry after the specified head.
- * This is good for implementing stacks.
- */
-static inline void llist_add(struct llist_head *_new, struct llist_head *head)
-{
- __llist_add(_new, head, head->next);
-}
-
-/**
- * llist_add_tail - add a new entry
- * @new: new entry to be added
- * @head: llist head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
- */
-static inline void llist_add_tail(struct llist_head *_new, struct llist_head *head)
-{
- __llist_add(_new, head->prev, head);
-}
-
-/*
- * Delete a llist entry by making the prev/next entries
- * point to each other.
- *
- * This is only for internal llist manipulation where we know
- * the prev/next entries already!
- */
-static inline void __llist_del(struct llist_head * prev, struct llist_head * next)
-{
- next->prev = prev;
- prev->next = next;
-}
-
-/**
- * llist_del - deletes entry from llist.
- * @entry: the element to delete from the llist.
- * Note: llist_empty on entry does not return true after this, the entry is
- * in an undefined state.
- */
-static inline void llist_del(struct llist_head *entry)
-{
- __llist_del(entry->prev, entry->next);
- entry->next = (struct llist_head *)LLIST_POISON1;
- entry->prev = (struct llist_head *)LLIST_POISON2;
-}
-
-/**
- * llist_del_init - deletes entry from llist and reinitialize it.
- * @entry: the element to delete from the llist.
- */
-static inline void llist_del_init(struct llist_head *entry)
-{
- __llist_del(entry->prev, entry->next);
- INIT_LLIST_HEAD(entry);
-}
-
-/**
- * llist_move - delete from one llist and add as another's head
- * @llist: the entry to move
- * @head: the head that will precede our entry
- */
-static inline void llist_move(struct llist_head *llist, struct llist_head *head)
-{
- __llist_del(llist->prev, llist->next);
- llist_add(llist, head);
-}
-
-/**
- * llist_move_tail - delete from one llist and add as another's tail
- * @llist: the entry to move
- * @head: the head that will follow our entry
- */
-static inline void llist_move_tail(struct llist_head *llist,
- struct llist_head *head)
-{
- __llist_del(llist->prev, llist->next);
- llist_add_tail(llist, head);
-}
-
-/**
- * llist_empty - tests whether a llist is empty
- * @head: the llist to test.
- */
-static inline int llist_empty(const struct llist_head *head)
-{
- return head->next == head;
-}
-
-static inline void __llist_splice(struct llist_head *llist,
- struct llist_head *head)
-{
- struct llist_head *first = llist->next;
- struct llist_head *last = llist->prev;
- struct llist_head *at = head->next;
-
- first->prev = head;
- head->next = first;
-
- last->next = at;
- at->prev = last;
-}
-
-/**
- * llist_splice - join two llists
- * @llist: the new llist to add.
- * @head: the place to add it in the first llist.
- */
-static inline void llist_splice(struct llist_head *llist, struct llist_head *head)
-{
- if (!llist_empty(llist))
- __llist_splice(llist, head);
-}
-
-/**
- * llist_splice_init - join two llists and reinitialise the emptied llist.
- * @llist: the new llist to add.
- * @head: the place to add it in the first llist.
- *
- * The llist at @llist is reinitialised
- */
-static inline void llist_splice_init(struct llist_head *llist,
- struct llist_head *head)
-{
- if (!llist_empty(llist)) {
- __llist_splice(llist, head);
- INIT_LLIST_HEAD(llist);
- }
-}
-
-/**
- * llist_entry - get the struct for this entry
- * @ptr: the &struct llist_head pointer.
- * @type: the type of the struct this is embedded in.
- * @member: the name of the llist_struct within the struct.
- */
-#define llist_entry(ptr, type, member) \
- container_of(ptr, type, member)
-
-/**
- * llist_for_each - iterate over a llist
- * @pos: the &struct llist_head to use as a loop counter.
- * @head: the head for your llist.
- */
-#define llist_for_each(pos, head) \
- for (pos = (head)->next, prefetch(pos->next); pos != (head); \
- pos = pos->next, prefetch(pos->next))
-
-/**
- * __llist_for_each - iterate over a llist
- * @pos: the &struct llist_head to use as a loop counter.
- * @head: the head for your llist.
- *
- * This variant differs from llist_for_each() in that it's the
- * simplest possible llist iteration code, no prefetching is done.
- * Use this for code that knows the llist to be very short (empty
- * or 1 entry) most of the time.
- */
-#define __llist_for_each(pos, head) \
- for (pos = (head)->next; pos != (head); pos = pos->next)
-
-/**
- * llist_for_each_prev - iterate over a llist backwards
- * @pos: the &struct llist_head to use as a loop counter.
- * @head: the head for your llist.
- */
-#define llist_for_each_prev(pos, head) \
- for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
- pos = pos->prev, prefetch(pos->prev))
-
-/**
- * llist_for_each_safe - iterate over a llist safe against removal of llist entry
- * @pos: the &struct llist_head to use as a loop counter.
- * @n: another &struct llist_head to use as temporary storage
- * @head: the head for your llist.
- */
-#define llist_for_each_safe(pos, n, head) \
- for (pos = (head)->next, n = pos->next; pos != (head); \
- pos = n, n = pos->next)
-
-/**
- * llist_for_each_entry - iterate over llist of given type
- * @pos: the type * to use as a loop counter.
- * @head: the head for your llist.
- * @member: the name of the llist_struct within the struct.
- */
-#define llist_for_each_entry(pos, head, member) \
- for (pos = llist_entry((head)->next, typeof(*pos), member), \
- prefetch(pos->member.next); \
- &pos->member != (head); \
- pos = llist_entry(pos->member.next, typeof(*pos), member), \
- prefetch(pos->member.next))
-
-/**
- * llist_for_each_entry_reverse - iterate backwards over llist of given type.
- * @pos: the type * to use as a loop counter.
- * @head: the head for your llist.
- * @member: the name of the llist_struct within the struct.
- */
-#define llist_for_each_entry_reverse(pos, head, member) \
- for (pos = llist_entry((head)->prev, typeof(*pos), member), \
- prefetch(pos->member.prev); \
- &pos->member != (head); \
- pos = llist_entry(pos->member.prev, typeof(*pos), member), \
- prefetch(pos->member.prev))
-
-/**
- * llist_for_each_entry_continue - iterate over llist of given type
- * continuing after existing point
- * @pos: the type * to use as a loop counter.
- * @head: the head for your llist.
- * @member: the name of the llist_struct within the struct.
- */
-#define llist_for_each_entry_continue(pos, head, member) \
- for (pos = llist_entry(pos->member.next, typeof(*pos), member), \
- prefetch(pos->member.next); \
- &pos->member != (head); \
- pos = llist_entry(pos->member.next, typeof(*pos), member), \
- prefetch(pos->member.next))
-
-/**
- * llist_for_each_entry_safe - iterate over llist of given type safe against removal of llist entry
- * @pos: the type * to use as a loop counter.
- * @n: another type * to use as temporary storage
- * @head: the head for your llist.
- * @member: the name of the llist_struct within the struct.
- */
-#define llist_for_each_entry_safe(pos, n, head, member) \
- for (pos = llist_entry((head)->next, typeof(*pos), member), \
- n = llist_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = n, n = llist_entry(n->member.next, typeof(*n), member))
-
-/**
- * llist_for_each_rcu - iterate over an rcu-protected llist
- * @pos: the &struct llist_head to use as a loop counter.
- * @head: the head for your llist.
- */
-#define llist_for_each_rcu(pos, head) \
- for (pos = (head)->next, prefetch(pos->next); pos != (head); \
- pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next))
-
-#define __llist_for_each_rcu(pos, head) \
- for (pos = (head)->next; pos != (head); \
- pos = pos->next, ({ smp_read_barrier_depends(); 0;}))
-
-/**
- * llist_for_each_safe_rcu - iterate over an rcu-protected llist safe
- * against removal of llist entry
- * @pos: the &struct llist_head to use as a loop counter.
- * @n: another &struct llist_head to use as temporary storage
- * @head: the head for your llist.
- */
-#define llist_for_each_safe_rcu(pos, n, head) \
- for (pos = (head)->next, n = pos->next; pos != (head); \
- pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next)
-
-/**
- * llist_for_each_entry_rcu - iterate over rcu llist of given type
- * @pos: the type * to use as a loop counter.
- * @head: the head for your llist.
- * @member: the name of the llist_struct within the struct.
- */
-#define llist_for_each_entry_rcu(pos, head, member) \
- for (pos = llist_entry((head)->next, typeof(*pos), member), \
- prefetch(pos->member.next); \
- &pos->member != (head); \
- pos = llist_entry(pos->member.next, typeof(*pos), member), \
- ({ smp_read_barrier_depends(); 0;}), \
- prefetch(pos->member.next))
-
-
-/**
- * llist_for_each_continue_rcu - iterate over an rcu-protected llist
- * continuing after existing point.
- * @pos: the &struct llist_head to use as a loop counter.
- * @head: the head for your llist.
- */
-#define llist_for_each_continue_rcu(pos, head) \
- for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \
- (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next))
-
-
-#endif
diff --git a/openbsc/include/openbsc/meas_rep.h b/openbsc/include/openbsc/meas_rep.h
index fd5fced43..3c2c8d1c1 100644
--- a/openbsc/include/openbsc/meas_rep.h
+++ b/openbsc/include/openbsc/meas_rep.h
@@ -7,6 +7,7 @@
struct gsm_meas_rep_cell {
u_int8_t rxlev;
u_int8_t bsic;
+ u_int8_t neigh_idx;
u_int16_t arfcn;
unsigned int flags;
};
diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h
index 3cba203de..2a94bb4e4 100644
--- a/openbsc/include/openbsc/mgcp.h
+++ b/openbsc/include/openbsc/mgcp.h
@@ -1,8 +1,8 @@
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
/*
- * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009 by on-waves.com
+ * (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2009-2010 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,14 @@
*
*/
+#ifndef OPENBSC_MGCP_H
+#define OPENBSC_MGCP_H
+
+#include <osmocore/msgb.h>
+
+#include <arpa/inet.h>
+
+#define RTP_PORT_DEFAULT 4000
/**
* Calculate the RTP audio port for the given multiplex
* and the direction. This allows a semi static endpoint
@@ -40,7 +48,74 @@
* network and BTS.
*
*/
-int rtp_calculate_port(int multiplex, int base)
+static inline int rtp_calculate_port(int multiplex, int base)
{
return base + (multiplex * 2);
}
+
+
+/*
+ * Handling of MGCP Endpoints and the MGCP Config
+ */
+struct mgcp_endpoint;
+struct mgcp_config;
+
+#define MGCP_ENDP_CRCX 1
+#define MGCP_ENDP_DLCX 2
+#define MGCP_ENDP_MDCX 3
+
+/*
+ * what to do with the msg?
+ * - continue as usual?
+ * - reject and send a failure code?
+ * - defer? do not send anything
+ */
+#define MGCP_POLICY_CONT 4
+#define MGCP_POLICY_REJECT 5
+#define MGCP_POLICY_DEFER 6
+
+typedef int (*mgcp_change)(struct mgcp_config *cfg, int endpoint, int state, int local_rtp);
+typedef int (*mgcp_policy)(struct mgcp_config *cfg, int endpoint, int state, const char *transactio_id);
+
+struct mgcp_config {
+ int source_port;
+ char *local_ip;
+ char *source_addr;
+ unsigned int number_endpoints;
+ char *bts_ip;
+
+ struct in_addr bts_in;
+ char *audio_name;
+ int audio_payload;
+ int audio_loop;
+ int early_bind;
+ int rtp_base_port;
+
+ char *forward_ip;
+ int forward_port;
+
+ mgcp_change change_cb;
+ mgcp_policy policy_cb;
+ void *data;
+
+ struct mgcp_endpoint *endpoints;
+ unsigned int last_call_id;
+};
+
+/* config management */
+struct mgcp_config *mgcp_config_alloc(void);
+int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg);
+int mgcp_vty_init(void);
+int mgcp_endpoints_allocate(struct mgcp_config *cfg);
+int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port);
+void mgcp_free_endp(struct mgcp_endpoint *endp);
+
+/*
+ * format helper functions
+ */
+struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg);
+struct msgb *mgcp_create_rsip(void);
+struct msgb *mgcp_create_response_with_data(int code, const char *msg, const char *trans, const char *data);
+
+
+#endif
diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h
new file mode 100644
index 000000000..10d0ca6ae
--- /dev/null
+++ b/openbsc/include/openbsc/mgcp_internal.h
@@ -0,0 +1,64 @@
+/* MGCP Private Data */
+
+/*
+ * (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2009-2010 by On-Waves
+ * 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.
+ *
+ */
+
+#ifndef OPENBSC_MGCP_DATA_H
+#define OPENBSC_MGCP_DATA_H
+
+#include <osmocore/select.h>
+
+#define CI_UNUSED 0
+
+struct mgcp_endpoint {
+ int ci;
+ char *callid;
+ char *local_options;
+ int conn_mode;
+
+ int bts_payload_type;
+ int net_payload_type;
+
+ /* the local rtp port we are binding to */
+ int rtp_port;
+
+ /*
+ * RTP mangling:
+ * - we get RTP and RTCP to us and need to forward to the BTS
+ * - we get RTP and RTCP from the BTS and forward to the network
+ */
+ struct bsc_fd local_rtp;
+ struct bsc_fd local_rtcp;
+
+ struct in_addr remote;
+ struct in_addr bts;
+
+ /* in network byte order */
+ int net_rtp, net_rtcp;
+ int bts_rtp, bts_rtcp;
+
+ /* backpointer */
+ struct mgcp_config *cfg;
+};
+
+#define ENDPOINT_NUMBER(endp) abs(endp - endp->cfg->endpoints)
+
+#endif
diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h
index fbf3cab1f..cb8339a79 100644
--- a/openbsc/include/openbsc/mncc.h
+++ b/openbsc/include/openbsc/mncc.h
@@ -25,7 +25,8 @@
#ifndef _MNCC_H
#define _MNCC_H
-#include <openbsc/linuxlist.h>
+#include <osmocore/linuxlist.h>
+#include <osmocore/mncc.h>
/* One end of a call */
struct gsm_call {
@@ -109,69 +110,6 @@ 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; /* 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 {
- int type;
- int plan;
- int present;
- int screen;
- char number[33];
-};
-
-struct gsm_mncc_cause {
- int location;
- int coding;
- int rec;
- int rec_val;
- int value;
- int diag_len;
- char diag[32];
-};
-
-struct gsm_mncc_useruser {
- int proto;
- char info[GSM_MAX_USERUSER + 1]; /* + termination char */
-};
-
-struct gsm_mncc_progress {
- int coding;
- int location;
- int descr;
-};
-
-struct gsm_mncc_facility {
- int len;
- char info[GSM_MAX_FACILITY];
-};
-
-struct gsm_mncc_ssversion {
- int len;
- char info[GSM_MAX_SSVERSION];
-};
-
-struct gsm_mncc_cccap {
- int dtmf;
- int pcp;
-};
-
-enum {
- GSM_MNCC_BCAP_SPEECH = 0,
- GSM_MNCC_BCAP_UNR_DIG = 1,
- GSM_MNCC_BCAP_AUDIO = 2,
- GSM_MNCC_BCAP_FAX_G3 = 3,
- GSM_MNCC_BCAP_OTHER_ITC = 5,
- GSM_MNCC_BCAP_RESERVED = 7,
-};
-
struct gsm_mncc {
/* context based information */
u_int32_t msg_type;
diff --git a/openbsc/include/openbsc/msgb.h b/openbsc/include/openbsc/msgb.h
deleted file mode 100644
index 1a0688f57..000000000
--- a/openbsc/include/openbsc/msgb.h
+++ /dev/null
@@ -1,115 +0,0 @@
-#ifndef _MSGB_H
-#define _MSGB_H
-
-/* (C) 2008 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 <openbsc/linuxlist.h>
-
-struct bts_link;
-
-struct msgb {
- struct llist_head list;
-
- /* ptr to the physical E1 link to the BTS(s) */
- struct gsm_bts_link *bts_link;
-
- /* Part of which TRX logical channel we were received / transmitted */
- struct gsm_bts_trx *trx;
- struct gsm_lchan *lchan;
-
- unsigned char *l2h;
- unsigned char *l3h;
- unsigned char *smsh;
- unsigned char *l4h;
-
- u_int16_t data_len;
- u_int16_t len;
-
- unsigned char *head;
- unsigned char *tail;
- unsigned char *data;
- unsigned char _data[0];
-};
-
-extern struct msgb *msgb_alloc(u_int16_t size, const char *name);
-extern void msgb_free(struct msgb *m);
-extern void msgb_enqueue(struct llist_head *queue, struct msgb *msg);
-extern struct msgb *msgb_dequeue(struct llist_head *queue);
-extern void msgb_reset(struct msgb *m);
-
-#define msgb_l2(m) ((void *)(m->l2h))
-#define msgb_l3(m) ((void *)(m->l3h))
-#define msgb_l4(m) ((void *)(m->l4h))
-#define msgb_sms(m) ((void *)(m->smsh))
-
-static inline unsigned int msgb_l2len(const struct msgb *msgb)
-{
- return msgb->tail - (u_int8_t *)msgb_l2(msgb);
-}
-
-static inline unsigned int msgb_l3len(const struct msgb *msgb)
-{
- return msgb->tail - (u_int8_t *)msgb_l3(msgb);
-}
-
-static inline unsigned int msgb_headlen(const struct msgb *msgb)
-{
- return msgb->len - msgb->data_len;
-}
-static inline unsigned char *msgb_put(struct msgb *msgb, unsigned int len)
-{
- unsigned char *tmp = msgb->tail;
- msgb->tail += len;
- msgb->len += len;
- return tmp;
-}
-static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len)
-{
- msgb->data -= len;
- msgb->len += len;
- return msgb->data;
-}
-static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len)
-{
- msgb->len -= len;
- return msgb->data += len;
-}
-static inline int msgb_tailroom(const struct msgb *msgb)
-{
- return (msgb->data + msgb->data_len) - msgb->tail;
-}
-
-/* increase the headroom of an empty msgb, reducing the tailroom */
-static inline void msgb_reserve(struct msgb *msg, int len)
-{
- msg->data += len;
- msg->tail += len;
-}
-
-static inline struct msgb *msgb_alloc_headroom(int size, int headroom,
- const char *name)
-{
- struct msgb *msg = msgb_alloc(size, name);
- if (msg)
- msgb_reserve(msg, headroom);
- return msg;
-}
-
-#endif /* _MSGB_H */
diff --git a/openbsc/include/openbsc/paging.h b/openbsc/include/openbsc/paging.h
index ab6a27494..6cbdca902 100644
--- a/openbsc/include/openbsc/paging.h
+++ b/openbsc/include/openbsc/paging.h
@@ -24,10 +24,10 @@
#include <stdlib.h>
#include <string.h>
-#include "linuxlist.h"
+#include <osmocore/linuxlist.h>
#include "gsm_data.h"
#include "gsm_subscriber.h"
-#include "timer.h"
+#include <osmocore/timer.h>
/* call once for every gsm_bts... */
void paging_init(struct gsm_bts *bts);
diff --git a/openbsc/include/openbsc/rtp_proxy.h b/openbsc/include/openbsc/rtp_proxy.h
index d128e4f23..f82711a8e 100644
--- a/openbsc/include/openbsc/rtp_proxy.h
+++ b/openbsc/include/openbsc/rtp_proxy.h
@@ -25,8 +25,8 @@
#include <netinet/in.h>
-#include <openbsc/linuxlist.h>
-#include <openbsc/select.h>
+#include <osmocore/linuxlist.h>
+#include <osmocore/select.h>
enum rtp_rx_action {
RTP_NONE,
diff --git a/openbsc/include/openbsc/select.h b/openbsc/include/openbsc/select.h
deleted file mode 100644
index c2af1d787..000000000
--- a/openbsc/include/openbsc/select.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _BSC_SELECT_H
-#define _BSC_SELECT_H
-
-#include <openbsc/linuxlist.h>
-
-#define BSC_FD_READ 0x0001
-#define BSC_FD_WRITE 0x0002
-#define BSC_FD_EXCEPT 0x0004
-
-struct bsc_fd {
- struct llist_head list;
- int fd;
- unsigned int when;
- int (*cb)(struct bsc_fd *fd, unsigned int what);
- void *data;
- unsigned int priv_nr;
-};
-
-int bsc_register_fd(struct bsc_fd *fd);
-void bsc_unregister_fd(struct bsc_fd *fd);
-int bsc_select_main(int polling);
-#endif /* _BSC_SELECT_H */
diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h
index 8c815f89e..0c22869f6 100644
--- a/openbsc/include/openbsc/signal.h
+++ b/openbsc/include/openbsc/signal.h
@@ -28,6 +28,7 @@
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_subscriber.h>
+#include <osmocore/signal.h>
/*
* Signalling subsystems
@@ -45,7 +46,8 @@ enum signal_subsystems {
/* SS_PAGING signals */
enum signal_paging {
- S_PAGING_COMPLETED,
+ S_PAGING_SUCCEEDED,
+ S_PAGING_EXPIRED,
};
/* SS_SMS signals */
@@ -69,6 +71,9 @@ enum signal_nm {
S_NM_FAIL_REP, /* GSM 12.21 failure event report */
S_NM_NACK, /* GSM 12.21 various NM_MT_*_NACK happened */
S_NM_IPACC_NACK, /* GSM 12.21 nanoBTS extensions NM_MT_IPACC_*_*_NACK happened */
+ S_NM_IPACC_ACK, /* GSM 12.21 nanoBTS extensions NM_MT_IPACC_*_*_ACK happened */
+ S_NM_IPACC_RESTART_ACK, /* nanoBTS has send a restart ack */
+ S_NM_IPACC_RESTART_NACK,/* nanoBTS has send a restart ack */
S_NM_TEST_REP, /* GSM 12.21 Test Report */
};
@@ -106,9 +111,6 @@ enum signal_global {
S_GLOBAL_SHUTDOWN,
};
-typedef int signal_cbfn(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data);
-
struct paging_signal_data {
struct gsm_subscriber *subscr;
struct gsm_bts *bts;
@@ -123,12 +125,9 @@ struct scall_signal_data {
void *data;
};
-/* Management */
-int register_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data);
-void unregister_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data);
-
-/* Dispatch */
-void dispatch_signal(unsigned int subsys, unsigned int signal, void *signal_data);
-
+struct ipacc_ack_signal_data {
+ struct gsm_bts *bts;
+ u_int8_t msg_type;
+};
#endif
diff --git a/openbsc/include/openbsc/silent_call.h b/openbsc/include/openbsc/silent_call.h
index 53ed4e248..fefc5182d 100644
--- a/openbsc/include/openbsc/silent_call.h
+++ b/openbsc/include/openbsc/silent_call.h
@@ -1,7 +1,10 @@
#ifndef _SILENT_CALL_H
#define _SILENT_CALL_H
-extern int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data);
+extern int gsm_silent_call_start(struct gsm_subscriber *subscr,
+ void *data, int type);
extern int gsm_silent_call_stop(struct gsm_subscriber *subscr);
+extern int silent_call_rx(struct msgb *msg);
+extern int silent_call_reroute(struct msgb *msg);
#endif /* _SILENT_CALL_H */
diff --git a/openbsc/include/openbsc/subchan_demux.h b/openbsc/include/openbsc/subchan_demux.h
index 9661b0481..02fa02338 100644
--- a/openbsc/include/openbsc/subchan_demux.h
+++ b/openbsc/include/openbsc/subchan_demux.h
@@ -22,7 +22,7 @@
*/
#include <sys/types.h>
-#include <openbsc/linuxlist.h>
+#include <osmocore/linuxlist.h>
#define NR_SUBCH 4
#define TRAU_FRAME_SIZE 40
diff --git a/openbsc/include/openbsc/talloc.h b/openbsc/include/openbsc/talloc.h
deleted file mode 100644
index f7f7643b8..000000000
--- a/openbsc/include/openbsc/talloc.h
+++ /dev/null
@@ -1,192 +0,0 @@
-#ifndef _TALLOC_H_
-#define _TALLOC_H_
-/*
- Unix SMB/CIFS implementation.
- Samba temporary memory allocation functions
-
- Copyright (C) Andrew Tridgell 2004-2005
- Copyright (C) Stefan Metzmacher 2006
-
- ** NOTE! The following LGPL license applies to the talloc
- ** library. This does NOT imply that all of Samba is released
- ** under the LGPL
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- This library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-
-#define HAVE_VA_COPY
-
-/* this is only needed for compatibility with the old talloc */
-typedef void TALLOC_CTX;
-
-/*
- this uses a little trick to allow __LINE__ to be stringified
-*/
-#ifndef __location__
-#define __TALLOC_STRING_LINE1__(s) #s
-#define __TALLOC_STRING_LINE2__(s) __TALLOC_STRING_LINE1__(s)
-#define __TALLOC_STRING_LINE3__ __TALLOC_STRING_LINE2__(__LINE__)
-#define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__
-#endif
-
-#ifndef TALLOC_DEPRECATED
-#define TALLOC_DEPRECATED 0
-#endif
-
-#ifndef PRINTF_ATTRIBUTE
-#if (__GNUC__ >= 3)
-/** Use gcc attribute to check printf fns. a1 is the 1-based index of
- * the parameter containing the format, and a2 the index of the first
- * argument. Note that some gcc 2.x versions don't handle this
- * properly **/
-#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
-#else
-#define PRINTF_ATTRIBUTE(a1, a2)
-#endif
-#endif
-
-/* try to make talloc_set_destructor() and talloc_steal() type safe,
- if we have a recent gcc */
-#if (__GNUC__ >= 3)
-#define _TALLOC_TYPEOF(ptr) __typeof__(ptr)
-#define talloc_set_destructor(ptr, function) \
- do { \
- int (*_talloc_destructor_fn)(_TALLOC_TYPEOF(ptr)) = (function); \
- _talloc_set_destructor((ptr), (int (*)(void *))_talloc_destructor_fn); \
- } while(0)
-/* this extremely strange macro is to avoid some braindamaged warning
- stupidity in gcc 4.1.x */
-#define talloc_steal(ctx, ptr) ({ _TALLOC_TYPEOF(ptr) __talloc_steal_ret = (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr)); __talloc_steal_ret; })
-#else
-#define talloc_set_destructor(ptr, function) \
- _talloc_set_destructor((ptr), (int (*)(void *))(function))
-#define _TALLOC_TYPEOF(ptr) void *
-#define talloc_steal(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr))
-#endif
-
-#define talloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_reference((ctx),(ptr))
-#define talloc_move(ctx, ptr) (_TALLOC_TYPEOF(*(ptr)))_talloc_move((ctx),(void *)(ptr))
-
-/* useful macros for creating type checked pointers */
-#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
-#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__)
-#define talloc_ptrtype(ctx, ptr) (_TALLOC_TYPEOF(ptr))talloc_size(ctx, sizeof(*(ptr)))
-
-#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__)
-
-#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
-#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__)
-
-#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
-#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
-#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__)
-#define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count)
-#define talloc_array_length(ctx) (talloc_get_size(ctx)/sizeof(*ctx))
-
-#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type)
-#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__)
-
-#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__)
-
-#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type)
-#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type)
-#define talloc_get_type_abort(ptr, type) (type *)_talloc_get_type_abort(ptr, #type, __location__)
-
-#define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type)
-
-#if TALLOC_DEPRECATED
-#define talloc_zero_p(ctx, type) talloc_zero(ctx, type)
-#define talloc_p(ctx, type) talloc(ctx, type)
-#define talloc_array_p(ctx, type, count) talloc_array(ctx, type, count)
-#define talloc_realloc_p(ctx, p, type, count) talloc_realloc(ctx, p, type, count)
-#define talloc_destroy(ctx) talloc_free(ctx)
-#define talloc_append_string(c, s, a) (s?talloc_strdup_append(s,a):talloc_strdup(c, a))
-#endif
-
-#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
-
-/* The following definitions come from talloc.c */
-void *_talloc(const void *context, size_t size);
-void *talloc_pool(const void *context, size_t size);
-void _talloc_set_destructor(const void *ptr, int (*_destructor)(void *));
-int talloc_increase_ref_count(const void *ptr);
-size_t talloc_reference_count(const void *ptr);
-void *_talloc_reference(const void *context, const void *ptr);
-int talloc_unlink(const void *context, void *ptr);
-const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
-void talloc_set_name_const(const void *ptr, const char *name);
-void *talloc_named(const void *context, size_t size,
- const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
-void *talloc_named_const(const void *context, size_t size, const char *name);
-const char *talloc_get_name(const void *ptr);
-void *talloc_check_name(const void *ptr, const char *name);
-void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location);
-void *talloc_parent(const void *ptr);
-const char *talloc_parent_name(const void *ptr);
-void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
-int talloc_free(void *ptr);
-void talloc_free_children(void *ptr);
-void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name);
-void *_talloc_steal(const void *new_ctx, const void *ptr);
-void *_talloc_move(const void *new_ctx, const void *pptr);
-size_t talloc_total_size(const void *ptr);
-size_t talloc_total_blocks(const void *ptr);
-void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
- void (*callback)(const void *ptr,
- int depth, int max_depth,
- int is_ref,
- void *private_data),
- void *private_data);
-void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f);
-void talloc_report_full(const void *ptr, FILE *f);
-void talloc_report(const void *ptr, FILE *f);
-void talloc_enable_null_tracking(void);
-void talloc_disable_null_tracking(void);
-void talloc_enable_leak_report(void);
-void talloc_enable_leak_report_full(void);
-void *_talloc_zero(const void *ctx, size_t size, const char *name);
-void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name);
-void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name);
-void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name);
-void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
-void *talloc_realloc_fn(const void *context, void *ptr, size_t size);
-void *talloc_autofree_context(void);
-size_t talloc_get_size(const void *ctx);
-void *talloc_find_parent_byname(const void *ctx, const char *name);
-void talloc_show_parents(const void *context, FILE *file);
-int talloc_is_parent(const void *context, const void *ptr);
-
-char *talloc_strdup(const void *t, const char *p);
-char *talloc_strdup_append(char *s, const char *a);
-char *talloc_strdup_append_buffer(char *s, const char *a);
-
-char *talloc_strndup(const void *t, const char *p, size_t n);
-char *talloc_strndup_append(char *s, const char *a, size_t n);
-char *talloc_strndup_append_buffer(char *s, const char *a, size_t n);
-
-char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
-char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
-char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
-
-char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
-char *talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
-char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
-
-void talloc_set_abort_fn(void (*abort_fn)(const char *reason));
-
-#endif
diff --git a/openbsc/include/openbsc/telnet_interface.h b/openbsc/include/openbsc/telnet_interface.h
index cd9da3cd9..20e794b49 100644
--- a/openbsc/include/openbsc/telnet_interface.h
+++ b/openbsc/include/openbsc/telnet_interface.h
@@ -22,8 +22,8 @@
#define TELNET_INTERFACE_H
#include "gsm_data.h"
-#include "linuxlist.h"
-#include "select.h"
+#include "debug.h"
+#include <osmocore/select.h>
#include <vty/vty.h>
@@ -32,6 +32,7 @@ struct telnet_connection {
struct gsm_network *network;
struct bsc_fd fd;
struct vty *vty;
+ struct debug_target *dbg;
};
diff --git a/openbsc/include/openbsc/timer.h b/openbsc/include/openbsc/timer.h
deleted file mode 100644
index fee888bfd..000000000
--- a/openbsc/include/openbsc/timer.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.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.
- *
- */
-
-#ifndef TIMER_H
-#define TIMER_H
-
-#include <sys/time.h>
-
-#include "linuxlist.h"
-
-/**
- * Timer management:
- * - Create a struct timer_list
- * - Fill out timeout and use add_timer or
- * use schedule_timer to schedule a timer in
- * x seconds and microseconds from now...
- * - Use del_timer to remove the timer
- *
- * Internally:
- * - We hook into select.c to give a timeval of the
- * nearest timer. On already passed timers we give
- * it a 0 to immediately fire after the select
- * - update_timers will call the callbacks and remove
- * the timers.
- *
- */
-struct timer_list {
- struct llist_head entry;
- struct timeval timeout;
- unsigned int active : 1;
- unsigned int handled : 1;
- unsigned int in_list : 1;
-
- void (*cb)(void*);
- void *data;
-};
-
-/**
- * timer management
- */
-void bsc_add_timer(struct timer_list *timer);
-void bsc_schedule_timer(struct timer_list *timer, int seconds, int microseconds);
-void bsc_del_timer(struct timer_list *timer);
-int bsc_timer_pending(struct timer_list *timer);
-
-
-/**
- * internal timer list management
- */
-struct timeval *bsc_nearest_timer();
-void bsc_prepare_timers();
-int bsc_update_timers();
-int bsc_timer_check(void);
-
-#endif
diff --git a/openbsc/include/openbsc/tlv.h b/openbsc/include/openbsc/tlv.h
deleted file mode 100644
index 06af53cac..000000000
--- a/openbsc/include/openbsc/tlv.h
+++ /dev/null
@@ -1,234 +0,0 @@
-#ifndef _TLV_H
-#define _TLV_H
-
-#include <sys/types.h>
-#include <string.h>
-
-#include <openbsc/msgb.h>
-
-/* Terminology / wording
- tag length value (in bits)
-
- V - - 8
- LV - 8 N * 8
- TLV 8 8 N * 8
- TL16V 8 16 N * 8
- TLV16 8 8 N * 16
- TvLV 8 8/16 N * 8
-
-*/
-
-#define LV_GROSS_LEN(x) (x+1)
-#define TLV_GROSS_LEN(x) (x+2)
-#define TLV16_GROSS_LEN(x) ((2*x)+2)
-#define TL16V_GROSS_LEN(x) (x+3)
-#define L16TV_GROSS_LEN(x) (x+3)
-
-#define TVLV_MAX_ONEBYTE 0x7f
-
-static inline u_int16_t TVLV_GROSS_LEN(u_int16_t len)
-{
- if (len <= TVLV_MAX_ONEBYTE)
- return TLV_GROSS_LEN(len);
- else
- return TL16V_GROSS_LEN(len);
-}
-
-/* TLV generation */
-
-static inline u_int8_t *lv_put(u_int8_t *buf, u_int8_t len,
- const u_int8_t *val)
-{
- *buf++ = len;
- memcpy(buf, val, len);
- return buf + len;
-}
-
-static inline u_int8_t *tlv_put(u_int8_t *buf, u_int8_t tag, u_int8_t len,
- const u_int8_t *val)
-{
- *buf++ = tag;
- *buf++ = len;
- memcpy(buf, val, len);
- return buf + len;
-}
-
-static inline u_int8_t *tlv16_put(u_int8_t *buf, u_int8_t tag, u_int8_t len,
- const u_int16_t *val)
-{
- *buf++ = tag;
- *buf++ = len;
- memcpy(buf, val, len*2);
- return buf + len*2;
-}
-
-static inline u_int8_t *tl16v_put(u_int8_t *buf, u_int8_t tag, u_int16_t len,
- const u_int8_t *val)
-{
- *buf++ = tag;
- *buf++ = len >> 8;
- *buf++ = len & 0xff;
- memcpy(buf, val, len);
- return buf + len*2;
-}
-
-static inline u_int8_t *tvlv_put(u_int8_t *buf, u_int8_t tag, u_int16_t len,
- const u_int8_t *val)
-{
- u_int8_t *ret;
-
- if (len <= TVLV_MAX_ONEBYTE) {
- ret = tlv_put(buf, tag, len, val);
- buf[1] |= 0x80;
- } else
- ret = tl16v_put(buf, tag, len, val);
-
- return ret;
-}
-
-static inline u_int8_t *msgb_tlv16_put(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int16_t *val)
-{
- u_int8_t *buf = msgb_put(msg, TLV16_GROSS_LEN(len));
- return tlv16_put(buf, tag, len, val);
-}
-
-static inline u_int8_t *msgb_tl16v_put(struct msgb *msg, u_int8_t tag, u_int16_t len,
- const u_int8_t *val)
-{
- u_int8_t *buf = msgb_put(msg, TL16V_GROSS_LEN(len));
- return tl16v_put(buf, tag, len, val);
-}
-
-static inline u_int8_t *msgb_tvlv_put(struct msgb *msg, u_int8_t tag, u_int16_t len,
- const u_int8_t *val)
-{
- u_int8_t *buf = msgb_put(msg, TVLV_GROSS_LEN(len));
- return tvlv_put(buf, tag, len, val);
-}
-
-static inline u_int8_t *msgb_l16tv_put(struct msgb *msg, u_int16_t len, u_int8_t tag,
- const u_int8_t *val)
-{
- u_int8_t *buf = msgb_put(msg, L16TV_GROSS_LEN(len));
-
- *buf++ = len >> 8;
- *buf++ = len & 0xff;
- *buf++ = tag;
- memcpy(buf, val, len);
- return buf + len;
-}
-
-static inline u_int8_t *v_put(u_int8_t *buf, u_int8_t val)
-{
- *buf++ = val;
- return buf;
-}
-
-static inline u_int8_t *tv_put(u_int8_t *buf, u_int8_t tag,
- u_int8_t val)
-{
- *buf++ = tag;
- *buf++ = val;
- return buf;
-}
-
-/* 'val' is still in host byte order! */
-static inline u_int8_t *tv16_put(u_int8_t *buf, u_int8_t tag,
- u_int16_t val)
-{
- *buf++ = tag;
- *buf++ = val >> 8;
- *buf++ = val & 0xff;
- return buf;
-}
-
-static inline u_int8_t *msgb_lv_put(struct msgb *msg, u_int8_t len, const u_int8_t *val)
-{
- u_int8_t *buf = msgb_put(msg, LV_GROSS_LEN(len));
- return lv_put(buf, len, val);
-}
-
-static inline u_int8_t *msgb_tlv_put(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int8_t *val)
-{
- u_int8_t *buf = msgb_put(msg, TLV_GROSS_LEN(len));
- return tlv_put(buf, tag, len, val);
-}
-
-static inline u_int8_t *msgb_tv_put(struct msgb *msg, u_int8_t tag, u_int8_t val)
-{
- u_int8_t *buf = msgb_put(msg, 2);
- return tv_put(buf, tag, val);
-}
-
-static inline u_int8_t *msgb_v_put(struct msgb *msg, u_int8_t val)
-{
- u_int8_t *buf = msgb_put(msg, 1);
- return v_put(buf, val);
-}
-
-static inline u_int8_t *msgb_tv16_put(struct msgb *msg, u_int8_t tag, u_int16_t val)
-{
- u_int8_t *buf = msgb_put(msg, 3);
- return tv16_put(buf, tag, val);
-}
-
-static inline u_int8_t *msgb_tlv_push(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int8_t *val)
-{
- u_int8_t *buf = msgb_push(msg, TLV_GROSS_LEN(len));
- return tlv_put(buf, tag, len, val);
-}
-
-static inline u_int8_t *msgb_tv_push(struct msgb *msg, u_int8_t tag, u_int8_t val)
-{
- u_int8_t *buf = msgb_push(msg, 2);
- return tv_put(buf, tag, val);
-}
-
-static inline u_int8_t *msgb_tv16_push(struct msgb *msg, u_int8_t tag, u_int16_t val)
-{
- u_int8_t *buf = msgb_push(msg, 3);
- return tv16_put(buf, tag, val);
-}
-
-/* TLV parsing */
-
-struct tlv_p_entry {
- u_int16_t len;
- const u_int8_t *val;
-};
-
-enum tlv_type {
- TLV_TYPE_FIXED,
- TLV_TYPE_T,
- TLV_TYPE_TV,
- TLV_TYPE_TLV,
- TLV_TYPE_TL16V,
- TLV_TYPE_TvLV,
-};
-
-struct tlv_def {
- enum tlv_type type;
- u_int8_t fixed_len;
-};
-
-struct tlv_definition {
- struct tlv_def def[0xff];
-};
-
-struct tlv_parsed {
- struct tlv_p_entry lv[0xff];
-};
-
-extern struct tlv_definition tvlv_att_def;
-
-int tlv_parse_one(u_int8_t *o_tag, u_int16_t *o_len, const u_int8_t **o_val,
- const struct tlv_definition *def,
- const u_int8_t *buf, int buf_len);
-int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
- const u_int8_t *buf, int buf_len, u_int8_t lv_tag, u_int8_t lv_tag2);
-
-#define TLVP_PRESENT(x, y) ((x)->lv[y].val)
-#define TLVP_LEN(x, y) (x)->lv[y].len
-#define TLVP_VAL(x, y) (x)->lv[y].val
-
-#endif /* _TLV_H */
diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h
index cf9410082..50c3cc5da 100644
--- a/openbsc/include/openbsc/transaction.h
+++ b/openbsc/include/openbsc/transaction.h
@@ -3,7 +3,7 @@
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_subscriber.h>
-#include <openbsc/linuxlist.h>
+#include <osmocore/linuxlist.h>
#include <openbsc/gsm_04_11.h>
/* One transaction */
diff --git a/openbsc/include/openbsc/ussd.h b/openbsc/include/openbsc/ussd.h
index e7bd6d69d..63ea31c5e 100644
--- a/openbsc/include/openbsc/ussd.h
+++ b/openbsc/include/openbsc/ussd.h
@@ -3,7 +3,7 @@
/* Handler function for mobile-originated USSD messages */
-#include <openbsc/msgb.h>
+#include <osmocore/msgb.h>
int handle_rcv_ussd(struct msgb *msg);
diff --git a/openbsc/include/sccp/Makefile.am b/openbsc/include/sccp/Makefile.am
index 42fd31047..6c8a51714 100644
--- a/openbsc/include/sccp/Makefile.am
+++ b/openbsc/include/sccp/Makefile.am
@@ -1 +1,2 @@
-noinst_HEADERS = sccp_types.h sccp.h
+sccp_HEADERS = sccp_types.h sccp.h
+sccpdir = $(includedir)/sccp
diff --git a/openbsc/include/sccp/sccp.h b/openbsc/include/sccp/sccp.h
index e5e8b819c..643479adc 100644
--- a/openbsc/include/sccp/sccp.h
+++ b/openbsc/include/sccp/sccp.h
@@ -27,11 +27,11 @@
#include <stdlib.h>
#include <sys/socket.h>
-
-#include <openbsc/msgb.h>
+#include <sys/types.h>
#include "sccp_types.h"
+struct msgb;
struct sccp_system;
enum {
diff --git a/openbsc/include/sccp/sccp_types.h b/openbsc/include/sccp/sccp_types.h
index 9310a6bf0..42fda96ae 100644
--- a/openbsc/include/sccp/sccp_types.h
+++ b/openbsc/include/sccp/sccp_types.h
@@ -24,6 +24,8 @@
#ifndef SCCP_TYPES_H
#define SCCP_TYPES_H
+#include <endian.h>
+
/* Table 1/Q.713 - SCCP message types */
enum sccp_message_types {
SCCP_MSG_TYPE_CR = 1,
@@ -87,11 +89,19 @@ enum {
};
struct sccp_called_party_address {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
u_int8_t point_code_indicator : 1,
ssn_indicator : 1,
global_title_indicator : 4,
routing_indicator : 1,
reserved : 1;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u_int8_t reserved : 1,
+ routing_indicator : 1,
+ global_title_indicator : 4,
+ ssn_indicator : 1,
+ point_code_indicator : 1;
+#endif
u_int8_t data[0];
} __attribute__((packed));
@@ -100,8 +110,13 @@ struct sccp_called_party_address {
/* Figure 6/Q.713 */
struct sccp_signalling_point_code {
u_int8_t lsb;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
u_int8_t msb : 6,
reserved : 2;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u_int8_t reserved : 2,
+ msb : 6;
+#endif
} __attribute__((packed));
/* SSN == subsystem number */
@@ -137,8 +152,13 @@ enum {
};
struct sccp_global_title {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
u_int8_t nature_of_addr_ind : 7,
odd_even : 1;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u_int8_t odd_even : 1,
+ nature_of_addr_ind : 7;
+#endif
u_int8_t data[0];
} __attribute__((packed));
diff --git a/openbsc/include/vty/command.h b/openbsc/include/vty/command.h
index dc12c5258..31dd7f3b2 100644
--- a/openbsc/include/vty/command.h
+++ b/openbsc/include/vty/command.h
@@ -358,4 +358,6 @@ void host_config_set(const char *);
void print_version(const char *);
+extern void *tall_vty_cmd_ctx;
+
#endif /* _ZEBRA_COMMAND_H */
diff --git a/openbsc/include/vty/vector.h b/openbsc/include/vty/vector.h
index 00f0079f3..22a184d61 100644
--- a/openbsc/include/vty/vector.h
+++ b/openbsc/include/vty/vector.h
@@ -59,4 +59,6 @@ vector vector_copy(vector v);
void *vector_lookup(vector, unsigned int);
void *vector_lookup_ensure(vector, unsigned int);
+extern void *tall_vty_vec_ctx;
+
#endif /* _ZEBRA_VECTOR_H */
diff --git a/openbsc/libsccp.pc.in b/openbsc/libsccp.pc.in
new file mode 100644
index 000000000..eda8d499c
--- /dev/null
+++ b/openbsc/libsccp.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: OpenBSC SCCP Lib
+Description: OpenBSC SCCP Lib
+Version: @VERSION@
+Libs: -L${libdir} -lsccp
+Cflags: -I${includedir}/
diff --git a/openbsc/openbsc.pc.in b/openbsc/openbsc.pc.in
index 0d00831a2..aba07e296 100644
--- a/openbsc/openbsc.pc.in
+++ b/openbsc/openbsc.pc.in
@@ -1,7 +1,7 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
-includedir=@includedir@/openbsc-1.0
+includedir=@includedir@/
Name: OpenBSC
Description: OpenBSC base station controller
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index 615884a38..2c695993d 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -1,23 +1,29 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS=-Wall
+AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS)
+AM_LDFLAGS = $(LIBOSMOCORE_LIBS)
sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \
- isdnsync bsc_mgcp bsc_msc_ip bsc_nat
-noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a
+ isdnsync bsc_mgcp ipaccess-proxy \
+ bsc_msc_ip bsc_nat
+noinst_LIBRARIES = libbsc.a libmsc.a libvty.a
noinst_HEADERS = vty/cardshell.h
+bscdir = $(libdir)
+bsc_LIBRARIES = libsccp.a
+
libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \
- msgb.c select.c chan_alloc.c timer.c debug.c \
+ chan_alloc.c debug.c \
gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.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 \
- talloc_ctx.c system_information.c bitvec.c rest_octets.c \
- rtp_proxy.c telnet_interface.c
+ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c \
+ input/misdn.c input/ipaccess.c \
+ talloc_ctx.c system_information.c rest_octets.c \
+ rtp_proxy.c bts_siemens_bs11.c bts_ipaccess_nanobts.c \
+ bts_unknown.c telnet_interface.c meas_rep.c
libmsc_a_SOURCES = gsm_subscriber.c db.c \
mncc.c gsm_04_08.c gsm_04_11.c transaction.c \
token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c \
- handover_logic.c handover_decision.c meas_rep.c
+ handover_logic.c handover_decision.c
libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c
@@ -26,22 +32,25 @@ libsccp_a_SOURCES = sccp/sccp.c
bsc_hack_SOURCES = bsc_hack.c bsc_init.c vty_interface.c vty_interface_layer3.c
bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT)
+bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c debug.c \
+ rs232.c bts_siemens_bs11.c
bsc_msc_ip_SOURCES = bssap.c bsc_msc_ip.c bsc_init.c vty_interface.c vty_interface_bsc.c \
bsc_msc.c
bsc_msc_ip_LDADD = libbsc.a libvty.a libsccp.a
-bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c \
- select.c timer.c rs232.c tlv_parser.c signal.c talloc.c
-ipaccess_find_SOURCES = ipaccess-find.c select.c timer.c
+ipaccess_find_SOURCES = ipaccess/ipaccess-find.c
-ipaccess_config_SOURCES = ipaccess-config.c
+ipaccess_config_SOURCES = ipaccess/ipaccess-config.c ipaccess/ipaccess-firmware.c
ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYPT)
isdnsync_SOURCES = isdnsync.c
-bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c
+bsc_mgcp_SOURCES = mgcp/mgcp_main.c mgcp/mgcp_protocol.c mgcp/mgcp_network.c mgcp/mgcp_vty.c \
+ debug.c telnet_interface.c
bsc_mgcp_LDADD = libvty.a
+ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c debug.c
+
bsc_nat_SOURCES = nat/bsc_nat.c nat/bsc_filter.c nat/bsc_nat_vty.c bsc_msc.c bssap.c
bsc_nat_LDADD = libvty.a libbsc.a libsccp.a
diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c
index bb7248be7..99d8dd621 100644
--- a/openbsc/src/abis_nm.c
+++ b/openbsc/src/abis_nm.c
@@ -38,15 +38,16 @@
#include <openbsc/gsm_data.h>
#include <openbsc/debug.h>
-#include <openbsc/msgb.h>
-#include <openbsc/tlv.h>
+#include <osmocore/msgb.h>
+#include <osmocore/tlv.h>
+#include <osmocore/talloc.h>
#include <openbsc/abis_nm.h>
#include <openbsc/misdn.h>
#include <openbsc/signal.h>
-#include <openbsc/talloc.h>
#define OM_ALLOC_SIZE 1024
#define OM_HEADROOM_SIZE 128
+#define IPACC_SEGMENT_SIZE 245
/* unidirectional messages from BTS to BSC */
static const enum abis_nm_msgtype reports[] = {
@@ -263,7 +264,7 @@ static const enum abis_nm_attr nm_att_settable[] = {
NM_ATT_MEAS_TYPE,
};
-static const struct tlv_definition nm_att_tlvdef = {
+const struct tlv_definition nm_att_tlvdef = {
.def = {
[NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
[NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
@@ -329,77 +330,6 @@ static const struct tlv_definition nm_att_tlvdef = {
[NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
[NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
[NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
- /* BS11 specifics */
- [NM_ATT_BS11_ESN_FW_CODE_NO] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_ESN_HW_CODE_NO] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_ESN_PCB_SERIAL] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_BOOT_SW_VERS] = { TLV_TYPE_TLV },
- [0xd5] = { TLV_TYPE_TLV },
- [0xa8] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_PASSWORD] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_TXPWR] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_RSSI_OFFS] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_LINE_CFG] = { TLV_TYPE_TV },
- [NM_ATT_BS11_L1_PROT_TYPE] = { TLV_TYPE_TV },
- [NM_ATT_BS11_BIT_ERR_THESH] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_BS11_DIVERSITY] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_LMT_LOGON_SESSION]={ TLV_TYPE_TLV },
- [NM_ATT_BS11_LMT_LOGIN_TIME] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_LMT_USER_ACC_LEV] ={ TLV_TYPE_TLV },
- [NM_ATT_BS11_LMT_USER_NAME] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_BTS_STATE] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_E1_STATE] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_PLL_MODE] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_PLL] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_CCLK_ACCURACY] = { TLV_TYPE_TV },
- [NM_ATT_BS11_CCLK_TYPE] = { TLV_TYPE_TV },
- /* 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_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 },
-
},
};
@@ -422,9 +352,11 @@ int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
return -EINVAL;
}
-int abis_nm_tlv_parse(struct tlv_parsed *tp, const u_int8_t *buf, int len)
+int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len)
{
- return tlv_parse(tp, &nm_att_tlvdef, buf, len, 0, 0);
+ if (!bts->model)
+ return -EIO;
+ return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
}
static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
@@ -540,11 +472,11 @@ static const char *obj_class_name(u_int8_t oc)
const char *nm_opstate_name(u_int8_t os)
{
switch (os) {
- case 1:
+ case NM_OPSTATE_DISABLED:
return "Disabled";
- case 2:
+ case NM_OPSTATE_ENABLED:
return "Enabled";
- case 0xff:
+ case NM_OPSTATE_NULL:
return "NULL";
default:
return "RFU";
@@ -598,6 +530,13 @@ const char *nm_adm_name(u_int8_t adm)
}
}
+int nm_is_running(struct gsm_nm_state *s) {
+ return (s->operational == NM_OPSTATE_ENABLED) && (
+ (s->availability == NM_AVSTATE_OK) ||
+ (s->availability == 0xff)
+ );
+}
+
static void debugp_foh(struct abis_om_fom_hdr *foh)
{
DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
@@ -793,7 +732,7 @@ static int abis_nm_rx_statechg_rep(struct msgb *mb)
new_state = *nm_state;
- abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+ abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
@@ -805,19 +744,25 @@ static int abis_nm_rx_statechg_rep(struct msgb *mb)
new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
new_state.availability);
- }
+ } else
+ new_state.availability = 0xff;
if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
}
DEBUGPC(DNM, "\n");
- if (memcmp(&new_state, nm_state, sizeof(new_state))) {
+ if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
+ new_state.operational != nm_state->operational ||
+ new_state.availability != nm_state->availability) {
/* Update the operational state of a given object in our in-memory data
* structures and send an event to the higher layer */
void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
- *nm_state = new_state;
+ nm_state->operational = new_state.operational;
+ nm_state->availability = new_state.availability;
+ if (nm_state->administrative == 0)
+ nm_state->administrative = new_state.administrative;
}
#if 0
if (op_state == 1) {
@@ -839,7 +784,7 @@ static int rx_fail_evt_rep(struct msgb *mb)
DEBUGPC(DNM, "Failure Event Report ");
- abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+ abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
@@ -933,7 +878,7 @@ static int abis_nm_rx_sw_act_req(struct msgb *mb)
if (nack)
return ret;
- abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+ abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
@@ -967,7 +912,7 @@ static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
struct tlv_parsed tp;
u_int8_t adm_state;
- abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+ abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
return -EINVAL;
@@ -983,7 +928,7 @@ static int abis_nm_rx_lmt_event(struct msgb *mb)
struct tlv_parsed tp;
DEBUGP(DNM, "LMT Event ");
- abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+ abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
@@ -1029,7 +974,7 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb)
else
DEBUGPC(DNM, "NACK 0x%02x ", mt);
- abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+ abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
DEBUGPC(DNM, "CAUSE=%s\n",
nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
@@ -1043,13 +988,11 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb)
/* check if last message is to be acked */
if (is_ack_nack(nmh->last_msgtype)) {
if (mt == MT_ACK(nmh->last_msgtype)) {
- fprintf(stderr, "received ACK (0x%x)\n",
- foh->msg_type);
+ DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
/* we got our ACK, continue sending the next msg */
} else if (mt == MT_NACK(nmh->last_msgtype)) {
/* we got a NACK, signal this to the caller */
- fprintf(stderr, "received NACK (0x%x)\n",
- foh->msg_type);
+ DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
/* FIXME: somehow signal this to the caller */
} else {
/* really strange things happen */
@@ -1071,6 +1014,12 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb)
case NM_MT_CONN_MDROP_LINK_ACK:
DEBUGP(DNM, "CONN MDROP LINK ACK\n");
break;
+ case NM_MT_IPACC_RESTART_ACK:
+ dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
+ break;
+ case NM_MT_IPACC_RESTART_NACK:
+ dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
+ break;
}
return 0;
@@ -1216,6 +1165,22 @@ struct abis_nm_sw {
static struct abis_nm_sw g_sw;
+static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
+{
+ if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
+ msgb_v_put(msg, NM_ATT_SW_DESCR);
+ msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
+ msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
+ sw->file_version);
+ } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
+ msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
+ msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
+ sw->file_version);
+ } else {
+ LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
+ }
+}
+
/* 6.2.1 / 8.3.1: Load Data Initiate */
static int sw_load_init(struct abis_nm_sw *sw)
{
@@ -1227,11 +1192,8 @@ static int sw_load_init(struct abis_nm_sw *sw)
fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
sw->obj_instance[0], sw->obj_instance[1],
sw->obj_instance[2]);
-
- /* FIXME: this is BS11 specific format */
- msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
- msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
- sw->file_version);
+
+ sw_add_file_id_and_ver(sw, msg);
msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
return abis_nm_sendmsg(sw->bts, msg);
@@ -1289,7 +1251,24 @@ static int sw_load_segment(struct abis_nm_sw *sw)
/* we only now know the exact length for the OM hdr */
len = strlen(line_buf)+2;
break;
+ case GSM_BTS_TYPE_NANOBTS: {
+ static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
+ len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
+ if (len < 0) {
+ perror("read failed");
+ return -EINVAL;
+ }
+
+ if (len != IPACC_SEGMENT_SIZE)
+ sw->last_seg = 1;
+
+ ++sw->seg_in_window;
+ msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
+ len += 3;
+ break;
+ }
default:
+ LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
/* FIXME: Other BTS types */
return -1;
}
@@ -1313,11 +1292,7 @@ static int sw_load_end(struct abis_nm_sw *sw)
sw->obj_instance[0], sw->obj_instance[1],
sw->obj_instance[2]);
- /* FIXME: this is BS11 specific format */
- msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
- msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
- sw->file_version);
-
+ sw_add_file_id_and_ver(sw, msg);
return abis_nm_sendmsg(sw->bts, msg);
}
@@ -1341,6 +1316,59 @@ static int sw_activate(struct abis_nm_sw *sw)
return abis_nm_sendmsg(sw->bts, msg);
}
+struct sdp_firmware {
+ char magic[4];
+ char more_magic[4];
+ unsigned int header_length;
+ unsigned int file_length;
+} __attribute__ ((packed));
+
+static int parse_sdp_header(struct abis_nm_sw *sw)
+{
+ struct sdp_firmware firmware_header;
+ int rc;
+ struct stat stat;
+
+ rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
+ if (rc != sizeof(firmware_header)) {
+ LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
+ return -1;
+ }
+
+ if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
+ LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
+ return -1;
+ }
+
+ if (firmware_header.more_magic[0] != 0x10 ||
+ firmware_header.more_magic[1] != 0x02 ||
+ firmware_header.more_magic[2] != 0x00 ||
+ firmware_header.more_magic[3] != 0x00) {
+ LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
+ return -1;
+ }
+
+
+ if (fstat(sw->fd, &stat) == -1) {
+ LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
+ return -1;
+ }
+
+ if (ntohl(firmware_header.file_length) != stat.st_size) {
+ LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
+ return -1;
+ }
+
+ /* go back to the start as we checked the whole filesize.. */
+ lseek(sw->fd, 0l, SEEK_SET);
+ LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
+ "There might be checksums in the file that are not\n"
+ "verified and incomplete firmware might be flashed.\n"
+ "There is absolutely no WARRANTY that flashing will\n"
+ "work.\n");
+ return 0;
+}
+
static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
{
char file_id[12+1];
@@ -1372,6 +1400,19 @@ static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
/* rewind to start of file */
rewind(sw->stream);
break;
+ case GSM_BTS_TYPE_NANOBTS:
+ /* TODO: extract that from the filename or content */
+ rc = parse_sdp_header(sw);
+ if (rc < 0) {
+ fprintf(stderr, "Could not parse the ipaccess SDP header\n");
+ return -1;
+ }
+
+ strcpy((char *)sw->file_id, "id");
+ sw->file_id_len = 3;
+ strcpy((char *)sw->file_version, "version");
+ sw->file_version_len = 8;
+ break;
default:
/* We don't know how to treat them yet */
close(sw->fd);
@@ -1470,6 +1511,12 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
rc = sw_load_end(sw);
}
break;
+ case NM_MT_LOAD_ABORT:
+ if (sw->cbfn)
+ sw->cbfn(GSM_HOOK_NM_SWLOAD,
+ NM_MT_LOAD_ABORT, mb,
+ sw->cb_data, NULL);
+ break;
}
break;
case SW_STATE_WAIT_ENDACK:
@@ -1483,6 +1530,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
sw->cbfn(GSM_HOOK_NM_SWLOAD,
NM_MT_LOAD_END_ACK, mb,
sw->cb_data, NULL);
+ rc = 0;
break;
case NM_MT_LOAD_END_NACK:
if (sw->forced) {
@@ -1559,10 +1607,26 @@ int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
return -EBUSY;
sw->bts = bts;
- sw->obj_class = NM_OC_SITE_MANAGER;
- sw->obj_instance[0] = 0xff;
- sw->obj_instance[1] = 0xff;
- sw->obj_instance[2] = 0xff;
+
+ switch (bts->type) {
+ case GSM_BTS_TYPE_BS11:
+ sw->obj_class = NM_OC_SITE_MANAGER;
+ sw->obj_instance[0] = 0xff;
+ sw->obj_instance[1] = 0xff;
+ sw->obj_instance[2] = 0xff;
+ break;
+ case GSM_BTS_TYPE_NANOBTS:
+ sw->obj_class = NM_OC_BASEB_TRANSC;
+ sw->obj_instance[0] = 0x00;
+ sw->obj_instance[1] = 0x00;
+ sw->obj_instance[2] = 0xff;
+ break;
+ case GSM_BTS_TYPE_UNKNOWN:
+ default:
+ LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
+ return -1;
+ break;
+ }
sw->window_size = win_size;
sw->state = SW_STATE_WAIT_INITACK;
sw->cbfn = cbfn;
@@ -1590,7 +1654,10 @@ int abis_nm_software_load_status(struct gsm_bts *bts)
return rc;
}
- percent = (ftell(sw->stream) * 100) / st.st_size;
+ if (sw->stream)
+ percent = (ftell(sw->stream) * 100) / st.st_size;
+ else
+ percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
return percent;
}
@@ -2281,11 +2348,19 @@ int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
}
//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
-static const u_int8_t bs11_logon_c8[] = { 0x02 };
-static const u_int8_t bs11_logon_c9[] = "FACTORY";
int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
{
+ return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
+}
+
+int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
+{
+ return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
+}
+
+int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
+{
struct abis_om_hdr *oh;
struct msgb *msg = nm_msgb_alloc();
struct bs11_date_time bdt;
@@ -2295,15 +2370,15 @@ int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
if (on) {
u_int8_t len = 3*2 + sizeof(bdt)
- + sizeof(bs11_logon_c8) + sizeof(bs11_logon_c9);
+ + 1 + strlen(name);
fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
sizeof(bdt), (u_int8_t *) &bdt);
msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
- sizeof(bs11_logon_c8), bs11_logon_c8);
+ 1, &level);
msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
- sizeof(bs11_logon_c9), bs11_logon_c9);
+ strlen(name), (u_int8_t *)name);
} else {
fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
@@ -2351,6 +2426,27 @@ int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
return abis_nm_sendmsg(bts, msg);
}
+/* Set the calibration value of the PLL (work value/set value)
+ * It depends on the login which one is changed */
+int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
+{
+ struct abis_om_hdr *oh;
+ struct msgb *msg;
+ u_int8_t tlv_value[2];
+
+ msg = nm_msgb_alloc();
+ oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
+ fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
+ BS11_OBJ_TRX1, 0x00, 0x00);
+
+ tlv_value[0] = value>>8;
+ tlv_value[1] = value&0xff;
+
+ msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
+
+ return abis_nm_sendmsg(bts, msg);
+}
+
int abis_nm_bs11_get_state(struct gsm_bts *bts)
{
return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
@@ -2597,14 +2693,15 @@ static int abis_nm_rx_ipacc(struct msgb *msg)
struct abis_om_fom_hdr *foh;
u_int8_t idstrlen = oh->data[0];
struct tlv_parsed tp;
+ struct ipacc_ack_signal_data signal;
if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
- DEBUGP(DNM, "id string is not com.ipaccess !?!\n");
+ LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
return -EINVAL;
}
foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
- abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+ abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
debugp_foh(foh);
@@ -2627,7 +2724,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg)
DEBUGPC(DNM, "\n");
break;
case NM_MT_IPACC_RSL_CONNECT_NACK:
- DEBUGPC(DNM, "RSL CONNECT NACK ");
+ LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
DEBUGPC(DNM, " CAUSE=%s\n",
nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
@@ -2639,35 +2736,35 @@ static int abis_nm_rx_ipacc(struct msgb *msg)
/* FIXME: decode and show the actual attributes */
break;
case NM_MT_IPACC_SET_NVATTR_NACK:
- DEBUGPC(DNM, "SET NVATTR NACK ");
+ LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
- DEBUGPC(DNM, " CAUSE=%s\n",
+ LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
else
- DEBUGPC(DNM, "\n");
+ LOGPC(DNM, LOGL_ERROR, "\n");
break;
case NM_MT_IPACC_GET_NVATTR_ACK:
DEBUGPC(DNM, "GET NVATTR ACK\n");
/* FIXME: decode and show the actual attributes */
break;
case NM_MT_IPACC_GET_NVATTR_NACK:
- DEBUGPC(DNM, "GET NVATTR NACK ");
+ LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
- DEBUGPC(DNM, " CAUSE=%s\n",
+ LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
else
- DEBUGPC(DNM, "\n");
+ LOGPC(DNM, LOGL_ERROR, "\n");
break;
case NM_MT_IPACC_SET_ATTR_ACK:
DEBUGPC(DNM, "SET ATTR ACK\n");
break;
case NM_MT_IPACC_SET_ATTR_NACK:
- DEBUGPC(DNM, "SET ATTR NACK ");
+ LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
- DEBUGPC(DNM, " CAUSE=%s\n",
+ LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
else
- DEBUGPC(DNM, "\n");
+ LOGPC(DNM, LOGL_ERROR, "\n");
break;
default:
DEBUGPC(DNM, "unknown\n");
@@ -2679,7 +2776,14 @@ static int abis_nm_rx_ipacc(struct msgb *msg)
case NM_MT_IPACC_RSL_CONNECT_NACK:
case NM_MT_IPACC_SET_NVATTR_NACK:
case NM_MT_IPACC_GET_NVATTR_NACK:
- dispatch_signal(SS_NM, S_NM_IPACC_NACK, &foh->msg_type);
+ signal.bts = msg->trx->bts;
+ signal.msg_type = foh->msg_type;
+ dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
+ break;
+ case NM_MT_IPACC_SET_NVATTR_ACK:
+ signal.bts = msg->trx->bts;
+ signal.msg_type = foh->msg_type;
+ dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
break;
default:
break;
@@ -2726,11 +2830,11 @@ int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
}
/* set some attributes in NVRAM */
-int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr,
+int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
int attr_len)
{
- return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_NVATTR,
- NM_OC_BASEB_TRANSC, 0, 0, 0xff, attr,
+ return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
+ NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
attr_len);
}
@@ -2781,7 +2885,7 @@ void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
{
int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
- trx->rf_locked = locked;
+ trx->nm_state.administrative = new_state;
if (!trx->bts || !trx->bts->oml_link)
return;
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index e2fadf00c..3079d0d54 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -1,7 +1,7 @@
/* GSM Radio Signalling Link messages on the A-bis interface
* 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
+/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
@@ -30,104 +30,23 @@
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_04_08.h>
-#include <openbsc/gsm_utils.h>
+#include <osmocore/gsm_utils.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/bsc_rll.h>
#include <openbsc/debug.h>
-#include <openbsc/tlv.h>
+#include <osmocore/tlv.h>
#include <openbsc/paging.h>
#include <openbsc/signal.h>
#include <openbsc/meas_rep.h>
#include <openbsc/rtp_proxy.h>
+#include <osmocore/rsl.h>
#define RSL_ALLOC_SIZE 1024
#define RSL_ALLOC_HEADROOM 128
#define MAX(a, b) (a) >= (b) ? (a) : (b)
-static const struct tlv_definition rsl_att_tlvdef = {
- .def = {
- [RSL_IE_CHAN_NR] = { TLV_TYPE_TV },
- [RSL_IE_LINK_IDENT] = { TLV_TYPE_TV },
- [RSL_IE_ACT_TYPE] = { TLV_TYPE_TV },
- [RSL_IE_BS_POWER] = { TLV_TYPE_TV },
- [RSL_IE_CHAN_IDENT] = { TLV_TYPE_TLV },
- [RSL_IE_CHAN_MODE] = { TLV_TYPE_TLV },
- [RSL_IE_ENCR_INFO] = { TLV_TYPE_TLV },
- [RSL_IE_FRAME_NUMBER] = { TLV_TYPE_FIXED, 2 },
- [RSL_IE_HANDO_REF] = { TLV_TYPE_TV },
- [RSL_IE_L1_INFO] = { TLV_TYPE_FIXED, 2 },
- [RSL_IE_L3_INFO] = { TLV_TYPE_TL16V },
- [RSL_IE_MS_IDENTITY] = { TLV_TYPE_TLV },
- [RSL_IE_MS_POWER] = { TLV_TYPE_TV },
- [RSL_IE_PAGING_GROUP] = { TLV_TYPE_TV },
- [RSL_IE_PAGING_LOAD] = { TLV_TYPE_FIXED, 2 },
- [RSL_IE_PYHS_CONTEXT] = { TLV_TYPE_TLV },
- [RSL_IE_ACCESS_DELAY] = { TLV_TYPE_TV },
- [RSL_IE_RACH_LOAD] = { TLV_TYPE_TLV },
- [RSL_IE_REQ_REFERENCE] = { TLV_TYPE_FIXED, 3 },
- [RSL_IE_RELEASE_MODE] = { TLV_TYPE_TV },
- [RSL_IE_RESOURCE_INFO] = { TLV_TYPE_TLV },
- [RSL_IE_RLM_CAUSE] = { TLV_TYPE_TLV },
- [RSL_IE_STARTNG_TIME] = { TLV_TYPE_FIXED, 2 },
- [RSL_IE_TIMING_ADVANCE] = { TLV_TYPE_TV },
- [RSL_IE_UPLINK_MEAS] = { TLV_TYPE_TLV },
- [RSL_IE_CAUSE] = { TLV_TYPE_TLV },
- [RSL_IE_MEAS_RES_NR] = { TLV_TYPE_TV },
- [RSL_IE_MSG_ID] = { TLV_TYPE_TV },
- [RSL_IE_SYSINFO_TYPE] = { TLV_TYPE_TV },
- [RSL_IE_MS_POWER_PARAM] = { TLV_TYPE_TLV },
- [RSL_IE_BS_POWER_PARAM] = { TLV_TYPE_TLV },
- [RSL_IE_PREPROC_PARAM] = { TLV_TYPE_TLV },
- [RSL_IE_PREPROC_MEAS] = { TLV_TYPE_TLV },
- [RSL_IE_IMM_ASS_INFO] = { TLV_TYPE_TLV },
- [RSL_IE_SMSCB_INFO] = { TLV_TYPE_FIXED, 23 },
- [RSL_IE_MS_TIMING_OFFSET] = { TLV_TYPE_TV },
- [RSL_IE_ERR_MSG] = { TLV_TYPE_TLV },
- [RSL_IE_FULL_BCCH_INFO] = { TLV_TYPE_TLV },
- [RSL_IE_CHAN_NEEDED] = { TLV_TYPE_TV },
- [RSL_IE_CB_CMD_TYPE] = { TLV_TYPE_TV },
- [RSL_IE_SMSCB_MSG] = { TLV_TYPE_TLV },
- [RSL_IE_FULL_IMM_ASS_INFO] = { TLV_TYPE_TLV },
- [RSL_IE_SACCH_INFO] = { TLV_TYPE_TLV },
- [RSL_IE_CBCH_LOAD_INFO] = { TLV_TYPE_TV },
- [RSL_IE_SMSCB_CHAN_INDICATOR] = { TLV_TYPE_TV },
- [RSL_IE_GROUP_CALL_REF] = { TLV_TYPE_TLV },
- [RSL_IE_CHAN_DESC] = { TLV_TYPE_TLV },
- [RSL_IE_NCH_DRX_INFO] = { TLV_TYPE_TLV },
- [RSL_IE_CMD_INDICATOR] = { TLV_TYPE_TLV },
- [RSL_IE_EMLPP_PRIO] = { TLV_TYPE_TV },
- [RSL_IE_UIC] = { TLV_TYPE_TLV },
- [RSL_IE_MAIN_CHAN_REF] = { TLV_TYPE_TV },
- [RSL_IE_MR_CONFIG] = { TLV_TYPE_TLV },
- [RSL_IE_MR_CONTROL] = { TLV_TYPE_TV },
- [RSL_IE_SUP_CODEC_TYPES] = { TLV_TYPE_TLV },
- [RSL_IE_CODEC_CONFIG] = { TLV_TYPE_TLV },
- [RSL_IE_RTD] = { TLV_TYPE_TV },
- [RSL_IE_TFO_STATUS] = { TLV_TYPE_TV },
- [RSL_IE_LLP_APDU] = { TLV_TYPE_TLV },
- [RSL_IE_SIEMENS_MRPCI] = { TLV_TYPE_TV },
- [RSL_IE_IPAC_PROXY_UDP] = { TLV_TYPE_FIXED, 2 },
- [RSL_IE_IPAC_BSCMPL_TOUT] = { TLV_TYPE_TV },
- [RSL_IE_IPAC_REMOTE_IP] = { TLV_TYPE_FIXED, 4 },
- [RSL_IE_IPAC_REMOTE_PORT] = { TLV_TYPE_FIXED, 2 },
- [RSL_IE_IPAC_RTP_PAYLOAD] = { TLV_TYPE_TV },
- [RSL_IE_IPAC_LOCAL_PORT] = { TLV_TYPE_FIXED, 2 },
- [RSL_IE_IPAC_SPEECH_MODE] = { TLV_TYPE_TV },
- [RSL_IE_IPAC_LOCAL_IP] = { TLV_TYPE_FIXED, 4 },
- [RSL_IE_IPAC_CONN_ID] = { TLV_TYPE_FIXED, 2 },
- [RSL_IE_IPAC_RTP_CSD_FMT] = { TLV_TYPE_TV },
- [RSL_IE_IPAC_RTP_JIT_BUF] = { TLV_TYPE_FIXED, 2 },
- [RSL_IE_IPAC_RTP_COMPR] = { TLV_TYPE_TV },
- [RSL_IE_IPAC_RTP_PAYLOAD2] = { TLV_TYPE_TV },
- [RSL_IE_IPAC_RTP_MPLEX] = { TLV_TYPE_FIXED, 8 },
- [RSL_IE_IPAC_RTP_MPLEX_ID] = { TLV_TYPE_TV },
- },
-};
-#define rsl_tlv_parse(dec, buf, len) \
- tlv_parse(dec, &rsl_att_tlvdef, buf, len, 0, 0)
-
static u_int8_t mdisc_by_msgtype(u_int8_t msg_type)
{
/* mask off the transparent bit ? */
@@ -155,44 +74,6 @@ static inline void init_dchan_hdr(struct abis_rsl_dchan_hdr *dh,
dh->ie_chan = RSL_IE_CHAN_NR;
}
-static inline void init_llm_hdr(struct abis_rsl_rll_hdr *dh,
- u_int8_t msg_type)
-{
- /* dh->c.msg_discr = mdisc_by_msgtype(msg_type); */
- dh->c.msg_discr = ABIS_RSL_MDISC_RLL;
- dh->c.msg_type = msg_type;
- dh->ie_chan = RSL_IE_CHAN_NR;
- dh->ie_link_id = RSL_IE_LINK_IDENT;
-}
-
-
-/* encode channel number as per Section 9.3.1 */
-u_int8_t rsl_enc_chan_nr(u_int8_t type, u_int8_t subch, u_int8_t timeslot)
-{
- u_int8_t ret;
-
- ret = (timeslot & 0x07) | type;
-
- switch (type) {
- case RSL_CHAN_Lm_ACCHs:
- subch &= 0x01;
- break;
- case RSL_CHAN_SDCCH4_ACCH:
- subch &= 0x07;
- break;
- case RSL_CHAN_SDCCH8_ACCH:
- subch &= 0x07;
- break;
- default:
- /* no subchannels allowed */
- subch = 0x00;
- break;
- }
- ret |= (subch << 3);
-
- return ret;
-}
-
/* determine logical channel based on TRX and channel number IE */
struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr)
{
@@ -237,6 +118,8 @@ struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr)
}
lchan = &ts->lchan[lch_idx];
+ debug_set_context(BSC_CTX_LCHAN, lchan);
+ debug_set_context(BSC_CTX_SUBSCR, lchan->subscr);
return lchan;
}
@@ -333,57 +216,14 @@ static int build_encr_info(u_int8_t *out, struct gsm_lchan *lchan)
return lchan->encr.key_len + 1;
}
-
-static const char *rsl_err_vals[0xff] = {
- [RSL_ERR_RADIO_IF_FAIL] = "Radio Interface Failure",
- [RSL_ERR_RADIO_LINK_FAIL] = "Radio Link Failure",
- [RSL_ERR_HANDOVER_ACC_FAIL] = "Handover Access Failure",
- [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",
- [RSL_ERR_CCCH_OVERLOAD] = "CCCH Overload",
- [RSL_ERR_ACCH_OVERLOAD] = "ACCH Overload",
- [RSL_ERR_PROCESSOR_OVERLOAD] = "Processor Overload",
- [RSL_ERR_RES_UNAVAIL] = "Resource not available, unspecified",
- [RSL_ERR_TRANSC_UNAVAIL] = "Transcoding not available",
- [RSL_ERR_SERV_OPT_UNAVAIL] = "Service or Option not available",
- [RSL_ERR_ENCR_UNIMPL] = "Encryption algorithm not implemented",
- [RSL_ERR_SERV_OPT_UNIMPL] = "Service or Option not implemented",
- [RSL_ERR_RCH_ALR_ACTV_ALLOC] = "Radio channel already activated",
- [RSL_ERR_INVALID_MESSAGE] = "Invalid Message, unspecified",
- [RSL_ERR_MSG_DISCR] = "Message Discriminator Error",
- [RSL_ERR_MSG_TYPE] = "Message Type Error",
- [RSL_ERR_MSG_SEQ] = "Message Sequence Error",
- [RSL_ERR_IE_ERROR] = "General IE error",
- [RSL_ERR_MAND_IE_ERROR] = "Mandatory IE error",
- [RSL_ERR_OPT_IE_ERROR] = "Optional IE error",
- [RSL_ERR_IE_NONEXIST] = "IE non-existent",
- [RSL_ERR_IE_LENGTH] = "IE length error",
- [RSL_ERR_IE_CONTENT] = "IE content error",
- [RSL_ERR_PROTO] = "Protocol error, unspecified",
- [RSL_ERR_INTERWORKING] = "Interworking error, unspecified",
-};
-
-static const char *rsl_err_name(u_int8_t err)
-{
- if (rsl_err_vals[err])
- return rsl_err_vals[err];
- else
- return "unknown";
-}
-
-static void print_rsl_cause(const u_int8_t *cause_v, u_int8_t cause_len)
+static void print_rsl_cause(int lvl, const u_int8_t *cause_v, u_int8_t cause_len)
{
int i;
- DEBUGPC(DRSL, "CAUSE=0x%02x(%s) ",
+ LOGPC(DRSL, lvl, "CAUSE=0x%02x(%s) ",
cause_v[0], rsl_err_name(cause_v[0]));
for (i = 1; i < cause_len-1; i++)
- DEBUGPC(DRSL, "%02x ", cause_v[i]);
+ LOGPC(DRSL, lvl, "%02x ", cause_v[i]);
}
/* Send a BCCH_INFO message as per Chapter 8.5.1 */
@@ -723,8 +563,7 @@ int rsl_deact_sacch(struct gsm_lchan *lchan)
msg->lchan = lchan;
msg->trx = lchan->ts->trx;
- DEBUGP(DRSL, "DEACTivate SACCH CMD channel=%s chan_nr=0x%02x\n",
- gsm_ts_name(lchan->ts), dh->chan_nr);
+ DEBUGP(DRSL, "%s DEACTivate SACCH CMD\n", gsm_lchan_name(lchan));
return abis_rsl_sendmsg(msg);
}
@@ -742,8 +581,7 @@ int rsl_rf_chan_release(struct gsm_lchan *lchan)
msg->lchan = lchan;
msg->trx = lchan->ts->trx;
- DEBUGP(DRSL, "RF Channel Release CMD channel=%s chan_nr=0x%02x\n",
- gsm_ts_name(lchan->ts), dh->chan_nr);
+ DEBUGP(DRSL, "%s RF Channel Release CMD\n", gsm_lchan_name(lchan));
/* BTS will respond by RF CHAN REL ACK */
return abis_rsl_sendmsg(msg);
@@ -836,8 +674,8 @@ int rsl_siemens_mrpci(struct gsm_lchan *lchan, struct rsl_mrpci *mrpci)
dh->chan_nr = lchan2chan_nr(lchan);
msgb_tv_put(msg, RSL_IE_SIEMENS_MRPCI, *(u_int8_t *)mrpci);
- DEBUGP(DRSL, "channel=%s chan_nr=0x%02x TX Siemens MRPCI 0x%02x\n",
- gsm_ts_name(lchan->ts), dh->chan_nr, *(u_int8_t *)mrpci);
+ DEBUGP(DRSL, "%s TX Siemens MRPCI 0x%02x\n",
+ gsm_lchan_name(lchan), *(u_int8_t *)mrpci);
msg->trx = lchan->ts->trx;
@@ -849,27 +687,13 @@ int rsl_siemens_mrpci(struct gsm_lchan *lchan, struct rsl_mrpci *mrpci)
/* Chapter 8.3.1 */
int rsl_data_request(struct msgb *msg, u_int8_t link_id)
{
- u_int8_t l3_len = msg->tail - (u_int8_t *)msgb_l3(msg);
- struct abis_rsl_rll_hdr *rh;
-
if (msg->lchan == NULL) {
LOGP(DRSL, LOGL_ERROR, "cannot send DATA REQUEST to unknown lchan\n");
return -EINVAL;
}
- if (msg->lchan->use_count <= 0) {
- DEBUGP(DRSL, "BUG: Trying to send data on unused lchan\n");
- }
-
- /* First push the L3 IE tag and length */
- msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len);
-
- /* Then push the RSL header */
- rh = (struct abis_rsl_rll_hdr *) msgb_push(msg, sizeof(*rh));
- init_llm_hdr(rh, RSL_MT_DATA_REQ);
- rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP;
- rh->chan_nr = lchan2chan_nr(msg->lchan);
- rh->link_id = link_id;
+ rsl_rll_push_l3(msg, RSL_MT_DATA_REQ, lchan2chan_nr(msg->lchan),
+ link_id, 1);
msg->trx = msg->lchan->ts->trx;
@@ -880,15 +704,10 @@ int rsl_data_request(struct msgb *msg, u_int8_t link_id)
/* Chapter 8.3.1 */
int rsl_establish_request(struct gsm_lchan *lchan, u_int8_t link_id)
{
- struct msgb *msg = rsl_msgb_alloc();
- struct abis_rsl_rll_hdr *rh;
-
- rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh));
- init_llm_hdr(rh, RSL_MT_EST_REQ);
- //rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP;
- rh->chan_nr = lchan2chan_nr(lchan);
- rh->link_id = link_id;
+ struct msgb *msg;
+ msg = rsl_rll_simple(RSL_MT_EST_REQ, lchan2chan_nr(lchan),
+ link_id, 0);
msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg);
@@ -901,16 +720,16 @@ int rsl_establish_request(struct gsm_lchan *lchan, u_int8_t link_id)
lchan_free() */
int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id)
{
- struct msgb *msg = rsl_msgb_alloc();
- struct abis_rsl_rll_hdr *rh;
- rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh));
- init_llm_hdr(rh, RSL_MT_REL_REQ);
- //rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP;
- rh->chan_nr = lchan2chan_nr(lchan);
- rh->link_id = link_id;
+ struct msgb *msg;
+
+ msg = rsl_rll_simple(RSL_MT_REL_REQ, lchan2chan_nr(lchan),
+ link_id, 0);
msgb_tv_put(msg, RSL_IE_RELEASE_MODE, 0); /* normal release */
+ lchan->state = LCHAN_S_REL_REQ;
+ /* FIXME: start some timer in case we don't receive a REL ACK ? */
+
msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg);
@@ -926,6 +745,10 @@ static int rsl_rx_chan_act_ack(struct msgb *msg)
if (rslh->ie_chan != RSL_IE_CHAN_NR)
return -EINVAL;
+ 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),
+ gsm_lchans_name(msg->lchan->state));
msg->lchan->state = LCHAN_S_ACTIVE;
dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_ACK, msg->lchan);
@@ -939,16 +762,24 @@ 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",
+ gsm_lchan_name(msg->lchan));
+
/* BTS has rejected channel activation ?!? */
if (dh->ie_chan != RSL_IE_CHAN_NR)
return -EINVAL;
rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh));
- if (TLVP_PRESENT(&tp, RSL_IE_CAUSE))
- print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE),
+ if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) {
+ const u_int8_t *cause = TLVP_VAL(&tp, RSL_IE_CAUSE);
+ print_rsl_cause(LOGL_ERROR, cause,
TLVP_LEN(&tp, RSL_IE_CAUSE));
-
- msg->lchan->state = LCHAN_S_NONE;
+ if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC)
+ msg->lchan->state = LCHAN_S_NONE;
+ } else
+ msg->lchan->state = LCHAN_S_NONE;
+
+ LOGPC(DRSL, LOGL_ERROR, "\n");
dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_NACK, msg->lchan);
@@ -963,14 +794,16 @@ static int rsl_rx_conn_fail(struct msgb *msg)
struct tlv_parsed tp;
/* FIXME: print which channel */
- LOGP(DRSL, LOGL_NOTICE, "CONNECTION FAIL: RELEASING\n");
+ LOGP(DRSL, LOGL_NOTICE, "%s CONNECTION FAIL: RELEASING ",
+ gsm_lchan_name(msg->lchan));
rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh));
if (TLVP_PRESENT(&tp, RSL_IE_CAUSE))
- print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE),
+ print_rsl_cause(LOGL_NOTICE, TLVP_VAL(&tp, RSL_IE_CAUSE),
TLVP_LEN(&tp, RSL_IE_CAUSE));
+ LOGPC(DRSL, LOGL_NOTICE, "\n");
/* FIXME: only free it after channel release ACK */
return rsl_rf_chan_release(msg->lchan);
}
@@ -1020,8 +853,8 @@ static void print_meas_rep(struct gsm_meas_rep *mr)
return;
for (i = 0; i < mr->num_cell; i++) {
struct gsm_meas_rep_cell *mrc = &mr->cell[i];
- DEBUGP(DMEAS, "ARFCN=%u BSIC=%u => %d dBm\n", mrc->arfcn, mrc->bsic,
- rxlev2dbm(mrc->rxlev));
+ DEBUGP(DMEAS, "IDX=%u ARFCN=%u BSIC=%u => %d dBm\n",
+ mrc->neigh_idx, mrc->arfcn, mrc->bsic, rxlev2dbm(mrc->rxlev));
}
}
@@ -1036,8 +869,11 @@ static int rsl_rx_meas_res(struct msgb *msg)
/* check if this channel is actually active */
/* FIXME: maybe this check should be way more generic/centralized */
- if (msg->lchan->state != LCHAN_S_ACTIVE)
+ if (msg->lchan->state != LCHAN_S_ACTIVE) {
+ LOGP(DRSL, LOGL_NOTICE, "%s: MEAS RES for inactive channel\n",
+ gsm_lchan_name(msg->lchan));
return 0;
+ }
memset(mr, 0, sizeof(*mr));
mr->lchan = msg->lchan;
@@ -1098,7 +934,7 @@ static int rsl_rx_hando_det(struct msgb *msg)
struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);
struct tlv_parsed tp;
- DEBUGP(DRSL, "HANDOVER DETECT ");
+ DEBUGP(DRSL, "%s HANDOVER DETECT ", gsm_lchan_name(msg->lchan));
rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh));
@@ -1120,18 +956,14 @@ static int abis_rsl_rx_dchan(struct msgb *msg)
char *ts_name;
msg->lchan = lchan_lookup(msg->trx, rslh->chan_nr);
- ts_name = gsm_ts_name(msg->lchan->ts);
-
- if (rslh->c.msg_type != RSL_MT_MEAS_RES)
- DEBUGP(DRSL, "channel=%s chan_nr=0x%02x ", ts_name, rslh->chan_nr);
+ ts_name = gsm_lchan_name(msg->lchan);
switch (rslh->c.msg_type) {
case RSL_MT_CHAN_ACTIV_ACK:
- DEBUGPC(DRSL, "CHANNEL ACTIVATE ACK\n");
+ DEBUGP(DRSL, "%s CHANNEL ACTIVATE ACK\n", ts_name);
rc = rsl_rx_chan_act_ack(msg);
break;
case RSL_MT_CHAN_ACTIV_NACK:
- DEBUGPC(DRSL, "CHANNEL ACTIVATE NACK\n");
rc = rsl_rx_chan_act_nack(msg);
break;
case RSL_MT_CONN_FAIL:
@@ -1144,27 +976,31 @@ static int abis_rsl_rx_dchan(struct msgb *msg)
rc = rsl_rx_hando_det(msg);
break;
case RSL_MT_RF_CHAN_REL_ACK:
- DEBUGPC(DRSL, "RF CHANNEL RELEASE ACK\n");
+ DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", ts_name);
+ if (msg->lchan->state != LCHAN_S_REL_REQ)
+ LOGP(DRSL, LOGL_NOTICE, "%s CHAN REL ACK but state %s\n",
+ gsm_lchan_name(msg->lchan),
+ gsm_lchans_name(msg->lchan->state));
msg->lchan->state = LCHAN_S_NONE;
lchan_free(msg->lchan);
break;
case RSL_MT_MODE_MODIFY_ACK:
- DEBUGPC(DRSL, "CHANNEL MODE MODIFY ACK\n");
+ DEBUGP(DRSL, "%s CHANNEL MODE MODIFY ACK\n", ts_name);
break;
case RSL_MT_MODE_MODIFY_NACK:
- DEBUGPC(DRSL, "CHANNEL MODE MODIFY NACK\n");
+ LOGP(DRSL, LOGL_ERROR, "%s CHANNEL MODE MODIFY NACK\n", ts_name);
break;
case RSL_MT_IPAC_PDCH_ACT_ACK:
- DEBUGPC(DRSL, "IPAC PDCH ACT ACK\n");
+ DEBUGPC(DRSL, "%s IPAC PDCH ACT ACK\n", ts_name);
break;
case RSL_MT_IPAC_PDCH_ACT_NACK:
- DEBUGPC(DRSL, "IPAC PDCH ACT NACK\n");
+ LOGP(DRSL, LOGL_ERROR, "%s IPAC PDCH ACT NACK\n", ts_name);
break;
case RSL_MT_IPAC_PDCH_DEACT_ACK:
- DEBUGPC(DRSL, "IPAC PDCH DEACT ACK\n");
+ DEBUGP(DRSL, "%s IPAC PDCH DEACT ACK\n", ts_name);
break;
case RSL_MT_IPAC_PDCH_DEACT_NACK:
- DEBUGPC(DRSL, "IPAC PDCH DEACT NACK\n");
+ LOGP(DRSL, LOGL_ERROR, "%s IPAC PDCH DEACT NACK\n", ts_name);
break;
case RSL_MT_PHY_CONTEXT_CONF:
case RSL_MT_PREPROC_MEAS_RES:
@@ -1174,12 +1010,12 @@ static int abis_rsl_rx_dchan(struct msgb *msg)
case RSL_MT_MR_CODEC_MOD_ACK:
case RSL_MT_MR_CODEC_MOD_NACK:
case RSL_MT_MR_CODEC_MOD_PER:
- DEBUGPC(DRSL, "Unimplemented Abis RSL DChan msg 0x%02x\n",
- rslh->c.msg_type);
+ LOGP(DRSL, LOGL_NOTICE, "%s Unimplemented Abis RSL DChan "
+ "msg 0x%02x\n", ts_name, rslh->c.msg_type);
break;
default:
- DEBUGPC(DRSL, "unknown Abis RSL DChan msg 0x%02x\n",
- rslh->c.msg_type);
+ LOGP(DRSL, LOGL_NOTICE, "%s unknown Abis RSL DChan msg 0x%02x\n",
+ ts_name, rslh->c.msg_type);
return -EINVAL;
}
@@ -1191,12 +1027,12 @@ static int rsl_rx_error_rep(struct msgb *msg)
struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
struct tlv_parsed tp;
- LOGP(DRSL, LOGL_ERROR, "ERROR REPORT ");
+ LOGP(DRSL, LOGL_ERROR, "%s ERROR REPORT ", gsm_trx_name(msg->trx));
rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg)-sizeof(*rslh));
if (TLVP_PRESENT(&tp, RSL_IE_CAUSE))
- print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE),
+ print_rsl_cause(LOGL_ERROR, TLVP_VAL(&tp, RSL_IE_CAUSE),
TLVP_LEN(&tp, RSL_IE_CAUSE));
LOGPC(DRSL, LOGL_ERROR, "\n");
@@ -1215,15 +1051,16 @@ static int abis_rsl_rx_trx(struct msgb *msg)
break;
case RSL_MT_RF_RES_IND:
/* interference on idle channels of TRX */
- //DEBUGP(DRSL, "TRX: RF Interference Indication\n");
+ //DEBUGP(DRSL, "%s RF Resource Indication\n", gsm_trx_name(msg->trx));
break;
case RSL_MT_OVERLOAD:
/* indicate CCCH / ACCH / processor overload */
- LOGP(DRSL, LOGL_ERROR, "TRX: CCCH/ACCH/CPU Overload\n");
+ LOGP(DRSL, LOGL_ERROR, "%s CCCH/ACCH/CPU Overload\n",
+ gsm_trx_name(msg->trx));
break;
default:
- DEBUGP(DRSL, "Unknown Abis RSL TRX message type 0x%02x\n",
- rslh->msg_type);
+ LOGP(DRSL, LOGL_NOTICE, "%s Unknown Abis RSL TRX message "
+ "type 0x%02x\n", gsm_trx_name(msg->trx), rslh->msg_type);
return -EINVAL;
}
return rc;
@@ -1269,18 +1106,24 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
lctype = get_ctype_by_chreq(bts, rqd_ref->ra, bts->network->neci);
chreq_reason = get_reason_by_chreq(bts, rqd_ref->ra, bts->network->neci);
- bts->network->stats.chreq.total++;
+ counter_inc(bts->network->stats.chreq.total);
/* check availability / allocate channel */
lchan = lchan_alloc(bts, lctype);
if (!lchan) {
- DEBUGP(DRSL, "CHAN RQD: no resources for %s 0x%x\n",
- gsm_lchan_name(lctype), rqd_ref->ra);
- bts->network->stats.chreq.no_channel++;
+ LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n",
+ msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra);
+ counter_inc(bts->network->stats.chreq.no_channel);
/* FIXME: send some kind of reject ?!? */
return -ENOMEM;
}
+ if (lchan->state != LCHAN_S_NONE)
+ LOGP(DRSL, LOGL_NOTICE, "%s lchan_alloc() returned channel "
+ "in state %s\n", gsm_lchan_name(lchan),
+ gsm_lchans_name(lchan->state));
+ lchan->state = LCHAN_S_ACT_REQ;
+
ts_number = lchan->ts->nr;
arfcn = lchan->ts->trx->arfcn;
subch = lchan->nr;
@@ -1308,10 +1151,9 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
ia.timing_advance = rqd_ta;
ia.mob_alloc_len = 0;
- DEBUGP(DRSL, "Activating ARFCN(%u) TS(%u) SS(%u) lctype %s "
- "chan_nr=0x%02x r=%s ra=0x%02x\n",
- arfcn, ts_number, subch, gsm_lchan_name(lchan->type),
- ia.chan_desc.chan_nr, gsm_chreq_name(chreq_reason),
+ DEBUGP(DRSL, "%s Activating ARFCN(%u) SS(%u) lctype %s "
+ "r=%s ra=0x%02x\n", gsm_lchan_name(lchan), arfcn, subch,
+ gsm_lchant_name(lchan->type), gsm_chreq_name(chreq_reason),
rqd_ref->ra);
/* Start timer T3101 to wait for GSM48_MT_RR_PAG_RESP */
@@ -1390,10 +1232,12 @@ 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;
- LOGP(DRLL, LOGL_ERROR, "ERROR INDICATION cause=0x%02x\n", rlm_cause[1]);
+ LOGP(DRLL, LOGL_ERROR, "%s ERROR INDICATION cause=%s\n",
+ gsm_lchan_name(msg->lchan),
+ get_value_string(rsl_rlm_cause_strs, rlm_cause[1]));
rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND);
-
+
if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED)
return rsl_rf_chan_release(msg->lchan);
@@ -1414,9 +1258,8 @@ static int abis_rsl_rx_rll(struct msgb *msg)
u_int8_t sapi = rllh->link_id & 7;
msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr);
- ts_name = gsm_ts_name(msg->lchan->ts);
- DEBUGP(DRLL, "channel=%s chan_nr=0x%02x sapi=%u ", ts_name,
- rllh->chan_nr, sapi);
+ ts_name = gsm_lchan_name(msg->lchan);
+ DEBUGP(DRLL, "%s SAPI=%u ", ts_name, sapi);
switch (rllh->c.msg_type) {
case RSL_MT_DATA_IND:
@@ -1566,9 +1409,8 @@ int rsl_ipacc_crcx(struct gsm_lchan *lchan)
lchan->abis_ip.speech_mode = 0x10 | ipa_smod_s_for_lchan(lchan);
msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode);
- DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_BIND "
- "speech_mode=0x%02x\n", gsm_ts_name(lchan->ts),
- dh->chan_nr, lchan->abis_ip.speech_mode);
+ DEBUGP(DRSL, "%s IPAC_BIND speech_mode=0x%02x\n",
+ gsm_lchan_name(lchan), lchan->abis_ip.speech_mode);
msg->trx = lchan->ts->trx;
@@ -1597,9 +1439,8 @@ int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port,
lchan->abis_ip.speech_mode = 0x00 | ipa_smod_s_for_lchan(lchan);
ia.s_addr = htonl(ip);
- DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_MDCX "
- "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,
+ DEBUGP(DRSL, "%s IPAC_MDCX IP=%s PORT=%d RTP_PAYLOAD2=%d CONN_ID=%d "
+ "speech_mode=0x%02x\n", gsm_lchan_name(lchan), inet_ntoa(ia), port,
rtp_payload2, lchan->abis_ip.conn_id, lchan->abis_ip.speech_mode);
msgb_tv16_put(msg, RSL_IE_IPAC_CONN_ID, lchan->abis_ip.conn_id);
@@ -1640,8 +1481,7 @@ int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan)
dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN;
dh->chan_nr = lchan2chan_nr(lchan);
- DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_PDCH_ACT\n",
- gsm_ts_name(lchan->ts), dh->chan_nr);
+ DEBUGP(DRSL, "%s IPAC_PDCH_ACT\n", gsm_lchan_name(lchan));
msg->trx = lchan->ts->trx;
@@ -1722,7 +1562,7 @@ static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg)
rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh));
if (TLVP_PRESENT(&tv, RSL_IE_CAUSE))
- print_rsl_cause(TLVP_VAL(&tv, RSL_IE_CAUSE),
+ print_rsl_cause(LOGL_DEBUG, TLVP_VAL(&tv, RSL_IE_CAUSE),
TLVP_LEN(&tv, RSL_IE_CAUSE));
/* the BTS tells us a RTP stream has been disconnected */
@@ -1739,38 +1579,38 @@ static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg)
static int abis_rsl_rx_ipacc(struct msgb *msg)
{
struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
+ char *ts_name;
int rc = 0;
msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr);
- DEBUGP(DRSL, "channel=%s chan_nr=0x%02x ",
- gsm_ts_name(msg->lchan->ts), rllh->chan_nr);
+ ts_name = gsm_lchan_name(msg->lchan);
switch (rllh->c.msg_type) {
case RSL_MT_IPAC_CRCX_ACK:
- DEBUGPC(DRSL, "IPAC_CRCX_ACK ");
+ DEBUGP(DRSL, "%s IPAC_CRCX_ACK ", ts_name);
rc = abis_rsl_rx_ipacc_crcx_ack(msg);
break;
case RSL_MT_IPAC_CRCX_NACK:
/* somehow the BTS was unable to bind the lchan to its local
* port?!? */
- DEBUGPC(DRSL, "IPAC_CRCX_NACK ");
+ LOGP(DRSL, LOGL_ERROR, "%s IPAC_CRCX_NACK\n", ts_name);
break;
case RSL_MT_IPAC_MDCX_ACK:
/* the BTS tells us that a connect operation was successful */
- DEBUGPC(DRSL, "IPAC_MDCX_ACK ");
+ DEBUGP(DRSL, "%s IPAC_MDCX_ACK ", ts_name);
rc = abis_rsl_rx_ipacc_mdcx_ack(msg);
break;
case RSL_MT_IPAC_MDCX_NACK:
/* somehow the BTS was unable to connect the lchan to a remote
* port */
- DEBUGPC(DRSL, "IPAC_MDCX_NACK ");
+ LOGP(DRSL, LOGL_ERROR, "%s IPAC_MDCX_NACK\n", ts_name);
break;
case RSL_MT_IPAC_DLCX_IND:
- DEBUGPC(DRSL, "IPAC_DLCX_IND ");
+ DEBUGP(DRSL, "%s IPAC_DLCX_IND ", ts_name);
rc = abis_rsl_rx_ipacc_dlcx_ind(msg);
break;
default:
- LOGP(DRSL, LOGL_NOTICE, "Unknown ip.access msg_type 0x%02x",
+ LOGP(DRSL, LOGL_NOTICE, "Unknown ip.access msg_type 0x%02x\n",
rllh->c.msg_type);
break;
}
@@ -1827,45 +1667,6 @@ int abis_rsl_rcvmsg(struct msgb *msg)
return rc;
}
-
-/* Section 3.3.2.3 TS 05.02. I think this looks like a table */
-int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf)
-{
- switch (ccch_conf) {
- case RSL_BCCH_CCCH_CONF_1_NC:
- return 1;
- case RSL_BCCH_CCCH_CONF_1_C:
- return 1;
- case RSL_BCCH_CCCH_CONF_2_NC:
- return 2;
- case RSL_BCCH_CCCH_CONF_3_NC:
- return 3;
- case RSL_BCCH_CCCH_CONF_4_NC:
- return 4;
- default:
- return -1;
- }
-}
-
-/* Section 3.3.2.3 TS 05.02 */
-int rsl_ccch_conf_to_bs_ccch_sdcch_comb(int ccch_conf)
-{
- switch (ccch_conf) {
- case RSL_BCCH_CCCH_CONF_1_NC:
- return 0;
- case RSL_BCCH_CCCH_CONF_1_C:
- return 1;
- case RSL_BCCH_CCCH_CONF_2_NC:
- return 0;
- case RSL_BCCH_CCCH_CONF_3_NC:
- return 0;
- case RSL_BCCH_CCCH_CONF_4_NC:
- return 0;
- default:
- return -1;
- }
-}
-
/* From Table 10.5.33 of GSM 04.08 */
int rsl_number_of_paging_subchannels(struct gsm_bts *bts)
{
diff --git a/openbsc/src/bitvec.c b/openbsc/src/bitvec.c
deleted file mode 100644
index d6f5679cf..000000000
--- a/openbsc/src/bitvec.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/* bit vector utility routines */
-
-/* (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 <sys/types.h>
-
-#include <openbsc/bitvec.h>
-
-#define BITNUM_FROM_COMP(byte, bit) ((byte*8)+bit)
-
-static inline unsigned int bytenum_from_bitnum(unsigned int bitnum)
-{
- unsigned int bytenum = bitnum / 8;
-
- return bytenum;
-}
-
-/* convert ZERO/ONE/L/H to a bitmask at given pos in a byte */
-static u_int8_t bitval2mask(enum bit_value bit, u_int8_t bitnum)
-{
- int bitval;
-
- switch (bit) {
- case ZERO:
- bitval = (0 << bitnum);
- break;
- case ONE:
- bitval = (1 << bitnum);
- break;
- case L:
- bitval = ((0x2b ^ (0 << bitnum)) & (1 << bitnum));
- break;
- case H:
- bitval = ((0x2b ^ (1 << bitnum)) & (1 << bitnum));
- break;
- default:
- return 0;
- }
- return bitval;
-}
-
-/* check if the bit is 0 or 1 for a given position inside a bitvec */
-enum bit_value bitvec_get_bit_pos(struct bitvec *bv, unsigned int bitnr)
-{
- unsigned int bytenum = bytenum_from_bitnum(bitnr);
- unsigned int bitnum = 7 - (bitnr % 8);
- u_int8_t bitval;
-
- if (bytenum >= bv->data_len)
- return -EINVAL;
-
- bitval = bitval2mask(ONE, bitnum);
-
- if (bv->data[bytenum] & bitval)
- return ONE;
-
- return ZERO;
-}
-
-/* get the Nth set bit inside the bit vector */
-unsigned int bitvec_get_nth_set_bit(struct bitvec *bv, unsigned int n)
-{
- unsigned int i, k = 0;
-
- for (i = 0; i < bv->data_len*8; i++) {
- if (bitvec_get_bit_pos(bv, i) == ONE) {
- k++;
- if (k == n)
- return i;
- }
- }
-
- return 0;
-}
-
-/* set the bit at a given position inside a bitvec */
-int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr,
- enum bit_value bit)
-{
- unsigned int bytenum = bytenum_from_bitnum(bitnr);
- unsigned int bitnum = 7 - (bitnr % 8);
- u_int8_t bitval;
-
- if (bytenum >= bv->data_len)
- return -EINVAL;
-
- /* first clear the bit */
- bitval = bitval2mask(ONE, bitnum);
- bv->data[bytenum] &= ~bitval;
-
- /* then set it to desired value */
- bitval = bitval2mask(bit, bitnum);
- bv->data[bytenum] |= bitval;
-
- return 0;
-}
-
-/* set the next bit inside a bitvec */
-int bitvec_set_bit(struct bitvec *bv, enum bit_value bit)
-{
- int rc;
-
- rc = bitvec_set_bit_pos(bv, bv->cur_bit, bit);
- if (!rc)
- bv->cur_bit++;
-
- return rc;
-}
-
-/* set multiple bits (based on array of bitvals) at current pos */
-int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count)
-{
- int i, rc;
-
- for (i = 0; i < count; i++) {
- rc = bitvec_set_bit(bv, bits[i]);
- if (rc)
- return rc;
- }
-
- return 0;
-}
-
-/* set multiple bits (based on numeric value) at current pos */
-int bitvec_set_uint(struct bitvec *bv, unsigned int ui, int num_bits)
-{
- int i, rc;
-
- for (i = 0; i < num_bits; i++) {
- int bit = 0;
- if (ui & (1 << (num_bits - i - 1)))
- bit = 1;
- rc = bitvec_set_bit(bv, bit);
- if (rc)
- return rc;
- }
-
- return 0;
-}
-
-/* pad all remaining bits up to num_bits */
-int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit)
-{
- unsigned int i;
-
- for (i = bv->cur_bit; i <= up_to_bit; i++)
- bitvec_set_bit(bv, L);
-
- return 0;
-}
diff --git a/openbsc/src/bs11_config.c b/openbsc/src/bs11_config.c
index 3e8bf88a3..80f9ba956 100644
--- a/openbsc/src/bs11_config.c
+++ b/openbsc/src/bs11_config.c
@@ -36,10 +36,10 @@
#include <openbsc/gsm_data.h>
#include <openbsc/abis_nm.h>
-#include <openbsc/msgb.h>
-#include <openbsc/tlv.h>
+#include <osmocore/msgb.h>
+#include <osmocore/tlv.h>
#include <openbsc/debug.h>
-#include <openbsc/select.h>
+#include <osmocore/select.h>
#include <openbsc/rs232.h>
/* state of our bs11_config application */
@@ -51,7 +51,7 @@ enum bs11cfg_state {
STATE_QUERY,
};
static enum bs11cfg_state bs11cfg_state = STATE_NONE;
-static char *command;
+static char *command, *value;
struct timer_list status_timer;
static const u_int8_t obj_li_attr[] = {
@@ -71,6 +71,13 @@ static const char *trx1_password = "1111111111";
static const u_int8_t too_fast[] = { 0x12, 0x80, 0x00, 0x00, 0x02, 0x02 };
+static struct debug_target *stderr_target;
+
+/* dummy function to keep gsm_data.c happy */
+struct counter *counter_alloc(const char *name)
+{
+ return NULL;
+}
int handle_serial_msg(struct msgb *rx_msg);
@@ -533,6 +540,21 @@ static int handle_state_resp(enum abis_bs11_phase state)
sleep(1);
abis_nm_bs11_factory_logon(g_bts, 0);
command = NULL;
+ } else if (!strcmp(command, "pll-setvalue")) {
+ abis_nm_bs11_set_pll(g_bts, atoi(value));
+ sleep(1);
+ abis_nm_bs11_factory_logon(g_bts, 0);
+ command = NULL;
+ } else if (!strcmp(command, "pll-workvalue")) {
+ /* To set the work value we need to login as FIELD */
+ abis_nm_bs11_factory_logon(g_bts, 0);
+ sleep(1);
+ abis_nm_bs11_infield_logon(g_bts, 1);
+ sleep(1);
+ abis_nm_bs11_set_pll(g_bts, atoi(value));
+ sleep(1);
+ abis_nm_bs11_infield_logon(g_bts, 0);
+ command = NULL;
} else if (!strcmp(command, "oml-tei")) {
abis_nm_bs11_conn_oml_tei(g_bts, 0, 1, 0xff, TEI_OML);
command = NULL;
@@ -627,7 +649,7 @@ int handle_serial_msg(struct msgb *rx_msg)
exit(0);
break;
case NM_MT_BS11_GET_STATE_ACK:
- rc = abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+ rc = abis_nm_tlv_parse(&tp, g_bts, foh->data, oh->length-sizeof(*foh));
print_state(&tp);
if (TLVP_PRESENT(&tp, NM_ATT_BS11_BTS_STATE) &&
TLVP_LEN(&tp, NM_ATT_BS11_BTS_STATE) >= 1)
@@ -635,7 +657,7 @@ int handle_serial_msg(struct msgb *rx_msg)
break;
case NM_MT_GET_ATTR_RESP:
printf("\n%sATTRIBUTES:\n", obj_name(foh));
- abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
+ abis_nm_tlv_parse(&tp, g_bts, foh->data, oh->length-sizeof(*foh));
rc = print_attr(&tp);
//hexdump(foh->data, oh->length-sizeof(*foh));
break;
@@ -699,25 +721,27 @@ static void print_help(void)
printf("\t-p --port </dev/ttyXXX>\t\tSpecify serial port\n");
printf("\t-s --software <file>\t\tSpecify Software file\n");
printf("\t-S --safety <file>\t\tSpecify Safety Load file\n");
- printf("\t-d --delay <ms>\t\tSpecify delay in milliseconds\n");
+ printf("\t-d --delay <ms>\t\t\tSpecify delay in milliseconds\n");
printf("\t-D --disconnect\t\t\tDisconnect BTS from BSC\n");
printf("\t-w --win-size <num>\t\tSpecify Window Size\n");
printf("\t-f --forced\t\t\tForce Software Load\n");
printf("\nSupported commands:\n");
- printf("\tquery\t\tQuery the BS-11 about serial number and configuration\n");
- printf("\tdisconnect\tDisconnect A-bis link (go into administrative state)\n");
- printf("\tresconnect\tReconnect A-bis link (go into normal state)\n");
- printf("\trestart\t\tRestart the BTS\n");
- printf("\tsoftware\tDownload Software (only in administrative state)\n");
- printf("\tcreate-trx1\tCreate objects for TRX1 (Danger: Your BS-11 might overheat)\n");
- printf("\tdelete-trx1\tDelete objects for TRX1\n");
- printf("\tpll-e1-locked\tSet the PLL to be locked to E1 clock\n");
- printf("\tpll-standalone\tSet the PLL to be in standalone mode\n");
- printf("\toml-tei\tSet OML E1 TS and TEI\n");
- printf("\tbport0-star\tSet BPORT0 line config to star\n");
+ printf("\tquery\t\t\tQuery the BS-11 about serial number and configuration\n");
+ printf("\tdisconnect\t\tDisconnect A-bis link (go into administrative state)\n");
+ printf("\tresconnect\t\tReconnect A-bis link (go into normal state)\n");
+ printf("\trestart\t\t\tRestart the BTS\n");
+ printf("\tsoftware\t\tDownload Software (only in administrative state)\n");
+ printf("\tcreate-trx1\t\tCreate objects for TRX1 (Danger: Your BS-11 might overheat)\n");
+ printf("\tdelete-trx1\t\tDelete objects for TRX1\n");
+ printf("\tpll-e1-locked\t\tSet the PLL to be locked to E1 clock\n");
+ printf("\tpll-standalone\t\tSet the PLL to be in standalone mode\n");
+ printf("\tpll-setvalue <value>\tSet the PLL set value\n");
+ printf("\tpll-workvalue <value>\tSet the PLL work value\n");
+ printf("\toml-tei\t\t\tSet OML E1 TS and TEI\n");
+ printf("\tbport0-star\t\tSet BPORT0 line config to star\n");
printf("\tbport0-multiport\tSet BPORT0 line config to multiport\n");
- printf("\tcreate-bport1\tCreate BPORT1 object\n");
- printf("\tdelete-bport1\tDelete BPORT1 object\n");
+ printf("\tcreate-bport1\t\tCreate BPORT1 object\n");
+ printf("\tdelete-bport1\t\tDelete BPORT1 object\n");
}
static void handle_options(int argc, char **argv)
@@ -754,7 +778,7 @@ static void handle_options(int argc, char **argv)
serial_port = optarg;
break;
case 'b':
- debug_parse_category_mask(optarg);
+ debug_parse_category_mask(stderr_target, optarg);
break;
case 's':
fname_software = optarg;
@@ -784,6 +808,9 @@ static void handle_options(int argc, char **argv)
}
if (optind < argc)
command = argv[optind];
+ if (optind+1 < argc)
+ value = argv[optind+1];
+
}
static int num_sigint;
@@ -807,7 +834,12 @@ int main(int argc, char **argv)
struct gsm_network *gsmnet;
int rc;
+ debug_init();
+ stderr_target = debug_target_create_stderr();
+ debug_add_target(stderr_target);
+ debug_set_all_filter(stderr_target, 1);
handle_options(argc, argv);
+ bts_model_bs11_init();
gsmnet = gsm_network_init(1, 1, NULL);
if (!gsmnet) {
diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c
index a9a5d372f..49c9d36ef 100644
--- a/openbsc/src/bsc_hack.c
+++ b/openbsc/src/bsc_hack.c
@@ -1,6 +1,6 @@
/* A hackish minimal BSC (+MSC +HLR) implementation */
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
+/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
@@ -31,17 +31,23 @@
#include <getopt.h>
#include <openbsc/db.h>
-#include <openbsc/select.h>
+#include <osmocore/select.h>
#include <openbsc/debug.h>
#include <openbsc/e1_input.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/signal.h>
/* MCC and MNC for the Location Area Identifier */
+static struct debug_target *stderr_target;
struct gsm_network *bsc_gsmnet = 0;
static const char *database_name = "hlr.sqlite3";
static const char *config_file = "openbsc.cfg";
+
+/* timer to store statistics */
+#define DB_SYNC_INTERVAL 60, 0
+static struct timer_list db_sync_timer;
+
extern int bsc_bootstrap_network(int (*mmc_rev)(struct gsm_network *, int, void *),
const char *cfg_file);
extern int bsc_shutdown_net(struct gsm_network *net);
@@ -105,10 +111,10 @@ static void handle_options(int argc, char** argv)
print_help();
exit(0);
case 's':
- debug_use_color(0);
+ debug_set_use_color(stderr_target, 0);
break;
case 'd':
- debug_parse_category_mask(optarg);
+ debug_parse_category_mask(stderr_target, optarg);
break;
case 'l':
database_name = strdup(optarg);
@@ -120,7 +126,7 @@ static void handle_options(int argc, char** argv)
create_pcap_file(optarg);
break;
case 'T':
- debug_timestamp(1);
+ debug_set_print_timestamp(stderr_target, 1);
break;
case 'P':
ipacc_rtp_direct = 0;
@@ -132,6 +138,7 @@ static void handle_options(int argc, char** argv)
}
}
+extern void *tall_vty_ctx;
static void signal_handler(int signal)
{
fprintf(stdout, "signal %u received\n", signal);
@@ -147,22 +154,53 @@ static void signal_handler(int signal)
/* in case of abort, we want to obtain a talloc report
* and then return to the caller, who will abort the process */
case SIGUSR1:
+ talloc_report(tall_vty_ctx, stderr);
talloc_report_full(tall_bsc_ctx, stderr);
break;
+ case SIGUSR2:
+ talloc_report_full(tall_vty_ctx, stderr);
+ break;
default:
break;
}
}
+/* timer handling */
+static int _db_store_counter(struct counter *counter, void *data)
+{
+ return db_store_counter(counter);
+}
+
+static void db_sync_timer_cb(void *data)
+{
+ /* store counters to database and re-schedule */
+ counters_for_each(_db_store_counter, NULL);
+ bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL);
+}
+
+extern int bts_model_unknown_init(void);
+extern int bts_model_bs11_init(void);
+extern int bts_model_nanobts_init(void);
+
int main(int argc, char **argv)
{
int rc;
+ debug_init();
tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
talloc_ctx_init();
on_dso_load_token();
on_dso_load_rrlp();
on_dso_load_ho_dec();
+ stderr_target = debug_target_create_stderr();
+ debug_add_target(stderr_target);
+
+ bts_model_unknown_init();
+ bts_model_bs11_init();
+ bts_model_nanobts_init();
+
+ /* enable filters */
+ debug_set_all_filter(stderr_target, 1);
/* parse options */
handle_options(argc, argv);
@@ -182,6 +220,11 @@ int main(int argc, char **argv)
}
printf("DB: Database prepared.\n");
+ /* setup the timer */
+ db_sync_timer.cb = db_sync_timer_cb;
+ db_sync_timer.data = NULL;
+ bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL);
+
rc = bsc_bootstrap_network(mncc_recv, config_file);
if (rc < 0)
exit(1);
@@ -189,10 +232,12 @@ int main(int argc, char **argv)
signal(SIGINT, &signal_handler);
signal(SIGABRT, &signal_handler);
signal(SIGUSR1, &signal_handler);
+ signal(SIGUSR2, &signal_handler);
signal(SIGPIPE, SIG_IGN);
while (1) {
bsc_upqueue(bsc_gsmnet);
+ debug_reset_context();
bsc_select_main(0);
}
}
diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c
index c87750d77..ecf0f03cd 100644
--- a/openbsc/src/bsc_init.c
+++ b/openbsc/src/bsc_init.c
@@ -21,7 +21,7 @@
*/
#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_utils.h>
+#include <osmocore/gsm_utils.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/abis_nm.h>
@@ -31,7 +31,7 @@
#include <openbsc/system_information.h>
#include <openbsc/paging.h>
#include <openbsc/signal.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
/* global pointer to the gsm network data structure */
extern struct gsm_network *bsc_gsmnet;
@@ -355,11 +355,11 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
switch (obj_class) {
case NM_OC_SITE_MANAGER:
bts = container_of(obj, struct gsm_bts, site_mgr);
- if (new_state->operational == 2 &&
- new_state->availability == NM_AVSTATE_OK) {
- printf("STARTING SITE MANAGER\n");
+ if ((new_state->operational == 2 &&
+ new_state->availability == NM_AVSTATE_OK) ||
+ (new_state->operational == 1 &&
+ new_state->availability == NM_AVSTATE_OFF_LINE))
abis_nm_opstart(bts, obj_class, 0xff, 0xff, 0xff);
- }
break;
case NM_OC_BTS:
bts = obj;
@@ -412,6 +412,8 @@ static int sw_activ_rep(struct msgb *mb)
struct gsm_bts *bts = mb->trx->bts;
struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr);
+ if (!trx)
+ return -EINVAL;
switch (foh->obj_class) {
case NM_OC_BASEB_TRANSC:
@@ -433,8 +435,7 @@ static int sw_activ_rep(struct msgb *mb)
* This code is here to make sure that on start
* a TRX remains locked.
*/
- int rc_state = trx->rf_locked ?
- NM_STATE_LOCKED : NM_STATE_UNLOCKED;
+ int rc_state = trx->nm_state.administrative;
/* Patch ARFCN into radio attribute */
nanobts_attr_radio[5] &= 0xf0;
nanobts_attr_radio[5] |= trx->arfcn >> 8;
@@ -691,7 +692,7 @@ static int set_system_infos(struct gsm_bts_trx *trx)
rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp));
}
#ifdef GPRS
- i = 13
+ i = 13;
rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13);
if (rc < 0)
goto err_out;
@@ -756,9 +757,10 @@ static void patch_nm_tables(struct gsm_bts *bts)
static void bootstrap_rsl(struct gsm_bts_trx *trx)
{
LOGP(DRSL, LOGL_NOTICE, "bootstrapping RSL for BTS/TRX (%u/%u) "
- "using MCC=%u MNC=%u BSIC=%u TSC=%u\n",
- trx->bts->nr, trx->nr, bsc_gsmnet->country_code,
- bsc_gsmnet->network_code, trx->bts->bsic, trx->bts->tsc);
+ "on ARFCN %u using MCC=%u MNC=%u LAC=%u CID=%u BSIC=%u TSC=%u\n",
+ 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);
set_system_infos(trx);
}
@@ -829,11 +831,6 @@ static int bootstrap_bts(struct gsm_bts *bts)
/* T3212 is set from vty/config */
/* some defaults for our system information */
- bts->si_common.rach_control.re = 1; /* no re-establishment */
- bts->si_common.rach_control.tx_integer = 5; /* 8 slots spread */
- bts->si_common.rach_control.max_trans = 3; /* 7 retransmissions */
- bts->si_common.rach_control.t2 = 4; /* no emergency calls */
-
bts->si_common.cell_options.radio_link_timeout = 2; /* 12 */
bts->si_common.cell_options.dtx = 2; /* MS shall not use upplink DTX */
bts->si_common.cell_options.pwrc = 0; /* PWRC not set */
diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c
deleted file mode 100644
index d25edc884..000000000
--- a/openbsc/src/bsc_mgcp.c
+++ /dev/null
@@ -1,1237 +0,0 @@
-/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
-
-/*
- * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009 by on-waves.com
- * 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 <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <limits.h>
-#include <unistd.h>
-
-#include <sys/socket.h>
-#include <arpa/inet.h>
-
-#include <openbsc/debug.h>
-#include <openbsc/msgb.h>
-#include <openbsc/talloc.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/select.h>
-#include <openbsc/mgcp.h>
-#include <openbsc/telnet_interface.h>
-
-#include <vty/command.h>
-#include <vty/vty.h>
-
-/* this is here for the vty... it will never be called */
-void subscr_put() { abort(); }
-
-#define _GNU_SOURCE
-#include <getopt.h>
-
-#warning "Make use of the rtp proxy code"
-
-static int source_port = 2427;
-static const char *local_ip = NULL;
-static const char *source_addr = "0.0.0.0";
-static struct bsc_fd bfd;
-static unsigned int number_endpoints = 0;
-static const char *bts_ip = NULL;
-static struct in_addr bts_in;
-static int first_request = 1;
-static const char *audio_name = "GSM-EFR/8000";
-static int audio_payload = 97;
-static int audio_loop = 0;
-static int early_bind = 0;
-static int rtp_base_port = 4000;
-
-static char *forward_ip = NULL;
-static int forward_port = 0;
-static char *config_file = "mgcp.cfg";
-
-/* used by msgb and mgcp */
-void *tall_bsc_ctx = NULL;
-
-enum mgcp_connection_mode {
- MGCP_CONN_NONE = 0,
- MGCP_CONN_RECV_ONLY = 1,
- MGCP_CONN_SEND_ONLY = 2,
- MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
-};
-
-enum {
- DEST_NETWORK = 0,
- DEST_BTS = 1,
-};
-
-enum {
- PROTO_RTP,
- PROTO_RTCP,
-};
-
-#define CI_UNUSED 0
-static unsigned int last_call_id = 0;
-
-struct mgcp_endpoint {
- int ci;
- char *callid;
- char *local_options;
- int conn_mode;
-
- /* the local rtp port we are binding to */
- int rtp_port;
-
- /*
- * RTP mangling:
- * - we get RTP and RTCP to us and need to forward to the BTS
- * - we get RTP and RTCP from the BTS and forward to the network
- */
- struct bsc_fd local_rtp;
- struct bsc_fd local_rtcp;
-
- struct in_addr remote;
- struct in_addr bts;
-
- /* in network byte order */
- int net_rtp, net_rtcp;
- int bts_rtp, bts_rtcp;
-};
-
-static struct mgcp_endpoint *endpoints = NULL;
-#define ENDPOINT_NUMBER(endp) abs(endp - endpoints)
-
-/**
- * Macro for tokenizing MGCP messages and SDP in one go.
- *
- */
-#define MSG_TOKENIZE_START \
- line_start = 0; \
- for (i = 0; i < msgb_l3len(msg); ++i) { \
- /* we have a line end */ \
- if (msg->l3h[i] == '\n') { \
- /* skip the first line */ \
- if (line_start == 0) { \
- line_start = i + 1; \
- continue; \
- } \
- \
- /* check if we have a proper param */ \
- if (i - line_start == 1 && msg->l3h[line_start] == '\r') { \
- } else if (i - line_start > 2 \
- && islower(msg->l3h[line_start]) \
- && msg->l3h[line_start + 1] == '=') { \
- } else if (i - line_start < 3 \
- || msg->l3h[line_start + 1] != ':' \
- || msg->l3h[line_start + 2] != ' ') \
- goto error; \
- \
- msg->l3h[i] = '\0'; \
- if (msg->l3h[i-1] == '\r') \
- msg->l3h[i-1] = '\0';
-
-#define MSG_TOKENIZE_END \
- line_start = i + 1; \
- } \
- }
-
-
-struct mgcp_msg_ptr {
- unsigned int start;
- unsigned int length;
-};
-
-struct mgcp_request {
- char *name;
- void (*handle_request) (struct msgb *msg, struct sockaddr_in *source);
- char *debug_name;
-};
-
-#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
- { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
-
-static void handle_audit_endpoint(struct msgb *msg, struct sockaddr_in *source);
-static void handle_create_con(struct msgb *msg, struct sockaddr_in *source);
-static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source);
-static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source);
-
-static int generate_call_id()
-{
- int i;
-
- /* use the call id */
- ++last_call_id;
-
- /* handle wrap around */
- if (last_call_id == CI_UNUSED)
- ++last_call_id;
-
- /* callstack can only be of size number_of_endpoints */
- /* verify that the call id is free, e.g. in case of overrun */
- for (i = 1; i < number_endpoints; ++i)
- if (endpoints[i].ci == last_call_id)
- return generate_call_id();
-
- return last_call_id;
-}
-
-/* FIXIME/TODO: need to have a list of pending transactions and check that */
-static unsigned int generate_transaction_id()
-{
- return abs(rand());
-}
-
-static int _send(int fd, struct in_addr *addr, int port, char *buf, int len)
-{
- struct sockaddr_in out;
- out.sin_family = AF_INET;
- out.sin_port = port;
- memcpy(&out.sin_addr, addr, sizeof(*addr));
-
- return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
-}
-
-/*
- * There is data coming. We will have to figure out if it
- * came from the BTS or the MediaGateway of the MSC. On top
- * of that we need to figure out if it was RTP or RTCP.
- *
- * Currently we do not communicate with the BSC so we have
- * no idea where the BTS is listening for RTP and need to
- * do the classic routing trick. Wait for the first packet
- * from the BTS and then go ahead.
- */
-static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
-{
- char buf[4096];
- struct sockaddr_in addr;
- socklen_t slen = sizeof(addr);
- struct mgcp_endpoint *endp;
- int rc, dest, proto;
-
- endp = (struct mgcp_endpoint *) fd->data;
-
- rc = recvfrom(fd->fd, &buf, sizeof(buf), 0,
- (struct sockaddr *) &addr, &slen);
- if (rc < 0) {
- DEBUGP(DMGCP, "Failed to receive message on: 0x%x\n",
- ENDPOINT_NUMBER(endp));
- return -1;
- }
-
- /* do not forward aynthing... maybe there is a packet from the bts */
- if (endp->ci == CI_UNUSED) {
- DEBUGP(DMGCP, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp));
- return -1;
- }
-
- /*
- * Figure out where to forward it to. This code assumes that we
- * have received the Connection Modify and know who is a legitimate
- * partner. According to the spec we could attempt to forward even
- * after the Create Connection but we will not as we are not really
- * able to tell if this is legitimate.
- */
- #warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
- dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 &&
- (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port)
- ? DEST_BTS : DEST_NETWORK;
- proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
-
- /* We have no idea who called us, maybe it is the BTS. */
- if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || forward_ip)) {
- /* it was the BTS... */
- if (!bts_ip || memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) {
- if (fd == &endp->local_rtp) {
- endp->bts_rtp = addr.sin_port;
- } else {
- endp->bts_rtcp = addr.sin_port;
- }
-
- endp->bts = addr.sin_addr;
- DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d/%d\n",
- ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp));
- }
- }
-
- /* dispatch */
- if (audio_loop)
- dest = !dest;
-
- if (dest == DEST_NETWORK) {
- return _send(fd->fd, &endp->remote,
- proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp,
- buf, rc);
- } else {
- return _send(fd->fd, &endp->bts,
- proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp,
- buf, rc);
- }
-}
-
-static int create_bind(struct bsc_fd *fd, int port)
-{
- struct sockaddr_in addr;
- int on = 1;
-
- fd->fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (fd->fd < 0)
- return -1;
-
- setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- inet_aton(source_addr, &addr.sin_addr);
-
- if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
- return -1;
-
- return 0;
-}
-
-static int bind_rtp(struct mgcp_endpoint *endp)
-{
- if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) {
- DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n",
- endp->rtp_port, ENDPOINT_NUMBER(endp));
- goto cleanup0;
- }
-
- if (create_bind(&endp->local_rtcp, endp->rtp_port + 1) != 0) {
- DEBUGP(DMGCP, "Failed to create RTCP port: %d on 0x%x\n",
- endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
- goto cleanup1;
- }
-
- endp->local_rtp.cb = rtp_data_cb;
- endp->local_rtp.data = endp;
- endp->local_rtp.when = BSC_FD_READ;
- if (bsc_register_fd(&endp->local_rtp) != 0) {
- DEBUGP(DMGCP, "Failed to register RTP port %d on 0x%x\n",
- endp->rtp_port, ENDPOINT_NUMBER(endp));
- goto cleanup2;
- }
-
- endp->local_rtcp.cb = rtp_data_cb;
- endp->local_rtcp.data = endp;
- endp->local_rtcp.when = BSC_FD_READ;
- if (bsc_register_fd(&endp->local_rtcp) != 0) {
- DEBUGP(DMGCP, "Failed to register RTCP port %d on 0x%x\n",
- endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
- goto cleanup3;
- }
-
- return 0;
-
-cleanup3:
- bsc_unregister_fd(&endp->local_rtp);
-cleanup2:
- close(endp->local_rtcp.fd);
- endp->local_rtcp.fd = -1;
-cleanup1:
- close(endp->local_rtp.fd);
- endp->local_rtp.fd = -1;
-cleanup0:
- return -1;
-}
-
-/*
- * array of function pointers for handling various
- * messages. In the future this might be binary sorted
- * for performance reasons.
- */
-static const struct mgcp_request mgcp_requests [] = {
- MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
- MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
- MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
- MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
-};
-
-static void send_response_with_data(int code, const char *msg, const char *trans,
- const char *data, struct sockaddr_in *source)
-{
- char buf[4096];
- int len;
-
- if (data) {
- len = snprintf(buf, sizeof(buf), "%d %s\n%s", code, trans, data);
- } else {
- len = snprintf(buf, sizeof(buf), "%d %s\n", code, trans);
- }
- DEBUGP(DMGCP, "Sending response: code: %d for '%s'\n", code, msg);
-
- sendto(bfd.fd, buf, len, 0, (struct sockaddr *)source, sizeof(*source));
-}
-
-static void send_response(int code, const char *msg, const char *trans, struct sockaddr_in *source)
-{
- send_response_with_data(code, msg, trans, NULL, source);
-}
-
-static void send_with_sdp(struct mgcp_endpoint *endp, const char *msg, const char *trans_id, struct sockaddr_in *source)
-{
- const char *addr = local_ip;
- char sdp_record[4096];
-
- if (!addr)
- addr = source_addr;
-
- snprintf(sdp_record, sizeof(sdp_record) - 1,
- "I: %d\n\n"
- "v=0\r\n"
- "c=IN IP4 %s\r\n"
- "m=audio %d RTP/AVP %d\r\n"
- "a=rtpmap:%d %s\r\n",
- endp->ci, addr, endp->rtp_port,
- audio_payload, audio_payload, audio_name);
- return send_response_with_data(200, msg, trans_id, sdp_record, source);
-}
-
-/* send a static record */
-static void send_rsip(struct sockaddr_in *source)
-{
- char reset[4096];
- int len, rc;
-
- len = snprintf(reset, sizeof(reset) - 1,
- "RSIP %u *@mgw MGCP 1.0\n"
- "RM: restart\n", generate_transaction_id());
- rc = sendto(bfd.fd, reset, len, 0, (struct sockaddr *) source, sizeof(*source));
- if (rc < 0) {
- DEBUGP(DMGCP, "Failed to send RSIP: %d\n", rc);
- }
-}
-
-/*
- * handle incoming messages:
- * - this can be a command (four letters, space, transaction id)
- * - or a response (three numbers, space, transaction id)
- */
-static void handle_message(struct msgb *msg, struct sockaddr_in *source)
-{
- int code;
-
- if (msg->len < 4) {
- DEBUGP(DMGCP, "mgs too short: %d\n", msg->len);
- return;
- }
-
- /* attempt to treat it as a response */
- if (sscanf((const char *)&msg->data[0], "%3d %*s", &code) == 1) {
- DEBUGP(DMGCP, "Response: Code: %d\n", code);
- } else {
- int i, handled = 0;
- msg->l3h = &msg->l2h[4];
- for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i)
- if (strncmp(mgcp_requests[i].name, (const char *) &msg->data[0], 4) == 0) {
- handled = 1;
- mgcp_requests[i].handle_request(msg, source);
- }
- if (!handled) {
- DEBUGP(DMGCP, "MSG with type: '%.4s' not handled\n", &msg->data[0]);
- }
- }
-}
-
-/* string tokenizer for the poor */
-static int find_msg_pointers(struct msgb *msg, struct mgcp_msg_ptr *ptrs, int ptrs_length)
-{
- int i, found = 0;
-
- int whitespace = 1;
- for (i = 0; i < msgb_l3len(msg) && ptrs_length > 0; ++i) {
- /* if we have a space we found an end */
- if (msg->l3h[i] == ' ' || msg->l3h[i] == '\r' || msg->l3h[i] == '\n') {
- if (!whitespace) {
- ++found;
- whitespace = 1;
- ptrs->length = i - ptrs->start - 1;
- ++ptrs;
- --ptrs_length;
- } else {
- /* skip any number of whitespace */
- }
-
- /* line end... stop */
- if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n')
- break;
- } else if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') {
- /* line end, be done */
- break;
- } else if (whitespace) {
- whitespace = 0;
- ptrs->start = i;
- }
- }
-
- if (ptrs_length == 0)
- return -1;
- return found;
-}
-
-static struct mgcp_endpoint *find_endpoint(const char *mgcp)
-{
- char *endptr = NULL;
- unsigned int gw = INT_MAX;
-
- gw = strtoul(mgcp, &endptr, 16);
- if (gw == 0 || gw >= number_endpoints || strcmp(endptr, "@mgw") != 0) {
- DEBUGP(DMGCP, "Not able to find endpoint: '%s'\n", mgcp);
- return NULL;
- }
-
- return &endpoints[gw];
-}
-
-static int analyze_header(struct msgb *msg, struct mgcp_msg_ptr *ptr, int size,
- const char **transaction_id, struct mgcp_endpoint **endp)
-{
- int found;
-
- if (size < 3) {
- DEBUGP(DMGCP, "Not enough space in ptr\n");
- return -1;
- }
-
- found = find_msg_pointers(msg, ptr, size);
-
- if (found < 3) {
- DEBUGP(DMGCP, "Gateway: Not enough params. Found: %d\n", found);
- return -1;
- }
-
- /*
- * replace the space with \0. the main method gurantess that
- * we still have + 1 for null termination
- */
- msg->l3h[ptr[3].start + ptr[3].length + 1] = '\0';
- msg->l3h[ptr[2].start + ptr[2].length + 1] = '\0';
- msg->l3h[ptr[1].start + ptr[1].length + 1] = '\0';
- msg->l3h[ptr[0].start + ptr[0].length + 1] = '\0';
-
- if (strncmp("1.0", (const char *)&msg->l3h[ptr[3].start], 3) != 0
- || strncmp("MGCP", (const char *)&msg->l3h[ptr[2].start], 4) != 0) {
- DEBUGP(DMGCP, "Wrong MGCP version. Not handling: '%s' '%s'\n",
- (const char *)&msg->l3h[ptr[3].start],
- (const char *)&msg->l3h[ptr[2].start]);
- return -1;
- }
-
- *transaction_id = (const char *)&msg->l3h[ptr[0].start];
- *endp = find_endpoint((const char *)&msg->l3h[ptr[1].start]);
- return *endp == NULL;
-}
-
-static int verify_call_id(const struct mgcp_endpoint *endp,
- const char *callid)
-{
- if (strcmp(endp->callid, callid) != 0) {
- DEBUGP(DMGCP, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
- ENDPOINT_NUMBER(endp), endp->callid, callid);
- return -1;
- }
-
- return 0;
-}
-
-static int verify_ci(const struct mgcp_endpoint *endp,
- const char *ci)
-{
- if (atoi(ci) != endp->ci) {
- DEBUGP(DMGCP, "ConnectionIdentifiers do not match on 0x%x. %d != %s\n",
- ENDPOINT_NUMBER(endp), endp->ci, ci);
- return -1;
- }
-
- return 0;
-}
-
-static void handle_audit_endpoint(struct msgb *msg, struct sockaddr_in *source)
-{
- struct mgcp_msg_ptr data_ptrs[6];
- int found, response;
- const char *trans_id;
- struct mgcp_endpoint *endp;
-
- found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
- if (found != 0)
- response = 500;
- else
- response = 200;
-
- return send_response(response, "AUEP", trans_id, source);
-}
-
-static int parse_conn_mode(const char* msg, int *conn_mode)
-{
- int ret = 0;
- if (strcmp(msg, "recvonly") == 0)
- *conn_mode = MGCP_CONN_RECV_ONLY;
- else if (strcmp(msg, "sendrecv") == 0)
- *conn_mode = MGCP_CONN_RECV_SEND;
- else {
- DEBUGP(DMGCP, "Unknown connection mode: '%s'\n", msg);
- ret = -1;
- }
-
- return ret;
-}
-
-static void handle_create_con(struct msgb *msg, struct sockaddr_in *source)
-{
- struct mgcp_msg_ptr data_ptrs[6];
- int found, i, line_start;
- const char *trans_id;
- struct mgcp_endpoint *endp;
- int error_code = 500;
-
- found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
- if (found != 0)
- return send_response(500, "CRCX", trans_id, source);
-
- if (endp->ci != CI_UNUSED) {
- DEBUGP(DMGCP, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp));
- return send_response(500, "CRCX", trans_id, source);
- }
-
- /* parse CallID C: and LocalParameters L: */
- MSG_TOKENIZE_START
- switch (msg->l3h[line_start]) {
- case 'L':
- endp->local_options = talloc_strdup(endpoints,
- (const char *)&msg->l3h[line_start + 3]);
- break;
- case 'C':
- endp->callid = talloc_strdup(endpoints,
- (const char *)&msg->l3h[line_start + 3]);
- break;
- case 'M':
- if (parse_conn_mode((const char *)&msg->l3h[line_start + 3],
- &endp->conn_mode) != 0) {
- error_code = 517;
- goto error2;
- }
- break;
- default:
- DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n",
- msg->l3h[line_start], msg->l3h[line_start],
- ENDPOINT_NUMBER(endp));
- break;
- }
- MSG_TOKENIZE_END
-
- /* initialize */
- endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
-
- /* set to zero until we get the info */
- memset(&endp->remote, 0, sizeof(endp->remote));
-
- /* bind to the port now */
- endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port);
- if (!early_bind && bind_rtp(endp) != 0)
- goto error2;
-
- /* assign a local call identifier or fail */
- endp->ci = generate_call_id();
- if (endp->ci == CI_UNUSED)
- goto error2;
-
- DEBUGP(DMGCP, "Creating endpoint on: 0x%x CI: %u port: %u\n",
- ENDPOINT_NUMBER(endp), endp->ci, endp->rtp_port);
- return send_with_sdp(endp, "CRCX", trans_id, source);
-error:
- DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
- hexdump(msg->l3h, msgb_l3len(msg)),
- ENDPOINT_NUMBER(endp), line_start, i);
- return send_response(error_code, "CRCX", trans_id, source);
-
-error2:
- DEBUGP(DMGCP, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
- return send_response(error_code, "CRCX", trans_id, source);
-}
-
-static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source)
-{
- struct mgcp_msg_ptr data_ptrs[6];
- int found, i, line_start;
- const char *trans_id;
- struct mgcp_endpoint *endp;
- int error_code = 500;
-
- found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
- if (found != 0)
- return send_response(error_code, "MDCX", trans_id, source);
-
- if (endp->ci == CI_UNUSED) {
- DEBUGP(DMGCP, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
- return send_response(error_code, "MDCX", trans_id, source);
- }
-
- MSG_TOKENIZE_START
- switch (msg->l3h[line_start]) {
- case 'C': {
- if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
- goto error3;
- break;
- }
- case 'I': {
- if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
- goto error3;
- break;
- }
- case 'L':
- /* skip */
- break;
- case 'M':
- if (parse_conn_mode((const char *)&msg->l3h[line_start + 3],
- &endp->conn_mode) != 0) {
- error_code = 517;
- goto error3;
- }
- break;
- case '\0':
- /* SDP file begins */
- break;
- case 'a':
- case 'o':
- case 's':
- case 't':
- case 'v':
- /* skip these SDP attributes */
- break;
- case 'm': {
- int port;
- const char *param = (const char *)&msg->l3h[line_start];
-
- if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) {
- endp->net_rtp = htons(port);
- endp->net_rtcp = htons(port + 1);
- }
- break;
- }
- case 'c': {
- char ipv4[16];
- const char *param = (const char *)&msg->l3h[line_start];
-
- if (sscanf(param, "c=IN IP4 %15s", ipv4) == 1) {
- inet_aton(ipv4, &endp->remote);
- }
- break;
- }
- default:
- DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n",
- msg->l3h[line_start], msg->l3h[line_start],
- ENDPOINT_NUMBER(endp));
- break;
- }
- MSG_TOKENIZE_END
-
- /* modify */
- DEBUGP(DMGCP, "Modified endpoint on: 0x%x Server: %s:%u\n",
- ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->net_rtp);
- return send_with_sdp(endp, "MDCX", trans_id, source);
-
-error:
- DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n",
- hexdump(msg->l3h, msgb_l3len(msg)),
- ENDPOINT_NUMBER(endp), line_start, i, msg->l3h[line_start]);
- return send_response(error_code, "MDCX", trans_id, source);
-
-error3:
- return send_response(error_code, "MDCX", trans_id, source);
-}
-
-static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source)
-{
- struct mgcp_msg_ptr data_ptrs[6];
- int found, i, line_start;
- const char *trans_id;
- struct mgcp_endpoint *endp;
- int error_code = 500;
-
- found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
- if (found != 0)
- return send_response(error_code, "DLCX", trans_id, source);
-
- if (endp->ci == CI_UNUSED) {
- DEBUGP(DMGCP, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp));
- return send_response(error_code, "DLCX", trans_id, source);
- }
-
- MSG_TOKENIZE_START
- switch (msg->l3h[line_start]) {
- case 'C': {
- if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
- goto error3;
- break;
- }
- case 'I': {
- if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
- goto error3;
- break;
- }
- default:
- DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n",
- msg->l3h[line_start], msg->l3h[line_start],
- ENDPOINT_NUMBER(endp));
- break;
- }
- MSG_TOKENIZE_END
-
-
- /* free the connection */
- DEBUGP(DMGCP, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
- endp->ci= CI_UNUSED;
- talloc_free(endp->callid);
- talloc_free(endp->local_options);
-
- if (!early_bind) {
- bsc_unregister_fd(&endp->local_rtp);
- bsc_unregister_fd(&endp->local_rtcp);
- }
-
- endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
-
- return send_response(250, "DLCX", trans_id, source);
-
-error:
- DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
- hexdump(msg->l3h, msgb_l3len(msg)),
- ENDPOINT_NUMBER(endp), line_start, i);
- return send_response(error_code, "DLCX", trans_id, source);
-
-error3:
- return send_response(error_code, "DLCX", trans_id, source);
-}
-
-static void print_help()
-{
- printf("Some useful help...\n");
- printf(" -h --help is printing this text.\n");
- printf(" -c --config-file filename The config file to use.\n");
-}
-
-static void handle_options(int argc, char** argv)
-{
- while (1) {
- int option_index = 0, c;
- static struct option long_options[] = {
- {"help", 0, 0, 'h'},
- {"config-file", 1, 0, 'c'},
- {0, 0, 0, 0},
- };
-
- c = getopt_long(argc, argv, "hc:", long_options, &option_index);
-
- if (c == -1)
- break;
-
- switch(c) {
- case 'h':
- print_help();
- exit(0);
- break;
- case 'c':
- config_file = talloc_strdup(tall_bsc_ctx, optarg);
- break;
- default:
- /* ignore */
- break;
- };
- }
-}
-
-static int read_call_agent(struct bsc_fd *fd, unsigned int what)
-{
- struct sockaddr_in addr;
- socklen_t slen = sizeof(addr);
- struct msgb *msg;
-
- msg = (struct msgb *) fd->data;
-
- /* read one less so we can use it as a \0 */
- int rc = recvfrom(bfd.fd, msg->data, msg->data_len - 1, 0,
- (struct sockaddr *) &addr, &slen);
- if (rc < 0) {
- perror("Gateway failed to read");
- return -1;
- } else if (slen > sizeof(addr)) {
- fprintf(stderr, "Gateway received message from outerspace: %d %d\n",
- slen, sizeof(addr));
- return -1;
- }
-
- if (first_request) {
- first_request = 0;
- send_rsip(&addr);
- return 0;
- }
-
- /* handle message now */
- msg->l2h = msgb_put(msg, rc);
- handle_message(msg, &addr);
- msgb_reset(msg);
- return 0;
-}
-
-/*
- * vty code for mgcp below
- */
-struct cmd_node mgcp_node = {
- MGCP_NODE,
- "%s(mgcp)#",
- 1,
-};
-
-static int config_write_mgcp(struct vty *vty)
-{
- vty_out(vty, "mgcp%s", VTY_NEWLINE);
- if (local_ip)
- vty_out(vty, " local ip %s%s", local_ip, VTY_NEWLINE);
- if (bts_ip)
- vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE);
- vty_out(vty, " bind ip %s%s", source_addr, VTY_NEWLINE);
- vty_out(vty, " bind port %u%s", source_port, VTY_NEWLINE);
- vty_out(vty, " bind early %u%s", !!early_bind, VTY_NEWLINE);
- vty_out(vty, " rtp base %u%s", rtp_base_port, VTY_NEWLINE);
- vty_out(vty, " sdp audio payload number %u%s", audio_payload, VTY_NEWLINE);
- vty_out(vty, " sdp audio payload name %s%s", audio_name, VTY_NEWLINE);
- vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE);
- vty_out(vty, " endpoints %u%s", number_endpoints, VTY_NEWLINE);
- if (forward_ip)
- vty_out(vty, " forward audio ip %s%s", forward_ip, VTY_NEWLINE);
- if (forward_port != 0)
- vty_out(vty, " forward audio port %d%s", forward_port, VTY_NEWLINE);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp",
- SHOW_STR "Display information about the MGCP Media Gateway")
-{
- int i;
-
- vty_out(vty, "MGCP is up and running with %u endpoints:%s", number_endpoints - 1, VTY_NEWLINE);
- for (i = 1; i < number_endpoints; ++i) {
- struct mgcp_endpoint *endp = &endpoints[i];
- vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s",
- i, endp->ci,
- ntohs(endp->net_rtp), ntohs(endp->net_rtcp),
- ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp,
- cfg_mgcp_cmd,
- "mgcp",
- "Configure the MGCP")
-{
- vty->node = MGCP_NODE;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_local_ip,
- cfg_mgcp_local_ip_cmd,
- "local ip IP",
- "Set the IP to be used in SDP records")
-{
- local_ip = talloc_strdup(tall_bsc_ctx, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_bts_ip,
- cfg_mgcp_bts_ip_cmd,
- "bts ip IP",
- "Set the IP of the BTS for RTP forwarding")
-{
- bts_ip = talloc_strdup(tall_bsc_ctx, argv[0]);
- inet_aton(bts_ip, &bts_in);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_bind_ip,
- cfg_mgcp_bind_ip_cmd,
- "bind ip IP",
- "Bind the MGCP to this local addr")
-{
- source_addr = talloc_strdup(tall_bsc_ctx, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_bind_port,
- cfg_mgcp_bind_port_cmd,
- "bind port <0-65534>",
- "Bind the MGCP to this port")
-{
- unsigned int port = atoi(argv[0]);
- if (port > 65534) {
- vty_out(vty, "%% wrong bind port '%s'%s", argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- source_port = port;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_bind_early,
- cfg_mgcp_bind_early_cmd,
- "bind early (0|1)",
- "Bind all RTP ports early")
-{
- unsigned int bind = atoi(argv[0]);
- if (bind != 0 && bind != 1) {
- vty_out(vty, "%% param must be 0 or 1.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- early_bind = bind == 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_rtp_base_port,
- cfg_mgcp_rtp_base_port_cmd,
- "rtp base <0-65534>",
- "Base port to use")
-{
- unsigned int port = atoi(argv[0]);
- if (port > 65534) {
- vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- rtp_base_port = port;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_sdp_payload_number,
- cfg_mgcp_sdp_payload_number_cmd,
- "sdp audio payload number <1-255>",
- "Set the audio codec to use")
-{
- unsigned int payload = atoi(argv[0]);
- if (payload > 255) {
- vty_out(vty, "%% wrong payload number '%s'%s", argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- audio_payload = payload;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_sdp_payload_name,
- cfg_mgcp_sdp_payload_name_cmd,
- "sdp audio payload name NAME",
- "Set the audio name to use")
-{
- audio_name = talloc_strdup(tall_bsc_ctx, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_loop,
- cfg_mgcp_loop_cmd,
- "loop (0|1)",
- "Loop the audio")
-{
- audio_loop = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_number_endp,
- cfg_mgcp_number_endp_cmd,
- "number endpoints <0-65534>",
- "The number of endpoints to allocate. This is not dynamic.")
-{
- /* + 1 as we start counting at one */
- number_endpoints = atoi(argv[0]) + 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_forward_ip,
- cfg_mgcp_forward_ip_cmd,
- "forward audio ip IP",
- "Forward packets from and to the IP. This disables most of the MGCP feature.")
-{
- if (forward_ip)
- talloc_free(forward_ip);
- forward_ip = talloc_strdup(tall_bsc_ctx, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_mgcp_forward_port,
- cfg_mgcp_forward_port_cmd,
- "forward audio port <1-15000>",
- "Forward packets from and to the port. This disables most of the MGCP feature.")
-{
- forward_port = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-int bsc_vty_init(struct gsm_network *dummy)
-{
- cmd_init(1);
- vty_init();
-
- install_element(VIEW_NODE, &show_mgcp_cmd);
-
-
- install_element(CONFIG_NODE, &cfg_mgcp_cmd);
- install_node(&mgcp_node, config_write_mgcp);
- install_default(MGCP_NODE);
- install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_bts_ip_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_bind_ip_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_loop_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_forward_ip_cmd);
- install_element(MGCP_NODE, &cfg_mgcp_forward_port_cmd);
- return 0;
-}
-
-int main(int argc, char** argv)
-{
- struct gsm_network dummy_network;
- struct sockaddr_in addr;
- int on = 1, i, rc;
-
- tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent");
- handle_options(argc, argv);
-
- telnet_init(&dummy_network, 4243);
- rc = vty_read_config_file(config_file);
- if (rc < 0) {
- fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
- return rc;
- }
-
-
- if (!bts_ip)
- fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n");
-
- endpoints = _talloc_zero_array(tall_bsc_ctx,
- sizeof(struct mgcp_endpoint),
- number_endpoints, "endpoints");
- if (!endpoints) {
- fprintf(stderr, "Failed to allocate endpoints: %d. Quitting.\n", number_endpoints);
- return -1;
- }
-
- /* Initialize all endpoints */
- for (i = 0; i < number_endpoints; ++i) {
- endpoints[i].local_rtp.fd = -1;
- endpoints[i].local_rtcp.fd = -1;
- endpoints[i].ci = CI_UNUSED;
- }
-
- /*
- * This application supports two modes.
- * 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX
- * 2.) plain forwarding of RTP packets on the endpoints.
- * both modes are mutual exclusive
- */
- if (forward_ip) {
- int port = rtp_base_port;
- if (forward_port != 0)
- port = forward_port;
-
- if (!early_bind) {
- DEBUGP(DMGCP, "Forwarding requires early bind.\n");
- return -1;
- }
-
- /*
- * Store the forward IP and assign a ci. For early bind
- * the sockets will be created after this.
- */
- for (i = 1; i < number_endpoints; ++i) {
- struct mgcp_endpoint *endp = &endpoints[i];
- inet_aton(forward_ip, &endp->remote);
- endp->ci = CI_UNUSED + 23;
- endp->net_rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port));
- endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port) + 1);
- }
-
- DEBUGP(DMGCP, "Configured for Audio Forwarding.\n");
- } else {
- bfd.when = BSC_FD_READ;
- bfd.cb = read_call_agent;
- bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (bfd.fd < 0) {
- perror("Gateway failed to listen");
- return -1;
- }
-
- setsockopt(bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(source_port);
- inet_aton(source_addr, &addr.sin_addr);
-
- if (bind(bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("Gateway failed to bind");
- return -1;
- }
-
- bfd.data = msgb_alloc(4096, "mgcp-msg");
- if (!bfd.data) {
- fprintf(stderr, "Gateway memory error.\n");
- return -1;
- }
-
-
- if (bsc_register_fd(&bfd) != 0) {
- DEBUGP(DMGCP, "Failed to register the fd\n");
- return -1;
- }
-
- DEBUGP(DMGCP, "Configured for MGCP.\n");
- }
-
- /* initialisation */
- srand(time(NULL));
-
- /* early bind */
- if (early_bind) {
- for (i = 1; i < number_endpoints; ++i) {
- struct mgcp_endpoint *endp = &endpoints[i];
- endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port);
- if (bind_rtp(endp) != 0)
- return -1;
- }
- }
-
- /* main loop */
- while (1) {
- bsc_select_main(0);
- }
-
-
- return 0;
-}
diff --git a/openbsc/src/bsc_msc_ip.c b/openbsc/src/bsc_msc_ip.c
index 5e3831bd4..4d5c42be4 100644
--- a/openbsc/src/bsc_msc_ip.c
+++ b/openbsc/src/bsc_msc_ip.c
@@ -35,11 +35,8 @@
#define _GNU_SOURCE
#include <getopt.h>
-#include <openbsc/select.h>
#include <openbsc/debug.h>
#include <openbsc/e1_input.h>
-#include <openbsc/talloc.h>
-#include <openbsc/select.h>
#include <openbsc/ipaccess.h>
#include <openbsc/bssap.h>
#include <openbsc/paging.h>
@@ -47,12 +44,16 @@
#include <openbsc/chan_alloc.h>
#include <openbsc/bsc_msc.h>
+#include <osmocore/select.h>
+#include <osmocore/talloc.h>
+
#include <sccp/sccp.h>
/* SCCP helper */
#define SCCP_IT_TIMER 60
/* MCC and MNC for the Location Area Identifier */
+static struct debug_target *stderr_target;
struct gsm_network *bsc_gsmnet = 0;
static const char *config_file = "openbsc.cfg";
static char *msc_address = "127.0.0.1";
@@ -714,16 +715,16 @@ static void handle_options(int argc, char** argv)
print_help();
exit(0);
case 's':
- debug_use_color(0);
+ debug_set_use_color(stderr_target, 0);
break;
case 'd':
- debug_parse_category_mask(optarg);
+ debug_parse_category_mask(stderr_target, optarg);
break;
case 'c':
config_file = strdup(optarg);
break;
case 'T':
- debug_timestamp(1);
+ debug_set_print_timestamp(stderr_target, 1);
break;
case 'P':
ipacc_rtp_direct = 0;
@@ -802,11 +803,25 @@ static void test_mode()
bssmap_rcvmsg_dt1(&conn, msg, ARRAY_SIZE(assignment_req));
}
+extern int bts_model_unknown_init(void);
+extern int bts_model_bs11_init(void);
+extern int bts_model_nanobts_init(void);
+
int main(int argc, char **argv)
{
int rc;
+ debug_init();
tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
+ stderr_target = debug_target_create_stderr();
+ debug_add_target(stderr_target);
+
+ bts_model_unknown_init();
+ bts_model_bs11_init();
+ bts_model_nanobts_init();
+
+ /* enable filters */
+ debug_set_all_filter(stderr_target, 1);
/* parse options */
handle_options(argc, argv);
diff --git a/openbsc/src/bsc_rll.c b/openbsc/src/bsc_rll.c
index 780a84e39..e9d6f252a 100644
--- a/openbsc/src/bsc_rll.c
+++ b/openbsc/src/bsc_rll.c
@@ -24,9 +24,9 @@
#include <errno.h>
#include <openbsc/debug.h>
-#include <openbsc/talloc.h>
-#include <openbsc/timer.h>
-#include <openbsc/linuxlist.h>
+#include <osmocore/talloc.h>
+#include <osmocore/timer.h>
+#include <osmocore/linuxlist.h>
#include <openbsc/bsc_rll.h>
#include <openbsc/gsm_data.h>
#include <openbsc/chan_alloc.h>
diff --git a/openbsc/src/bssap.c b/openbsc/src/bssap.c
index 002e7ce21..7ded8d1f3 100644
--- a/openbsc/src/bssap.c
+++ b/openbsc/src/bssap.c
@@ -26,10 +26,11 @@
#include <openbsc/debug.h>
#include <openbsc/mgcp.h>
#include <openbsc/signal.h>
-#include <openbsc/tlv.h>
#include <openbsc/paging.h>
#include <openbsc/chan_alloc.h>
+#include <osmocore/tlv.h>
+
#include <sccp/sccp.h>
#include <arpa/inet.h>
@@ -684,9 +685,9 @@ int dtap_rcvmsg(struct gsm_lchan *lchan, struct msgb *msg, unsigned int length)
if (gh->msg_type == GSM48_MT_MM_LOC_UPD_ACCEPT) {
struct gsm_network *net = gsm48->trx->bts->network;
struct gsm48_loc_area_id *lai = (struct gsm48_loc_area_id *) &gh->data[0];
- gsm0408_generate_lai(lai, net->country_code,
- net->network_code,
- gsm48->trx->bts->location_area_code);
+ gsm48_generate_lai(lai, net->country_code,
+ net->network_code,
+ gsm48->trx->bts->location_area_code);
}
}
}
@@ -726,8 +727,8 @@ struct msgb *bssmap_create_layer3(struct msgb *msg_l3)
data[2] = CELL_IDENT_WHOLE_GLOBAL;
lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
- gsm0408_generate_lai(lai, country_code,
- network_code, bts->location_area_code);
+ gsm48_generate_lai(lai, country_code,
+ network_code, bts->location_area_code);
ci = (u_int16_t *) msgb_put(msg, 2);
*ci = htons(bts->cell_identity);
diff --git a/openbsc/src/bts_ipaccess_nanobts.c b/openbsc/src/bts_ipaccess_nanobts.c
new file mode 100644
index 000000000..cb48ea98a
--- /dev/null
+++ b/openbsc/src/bts_ipaccess_nanobts.c
@@ -0,0 +1,84 @@
+/* ip.access nanoBTS specific code */
+
+/* (C) 2009-2010 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 <sys/types.h>
+
+#include <openbsc/gsm_data.h>
+#include <osmocore/tlv.h>
+#include <openbsc/abis_nm.h>
+
+static struct gsm_bts_model model_nanobts = {
+ .type = GSM_BTS_TYPE_NANOBTS,
+ .nm_att_tlvdef = {
+ .def = {
+ /* 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_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 },
+ },
+ },
+};
+
+int bts_model_nanobts_init(void)
+{
+ return gsm_bts_model_register(&model_nanobts);
+}
diff --git a/openbsc/src/bts_siemens_bs11.c b/openbsc/src/bts_siemens_bs11.c
new file mode 100644
index 000000000..c966825ee
--- /dev/null
+++ b/openbsc/src/bts_siemens_bs11.c
@@ -0,0 +1,66 @@
+/* Siemens BS-11 specific code */
+
+/* (C) 2009-2010 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 <sys/types.h>
+
+#include <openbsc/gsm_data.h>
+#include <osmocore/tlv.h>
+#include <openbsc/abis_nm.h>
+
+static struct gsm_bts_model model_bs11 = {
+ .type = GSM_BTS_TYPE_BS11,
+ .nm_att_tlvdef = {
+ .def = {
+ [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TLV },
+ /* BS11 specifics */
+ [NM_ATT_BS11_ESN_FW_CODE_NO] = { TLV_TYPE_TLV },
+ [NM_ATT_BS11_ESN_HW_CODE_NO] = { TLV_TYPE_TLV },
+ [NM_ATT_BS11_ESN_PCB_SERIAL] = { TLV_TYPE_TLV },
+ [NM_ATT_BS11_BOOT_SW_VERS] = { TLV_TYPE_TLV },
+ [0xd5] = { TLV_TYPE_TLV },
+ [0xa8] = { TLV_TYPE_TLV },
+ [NM_ATT_BS11_PASSWORD] = { TLV_TYPE_TLV },
+ [NM_ATT_BS11_TXPWR] = { TLV_TYPE_TLV },
+ [NM_ATT_BS11_RSSI_OFFS] = { TLV_TYPE_TLV },
+ [NM_ATT_BS11_LINE_CFG] = { TLV_TYPE_TV },
+ [NM_ATT_BS11_L1_PROT_TYPE] = { TLV_TYPE_TV },
+ [NM_ATT_BS11_BIT_ERR_THESH] = { TLV_TYPE_FIXED, 2 },
+ [NM_ATT_BS11_DIVERSITY] = { TLV_TYPE_TLV },
+ [NM_ATT_BS11_LMT_LOGON_SESSION]={ TLV_TYPE_TLV },
+ [NM_ATT_BS11_LMT_LOGIN_TIME] = { TLV_TYPE_TLV },
+ [NM_ATT_BS11_LMT_USER_ACC_LEV] ={ TLV_TYPE_TLV },
+ [NM_ATT_BS11_LMT_USER_NAME] = { TLV_TYPE_TLV },
+ [NM_ATT_BS11_BTS_STATE] = { TLV_TYPE_TLV },
+ [NM_ATT_BS11_E1_STATE] = { TLV_TYPE_TLV },
+ [NM_ATT_BS11_PLL_MODE] = { TLV_TYPE_TLV },
+ [NM_ATT_BS11_PLL] = { TLV_TYPE_TLV },
+ [NM_ATT_BS11_CCLK_ACCURACY] = { TLV_TYPE_TV },
+ [NM_ATT_BS11_CCLK_TYPE] = { TLV_TYPE_TV },
+ [0x95] = { TLV_TYPE_FIXED, 2 },
+ },
+ },
+};
+
+int bts_model_bs11_init(void)
+{
+ return gsm_bts_model_register(&model_bs11);
+}
diff --git a/openbsc/include/openbsc/gsm_utils.h b/openbsc/src/bts_unknown.c
index 5809221a3..aac5d99c8 100644
--- a/openbsc/include/openbsc/gsm_utils.h
+++ b/openbsc/src/bts_unknown.c
@@ -1,8 +1,6 @@
-/* GSM utility functions, e.g. coding and decoding */
-/*
- * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
- * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009 by Harald Welte <laforge@gnumonks.org>
+/* Generic BTS - VTY code tries to allocate this BTS before type is known */
+
+/* (C) 2010 by Daniel Willmann <daniel@totalueberwachung.de>
*
* All Rights Reserved
*
@@ -22,20 +20,21 @@
*
*/
-#ifndef GSM_UTILS_H
-#define GSM_UTILS_H
-
#include <sys/types.h>
-int gsm_7bit_decode(char *decoded, const u_int8_t *user_data, u_int8_t length);
-int gsm_7bit_encode(u_int8_t *result, const char *data);
-
-int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm);
-int ms_pwr_dbm(enum gsm_band band, u_int8_t lvl);
+#include <openbsc/gsm_data.h>
+#include <osmocore/tlv.h>
+#include <openbsc/abis_nm.h>
-/* According to TS 08.05 Chapter 8.1.4 */
-int rxlev2dbm(u_int8_t rxlev);
-u_int8_t dbm2rxlev(int dbm);
+static struct gsm_bts_model model_unknown = {
+ .type = GSM_BTS_TYPE_UNKNOWN,
+ .nm_att_tlvdef = {
+ .def = {
+ },
+ },
+};
-void generate_backtrace();
-#endif
+int bts_model_unknown_init(void)
+{
+ return gsm_bts_model_register(&model_unknown);
+}
diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c
index 27d582931..b5497bcb8 100644
--- a/openbsc/src/chan_alloc.c
+++ b/openbsc/src/chan_alloc.c
@@ -33,6 +33,29 @@
#include <openbsc/debug.h>
#include <openbsc/signal.h>
+static int ts_is_usable(struct gsm_bts_trx_ts *ts)
+{
+ /* FIXME: How does this behave for BS-11 ? */
+ if (is_ipaccess_bts(ts->trx->bts)) {
+ if (!nm_is_running(&ts->nm_state))
+ return 0;
+ }
+
+ return 1;
+}
+
+int trx_is_usable(struct gsm_bts_trx *trx)
+{
+ /* FIXME: How does this behave for BS-11 ? */
+ if (is_ipaccess_bts(trx->bts)) {
+ if (!nm_is_running(&trx->nm_state) ||
+ !nm_is_running(&trx->bb_transc.nm_state))
+ return 0;
+ }
+
+ return 1;
+}
+
struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts,
enum gsm_phys_chan_config pchan)
{
@@ -61,6 +84,9 @@ struct gsm_bts_trx_ts *ts_alloc(struct gsm_bts *bts,
llist_for_each_entry(trx, &bts->trx_list, list) {
int from, to;
+ if (!trx_is_usable(trx))
+ continue;
+
/* the following constraints are pure policy,
* no requirement to put this restriction in place */
if (trx == bts->c0) {
@@ -95,6 +121,10 @@ struct gsm_bts_trx_ts *ts_alloc(struct gsm_bts *bts,
for (j = from; j <= to; j++) {
struct gsm_bts_trx_ts *ts = &trx->ts[j];
+
+ if (!ts_is_usable(ts))
+ continue;
+
if (ts->pchan == GSM_PCHAN_NONE) {
ts->pchan = pchan;
/* set channel attribute on OML */
@@ -119,6 +149,7 @@ static const u_int8_t subslots_per_pchan[] = {
[GSM_PCHAN_TCH_F] = 1,
[GSM_PCHAN_TCH_H] = 2,
[GSM_PCHAN_SDCCH8_SACCH8C] = 8,
+ /* FIXME: what about dynamic TCH_F_TCH_H ? */
};
static struct gsm_lchan *
@@ -127,14 +158,20 @@ _lc_find_trx(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan)
struct gsm_bts_trx_ts *ts;
int j, ss;
+ if (!trx_is_usable(trx))
+ return NULL;
+
for (j = 0; j < 8; j++) {
ts = &trx->ts[j];
+ if (!ts_is_usable(ts))
+ continue;
if (ts->pchan != pchan)
continue;
/* check if all sub-slots are allocated yet */
for (ss = 0; ss < subslots_per_pchan[pchan]; ss++) {
struct gsm_lchan *lc = &ts->lchan[ss];
- if (lc->type == GSM_LCHAN_NONE)
+ if (lc->type == GSM_LCHAN_NONE &&
+ lc->state == LCHAN_S_NONE)
return lc;
}
}
@@ -256,6 +293,8 @@ void lchan_free(struct gsm_lchan *lchan)
}
for (i = 0; i < ARRAY_SIZE(lchan->neigh_meas); i++)
lchan->neigh_meas[i].arfcn = 0;
+ lchan->silent_call = 0;
+
/* FIXME: ts_free() the timeslot, if we're the last logical
* channel using it */
}
@@ -280,7 +319,7 @@ int _lchan_release(struct gsm_lchan *lchan)
LOGP(DRLL, LOGL_ERROR, "Channel count is negative: %d\n",
lchan->use_count);
- DEBUGP(DRLL, "Recycling the channel with: %d (%x)\n", lchan->nr, lchan->nr);
+ DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan));
rsl_release_request(lchan, 0);
return 1;
}
@@ -317,3 +356,51 @@ struct gsm_lchan *lchan_for_subscr(struct gsm_subscriber *subscr)
return NULL;
}
+
+void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts)
+{
+ struct gsm_bts_trx *trx;
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ int i;
+
+ /* skip administratively deactivated tranxsceivers */
+ if (!nm_is_running(&trx->nm_state) ||
+ !nm_is_running(&trx->bb_transc.nm_state))
+ continue;
+
+ for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[i];
+ struct load_counter *pl = &cl->pchan[ts->pchan];
+ int j;
+
+ /* skip administratively deactivated timeslots */
+ if (!nm_is_running(&ts->nm_state))
+ continue;
+
+ for (j = 0; j < subslots_per_pchan[ts->pchan]; j++) {
+ struct gsm_lchan *lchan = &ts->lchan[j];
+
+ pl->total++;
+
+ switch (lchan->state) {
+ case LCHAN_S_NONE:
+ break;
+ default:
+ pl->used++;
+ break;
+ }
+ }
+ }
+ }
+}
+
+void network_chan_load(struct pchan_load *pl, struct gsm_network *net)
+{
+ struct gsm_bts *bts;
+
+ memset(pl, 0, sizeof(*pl));
+
+ llist_for_each_entry(bts, &net->bts_list, list)
+ bts_chan_load(pl, bts);
+}
diff --git a/openbsc/src/db.c b/openbsc/src/db.c
index d85386548..10c1d6d4c 100644
--- a/openbsc/src/db.c
+++ b/openbsc/src/db.c
@@ -23,8 +23,9 @@
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_04_11.h>
#include <openbsc/db.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/debug.h>
+#include <osmocore/statistics.h>
#include <libgen.h>
#include <stdio.h>
@@ -117,12 +118,35 @@ static char *create_stmts[] = {
"subscriber_id INTEGER NOT NULL, "
"apdu BLOB "
")",
+ "CREATE TABLE IF NOT EXISTS Counters ("
+ "id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "timestamp TIMESTAMP NOT NULL, "
+ "value INTEGER NOT NULL, "
+ "name TEXT NOT NULL "
+ ")",
+ "CREATE TABLE IF NOT EXISTS AuthKeys ("
+ "id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "subscriber_id INTEGER UNIQUE NOT NULL, "
+ "algorithm_id INTEGER NOT NULL, "
+ "a3a8_ki BLOB "
+ ")",
+ "CREATE TABLE IF NOT EXISTS AuthTuples ("
+ "id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "subscriber_id NUMERIC UNIQUE NOT NULL, "
+ "issued TIMESTAMP NOT NULL, "
+ "use_count INTEGER NOT NULL DEFAULT 0, "
+ "key_seq INTEGER NOT NULL, "
+ "rand BLOB NOT NULL, "
+ "sres BLOB NOT NULL, "
+ "kc BLOB NOT NULL "
+ ")",
};
-void db_error_func(dbi_conn conn, void* data) {
- const char* msg;
+void db_error_func(dbi_conn conn, void *data)
+{
+ const char *msg;
dbi_conn_error(conn, &msg);
- printf("DBI: %s\n", msg);
+ LOGP(DDB, LOGL_ERROR, "DBI: %s\n", msg);
}
static int check_db_revision(void)
@@ -149,11 +173,13 @@ static int check_db_revision(void)
return 0;
}
-int db_init(const char *name) {
+int db_init(const char *name)
+{
dbi_initialize(NULL);
+
conn = dbi_conn_new("sqlite3");
- if (conn==NULL) {
- printf("DB: Failed to create connection.\n");
+ if (conn == NULL) {
+ LOGP(DDB, LOGL_FATAL, "Failed to create connection.\n");
return 1;
}
@@ -186,21 +212,23 @@ out_err:
}
-int db_prepare() {
+int db_prepare()
+{
dbi_result result;
int i;
for (i = 0; i < ARRAY_SIZE(create_stmts); i++) {
result = dbi_conn_query(conn, create_stmts[i]);
- if (result==NULL) {
- printf("DB: Failed to create some table.\n");
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR,
+ "Failed to create some table.\n");
return 1;
}
dbi_result_free(result);
}
if (check_db_revision() < 0) {
- fprintf(stderr, "Database schema revision invalid, "
+ LOGP(DDB, LOGL_FATAL, "Database schema revision invalid, "
"please update your database schema\n");
return -1;
}
@@ -208,7 +236,8 @@ int db_prepare() {
return 0;
}
-int db_fini() {
+int db_fini()
+{
dbi_conn_close(conn);
dbi_shutdown();
@@ -219,10 +248,10 @@ int db_fini() {
return 0;
}
-struct gsm_subscriber* db_create_subscriber(struct gsm_network *net, char *imsi)
+struct gsm_subscriber *db_create_subscriber(struct gsm_network *net, char *imsi)
{
dbi_result result;
- struct gsm_subscriber* subscr;
+ struct gsm_subscriber *subscr;
/* Is this subscriber known in the db? */
subscr = db_get_subscriber(net, GSM_SUBSCRIBER_IMSI, imsi);
@@ -230,11 +259,10 @@ struct gsm_subscriber* db_create_subscriber(struct gsm_network *net, char *imsi)
result = dbi_conn_queryf(conn,
"UPDATE Subscriber set updated = datetime('now') "
"WHERE imsi = %s " , imsi);
- if (result==NULL) {
- printf("DB: failed to update timestamp\n");
- } else {
+ if (!result)
+ LOGP(DDB, LOGL_ERROR, "failed to update timestamp\n");
+ else
dbi_result_free(result);
- }
return subscr;
}
@@ -249,14 +277,13 @@ struct gsm_subscriber* db_create_subscriber(struct gsm_network *net, char *imsi)
"(%s, datetime('now'), datetime('now')) ",
imsi
);
- if (result==NULL) {
- printf("DB: Failed to create Subscriber by IMSI.\n");
- }
+ if (!result)
+ LOGP(DDB, LOGL_ERROR, "Failed to create Subscriber by IMSI.\n");
subscr->net = net;
subscr->id = dbi_conn_sequence_last(conn, NULL);
strncpy(subscr->imsi, imsi, GSM_IMSI_LENGTH-1);
dbi_result_free(result);
- printf("DB: New Subscriber: ID %llu, IMSI %s\n", subscr->id, subscr->imsi);
+ LOGP(DDB, LOGL_INFO, "New Subscriber: ID %llu, IMSI %s\n", subscr->id, subscr->imsi);
db_subscriber_alloc_exten(subscr);
return subscr;
}
@@ -288,7 +315,9 @@ static int get_equipment_by_subscr(struct gsm_subscriber *subscr)
if (string)
strncpy(equip->imei, string, sizeof(equip->imei));
- cm1 = dbi_result_get_uint(result, "classmark1") & 0xff;
+ string = dbi_result_get_string(result, "classmark1");
+ if (string)
+ cm1 = atoi(string) & 0xff;
equip->classmark1 = *((struct gsm48_classmark1 *) &cm1);
equip->classmark2_len = dbi_result_get_field_length(result, "classmark2");
@@ -307,6 +336,214 @@ static int get_equipment_by_subscr(struct gsm_subscriber *subscr)
return 0;
}
+
+int get_authinfo_by_subscr(struct gsm_auth_info *ainfo,
+ struct gsm_subscriber *subscr)
+{
+ dbi_result result;
+ const unsigned char *a3a8_ki;
+
+ result = dbi_conn_queryf(conn,
+ "SELECT * FROM AuthKeys WHERE subscriber_id=%u",
+ subscr->id);
+ if (!result)
+ return -EIO;
+
+ if (!dbi_result_next_row(result)) {
+ dbi_result_free(result);
+ return -ENOENT;
+ }
+
+ ainfo->auth_algo = dbi_result_get_ulonglong(result, "algorithm_id");
+ ainfo->a3a8_ki_len = dbi_result_get_field_length(result, "a3a8_ki");
+ a3a8_ki = dbi_result_get_binary(result, "a3a8_ki");
+ if (ainfo->a3a8_ki_len > sizeof(ainfo->a3a8_ki))
+ ainfo->a3a8_ki_len = sizeof(ainfo->a3a8_ki_len);
+ memcpy(ainfo->a3a8_ki, a3a8_ki, ainfo->a3a8_ki_len);
+
+ dbi_result_free(result);
+
+ return 0;
+}
+
+int set_authinfo_for_subscr(struct gsm_auth_info *ainfo,
+ struct gsm_subscriber *subscr)
+{
+ dbi_result result;
+ struct gsm_auth_info ainfo_old;
+ int rc, upd;
+ unsigned char *ki_str;
+
+ /* Deletion ? */
+ if (ainfo == NULL) {
+ result = dbi_conn_queryf(conn,
+ "DELETE FROM AuthKeys WHERE subscriber_id=%u",
+ subscr->id);
+
+ if (!result)
+ return -EIO;
+
+ dbi_result_free(result);
+
+ return 0;
+ }
+
+ /* Check if already existing */
+ rc = get_authinfo_by_subscr(&ainfo_old, subscr);
+ if (rc && rc != -ENOENT)
+ return rc;
+ upd = rc ? 0 : 1;
+
+ /* Update / Insert */
+ dbi_conn_quote_binary_copy(conn,
+ ainfo->a3a8_ki, ainfo->a3a8_ki_len, &ki_str);
+
+ if (!upd) {
+ result = dbi_conn_queryf(conn,
+ "INSERT INTO AuthKeys "
+ "(subscriber_id, algorithm_id, a3a8_ki) "
+ "VALUES (%u, %u, %s)",
+ subscr->id, ainfo->auth_algo, ki_str);
+ } else {
+ result = dbi_conn_queryf(conn,
+ "UPDATE AuthKeys "
+ "SET algorithm_id=%u, a3a8_ki=%s "
+ "WHERE subscriber_id=%u",
+ ainfo->auth_algo, ki_str, subscr->id);
+ }
+
+ free(ki_str);
+
+ if (!result)
+ return -EIO;
+
+ dbi_result_free(result);
+
+ return 0;
+}
+
+int get_authtuple_by_subscr(struct gsm_auth_tuple *atuple,
+ struct gsm_subscriber *subscr)
+{
+ dbi_result result;
+ int len;
+ const unsigned char *blob;
+
+ result = dbi_conn_queryf(conn,
+ "SELECT * FROM AuthTuples WHERE subscriber_id=%u",
+ subscr->id);
+ if (!result)
+ return -EIO;
+
+ if (!dbi_result_next_row(result)) {
+ dbi_result_free(result);
+ return -ENOENT;
+ }
+
+ memset(atuple, 0, sizeof(atuple));
+
+ atuple->use_count = dbi_result_get_ulonglong(result, "use_count");
+ atuple->key_seq = dbi_result_get_ulonglong(result, "key_seq");
+
+ len = dbi_result_get_field_length(result, "rand");
+ if (len != sizeof(atuple->rand))
+ goto err_size;
+
+ blob = dbi_result_get_binary(result, "rand");
+ memcpy(atuple->rand, blob, len);
+
+ len = dbi_result_get_field_length(result, "sres");
+ if (len != sizeof(atuple->sres))
+ goto err_size;
+
+ blob = dbi_result_get_binary(result, "sres");
+ memcpy(atuple->sres, blob, len);
+
+ len = dbi_result_get_field_length(result, "kc");
+ if (len != sizeof(atuple->kc))
+ goto err_size;
+
+ blob = dbi_result_get_binary(result, "kc");
+ memcpy(atuple->kc, blob, len);
+
+ dbi_result_free(result);
+
+ return 0;
+
+err_size:
+ dbi_result_free(result);
+ return -EIO;
+}
+
+int set_authtuple_for_subscr(struct gsm_auth_tuple *atuple,
+ struct gsm_subscriber *subscr)
+{
+ dbi_result result;
+ int rc, upd;
+ struct gsm_auth_tuple atuple_old;
+ unsigned char *rand_str, *sres_str, *kc_str;
+
+ /* Deletion ? */
+ if (atuple == NULL) {
+ result = dbi_conn_queryf(conn,
+ "DELETE FROM AuthTuples WHERE subscriber_id=%u",
+ subscr->id);
+
+ if (!result)
+ return -EIO;
+
+ dbi_result_free(result);
+
+ return 0;
+ }
+
+ /* Check if already existing */
+ rc = get_authtuple_by_subscr(&atuple_old, subscr);
+ if (rc && rc != -ENOENT)
+ return rc;
+ upd = rc ? 0 : 1;
+
+ /* Update / Insert */
+ dbi_conn_quote_binary_copy(conn,
+ atuple->rand, sizeof(atuple->rand), &rand_str);
+ dbi_conn_quote_binary_copy(conn,
+ atuple->sres, sizeof(atuple->sres), &sres_str);
+ dbi_conn_quote_binary_copy(conn,
+ atuple->kc, sizeof(atuple->kc), &kc_str);
+
+ if (!upd) {
+ result = dbi_conn_queryf(conn,
+ "INSERT INTO AuthTuples "
+ "(subscriber_id, issued, use_count, "
+ "key_seq, rand, sres, kc) "
+ "VALUES (%u, datetime('now'), %u, "
+ "%u, %s, %s, %s ) ",
+ subscr->id, atuple->use_count, atuple->key_seq,
+ rand_str, sres_str, kc_str);
+ } else {
+ char *issued = atuple->key_seq == atuple_old.key_seq ?
+ "issued" : "datetime('now')";
+ result = dbi_conn_queryf(conn,
+ "UPDATE AuthKeys "
+ "SET issued=%s, use_count=%u, "
+ "key_seq=%u, rand=%s, sres=%s, kc=%s "
+ "WHERE subscriber_id = %u",
+ issued, atuple->use_count, atuple->key_seq,
+ rand_str, sres_str, kc_str, subscr->id);
+ }
+
+ free(rand_str);
+ free(sres_str);
+ free(kc_str);
+
+ if (!result)
+ return -EIO;
+
+ dbi_result_free(result);
+
+ return 0;
+}
+
#define BASE_QUERY "SELECT * FROM Subscriber "
struct gsm_subscriber *db_get_subscriber(struct gsm_network *net,
enum gsm_subscriber_field field,
@@ -353,15 +590,15 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net,
free(quoted);
break;
default:
- printf("DB: Unknown query selector for Subscriber.\n");
+ LOGP(DDB, LOGL_NOTICE, "Unknown query selector for Subscriber.\n");
return NULL;
}
- if (result==NULL) {
- printf("DB: Failed to query Subscriber.\n");
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber.\n");
return NULL;
}
if (!dbi_result_next_row(result)) {
- printf("DB: Failed to find the Subscriber. '%u' '%s'\n",
+ DEBUGP(DDB, "Failed to find the Subscriber. '%u' '%s'\n",
field, id);
dbi_result_free(result);
return NULL;
@@ -388,7 +625,7 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net,
subscr->lac = dbi_result_get_uint(result, "lac");
subscr->authorized = dbi_result_get_uint(result, "authorized");
- printf("DB: Found Subscriber: ID %llu, IMSI %s, NAME '%s', TMSI %u, EXTEN '%s', LAC %hu, AUTH %u\n",
+ DEBUGP(DDB, "Found Subscriber: ID %llu, IMSI %s, NAME '%s', TMSI %u, EXTEN '%s', LAC %hu, AUTH %u\n",
subscr->id, subscr->imsi, subscr->name, subscr->tmsi, subscr->extension,
subscr->lac, subscr->authorized);
dbi_result_free(result);
@@ -398,7 +635,8 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net,
return subscr;
}
-int db_sync_subscriber(struct gsm_subscriber* subscriber) {
+int db_sync_subscriber(struct gsm_subscriber *subscriber)
+{
dbi_result result;
char tmsi[14];
char *q_tmsi;
@@ -410,6 +648,7 @@ int db_sync_subscriber(struct gsm_subscriber* subscriber) {
&q_tmsi);
} else
q_tmsi = strdup("NULL");
+
result = dbi_conn_queryf(conn,
"UPDATE Subscriber "
"SET updated = datetime('now'), "
@@ -424,14 +663,17 @@ int db_sync_subscriber(struct gsm_subscriber* subscriber) {
subscriber->authorized,
q_tmsi,
subscriber->lac,
- subscriber->imsi
- );
+ subscriber->imsi);
+
free(q_tmsi);
- if (result==NULL) {
- printf("DB: Failed to update Subscriber (by IMSI).\n");
+
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR, "Failed to update Subscriber (by IMSI).\n");
return 1;
}
+
dbi_result_free(result);
+
return 0;
}
@@ -442,15 +684,15 @@ int db_sync_equipment(struct gsm_equipment *equip)
u_int8_t classmark1;
memcpy(&classmark1, &equip->classmark1, sizeof(classmark1));
- printf("DB: Sync Equipment IMEI=%s, classmark1=%02x",
+ DEBUGP(DDB, "Sync Equipment IMEI=%s, classmark1=%02x",
equip->imei, classmark1);
if (equip->classmark2_len)
- printf(", classmark2=%s",
+ DEBUGPC(DDB, ", classmark2=%s",
hexdump(equip->classmark2, equip->classmark2_len));
if (equip->classmark3_len)
- printf(", classmark3=%s",
+ DEBUGPC(DDB, ", classmark3=%s",
hexdump(equip->classmark3, equip->classmark3_len));
- printf("\n");
+ DEBUGPC(DDB, "\n");
dbi_conn_quote_binary_copy(conn, equip->classmark2,
equip->classmark2_len, &cm2);
@@ -470,7 +712,7 @@ int db_sync_equipment(struct gsm_equipment *equip)
free(cm3);
if (!result) {
- printf("DB: Failed to update Equipment\n");
+ LOGP(DDB, LOGL_ERROR, "Failed to update Equipment\n");
return -EIO;
}
@@ -478,10 +720,12 @@ int db_sync_equipment(struct gsm_equipment *equip)
return 0;
}
-int db_subscriber_alloc_tmsi(struct gsm_subscriber* subscriber) {
- dbi_result result=NULL;
+int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber)
+{
+ dbi_result result = NULL;
char tmsi[14];
char* tmsi_quoted;
+
for (;;) {
subscriber->tmsi = rand();
if (subscriber->tmsi == GSM_RESERVED_TMSI)
@@ -492,20 +736,23 @@ int db_subscriber_alloc_tmsi(struct gsm_subscriber* subscriber) {
result = dbi_conn_queryf(conn,
"SELECT * FROM Subscriber "
"WHERE tmsi = %s ",
- tmsi_quoted
- );
+ tmsi_quoted);
+
free(tmsi_quoted);
- if (result==NULL) {
- printf("DB: Failed to query Subscriber while allocating new TMSI.\n");
+
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber "
+ "while allocating new TMSI.\n");
return 1;
}
- if (dbi_result_get_numrows(result)){
+ if (dbi_result_get_numrows(result)) {
dbi_result_free(result);
continue;
}
if (!dbi_result_next_row(result)) {
dbi_result_free(result);
- printf("DB: Allocated TMSI %u for IMSI %s.\n", subscriber->tmsi, subscriber->imsi);
+ DEBUGP(DDB, "Allocated TMSI %u for IMSI %s.\n",
+ subscriber->tmsi, subscriber->imsi);
return db_sync_subscriber(subscriber);
}
dbi_result_free(result);
@@ -513,9 +760,11 @@ int db_subscriber_alloc_tmsi(struct gsm_subscriber* subscriber) {
return 0;
}
-int db_subscriber_alloc_exten(struct gsm_subscriber* subscriber) {
- dbi_result result=NULL;
+int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber)
+{
+ dbi_result result = NULL;
u_int32_t try;
+
for (;;) {
try = (rand()%(GSM_MAX_EXTEN-GSM_MIN_EXTEN+1)+GSM_MIN_EXTEN);
result = dbi_conn_queryf(conn,
@@ -523,8 +772,9 @@ int db_subscriber_alloc_exten(struct gsm_subscriber* subscriber) {
"WHERE extension = %i",
try
);
- if (result==NULL) {
- printf("DB: Failed to query Subscriber while allocating new extension.\n");
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber "
+ "while allocating new extension.\n");
return 1;
}
if (dbi_result_get_numrows(result)){
@@ -538,7 +788,7 @@ int db_subscriber_alloc_exten(struct gsm_subscriber* subscriber) {
dbi_result_free(result);
}
sprintf(subscriber->extension, "%i", try);
- printf("DB: Allocated extension %i for IMSI %s.\n", try, subscriber->imsi);
+ DEBUGP(DDB, "Allocated extension %i for IMSI %s.\n", try, subscriber->imsi);
return db_sync_subscriber(subscriber);
}
/*
@@ -547,7 +797,7 @@ int db_subscriber_alloc_exten(struct gsm_subscriber* subscriber) {
* an error.
*/
-int db_subscriber_alloc_token(struct gsm_subscriber* subscriber, u_int32_t* token)
+int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, u_int32_t *token)
{
dbi_result result;
u_int32_t try;
@@ -561,7 +811,8 @@ int db_subscriber_alloc_token(struct gsm_subscriber* subscriber, u_int32_t* toke
"WHERE subscriber_id = %llu OR token = \"%08X\" ",
subscriber->id, try);
if (!result) {
- printf("DB: Failed to query AuthToken while allocating new token.\n");
+ LOGP(DDB, LOGL_ERROR, "Failed to query AuthToken "
+ "while allocating new token.\n");
return 1;
}
if (dbi_result_get_numrows(result)) {
@@ -581,17 +832,19 @@ int db_subscriber_alloc_token(struct gsm_subscriber* subscriber, u_int32_t* toke
"(%llu, datetime('now'), \"%08X\") ",
subscriber->id, try);
if (!result) {
- printf("DB: Failed to create token %08X for IMSI %s.\n", try, subscriber->imsi);
+ LOGP(DDB, LOGL_ERROR, "Failed to create token %08X for "
+ "IMSI %s.\n", try, subscriber->imsi);
return 1;
}
dbi_result_free(result);
*token = try;
- printf("DB: Allocated token %08X for IMSI %s.\n", try, subscriber->imsi);
+ DEBUGP(DDB, "Allocated token %08X for IMSI %s.\n", try, subscriber->imsi);
return 0;
}
-int db_subscriber_assoc_imei(struct gsm_subscriber* subscriber, char imei[GSM_IMEI_LENGTH]) {
+int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char imei[GSM_IMEI_LENGTH])
+{
unsigned long long equipment_id, watch_id;
dbi_result result;
@@ -603,32 +856,32 @@ int db_subscriber_assoc_imei(struct gsm_subscriber* subscriber, char imei[GSM_IM
"(imei, created, updated) "
"VALUES "
"(%s, datetime('now'), datetime('now')) ",
- imei
- );
- if (result==NULL) {
- printf("DB: Failed to create Equipment by IMEI.\n");
+ imei);
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR, "Failed to create Equipment by IMEI.\n");
return 1;
}
+
equipment_id = 0;
if (dbi_result_get_numrows_affected(result)) {
equipment_id = dbi_conn_sequence_last(conn, NULL);
}
dbi_result_free(result);
- if (equipment_id) {
- printf("DB: New Equipment: ID %llu, IMEI %s\n", equipment_id, imei);
- }
+
+ if (equipment_id)
+ DEBUGP(DDB, "New Equipment: ID %llu, IMEI %s\n", equipment_id, imei);
else {
result = dbi_conn_queryf(conn,
"SELECT id FROM Equipment "
"WHERE imei = %s ",
imei
);
- if (result==NULL) {
- printf("DB: Failed to query Equipment by IMEI.\n");
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR, "Failed to query Equipment by IMEI.\n");
return 1;
}
if (!dbi_result_next_row(result)) {
- printf("DB: Failed to find the Equipment.\n");
+ LOGP(DDB, LOGL_ERROR, "Failed to find the Equipment.\n");
dbi_result_free(result);
return 1;
}
@@ -641,33 +894,33 @@ int db_subscriber_assoc_imei(struct gsm_subscriber* subscriber, char imei[GSM_IM
"(subscriber_id, equipment_id, created, updated) "
"VALUES "
"(%llu, %llu, datetime('now'), datetime('now')) ",
- subscriber->id, equipment_id
- );
- if (result==NULL) {
- printf("DB: Failed to create EquipmentWatch.\n");
+ subscriber->id, equipment_id);
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR, "Failed to create EquipmentWatch.\n");
return 1;
}
+
watch_id = 0;
- if (dbi_result_get_numrows_affected(result)) {
+ if (dbi_result_get_numrows_affected(result))
watch_id = dbi_conn_sequence_last(conn, NULL);
- }
+
dbi_result_free(result);
- if (watch_id) {
- printf("DB: New EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n", equipment_id, subscriber->imsi, imei);
- }
+ if (watch_id)
+ DEBUGP(DDB, "New EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n",
+ equipment_id, subscriber->imsi, imei);
else {
result = dbi_conn_queryf(conn,
"UPDATE EquipmentWatch "
"SET updated = datetime('now') "
"WHERE subscriber_id = %llu AND equipment_id = %llu ",
- subscriber->id, equipment_id
- );
- if (result==NULL) {
- printf("DB: Failed to update EquipmentWatch.\n");
+ subscriber->id, equipment_id);
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR, "Failed to update EquipmentWatch.\n");
return 1;
}
dbi_result_free(result);
- printf("DB: Updated EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n", equipment_id, subscriber->imsi, imei);
+ DEBUGP(DDB, "Updated EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n",
+ equipment_id, subscriber->imsi, imei);
}
return 0;
@@ -788,6 +1041,33 @@ struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id)
return sms;
}
+struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, int min_subscr_id)
+{
+ dbi_result result;
+ struct gsm_sms *sms;
+
+ result = dbi_conn_queryf(conn,
+ "SELECT * FROM SMS,Subscriber "
+ "WHERE sms.receiver_id >= %llu AND sms.sent is NULL "
+ "AND sms.receiver_id = subscriber.id "
+ "AND subscriber.lac > 0 "
+ "ORDER BY sms.receiver_id, id LIMIT 1",
+ min_subscr_id);
+ if (!result)
+ return NULL;
+
+ if (!dbi_result_next_row(result)) {
+ dbi_result_free(result);
+ return NULL;
+ }
+
+ sms = sms_from_result(net, result);
+
+ dbi_result_free(result);
+
+ return sms;
+}
+
/* retrieve the next unsent SMS for a given subscriber */
struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr)
{
@@ -826,7 +1106,7 @@ int db_sms_mark_sent(struct gsm_sms *sms)
"SET sent = datetime('now') "
"WHERE id = %llu", sms->id);
if (!result) {
- printf("DB: Failed to mark SMS %llu as sent.\n", sms->id);
+ LOGP(DDB, LOGL_ERROR, "Failed to mark SMS %llu as sent.\n", sms->id);
return 1;
}
@@ -844,7 +1124,8 @@ int db_sms_inc_deliver_attempts(struct gsm_sms *sms)
"SET deliver_attempts = deliver_attempts + 1 "
"WHERE id = %llu", sms->id);
if (!result) {
- printf("DB: Failed to inc deliver attempts for SMS %llu.\n", sms->id);
+ LOGP(DDB, LOGL_ERROR, "Failed to inc deliver attempts for "
+ "SMS %llu.\n", sms->id);
return 1;
}
@@ -875,3 +1156,24 @@ int db_apdu_blob_store(struct gsm_subscriber *subscr,
dbi_result_free(result);
return 0;
}
+
+int db_store_counter(struct counter *ctr)
+{
+ dbi_result result;
+ char *q_name;
+
+ dbi_conn_quote_string_copy(conn, ctr->name, &q_name);
+
+ result = dbi_conn_queryf(conn,
+ "INSERT INTO Counters "
+ "(timestamp,name,value) VALUES "
+ "(datetime('now'),%s,%lu)", q_name, ctr->value);
+
+ free(q_name);
+
+ if (!result)
+ return -EIO;
+
+ dbi_result_free(result);
+ return 0;
+}
diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c
index 6e9213025..dabd14f43 100644
--- a/openbsc/src/debug.c
+++ b/openbsc/src/debug.c
@@ -25,23 +25,59 @@
#include <string.h>
#include <strings.h>
#include <time.h>
+#include <errno.h>
#include <openbsc/debug.h>
+#include <osmocore/talloc.h>
+#include <osmocore/utils.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/gsm_subscriber.h>
-unsigned int debug_mask = 0xffffffff & ~(DMI|DMIB|DMEAS);
+/* default categories */
+static struct debug_category default_categories[Debug_LastEntry] = {
+ [DRLL] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DCC] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DNM] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DRR] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DRSL] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DMM] = { .enabled = 1, .loglevel = LOGL_INFO },
+ [DMNCC] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DSMS] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DPAG] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DMEAS] = { .enabled = 0, .loglevel = LOGL_NOTICE },
+ [DMI] = { .enabled = 0, .loglevel = LOGL_NOTICE },
+ [DMIB] = { .enabled = 0, .loglevel = LOGL_NOTICE },
+ [DMUX] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DINP] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DSCCP] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DMSC] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DMGCP] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DHO] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DDB] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DREF] = { .enabled = 0, .loglevel = LOGL_NOTICE },
+};
struct debug_info {
const char *name;
const char *color;
const char *description;
int number;
+ int position;
+};
+
+struct debug_context {
+ struct gsm_lchan *lchan;
+ struct gsm_subscriber *subscr;
+ struct gsm_bts *bts;
};
+static struct debug_context debug_context;
+static void *tall_dbg_ctx = NULL;
+static LLIST_HEAD(target_list);
+
#define DEBUG_CATEGORY(NUMBER, NAME, COLOR, DESCRIPTION) \
{ .name = NAME, .color = COLOR, .description = DESCRIPTION, .number = NUMBER },
-#define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
-
static const struct debug_info debug_info[] = {
DEBUG_CATEGORY(DRLL, "DRLL", "\033[1;31m", "")
DEBUG_CATEGORY(DCC, "DCC", "\033[1;32m", "")
@@ -62,52 +98,82 @@ static const struct debug_info debug_info[] = {
DEBUG_CATEGORY(DMGCP, "DMGCP", "", "")
DEBUG_CATEGORY(DHO, "DHO", "", "")
DEBUG_CATEGORY(DNAT, "DNAT", "", "")
+ DEBUG_CATEGORY(DDB, "DDB", "", "")
+ DEBUG_CATEGORY(DDB, "DREF", "", "")
};
-static int use_color = 1;
+static const struct value_string loglevel_strs[] = {
+ { 0, "EVERYTHING" },
+ { 1, "DEBUG" },
+ { 3, "INFO" },
+ { 5, "NOTICE" },
+ { 7, "ERROR" },
+ { 8, "FATAL" },
+ { 0, NULL },
+};
-void debug_use_color(int color)
+int debug_parse_level(const char *lvl)
{
- use_color = color;
+ return get_string_value(loglevel_strs, lvl);
}
-static int print_timestamp = 0;
-
-void debug_timestamp(int enable)
+int debug_parse_category(const char *category)
{
- print_timestamp = enable;
-}
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(debug_info); ++i) {
+ if (!strcasecmp(debug_info[i].name+1, category))
+ return debug_info[i].number;
+ }
+ return -EINVAL;
+}
/*
* Parse the category mask.
- * category1:category2:category3
+ * The format can be this: category1:category2:category3
+ * or category1,2:category2,3:...
*/
-void debug_parse_category_mask(const char *_mask)
+void debug_parse_category_mask(struct debug_target* target, const char *_mask)
{
- unsigned int new_mask = 0;
int i = 0;
char *mask = strdup(_mask);
char *category_token = NULL;
+ /* Disable everything to enable it afterwards */
+ for (i = 0; i < ARRAY_SIZE(target->categories); ++i)
+ target->categories[i].enabled = 0;
+
category_token = strtok(mask, ":");
do {
for (i = 0; i < ARRAY_SIZE(debug_info); ++i) {
- if (strcasecmp(debug_info[i].name, category_token) == 0)
- new_mask |= debug_info[i].number;
+ char* colon = strstr(category_token, ",");
+ int length = strlen(category_token);
+
+ if (colon)
+ length = colon - category_token;
+
+ if (strncasecmp(debug_info[i].name, category_token, length) == 0) {
+ int number = debug_info[i].number;
+ int level = 0;
+
+ if (colon)
+ level = atoi(colon+1);
+
+ target->categories[number].enabled = 1;
+ target->categories[number].loglevel = level;
+ }
}
} while ((category_token = strtok(NULL, ":")));
-
free(mask);
- debug_mask = new_mask;
}
-const char* color(int subsys)
+static const char* color(int subsys)
{
int i = 0;
- for (i = 0; use_color && i < ARRAY_SIZE(debug_info); ++i) {
+ for (i = 0; i < ARRAY_SIZE(debug_info); ++i) {
if (debug_info[i].number == subsys)
return debug_info[i].color;
}
@@ -115,35 +181,111 @@ const char* color(int subsys)
return "";
}
-void debugp(unsigned int subsys, char *file, int line, int cont, const char *format, ...)
+static void _output(struct debug_target *target, unsigned int subsys, char *file, int line,
+ int cont, const char *format, va_list ap)
{
- va_list ap;
- FILE *outfd = stderr;
-
- if (!(debug_mask & subsys))
- return;
+ char col[30];
+ char sub[30];
+ char tim[30];
+ char buf[4096];
+ char final[4096];
- va_start(ap, format);
+ /* prepare the data */
+ col[0] = '\0';
+ sub[0] = '\0';
+ tim[0] = '\0';
+ buf[0] = '\0';
- fprintf(outfd, "%s", color(subsys));
+ /* are we using color */
+ if (target->use_color) {
+ snprintf(col, sizeof(col), "%s", color(subsys));
+ col[sizeof(col)-1] = '\0';
+ }
+ vsnprintf(buf, sizeof(buf), format, ap);
+ buf[sizeof(buf)-1] = '\0';
if (!cont) {
- if (print_timestamp) {
+ if (target->print_timestamp) {
char *timestr;
time_t tm;
tm = time(NULL);
timestr = ctime(&tm);
timestr[strlen(timestr)-1] = '\0';
- fprintf(outfd, "%s ", timestr);
+ snprintf(tim, sizeof(tim), "%s ", timestr);
+ tim[sizeof(tim)-1] = '\0';
+ }
+ snprintf(sub, sizeof(sub), "<%4.4x> %s:%d ", subsys, file, line);
+ sub[sizeof(sub)-1] = '\0';
+ }
+
+ snprintf(final, sizeof(final), "%s%s%s%s\033[0;m", col, tim, sub, buf);
+ final[sizeof(final)-1] = '\0';
+ target->output(target, final);
+}
+
+
+static void _debugp(unsigned int subsys, int level, char *file, int line,
+ int cont, const char *format, va_list ap)
+{
+ struct debug_target *tar;
+
+ llist_for_each_entry(tar, &target_list, entry) {
+ struct debug_category *category;
+ int output = 0;
+
+ category = &tar->categories[subsys];
+ /* subsystem is not supposed to be debugged */
+ if (!category->enabled)
+ continue;
+
+ /* Check the global log level */
+ if (tar->loglevel != 0 && level < tar->loglevel)
+ continue;
+
+ /* Check the category log level */
+ if (category->loglevel != 0 && level < category->loglevel)
+ continue;
+
+ /*
+ * Apply filters here... if that becomes messy we will need to put
+ * filters in a list and each filter will say stop, continue, output
+ */
+ if ((tar->filter_map & DEBUG_FILTER_ALL) != 0) {
+ output = 1;
+ } else if ((tar->filter_map & DEBUG_FILTER_IMSI) != 0
+ && debug_context.subscr && strcmp(debug_context.subscr->imsi, tar->imsi_filter) == 0) {
+ output = 1;
+ }
+
+ if (output) {
+ /* FIXME: copying the va_list is an ugly workaround against a bug
+ * hidden somewhere in _output. If we do not copy here, the first
+ * call to _output() will corrupt the va_list contents, and any
+ * further _output() calls with the same va_list will segfault */
+ va_list bp;
+ va_copy(bp, ap);
+ _output(tar, subsys, file, line, cont, format, bp);
+ va_end(bp);
}
- fprintf(outfd, "<%4.4x> %s:%d ", subsys, file, line);
}
- vfprintf(outfd, format, ap);
- fprintf(outfd, "\033[0;m");
+}
+
+void debugp(unsigned int subsys, char *file, int line, int cont, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ _debugp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
va_end(ap);
+}
+
+void debugp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
+{
+ va_list ap;
- fflush(outfd);
+ va_start(ap, format);
+ _debugp(subsys, level, file, line, cont, format, ap);
+ va_end(ap);
}
static char hexd_buff[4096];
@@ -165,3 +307,122 @@ char *hexdump(const unsigned char *buf, int len)
return hexd_buff;
}
+
+
+void debug_add_target(struct debug_target *target)
+{
+ llist_add_tail(&target->entry, &target_list);
+}
+
+void debug_del_target(struct debug_target *target)
+{
+ llist_del(&target->entry);
+}
+
+void debug_reset_context(void)
+{
+ memset(&debug_context, 0, sizeof(debug_context));
+}
+
+/* currently we are not reffing these */
+void debug_set_context(int ctx, void *value)
+{
+ switch (ctx) {
+ case BSC_CTX_LCHAN:
+ debug_context.lchan = (struct gsm_lchan *) value;
+ break;
+ case BSC_CTX_SUBSCR:
+ debug_context.subscr = (struct gsm_subscriber *) value;
+ break;
+ case BSC_CTX_BTS:
+ debug_context.bts = (struct gsm_bts *) value;
+ break;
+ case BSC_CTX_SCCP:
+ break;
+ default:
+ break;
+ }
+}
+
+void debug_set_imsi_filter(struct debug_target *target, const char *imsi)
+{
+ if (imsi) {
+ target->filter_map |= DEBUG_FILTER_IMSI;
+ target->imsi_filter = talloc_strdup(target, imsi);
+ } else if (target->imsi_filter) {
+ target->filter_map &= ~DEBUG_FILTER_IMSI;
+ talloc_free(target->imsi_filter);
+ target->imsi_filter = NULL;
+ }
+}
+
+void debug_set_all_filter(struct debug_target *target, int all)
+{
+ if (all)
+ target->filter_map |= DEBUG_FILTER_ALL;
+ else
+ target->filter_map &= ~DEBUG_FILTER_ALL;
+}
+
+void debug_set_use_color(struct debug_target *target, int use_color)
+{
+ target->use_color = use_color;
+}
+
+void debug_set_print_timestamp(struct debug_target *target, int print_timestamp)
+{
+ target->print_timestamp = print_timestamp;
+}
+
+void debug_set_log_level(struct debug_target *target, int log_level)
+{
+ target->loglevel = log_level;
+}
+
+void debug_set_category_filter(struct debug_target *target, int category, int enable, int level)
+{
+ if (category >= Debug_LastEntry)
+ return;
+ target->categories[category].enabled = !!enable;
+ target->categories[category].loglevel = level;
+}
+
+static void _stderr_output(struct debug_target *target, const char *log)
+{
+ fprintf(target->tgt_stdout.out, "%s", log);
+ fflush(target->tgt_stdout.out);
+}
+
+struct debug_target *debug_target_create(void)
+{
+ struct debug_target *target;
+
+ target = talloc_zero(tall_dbg_ctx, struct debug_target);
+ if (!target)
+ return NULL;
+
+ INIT_LLIST_HEAD(&target->entry);
+ memcpy(target->categories, default_categories, sizeof(default_categories));
+ target->use_color = 1;
+ target->print_timestamp = 0;
+ target->loglevel = 0;
+ return target;
+}
+
+struct debug_target *debug_target_create_stderr(void)
+{
+ struct debug_target *target;
+
+ target = debug_target_create();
+ if (!target)
+ return NULL;
+
+ target->tgt_stdout.out = stderr;
+ target->output = _stderr_output;
+ return target;
+}
+
+void debug_init(void)
+{
+ tall_dbg_ctx = talloc_named_const(NULL, 1, "debug");
+}
diff --git a/openbsc/src/e1_config.c b/openbsc/src/e1_config.c
index 6a2abd85b..50fbceccd 100644
--- a/openbsc/src/e1_config.c
+++ b/openbsc/src/e1_config.c
@@ -9,7 +9,7 @@
#include <openbsc/trau_mux.h>
#include <openbsc/misdn.h>
#include <openbsc/ipaccess.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/debug.h>
#define SAPI_L2ML 0
diff --git a/openbsc/src/e1_input.c b/openbsc/src/e1_input.c
index 083d8f8de..c20359c09 100644
--- a/openbsc/src/e1_input.c
+++ b/openbsc/src/e1_input.c
@@ -40,18 +40,18 @@
#define PF_ISDN AF_ISDN
#endif
-#include <openbsc/select.h>
-#include <openbsc/msgb.h>
+#include <osmocore/select.h>
+#include <osmocore/msgb.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 <openbsc/linuxlist.h>
+#include <osmocore/linuxlist.h>
#include <openbsc/subchan_demux.h>
#include <openbsc/trau_frame.h>
#include <openbsc/trau_mux.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/signal.h>
#include <openbsc/misdn.h>
@@ -234,10 +234,16 @@ int abis_rsl_sendmsg(struct msgb *msg)
msg->l2h = msg->data;
- if (!msg->trx || !msg->trx->rsl_link) {
- LOGP(DRSL, LOGL_ERROR, "rsl_sendmsg: msg->trx == NULL\n");
+ if (!msg->trx) {
+ LOGP(DRSL, LOGL_ERROR, "rsl_sendmsg: msg->trx == NULL: %s\n",
+ hexdump(msg->data, msg->len));
talloc_free(msg);
return -EINVAL;
+ } else if (!msg->trx->rsl_link) {
+ LOGP(DRSL, LOGL_ERROR, "rsl_sendmsg: msg->trx->rsl_link == NULL: %s\n",
+ hexdump(msg->data, msg->len));
+ talloc_free(msg);
+ return -EIO;
}
sign_link = msg->trx->rsl_link;
@@ -435,6 +441,8 @@ int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg,
"tei %d, sapi %d\n", tei, sapi);
return -EINVAL;
}
+
+ debug_set_context(BSC_CTX_BTS, link->trx->bts);
switch (link->type) {
case E1INP_SIGN_OML:
msg->trx = link->trx;
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index 0e419742e..e57ef4f59 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -31,12 +31,12 @@
#include <netinet/in.h>
#include <openbsc/db.h>
-#include <openbsc/msgb.h>
-#include <openbsc/bitvec.h>
-#include <openbsc/tlv.h>
+#include <osmocore/msgb.h>
+#include <osmocore/bitvec.h>
+#include <osmocore/tlv.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_utils.h>
+#include <osmocore/gsm_utils.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/gsm_04_11.h>
#include <openbsc/gsm_04_08.h>
@@ -47,124 +47,14 @@
#include <openbsc/trau_frame.h>
#include <openbsc/trau_mux.h>
#include <openbsc/rtp_proxy.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
+#include <osmocore/gsm48.h>
#include <openbsc/transaction.h>
#include <openbsc/ussd.h>
-
-#define GSM_MAX_FACILITY 128
-#define GSM_MAX_SSVERSION 128
-#define GSM_MAX_USERUSER 128
+#include <openbsc/silent_call.h>
void *tall_locop_ctx;
-static const struct tlv_definition rsl_att_tlvdef = {
- .def = {
- [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV },
- [GSM48_IE_NAME_LONG] = { TLV_TYPE_TLV },
- [GSM48_IE_NAME_SHORT] = { TLV_TYPE_TLV },
- [GSM48_IE_UTC] = { TLV_TYPE_TV },
- [GSM48_IE_NET_TIME_TZ] = { TLV_TYPE_FIXED, 7 },
- [GSM48_IE_LSA_IDENT] = { TLV_TYPE_TLV },
-
- [GSM48_IE_BEARER_CAP] = { TLV_TYPE_TLV },
- [GSM48_IE_CAUSE] = { TLV_TYPE_TLV },
- [GSM48_IE_CC_CAP] = { TLV_TYPE_TLV },
- [GSM48_IE_ALERT] = { TLV_TYPE_TLV },
- [GSM48_IE_FACILITY] = { TLV_TYPE_TLV },
- [GSM48_IE_PROGR_IND] = { TLV_TYPE_TLV },
- [GSM48_IE_AUX_STATUS] = { TLV_TYPE_TLV },
- [GSM48_IE_NOTIFY] = { TLV_TYPE_TV },
- [GSM48_IE_KPD_FACILITY] = { TLV_TYPE_TV },
- [GSM48_IE_SIGNAL] = { TLV_TYPE_TV },
- [GSM48_IE_CONN_BCD] = { TLV_TYPE_TLV },
- [GSM48_IE_CONN_SUB] = { TLV_TYPE_TLV },
- [GSM48_IE_CALLING_BCD] = { TLV_TYPE_TLV },
- [GSM48_IE_CALLING_SUB] = { TLV_TYPE_TLV },
- [GSM48_IE_CALLED_BCD] = { TLV_TYPE_TLV },
- [GSM48_IE_CALLED_SUB] = { TLV_TYPE_TLV },
- [GSM48_IE_REDIR_BCD] = { TLV_TYPE_TLV },
- [GSM48_IE_REDIR_SUB] = { TLV_TYPE_TLV },
- [GSM48_IE_LOWL_COMPAT] = { TLV_TYPE_TLV },
- [GSM48_IE_HIGHL_COMPAT] = { TLV_TYPE_TLV },
- [GSM48_IE_USER_USER] = { TLV_TYPE_TLV },
- [GSM48_IE_SS_VERS] = { TLV_TYPE_TLV },
- [GSM48_IE_MORE_DATA] = { TLV_TYPE_T },
- [GSM48_IE_CLIR_SUPP] = { TLV_TYPE_T },
- [GSM48_IE_CLIR_INVOC] = { TLV_TYPE_T },
- [GSM48_IE_REV_C_SETUP] = { TLV_TYPE_T },
- [GSM48_IE_REPEAT_CIR] = { TLV_TYPE_T },
- [GSM48_IE_REPEAT_SEQ] = { TLV_TYPE_T },
- /* FIXME: more elements */
- },
-};
-
-static const char *rr_cause_names[] = {
- [GSM48_RR_CAUSE_NORMAL] = "Normal event",
- [GSM48_RR_CAUSE_ABNORMAL_UNSPEC] = "Abnormal release, unspecified",
- [GSM48_RR_CAUSE_ABNORMAL_UNACCT] = "Abnormal release, channel unacceptable",
- [GSM48_RR_CAUSE_ABNORMAL_TIMER] = "Abnormal release, timer expired",
- [GSM48_RR_CAUSE_ABNORMAL_NOACT] = "Abnormal release, no activity on radio path",
- [GSM48_RR_CAUSE_PREMPTIVE_REL] = "Preemptive release",
- [GSM48_RR_CAUSE_HNDOVER_IMP] = "Handover impossible, timing advance out of range",
- [GSM48_RR_CAUSE_CHAN_MODE_UNACCT] = "Channel mode unacceptable",
- [GSM48_RR_CAUSE_FREQ_NOT_IMPL] = "Frequency not implemented",
- [GSM48_RR_CAUSE_CALL_CLEARED] = "Call already cleared",
- [GSM48_RR_CAUSE_SEMANT_INCORR] = "Semantically incorrect message",
- [GSM48_RR_CAUSE_INVALID_MAND_INF] = "Invalid mandatory information",
- [GSM48_RR_CAUSE_MSG_TYPE_N] = "Message type non-existant or not implemented",
- [GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT] = "Message type not compatible with protocol state",
- [GSM48_RR_CAUSE_COND_IE_ERROR] = "Conditional IE error",
- [GSM48_RR_CAUSE_NO_CELL_ALLOC_A] = "No cell allocation available",
- [GSM48_RR_CAUSE_PROT_ERROR_UNSPC] = "Protocol error unspecified",
-};
-
-static const char *cc_state_names[] = {
- "NULL",
- "INITIATED",
- "illegal state 2",
- "MO_CALL_PROC",
- "CALL_DELIVERED",
- "illegal state 5",
- "CALL_PRESENT",
- "CALL_RECEIVED",
- "CONNECT_REQUEST",
- "MO_TERM_CALL_CONF",
- "ACTIVE",
- "DISCONNECT_REQ",
- "DISCONNECT_IND",
- "illegal state 13",
- "illegal state 14",
- "illegal state 15",
- "illegal state 16",
- "illegal state 17",
- "illegal state 18",
- "RELEASE_REQ",
- "illegal state 20",
- "illegal state 21",
- "illegal state 22",
- "illegal state 23",
- "illegal state 24",
- "illegal state 25",
- "MO_ORIG_MODIFY",
- "MO_TERM_MODIFY",
- "CONNECT_IND",
- "illegal state 29",
- "illegal state 30",
- "illegal state 31",
-};
-
-static char strbuf[64];
-
-static const char *rr_cause_name(u_int8_t cause)
-{
- if (cause < ARRAY_SIZE(rr_cause_names) &&
- rr_cause_names[cause])
- return rr_cause_names[cause];
-
- snprintf(strbuf, sizeof(strbuf), "0x%02x", cause);
- return strbuf;
-}
-
int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi);
static int gsm48_tx_simple(struct gsm_lchan *lchan,
u_int8_t pdisc, u_int8_t msg_type);
@@ -280,539 +170,6 @@ static int gsm0408_handle_lchan_signal(unsigned int subsys, unsigned int signal,
return 0;
}
-static const char bcd_num_digits[] = {
- '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', '*', '#', 'a', 'b', 'c', '\0'
-};
-
-/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */
-int decode_bcd_number(char *output, int output_len, const u_int8_t *bcd_lv,
- int h_len)
-{
- u_int8_t in_len = bcd_lv[0];
- int i;
-
- for (i = 1 + h_len; i <= in_len; i++) {
- /* lower nibble */
- output_len--;
- if (output_len <= 1)
- break;
- *output++ = bcd_num_digits[bcd_lv[i] & 0xf];
-
- /* higher nibble */
- output_len--;
- if (output_len <= 1)
- break;
- *output++ = bcd_num_digits[bcd_lv[i] >> 4];
- }
- if (output_len >= 1)
- *output++ = '\0';
-
- return 0;
-}
-
-/* convert a single ASCII character to call-control BCD */
-static int asc_to_bcd(const char asc)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(bcd_num_digits); i++) {
- if (bcd_num_digits[i] == asc)
- return i;
- }
- return -EINVAL;
-}
-
-/* convert a ASCII phone number to 'called/calling/connect party BCD number' */
-int encode_bcd_number(u_int8_t *bcd_lv, u_int8_t max_len,
- int h_len, const char *input)
-{
- int in_len = strlen(input);
- int i;
- u_int8_t *bcd_cur = bcd_lv + 1 + h_len;
-
- /* two digits per byte, plus type byte */
- bcd_lv[0] = in_len/2 + h_len;
- if (in_len % 2)
- bcd_lv[0]++;
-
- if (bcd_lv[0] > max_len)
- return -EIO;
-
- for (i = 0; i < in_len; i++) {
- int rc = asc_to_bcd(input[i]);
- if (rc < 0)
- return rc;
- if (i % 2 == 0)
- *bcd_cur = rc;
- else
- *bcd_cur++ |= (rc << 4);
- }
- /* append padding nibble in case of odd length */
- if (i % 2)
- *bcd_cur++ |= 0xf0;
-
- /* return how many bytes we used */
- return (bcd_cur - bcd_lv);
-}
-
-/* decode 'bearer capability' */
-static int decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap,
- const u_int8_t *lv)
-{
- u_int8_t in_len = lv[0];
- int i, s;
-
- if (in_len < 1)
- return -EINVAL;
-
- bcap->speech_ver[0] = -1; /* end of list, of maximum 7 values */
-
- /* octet 3 */
- bcap->transfer = lv[1] & 0x07;
- bcap->mode = (lv[1] & 0x08) >> 3;
- bcap->coding = (lv[1] & 0x10) >> 4;
- bcap->radio = (lv[1] & 0x60) >> 5;
-
- if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) {
- i = 1;
- s = 0;
- while(!(lv[i] & 0x80)) {
- i++; /* octet 3a etc */
- if (in_len < i)
- return 0;
- bcap->speech_ver[s++] = lv[i] & 0x0f;
- bcap->speech_ver[s] = -1; /* end of list */
- if (i == 2) /* octet 3a */
- bcap->speech_ctm = (lv[i] & 0x20) >> 5;
- if (s == 7) /* maximum speech versions + end of list */
- return 0;
- }
- } else {
- i = 1;
- while (!(lv[i] & 0x80)) {
- i++; /* octet 3a etc */
- if (in_len < i)
- return 0;
- /* ignore them */
- }
- /* FIXME: implement OCTET 4+ parsing */
- }
-
- return 0;
-}
-
-/* encode 'bearer capability' */
-static int encode_bearer_cap(struct msgb *msg, int lv_only,
- const struct gsm_mncc_bearer_cap *bcap)
-{
- u_int8_t lv[32 + 1];
- int i = 1, s;
-
- lv[1] = bcap->transfer;
- lv[1] |= bcap->mode << 3;
- lv[1] |= bcap->coding << 4;
- lv[1] |= bcap->radio << 5;
-
- if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) {
- for (s = 0; bcap->speech_ver[s] >= 0; s++) {
- i++; /* octet 3a etc */
- lv[i] = bcap->speech_ver[s];
- if (i == 2) /* octet 3a */
- lv[i] |= bcap->speech_ctm << 5;
- }
- lv[i] |= 0x80; /* last IE of octet 3 etc */
- } else {
- /* FIXME: implement OCTET 4+ encoding */
- }
-
- lv[0] = i;
- if (lv_only)
- msgb_lv_put(msg, lv[0], lv+1);
- else
- msgb_tlv_put(msg, GSM48_IE_BEARER_CAP, lv[0], lv+1);
-
- return 0;
-}
-
-/* decode 'call control cap' */
-static int decode_cccap(struct gsm_mncc_cccap *ccap, const u_int8_t *lv)
-{
- u_int8_t in_len = lv[0];
-
- if (in_len < 1)
- return -EINVAL;
-
- /* octet 3 */
- ccap->dtmf = lv[1] & 0x01;
- ccap->pcp = (lv[1] & 0x02) >> 1;
-
- return 0;
-}
-
-/* decode 'called party BCD number' */
-static int decode_called(struct gsm_mncc_number *called,
- const u_int8_t *lv)
-{
- u_int8_t in_len = lv[0];
-
- if (in_len < 1)
- return -EINVAL;
-
- /* octet 3 */
- called->plan = lv[1] & 0x0f;
- called->type = (lv[1] & 0x70) >> 4;
-
- /* octet 4..N */
- decode_bcd_number(called->number, sizeof(called->number), lv, 1);
-
- return 0;
-}
-
-/* encode 'called party BCD number' */
-static int encode_called(struct msgb *msg,
- const struct gsm_mncc_number *called)
-{
- u_int8_t lv[18];
- int ret;
-
- /* octet 3 */
- lv[1] = called->plan;
- lv[1] |= called->type << 4;
-
- /* octet 4..N, octet 2 */
- ret = encode_bcd_number(lv, sizeof(lv), 1, called->number);
- if (ret < 0)
- return ret;
-
- msgb_tlv_put(msg, GSM48_IE_CALLED_BCD, lv[0], lv+1);
-
- return 0;
-}
-
-/* encode callerid of various IEs */
-static int encode_callerid(struct msgb *msg, int ie,
- const struct gsm_mncc_number *callerid)
-{
- u_int8_t lv[13];
- int h_len = 1;
- int ret;
-
- /* octet 3 */
- lv[1] = callerid->plan;
- lv[1] |= callerid->type << 4;
-
- if (callerid->present || callerid->screen) {
- /* octet 3a */
- lv[2] = callerid->screen;
- lv[2] |= callerid->present << 5;
- lv[2] |= 0x80;
- h_len++;
- } else
- lv[1] |= 0x80;
-
- /* octet 4..N, octet 2 */
- ret = encode_bcd_number(lv, sizeof(lv), h_len, callerid->number);
- if (ret < 0)
- return ret;
-
- msgb_tlv_put(msg, ie, lv[0], lv+1);
-
- return 0;
-}
-
-/* decode 'cause' */
-static int decode_cause(struct gsm_mncc_cause *cause,
- const u_int8_t *lv)
-{
- u_int8_t in_len = lv[0];
- int i;
-
- if (in_len < 2)
- return -EINVAL;
-
- cause->diag_len = 0;
-
- /* octet 3 */
- cause->location = lv[1] & 0x0f;
- cause->coding = (lv[1] & 0x60) >> 5;
-
- i = 1;
- if (!(lv[i] & 0x80)) {
- i++; /* octet 3a */
- if (in_len < i+1)
- return 0;
- cause->rec = 1;
- cause->rec_val = lv[i] & 0x7f;
-
- }
- i++;
-
- /* octet 4 */
- cause->value = lv[i] & 0x7f;
- i++;
-
- if (in_len < i) /* no diag */
- return 0;
-
- if (in_len - (i-1) > 32) /* maximum 32 octets */
- return 0;
-
- /* octet 5-N */
- memcpy(cause->diag, lv + i, in_len - (i-1));
- cause->diag_len = in_len - (i-1);
-
- return 0;
-}
-
-/* encode 'cause' */
-static int encode_cause(struct msgb *msg, int lv_only,
- const struct gsm_mncc_cause *cause)
-{
- u_int8_t lv[32+4];
- int i;
-
- if (cause->diag_len > 32)
- return -EINVAL;
-
- /* octet 3 */
- lv[1] = cause->location;
- lv[1] |= cause->coding << 5;
-
- i = 1;
- if (cause->rec) {
- i++; /* octet 3a */
- lv[i] = cause->rec_val;
- }
- lv[i] |= 0x80; /* end of octet 3 */
-
- /* octet 4 */
- i++;
- lv[i] = 0x80 | cause->value;
-
- /* octet 5-N */
- if (cause->diag_len) {
- memcpy(lv + i, cause->diag, cause->diag_len);
- i += cause->diag_len;
- }
-
- lv[0] = i;
- if (lv_only)
- msgb_lv_put(msg, lv[0], lv+1);
- else
- msgb_tlv_put(msg, GSM48_IE_CAUSE, lv[0], lv+1);
-
- return 0;
-}
-
-/* encode 'calling number' */
-static int encode_calling(struct msgb *msg,
- const struct gsm_mncc_number *calling)
-{
- return encode_callerid(msg, GSM48_IE_CALLING_BCD, calling);
-}
-
-/* encode 'connected number' */
-static int encode_connected(struct msgb *msg,
- const struct gsm_mncc_number *connected)
-{
- return encode_callerid(msg, GSM48_IE_CONN_BCD, connected);
-}
-
-/* encode 'redirecting number' */
-static int encode_redirecting(struct msgb *msg,
- const struct gsm_mncc_number *redirecting)
-{
- return encode_callerid(msg, GSM48_IE_REDIR_BCD, redirecting);
-}
-
-/* decode 'facility' */
-static int decode_facility(struct gsm_mncc_facility *facility,
- const u_int8_t *lv)
-{
- u_int8_t in_len = lv[0];
-
- if (in_len < 1)
- return -EINVAL;
-
- if (in_len > sizeof(facility->info))
- return -EINVAL;
-
- memcpy(facility->info, lv+1, in_len);
- facility->len = in_len;
-
- return 0;
-}
-
-/* encode 'facility' */
-static int encode_facility(struct msgb *msg, int lv_only,
- const struct gsm_mncc_facility *facility)
-{
- u_int8_t lv[GSM_MAX_FACILITY + 1];
-
- if (facility->len < 1 || facility->len > GSM_MAX_FACILITY)
- return -EINVAL;
-
- memcpy(lv+1, facility->info, facility->len);
- lv[0] = facility->len;
- if (lv_only)
- msgb_lv_put(msg, lv[0], lv+1);
- else
- msgb_tlv_put(msg, GSM48_IE_FACILITY, lv[0], lv+1);
-
- return 0;
-}
-
-/* decode 'notify' */
-static int decode_notify(int *notify, const u_int8_t *v)
-{
- *notify = v[0] & 0x7f;
-
- return 0;
-}
-
-/* encode 'notify' */
-static int encode_notify(struct msgb *msg, int notify)
-{
- msgb_v_put(msg, notify | 0x80);
-
- return 0;
-}
-
-/* encode 'signal' */
-static int encode_signal(struct msgb *msg, int signal)
-{
- msgb_tv_put(msg, GSM48_IE_SIGNAL, signal);
-
- return 0;
-}
-
-/* decode 'keypad' */
-static int decode_keypad(int *keypad, const u_int8_t *lv)
-{
- u_int8_t in_len = lv[0];
-
- if (in_len < 1)
- return -EINVAL;
-
- *keypad = lv[1] & 0x7f;
-
- return 0;
-}
-
-/* encode 'keypad' */
-static int encode_keypad(struct msgb *msg, int keypad)
-{
- msgb_tv_put(msg, GSM48_IE_KPD_FACILITY, keypad);
-
- return 0;
-}
-
-/* decode 'progress' */
-static int decode_progress(struct gsm_mncc_progress *progress,
- const u_int8_t *lv)
-{
- u_int8_t in_len = lv[0];
-
- if (in_len < 2)
- return -EINVAL;
-
- progress->coding = (lv[1] & 0x60) >> 5;
- progress->location = lv[1] & 0x0f;
- progress->descr = lv[2] & 0x7f;
-
- return 0;
-}
-
-/* encode 'progress' */
-static int encode_progress(struct msgb *msg, int lv_only,
- const struct gsm_mncc_progress *p)
-{
- u_int8_t lv[3];
-
- lv[0] = 2;
- lv[1] = 0x80 | ((p->coding & 0x3) << 5) | (p->location & 0xf);
- lv[2] = 0x80 | (p->descr & 0x7f);
- if (lv_only)
- msgb_lv_put(msg, lv[0], lv+1);
- else
- msgb_tlv_put(msg, GSM48_IE_PROGR_IND, lv[0], lv+1);
-
- return 0;
-}
-
-/* decode 'user-user' */
-static int decode_useruser(struct gsm_mncc_useruser *uu,
- const u_int8_t *lv)
-{
- u_int8_t in_len = lv[0];
- char *info = uu->info;
- int info_len = sizeof(uu->info);
- int i;
-
- if (in_len < 1)
- return -EINVAL;
-
- uu->proto = lv[1];
-
- for (i = 2; i <= in_len; i++) {
- info_len--;
- if (info_len <= 1)
- break;
- *info++ = lv[i];
- }
- if (info_len >= 1)
- *info++ = '\0';
-
- return 0;
-}
-
-/* encode 'useruser' */
-static int encode_useruser(struct msgb *msg, int lv_only,
- const struct gsm_mncc_useruser *uu)
-{
- u_int8_t lv[GSM_MAX_USERUSER + 2];
-
- if (strlen(uu->info) > GSM_MAX_USERUSER)
- return -EINVAL;
-
- lv[0] = 1 + strlen(uu->info);
- lv[1] = uu->proto;
- memcpy(lv + 2, uu->info, strlen(uu->info));
- if (lv_only)
- msgb_lv_put(msg, lv[0], lv+1);
- else
- msgb_tlv_put(msg, GSM48_IE_USER_USER, lv[0], lv+1);
-
- return 0;
-}
-
-/* decode 'ss version' */
-static int decode_ssversion(struct gsm_mncc_ssversion *ssv,
- const u_int8_t *lv)
-{
- u_int8_t in_len = lv[0];
-
- if (in_len < 1 || in_len < sizeof(ssv->info))
- return -EINVAL;
-
- memcpy(ssv->info, lv + 1, in_len);
- ssv->len = in_len;
-
- return 0;
-}
-
-/* encode 'more data' */
-static int encode_more(struct msgb *msg)
-{
- u_int8_t *ie;
-
- ie = msgb_put(msg, 1);
- ie[0] = GSM48_IE_MORE_DATA;
-
- return 0;
-}
-
/* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */
int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause)
{
@@ -827,9 +184,12 @@ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause)
gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
gh->data[0] = cause;
- DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr);
+ LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT "
+ "LAC=%u BTS=%u\n", lchan->subscr ?
+ subscr_name(lchan->subscr) : "unknown",
+ lchan->ts->trx->bts->location_area_code, lchan->ts->trx->bts->nr);
- bts->network->stats.loc_upd_resp.reject++;
+ counter_inc(bts->network->stats.loc_upd_resp.reject);
return gsm48_sendmsg(msg, NULL);
}
@@ -850,7 +210,7 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi)
gh->msg_type = GSM48_MT_MM_LOC_UPD_ACCEPT;
lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
- gsm0408_generate_lai(lai, bts->network->country_code,
+ gsm48_generate_lai(lai, bts->network->country_code,
bts->network->network_code, bts->location_area_code);
mid = msgb_put(msg, GSM48_MID_TMSI_LEN);
@@ -858,7 +218,7 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi)
DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n");
- bts->network->stats.loc_upd_resp.accept++;
+ counter_inc(bts->network->stats.loc_upd_resp.accept);
return gsm48_sendmsg(msg, NULL);
}
@@ -979,13 +339,13 @@ static int mm_rx_loc_upd_req(struct msgb *msg)
switch (lu->type) {
case GSM48_LUPD_NORMAL:
- bts->network->stats.loc_upd_type.normal++;
+ counter_inc(bts->network->stats.loc_upd_type.normal);
break;
case GSM48_LUPD_IMSI_ATT:
- bts->network->stats.loc_upd_type.attach++;
+ counter_inc(bts->network->stats.loc_upd_type.attach);
break;
case GSM48_LUPD_PERIODIC:
- bts->network->stats.loc_upd_type.periodic++;
+ counter_inc(bts->network->stats.loc_upd_type.periodic);
break;
}
@@ -1168,20 +528,19 @@ int gsm48_tx_mm_info(struct gsm_lchan *lchan)
}
/* Section 9.2.2 */
-int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand)
+int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand, int key_seq)
{
struct msgb *msg = gsm48_msgb_alloc();
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
struct gsm48_auth_req *ar = (struct gsm48_auth_req *) msgb_put(msg, sizeof(*ar));
- DEBUGP(DMM, "-> AUTH REQ\n");
+ DEBUGP(DMM, "-> AUTH REQ (rand = %s)\n", hexdump(rand, 16));
msg->lchan = lchan;
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_AUTH_REQ;
- /* Key Sequence: FIXME fixed to 0 */
- ar->key_seq = 0;
+ ar->key_seq = key_seq;
/* 16 bytes RAND parameters */
if (rand)
@@ -1315,7 +674,7 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ",
mi_type, mi_string);
- bts->network->stats.loc_upd_type.detach++;
+ counter_inc(bts->network->stats.loc_upd_type.detach);
switch (mi_type) {
case GSM_MI_TYPE_TMSI:
@@ -1338,8 +697,7 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
if (subscr) {
subscr_update(subscr, msg->trx->bts,
GSM_SUBSCRIBER_UPDATE_DETACHED);
- DEBUGP(DMM, "Subscriber: %s\n",
- subscr->name ? subscr->name : subscr->imsi);
+ DEBUGP(DMM, "Subscriber: %s\n", subscr_name(subscr));
subscr->equipment.classmark1 = idi->classmark1;
db_sync_equipment(&subscr->equipment);
@@ -1387,7 +745,7 @@ static int gsm0408_rcv_mm(struct msgb *msg)
case GSM48_MT_MM_TMSI_REALL_COMPL:
DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n",
msg->lchan->subscr ?
- msg->lchan->subscr->imsi :
+ subscr_name(msg->lchan->subscr) :
"unknown subscriber");
break;
case GSM48_MT_MM_IMSI_DETACH_IND:
@@ -1400,7 +758,7 @@ static int gsm0408_rcv_mm(struct msgb *msg)
DEBUGP(DMM, "AUTHENTICATION RESPONSE: Not implemented\n");
break;
default:
- fprintf(stderr, "Unknown GSM 04.08 MM msg type 0x%02x\n",
+ LOGP(DMM, LOGL_NOTICE, "Unknown GSM 04.08 MM msg type 0x%02x\n",
gh->msg_type);
break;
}
@@ -1603,8 +961,8 @@ static int gsm0408_rcv_rr(struct msgb *msg)
rc = gsm48_rx_rr_ho_fail(msg);
break;
default:
- fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n",
- gh->msg_type);
+ LOGP(DRR, LOGL_NOTICE, "Unimplemented "
+ "GSM 04.08 RR msg type 0x%02x\n", gh->msg_type);
break;
}
@@ -2085,7 +1443,7 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
memset(&setup, 0, sizeof(struct gsm_mncc));
setup.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
/* emergency setup is identified by msg_type */
if (msg_type == GSM48_MT_CC_EMERG_SETUP)
setup.emergency = 1;
@@ -2101,31 +1459,31 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
/* bearer capability */
if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
setup.fields |= MNCC_F_BEARER_CAP;
- decode_bearer_cap(&setup.bearer_cap,
+ gsm48_decode_bearer_cap(&setup.bearer_cap,
TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
}
/* facility */
if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
setup.fields |= MNCC_F_FACILITY;
- decode_facility(&setup.facility,
+ gsm48_decode_facility(&setup.facility,
TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
}
/* called party bcd number */
if (TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) {
setup.fields |= MNCC_F_CALLED;
- decode_called(&setup.called,
+ gsm48_decode_called(&setup.called,
TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1);
}
/* user-user */
if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
setup.fields |= MNCC_F_USERUSER;
- decode_useruser(&setup.useruser,
+ gsm48_decode_useruser(&setup.useruser,
TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
}
/* ss-version */
if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
setup.fields |= MNCC_F_SSVERSION;
- decode_ssversion(&setup.ssversion,
+ gsm48_decode_ssversion(&setup.ssversion,
TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
}
/* CLIR suppression */
@@ -2137,12 +1495,16 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
/* cc cap */
if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
setup.fields |= MNCC_F_CCCAP;
- decode_cccap(&setup.cccap,
+ gsm48_decode_cccap(&setup.cccap,
TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
}
new_cc_state(trans, GSM_CSTATE_INITIATED);
+ LOGP(DCC, LOGL_INFO, "Subscriber %s (%s) sends SETUP to %s\n",
+ subscr_name(trans->subscr), trans->subscr->extension,
+ setup.called.number);
+
/* indicate setup to MNCC */
mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_IND, &setup);
@@ -2193,28 +1555,28 @@ static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg)
/* bearer capability */
if (setup->fields & MNCC_F_BEARER_CAP)
- encode_bearer_cap(msg, 0, &setup->bearer_cap);
+ gsm48_encode_bearer_cap(msg, 0, &setup->bearer_cap);
/* facility */
if (setup->fields & MNCC_F_FACILITY)
- encode_facility(msg, 0, &setup->facility);
+ gsm48_encode_facility(msg, 0, &setup->facility);
/* progress */
if (setup->fields & MNCC_F_PROGRESS)
- encode_progress(msg, 0, &setup->progress);
+ gsm48_encode_progress(msg, 0, &setup->progress);
/* calling party BCD number */
if (setup->fields & MNCC_F_CALLING)
- encode_calling(msg, &setup->calling);
+ gsm48_encode_calling(msg, &setup->calling);
/* called party BCD number */
if (setup->fields & MNCC_F_CALLED)
- encode_called(msg, &setup->called);
+ gsm48_encode_called(msg, &setup->called);
/* user-user */
if (setup->fields & MNCC_F_USERUSER)
- encode_useruser(msg, 0, &setup->useruser);
+ gsm48_encode_useruser(msg, 0, &setup->useruser);
/* redirecting party BCD number */
if (setup->fields & MNCC_F_REDIRECTING)
- encode_redirecting(msg, &setup->redirecting);
+ gsm48_encode_redirecting(msg, &setup->redirecting);
/* signal */
if (setup->fields & MNCC_F_SIGNAL)
- encode_signal(msg, setup->signal);
+ gsm48_encode_signal(msg, setup->signal);
new_cc_state(trans, GSM_CSTATE_CALL_PRESENT);
@@ -2233,7 +1595,7 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
memset(&call_conf, 0, sizeof(struct gsm_mncc));
call_conf.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
#if 0
/* repeat */
if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_CIR))
@@ -2244,19 +1606,19 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg)
/* bearer capability */
if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
call_conf.fields |= MNCC_F_BEARER_CAP;
- decode_bearer_cap(&call_conf.bearer_cap,
+ gsm48_decode_bearer_cap(&call_conf.bearer_cap,
TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
}
/* cause */
if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
call_conf.fields |= MNCC_F_CAUSE;
- decode_cause(&call_conf.cause,
+ gsm48_decode_cause(&call_conf.cause,
TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
}
/* cc cap */
if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
call_conf.fields |= MNCC_F_CCCAP;
- decode_cccap(&call_conf.cccap,
+ gsm48_decode_cccap(&call_conf.cccap,
TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
}
@@ -2278,13 +1640,13 @@ static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg)
/* bearer capability */
if (proceeding->fields & MNCC_F_BEARER_CAP)
- encode_bearer_cap(msg, 0, &proceeding->bearer_cap);
+ gsm48_encode_bearer_cap(msg, 0, &proceeding->bearer_cap);
/* facility */
if (proceeding->fields & MNCC_F_FACILITY)
- encode_facility(msg, 0, &proceeding->facility);
+ gsm48_encode_facility(msg, 0, &proceeding->facility);
/* progress */
if (proceeding->fields & MNCC_F_PROGRESS)
- encode_progress(msg, 0, &proceeding->progress);
+ gsm48_encode_progress(msg, 0, &proceeding->progress);
return gsm48_sendmsg(msg, trans);
}
@@ -2301,24 +1663,24 @@ static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
memset(&alerting, 0, sizeof(struct gsm_mncc));
alerting.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
/* facility */
if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
alerting.fields |= MNCC_F_FACILITY;
- decode_facility(&alerting.facility,
+ gsm48_decode_facility(&alerting.facility,
TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
}
/* progress */
if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
alerting.fields |= MNCC_F_PROGRESS;
- decode_progress(&alerting.progress,
+ gsm48_decode_progress(&alerting.progress,
TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
}
/* ss-version */
if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
alerting.fields |= MNCC_F_SSVERSION;
- decode_ssversion(&alerting.ssversion,
+ gsm48_decode_ssversion(&alerting.ssversion,
TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
}
@@ -2338,13 +1700,13 @@ static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg)
/* facility */
if (alerting->fields & MNCC_F_FACILITY)
- encode_facility(msg, 0, &alerting->facility);
+ gsm48_encode_facility(msg, 0, &alerting->facility);
/* progress */
if (alerting->fields & MNCC_F_PROGRESS)
- encode_progress(msg, 0, &alerting->progress);
+ gsm48_encode_progress(msg, 0, &alerting->progress);
/* user-user */
if (alerting->fields & MNCC_F_USERUSER)
- encode_useruser(msg, 0, &alerting->useruser);
+ gsm48_encode_useruser(msg, 0, &alerting->useruser);
new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED);
@@ -2360,10 +1722,10 @@ static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg)
gh->msg_type = GSM48_MT_CC_PROGRESS;
/* progress */
- encode_progress(msg, 1, &progress->progress);
+ gsm48_encode_progress(msg, 1, &progress->progress);
/* user-user */
if (progress->fields & MNCC_F_USERUSER)
- encode_useruser(msg, 0, &progress->useruser);
+ gsm48_encode_useruser(msg, 0, &progress->useruser);
return gsm48_sendmsg(msg, trans);
}
@@ -2381,16 +1743,16 @@ static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg)
/* facility */
if (connect->fields & MNCC_F_FACILITY)
- encode_facility(msg, 0, &connect->facility);
+ gsm48_encode_facility(msg, 0, &connect->facility);
/* progress */
if (connect->fields & MNCC_F_PROGRESS)
- encode_progress(msg, 0, &connect->progress);
+ gsm48_encode_progress(msg, 0, &connect->progress);
/* connected number */
if (connect->fields & MNCC_F_CONNECTED)
- encode_connected(msg, &connect->connected);
+ gsm48_encode_connected(msg, &connect->connected);
/* user-user */
if (connect->fields & MNCC_F_USERUSER)
- encode_useruser(msg, 0, &connect->useruser);
+ gsm48_encode_useruser(msg, 0, &connect->useruser);
new_cc_state(trans, GSM_CSTATE_CONNECT_IND);
@@ -2408,7 +1770,7 @@ static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg)
memset(&connect, 0, sizeof(struct gsm_mncc));
connect.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
/* use subscriber as connected party number */
if (trans->subscr) {
connect.fields |= MNCC_F_CONNECTED;
@@ -2420,19 +1782,19 @@ static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg)
/* facility */
if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
connect.fields |= MNCC_F_FACILITY;
- decode_facility(&connect.facility,
+ gsm48_decode_facility(&connect.facility,
TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
}
/* user-user */
if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
connect.fields |= MNCC_F_USERUSER;
- decode_useruser(&connect.useruser,
+ gsm48_decode_useruser(&connect.useruser,
TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
}
/* ss-version */
if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
connect.fields |= MNCC_F_SSVERSION;
- decode_ssversion(&connect.ssversion,
+ gsm48_decode_ssversion(&connect.ssversion,
TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
}
@@ -2481,29 +1843,29 @@ static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg)
memset(&disc, 0, sizeof(struct gsm_mncc));
disc.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0);
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0);
/* cause */
if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
disc.fields |= MNCC_F_CAUSE;
- decode_cause(&disc.cause,
+ gsm48_decode_cause(&disc.cause,
TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
}
/* facility */
if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
disc.fields |= MNCC_F_FACILITY;
- decode_facility(&disc.facility,
+ gsm48_decode_facility(&disc.facility,
TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
}
/* user-user */
if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
disc.fields |= MNCC_F_USERUSER;
- decode_useruser(&disc.useruser,
+ gsm48_decode_useruser(&disc.useruser,
TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
}
/* ss-version */
if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
disc.fields |= MNCC_F_SSVERSION;
- decode_ssversion(&disc.ssversion,
+ gsm48_decode_ssversion(&disc.ssversion,
TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
}
@@ -2534,19 +1896,19 @@ static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg)
/* cause */
if (disc->fields & MNCC_F_CAUSE)
- encode_cause(msg, 1, &disc->cause);
+ gsm48_encode_cause(msg, 1, &disc->cause);
else
- encode_cause(msg, 1, &default_cause);
+ gsm48_encode_cause(msg, 1, &default_cause);
/* facility */
if (disc->fields & MNCC_F_FACILITY)
- encode_facility(msg, 0, &disc->facility);
+ gsm48_encode_facility(msg, 0, &disc->facility);
/* progress */
if (disc->fields & MNCC_F_PROGRESS)
- encode_progress(msg, 0, &disc->progress);
+ gsm48_encode_progress(msg, 0, &disc->progress);
/* user-user */
if (disc->fields & MNCC_F_USERUSER)
- encode_useruser(msg, 0, &disc->useruser);
+ gsm48_encode_useruser(msg, 0, &disc->useruser);
/* store disconnect cause for T306 expiry */
memcpy(&trans->cc.msg, disc, sizeof(struct gsm_mncc));
@@ -2568,29 +1930,29 @@ static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg)
memset(&rel, 0, sizeof(struct gsm_mncc));
rel.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
/* cause */
if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
rel.fields |= MNCC_F_CAUSE;
- decode_cause(&rel.cause,
+ gsm48_decode_cause(&rel.cause,
TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
}
/* facility */
if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
rel.fields |= MNCC_F_FACILITY;
- decode_facility(&rel.facility,
+ gsm48_decode_facility(&rel.facility,
TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
}
/* user-user */
if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
rel.fields |= MNCC_F_USERUSER;
- decode_useruser(&rel.useruser,
+ gsm48_decode_useruser(&rel.useruser,
TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
}
/* ss-version */
if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
rel.fields |= MNCC_F_SSVERSION;
- decode_ssversion(&rel.ssversion,
+ gsm48_decode_ssversion(&rel.ssversion,
TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
}
@@ -2627,13 +1989,13 @@ static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg)
/* cause */
if (rel->fields & MNCC_F_CAUSE)
- encode_cause(msg, 0, &rel->cause);
+ gsm48_encode_cause(msg, 0, &rel->cause);
/* facility */
if (rel->fields & MNCC_F_FACILITY)
- encode_facility(msg, 0, &rel->facility);
+ gsm48_encode_facility(msg, 0, &rel->facility);
/* user-user */
if (rel->fields & MNCC_F_USERUSER)
- encode_useruser(msg, 0, &rel->useruser);
+ gsm48_encode_useruser(msg, 0, &rel->useruser);
trans->cc.T308_second = 0;
memcpy(&trans->cc.msg, rel, sizeof(struct gsm_mncc));
@@ -2656,29 +2018,29 @@ static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
memset(&rel, 0, sizeof(struct gsm_mncc));
rel.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
/* cause */
if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
rel.fields |= MNCC_F_CAUSE;
- decode_cause(&rel.cause,
+ gsm48_decode_cause(&rel.cause,
TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
}
/* facility */
if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
rel.fields |= MNCC_F_FACILITY;
- decode_facility(&rel.facility,
+ gsm48_decode_facility(&rel.facility,
TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
}
/* user-user */
if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
rel.fields |= MNCC_F_USERUSER;
- decode_useruser(&rel.useruser,
+ gsm48_decode_useruser(&rel.useruser,
TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
}
/* ss-version */
if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
rel.fields |= MNCC_F_SSVERSION;
- decode_ssversion(&rel.ssversion,
+ gsm48_decode_ssversion(&rel.ssversion,
TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
}
@@ -2720,13 +2082,13 @@ static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg)
/* cause */
if (rel->fields & MNCC_F_CAUSE)
- encode_cause(msg, 0, &rel->cause);
+ gsm48_encode_cause(msg, 0, &rel->cause);
/* facility */
if (rel->fields & MNCC_F_FACILITY)
- encode_facility(msg, 0, &rel->facility);
+ gsm48_encode_facility(msg, 0, &rel->facility);
/* user-user */
if (rel->fields & MNCC_F_USERUSER)
- encode_useruser(msg, 0, &rel->useruser);
+ gsm48_encode_useruser(msg, 0, &rel->useruser);
trans_free(trans);
@@ -2742,17 +2104,17 @@ static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg)
memset(&fac, 0, sizeof(struct gsm_mncc));
fac.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_FACILITY, 0);
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, GSM48_IE_FACILITY, 0);
/* facility */
if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
fac.fields |= MNCC_F_FACILITY;
- decode_facility(&fac.facility,
+ gsm48_decode_facility(&fac.facility,
TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
}
/* ss-version */
if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
fac.fields |= MNCC_F_SSVERSION;
- decode_ssversion(&fac.ssversion,
+ gsm48_decode_ssversion(&fac.ssversion,
TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
}
@@ -2768,7 +2130,7 @@ static int gsm48_cc_tx_facility(struct gsm_trans *trans, void *arg)
gh->msg_type = GSM48_MT_CC_FACILITY;
/* facility */
- encode_facility(msg, 1, &fac->facility);
+ gsm48_encode_facility(msg, 1, &fac->facility);
return gsm48_sendmsg(msg, trans);
}
@@ -2802,9 +2164,9 @@ static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg)
/* cause */
if (hold_rej->fields & MNCC_F_CAUSE)
- encode_cause(msg, 1, &hold_rej->cause);
+ gsm48_encode_cause(msg, 1, &hold_rej->cause);
else
- encode_cause(msg, 1, &default_cause);
+ gsm48_encode_cause(msg, 1, &default_cause);
return gsm48_sendmsg(msg, trans);
}
@@ -2839,9 +2201,9 @@ static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg)
/* cause */
if (retrieve_rej->fields & MNCC_F_CAUSE)
- encode_cause(msg, 1, &retrieve_rej->cause);
+ gsm48_encode_cause(msg, 1, &retrieve_rej->cause);
else
- encode_cause(msg, 1, &default_cause);
+ gsm48_encode_cause(msg, 1, &default_cause);
return gsm48_sendmsg(msg, trans);
}
@@ -2855,11 +2217,11 @@ static int gsm48_cc_rx_start_dtmf(struct gsm_trans *trans, struct msgb *msg)
memset(&dtmf, 0, sizeof(struct gsm_mncc));
dtmf.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
/* keypad facility */
if (TLVP_PRESENT(&tp, GSM48_IE_KPD_FACILITY)) {
dtmf.fields |= MNCC_F_KEYPAD;
- decode_keypad(&dtmf.keypad,
+ gsm48_decode_keypad(&dtmf.keypad,
TLVP_VAL(&tp, GSM48_IE_KPD_FACILITY)-1);
}
@@ -2876,7 +2238,7 @@ static int gsm48_cc_tx_start_dtmf_ack(struct gsm_trans *trans, void *arg)
/* keypad */
if (dtmf->fields & MNCC_F_KEYPAD)
- encode_keypad(msg, dtmf->keypad);
+ gsm48_encode_keypad(msg, dtmf->keypad);
return gsm48_sendmsg(msg, trans);
}
@@ -2891,9 +2253,9 @@ static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg)
/* cause */
if (dtmf->fields & MNCC_F_CAUSE)
- encode_cause(msg, 1, &dtmf->cause);
+ gsm48_encode_cause(msg, 1, &dtmf->cause);
else
- encode_cause(msg, 1, &default_cause);
+ gsm48_encode_cause(msg, 1, &default_cause);
return gsm48_sendmsg(msg, trans);
}
@@ -2927,11 +2289,11 @@ static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg)
memset(&modify, 0, sizeof(struct gsm_mncc));
modify.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
/* bearer capability */
if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
modify.fields |= MNCC_F_BEARER_CAP;
- decode_bearer_cap(&modify.bearer_cap,
+ gsm48_decode_bearer_cap(&modify.bearer_cap,
TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
}
@@ -2951,7 +2313,7 @@ static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg)
gsm48_start_cc_timer(trans, 0x323, GSM48_T323);
/* bearer capability */
- encode_bearer_cap(msg, 1, &modify->bearer_cap);
+ gsm48_encode_bearer_cap(msg, 1, &modify->bearer_cap);
new_cc_state(trans, GSM_CSTATE_MO_TERM_MODIFY);
@@ -2969,11 +2331,11 @@ static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg
memset(&modify, 0, sizeof(struct gsm_mncc));
modify.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0);
/* bearer capability */
if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
modify.fields |= MNCC_F_BEARER_CAP;
- decode_bearer_cap(&modify.bearer_cap,
+ gsm48_decode_bearer_cap(&modify.bearer_cap,
TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
}
@@ -2991,7 +2353,7 @@ static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg)
gh->msg_type = GSM48_MT_CC_MODIFY_COMPL;
/* bearer capability */
- encode_bearer_cap(msg, 1, &modify->bearer_cap);
+ gsm48_encode_bearer_cap(msg, 1, &modify->bearer_cap);
new_cc_state(trans, GSM_CSTATE_ACTIVE);
@@ -3009,17 +2371,17 @@ static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg)
memset(&modify, 0, sizeof(struct gsm_mncc));
modify.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, GSM48_IE_CAUSE);
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, GSM48_IE_CAUSE);
/* bearer capability */
if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
modify.fields |= GSM48_IE_BEARER_CAP;
- decode_bearer_cap(&modify.bearer_cap,
+ gsm48_decode_bearer_cap(&modify.bearer_cap,
TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
}
/* cause */
if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
modify.fields |= MNCC_F_CAUSE;
- decode_cause(&modify.cause,
+ gsm48_decode_cause(&modify.cause,
TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
}
@@ -3037,9 +2399,9 @@ static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg)
gh->msg_type = GSM48_MT_CC_MODIFY_REJECT;
/* bearer capability */
- encode_bearer_cap(msg, 1, &modify->bearer_cap);
+ gsm48_encode_bearer_cap(msg, 1, &modify->bearer_cap);
/* cause */
- encode_cause(msg, 1, &modify->cause);
+ gsm48_encode_cause(msg, 1, &modify->cause);
new_cc_state(trans, GSM_CSTATE_ACTIVE);
@@ -3055,7 +2417,7 @@ static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg)
gh->msg_type = GSM48_MT_CC_NOTIFY;
/* notify */
- encode_notify(msg, notify->notify);
+ gsm48_encode_notify(msg, notify->notify);
return gsm48_sendmsg(msg, trans);
}
@@ -3069,9 +2431,9 @@ static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg)
memset(&notify, 0, sizeof(struct gsm_mncc));
notify.callref = trans->callref;
-// tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len);
+// tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len);
if (payload_len >= 1)
- decode_notify(&notify.notify, gh->data);
+ gsm48_decode_notify(&notify.notify, gh->data);
return mncc_recvmsg(trans->subscr->net, trans, MNCC_NOTIFY_IND, &notify);
}
@@ -3086,10 +2448,10 @@ static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg)
/* user-user */
if (user->fields & MNCC_F_USERUSER)
- encode_useruser(msg, 1, &user->useruser);
+ gsm48_encode_useruser(msg, 1, &user->useruser);
/* more data */
if (user->more)
- encode_more(msg);
+ gsm48_encode_more(msg);
return gsm48_sendmsg(msg, trans);
}
@@ -3103,11 +2465,11 @@ static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg)
memset(&user, 0, sizeof(struct gsm_mncc));
user.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_USER_USER, 0);
+ tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, GSM48_IE_USER_USER, 0);
/* user-user */
if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
user.fields |= MNCC_F_USERUSER;
- decode_useruser(&user.useruser,
+ gsm48_decode_useruser(&user.useruser,
TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
}
/* more data */
@@ -3445,7 +2807,7 @@ static int gsm0408_rcv_cc(struct msgb *msg)
"Received '%s' from MS in state %d (%s)\n",
lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-",
- gsm0408_cc_msg_names[msg_type], trans?(trans->cc.state):0,
+ gsm48_cc_msg_names[msg_type], trans?(trans->cc.state):0,
cc_state_names[trans?(trans->cc.state):0]);
/* Create transaction */
@@ -3488,6 +2850,9 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
struct gsm48_hdr *gh = msgb_l3(msg);
u_int8_t pdisc = gh->proto_discr & 0x0f;
int rc = 0;
+
+ if (silent_call_reroute(msg))
+ return silent_call_rx(msg);
switch (pdisc) {
case GSM48_PDISC_CC:
@@ -3504,15 +2869,15 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
break;
case GSM48_PDISC_MM_GPRS:
case GSM48_PDISC_SM_GPRS:
- fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02x\n",
- pdisc);
+ LOGP(DRLL, LOGL_NOTICE, "Unimplemented "
+ "GSM 04.08 discriminator 0x%02x\n", pdisc);
break;
case GSM48_PDISC_NC_SS:
rc = handle_rcv_ussd(msg);
break;
default:
- fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02x\n",
- pdisc);
+ LOGP(DRLL, LOGL_NOTICE, "Unknown "
+ "GSM 04.08 discriminator 0x%02x\n", pdisc);
break;
}
diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c
index 9156a3909..68f34f409 100644
--- a/openbsc/src/gsm_04_08_utils.c
+++ b/openbsc/src/gsm_04_08_utils.c
@@ -28,7 +28,8 @@
#include <errno.h>
#include <netinet/in.h>
-#include <openbsc/msgb.h>
+#include <osmocore/msgb.h>
+#include <osmocore/gsm48.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/transaction.h>
@@ -42,75 +43,6 @@
* or should OpenBSC always act as RTP relay/proxy in between (0) ? */
int ipacc_rtp_direct = 1;
-
-const char *gsm0408_cc_msg_names[] = {
- "unknown 0x00",
- "ALERTING",
- "CALL_PROC",
- "PROGRESS",
- "ESTAB",
- "SETUP",
- "ESTAB_CONF",
- "CONNECT",
- "CALL_CONF",
- "START_CC",
- "unknown 0x0a",
- "RECALL",
- "unknown 0x0c",
- "unknown 0x0d",
- "EMERG_SETUP",
- "CONNECT_ACK",
- "USER_INFO",
- "unknown 0x11",
- "unknown 0x12",
- "MODIFY_REJECT",
- "unknown 0x14",
- "unknown 0x15",
- "unknown 0x16",
- "MODIFY",
- "HOLD",
- "HOLD_ACK",
- "HOLD_REJ",
- "unknown 0x1b",
- "RETR",
- "RETR_ACK",
- "RETR_REJ",
- "MODIFY_COMPL",
- "unknown 0x20",
- "unknown 0x21",
- "unknown 0x22",
- "unknown 0x23",
- "unknown 0x24",
- "DISCONNECT",
- "unknown 0x26",
- "unknown 0x27",
- "unknown 0x28",
- "unknown 0x29",
- "RELEASE_COMPL",
- "unknown 0x2b",
- "unknown 0x2c",
- "RELEASE",
- "unknown 0x2e",
- "unknown 0x2f",
- "unknown 0x30",
- "STOP_DTMF",
- "STOP_DTMF_ACK",
- "unknown 0x33",
- "STATUS_ENQ",
- "START_DTMF",
- "START_DTMF_ACK",
- "START_DTMF_REJ",
- "unknown 0x38",
- "CONG_CTRL",
- "FACILITY",
- "unknown 0x3b",
- "STATUS",
- "unknown 0x3c",
- "NOTIFY",
- "unknown 0x3f",
-};
-
-
struct msgb *gsm48_msgb_alloc(void)
{
return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM,
@@ -136,7 +68,7 @@ int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans)
"Sending '%s' to MS.\n", msg->trx->bts->nr,
msg->trx->nr, msg->lchan->ts->nr,
gh->proto_discr & 0xf0,
- gsm0408_cc_msg_names[gh->msg_type & 0x3f]);
+ gsm48_cc_msg_names[gh->msg_type & 0x3f]);
else
DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) "
"Sending 0x%02x to MS.\n", msg->trx->bts->nr,
@@ -149,94 +81,6 @@ int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans)
return rsl_data_request(msg, 0);
}
-static void to_bcd(u_int8_t *bcd, u_int16_t val)
-{
- bcd[2] = val % 10;
- val = val / 10;
- bcd[1] = val % 10;
- val = val / 10;
- bcd[0] = val % 10;
- val = val / 10;
-}
-
-static char bcd2char(u_int8_t bcd)
-{
- if (bcd < 0xa)
- return '0' + bcd;
- else
- return 'A' + (bcd - 0xa);
-}
-
-/* only works for numbers in ascci */
-static u_int8_t char2bcd(char c)
-{
- return c - 0x30;
-}
-
-
-void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
- u_int16_t mnc, u_int16_t lac)
-{
- u_int8_t bcd[3];
-
- to_bcd(bcd, mcc);
- lai48->digits[0] = bcd[0] | (bcd[1] << 4);
- lai48->digits[1] = bcd[2];
-
- to_bcd(bcd, mnc);
- /* FIXME: do we need three-digit MNC? See Table 10.5.3 */
-#if 0
- lai48->digits[1] |= bcd[2] << 4;
- lai48->digits[2] = bcd[0] | (bcd[1] << 4);
-#else
- lai48->digits[1] |= 0xf << 4;
- lai48->digits[2] = bcd[1] | (bcd[2] << 4);
-#endif
-
- lai48->lac = htons(lac);
-}
-
-int gsm48_generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi)
-{
- u_int32_t *tptr = (u_int32_t *) &buf[3];
-
- buf[0] = GSM48_IE_MOBILE_ID;
- buf[1] = GSM48_TMSI_LEN;
- buf[2] = 0xf0 | GSM_MI_TYPE_TMSI;
- *tptr = htonl(tmsi);
-
- return 7;
-}
-
-int gsm48_generate_mid_from_imsi(u_int8_t *buf, const char *imsi)
-{
- unsigned int length = strlen(imsi), i, off = 0;
- u_int8_t odd = (length & 0x1) == 1;
-
- buf[0] = GSM48_IE_MOBILE_ID;
- buf[2] = char2bcd(imsi[0]) << 4 | GSM_MI_TYPE_IMSI | (odd << 3);
-
- /* if the length is even we will fill half of the last octet */
- if (odd)
- buf[1] = (length + 1) >> 1;
- else
- buf[1] = (length + 2) >> 1;
-
- for (i = 1; i < buf[1]; ++i) {
- u_int8_t lower, upper;
-
- lower = char2bcd(imsi[++off]);
- if (!odd && off + 1 == length)
- upper = 0x0f;
- else
- upper = char2bcd(imsi[++off]) & 0x0f;
-
- buf[2 + i] = (upper << 4) | lower;
- }
-
- return 2 + buf[1];
-}
-
/* Section 9.1.8 / Table 9.9 */
struct chreq {
u_int8_t val;
@@ -340,7 +184,7 @@ enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci)
if ((ra & chr->mask) == chr->val)
return ctype_by_chreq[chr->type];
}
- fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra);
+ LOGP(DRR, LOGL_ERROR, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra);
return GSM_LCHAN_SDCCH;
}
@@ -363,7 +207,7 @@ enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra, in
if ((ra & chr->mask) == chr->val)
return reason_by_chreq[chr->type];
}
- fprintf(stderr, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra);
+ LOGP(DRR, LOGL_ERROR, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra);
return GSM_CHREQ_REASON_OTHER;
}
@@ -475,7 +319,7 @@ int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr)
if (!msg->lchan->subscr) {
msg->lchan->subscr = subscr;
} else if (msg->lchan->subscr != subscr) {
- DEBUGP(DRR, "<- Channel already owned by someone else?\n");
+ LOGP(DRR, LOGL_ERROR, "<- Channel already owned by someone else?\n");
subscr_put(subscr);
return -EINVAL;
} else {
@@ -490,7 +334,7 @@ int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr)
bts->network->stats.paging.completed++;
- dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
+ dispatch_signal(SS_PAGING, S_PAGING_SUCCEEDED, &sig_data);
/* Stop paging on the bts we received the paging response */
paging_request_stop(msg->trx->bts, subscr, msg->lchan);
@@ -596,7 +440,8 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan,
/* in case of multi rate we need to attach a config */
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
if (lchan->mr_conf.ver == 0) {
- DEBUGP(DRR, "BUG: Using multirate codec without multirate config.\n");
+ LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec "
+ "without multirate config.\n");
} else {
u_int8_t *data = msgb_put(msg, 4);
data[0] = GSM48_IE_MUL_RATE_CFG;
@@ -636,7 +481,8 @@ int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode)
/* in case of multi rate we need to attach a config */
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
if (lchan->mr_conf.ver == 0) {
- DEBUGP(DRR, "BUG: Using multirate codec without multirate config.\n");
+ LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec "
+ "without multirate config.\n");
} else {
u_int8_t *data = msgb_put(msg, 4);
data[0] = GSM48_IE_MUL_RATE_CFG;
@@ -669,7 +515,7 @@ int gsm48_rx_rr_modif_ack(struct msgb *msg)
DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n");
if (mod->mode != msg->lchan->tch_mode) {
- DEBUGP(DRR, "CHANNEL MODE change failed. Wanted: %d Got: %d\n",
+ LOGP(DRR, LOGL_ERROR, "CHANNEL MODE change failed. Wanted: %d Got: %d\n",
msg->lchan->tch_mode, mod->mode);
return -1;
}
@@ -710,6 +556,7 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg)
u_int8_t *data = gh->data;
struct gsm_bts *bts = msg->lchan->ts->trx->bts;
struct bitvec *nbv = &bts->si_common.neigh_list;
+ struct gsm_meas_rep_cell *mrc;
if (gh->msg_type != GSM48_MT_RR_MEAS_REP)
return -EINVAL;
@@ -731,42 +578,51 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg)
return 0;
/* an encoding nightmare in perfection */
-
- rep->cell[0].rxlev = data[3] & 0x3f;
- rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[4] >> 2);
- rep->cell[0].bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5);
+ mrc = &rep->cell[0];
+ mrc->rxlev = data[3] & 0x3f;
+ mrc->neigh_idx = data[4] >> 3;
+ mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
+ mrc->bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5);
if (rep->num_cell < 2)
return 0;
- rep->cell[1].rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7);
- rep->cell[1].arfcn = bitvec_get_nth_set_bit(nbv, (data[6] >> 2) & 0x1f);
- rep->cell[1].bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4);
+ mrc = &rep->cell[1];
+ mrc->rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7);
+ mrc->neigh_idx = (data[6] >> 2) & 0x1f;
+ mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
+ mrc->bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4);
if (rep->num_cell < 3)
return 0;
- rep->cell[2].rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6);
- rep->cell[2].arfcn = bitvec_get_nth_set_bit(nbv, (data[8] >> 1) & 0x1f);
- rep->cell[2].bsic = ((data[8] & 0x01) << 6) | (data[9] >> 3);
+ mrc = &rep->cell[2];
+ mrc->rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6);
+ mrc->neigh_idx = (data[8] >> 1) & 0x1f;
+ mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
+ mrc->bsic = ((data[8] & 0x01) << 5) | (data[9] >> 3);
if (rep->num_cell < 4)
return 0;
- rep->cell[3].rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5);
- rep->cell[3].arfcn = bitvec_get_nth_set_bit(nbv, data[10] & 0x1f);
- rep->cell[3].bsic = data[11] >> 2;
+ mrc = &rep->cell[3];
+ mrc->rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5);
+ mrc->neigh_idx = data[10] & 0x1f;
+ mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
+ mrc->bsic = data[11] >> 2;
if (rep->num_cell < 5)
return 0;
- rep->cell[4].rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4);
- rep->cell[4].arfcn = bitvec_get_nth_set_bit(nbv,
- ((data[12] & 0xf) << 1) | (data[13] >> 7));
- rep->cell[4].bsic = (data[13] >> 1) & 0x3f;
+ mrc = &rep->cell[4];
+ mrc->rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4);
+ mrc->neigh_idx = ((data[12] & 0xf) << 1) | (data[13] >> 7);
+ mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
+ mrc->bsic = (data[13] >> 1) & 0x3f;
if (rep->num_cell < 6)
return 0;
- rep->cell[5].rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3);
- rep->cell[5].arfcn = bitvec_get_nth_set_bit(nbv,
- ((data[14] & 0x07) << 2) | (data[15] >> 6));
- rep->cell[5].bsic = data[15] & 0x3f;
+ mrc = &rep->cell[5];
+ mrc->rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3);
+ mrc->neigh_idx = ((data[14] & 0x07) << 2) | (data[15] >> 6);
+ mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
+ mrc->bsic = data[15] & 0x3f;
return 0;
}
diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c
index 579bb55d1..881c3755a 100644
--- a/openbsc/src/gsm_04_11.c
+++ b/openbsc/src/gsm_04_11.c
@@ -31,18 +31,18 @@
#include <time.h>
#include <netinet/in.h>
-#include <openbsc/msgb.h>
-#include <openbsc/tlv.h>
+#include <osmocore/msgb.h>
+#include <osmocore/tlv.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/gsm_04_11.h>
#include <openbsc/gsm_04_08.h>
-#include <openbsc/gsm_utils.h>
+#include <osmocore/gsm_utils.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/signal.h>
#include <openbsc/db.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/transaction.h>
#include <openbsc/paging.h>
#include <openbsc/bsc_rll.h>
@@ -215,7 +215,8 @@ static u_int8_t unbcdify(u_int8_t value)
u_int8_t ret;
if ((value & 0x0F) > 9 || (value >> 4) > 9)
- DEBUGP(DSMS, "unbcdify got too big nibble: 0x%02X\n", value);
+ LOGP(DSMS, LOGL_ERROR,
+ "unbcdify got too big nibble: 0x%02X\n", value);
ret = (value&0x0F)*10;
ret += value>>4;
@@ -311,7 +312,8 @@ static unsigned long gsm340_vp_relative_integer(u_int8_t *sms_vp)
unsigned long minutes;
vp = *(sms_vp);
if (vp == 0) {
- DEBUGP(DSMS, "reserved relative_integer validity period\n");
+ LOGP(DSMS, LOGL_ERROR,
+ "reserved relative_integer validity period\n");
return gsm340_vp_default();
}
minutes = vp/60;
@@ -356,7 +358,8 @@ static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp)
default:
/* The GSM spec says that the SC should reject any
unsupported and/or undefined values. FIXME */
- DEBUGP(DSMS, "Reserved enhanced validity period format\n");
+ LOGP(DSMS, LOGL_ERROR,
+ "Reserved enhanced validity period format\n");
return gsm340_vp_default();
}
case GSM340_TP_VPF_NONE:
@@ -373,7 +376,8 @@ enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs)
if ((cgbits & 0xc) == 0) {
if (cgbits & 2)
- DEBUGP(DSMS, "Compressed SMS not supported yet\n");
+ LOGP(DSMS, LOGL_NOTICE,
+ "Compressed SMS not supported yet\n");
switch ((dcs >> 2)&0x03) {
case 0:
@@ -403,7 +407,7 @@ enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs)
static int gsm340_rx_sms_submit(struct msgb *msg, struct gsm_sms *gsms)
{
if (db_sms_store(gsms) != 0) {
- DEBUGP(DSMS, "Failed to store SMS in Database\n");
+ LOGP(DSMS, LOGL_ERROR, "Failed to store SMS in Database\n");
return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
}
/* dispatch a signal to tell higher level about it */
@@ -422,7 +426,7 @@ static int gsm340_gen_oa(u_int8_t *oa, unsigned int oa_len,
oa[1] = 0xb9; /* networks-specific number, private numbering plan */
- len_in_bytes = encode_bcd_number(oa, oa_len, 1, subscr->extension);
+ len_in_bytes = gsm48_encode_bcd_number(oa, oa_len, 1, subscr->extension);
/* GSM 03.40 tells us the length is in 'useful semi-octets' */
oa[0] = strlen(subscr->extension) & 0xff;
@@ -497,7 +501,8 @@ static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms)
memcpy(smsp, sms->user_data, sms->user_data_len);
break;
default:
- DEBUGP(DSMS, "Unhandled Data Coding Scheme: 0x%02X\n", sms->data_coding_scheme);
+ LOGP(DSMS, LOGL_NOTICE, "Unhandled Data Coding Scheme: 0x%02X\n",
+ sms->data_coding_scheme);
break;
}
@@ -517,7 +522,7 @@ static int gsm340_rx_tpdu(struct msgb *msg)
u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
int rc = 0;
- bts->network->stats.sms.submitted++;
+ counter_inc(bts->network->stats.sms.submitted);
gsms = sms_alloc();
if (!gsms)
@@ -537,7 +542,7 @@ static int gsm340_rx_tpdu(struct msgb *msg)
/* length in bytes of the destination address */
da_len_bytes = 2 + *smsp/2 + *smsp%2;
if (da_len_bytes > 12) {
- DEBUGP(DSMS, "Destination Address > 12 bytes ?!?\n");
+ LOGP(DSMS, LOGL_ERROR, "Destination Address > 12 bytes ?!?\n");
rc = GSM411_RP_CAUSE_SEMANT_INC_MSG;
goto out;
}
@@ -546,7 +551,7 @@ static int gsm340_rx_tpdu(struct msgb *msg)
/* mangle first byte to reflect length in bytes, not digits */
address_lv[0] = da_len_bytes - 1;
/* convert to real number */
- decode_bcd_number(gsms->dest_addr, sizeof(gsms->dest_addr), address_lv, 1);
+ gsm48_decode_bcd_number(gsms->dest_addr, sizeof(gsms->dest_addr), address_lv, 1);
smsp += da_len_bytes;
gsms->protocol_id = *smsp++;
@@ -570,8 +575,8 @@ static int gsm340_rx_tpdu(struct msgb *msg)
sms_vp = 0;
break;
default:
- DEBUGP(DSMS, "SMS Validity period not implemented: 0x%02x\n",
- sms_vpf);
+ LOGP(DSMS, LOGL_NOTICE,
+ "SMS Validity period not implemented: 0x%02x\n", sms_vpf);
return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
}
gsms->user_data_len = *smsp++;
@@ -589,16 +594,17 @@ static int gsm340_rx_tpdu(struct msgb *msg)
}
}
- DEBUGP(DSMS, "SMS:\nMTI: 0x%02x, VPF: 0x%02x, MR: 0x%02x "
- "PID: 0x%02x, DCS: 0x%02x, DA: %s, UserDataLength: 0x%02x "
- "UserData: \"%s\"\n", sms_mti, sms_vpf, gsms->msg_ref,
- gsms->protocol_id, gsms->data_coding_scheme,
- gsms->dest_addr, gsms->user_data_len,
+ gsms->sender = subscr_get(msg->lchan->subscr);
+
+ LOGP(DSMS, LOGL_INFO, "RX SMS: Sender: %s, MTI: 0x%02x, VPF: 0x%02x, "
+ "MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, DA: %s, "
+ "UserDataLength: 0x%02x, UserData: \"%s\"\n",
+ subscr_name(gsms->sender), sms_mti, sms_vpf, gsms->msg_ref,
+ gsms->protocol_id, gsms->data_coding_scheme, gsms->dest_addr,
+ gsms->user_data_len,
sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
hexdump(gsms->user_data, gsms->user_data_len));
- gsms->sender = subscr_get(msg->lchan->subscr);
-
gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp);
dispatch_signal(SS_SMS, 0, gsms);
@@ -607,7 +613,7 @@ static int gsm340_rx_tpdu(struct msgb *msg)
gsms->receiver = subscr_get_by_extension(bts->network, gsms->dest_addr);
if (!gsms->receiver) {
rc = 1; /* cause 1: unknown subscriber */
- bts->network->stats.sms.no_receiver++;
+ counter_inc(bts->network->stats.sms.no_receiver);
goto out;
}
@@ -618,11 +624,11 @@ static int gsm340_rx_tpdu(struct msgb *msg)
break;
case GSM340_SMS_COMMAND_MS2SC:
case GSM340_SMS_DELIVER_REP_MS2SC:
- DEBUGP(DSMS, "Unimplemented MTI 0x%02x\n", sms_mti);
+ LOGP(DSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti);
rc = GSM411_RP_CAUSE_IE_NOTEXIST;
break;
default:
- DEBUGP(DSMS, "Undefined MTI 0x%02x\n", sms_mti);
+ LOGP(DSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti);
rc = GSM411_RP_CAUSE_IE_NOTEXIST;
break;
}
@@ -652,7 +658,7 @@ static int gsm411_send_rp_error(struct gsm_trans *trans,
msgb_tv_put(msg, 1, cause);
- DEBUGP(DSMS, "TX: SMS RP ERROR, cause %d (%s)\n", cause,
+ LOGP(DSMS, LOGL_NOTICE, "TX: SMS RP ERROR, cause %d (%s)\n", cause,
get_value_string(rp_cause_strs, cause));
return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_ERROR_MT, msg_ref);
@@ -668,10 +674,11 @@ static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
int rc = 0;
if (src_len && src)
- DEBUGP(DSMS, "RP-DATA (MO) with SRC ?!?\n");
+ LOGP(DSMS, LOGL_ERROR, "RP-DATA (MO) with SRC ?!?\n");
if (!dst_len || !dst || !tpdu_len || !tpdu) {
- DEBUGP(DSMS, "RP-DATA (MO) without DST or TPDU ?!?\n");
+ LOGP(DSMS, LOGL_ERROR,
+ "RP-DATA (MO) without DST or TPDU ?!?\n");
gsm411_send_rp_error(trans, rph->msg_ref,
GSM411_RP_CAUSE_INV_MAND_INF);
return -EIO;
@@ -726,13 +733,13 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
* transmitted */
if (!trans->sms.is_mt) {
- DEBUGP(DSMS, "RX RP-ACK on a MO transfer ?\n");
+ LOGP(DSMS, LOGL_ERROR, "RX RP-ACK on a MO transfer ?\n");
return gsm411_send_rp_error(trans, rph->msg_ref,
GSM411_RP_CAUSE_MSG_INCOMP_STATE);
}
if (!sms) {
- DEBUGP(DSMS, "RX RP-ACK but no sms in transaction?!?\n");
+ LOGP(DSMS, LOGL_ERROR, "RX RP-ACK but no sms in transaction?!?\n");
return gsm411_send_rp_error(trans, rph->msg_ref,
GSM411_RP_CAUSE_PROTOCOL_ERR);
}
@@ -745,14 +752,16 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
sms_free(sms);
trans->sms.sms = NULL;
- /* free the transaction here */
- trans_free(trans);
-
/* check for more messages for this subscriber */
sms = db_sms_get_unsent_for_subscr(msg->lchan->subscr);
if (sms)
gsm411_send_sms_lchan(msg->lchan, sms);
- else
+
+ /* free the transaction here */
+ trans_free(trans);
+
+ /* release channel if done */
+ if (!sms)
rsl_release_request(msg->lchan, trans->sms.link_id);
return 0;
@@ -761,6 +770,7 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
struct gsm411_rp_hdr *rph)
{
+ struct gsm_network *net = trans->lchan->ts->trx->bts->network;
struct gsm_sms *sms = trans->sms.sms;
u_int8_t cause_len = rph->data[0];
u_int8_t cause = rph->data[1];
@@ -769,11 +779,12 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
* successfully receive the SMS. We need to investigate
* the cause and take action depending on it */
- DEBUGP(DSMS, "RX SMS RP-ERROR, cause %d:%d (%s)\n", cause_len, cause,
- get_value_string(rp_cause_strs, cause));
+ LOGP(DSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n",
+ subscr_name(msg->lchan->subscr), cause_len, cause,
+ get_value_string(rp_cause_strs, cause));
if (!trans->sms.is_mt) {
- DEBUGP(DSMS, "RX RP-ERR on a MO transfer ?\n");
+ LOGP(DSMS, LOGL_ERROR, "RX RP-ERR on a MO transfer ?\n");
#if 0
return gsm411_send_rp_error(trans, rph->msg_ref,
GSM411_RP_CAUSE_MSG_INCOMP_STATE);
@@ -781,7 +792,8 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
}
if (!sms) {
- DEBUGP(DSMS, "RX RP-ERR, but no sms in transaction?!?\n");
+ LOGP(DSMS, LOGL_ERROR,
+ "RX RP-ERR, but no sms in transaction?!?\n");
return -EINVAL;
#if 0
return gsm411_send_rp_error(trans, rph->msg_ref,
@@ -794,9 +806,9 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
* to store this in our database and wati for a SMMA message */
/* FIXME */
dispatch_signal(SS_SMS, S_SMS_MEM_EXCEEDED, trans->subscr);
- trans->lchan->ts->trx->bts->network->stats.sms.rp_err_mem++;
+ counter_inc(net->stats.sms.rp_err_mem);
} else
- trans->lchan->ts->trx->bts->network->stats.sms.rp_err_other++;
+ counter_inc(net->stats.sms.rp_err_other);
sms_free(sms);
trans->sms.sms = NULL;
@@ -858,7 +870,7 @@ static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh,
rc = gsm411_rx_rp_error(msg, trans, rp_data);
break;
default:
- DEBUGP(DSMS, "Invalid RP type 0x%02x\n", msg_type);
+ LOGP(DSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type);
rc = gsm411_send_rp_error(trans, rp_data->msg_ref,
GSM411_RP_CAUSE_MSGTYPE_NOTEXIST);
break;
@@ -889,7 +901,7 @@ static int gsm411_tx_cp_error(struct gsm_trans *trans, u_int8_t cause)
struct msgb *msg = gsm411_msgb_alloc();
u_int8_t *causep;
- DEBUGP(DSMS, "TX CP-ERROR, cause %d (%s)\n", cause,
+ LOGP(DSMS, LOGL_NOTICE, "TX CP-ERROR, cause %d (%s)\n", cause,
get_value_string(cp_cause_strs, cause));
causep = msgb_put(msg, 1);
@@ -936,6 +948,33 @@ int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id)
switch(msg_type) {
case GSM411_MT_CP_DATA:
DEBUGPC(DSMS, "RX SMS CP-DATA\n");
+
+ /* 5.4: For MO, if a CP-DATA is received for a new
+ * transaction, equals reception of an implicit
+ * last CP-ACK for previous transaction */
+ if (trans->sms.cp_state == GSM411_CPS_IDLE) {
+ int i;
+ struct gsm_trans *ptrans;
+
+ /* Scan through all remote initiated transactions */
+ for (i=8; i<15; i++) {
+ if (i == transaction_id)
+ continue;
+
+ ptrans = trans_find_by_id(lchan->subscr,
+ GSM48_PDISC_SMS, i);
+ if (!ptrans)
+ continue;
+
+ DEBUGP(DSMS, "Implicit CP-ACK for trans_id=%x\n", i);
+
+ /* Finish it for good */
+ bsc_del_timer(&ptrans->sms.cp_timer);
+ ptrans->sms.cp_state = GSM411_CPS_IDLE;
+ trans_free(ptrans);
+ }
+ }
+
/* 5.2.3.1.3: MO state exists when SMC has received
* CP-DATA, including sending of the assoc. CP-ACK */
/* 5.2.3.2.4: MT state exists when SMC has received
@@ -1008,10 +1047,14 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms)
struct gsm_trans *trans;
u_int8_t *data, *rp_ud_len;
u_int8_t msg_ref = 42;
- u_int8_t transaction_id;
+ int transaction_id;
int rc;
- transaction_id = 4; /* FIXME: we always use 4 for now */
+ transaction_id = trans_assign_trans_id(lchan->subscr, GSM48_PDISC_SMS, 0);
+ if (transaction_id == -1) {
+ LOGP(DSMS, LOGL_ERROR, "No available transaction ids\n");
+ return -EBUSY;
+ }
msg->lchan = lchan;
@@ -1021,7 +1064,7 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms)
trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
transaction_id, new_callref++);
if (!trans) {
- DEBUGP(DSMS, "No memory for trans\n");
+ LOGP(DSMS, LOGL_ERROR, "No memory for trans\n");
/* FIXME: send some error message */
return -ENOMEM;
}
@@ -1069,7 +1112,7 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms)
DEBUGP(DSMS, "TX: SMS DELIVER\n");
- lchan->ts->trx->bts->network->stats.sms.delivered++;
+ counter_inc(lchan->ts->trx->bts->network->stats.sms.delivered);
return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref);
/* FIXME: enter 'wait for RP-ACK' state, start TR1N */
diff --git a/openbsc/src/gsm_04_80.c b/openbsc/src/gsm_04_80.c
index d3b472f30..8271274f1 100644
--- a/openbsc/src/gsm_04_80.c
+++ b/openbsc/src/gsm_04_80.c
@@ -29,11 +29,11 @@
#include <string.h>
#include <errno.h>
-#include <openbsc/msgb.h>
-#include <openbsc/tlv.h>
+#include <osmocore/msgb.h>
+#include <osmocore/tlv.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_utils.h>
+#include <osmocore/gsm_utils.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/gsm_04_80.h>
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index 8330b5190..bd331911e 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -1,4 +1,4 @@
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
+/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
@@ -26,23 +26,14 @@
#include <ctype.h>
#include <openbsc/gsm_data.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
+#include <osmocore/gsm_utils.h>
#include <openbsc/abis_nm.h>
+#include <osmocore/statistics.h>
void *tall_bsc_ctx;
-const char *get_value_string(const struct value_string *vs, u_int32_t val)
-{
- int i;
-
- for (i = 0;; i++) {
- if (vs[i].value == 0 && vs[i].str == NULL)
- break;
- if (vs[i].value == val)
- return vs[i].str;
- }
- return "unknown";
-}
+static LLIST_HEAD(bts_models);
void set_ts_e1link(struct gsm_bts_trx_ts *ts, u_int8_t e1_nr,
u_int8_t e1_ts, u_int8_t e1_ts_ss)
@@ -92,7 +83,7 @@ static const char *lchan_names[] = {
[GSM_LCHAN_UNKNOWN] = "UNKNOWN",
};
-const char *gsm_lchan_name(enum gsm_chan_t c)
+const char *gsm_lchant_name(enum gsm_chan_t c)
{
if (c >= ARRAY_SIZE(lchan_names))
return "INVALID";
@@ -100,6 +91,20 @@ const char *gsm_lchan_name(enum gsm_chan_t c)
return lchan_names[c];
}
+static const struct value_string lchan_s_names[] = {
+ { LCHAN_S_NONE, "NONE" },
+ { LCHAN_S_ACT_REQ, "ACTIVATION REQUESTED" },
+ { LCHAN_S_ACTIVE, "ACTIVE" },
+ { LCHAN_S_INACTIVE, "INACTIVE" },
+ { LCHAN_S_REL_REQ, "RELEASE REQUESTED" },
+ { 0, NULL },
+};
+
+const char *gsm_lchans_name(enum gsm_lchan_state s)
+{
+ return get_value_string(lchan_s_names, s);
+}
+
static const char *chreq_names[] = {
[GSM_CHREQ_REASON_EMERG] = "EMERGENCY",
[GSM_CHREQ_REASON_PAG] = "PAGING",
@@ -116,6 +121,29 @@ const char *gsm_chreq_name(enum gsm_chreq_reason_t c)
return chreq_names[c];
}
+static struct gsm_bts_model *bts_model_find(enum gsm_bts_type type)
+{
+ struct gsm_bts_model *model;
+
+ llist_for_each_entry(model, &bts_models, list) {
+ if (model->type == type)
+ return model;
+ }
+
+ return NULL;
+}
+
+int gsm_bts_model_register(struct gsm_bts_model *model)
+{
+ if (bts_model_find(model->type))
+ return -EEXIST;
+
+ tlv_def_patch(&model->nm_att_tlvdef, &nm_att_tlvdef);
+ llist_add_tail(&model->list, &bts_models);
+ return 0;
+}
+
+
struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)
{
struct gsm_bts_trx *trx = talloc_zero(bts, struct gsm_bts_trx);
@@ -126,6 +154,7 @@ struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)
trx->bts = bts;
trx->nr = bts->num_trx++;
+ trx->nm_state.administrative = NM_STATE_UNLOCKED;
for (k = 0; k < TRX_NR_TS; k++) {
struct gsm_bts_trx_ts *ts = &trx->ts[k];
@@ -145,6 +174,9 @@ struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)
}
}
+ if (trx->nr != 0)
+ trx->nominal_power = bts->c0->nominal_power;
+
llist_add_tail(&trx->list, &bts->trx_list);
return trx;
@@ -154,14 +186,21 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type,
u_int8_t tsc, u_int8_t bsic)
{
struct gsm_bts *bts = talloc_zero(net, struct gsm_bts);
+ struct gsm_bts_model *model = bts_model_find(type);
int i;
if (!bts)
return NULL;
+ if (!model && type != GSM_BTS_TYPE_UNKNOWN) {
+ talloc_free(bts);
+ return NULL;
+ }
+
bts->network = net;
bts->nr = net->num_bts++;
bts->type = type;
+ bts->model = model;
bts->tsc = tsc;
bts->bsic = bsic;
bts->num_trx = 0;
@@ -175,6 +214,10 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type,
bts->si_common.cell_alloc.data = bts->si_common.data.cell_alloc;
bts->si_common.cell_alloc.data_len =
sizeof(bts->si_common.data.cell_alloc);
+ bts->si_common.rach_control.re = 1; /* no re-establishment */
+ bts->si_common.rach_control.tx_integer = 9; /* 12 slots spread - 217/115 slots delay */
+ bts->si_common.rach_control.max_trans = 3; /* 7 retransmissions */
+ bts->si_common.rach_control.t2 = 4; /* no emergency calls */
for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) {
bts->gprs.nsvc[i].bts = bts;
@@ -206,6 +249,7 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c
net->country_code = country_code;
net->network_code = network_code;
net->num_bts = 0;
+ net->reject_cause = GSM48_REJECT_ROAMING_NOT_ALLOWED;
net->T3101 = GSM_T3101_DEFAULT;
net->T3113 = GSM_T3113_DEFAULT;
/* FIXME: initialize all other timers! */
@@ -222,6 +266,32 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c
INIT_LLIST_HEAD(&net->upqueue);
INIT_LLIST_HEAD(&net->bts_list);
+ net->stats.chreq.total = counter_alloc("net.chreq.total");
+ net->stats.chreq.no_channel = counter_alloc("net.chreq.no_channel");
+ net->stats.handover.attempted = counter_alloc("net.handover.attempted");
+ net->stats.handover.no_channel = counter_alloc("net.handover.no_channel");
+ net->stats.handover.timeout = counter_alloc("net.handover.timeout");
+ net->stats.handover.completed = counter_alloc("net.handover.completed");
+ net->stats.handover.failed = counter_alloc("net.handover.failed");
+ net->stats.loc_upd_type.attach = counter_alloc("net.loc_upd_type.attach");
+ net->stats.loc_upd_type.normal = counter_alloc("net.loc_upd_type.normal");
+ net->stats.loc_upd_type.periodic = counter_alloc("net.loc_upd_type.periodic");
+ net->stats.loc_upd_type.detach = counter_alloc("net.imsi_detach.count");
+ net->stats.loc_upd_resp.reject = counter_alloc("net.loc_upd_resp.reject");
+ net->stats.loc_upd_resp.accept = counter_alloc("net.loc_upd_resp.accept");
+ net->stats.paging.attempted = counter_alloc("net.paging.attempted");
+ net->stats.paging.detached = counter_alloc("net.paging.detached");
+ net->stats.paging.completed = counter_alloc("net.paging.completed");
+ net->stats.paging.expired = counter_alloc("net.paging.expired");
+ net->stats.sms.submitted = counter_alloc("net.sms.submitted");
+ net->stats.sms.no_receiver = counter_alloc("net.sms.no_receiver");
+ net->stats.sms.delivered = counter_alloc("net.sms.delivered");
+ net->stats.sms.rp_err_mem = counter_alloc("net.sms.rp_err_mem");
+ net->stats.sms.rp_err_other = counter_alloc("net.sms.rp_err_other");
+ net->stats.call.dialled = counter_alloc("net.call.dialled");
+ net->stats.call.alerted = counter_alloc("net.call.alerted");
+ net->stats.call.connected = counter_alloc("net.call.connected");
+
net->mncc_recv = mncc_recv;
net->core_country_code = -1;
@@ -282,6 +352,15 @@ struct gsm_bts_trx *gsm_bts_trx_num(struct gsm_bts *bts, int num)
static char ts2str[255];
+char *gsm_trx_name(struct gsm_bts_trx *trx)
+{
+ snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d)",
+ trx->bts->nr, trx->nr);
+
+ return ts2str;
+}
+
+
char *gsm_ts_name(struct gsm_bts_trx_ts *ts)
{
snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d)",
@@ -290,6 +369,16 @@ char *gsm_ts_name(struct gsm_bts_trx_ts *ts)
return ts2str;
}
+char *gsm_lchan_name(struct gsm_lchan *lchan)
+{
+ struct gsm_bts_trx_ts *ts = lchan->ts;
+
+ snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d,ss=%d)",
+ ts->trx->bts->nr, ts->trx->nr, ts->nr, lchan->nr);
+
+ return ts2str;
+}
+
static const char *bts_types[] = {
[GSM_BTS_TYPE_UNKNOWN] = "unknown",
[GSM_BTS_TYPE_BS11] = "bs11",
@@ -313,6 +402,17 @@ const char *btstype2str(enum gsm_bts_type type)
return bts_types[type];
}
+struct gsm_bts_trx *gsm_bts_trx_by_nr(struct gsm_bts *bts, int nr)
+{
+ struct gsm_bts_trx *trx;
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ if (trx->nr == nr)
+ return trx;
+ }
+ return NULL;
+}
+
/* Search for a BTS in the given Location Area; optionally start searching
* with start_bts (for continuing to search after the first result) */
struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac,
@@ -340,47 +440,6 @@ struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac,
return NULL;
}
-char *gsm_band_name(enum gsm_band band)
-{
- switch (band) {
- case GSM_BAND_400:
- return "GSM400";
- case GSM_BAND_850:
- return "GSM850";
- case GSM_BAND_900:
- return "GSM900";
- case GSM_BAND_1800:
- return "DCS1800";
- case GSM_BAND_1900:
- return "PCS1900";
- }
- return "invalid";
-}
-
-enum gsm_band gsm_band_parse(const char* mhz)
-{
- while (*mhz && !isdigit(*mhz))
- mhz++;
-
- if (*mhz == '\0')
- return -EINVAL;
-
- switch (atoi(mhz)) {
- case 400:
- return GSM_BAND_400;
- case 850:
- return GSM_BAND_850;
- case 900:
- return GSM_BAND_900;
- case 1800:
- return GSM_BAND_1800;
- case 1900:
- return GSM_BAND_1900;
- default:
- return -EINVAL;
- }
-}
-
static const char *gsm_auth_policy_names[] = {
[GSM_AUTH_POLICY_CLOSED] = "closed",
[GSM_AUTH_POLICY_ACCEPT_ALL] = "accept-all",
@@ -440,3 +499,27 @@ struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan)
return meas_rep;
}
+
+int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type)
+{
+ struct gsm_bts_model *model;
+
+ model = bts_model_find(type);
+ if (!model)
+ return -EINVAL;
+
+ bts->type = type;
+ bts->model = model;
+
+ switch (bts->type) {
+ case GSM_BTS_TYPE_NANOBTS:
+ /* Set the default OML Stream ID to 0xff */
+ bts->oml_tei = 0xff;
+ bts->c0->nominal_power = 23;
+ break;
+ case GSM_BTS_TYPE_BS11:
+ break;
+ }
+
+ return 0;
+}
diff --git a/openbsc/src/gsm_subscriber.c b/openbsc/src/gsm_subscriber.c
index c81b522d4..692508753 100644
--- a/openbsc/src/gsm_subscriber.c
+++ b/openbsc/src/gsm_subscriber.c
@@ -34,6 +34,14 @@
extern struct llist_head *subscr_bsc_active_subscriber(void);
+char *subscr_name(struct gsm_subscriber *subscr)
+{
+ if (strlen(subscr->name))
+ return subscr->name;
+
+ return subscr->imsi;
+}
+
struct gsm_subscriber *subscr_get_by_tmsi(struct gsm_network *net,
u_int32_t tmsi)
{
@@ -100,12 +108,15 @@ int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason)
s->net = bts->network;
/* Indicate "attached to LAC" */
s->lac = bts->location_area_code;
+ LOGP(DMM, LOGL_INFO, "Subscriber %s ATTACHED LAC=%u\n",
+ subscr_name(s), s->lac);
dispatch_signal(SS_SUBSCR, S_SUBSCR_ATTACHED, s);
break;
case GSM_SUBSCRIBER_UPDATE_DETACHED:
/* Only detach if we are currently in this area */
if (bts->location_area_code == s->lac)
s->lac = GSM_LAC_RESERVED_DETACHED;
+ LOGP(DMM, LOGL_INFO, "Subscriber %s DETACHED\n", subscr_name(s));
dispatch_signal(SS_SUBSCR, S_SUBSCR_DETACHED, s);
break;
default:
diff --git a/openbsc/src/gsm_subscriber_base.c b/openbsc/src/gsm_subscriber_base.c
index 929834e42..48e4510a2 100644
--- a/openbsc/src/gsm_subscriber_base.c
+++ b/openbsc/src/gsm_subscriber_base.c
@@ -27,11 +27,10 @@
#include <string.h>
#include <assert.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/paging.h>
#include <openbsc/debug.h>
-#include <openbsc/paging.h>
#include <openbsc/chan_alloc.h>
LLIST_HEAD(active_subscribers);
@@ -139,7 +138,7 @@ static void subscr_free(struct gsm_subscriber *subscr)
struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr)
{
subscr->use_count++;
- DEBUGP(DCC, "subscr %s usage increases usage to: %d\n",
+ DEBUGP(DREF, "subscr %s usage increases usage to: %d\n",
subscr->extension, subscr->use_count);
return subscr;
}
@@ -147,7 +146,7 @@ struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr)
struct gsm_subscriber *subscr_put(struct gsm_subscriber *subscr)
{
subscr->use_count--;
- DEBUGP(DCC, "subscr %s usage decreased usage to: %d\n",
+ DEBUGP(DREF, "subscr %s usage decreased usage to: %d\n",
subscr->extension, subscr->use_count);
if (subscr->use_count <= 0)
subscr_free(subscr);
diff --git a/openbsc/src/gsm_utils.c b/openbsc/src/gsm_utils.c
deleted file mode 100644
index 9439993db..000000000
--- a/openbsc/src/gsm_utils.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
- * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (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 <openbsc/gsm_data.h>
-#include <openbsc/gsm_utils.h>
-#include <execinfo.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-/* GSM 03.38 6.2.1 Charachter packing */
-int gsm_7bit_decode(char *text, const u_int8_t *user_data, u_int8_t length)
-{
- int i = 0;
- int l = 0;
-
- /* FIXME: We need to account for user data headers here */
- i += l;
- for (; i < length; i ++)
- *(text ++) =
- ((user_data[(i * 7 + 7) >> 3] <<
- (7 - ((i * 7 + 7) & 7))) |
- (user_data[(i * 7) >> 3] >>
- ((i * 7) & 7))) & 0x7f;
- *text = '\0';
-
- return i - l;
-}
-
-
-/* GSM 03.38 6.2.1 Charachter packing */
-int gsm_7bit_encode(u_int8_t *result, const char *data)
-{
- int i,j = 0;
- unsigned char ch1, ch2;
- int shift = 0;
-
- for ( i=0; i<strlen(data); i++ ) {
-
- ch1 = data[i] & 0x7F;
- ch1 = ch1 >> shift;
- ch2 = data[(i+1)] & 0x7F;
- ch2 = ch2 << (7-shift);
-
- ch1 = ch1 | ch2;
-
- result[j++] = ch1;
-
- shift++;
-
- if ((shift == 7) && (i+1<strlen(data))) {
- shift = 0;
- i++;
- }
- }
-
- return i;
-}
-
-/* determine power control level for given dBm value, as indicated
- * by the tables in chapter 4.1.1 of GSM TS 05.05 */
-int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm)
-{
- switch (band) {
- case GSM_BAND_400:
- case GSM_BAND_900:
- case GSM_BAND_850:
- if (dbm >= 39)
- return 0;
- else if (dbm < 5)
- return 19;
- else {
- /* we are guaranteed to have (5 <= dbm < 39) */
- return 2 + ((39 - dbm) / 2);
- }
- break;
- case GSM_BAND_1800:
- if (dbm >= 36)
- return 29;
- else if (dbm >= 34)
- return 30;
- else if (dbm >= 32)
- return 31;
- else if (dbm == 31)
- return 0;
- else {
- /* we are guaranteed to have (0 <= dbm < 31) */
- return (30 - dbm) / 2;
- }
- break;
- case GSM_BAND_1900:
- if (dbm >= 33)
- return 30;
- else if (dbm >= 32)
- return 31;
- else if (dbm == 31)
- return 0;
- else {
- /* we are guaranteed to have (0 <= dbm < 31) */
- return (30 - dbm) / 2;
- }
- break;
- }
- return -EINVAL;
-}
-
-int ms_pwr_dbm(enum gsm_band band, u_int8_t lvl)
-{
- lvl &= 0x1f;
-
- switch (band) {
- case GSM_BAND_400:
- case GSM_BAND_900:
- case GSM_BAND_850:
- if (lvl < 2)
- return 39;
- else if (lvl < 20)
- return 39 - ((lvl - 2) * 2) ;
- else
- return 5;
- break;
- case GSM_BAND_1800:
- if (lvl < 16)
- return 30 - (lvl * 2);
- else if (lvl < 29)
- return 0;
- else
- return 36 - ((lvl - 29) * 2);
- break;
- case GSM_BAND_1900:
- if (lvl < 16)
- return 30 - (lvl * 2);
- else if (lvl < 30)
- return -EINVAL;
- else
- return 33 - (lvl - 30);
- break;
- }
- return -EINVAL;
-}
-
-/* According to TS 08.05 Chapter 8.1.4 */
-int rxlev2dbm(u_int8_t rxlev)
-{
- if (rxlev > 63)
- rxlev = 63;
-
- return -110 + rxlev;
-}
-
-/* According to TS 08.05 Chapter 8.1.4 */
-u_int8_t dbm2rxlev(int dbm)
-{
- int rxlev = dbm + 110;
-
- if (rxlev > 63)
- rxlev = 63;
- else if (rxlev < 0)
- rxlev = 0;
-
- return rxlev;
-}
-
-void generate_backtrace()
-{
- int i, nptrs;
- void *buffer[100];
- char **strings;
-
- nptrs = backtrace(buffer, ARRAY_SIZE(buffer));
- printf("backtrace() returned %d addresses\n", nptrs);
-
- strings = backtrace_symbols(buffer, nptrs);
- if (!strings)
- return;
-
- for (i = 1; i < nptrs; i++)
- printf("%s\n", strings[i]);
-
- free(strings);
-}
diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c
index b37cecddb..efafca6e2 100644
--- a/openbsc/src/handover_decision.c
+++ b/openbsc/src/handover_decision.c
@@ -25,14 +25,14 @@
#include <stdlib.h>
#include <errno.h>
-#include <openbsc/msgb.h>
+#include <osmocore/msgb.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/meas_rep.h>
#include <openbsc/signal.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/handover.h>
-#include <openbsc/gsm_utils.h>
+#include <osmocore/gsm_utils.h>
/* issue handover to a cell identified by ARFCN and BSIC */
static int handover_to_arfcn_bsic(struct gsm_lchan *lchan,
diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c
index d40374f10..6b56bad28 100644
--- a/openbsc/src/handover_logic.c
+++ b/openbsc/src/handover_logic.c
@@ -29,16 +29,16 @@
#include <time.h>
#include <netinet/in.h>
-#include <openbsc/msgb.h>
+#include <osmocore/msgb.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_utils.h>
+#include <osmocore/gsm_utils.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/signal.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/transaction.h>
#include <openbsc/rtp_proxy.h>
@@ -97,12 +97,12 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n",
old_lchan->ts->trx->bts->nr, bts->nr);
- bts->network->stats.handover.attempted++;
+ counter_inc(bts->network->stats.handover.attempted);
new_lchan = lchan_alloc(bts, old_lchan->type);
if (!new_lchan) {
LOGP(DHO, LOGL_NOTICE, "No free channel\n");
- bts->network->stats.handover.no_channel++;
+ counter_inc(bts->network->stats.handover.no_channel);
return -ENOSPC;
}
@@ -144,9 +144,10 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
static void ho_T3103_cb(void *_ho)
{
struct bsc_handover *ho = _ho;
+ struct gsm_network *net = ho->new_lchan->ts->trx->bts->network;
DEBUGP(DHO, "HO T3103 expired\n");
- ho->new_lchan->ts->trx->bts->network->stats.handover.timeout++;
+ counter_inc(net->stats.handover.timeout);
lchan_free(ho->new_lchan);
llist_del(&ho->list);
@@ -207,6 +208,7 @@ static int ho_chan_activ_nack(struct gsm_lchan *new_lchan)
/* GSM 04.08 HANDOVER COMPLETE has been received on new channel */
static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
{
+ struct gsm_network *net = new_lchan->ts->trx->bts->network;
struct bsc_handover *ho;
ho = bsc_ho_by_new_lchan(new_lchan);
@@ -215,7 +217,12 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
return -ENODEV;
}
- new_lchan->ts->trx->bts->network->stats.handover.completed++;
+ LOGP(DHO, LOGL_INFO, "Subscriber %s HO from BTS %u->%u on ARFCN "
+ "%u->%u\n", subscr_name(ho->old_lchan->subscr),
+ ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr,
+ ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn);
+
+ counter_inc(net->stats.handover.completed);
bsc_del_timer(&ho->T3103);
@@ -235,6 +242,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
/* GSM 04.08 HANDOVER FAIL has been received */
static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan)
{
+ struct gsm_network *net = old_lchan->ts->trx->bts->network;
struct bsc_handover *ho;
ho = bsc_ho_by_old_lchan(old_lchan);
@@ -243,7 +251,7 @@ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan)
return -ENODEV;
}
- old_lchan->ts->trx->bts->network->stats.handover.failed++;
+ counter_inc(net->stats.handover.failed);
bsc_del_timer(&ho->T3103);
llist_del(&ho->list);
@@ -276,8 +284,8 @@ static int ho_ipac_crcx_ack(struct gsm_lchan *new_lchan)
ho = bsc_ho_by_new_lchan(new_lchan);
if (!ho) {
- LOGP(DHO, LOGL_ERROR, "unable to find HO record\n");
- return -ENODEV;
+ /* it is perfectly normal, we have CRCX even in non-HO cases */
+ return 0;
}
if (ipacc_rtp_direct) {
diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c
index 84b5641ad..943a5e88d 100644
--- a/openbsc/src/input/ipaccess.c
+++ b/openbsc/src/input/ipaccess.c
@@ -32,9 +32,9 @@
#include <sys/ioctl.h>
#include <arpa/inet.h>
-#include <openbsc/select.h>
-#include <openbsc/tlv.h>
-#include <openbsc/msgb.h>
+#include <osmocore/select.h>
+#include <osmocore/tlv.h>
+#include <osmocore/msgb.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/abis_nm.h>
@@ -42,7 +42,7 @@
#include <openbsc/subchan_demux.h>
#include <openbsc/e1_input.h>
#include <openbsc/ipaccess.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
/* data structure for one E1 interface with A-bis */
struct ia_e1_handle {
@@ -224,7 +224,7 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg,
&site_id, &bts_id, &trx_id);
bts = find_bts_by_unitid(e1h->gsmnet, site_id, bts_id);
if (!bts) {
- DEBUGP(DINP, "Unable to find BTS configuration for "
+ LOGP(DINP, LOGL_ERROR, "Unable to find BTS configuration for "
" %u/%u/%u, disconnecting\n", site_id, bts_id,
trx_id);
return -EIO;
@@ -281,7 +281,8 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error)
hh = (struct ipaccess_head *) msg->data;
ret = recv(bfd->fd, msg->data, 3, 0);
if (ret < 0) {
- fprintf(stderr, "recv error %s\n", strerror(errno));
+ if (errno != EAGAIN)
+ LOGP(DINP, LOGL_ERROR, "recv error %d %s\n", ret, strerror(errno));
msgb_free(msg);
*error = ret;
return NULL;
@@ -298,7 +299,7 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error)
len = ntohs(hh->len);
ret = recv(bfd->fd, msg->l2h, len, 0);
if (ret < len) {
- fprintf(stderr, "short read!\n");
+ LOGP(DINP, LOGL_ERROR, "short read!\n");
msgb_free(msg);
*error = -EIO;
return NULL;
@@ -321,7 +322,13 @@ static int handle_ts1_read(struct bsc_fd *bfd)
msg = ipaccess_read_msg(bfd, &error);
if (!msg) {
if (error == 0) {
- fprintf(stderr, "BTS disappeared, dead socket\n");
+ link = e1inp_lookup_sign_link(e1i_ts, IPAC_PROTO_OML, 0);
+ if (link) {
+ link->trx->bts->ip_access.flags = 0;
+ LOGP(DINP, LOGL_NOTICE, "BTS %u disappeared, dead socket\n",
+ link->trx->bts->nr);
+ } else
+ LOGP(DINP, LOGL_NOTICE, "unknown BTS disappeared, dead socket\n");
e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_RSL);
e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_OML);
bsc_unregister_fd(bfd);
@@ -351,7 +358,8 @@ static int handle_ts1_read(struct bsc_fd *bfd)
link = e1inp_lookup_sign_link(e1i_ts, hh->proto, 0);
if (!link) {
- printf("no matching signalling link for hh->proto=0x%02x\n", hh->proto);
+ LOGP(DINP, LOGL_ERROR, "no matching signalling link for "
+ "hh->proto=0x%02x\n", hh->proto);
msgb_free(msg);
return -EIO;
}
@@ -373,7 +381,7 @@ static int handle_ts1_read(struct bsc_fd *bfd)
ret = abis_nm_rcvmsg(msg);
break;
default:
- DEBUGP(DMI, "Unknown IP.access protocol proto=0x%02x\n", hh->proto);
+ LOGP(DINP, LOGL_NOTICE, "Unknown IP.access protocol proto=0x%02x\n", hh->proto);
msgb_free(msg);
break;
}
@@ -473,7 +481,7 @@ static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what)
if (what & BSC_FD_WRITE)
rc = handle_ts1_write(bfd);
} else
- fprintf(stderr, "unknown E1 TS type %u\n", e1i_ts->type);
+ LOGP(DINP, LOGL_ERROR, "unknown E1 TS type %u\n", e1i_ts->type);
return rc;
}
@@ -503,7 +511,8 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
perror("accept");
return ret;
}
- DEBUGP(DINP, "accept()ed new OML link from %s\n", inet_ntoa(sa.sin_addr));
+ LOGP(DINP, LOGL_NOTICE, "accept()ed new OML link from %s\n",
+ inet_ntoa(sa.sin_addr));
line = talloc_zero(tall_bsc_ctx, struct e1inp_line);
if (!line) {
@@ -525,7 +534,7 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
bfd->when = BSC_FD_READ;
ret = bsc_register_fd(bfd);
if (ret < 0) {
- fprintf(stderr, "could not register FD\n");
+ LOGP(DINP, LOGL_ERROR, "could not register FD\n");
close(bfd->fd);
talloc_free(line);
return ret;
@@ -561,13 +570,13 @@ static int rsl_listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
perror("accept");
return bfd->fd;
}
- DEBUGP(DINP, "accept()ed new RSL link from %s\n", inet_ntoa(sa.sin_addr));
+ LOGP(DINP, LOGL_NOTICE, "accept()ed new RSL link from %s\n", inet_ntoa(sa.sin_addr));
bfd->priv_nr = 2;
bfd->cb = ipaccess_fd_cb;
bfd->when = BSC_FD_READ;
ret = bsc_register_fd(bfd);
if (ret < 0) {
- fprintf(stderr, "could not register FD\n");
+ LOGP(DINP, LOGL_ERROR, "could not register FD\n");
close(bfd->fd);
talloc_free(bfd);
return ret;
@@ -589,6 +598,11 @@ static int make_sock(struct bsc_fd *bfd, u_int16_t port,
bfd->when = BSC_FD_READ;
//bfd->data = line;
+ if (bfd->fd < 0) {
+ LOGP(DINP, LOGL_ERROR, "could not create TCP socket.\n");
+ return -EIO;
+ }
+
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
@@ -598,20 +612,23 @@ static int make_sock(struct bsc_fd *bfd, u_int16_t port,
ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
if (ret < 0) {
- fprintf(stderr, "could not bind l2 socket %s\n",
+ LOGP(DINP, LOGL_ERROR, "could not bind l2 socket %s\n",
strerror(errno));
+ close(bfd->fd);
return -EIO;
}
ret = listen(bfd->fd, 1);
if (ret < 0) {
perror("listen");
+ close(bfd->fd);
return ret;
}
ret = bsc_register_fd(bfd);
if (ret < 0) {
perror("register_listen_fd");
+ close(bfd->fd);
return ret;
}
return 0;
@@ -630,11 +647,16 @@ int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa)
bfd->data = line;
bfd->priv_nr = 1;
+ if (bfd->fd < 0) {
+ LOGP(DINP, LOGL_ERROR, "could not create TCP socket.\n");
+ return -EIO;
+ }
+
setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa));
if (ret < 0) {
- fprintf(stderr, "could not connect socket\n");
+ LOGP(DINP, LOGL_ERROR, "could not connect socket\n");
close(bfd->fd);
return ret;
}
@@ -668,12 +690,12 @@ int ipaccess_setup(struct gsm_network *gsmnet)
e1h->gsmnet = gsmnet;
/* Listen for OML connections */
- ret = make_sock(&e1h->listen_fd, 3002, listen_fd_cb);
+ ret = make_sock(&e1h->listen_fd, IPA_TCP_PORT_OML, listen_fd_cb);
if (ret < 0)
return ret;
/* Listen for RSL connections */
- ret = make_sock(&e1h->rsl_listen_fd, 3003, rsl_listen_fd_cb);
+ ret = make_sock(&e1h->rsl_listen_fd, IPA_TCP_PORT_RSL, rsl_listen_fd_cb);
return ret;
}
diff --git a/openbsc/src/input/misdn.c b/openbsc/src/input/misdn.c
index 135cfad48..56930d498 100644
--- a/openbsc/src/input/misdn.c
+++ b/openbsc/src/input/misdn.c
@@ -41,15 +41,15 @@
#define PF_ISDN AF_ISDN
#endif
-#include <openbsc/select.h>
-#include <openbsc/msgb.h>
+#include <osmocore/select.h>
+#include <osmocore/msgb.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/abis_nm.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/subchan_demux.h>
#include <openbsc/e1_input.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#define TS1_ALLOC_SIZE 300
diff --git a/openbsc/src/ipaccess-config.c b/openbsc/src/ipaccess-config.c
deleted file mode 100644
index c50a46581..000000000
--- a/openbsc/src/ipaccess-config.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/* ip.access nanoBTS configuration tool */
-
-/* (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 <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <sys/types.h>
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-
-#include <openbsc/select.h>
-#include <openbsc/timer.h>
-#include <openbsc/ipaccess.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/e1_input.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/signal.h>
-#include <openbsc/debug.h>
-
-static struct gsm_network *gsmnet;
-
-static int net_listen_testnr;
-static int restart;
-static char *prim_oml_ip;
-static char *unit_id;
-static u_int16_t nv_flags;
-static u_int16_t nv_mask;
-
-/*
-static u_int8_t prim_oml_attr[] = { 0x95, 0x00, 7, 0x88, 192, 168, 100, 11, 0x00, 0x00 };
-static u_int8_t unit_id_attr[] = { 0x91, 0x00, 9, '2', '3', '4', '2', '/' , '0', '/', '0', 0x00 };
-*/
-
-/*
- * Callback function for NACK on the OML NM
- *
- * Currently we send the config requests but don't check the
- * result. The nanoBTS will send us a NACK when we did something the
- * BTS didn't like.
- */
-static int ipacc_msg_nack(u_int8_t mt)
-{
- fprintf(stderr, "Failure to set attribute. This seems fatal\n");
- exit(-1);
- return 0;
-}
-
-struct ipacc_ferr_elem {
- int16_t freq_err;
- u_int8_t freq_qual;
- u_int8_t arfcn;
-} __attribute__((packed));
-
-struct ipacc_cusage_elem {
- u_int16_t arfcn:10,
- rxlev:6;
-} __attribute__ ((packed));
-
-static int test_rep(void *_msg)
-{
- struct msgb *msg = _msg;
- struct abis_om_fom_hdr *foh = msgb_l3(msg);
- u_int16_t test_rep_len, ferr_list_len;
- struct ipacc_ferr_elem *ife;
- struct ipac_bcch_info binfo;
- int i, rc;
-
- DEBUGP(DNM, "TEST REPORT: ");
-
- if (foh->data[0] != NM_ATT_TEST_NO ||
- foh->data[2] != NM_ATT_TEST_REPORT)
- return -EINVAL;
-
- DEBUGPC(DNM, "test_no=0x%02x ", foh->data[1]);
- /* data[2] == NM_ATT_TEST_REPORT */
- /* data[3..4]: test_rep_len */
- test_rep_len = ntohs(*(u_int16_t *) &foh->data[3]);
- /* data[5]: ip.access test result */
- DEBUGPC(DNM, "test_res=%s\n", ipacc_testres_name(foh->data[5]));
-
- /* data[6]: ip.access nested IE. 3 == freq_err_list */
- switch (foh->data[6]) {
- case NM_IPAC_EIE_FREQ_ERR_LIST:
- /* data[7..8]: length of ferr_list */
- ferr_list_len = ntohs(*(u_int16_t *) &foh->data[7]);
-
- /* data[9...]: frequency error list elements */
- for (i = 0; i < ferr_list_len; i+= sizeof(*ife)) {
- ife = (struct ipacc_ferr_elem *) (foh->data + 9 + i);
- DEBUGP(DNM, "==> ARFCN %4u, Frequency Error %6hd\n",
- ife->arfcn, ntohs(ife->freq_err));
- }
- break;
- case NM_IPAC_EIE_CHAN_USE_LIST:
- /* data[7..8]: length of ferr_list */
- ferr_list_len = ntohs(*(u_int16_t *) &foh->data[7]);
-
- /* data[9...]: channel usage list elements */
- for (i = 0; i < ferr_list_len; i+= 2) {
- u_int16_t *cu_ptr = (u_int16_t *)(foh->data + 9 + i);
- u_int16_t cu = ntohs(*cu_ptr);
- DEBUGP(DNM, "==> ARFCN %4u, RxLev %2u\n",
- cu & 0x3ff, cu >> 10);
- }
- break;
- case NM_IPAC_EIE_BCCH_INFO_TYPE:
- break;
- case NM_IPAC_EIE_BCCH_INFO:
- rc = ipac_parse_bcch_info(&binfo, foh->data+6);
- if (rc < 0) {
- DEBUGP(DNM, "BCCH Info parsing failed\n");
- break;
- }
- DEBUGP(DNM, "==> ARFCN %u, RxLev %2u, RxQual %2u: %3d-%d, LAC %d CI %d\n",
- binfo.arfcn, binfo.rx_lev, binfo.rx_qual,
- binfo.cgi.mcc, binfo.cgi.mnc,
- binfo.cgi.lac, binfo.cgi.ci);
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static int nm_sig_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- u_int8_t *msg_type;
-
- switch (signal) {
- case S_NM_IPACC_NACK:
- msg_type = signal_data;
- return ipacc_msg_nack(*msg_type);
- case S_NM_TEST_REP:
- return test_rep(signal_data);
- default:
- break;
- }
-
- return 0;
-}
-
-static void bootstrap_om(struct gsm_bts *bts)
-{
- int len;
- static u_int8_t buf[1024];
- u_int8_t *cur = buf;
-
- printf("OML link established\n");
-
- if (unit_id) {
- len = strlen(unit_id);
- if (len > sizeof(buf)-10)
- return;
- buf[0] = NM_ATT_IPACC_UNIT_ID;
- buf[1] = (len+1) >> 8;
- buf[2] = (len+1) & 0xff;
- memcpy(buf+3, unit_id, len);
- buf[3+len] = 0;
- printf("setting Unit ID to '%s'\n", unit_id);
- abis_nm_ipaccess_set_nvattr(bts, buf, 3+len+1);
- }
- if (prim_oml_ip) {
- struct in_addr ia;
-
- if (!inet_aton(prim_oml_ip, &ia)) {
- fprintf(stderr, "invalid IP address: %s\n",
- prim_oml_ip);
- return;
- }
-
- /* 0x88 + IP + port */
- len = 1 + sizeof(ia) + 2;
-
- *cur++ = NM_ATT_IPACC_PRIM_OML_CFG_LIST;
- *cur++ = (len) >> 8;
- *cur++ = (len) & 0xff;
- *cur++ = 0x88;
- memcpy(cur, &ia, sizeof(ia));
- cur += sizeof(ia);
- *cur++ = 0;
- *cur++ = 0;
- printf("setting primary OML link IP to '%s'\n", inet_ntoa(ia));
- abis_nm_ipaccess_set_nvattr(bts, buf, 3+len);
- }
- if (nv_mask) {
- len = 4;
-
- *cur++ = NM_ATT_IPACC_NV_FLAGS;
- *cur++ = (len) >> 8;
- *cur++ = (len) & 0xff;
- *cur++ = nv_flags & 0xff;
- *cur++ = nv_mask & 0xff;
- *cur++ = nv_flags >> 8;
- *cur++ = nv_mask >> 8;
- printf("setting NV Flags/Mask to 0x%04x/0x%04x\n",
- nv_flags, nv_mask);
- abis_nm_ipaccess_set_nvattr(bts, buf, 3+len);
- }
-
- if (restart) {
- printf("restarting BTS\n");
- abis_nm_ipaccess_restart(bts);
- }
-}
-
-void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
-{
- switch (event) {
- case EVT_E1_TEI_UP:
- switch (type) {
- case E1INP_SIGN_OML:
- bootstrap_om(trx->bts);
- break;
- case E1INP_SIGN_RSL:
- /* FIXME */
- break;
- default:
- break;
- }
- break;
- case EVT_E1_TEI_DN:
- fprintf(stderr, "Lost some E1 TEI link\n");
- /* FIXME: deal with TEI or L1 link loss */
- break;
- default:
- break;
- }
-}
-
-int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
- struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
-{
- if (evt == EVT_STATECHG_OPER &&
- obj_class == NM_OC_RADIO_CARRIER &&
- new_state->availability == 3 &&
- net_listen_testnr) {
- struct gsm_bts_trx *trx = obj;
- u_int8_t phys_config[] = { 0x02, 0x0a, 0x00, 0x01, 0x02 };
- abis_nm_perform_test(trx->bts, 2, 0, 0, 0xff,
- net_listen_testnr, 1,
- phys_config, sizeof(phys_config));
- }
- return 0;
-}
-
-static void print_usage(void)
-{
- printf("Usage: ipaccess-config\n");
-}
-
-static void print_help(void)
-{
- printf(" -u --unit-id UNIT_ID\n");
- printf(" -o --oml-ip ip\n");
- printf(" -r --restart\n");
- printf(" -n flags/mask\tSet NVRAM attributes.\n");
- printf(" -l --listen testnr \tPerform specified test number\n");
- printf(" -h --help this text\n");
- printf(" -s --stream-id ID\n");
-}
-
-int main(int argc, char **argv)
-{
- struct gsm_bts *bts;
- struct sockaddr_in sin;
- int rc, option_index = 0, stream_id = 0xff;
-
- printf("ipaccess-config (C) 2009 by Harald Welte\n");
- printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n");
-
- while (1) {
- int c;
- unsigned long ul;
- char *slash;
- static struct option long_options[] = {
- { "unit-id", 1, 0, 'u' },
- { "oml-ip", 1, 0, 'o' },
- { "restart", 0, 0, 'r' },
- { "help", 0, 0, 'h' },
- { "listen", 1, 0, 'l' },
- { "stream-id", 1, 0, 's' },
- };
-
- c = getopt_long(argc, argv, "u:o:rn:l:hs:", long_options,
- &option_index);
-
- if (c == -1)
- break;
-
- switch (c) {
- case 'u':
- unit_id = optarg;
- break;
- case 'o':
- prim_oml_ip = optarg;
- break;
- case 'r':
- restart = 1;
- break;
- case 'n':
- slash = strchr(optarg, '/');
- if (!slash)
- exit(2);
- ul = strtoul(optarg, NULL, 16);
- nv_flags = ul & 0xffff;
- ul = strtoul(slash+1, NULL, 16);
- nv_mask = ul & 0xffff;
- break;
- case 'l':
- net_listen_testnr = atoi(optarg);
- break;
- case 's':
- stream_id = atoi(optarg);
- printf("foo: %d\n", stream_id);
- break;
- case 'h':
- print_usage();
- print_help();
- exit(0);
- }
- };
-
- if (optind >= argc) {
- fprintf(stderr, "you have to specify the IP address of the BTS. Use --help for more information\n");
- exit(2);
- }
-
- gsmnet = gsm_network_init(1, 1, NULL);
- if (!gsmnet)
- exit(1);
-
- bts = gsm_bts_alloc(gsmnet, GSM_BTS_TYPE_NANOBTS, HARDCODED_TSC,
- HARDCODED_BSIC);
- bts->oml_tei = stream_id;
-
- register_signal_handler(SS_NM, nm_sig_cb, NULL);
- printf("Trying to connect to ip.access BTS ...\n");
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- inet_aton(argv[optind], &sin.sin_addr);
- rc = ia_config_connect(bts, &sin);
- if (rc < 0) {
- perror("Error connecting to the BTS");
- exit(1);
- }
-
- while (1) {
- rc = bsc_select_main(0);
- if (rc < 0)
- exit(3);
- }
-
- exit(0);
-}
-
diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c
new file mode 100644
index 000000000..037ed6000
--- /dev/null
+++ b/openbsc/src/ipaccess/ipaccess-config.c
@@ -0,0 +1,667 @@
+/* ip.access nanoBTS configuration tool */
+
+/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2009 by Holger Hans Peter Freyther
+ * (C) 2009 by On Waves
+ * 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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+
+#include <osmocore/select.h>
+#include <osmocore/timer.h>
+#include <openbsc/ipaccess.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/e1_input.h>
+#include <openbsc/abis_nm.h>
+#include <openbsc/signal.h>
+#include <openbsc/debug.h>
+#include <osmocore/talloc.h>
+
+static struct gsm_network *gsmnet;
+
+static int net_listen_testnr;
+static int restart;
+static char *prim_oml_ip;
+static char *unit_id;
+static u_int16_t nv_flags;
+static u_int16_t nv_mask;
+static char *software = NULL;
+static int sw_load_state = 0;
+static int oml_state = 0;
+
+struct sw_load {
+ u_int8_t file_id[255];
+ u_int8_t file_id_len;
+
+ u_int8_t file_version[255];
+ u_int8_t file_version_len;
+};
+
+static void *tall_ctx_config = NULL;
+static struct sw_load *sw_load1 = NULL;
+static struct sw_load *sw_load2 = NULL;
+
+/*
+static u_int8_t prim_oml_attr[] = { 0x95, 0x00, 7, 0x88, 192, 168, 100, 11, 0x00, 0x00 };
+static u_int8_t unit_id_attr[] = { 0x91, 0x00, 9, '2', '3', '4', '2', '/' , '0', '/', '0', 0x00 };
+*/
+
+/*
+ * Callback function for NACK on the OML NM
+ *
+ * Currently we send the config requests but don't check the
+ * result. The nanoBTS will send us a NACK when we did something the
+ * BTS didn't like.
+ */
+static int ipacc_msg_nack(u_int8_t mt)
+{
+ fprintf(stderr, "Failure to set attribute. This seems fatal\n");
+ exit(-1);
+ return 0;
+}
+
+static int ipacc_msg_ack(u_int8_t mt, struct gsm_bts *bts)
+{
+ if (sw_load_state == 1) {
+ fprintf(stderr, "The new software is activaed.\n");
+
+ if (restart) {
+ abis_nm_ipaccess_restart(bts);
+ } else {
+ exit(0);
+ }
+ } else if (oml_state == 1) {
+ fprintf(stderr, "Set the primary OML IP.\n");
+ if (restart) {
+ abis_nm_ipaccess_restart(bts);
+ } else {
+ exit(0);
+ }
+ }
+
+ return 0;
+}
+
+struct ipacc_ferr_elem {
+ int16_t freq_err;
+ u_int8_t freq_qual;
+ u_int8_t arfcn;
+} __attribute__((packed));
+
+struct ipacc_cusage_elem {
+ u_int16_t arfcn:10,
+ rxlev:6;
+} __attribute__ ((packed));
+
+static int test_rep(void *_msg)
+{
+ struct msgb *msg = _msg;
+ struct abis_om_fom_hdr *foh = msgb_l3(msg);
+ u_int16_t test_rep_len, ferr_list_len;
+ struct ipacc_ferr_elem *ife;
+ struct ipac_bcch_info binfo;
+ int i, rc;
+
+ DEBUGP(DNM, "TEST REPORT: ");
+
+ if (foh->data[0] != NM_ATT_TEST_NO ||
+ foh->data[2] != NM_ATT_TEST_REPORT)
+ return -EINVAL;
+
+ DEBUGPC(DNM, "test_no=0x%02x ", foh->data[1]);
+ /* data[2] == NM_ATT_TEST_REPORT */
+ /* data[3..4]: test_rep_len */
+ test_rep_len = ntohs(*(u_int16_t *) &foh->data[3]);
+ /* data[5]: ip.access test result */
+ DEBUGPC(DNM, "test_res=%s\n", ipacc_testres_name(foh->data[5]));
+
+ /* data[6]: ip.access nested IE. 3 == freq_err_list */
+ switch (foh->data[6]) {
+ case NM_IPAC_EIE_FREQ_ERR_LIST:
+ /* data[7..8]: length of ferr_list */
+ ferr_list_len = ntohs(*(u_int16_t *) &foh->data[7]);
+
+ /* data[9...]: frequency error list elements */
+ for (i = 0; i < ferr_list_len; i+= sizeof(*ife)) {
+ ife = (struct ipacc_ferr_elem *) (foh->data + 9 + i);
+ DEBUGP(DNM, "==> ARFCN %4u, Frequency Error %6hd\n",
+ ife->arfcn, ntohs(ife->freq_err));
+ }
+ break;
+ case NM_IPAC_EIE_CHAN_USE_LIST:
+ /* data[7..8]: length of ferr_list */
+ ferr_list_len = ntohs(*(u_int16_t *) &foh->data[7]);
+
+ /* data[9...]: channel usage list elements */
+ for (i = 0; i < ferr_list_len; i+= 2) {
+ u_int16_t *cu_ptr = (u_int16_t *)(foh->data + 9 + i);
+ u_int16_t cu = ntohs(*cu_ptr);
+ DEBUGP(DNM, "==> ARFCN %4u, RxLev %2u\n",
+ cu & 0x3ff, cu >> 10);
+ }
+ break;
+ case NM_IPAC_EIE_BCCH_INFO_TYPE:
+ break;
+ case NM_IPAC_EIE_BCCH_INFO:
+ rc = ipac_parse_bcch_info(&binfo, foh->data+6);
+ if (rc < 0) {
+ DEBUGP(DNM, "BCCH Info parsing failed\n");
+ break;
+ }
+ DEBUGP(DNM, "==> ARFCN %u, RxLev %2u, RxQual %2u: %3d-%d, LAC %d CI %d\n",
+ binfo.arfcn, binfo.rx_lev, binfo.rx_qual,
+ binfo.cgi.mcc, binfo.cgi.mnc,
+ binfo.cgi.lac, binfo.cgi.ci);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int nm_sig_cb(unsigned int subsys, unsigned int signal,
+ void *handler_data, void *signal_data)
+{
+ struct ipacc_ack_signal_data *ipacc_data;
+
+ switch (signal) {
+ case S_NM_IPACC_NACK:
+ ipacc_data = signal_data;
+ return ipacc_msg_nack(ipacc_data->msg_type);
+ case S_NM_IPACC_ACK:
+ ipacc_data = signal_data;
+ return ipacc_msg_ack(ipacc_data->msg_type, ipacc_data->bts);
+ case S_NM_TEST_REP:
+ return test_rep(signal_data);
+ case S_NM_IPACC_RESTART_ACK:
+ printf("The BTS has acked the restart. Exiting.\n");
+ exit(0);
+ break;
+ case S_NM_IPACC_RESTART_NACK:
+ printf("The BTS has nacked the restart. Exiting.\n");
+ exit(0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* callback function passed to the ABIS OML code */
+static int percent;
+static int percent_old;
+static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg,
+ void *data, void *param)
+{
+ struct msgb *msg;
+ struct gsm_bts *bts;
+
+ if (hook != GSM_HOOK_NM_SWLOAD)
+ return 0;
+
+ bts = (struct gsm_bts *) data;
+
+ switch (event) {
+ case NM_MT_LOAD_INIT_ACK:
+ fprintf(stdout, "Software Load Initiate ACK\n");
+ break;
+ case NM_MT_LOAD_INIT_NACK:
+ fprintf(stderr, "ERROR: Software Load Initiate NACK\n");
+ exit(5);
+ break;
+ case NM_MT_LOAD_END_ACK:
+ fprintf(stderr, "LOAD END ACK...");
+ /* now make it the default */
+ sw_load_state = 1;
+
+ msg = msgb_alloc(1024, "sw: nvattr");
+ msg->l2h = msgb_put(msg, 3);
+ msg->l3h = &msg->l2h[3];
+
+ /* activate software */
+ if (sw_load1) {
+ msgb_v_put(msg, NM_ATT_SW_DESCR);
+ msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw_load1->file_id_len, sw_load1->file_id);
+ msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw_load1->file_version_len,
+ sw_load1->file_version);
+ }
+
+ if (sw_load2) {
+ msgb_v_put(msg, NM_ATT_SW_DESCR);
+ msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw_load2->file_id_len, sw_load2->file_id);
+ msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw_load2->file_version_len,
+ sw_load2->file_version);
+ }
+
+ /* fill in the data */
+ msg->l2h[0] = NM_ATT_IPACC_CUR_SW_CFG;
+ msg->l2h[1] = msgb_l3len(msg) >> 8;
+ msg->l2h[2] = msgb_l3len(msg) & 0xff;
+ printf("Foo l2h: %p l3h: %p... length l2: %u l3: %u\n", msg->l2h, msg->l3h, msgb_l2len(msg), msgb_l3len(msg));
+ abis_nm_ipaccess_set_nvattr(bts->c0, msg->l2h, msgb_l2len(msg));
+ msgb_free(msg);
+ break;
+ case NM_MT_LOAD_END_NACK:
+ fprintf(stderr, "ERROR: Software Load End NACK\n");
+ exit(3);
+ break;
+ case NM_MT_ACTIVATE_SW_NACK:
+ fprintf(stderr, "ERROR: Activate Software NACK\n");
+ exit(4);
+ break;
+ case NM_MT_ACTIVATE_SW_ACK:
+ break;
+ case NM_MT_LOAD_SEG_ACK:
+ percent = abis_nm_software_load_status(bts);
+ if (percent > percent_old)
+ printf("Software Download Progress: %d%%\n", percent);
+ percent_old = percent;
+ break;
+ case NM_MT_LOAD_ABORT:
+ fprintf(stderr, "ERROR: Load aborted by the BTS.\n");
+ exit(6);
+ break;
+ }
+ return 0;
+}
+
+static void bootstrap_om(struct gsm_bts *bts)
+{
+ int len;
+ static u_int8_t buf[1024];
+ u_int8_t *cur = buf;
+
+ printf("OML link established\n");
+
+ if (unit_id) {
+ len = strlen(unit_id);
+ if (len > sizeof(buf)-10)
+ return;
+ buf[0] = NM_ATT_IPACC_UNIT_ID;
+ buf[1] = (len+1) >> 8;
+ buf[2] = (len+1) & 0xff;
+ memcpy(buf+3, unit_id, len);
+ buf[3+len] = 0;
+ printf("setting Unit ID to '%s'\n", unit_id);
+ abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len+1);
+ }
+ if (prim_oml_ip) {
+ struct in_addr ia;
+
+ if (!inet_aton(prim_oml_ip, &ia)) {
+ fprintf(stderr, "invalid IP address: %s\n",
+ prim_oml_ip);
+ return;
+ }
+
+ /* 0x88 + IP + port */
+ len = 1 + sizeof(ia) + 2;
+
+ *cur++ = NM_ATT_IPACC_PRIM_OML_CFG_LIST;
+ *cur++ = (len) >> 8;
+ *cur++ = (len) & 0xff;
+ *cur++ = 0x88;
+ memcpy(cur, &ia, sizeof(ia));
+ cur += sizeof(ia);
+ *cur++ = 0;
+ *cur++ = 0;
+ printf("setting primary OML link IP to '%s'\n", inet_ntoa(ia));
+ oml_state = 1;
+ abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len);
+ }
+ if (nv_mask) {
+ len = 4;
+
+ *cur++ = NM_ATT_IPACC_NV_FLAGS;
+ *cur++ = (len) >> 8;
+ *cur++ = (len) & 0xff;
+ *cur++ = nv_flags & 0xff;
+ *cur++ = nv_mask & 0xff;
+ *cur++ = nv_flags >> 8;
+ *cur++ = nv_mask >> 8;
+ printf("setting NV Flags/Mask to 0x%04x/0x%04x\n",
+ nv_flags, nv_mask);
+ abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len);
+ }
+
+ if (restart && !prim_oml_ip && !software) {
+ printf("restarting BTS\n");
+ abis_nm_ipaccess_restart(bts);
+ }
+
+}
+
+void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
+{
+ switch (event) {
+ case EVT_E1_TEI_UP:
+ switch (type) {
+ case E1INP_SIGN_OML:
+ bootstrap_om(trx->bts);
+ break;
+ case E1INP_SIGN_RSL:
+ /* FIXME */
+ break;
+ default:
+ break;
+ }
+ break;
+ case EVT_E1_TEI_DN:
+ fprintf(stderr, "Lost some E1 TEI link\n");
+ /* FIXME: deal with TEI or L1 link loss */
+ break;
+ default:
+ break;
+ }
+}
+
+int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
+ struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
+{
+ if (evt == EVT_STATECHG_OPER &&
+ obj_class == NM_OC_RADIO_CARRIER &&
+ new_state->availability == 3) {
+ struct gsm_bts_trx *trx = obj;
+
+ if (net_listen_testnr) {
+ u_int8_t phys_config[] = { 0x02, 0x0a, 0x00, 0x01, 0x02 };
+ abis_nm_perform_test(trx->bts, 2, 0, 0, 0xff,
+ net_listen_testnr, 1,
+ phys_config, sizeof(phys_config));
+ } else if (software) {
+ int rc;
+ printf("Attempting software upload with '%s'\n", software);
+ rc = abis_nm_software_load(trx->bts, software, 19, 0, swload_cbfn, trx->bts);
+ if (rc < 0) {
+ fprintf(stderr, "Failed to start software load\n");
+ exit(-3);
+ }
+ }
+ }
+ return 0;
+}
+
+static struct sw_load *create_swload(struct sdp_header *header)
+{
+ struct sw_load *load;
+
+ load = talloc_zero(tall_ctx_config, struct sw_load);
+
+ strncpy((char *)load->file_id, header->firmware_info.sw_part, 20);
+ load->file_id_len = strlen(header->firmware_info.sw_part) + 1;
+
+ strncpy((char *)load->file_version, header->firmware_info.version, 20);
+ load->file_version_len = strlen(header->firmware_info.version) + 1;
+
+ return load;
+}
+
+static void find_sw_load_params(const char *filename)
+{
+ struct stat stat;
+ struct sdp_header *header;
+ struct llist_head *entry;
+ int fd;
+ void *tall_firm_ctx = 0;
+
+ entry = talloc_zero(tall_firm_ctx, struct llist_head);
+ INIT_LLIST_HEAD(entry);
+
+ fd = open(filename, O_RDONLY);
+ if (!fd) {
+ perror("nada");
+ return;
+ }
+
+ /* verify the file */
+ if (fstat(fd, &stat) == -1) {
+ perror("Can not stat the file");
+ return;
+ }
+
+ ipaccess_analyze_file(fd, stat.st_size, 0, entry);
+ if (close(fd) != 0) {
+ perror("Close failed.\n");
+ return;
+ }
+
+ /* try to find what we are looking for */
+ llist_for_each_entry(header, entry, entry) {
+ if (ntohs(header->firmware_info.more_more_magic) == 0x1000) {
+ sw_load1 = create_swload(header);
+ } else if (ntohs(header->firmware_info.more_more_magic) == 0x2001) {
+ sw_load2 = create_swload(header);
+ }
+ }
+
+ talloc_free(tall_firm_ctx);
+}
+
+static void analyze_firmware(const char *filename)
+{
+ struct stat stat;
+ struct sdp_header *header;
+ struct sdp_header_item *sub_entry;
+ struct llist_head *entry;
+ int fd;
+ void *tall_firm_ctx = 0;
+
+ entry = talloc_zero(tall_firm_ctx, struct llist_head);
+ INIT_LLIST_HEAD(entry);
+
+ printf("Opening possible firmware '%s'\n", filename);
+ fd = open(filename, O_RDONLY);
+ if (!fd) {
+ perror("nada");
+ return;
+ }
+
+ /* verify the file */
+ if (fstat(fd, &stat) == -1) {
+ perror("Can not stat the file");
+ return;
+ }
+
+ ipaccess_analyze_file(fd, stat.st_size, 0, entry);
+ if (close(fd) != 0) {
+ perror("Close failed.\n");
+ return;
+ }
+
+ llist_for_each_entry(header, entry, entry) {
+ printf("Printing header information:\n");
+ printf("more_more_magic: 0x%x\n", ntohs(header->firmware_info.more_more_magic));
+ printf("header_length: %u\n", ntohl(header->firmware_info.header_length));
+ printf("file_length: %u\n", ntohl(header->firmware_info.file_length));
+ printf("sw_part: %.20s\n", header->firmware_info.sw_part);
+ printf("text1: %.64s\n", header->firmware_info.text1);
+ printf("time: %.12s\n", header->firmware_info.time);
+ printf("date: %.14s\n", header->firmware_info.date);
+ printf("text2: %.10s\n", header->firmware_info.text2);
+ printf("version: %.20s\n", header->firmware_info.version);
+ printf("subitems...\n");
+
+ llist_for_each_entry(sub_entry, &header->header_list, entry) {
+ printf("\tsomething1: %u\n", sub_entry->header_entry.something1);
+ printf("\ttext1: %.64s\n", sub_entry->header_entry.text1);
+ printf("\ttime: %.12s\n", sub_entry->header_entry.time);
+ printf("\tdate: %.14s\n", sub_entry->header_entry.date);
+ printf("\ttext2: %.10s\n", sub_entry->header_entry.text2);
+ printf("\tversion: %.20s\n", sub_entry->header_entry.version);
+ printf("\tlength: %u\n", ntohl(sub_entry->header_entry.length));
+ printf("\taddr1: 0x%x\n", ntohl(sub_entry->header_entry.addr1));
+ printf("\taddr2: 0x%x\n", ntohl(sub_entry->header_entry.addr2));
+ printf("\tstart: 0x%x\n", ntohl(sub_entry->header_entry.start));
+ printf("\n\n");
+ }
+ printf("\n\n");
+ }
+
+ talloc_free(tall_firm_ctx);
+}
+
+static void print_usage(void)
+{
+ printf("Usage: ipaccess-config\n");
+}
+
+static void print_help(void)
+{
+ printf(" -u --unit-id UNIT_ID\n");
+ printf(" -o --oml-ip ip\n");
+ printf(" -r --restart\n");
+ printf(" -n flags/mask\tSet NVRAM attributes.\n");
+ printf(" -l --listen testnr \tPerform specified test number\n");
+ printf(" -h --help this text\n");
+ printf(" -s --stream-id ID\n");
+ printf(" -d --software firmware\n");
+ printf(" -f --firmware firmware Provide firmware information\n");
+}
+
+int main(int argc, char **argv)
+{
+ struct gsm_bts *bts;
+ struct sockaddr_in sin;
+ int rc, option_index = 0, stream_id = 0xff;
+ struct debug_target *stderr_target;
+
+ debug_init();
+ stderr_target = debug_target_create_stderr();
+ debug_add_target(stderr_target);
+ debug_set_all_filter(stderr_target, 1);
+ debug_set_log_level(stderr_target, 0);
+ debug_parse_category_mask(stderr_target, "DNM,0");
+ bts_model_nanobts_init();
+
+ printf("ipaccess-config (C) 2009 by Harald Welte\n");
+ printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n");
+
+ while (1) {
+ int c;
+ unsigned long ul;
+ char *slash;
+ static struct option long_options[] = {
+ { "unit-id", 1, 0, 'u' },
+ { "oml-ip", 1, 0, 'o' },
+ { "restart", 0, 0, 'r' },
+ { "help", 0, 0, 'h' },
+ { "listen", 1, 0, 'l' },
+ { "stream-id", 1, 0, 's' },
+ { "software", 1, 0, 'd' },
+ { "firmware", 1, 0, 'f' },
+ };
+
+ c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:", long_options,
+ &option_index);
+
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'u':
+ unit_id = optarg;
+ break;
+ case 'o':
+ prim_oml_ip = optarg;
+ break;
+ case 'r':
+ restart = 1;
+ break;
+ case 'n':
+ slash = strchr(optarg, '/');
+ if (!slash)
+ exit(2);
+ ul = strtoul(optarg, NULL, 16);
+ nv_flags = ul & 0xffff;
+ ul = strtoul(slash+1, NULL, 16);
+ nv_mask = ul & 0xffff;
+ break;
+ case 'l':
+ net_listen_testnr = atoi(optarg);
+ break;
+ case 's':
+ stream_id = atoi(optarg);
+ break;
+ case 'd':
+ software = strdup(optarg);
+ find_sw_load_params(optarg);
+ break;
+ case 'f':
+ analyze_firmware(optarg);
+ exit(0);
+ case 'h':
+ print_usage();
+ print_help();
+ exit(0);
+ }
+ };
+
+ if (optind >= argc) {
+ fprintf(stderr, "you have to specify the IP address of the BTS. Use --help for more information\n");
+ exit(2);
+ }
+
+ gsmnet = gsm_network_init(1, 1, NULL);
+ if (!gsmnet)
+ exit(1);
+
+ bts = gsm_bts_alloc(gsmnet, GSM_BTS_TYPE_NANOBTS, HARDCODED_TSC,
+ HARDCODED_BSIC);
+ /* ip.access supports up to 4 chained TRX */
+ gsm_bts_trx_alloc(bts);
+ gsm_bts_trx_alloc(bts);
+ gsm_bts_trx_alloc(bts);
+ bts->oml_tei = stream_id;
+
+ register_signal_handler(SS_NM, nm_sig_cb, NULL);
+ printf("Trying to connect to ip.access BTS ...\n");
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ inet_aton(argv[optind], &sin.sin_addr);
+ rc = ia_config_connect(bts, &sin);
+ if (rc < 0) {
+ perror("Error connecting to the BTS");
+ exit(1);
+ }
+
+ while (1) {
+ rc = bsc_select_main(0);
+ if (rc < 0)
+ exit(3);
+ }
+
+ exit(0);
+}
+
diff --git a/openbsc/src/ipaccess-find.c b/openbsc/src/ipaccess/ipaccess-find.c
index f469b6788..01f8a2d8d 100644
--- a/openbsc/src/ipaccess-find.c
+++ b/openbsc/src/ipaccess/ipaccess-find.c
@@ -8,8 +8,8 @@
#include <arpa/inet.h>
-#include <openbsc/select.h>
-#include <openbsc/timer.h>
+#include <osmocore/select.h>
+#include <osmocore/timer.h>
#include <openbsc/ipaccess.h>
#include <openbsc/gsm_data.h>
diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c
new file mode 100644
index 000000000..8aba50978
--- /dev/null
+++ b/openbsc/src/ipaccess/ipaccess-firmware.c
@@ -0,0 +1,123 @@
+/* Routines for parsing an ipacces SDP firmware file */
+
+/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.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 <openbsc/debug.h>
+#include <openbsc/ipaccess.h>
+#include <osmocore/talloc.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define PART_LENGTH 138
+
+static_assert(sizeof(struct sdp_header_entry) == 138, right_entry);
+static_assert(sizeof(struct sdp_firmware) == 160, _right_header_length);
+
+/* more magic, the second "int" in the header */
+static char more_magic[] = { 0x10, 0x02 };
+
+int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned int base_offset, struct llist_head *list)
+{
+ struct sdp_firmware *firmware_header = 0;
+ struct sdp_header *header;
+ char buf[4096];
+ int rc, i;
+
+ rc = read(fd, buf, sizeof(*firmware_header));
+ if (rc < 0) {
+ perror("Can not read header start.");
+ return -1;
+ }
+
+ firmware_header = (struct sdp_firmware *) &buf[0];
+ if (strncmp(firmware_header->magic, " SDP", 4) != 0) {
+ fprintf(stderr, "Wrong magic.\n");
+ return -1;
+ }
+
+ if (memcmp(firmware_header->more_magic, more_magic, 2) != 0) {
+ fprintf(stderr, "Wrong more magic. Got: 0x%x %x %x %x\n",
+ firmware_header->more_magic[0] & 0xff, firmware_header->more_magic[1] & 0xff,
+ firmware_header->more_magic[2] & 0xff, firmware_header->more_magic[3] & 0xff);
+ return -1;
+ }
+
+
+ if (!firmware_header)
+ return -1;
+
+ if (ntohl(firmware_header->file_length) != st_size) {
+ fprintf(stderr, "The filesize and the header do not match.\n");
+ return -1;
+ }
+
+ /* add the firmware */
+ header = talloc_zero(list, struct sdp_header);
+ header->firmware_info = *firmware_header;
+ INIT_LLIST_HEAD(&header->header_list);
+ llist_add(&header->entry, list);
+
+ /* this semantic appears to be only the case for 0x0000 */
+ if (firmware_header->more_more_magic != 0)
+ return -1;
+
+ if (ntohs(firmware_header->part_length) % PART_LENGTH != 0) {
+ fprintf(stderr, "The part length seems to be wrong.\n");
+ return -1;
+ }
+
+ /* look into each firmware now */
+ for (i = 0; i < ntohs(firmware_header->part_length) / PART_LENGTH; ++i) {
+ struct sdp_header_entry entry;
+ struct sdp_header_item *header_entry;
+ unsigned int offset = base_offset + sizeof(struct sdp_firmware);
+ offset += i * 138;
+
+ if (lseek(fd, offset, SEEK_SET) != offset) {
+ fprintf(stderr, "Can not seek to the offset: %u.\n", offset);
+ return -1;
+ }
+
+ rc = read(fd, &entry, sizeof(entry));
+ if (rc != sizeof(entry)) {
+ fprintf(stderr, "Can not read the header entry.\n");
+ return -1;
+ }
+
+ /* now we need to find the SDP file... */
+ offset = ntohl(entry.start) + 4 + base_offset;
+ if (lseek(fd, offset, SEEK_SET) != offset) {
+ perror("can't seek to sdp");
+ return -1;
+ }
+
+ header_entry = talloc_zero(header, struct sdp_header_item);
+ header_entry->header_entry = entry;
+ llist_add(&header_entry->entry, &header->header_list);
+
+ ipaccess_analyze_file(fd, ntohl(entry.length), offset, list);
+ }
+
+ return 0;
+}
+
diff --git a/openbsc/src/ipaccess/ipaccess-proxy.c b/openbsc/src/ipaccess/ipaccess-proxy.c
new file mode 100644
index 000000000..217e0bdf1
--- /dev/null
+++ b/openbsc/src/ipaccess/ipaccess-proxy.c
@@ -0,0 +1,1127 @@
+/* OpenBSC Abis/IP proxy 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 <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <openbsc/gsm_data.h>
+#include <osmocore/select.h>
+#include <osmocore/tlv.h>
+#include <osmocore/msgb.h>
+#include <openbsc/debug.h>
+#include <openbsc/ipaccess.h>
+#include <osmocore/talloc.h>
+
+static struct debug_target *stderr_target;
+
+/* one instance of an ip.access protocol proxy */
+struct ipa_proxy {
+ /* socket where we listen for incoming OML from BTS */
+ struct bsc_fd oml_listen_fd;
+ /* socket where we listen for incoming RSL from BTS */
+ struct bsc_fd rsl_listen_fd;
+ /* list of BTS's (struct ipa_bts_conn */
+ struct llist_head bts_list;
+ /* the BSC reconnect timer */
+ struct timer_list reconn_timer;
+};
+
+/* global pointer to the proxy structure */
+static struct ipa_proxy *ipp;
+
+struct ipa_proxy_conn {
+ struct bsc_fd fd;
+ struct llist_head tx_queue;
+ struct ipa_bts_conn *bts_conn;
+};
+
+#define MAX_TRX 4
+
+/* represents a particular BTS in our proxy */
+struct ipa_bts_conn {
+ /* list of BTS's (ipa_proxy->bts_list) */
+ struct llist_head list;
+ /* back pointer to the proxy which we belong to */
+ struct ipa_proxy *ipp;
+ /* the unit ID as determined by CCM */
+ struct {
+ u_int16_t site_id;
+ u_int16_t bts_id;
+ } unit_id;
+
+ /* incoming connections from BTS */
+ struct ipa_proxy_conn *oml_conn;
+ struct ipa_proxy_conn *rsl_conn[MAX_TRX];
+
+ /* outgoing connections to BSC */
+ struct ipa_proxy_conn *bsc_oml_conn;
+ struct ipa_proxy_conn *bsc_rsl_conn[MAX_TRX];
+
+ /* UDP sockets for BTS and BSC injection */
+ struct bsc_fd udp_bts_fd;
+ struct bsc_fd udp_bsc_fd;
+
+ char *id_tags[0xff];
+ u_int8_t *id_resp;
+ unsigned int id_resp_len;
+};
+
+enum ipp_fd_type {
+ OML_FROM_BTS = 1,
+ RSL_FROM_BTS = 2,
+ OML_TO_BSC = 3,
+ RSL_TO_BSC = 4,
+ UDP_TO_BTS = 5,
+ UDP_TO_BSC = 6,
+};
+
+/* some of the code against we link from OpenBSC needs this */
+void *tall_bsc_ctx;
+
+static char *listen_ipaddr;
+static char *bsc_ipaddr;
+
+#define PROXY_ALLOC_SIZE 300
+
+static const u_int8_t pong[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG };
+static const u_int8_t id_ack[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK };
+static const u_int8_t id_req[] = { 0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET,
+ 0x01, IPAC_IDTAG_UNIT,
+ 0x01, IPAC_IDTAG_MACADDR,
+ 0x01, IPAC_IDTAG_LOCATION1,
+ 0x01, IPAC_IDTAG_LOCATION2,
+ 0x01, IPAC_IDTAG_EQUIPVERS,
+ 0x01, IPAC_IDTAG_SWVERSION,
+ 0x01, IPAC_IDTAG_UNITNAME,
+ 0x01, IPAC_IDTAG_SERNR,
+ };
+
+static const char *idtag_names[] = {
+ [IPAC_IDTAG_SERNR] = "Serial_Number",
+ [IPAC_IDTAG_UNITNAME] = "Unit_Name",
+ [IPAC_IDTAG_LOCATION1] = "Location_1",
+ [IPAC_IDTAG_LOCATION2] = "Location_2",
+ [IPAC_IDTAG_EQUIPVERS] = "Equipment_Version",
+ [IPAC_IDTAG_SWVERSION] = "Software_Version",
+ [IPAC_IDTAG_IPADDR] = "IP_Address",
+ [IPAC_IDTAG_MACADDR] = "MAC_Address",
+ [IPAC_IDTAG_UNIT] = "Unit_ID",
+};
+
+static const char *ipac_idtag_name(int tag)
+{
+ if (tag >= ARRAY_SIZE(idtag_names))
+ return "unknown";
+
+ return idtag_names[tag];
+}
+
+static int ipac_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len)
+{
+ u_int8_t t_len;
+ u_int8_t t_tag;
+ u_int8_t *cur = buf;
+
+ while (cur < buf + len) {
+ t_len = *cur++;
+ t_tag = *cur++;
+
+ DEBUGPC(DMI, "%s='%s' ", ipac_idtag_name(t_tag), cur);
+
+ dec->lv[t_tag].len = t_len;
+ dec->lv[t_tag].val = cur;
+
+ cur += t_len;
+ }
+ return 0;
+}
+
+static int parse_unitid(const char *str, u_int16_t *site_id, u_int16_t *bts_id,
+ u_int16_t *trx_id)
+{
+ unsigned long ul;
+ char *endptr;
+ const char *nptr;
+
+ nptr = str;
+ ul = strtoul(nptr, &endptr, 10);
+ if (endptr <= nptr)
+ return -EINVAL;
+ if (site_id)
+ *site_id = ul & 0xffff;
+
+ if (*endptr++ != '/')
+ return -EINVAL;
+
+ nptr = endptr;
+ ul = strtoul(nptr, &endptr, 10);
+ if (endptr <= nptr)
+ return -EINVAL;
+ if (bts_id)
+ *bts_id = ul & 0xffff;
+
+ if (*endptr++ != '/')
+ return -EINVAL;
+
+ nptr = endptr;
+ ul = strtoul(nptr, &endptr, 10);
+ if (endptr <= nptr)
+ return -EINVAL;
+ if (trx_id)
+ *trx_id = ul & 0xffff;
+
+ return 0;
+}
+
+static struct ipa_bts_conn *find_bts_by_unitid(struct ipa_proxy *ipp,
+ u_int16_t site_id,
+ u_int16_t bts_id)
+{
+ struct ipa_bts_conn *ipbc;
+
+ llist_for_each_entry(ipbc, &ipp->bts_list, list) {
+ if (ipbc->unit_id.site_id == site_id &&
+ ipbc->unit_id.bts_id == bts_id)
+ return ipbc;
+ }
+
+ return NULL;
+}
+
+struct ipa_proxy_conn *alloc_conn(void)
+{
+ struct ipa_proxy_conn *ipc;
+
+ ipc = talloc_zero(tall_bsc_ctx, struct ipa_proxy_conn);
+ if (!ipc)
+ return NULL;
+
+ INIT_LLIST_HEAD(&ipc->tx_queue);
+
+ return ipc;
+}
+
+static int store_idtags(struct ipa_bts_conn *ipbc, struct tlv_parsed *tlvp)
+{
+ unsigned int i, len;
+
+ for (i = 0; i <= 0xff; i++) {
+ if (!TLVP_PRESENT(tlvp, i))
+ continue;
+
+ len = TLVP_LEN(tlvp, i);
+#if 0
+ if (!ipbc->id_tags[i])
+ ipbc->id_tags[i] = talloc_size(tall_bsc_ctx, len);
+ else
+#endif
+ ipbc->id_tags[i] = talloc_realloc_size(ipbc,
+ ipbc->id_tags[i], len);
+ if (!ipbc->id_tags[i])
+ return -ENOMEM;
+
+ memset(ipbc->id_tags[i], 0, len);
+ //memcpy(ipbc->id_tags[i], TLVP_VAL(tlvp, i), len);
+ }
+ return 0;
+}
+
+
+static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data);
+
+#define logp_ipbc_uid(ss, lvl, ipbc, trx_id) _logp_ipbc_uid(ss, lvl, __FILE__, __LINE__, ipbc, trx_id)
+
+static void _logp_ipbc_uid(unsigned int ss, unsigned int lvl, char *file, int line,
+ struct ipa_bts_conn *ipbc, u_int8_t trx_id)
+{
+ if (ipbc)
+ debugp2(ss, lvl, file, line, 0, "(%u/%u/%u) ", ipbc->unit_id.site_id,
+ ipbc->unit_id.bts_id, trx_id);
+ else
+ debugp2(ss, lvl, file, line, 0, "unknown ");
+}
+
+/* UDP socket handling */
+
+static int make_sock(struct bsc_fd *bfd, u_int16_t port, int proto, int priv_nr,
+ int (*cb)(struct bsc_fd *fd, unsigned int what),
+ void *data)
+{
+ struct sockaddr_in addr;
+ int ret, on = 1;
+
+ bfd->fd = socket(AF_INET, SOCK_DGRAM, proto);
+ bfd->cb = cb;
+ bfd->when = BSC_FD_READ;
+ bfd->data = data;
+ bfd->priv_nr = priv_nr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = INADDR_ANY;
+
+ setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+ ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
+ if (ret < 0) {
+ LOGP(DINP, LOGL_ERROR, "could not bind socket: %s\n",
+ strerror(errno));
+ return -EIO;
+ }
+
+ ret = bsc_register_fd(bfd);
+ if (ret < 0) {
+ perror("register UDP fd");
+ return ret;
+ }
+ return 0;
+}
+
+static int handle_udp_read(struct bsc_fd *bfd)
+{
+ struct ipa_bts_conn *ipbc = bfd->data;
+ struct ipa_proxy_conn *other_conn = NULL;
+ struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP UDP");
+ struct ipaccess_head *hh;
+ int ret;
+
+ /* with UDP sockets, we cannot read partial packets but have to read
+ * all of it in one go */
+ hh = (struct ipaccess_head *) msg->data;
+ ret = recv(bfd->fd, msg->data, msg->data_len, 0);
+ if (ret < 0) {
+ if (errno != EAGAIN)
+ LOGP(DINP, LOGL_ERROR, "recv error %s\n", strerror(errno));
+ msgb_free(msg);
+ return ret;
+ }
+ if (ret == 0) {
+ DEBUGP(DINP, "UDP peer disappeared, dead socket\n");
+ bsc_unregister_fd(bfd);
+ close(bfd->fd);
+ bfd->fd = -1;
+ msgb_free(msg);
+ return -EIO;
+ }
+ if (ret < sizeof(*hh)) {
+ DEBUGP(DINP, "could not even read header!?!\n");
+ msgb_free(msg);
+ return -EIO;
+ }
+ msgb_put(msg, ret);
+ msg->l2h = msg->data + sizeof(*hh);
+ DEBUGP(DMI, "UDP RX: %s\n", hexdump(msg->data, msg->len));
+
+ if (hh->len != msg->len - sizeof(*hh)) {
+ DEBUGP(DINP, "length (%u/%u) disagrees with header(%u)\n",
+ msg->len, msg->len - 3, hh->len);
+ msgb_free(msg);
+ return -EIO;
+ }
+
+ switch (bfd->priv_nr & 0xff) {
+ case UDP_TO_BTS:
+ /* injection towards BTS */
+ switch (hh->proto) {
+ case IPAC_PROTO_RSL:
+ /* FIXME: what to do about TRX > 0 */
+ other_conn = ipbc->rsl_conn[0];
+ break;
+ default:
+ DEBUGP(DINP, "Unknown protocol 0x%02x, sending to "
+ "OML FD\n", hh->proto);
+ /* fall through */
+ case IPAC_PROTO_IPACCESS:
+ case IPAC_PROTO_OML:
+ other_conn = ipbc->oml_conn;
+ break;
+ }
+ break;
+ case UDP_TO_BSC:
+ /* injection towards BSC */
+ switch (hh->proto) {
+ case IPAC_PROTO_RSL:
+ /* FIXME: what to do about TRX > 0 */
+ other_conn = ipbc->bsc_rsl_conn[0];
+ break;
+ default:
+ DEBUGP(DINP, "Unknown protocol 0x%02x, sending to "
+ "OML FD\n", hh->proto);
+ case IPAC_PROTO_IPACCESS:
+ case IPAC_PROTO_OML:
+ other_conn = ipbc->bsc_oml_conn;
+ break;
+ }
+ break;
+ default:
+ DEBUGP(DINP, "Unknown filedescriptor priv_nr=%04x\n", bfd->priv_nr);
+ break;
+ }
+
+ if (other_conn) {
+ /* enqueue the message for TX on the respective FD */
+ msgb_enqueue(&other_conn->tx_queue, msg);
+ other_conn->fd.when |= BSC_FD_WRITE;
+ } else
+ msgb_free(msg);
+
+ return 0;
+}
+
+static int handle_udp_write(struct bsc_fd *bfd)
+{
+ /* not implemented yet */
+ bfd->when &= ~BSC_FD_WRITE;
+
+ return -EIO;
+}
+
+/* callback from select.c in case one of the fd's can be read/written */
+static int udp_fd_cb(struct bsc_fd *bfd, unsigned int what)
+{
+ int rc = 0;
+
+ if (what & BSC_FD_READ)
+ rc = handle_udp_read(bfd);
+ if (what & BSC_FD_WRITE)
+ rc = handle_udp_write(bfd);
+
+ return rc;
+}
+
+
+static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct bsc_fd *bfd,
+ u_int16_t site_id, u_int16_t bts_id,
+ u_int16_t trx_id, struct tlv_parsed *tlvp,
+ struct msgb *msg)
+{
+ struct ipa_bts_conn *ipbc;
+ u_int16_t udp_port;
+ int ret = 0;
+ struct sockaddr_in sin;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ inet_aton(bsc_ipaddr, &sin.sin_addr);
+
+ DEBUGP(DINP, "(%u/%u/%u) New BTS connection: ",
+ site_id, bts_id, trx_id);
+
+ /* OML needs to be established before RSL */
+ if ((bfd->priv_nr & 0xff) != OML_FROM_BTS) {
+ DEBUGPC(DINP, "Not a OML connection ?!?\n");
+ return -EIO;
+ }
+
+ /* allocate new BTS connection data structure */
+ ipbc = talloc_zero(tall_bsc_ctx, struct ipa_bts_conn);
+ if (!ipbc) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ DEBUGPC(DINP, "Created BTS Conn data structure\n");
+ ipbc->ipp = ipp;
+ ipbc->unit_id.site_id = site_id;
+ ipbc->unit_id.bts_id = bts_id;
+ ipbc->oml_conn = ipc;
+ ipc->bts_conn = ipbc;
+
+ /* store the content of the ID TAGS for later reference */
+ store_idtags(ipbc, tlvp);
+ ipbc->id_resp_len = msg->len;
+ ipbc->id_resp = talloc_size(tall_bsc_ctx, ipbc->id_resp_len);
+ memcpy(ipbc->id_resp, msg->data, ipbc->id_resp_len);
+
+ /* Create OML TCP connection towards BSC */
+ sin.sin_port = htons(IPA_TCP_PORT_OML);
+ ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc);
+ if (!ipbc->bsc_oml_conn) {
+ ret = -EIO;
+ goto err_bsc_conn;
+ }
+
+ DEBUGP(DINP, "(%u/%u/%u) OML Connected to BSC\n",
+ site_id, bts_id, trx_id);
+
+ /* Create UDP socket for BTS packet injection */
+ udp_port = 10000 + (site_id % 1000)*100 + (bts_id % 100);
+ ret = make_sock(&ipbc->udp_bts_fd, udp_port, IPPROTO_UDP,
+ UDP_TO_BTS, udp_fd_cb, ipbc);
+ if (ret < 0)
+ goto err_udp_bts;
+ DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection "
+ "towards BTS at port %u\n", site_id, bts_id, trx_id, udp_port);
+
+ /* Create UDP socket for BSC packet injection */
+ udp_port = 20000 + (site_id % 1000)*100 + (bts_id % 100);
+ ret = make_sock(&ipbc->udp_bsc_fd, udp_port, IPPROTO_UDP,
+ UDP_TO_BSC, udp_fd_cb, ipbc);
+ if (ret < 0)
+ goto err_udp_bsc;
+ DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection "
+ "towards BSC at port %u\n", site_id, bts_id, trx_id, udp_port);
+ llist_add(&ipbc->list, &ipp->bts_list);
+
+ return 0;
+
+err_udp_bsc:
+ bsc_unregister_fd(&ipbc->udp_bts_fd);
+err_udp_bts:
+ bsc_unregister_fd(&ipbc->bsc_oml_conn->fd);
+ close(ipbc->bsc_oml_conn->fd.fd);
+ talloc_free(ipbc->bsc_oml_conn);
+ ipbc->bsc_oml_conn = NULL;
+err_bsc_conn:
+ talloc_free(ipbc->id_resp);
+ talloc_free(ipbc);
+#if 0
+ bsc_unregister_fd(bfd);
+ close(bfd->fd);
+ talloc_free(bfd);
+#endif
+err_out:
+ return ret;
+}
+
+static int ipaccess_rcvmsg(struct ipa_proxy_conn *ipc, struct msgb *msg,
+ struct bsc_fd *bfd)
+{
+ struct tlv_parsed tlvp;
+ u_int8_t msg_type = *(msg->l2h);
+ u_int16_t site_id, bts_id, trx_id;
+ struct ipa_bts_conn *ipbc;
+ int ret = 0;
+
+ switch (msg_type) {
+ case IPAC_MSGT_PING:
+ ret = write(bfd->fd, pong, sizeof(pong));
+ if (ret < 0)
+ return ret;
+ if (ret < sizeof(pong)) {
+ DEBUGP(DINP, "short write\n");
+ return -EIO;
+ }
+ break;
+ case IPAC_MSGT_PONG:
+ DEBUGP(DMI, "PONG!\n");
+ break;
+ case IPAC_MSGT_ID_RESP:
+ DEBUGP(DMI, "ID_RESP ");
+ /* parse tags, search for Unit ID */
+ ipac_idtag_parse(&tlvp, (u_int8_t *)msg->l2h + 2,
+ msgb_l2len(msg)-2);
+ DEBUGP(DMI, "\n");
+
+ if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) {
+ LOGP(DINP, LOGL_ERROR, "No Unit ID in ID RESPONSE !?!\n");
+ return -EIO;
+ }
+
+ /* lookup BTS, create sign_link, ... */
+ parse_unitid((char *)TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT),
+ &site_id, &bts_id, &trx_id);
+ ipbc = find_bts_by_unitid(ipp, site_id, bts_id);
+ if (!ipbc) {
+ /* We have not found an ipbc (per-bts proxy instance)
+ * for this BTS yet. The first connection of a new BTS must
+ * be a OML connection. We allocate the associated data structures,
+ * and try to connect to the remote end */
+
+ return ipbc_alloc_connect(ipc, bfd, site_id, bts_id,
+ trx_id, &tlvp, msg);
+ /* if this fails, the caller will clean up bfd */
+ } else {
+ struct sockaddr_in sin;
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ inet_aton(bsc_ipaddr, &sin.sin_addr);
+
+ DEBUGP(DINP, "Identified BTS %u/%u/%u\n",
+ site_id, bts_id, trx_id);
+
+ if ((bfd->priv_nr & 0xff) != RSL_FROM_BTS) {
+ LOGP(DINP, LOGL_ERROR, "Second OML connection from "
+ "same BTS ?!?\n");
+ return 0;
+ }
+
+ if (trx_id > MAX_TRX) {
+ LOGP(DINP, LOGL_ERROR, "We don't support more "
+ "than %u TRX\n", MAX_TRX);
+ return -EINVAL;
+ }
+
+ ipc->bts_conn = ipbc;
+ /* store TRX number in higher 8 bit of the bfd private number */
+ bfd->priv_nr |= trx_id << 8;
+ ipbc->rsl_conn[trx_id] = ipc;
+
+ /* Create RSL TCP connection towards BSC */
+ sin.sin_port = htons(IPA_TCP_PORT_RSL);
+ ipbc->bsc_rsl_conn[trx_id] =
+ connect_bsc(&sin, RSL_TO_BSC | (trx_id << 8), ipbc);
+ if (!ipbc->bsc_oml_conn)
+ return -EIO;
+ DEBUGP(DINP, "(%u/%u/%u) Connected RSL to BSC\n",
+ site_id, bts_id, trx_id);
+ }
+ break;
+ case IPAC_MSGT_ID_GET:
+ DEBUGP(DMI, "ID_GET\n");
+ if ((bfd->priv_nr & 0xff) != OML_TO_BSC &&
+ (bfd->priv_nr & 0xff) != RSL_TO_BSC) {
+ DEBUGP(DINP, "IDentity REQuest from BTS ?!?\n");
+ return -EIO;
+ }
+ ipbc = ipc->bts_conn;
+ if (!ipbc) {
+ DEBUGP(DINP, "ID_GET from BSC before we have ID_RESP from BTS\n");
+ return -EIO;
+ }
+ ret = write(bfd->fd, ipbc->id_resp, ipbc->id_resp_len);
+ break;
+ case IPAC_MSGT_ID_ACK:
+ DEBUGP(DMI, "ID_ACK? -> ACK!\n");
+ ret = write(bfd->fd, id_ack, sizeof(id_ack));
+ break;
+ }
+ return 0;
+}
+
+struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error)
+{
+ struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP");
+ struct ipaccess_head *hh;
+ int len, ret = 0;
+
+ if (!msg) {
+ *error = -ENOMEM;
+ return NULL;
+ }
+
+ /* first read our 3-byte header */
+ hh = (struct ipaccess_head *) msg->data;
+ ret = recv(bfd->fd, msg->data, 3, 0);
+ if (ret < 0) {
+ if (errno != EAGAIN)
+ LOGP(DINP, LOGL_ERROR, "recv error: %s\n", strerror(errno));
+ msgb_free(msg);
+ *error = ret;
+ return NULL;
+ } else if (ret == 0) {
+ msgb_free(msg);
+ *error = ret;
+ return NULL;
+ }
+
+ msgb_put(msg, ret);
+
+ /* then read te length as specified in header */
+ msg->l2h = msg->data + sizeof(*hh);
+ len = ntohs(hh->len);
+ ret = recv(bfd->fd, msg->l2h, len, 0);
+ if (ret < len) {
+ LOGP(DINP, LOGL_ERROR, "short read!\n");
+ msgb_free(msg);
+ *error = -EIO;
+ return NULL;
+ }
+ msgb_put(msg, ret);
+
+ return msg;
+}
+
+static struct ipa_proxy_conn *ipc_by_priv_nr(struct ipa_bts_conn *ipbc,
+ unsigned int priv_nr)
+{
+ struct ipa_proxy_conn *bsc_conn;
+ unsigned int trx_id = priv_nr >> 8;
+
+ switch (priv_nr & 0xff) {
+ case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */
+ bsc_conn = ipbc->bsc_oml_conn;
+ break;
+ case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */
+ bsc_conn = ipbc->bsc_rsl_conn[trx_id];
+ break;
+ case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */
+ bsc_conn = ipbc->oml_conn;
+ break;
+ case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */
+ bsc_conn = ipbc->rsl_conn[trx_id];
+ break;
+ default:
+ bsc_conn = NULL;
+ break;
+ }
+ return bsc_conn;
+}
+
+static void reconn_tmr_cb(void *data)
+{
+ struct ipa_proxy *ipp = data;
+ struct ipa_bts_conn *ipbc;
+ struct sockaddr_in sin;
+ int i;
+
+ DEBUGP(DINP, "Running reconnect timer\n");
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ inet_aton(bsc_ipaddr, &sin.sin_addr);
+
+ llist_for_each_entry(ipbc, &ipp->bts_list, list) {
+ /* if OML to BSC is dead, try to restore it */
+ if (ipbc->oml_conn && !ipbc->bsc_oml_conn) {
+ sin.sin_port = htons(IPA_TCP_PORT_OML);
+ logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0);
+ LOGPC(DINP, LOGL_NOTICE, "OML Trying to reconnect\n");
+ ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc);
+ if (!ipbc->bsc_oml_conn)
+ goto reschedule;
+ logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0);
+ LOGPC(DINP, LOGL_NOTICE, "OML Reconnected\n");
+ }
+ /* if we (still) don't have a OML connection, skip RSL */
+ if (!ipbc->oml_conn || !ipbc->bsc_oml_conn)
+ continue;
+
+ for (i = 0; i < ARRAY_SIZE(ipbc->rsl_conn); i++) {
+ unsigned int priv_nr;
+ /* don't establish RSL links which we don't have */
+ if (!ipbc->rsl_conn[i])
+ continue;
+ if (ipbc->bsc_rsl_conn[i])
+ continue;
+ priv_nr = ipbc->rsl_conn[i]->fd.priv_nr;
+ priv_nr &= ~0xff;
+ priv_nr |= RSL_TO_BSC;
+ sin.sin_port = htons(IPA_TCP_PORT_RSL);
+ logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
+ LOGPC(DINP, LOGL_NOTICE, "RSL Trying to reconnect\n");
+ ipbc->bsc_rsl_conn[i] = connect_bsc(&sin, priv_nr, ipbc);
+ if (!ipbc->bsc_rsl_conn)
+ goto reschedule;
+ logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
+ LOGPC(DINP, LOGL_NOTICE, "RSL Reconnected\n");
+ }
+ }
+ return;
+
+reschedule:
+ bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
+}
+
+static void handle_dead_socket(struct bsc_fd *bfd)
+{
+ struct ipa_proxy_conn *ipc = bfd->data; /* local conn */
+ struct ipa_proxy_conn *bsc_conn; /* remote conn */
+ struct ipa_bts_conn *ipbc = ipc->bts_conn;
+ unsigned int trx_id = bfd->priv_nr >> 8;
+ struct msgb *msg, *msg2;
+
+ bsc_unregister_fd(bfd);
+ close(bfd->fd);
+ bfd->fd = -1;
+
+ /* FIXME: clear tx_queue, remove all references, etc. */
+ llist_for_each_entry_safe(msg, msg2, &ipc->tx_queue, list)
+ msgb_free(msg);
+
+ switch (bfd->priv_nr & 0xff) {
+ case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */
+ ipbc->oml_conn = NULL;
+ bsc_conn = ipbc->bsc_oml_conn;
+ /* close the connection to the BSC */
+ bsc_unregister_fd(&bsc_conn->fd);
+ close(bsc_conn->fd.fd);
+ llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list)
+ msgb_free(msg);
+ talloc_free(bsc_conn);
+ ipbc->bsc_oml_conn = NULL;
+ /* FIXME: do we need to delete the entire ipbc ? */
+ break;
+ case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */
+ ipbc->rsl_conn[trx_id] = NULL;
+ bsc_conn = ipbc->bsc_rsl_conn[trx_id];
+ /* close the connection to the BSC */
+ bsc_unregister_fd(&bsc_conn->fd);
+ close(bsc_conn->fd.fd);
+ llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list)
+ msgb_free(msg);
+ talloc_free(bsc_conn);
+ ipbc->bsc_rsl_conn[trx_id] = NULL;
+ break;
+ case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */
+ ipbc->bsc_oml_conn = NULL;
+ bsc_conn = ipbc->oml_conn;
+ /* start reconnect timer */
+ bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
+ break;
+ case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */
+ ipbc->bsc_rsl_conn[trx_id] = NULL;
+ bsc_conn = ipbc->rsl_conn[trx_id];
+ /* start reconnect timer */
+ bsc_schedule_timer(&ipp->reconn_timer, 5, 0);
+ break;
+ default:
+ bsc_conn = NULL;
+ break;
+ }
+
+ talloc_free(ipc);
+}
+
+static int handle_tcp_read(struct bsc_fd *bfd)
+{
+ struct ipa_proxy_conn *ipc = bfd->data;
+ struct ipa_bts_conn *ipbc = ipc->bts_conn;
+ struct ipa_proxy_conn *bsc_conn;
+ struct msgb *msg;
+ struct ipaccess_head *hh;
+ int ret = 0;
+ char *btsbsc;
+
+ if ((bfd->priv_nr & 0xff) <= 2)
+ btsbsc = "BTS";
+ else
+ btsbsc = "BSC";
+
+ msg = ipaccess_read_msg(bfd, &ret);
+ if (!msg) {
+ if (ret == 0) {
+ logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
+ LOGPC(DINP, LOGL_NOTICE, "%s disappeared, "
+ "dead socket\n", btsbsc);
+ handle_dead_socket(bfd);
+ }
+ return ret;
+ }
+
+ msgb_put(msg, ret);
+ logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
+ DEBUGPC(DMI, "RX<-%s: %s\n", btsbsc, hexdump(msg->data, msg->len));
+
+ hh = (struct ipaccess_head *) msg->data;
+ if (hh->proto == IPAC_PROTO_IPACCESS) {
+ ret = ipaccess_rcvmsg(ipc, msg, bfd);
+ if (ret < 0) {
+ bsc_unregister_fd(bfd);
+ close(bfd->fd);
+ bfd->fd = -1;
+ talloc_free(bfd);
+ }
+ /* we do not forward the CCM protocol through the
+ * proxy but rather terminate it ourselves */
+ msgb_free(msg);
+ return ret;
+ }
+
+ if (!ipbc) {
+ LOGP(DINP, LOGL_ERROR,
+ "received %s packet but no ipc->bts_conn?!?\n", btsbsc);
+ msgb_free(msg);
+ return -EIO;
+ }
+
+ bsc_conn = ipc_by_priv_nr(ipbc, bfd->priv_nr);
+ if (bsc_conn) {
+ /* enqueue packet towards BSC */
+ msgb_enqueue(&bsc_conn->tx_queue, msg);
+ /* mark respective filedescriptor as 'we want to write' */
+ bsc_conn->fd.when |= BSC_FD_WRITE;
+ } else {
+ logp_ipbc_uid(DINP, LOGL_INFO, ipbc, bfd->priv_nr >> 8);
+ LOGPC(DINP, LOGL_INFO, "Dropping packet from %s, "
+ "since remote connection is dead\n", btsbsc);
+ msgb_free(msg);
+ }
+
+ return ret;
+}
+
+/* a TCP socket is ready to be written to */
+static int handle_tcp_write(struct bsc_fd *bfd)
+{
+ struct ipa_proxy_conn *ipc = bfd->data;
+ struct ipa_bts_conn *ipbc = ipc->bts_conn;
+ struct llist_head *lh;
+ struct msgb *msg;
+ char *btsbsc;
+ int ret;
+
+ if ((bfd->priv_nr & 0xff) <= 2)
+ btsbsc = "BTS";
+ else
+ btsbsc = "BSC";
+
+
+ /* get the next msg for this timeslot */
+ if (llist_empty(&ipc->tx_queue)) {
+ bfd->when &= ~BSC_FD_WRITE;
+ return 0;
+ }
+ lh = ipc->tx_queue.next;
+ llist_del(lh);
+ msg = llist_entry(lh, struct msgb, list);
+
+ logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
+ DEBUGPC(DMI, "TX %04x: %s\n", bfd->priv_nr,
+ hexdump(msg->data, msg->len));
+
+ ret = send(bfd->fd, msg->data, msg->len, 0);
+ msgb_free(msg);
+
+ if (ret == 0) {
+ logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
+ LOGP(DINP, LOGL_NOTICE, "%s disappeared, dead socket\n", btsbsc);
+ handle_dead_socket(bfd);
+ }
+
+ return ret;
+}
+
+/* callback from select.c in case one of the fd's can be read/written */
+static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what)
+{
+ int rc = 0;
+
+ if (what & BSC_FD_READ) {
+ rc = handle_tcp_read(bfd);
+ if (rc < 0)
+ return rc;
+ }
+ if (what & BSC_FD_WRITE)
+ rc = handle_tcp_write(bfd);
+
+ return rc;
+}
+
+/* callback of the listening filedescriptor */
+static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
+{
+ int ret;
+ struct ipa_proxy_conn *ipc;
+ struct bsc_fd *bfd;
+ struct sockaddr_in sa;
+ socklen_t sa_len = sizeof(sa);
+
+ if (!(what & BSC_FD_READ))
+ return 0;
+
+ ret = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len);
+ if (ret < 0) {
+ perror("accept");
+ return ret;
+ }
+ DEBUGP(DINP, "accept()ed new %s link from %s\n",
+ (listen_bfd->priv_nr & 0xff) == OML_FROM_BTS ? "OML" : "RSL",
+ inet_ntoa(sa.sin_addr));
+
+ ipc = alloc_conn();
+ if (!ipc) {
+ close(ret);
+ return -ENOMEM;
+ }
+
+ bfd = &ipc->fd;
+ bfd->fd = ret;
+ bfd->data = ipc;
+ bfd->priv_nr = listen_bfd->priv_nr;
+ bfd->cb = ipaccess_fd_cb;
+ bfd->when = BSC_FD_READ;
+ ret = bsc_register_fd(bfd);
+ if (ret < 0) {
+ LOGP(DINP, LOGL_ERROR, "could not register FD\n");
+ close(bfd->fd);
+ talloc_free(ipc);
+ return ret;
+ }
+
+ /* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */
+ ret = write(bfd->fd, id_req, sizeof(id_req));
+
+ return 0;
+}
+
+static int make_listen_sock(struct bsc_fd *bfd, u_int16_t port, int priv_nr,
+ int (*cb)(struct bsc_fd *fd, unsigned int what))
+{
+ struct sockaddr_in addr;
+ int ret, on = 1;
+
+ bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ bfd->cb = cb;
+ bfd->when = BSC_FD_READ;
+ bfd->priv_nr = priv_nr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ if (!listen_ipaddr)
+ addr.sin_addr.s_addr = INADDR_ANY;
+ else
+ inet_aton(listen_ipaddr, &addr.sin_addr);
+
+ setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+ ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
+ if (ret < 0) {
+ LOGP(DINP, LOGL_ERROR, "could not bind listen socket %s\n",
+ strerror(errno));
+ return -EIO;
+ }
+
+ ret = listen(bfd->fd, 1);
+ if (ret < 0) {
+ perror("listen");
+ return ret;
+ }
+
+ ret = bsc_register_fd(bfd);
+ if (ret < 0) {
+ perror("register_listen_fd");
+ return ret;
+ }
+ return 0;
+}
+
+/* Actively connect to a BSC. */
+static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data)
+{
+ struct ipa_proxy_conn *ipc;
+ struct bsc_fd *bfd;
+ int ret, on = 1;
+
+ ipc = alloc_conn();
+ if (!ipc)
+ return NULL;
+
+ ipc->bts_conn = data;
+
+ bfd = &ipc->fd;
+ bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ bfd->cb = ipaccess_fd_cb;
+ bfd->when = BSC_FD_READ | BSC_FD_WRITE;
+ bfd->data = ipc;
+ bfd->priv_nr = priv_nr;
+
+ setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+ ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa));
+ if (ret < 0) {
+ LOGP(DINP, LOGL_ERROR, "could not connect socket\n");
+ close(bfd->fd);
+ talloc_free(ipc);
+ return NULL;
+ }
+
+ /* pre-fill tx_queue with identity request */
+ ret = bsc_register_fd(bfd);
+ if (ret < 0) {
+ close(bfd->fd);
+ talloc_free(ipc);
+ return NULL;
+ }
+
+ return ipc;
+}
+
+static int ipaccess_proxy_setup(void)
+{
+ int ret;
+
+ ipp = talloc_zero(tall_bsc_ctx, struct ipa_proxy);
+ if (!ipp)
+ return -ENOMEM;
+ INIT_LLIST_HEAD(&ipp->bts_list);
+ ipp->reconn_timer.cb = reconn_tmr_cb;
+ ipp->reconn_timer.data = ipp;
+
+ /* Listen for OML connections */
+ ret = make_listen_sock(&ipp->oml_listen_fd, IPA_TCP_PORT_OML,
+ OML_FROM_BTS, listen_fd_cb);
+ if (ret < 0)
+ return ret;
+
+ /* Listen for RSL connections */
+ ret = make_listen_sock(&ipp->rsl_listen_fd, IPA_TCP_PORT_RSL,
+ RSL_FROM_BTS, listen_fd_cb);
+
+ return ret;
+}
+
+static void signal_handler(int signal)
+{
+ fprintf(stdout, "signal %u received\n", signal);
+
+ switch (signal) {
+ case SIGABRT:
+ /* in case of abort, we want to obtain a talloc report
+ * and then return to the caller, who will abort the process */
+ case SIGUSR1:
+ talloc_report_full(tall_bsc_ctx, stderr);
+ break;
+ default:
+ break;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int rc;
+
+ listen_ipaddr = "192.168.100.11";
+ bsc_ipaddr = "192.168.100.239";
+
+ tall_bsc_ctx = talloc_named_const(NULL, 1, "ipaccess-proxy");
+
+ debug_init();
+ stderr_target = debug_target_create_stderr();
+ debug_add_target(stderr_target);
+ debug_set_all_filter(stderr_target, 1);
+ debug_parse_category_mask(stderr_target, "DINP:DMI");
+
+ rc = ipaccess_proxy_setup();
+ if (rc < 0)
+ exit(1);
+
+ signal(SIGUSR1, &signal_handler);
+ signal(SIGABRT, &signal_handler);
+
+ while (1) {
+ bsc_select_main(0);
+ }
+}
diff --git a/openbsc/src/mgcp/mgcp_main.c b/openbsc/src/mgcp/mgcp_main.c
new file mode 100644
index 000000000..cea0ba427
--- /dev/null
+++ b/openbsc/src/mgcp/mgcp_main.c
@@ -0,0 +1,216 @@
+/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
+/* The main method to drive it as a standalone process */
+
+/*
+ * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2009 by On-Waves
+ * 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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+
+#include <openbsc/debug.h>
+#include <osmocore/msgb.h>
+#include <osmocore/talloc.h>
+#include <openbsc/gsm_data.h>
+#include <osmocore/select.h>
+#include <openbsc/mgcp.h>
+#include <openbsc/telnet_interface.h>
+
+/* this is here for the vty... it will never be called */
+void subscr_put() { abort(); }
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+#warning "Make use of the rtp proxy code"
+
+static struct bsc_fd bfd;
+static int first_request = 1;
+static struct mgcp_config *cfg;
+
+static char *config_file = "mgcp.cfg";
+
+/* used by msgb and mgcp */
+void *tall_bsc_ctx = NULL;
+
+static void print_help()
+{
+ printf("Some useful help...\n");
+ printf(" -h --help is printing this text.\n");
+ printf(" -c --config-file filename The config file to use.\n");
+}
+
+static void handle_options(int argc, char** argv)
+{
+ while (1) {
+ int option_index = 0, c;
+ static struct option long_options[] = {
+ {"help", 0, 0, 'h'},
+ {"config-file", 1, 0, 'c'},
+ {0, 0, 0, 0},
+ };
+
+ c = getopt_long(argc, argv, "hc:", long_options, &option_index);
+
+ if (c == -1)
+ break;
+
+ switch(c) {
+ case 'h':
+ print_help();
+ exit(0);
+ break;
+ case 'c':
+ config_file = talloc_strdup(tall_bsc_ctx, optarg);
+ break;
+ default:
+ /* ignore */
+ break;
+ };
+ }
+}
+
+static int read_call_agent(struct bsc_fd *fd, unsigned int what)
+{
+ struct sockaddr_in addr;
+ socklen_t slen = sizeof(addr);
+ struct msgb *msg;
+ struct msgb *resp;
+
+ msg = (struct msgb *) fd->data;
+
+ /* read one less so we can use it as a \0 */
+ int rc = recvfrom(bfd.fd, msg->data, msg->data_len - 1, 0,
+ (struct sockaddr *) &addr, &slen);
+ if (rc < 0) {
+ perror("Gateway failed to read");
+ return -1;
+ } else if (slen > sizeof(addr)) {
+ fprintf(stderr, "Gateway received message from outerspace: %d %d\n",
+ slen, sizeof(addr));
+ return -1;
+ }
+
+ if (first_request) {
+ first_request = 0;
+ resp = mgcp_create_rsip();
+
+ if (resp) {
+ sendto(bfd.fd, resp->l2h, msgb_l2len(resp), 0,
+ (struct sockaddr *) &addr, sizeof(addr));
+ msgb_free(resp);
+ }
+ return 0;
+ }
+
+ /* handle message now */
+ msg->l2h = msgb_put(msg, rc);
+ resp = mgcp_handle_message(cfg, msg);
+ msgb_reset(msg);
+
+ if (resp) {
+ sendto(bfd.fd, resp->l2h, msgb_l2len(resp), 0, (struct sockaddr *) &addr, sizeof(addr));
+ msgb_free(resp);
+ }
+ return 0;
+}
+
+
+int main(int argc, char** argv)
+{
+ struct gsm_network dummy_network;
+ struct sockaddr_in addr;
+ int on = 1, rc;
+ struct debug_target *stderr_target;
+
+ tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent");
+
+ debug_init();
+ stderr_target = debug_target_create_stderr();
+ debug_add_target(stderr_target);
+ debug_set_all_filter(stderr_target, 1);
+
+ cfg = mgcp_config_alloc();
+ if (!cfg)
+ return -1;
+
+ handle_options(argc, argv);
+
+ telnet_init(&dummy_network, 4243);
+ rc = mgcp_parse_config(config_file, cfg);
+ if (rc < 0)
+ return rc;
+
+
+ /* we need to bind a socket */
+ if (rc == 0) {
+ bfd.when = BSC_FD_READ;
+ bfd.cb = read_call_agent;
+ bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (bfd.fd < 0) {
+ perror("Gateway failed to listen");
+ return -1;
+ }
+
+ setsockopt(bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(cfg->source_port);
+ inet_aton(cfg->source_addr, &addr.sin_addr);
+
+ if (bind(bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("Gateway failed to bind");
+ return -1;
+ }
+
+ bfd.data = msgb_alloc(4096, "mgcp-msg");
+ if (!bfd.data) {
+ fprintf(stderr, "Gateway memory error.\n");
+ return -1;
+ }
+
+
+ if (bsc_register_fd(&bfd) != 0) {
+ DEBUGP(DMGCP, "Failed to register the fd\n");
+ return -1;
+ }
+
+ DEBUGP(DMGCP, "Configured for MGCP.\n");
+ }
+
+ /* initialisation */
+ srand(time(NULL));
+
+ /* main loop */
+ while (1) {
+ bsc_select_main(0);
+ }
+
+
+ return 0;
+}
diff --git a/openbsc/src/mgcp/mgcp_network.c b/openbsc/src/mgcp/mgcp_network.c
new file mode 100644
index 000000000..b76ca4732
--- /dev/null
+++ b/openbsc/src/mgcp/mgcp_network.c
@@ -0,0 +1,255 @@
+/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
+/* The protocol implementation */
+
+/*
+ * (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2009-2010 by On-Waves
+ * 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 <string.h>
+#include <unistd.h>
+#include <endian.h>
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <osmocore/msgb.h>
+#include <osmocore/talloc.h>
+#include <osmocore/select.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/mgcp.h>
+#include <openbsc/mgcp_internal.h>
+
+#warning "Make use of the rtp proxy code"
+
+/* according to rtp_proxy.c RFC 3550 */
+struct rtp_hdr {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ u_int8_t csrc_count:4,
+ extension:1,
+ padding:1,
+ version:2;
+ u_int8_t payload_type:7,
+ marker:1;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u_int8_t version:2,
+ padding:1,
+ extension:1,
+ csrc_count:4;
+ u_int8_t marker:1,
+ payload_type:7;
+#endif
+ u_int16_t sequence;
+ u_int32_t timestamp;
+ u_int32_t ssrc;
+} __attribute__((packed));
+
+
+enum {
+ DEST_NETWORK = 0,
+ DEST_BTS = 1,
+};
+
+enum {
+ PROTO_RTP,
+ PROTO_RTCP,
+};
+
+
+static int udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
+{
+ struct sockaddr_in out;
+ out.sin_family = AF_INET;
+ out.sin_port = port;
+ memcpy(&out.sin_addr, addr, sizeof(*addr));
+
+ return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
+}
+
+static void patch_payload(int payload, char *data, int len)
+{
+ struct rtp_hdr *rtp_hdr;
+
+ if (len < sizeof(*rtp_hdr))
+ return;
+
+ rtp_hdr = (struct rtp_hdr *) data;
+ rtp_hdr->payload_type = payload;
+}
+
+/*
+ * There is data coming. We will have to figure out if it
+ * came from the BTS or the MediaGateway of the MSC. On top
+ * of that we need to figure out if it was RTP or RTCP.
+ *
+ * Currently we do not communicate with the BSC so we have
+ * no idea where the BTS is listening for RTP and need to
+ * do the classic routing trick. Wait for the first packet
+ * from the BTS and then go ahead.
+ */
+static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
+{
+ char buf[4096];
+ struct sockaddr_in addr;
+ socklen_t slen = sizeof(addr);
+ struct mgcp_endpoint *endp;
+ struct mgcp_config *cfg;
+ int rc, dest, proto;
+
+ endp = (struct mgcp_endpoint *) fd->data;
+ cfg = endp->cfg;
+
+ rc = recvfrom(fd->fd, &buf, sizeof(buf), 0,
+ (struct sockaddr *) &addr, &slen);
+ if (rc < 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x\n",
+ ENDPOINT_NUMBER(endp));
+ return -1;
+ }
+
+ /* do not forward aynthing... maybe there is a packet from the bts */
+ if (endp->ci == CI_UNUSED) {
+ LOGP(DMGCP, LOGL_ERROR, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp));
+ return -1;
+ }
+
+ /*
+ * Figure out where to forward it to. This code assumes that we
+ * have received the Connection Modify and know who is a legitimate
+ * partner. According to the spec we could attempt to forward even
+ * after the Create Connection but we will not as we are not really
+ * able to tell if this is legitimate.
+ */
+ #warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
+ dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 &&
+ (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port)
+ ? DEST_BTS : DEST_NETWORK;
+ proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
+
+ /* We have no idea who called us, maybe it is the BTS. */
+ if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || cfg->forward_ip)) {
+ /* it was the BTS... */
+ if (!cfg->bts_ip || memcmp(&addr.sin_addr, &cfg->bts_in, sizeof(cfg->bts_in)) == 0) {
+ if (fd == &endp->local_rtp) {
+ endp->bts_rtp = addr.sin_port;
+ } else {
+ endp->bts_rtcp = addr.sin_port;
+ }
+
+ endp->bts = addr.sin_addr;
+ LOGP(DMGCP, LOGL_NOTICE, "Found BTS for endpoint: 0x%x on port: %d/%d\n",
+ ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp));
+ }
+ }
+
+ /* dispatch */
+ if (cfg->audio_loop)
+ dest = !dest;
+
+ if (dest == DEST_NETWORK) {
+ patch_payload(endp->net_payload_type, buf, rc);
+ return udp_send(fd->fd, &endp->remote,
+ proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp,
+ buf, rc);
+ } else {
+ patch_payload(endp->bts_payload_type, buf, rc);
+ return udp_send(fd->fd, &endp->bts,
+ proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp,
+ buf, rc);
+ }
+}
+
+static int create_bind(const char *source_addr, struct bsc_fd *fd, int port)
+{
+ struct sockaddr_in addr;
+ int on = 1;
+
+ fd->fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd->fd < 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to create UDP port.\n");
+ return -1;
+ }
+
+ setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ inet_aton(source_addr, &addr.sin_addr);
+
+ if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int bind_rtp(struct mgcp_endpoint *endp)
+{
+ struct mgcp_config *cfg = endp->cfg;
+
+ if (create_bind(cfg->source_addr, &endp->local_rtp, endp->rtp_port) != 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to create RTP port: %s:%d on 0x%x\n",
+ cfg->source_addr, endp->rtp_port, ENDPOINT_NUMBER(endp));
+ goto cleanup0;
+ }
+
+ if (create_bind(cfg->source_addr, &endp->local_rtcp, endp->rtp_port + 1) != 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to create RTCP port: %s:%d on 0x%x\n",
+ cfg->source_addr, endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
+ goto cleanup1;
+ }
+
+ endp->local_rtp.cb = rtp_data_cb;
+ endp->local_rtp.data = endp;
+ endp->local_rtp.when = BSC_FD_READ;
+ if (bsc_register_fd(&endp->local_rtp) != 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to register RTP port %d on 0x%x\n",
+ endp->rtp_port, ENDPOINT_NUMBER(endp));
+ goto cleanup2;
+ }
+
+ endp->local_rtcp.cb = rtp_data_cb;
+ endp->local_rtcp.data = endp;
+ endp->local_rtcp.when = BSC_FD_READ;
+ if (bsc_register_fd(&endp->local_rtcp) != 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to register RTCP port %d on 0x%x\n",
+ endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
+ goto cleanup3;
+ }
+
+ return 0;
+
+cleanup3:
+ bsc_unregister_fd(&endp->local_rtp);
+cleanup2:
+ close(endp->local_rtcp.fd);
+ endp->local_rtcp.fd = -1;
+cleanup1:
+ close(endp->local_rtp.fd);
+ endp->local_rtp.fd = -1;
+cleanup0:
+ return -1;
+}
+
+int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
+{
+ endp->rtp_port = rtp_port;
+ return bind_rtp(endp);
+}
diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c
new file mode 100644
index 000000000..f7ef5470d
--- /dev/null
+++ b/openbsc/src/mgcp/mgcp_protocol.c
@@ -0,0 +1,745 @@
+/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
+/* The protocol implementation */
+
+/*
+ * (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2009-2010 by On-Waves
+ * 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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include <openbsc/debug.h>
+#include <osmocore/msgb.h>
+#include <osmocore/talloc.h>
+#include <openbsc/gsm_data.h>
+#include <osmocore/select.h>
+#include <openbsc/mgcp.h>
+#include <openbsc/mgcp_internal.h>
+
+enum mgcp_connection_mode {
+ MGCP_CONN_NONE = 0,
+ MGCP_CONN_RECV_ONLY = 1,
+ MGCP_CONN_SEND_ONLY = 2,
+ MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
+};
+
+/**
+ * Macro for tokenizing MGCP messages and SDP in one go.
+ *
+ */
+#define MSG_TOKENIZE_START \
+ line_start = 0; \
+ for (i = 0; i < msgb_l3len(msg); ++i) { \
+ /* we have a line end */ \
+ if (msg->l3h[i] == '\n') { \
+ /* skip the first line */ \
+ if (line_start == 0) { \
+ line_start = i + 1; \
+ continue; \
+ } \
+ \
+ /* check if we have a proper param */ \
+ if (i - line_start == 1 && msg->l3h[line_start] == '\r') { \
+ } else if (i - line_start > 2 \
+ && islower(msg->l3h[line_start]) \
+ && msg->l3h[line_start + 1] == '=') { \
+ } else if (i - line_start < 3 \
+ || msg->l3h[line_start + 1] != ':' \
+ || msg->l3h[line_start + 2] != ' ') \
+ goto error; \
+ \
+ msg->l3h[i] = '\0'; \
+ if (msg->l3h[i-1] == '\r') \
+ msg->l3h[i-1] = '\0';
+
+#define MSG_TOKENIZE_END \
+ line_start = i + 1; \
+ } \
+ }
+
+
+struct mgcp_msg_ptr {
+ unsigned int start;
+ unsigned int length;
+};
+
+struct mgcp_request {
+ char *name;
+ struct msgb *(*handle_request) (struct mgcp_config *cfg, struct msgb *msg);
+ char *debug_name;
+};
+
+#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
+ { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
+
+static struct msgb *handle_audit_endpoint(struct mgcp_config *cfg, struct msgb *msg);
+static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg);
+static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg);
+static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg);
+
+static int generate_call_id(struct mgcp_config *cfg)
+{
+ int i;
+
+ /* use the call id */
+ ++cfg->last_call_id;
+
+ /* handle wrap around */
+ if (cfg->last_call_id == CI_UNUSED)
+ ++cfg->last_call_id;
+
+ /* callstack can only be of size number_of_endpoints */
+ /* verify that the call id is free, e.g. in case of overrun */
+ for (i = 1; i < cfg->number_endpoints; ++i)
+ if (cfg->endpoints[i].ci == cfg->last_call_id)
+ return generate_call_id(cfg);
+
+ return cfg->last_call_id;
+}
+
+/* FIXIME/TODO: need to have a list of pending transactions and check that */
+static unsigned int generate_transaction_id()
+{
+ return abs(rand());
+}
+
+/*
+ * array of function pointers for handling various
+ * messages. In the future this might be binary sorted
+ * for performance reasons.
+ */
+static const struct mgcp_request mgcp_requests [] = {
+ MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
+ MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
+ MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
+ MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
+};
+
+static struct msgb *mgcp_msgb_alloc(void)
+{
+ struct msgb *msg;
+ msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
+ if (!msg)
+ LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
+
+ return msg;
+}
+
+struct msgb *mgcp_create_response_with_data(int code, const char *msg, const char *trans,
+ const char *data)
+{
+ int len;
+ struct msgb *res;
+
+ res = mgcp_msgb_alloc();
+ if (!res)
+ return NULL;
+
+ if (data) {
+ len = snprintf((char *) res->data, 2048, "%d %s\n%s", code, trans, data);
+ } else {
+ len = snprintf((char *) res->data, 2048, "%d %s\n", code, trans);
+ }
+
+ res->l2h = msgb_put(res, len);
+ LOGP(DMGCP, LOGL_DEBUG, "Sending response: code: %d for '%s'\n", code, res->l2h);
+ return res;
+}
+
+static struct msgb *create_response(int code, const char *msg, const char *trans)
+{
+ return mgcp_create_response_with_data(code, msg, trans, NULL);
+}
+
+static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
+ const char *msg, const char *trans_id)
+{
+ const char *addr = endp->cfg->local_ip;
+ char sdp_record[4096];
+
+ if (!addr)
+ addr = endp->cfg->source_addr;
+
+ snprintf(sdp_record, sizeof(sdp_record) - 1,
+ "I: %d\n\n"
+ "v=0\r\n"
+ "c=IN IP4 %s\r\n"
+ "m=audio %d RTP/AVP %d\r\n"
+ "a=rtpmap:%d %s\r\n",
+ endp->ci, addr, endp->rtp_port,
+ endp->bts_payload_type, endp->bts_payload_type,
+ endp->cfg->audio_name);
+ return mgcp_create_response_with_data(200, msg, trans_id, sdp_record);
+}
+
+/* send a static record */
+struct msgb *mgcp_create_rsip(void)
+{
+ struct msgb *msg;
+ int len;
+
+ msg = mgcp_msgb_alloc();
+ if (!msg)
+ return NULL;
+
+ len = snprintf((char *) msg->data, 2048,
+ "RSIP %u *@mgw MGCP 1.0\n"
+ "RM: restart\n", generate_transaction_id());
+ msg->l2h = msgb_put(msg, len);
+ return msg;
+}
+
+/*
+ * handle incoming messages:
+ * - this can be a command (four letters, space, transaction id)
+ * - or a response (three numbers, space, transaction id)
+ */
+struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
+{
+ int code;
+ struct msgb *resp = NULL;
+
+ if (msg->len < 4) {
+ LOGP(DMGCP, LOGL_ERROR, "mgs too short: %d\n", msg->len);
+ return NULL;
+ }
+
+ /* attempt to treat it as a response */
+ if (sscanf((const char *)&msg->data[0], "%3d %*s", &code) == 1) {
+ LOGP(DMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
+ } else {
+ int i, handled = 0;
+ msg->l3h = &msg->l2h[4];
+ for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i)
+ if (strncmp(mgcp_requests[i].name, (const char *) &msg->data[0], 4) == 0) {
+ handled = 1;
+ resp = mgcp_requests[i].handle_request(cfg, msg);
+ break;
+ }
+ if (!handled) {
+ LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->data[0]);
+ }
+ }
+
+ return resp;
+}
+
+/* string tokenizer for the poor */
+static int find_msg_pointers(struct msgb *msg, struct mgcp_msg_ptr *ptrs, int ptrs_length)
+{
+ int i, found = 0;
+
+ int whitespace = 1;
+ for (i = 0; i < msgb_l3len(msg) && ptrs_length > 0; ++i) {
+ /* if we have a space we found an end */
+ if (msg->l3h[i] == ' ' || msg->l3h[i] == '\r' || msg->l3h[i] == '\n') {
+ if (!whitespace) {
+ ++found;
+ whitespace = 1;
+ ptrs->length = i - ptrs->start - 1;
+ ++ptrs;
+ --ptrs_length;
+ } else {
+ /* skip any number of whitespace */
+ }
+
+ /* line end... stop */
+ if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n')
+ break;
+ } else if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') {
+ /* line end, be done */
+ break;
+ } else if (whitespace) {
+ whitespace = 0;
+ ptrs->start = i;
+ }
+ }
+
+ if (ptrs_length == 0)
+ return -1;
+ return found;
+}
+
+static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *mgcp)
+{
+ char *endptr = NULL;
+ unsigned int gw = INT_MAX;
+
+ gw = strtoul(mgcp, &endptr, 16);
+ if (gw == 0 || gw >= cfg->number_endpoints || strcmp(endptr, "@mgw") != 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Not able to find endpoint: '%s'\n", mgcp);
+ return NULL;
+ }
+
+ return &cfg->endpoints[gw];
+}
+
+static int analyze_header(struct mgcp_config *cfg, struct msgb *msg,
+ struct mgcp_msg_ptr *ptr, int size,
+ const char **transaction_id, struct mgcp_endpoint **endp)
+{
+ int found;
+
+ *transaction_id = "000000";
+
+ if (size < 3) {
+ LOGP(DMGCP, LOGL_ERROR, "Not enough space in ptr\n");
+ return -1;
+ }
+
+ found = find_msg_pointers(msg, ptr, size);
+
+ if (found <= 3) {
+ LOGP(DMGCP, LOGL_ERROR, "Gateway: Not enough params. Found: %d\n", found);
+ return -1;
+ }
+
+ /*
+ * replace the space with \0. the main method gurantess that
+ * we still have + 1 for null termination
+ */
+ msg->l3h[ptr[3].start + ptr[3].length + 1] = '\0';
+ msg->l3h[ptr[2].start + ptr[2].length + 1] = '\0';
+ msg->l3h[ptr[1].start + ptr[1].length + 1] = '\0';
+ msg->l3h[ptr[0].start + ptr[0].length + 1] = '\0';
+
+ if (strncmp("1.0", (const char *)&msg->l3h[ptr[3].start], 3) != 0
+ || strncmp("MGCP", (const char *)&msg->l3h[ptr[2].start], 4) != 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Wrong MGCP version. Not handling: '%s' '%s'\n",
+ (const char *)&msg->l3h[ptr[3].start],
+ (const char *)&msg->l3h[ptr[2].start]);
+ return -1;
+ }
+
+ *transaction_id = (const char *)&msg->l3h[ptr[0].start];
+ *endp = find_endpoint(cfg, (const char *)&msg->l3h[ptr[1].start]);
+ return *endp == NULL;
+}
+
+static int verify_call_id(const struct mgcp_endpoint *endp,
+ const char *callid)
+{
+ if (strcmp(endp->callid, callid) != 0) {
+ LOGP(DMGCP, LOGL_ERROR, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
+ ENDPOINT_NUMBER(endp), endp->callid, callid);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int verify_ci(const struct mgcp_endpoint *endp,
+ const char *ci)
+{
+ if (atoi(ci) != endp->ci) {
+ LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %d != %s\n",
+ ENDPOINT_NUMBER(endp), endp->ci, ci);
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct msgb *handle_audit_endpoint(struct mgcp_config *cfg, struct msgb *msg)
+{
+ struct mgcp_msg_ptr data_ptrs[6];
+ int found, response;
+ const char *trans_id;
+ struct mgcp_endpoint *endp;
+
+ found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+ if (found != 0)
+ response = 500;
+ else
+ response = 200;
+
+ return create_response(response, "AUEP", trans_id);
+}
+
+static int parse_conn_mode(const char* msg, int *conn_mode)
+{
+ int ret = 0;
+ if (strcmp(msg, "recvonly") == 0)
+ *conn_mode = MGCP_CONN_RECV_ONLY;
+ else if (strcmp(msg, "sendrecv") == 0)
+ *conn_mode = MGCP_CONN_RECV_SEND;
+ else {
+ LOGP(DMGCP, LOGL_ERROR, "Unknown connection mode: '%s'\n", msg);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
+{
+ struct mgcp_msg_ptr data_ptrs[6];
+ int found, i, line_start;
+ const char *trans_id;
+ struct mgcp_endpoint *endp;
+ int error_code = 500;
+ int port;
+
+ found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+ if (found != 0)
+ return create_response(500, "CRCX", trans_id);
+
+ if (endp->ci != CI_UNUSED) {
+ LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp));
+ return create_response(500, "CRCX", trans_id);
+ }
+
+ /* parse CallID C: and LocalParameters L: */
+ MSG_TOKENIZE_START
+ switch (msg->l3h[line_start]) {
+ case 'L':
+ endp->local_options = talloc_strdup(cfg->endpoints,
+ (const char *)&msg->l3h[line_start + 3]);
+ break;
+ case 'C':
+ endp->callid = talloc_strdup(cfg->endpoints,
+ (const char *)&msg->l3h[line_start + 3]);
+ break;
+ case 'M':
+ if (parse_conn_mode((const char *)&msg->l3h[line_start + 3],
+ &endp->conn_mode) != 0) {
+ error_code = 517;
+ goto error2;
+ }
+ break;
+ default:
+ LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
+ msg->l3h[line_start], msg->l3h[line_start],
+ ENDPOINT_NUMBER(endp));
+ break;
+ }
+ MSG_TOKENIZE_END
+
+ /* initialize */
+ endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
+
+ /* set to zero until we get the info */
+ memset(&endp->remote, 0, sizeof(endp->remote));
+
+ /* bind to the port now */
+ port = rtp_calculate_port(ENDPOINT_NUMBER(endp), cfg->rtp_base_port);
+ if (cfg->early_bind)
+ endp->rtp_port = port;
+ else if (mgcp_bind_rtp_port(endp, port) != 0)
+ goto error2;
+
+ /* assign a local call identifier or fail */
+ endp->ci = generate_call_id(cfg);
+ if (endp->ci == CI_UNUSED)
+ goto error2;
+
+ endp->bts_payload_type = cfg->audio_payload;
+
+ /* policy CB */
+ if (cfg->policy_cb) {
+ switch (cfg->policy_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, trans_id)) {
+ case MGCP_POLICY_REJECT:
+ LOGP(DMGCP, LOGL_NOTICE, "CRCX rejected by policy on 0x%x\n",
+ ENDPOINT_NUMBER(endp));
+ mgcp_free_endp(endp);
+ return create_response(500, "CRCX", trans_id);
+ break;
+ case MGCP_POLICY_DEFER:
+ /* stop processing */
+ return NULL;
+ break;
+ case MGCP_POLICY_CONT:
+ /* just continue */
+ break;
+ }
+ }
+
+ LOGP(DMGCP, LOGL_NOTICE, "Creating endpoint on: 0x%x CI: %u port: %u\n",
+ ENDPOINT_NUMBER(endp), endp->ci, endp->rtp_port);
+ if (cfg->change_cb)
+ cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, endp->rtp_port);
+
+ return create_response_with_sdp(endp, "CRCX", trans_id);
+error:
+ LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
+ hexdump(msg->l3h, msgb_l3len(msg)),
+ ENDPOINT_NUMBER(endp), line_start, i);
+ return create_response(error_code, "CRCX", trans_id);
+
+error2:
+ LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
+ return create_response(error_code, "CRCX", trans_id);
+}
+
+static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
+{
+ struct mgcp_msg_ptr data_ptrs[6];
+ int found, i, line_start;
+ const char *trans_id;
+ struct mgcp_endpoint *endp;
+ int error_code = 500;
+
+ found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+ if (found != 0)
+ return create_response(error_code, "MDCX", trans_id);
+
+ if (endp->ci == CI_UNUSED) {
+ LOGP(DMGCP, LOGL_ERROR, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
+ return create_response(error_code, "MDCX", trans_id);
+ }
+
+ MSG_TOKENIZE_START
+ switch (msg->l3h[line_start]) {
+ case 'C': {
+ if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
+ goto error3;
+ break;
+ }
+ case 'I': {
+ if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
+ goto error3;
+ break;
+ }
+ case 'L':
+ /* skip */
+ break;
+ case 'M':
+ if (parse_conn_mode((const char *)&msg->l3h[line_start + 3],
+ &endp->conn_mode) != 0) {
+ error_code = 517;
+ goto error3;
+ }
+ break;
+ case '\0':
+ /* SDP file begins */
+ break;
+ case 'a':
+ case 'o':
+ case 's':
+ case 't':
+ case 'v':
+ /* skip these SDP attributes */
+ break;
+ case 'm': {
+ int port;
+ int payload;
+ const char *param = (const char *)&msg->l3h[line_start];
+
+ if (sscanf(param, "m=audio %d RTP/AVP %d", &port, &payload) == 2) {
+ endp->net_rtp = htons(port);
+ endp->net_rtcp = htons(port + 1);
+ endp->net_payload_type = payload;
+ }
+ break;
+ }
+ case 'c': {
+ char ipv4[16];
+ const char *param = (const char *)&msg->l3h[line_start];
+
+ if (sscanf(param, "c=IN IP4 %15s", ipv4) == 1) {
+ inet_aton(ipv4, &endp->remote);
+ }
+ break;
+ }
+ default:
+ LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
+ msg->l3h[line_start], msg->l3h[line_start],
+ ENDPOINT_NUMBER(endp));
+ break;
+ }
+ MSG_TOKENIZE_END
+
+ /* policy CB */
+ if (cfg->policy_cb) {
+ switch (cfg->policy_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, trans_id)) {
+ case MGCP_POLICY_REJECT:
+ LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
+ ENDPOINT_NUMBER(endp));
+ return create_response(500, "MDCX", trans_id);
+ break;
+ case MGCP_POLICY_DEFER:
+ /* stop processing */
+ return NULL;
+ break;
+ case MGCP_POLICY_CONT:
+ /* just continue */
+ break;
+ }
+ }
+
+ /* modify */
+ LOGP(DMGCP, LOGL_NOTICE, "Modified endpoint on: 0x%x Server: %s:%u\n",
+ ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), ntohs(endp->net_rtp));
+ if (cfg->change_cb)
+ cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, endp->rtp_port);
+ return create_response_with_sdp(endp, "MDCX", trans_id);
+
+error:
+ LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n",
+ hexdump(msg->l3h, msgb_l3len(msg)),
+ ENDPOINT_NUMBER(endp), line_start, i, msg->l3h[line_start]);
+ return create_response(error_code, "MDCX", trans_id);
+
+error3:
+ return create_response(error_code, "MDCX", trans_id);
+}
+
+static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
+{
+ struct mgcp_msg_ptr data_ptrs[6];
+ int found, i, line_start;
+ const char *trans_id;
+ struct mgcp_endpoint *endp;
+ int error_code = 500;
+
+ found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+ if (found != 0)
+ return create_response(error_code, "DLCX", trans_id);
+
+ if (endp->ci == CI_UNUSED) {
+ LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp));
+ return create_response(error_code, "DLCX", trans_id);
+ }
+
+ MSG_TOKENIZE_START
+ switch (msg->l3h[line_start]) {
+ case 'C': {
+ if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
+ goto error3;
+ break;
+ }
+ case 'I': {
+ if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
+ goto error3;
+ break;
+ }
+ default:
+ LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
+ msg->l3h[line_start], msg->l3h[line_start],
+ ENDPOINT_NUMBER(endp));
+ break;
+ }
+ MSG_TOKENIZE_END
+
+ /* policy CB */
+ if (cfg->policy_cb) {
+ switch (cfg->policy_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, trans_id)) {
+ case MGCP_POLICY_REJECT:
+ LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
+ ENDPOINT_NUMBER(endp));
+ return create_response(500, "DLCX", trans_id);
+ break;
+ case MGCP_POLICY_DEFER:
+ /* stop processing */
+ return NULL;
+ break;
+ case MGCP_POLICY_CONT:
+ /* just continue */
+ break;
+ }
+ }
+
+ /* free the connection */
+ mgcp_free_endp(endp);
+ if (cfg->change_cb)
+ cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, endp->rtp_port);
+
+ return create_response(250, "DLCX", trans_id);
+
+error:
+ LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
+ hexdump(msg->l3h, msgb_l3len(msg)),
+ ENDPOINT_NUMBER(endp), line_start, i);
+ return create_response(error_code, "DLCX", trans_id);
+
+error3:
+ return create_response(error_code, "DLCX", trans_id);
+}
+
+struct mgcp_config *mgcp_config_alloc(void)
+{
+ struct mgcp_config *cfg;
+
+ cfg = talloc_zero(NULL, struct mgcp_config);
+ if (!cfg) {
+ LOGP(DMGCP, LOGL_FATAL, "Failed to allocate config.\n");
+ return NULL;
+ }
+
+ cfg->source_port = 2427;
+ cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
+ cfg->audio_name = talloc_strdup(cfg, "GSM-EFR/8000");
+ cfg->audio_payload = 97;
+ cfg->rtp_base_port = RTP_PORT_DEFAULT;
+
+ return cfg;
+}
+
+int mgcp_endpoints_allocate(struct mgcp_config *cfg)
+{
+ int i;
+
+ /* Initialize all endpoints */
+ cfg->endpoints = _talloc_zero_array(cfg,
+ sizeof(struct mgcp_endpoint),
+ cfg->number_endpoints, "endpoints");
+ if (!cfg->endpoints)
+ return -1;
+
+ for (i = 0; i < cfg->number_endpoints; ++i) {
+ cfg->endpoints[i].local_rtp.fd = -1;
+ cfg->endpoints[i].local_rtcp.fd = -1;
+ cfg->endpoints[i].ci = CI_UNUSED;
+ cfg->endpoints[i].cfg = cfg;
+ cfg->endpoints[i].net_payload_type = -1;
+ cfg->endpoints[i].bts_payload_type = -1;
+ }
+
+ return 0;
+}
+
+void mgcp_free_endp(struct mgcp_endpoint *endp)
+{
+ LOGP(DMGCP, LOGL_NOTICE, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
+ endp->ci= CI_UNUSED;
+
+ if (endp->callid) {
+ talloc_free(endp->callid);
+ endp->callid = NULL;
+ }
+
+ if (endp->local_options) {
+ talloc_free(endp->local_options);
+ endp->callid = NULL;
+ }
+
+ if (!endp->cfg->early_bind) {
+ bsc_unregister_fd(&endp->local_rtp);
+ bsc_unregister_fd(&endp->local_rtcp);
+ }
+
+ endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
+ endp->net_payload_type = endp->bts_payload_type = -1;
+}
diff --git a/openbsc/src/mgcp/mgcp_vty.c b/openbsc/src/mgcp/mgcp_vty.c
new file mode 100644
index 000000000..f13b3cfa7
--- /dev/null
+++ b/openbsc/src/mgcp/mgcp_vty.c
@@ -0,0 +1,339 @@
+/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
+/* The protocol implementation */
+
+/*
+ * (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2009-2010 by On-Waves
+ * 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 <sys/types.h>
+
+#include <osmocore/talloc.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/mgcp.h>
+#include <openbsc/mgcp_internal.h>
+
+#include <vty/command.h>
+#include <vty/vty.h>
+
+static struct mgcp_config *g_cfg = NULL;
+
+/*
+ * vty code for mgcp below
+ */
+struct cmd_node mgcp_node = {
+ MGCP_NODE,
+ "%s(mgcp)#",
+ 1,
+};
+
+static int config_write_mgcp(struct vty *vty)
+{
+ vty_out(vty, "mgcp%s", VTY_NEWLINE);
+ if (g_cfg->local_ip)
+ vty_out(vty, " local ip %s%s", g_cfg->local_ip, VTY_NEWLINE);
+ if (g_cfg->bts_ip)
+ vty_out(vty, " bts ip %s%s", g_cfg->bts_ip, VTY_NEWLINE);
+ vty_out(vty, " bind ip %s%s", g_cfg->source_addr, VTY_NEWLINE);
+ vty_out(vty, " bind port %u%s", g_cfg->source_port, VTY_NEWLINE);
+ vty_out(vty, " bind early %u%s", !!g_cfg->early_bind, VTY_NEWLINE);
+ vty_out(vty, " rtp base %u%s", g_cfg->rtp_base_port, VTY_NEWLINE);
+ vty_out(vty, " sdp audio payload number %u%s", g_cfg->audio_payload, VTY_NEWLINE);
+ vty_out(vty, " sdp audio payload name %s%s", g_cfg->audio_name, VTY_NEWLINE);
+ vty_out(vty, " loop %u%s", !!g_cfg->audio_loop, VTY_NEWLINE);
+ vty_out(vty, " endpoints %u%s", g_cfg->number_endpoints, VTY_NEWLINE);
+ if (g_cfg->forward_ip)
+ vty_out(vty, " forward audio ip %s%s", g_cfg->forward_ip, VTY_NEWLINE);
+ if (g_cfg->forward_port != 0)
+ vty_out(vty, " forward audio port %d%s", g_cfg->forward_port, VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp",
+ SHOW_STR "Display information about the MGCP Media Gateway")
+{
+ int i;
+
+ vty_out(vty, "MGCP is up and running with %u endpoints:%s", g_cfg->number_endpoints - 1, VTY_NEWLINE);
+ for (i = 1; i < g_cfg->number_endpoints; ++i) {
+ struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
+ vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s",
+ i, endp->ci,
+ ntohs(endp->net_rtp), ntohs(endp->net_rtcp),
+ ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp,
+ cfg_mgcp_cmd,
+ "mgcp",
+ "Configure the MGCP")
+{
+ vty->node = MGCP_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_local_ip,
+ cfg_mgcp_local_ip_cmd,
+ "local ip IP",
+ "Set the IP to be used in SDP records")
+{
+ if (g_cfg->local_ip)
+ talloc_free(g_cfg->local_ip);
+ g_cfg->local_ip = talloc_strdup(g_cfg, argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_bts_ip,
+ cfg_mgcp_bts_ip_cmd,
+ "bts ip IP",
+ "Set the IP of the BTS for RTP forwarding")
+{
+ if (g_cfg->bts_ip)
+ talloc_free(g_cfg->bts_ip);
+ g_cfg->bts_ip = talloc_strdup(g_cfg, argv[0]);
+ inet_aton(g_cfg->bts_ip, &g_cfg->bts_in);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_bind_ip,
+ cfg_mgcp_bind_ip_cmd,
+ "bind ip IP",
+ "Bind the MGCP to this local addr")
+{
+ if (g_cfg->source_addr)
+ talloc_free(g_cfg->source_addr);
+ g_cfg->source_addr = talloc_strdup(g_cfg, argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_bind_port,
+ cfg_mgcp_bind_port_cmd,
+ "bind port <0-65534>",
+ "Bind the MGCP to this port")
+{
+ unsigned int port = atoi(argv[0]);
+ if (port > 65534) {
+ vty_out(vty, "%% wrong bind port '%s'%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ g_cfg->source_port = port;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_bind_early,
+ cfg_mgcp_bind_early_cmd,
+ "bind early (0|1)",
+ "Bind all RTP ports early")
+{
+ unsigned int bind = atoi(argv[0]);
+ if (bind != 0 && bind != 1) {
+ vty_out(vty, "%% param must be 0 or 1.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ g_cfg->early_bind = bind == 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_rtp_base_port,
+ cfg_mgcp_rtp_base_port_cmd,
+ "rtp base <0-65534>",
+ "Base port to use")
+{
+ unsigned int port = atoi(argv[0]);
+ if (port > 65534) {
+ vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ g_cfg->rtp_base_port = port;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_sdp_payload_number,
+ cfg_mgcp_sdp_payload_number_cmd,
+ "sdp audio payload number <1-255>",
+ "Set the audio codec to use")
+{
+ unsigned int payload = atoi(argv[0]);
+ if (payload > 255) {
+ vty_out(vty, "%% wrong payload number '%s'%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ g_cfg->audio_payload = payload;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_sdp_payload_name,
+ cfg_mgcp_sdp_payload_name_cmd,
+ "sdp audio payload name NAME",
+ "Set the audio name to use")
+{
+ if (g_cfg->audio_name)
+ talloc_free(g_cfg->audio_name);
+ g_cfg->audio_name = talloc_strdup(g_cfg, argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_loop,
+ cfg_mgcp_loop_cmd,
+ "loop (0|1)",
+ "Loop the audio")
+{
+ g_cfg->audio_loop = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_number_endp,
+ cfg_mgcp_number_endp_cmd,
+ "number endpoints <0-65534>",
+ "The number of endpoints to allocate. This is not dynamic.")
+{
+ /* + 1 as we start counting at one */
+ g_cfg->number_endpoints = atoi(argv[0]) + 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_forward_ip,
+ cfg_mgcp_forward_ip_cmd,
+ "forward audio ip IP",
+ "Forward packets from and to the IP. This disables most of the MGCP feature.")
+{
+ if (g_cfg->forward_ip)
+ talloc_free(g_cfg->forward_ip);
+ g_cfg->forward_ip = talloc_strdup(g_cfg, argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_forward_port,
+ cfg_mgcp_forward_port_cmd,
+ "forward audio port <1-15000>",
+ "Forward packets from and to the port. This disables most of the MGCP feature.")
+{
+ g_cfg->forward_port = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
+int mgcp_vty_init(void)
+{
+ install_element(VIEW_NODE, &show_mgcp_cmd);
+
+ install_element(CONFIG_NODE, &cfg_mgcp_cmd);
+ install_node(&mgcp_node, config_write_mgcp);
+ install_default(MGCP_NODE);
+ install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_bts_ip_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_bind_ip_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_loop_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_forward_ip_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_forward_port_cmd);
+ return 0;
+}
+
+int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg)
+{
+ int i, rc;
+
+ g_cfg = cfg;
+ rc = vty_read_config_file(config_file);
+ if (rc < 0) {
+ fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
+ return rc;
+ }
+
+
+ if (!g_cfg->bts_ip)
+ fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n");
+
+ if (mgcp_endpoints_allocate(g_cfg) != 0) {
+ fprintf(stderr, "Failed to allocate endpoints: %d. Quitting.\n", g_cfg->number_endpoints);
+ return -1;
+ }
+
+ /*
+ * This application supports two modes.
+ * 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX
+ * 2.) plain forwarding of RTP packets on the endpoints.
+ * both modes are mutual exclusive
+ */
+ if (g_cfg->forward_ip) {
+ int port = g_cfg->rtp_base_port;
+ if (g_cfg->forward_port != 0)
+ port = g_cfg->forward_port;
+
+ if (!g_cfg->early_bind) {
+ LOGP(DMGCP, LOGL_NOTICE, "Forwarding requires early bind.\n");
+ return -1;
+ }
+
+ /*
+ * Store the forward IP and assign a ci. For early bind
+ * the sockets will be created after this.
+ */
+ for (i = 1; i < g_cfg->number_endpoints; ++i) {
+ struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
+ inet_aton(g_cfg->forward_ip, &endp->remote);
+ endp->ci = CI_UNUSED + 23;
+ endp->net_rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port));
+ endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port) + 1);
+ }
+
+ LOGP(DMGCP, LOGL_NOTICE, "Configured for Audio Forwarding.\n");
+ }
+
+ /* early bind */
+ if (g_cfg->early_bind) {
+ for (i = 1; i < g_cfg->number_endpoints; ++i) {
+ struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
+ int rtp_port;
+
+ rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), g_cfg->rtp_base_port);
+ if (mgcp_bind_rtp_port(endp, rtp_port) != 0) {
+ LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", rtp_port);
+ return -1;
+ }
+ }
+ }
+
+ return !!g_cfg->forward_ip;
+}
+
+struct gsm_network;
+int bsc_vty_init(struct gsm_network *dummy)
+{
+ cmd_init(1);
+ vty_init();
+
+ mgcp_vty_init();
+ return 0;
+}
+
diff --git a/openbsc/src/mncc.c b/openbsc/src/mncc.c
index 15e2978e6..01d59aad1 100644
--- a/openbsc/src/mncc.c
+++ b/openbsc/src/mncc.c
@@ -28,7 +28,7 @@
#include <openbsc/gsm_04_08.h>
#include <openbsc/debug.h>
#include <openbsc/mncc.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/gsm_data.h>
#include <openbsc/transaction.h>
#include <openbsc/rtp_proxy.h>
diff --git a/openbsc/src/msgb.c b/openbsc/src/msgb.c
deleted file mode 100644
index 914b36ae7..000000000
--- a/openbsc/src/msgb.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/* (C) 2008 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 <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <openbsc/msgb.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/talloc.h>
-#include <openbsc/debug.h>
-
-static void *tall_msgb_ctx;
-
-struct msgb *msgb_alloc(u_int16_t size, const char *name)
-{
- struct msgb *msg;
-
- msg = _talloc_zero(tall_msgb_ctx, sizeof(*msg) + size, name);
-
- if (!msg) {
- LOGP(DRSL, LOGL_FATAL, "unable to allocate msgb\n");
- return NULL;
- }
-
- msg->data_len = size;
- msg->len = 0;
- msg->data = msg->_data;
-
- msg->head = msg->data;
- msg->data = msg->data;
- /* reset tail pointer */
- msg->tail = msg->data;
- //msg->end = msg->tail + size;
-
- return msg;
-}
-
-void msgb_free(struct msgb *m)
-{
- talloc_free(m);
-}
-
-void msgb_enqueue(struct llist_head *queue, struct msgb *msg)
-{
- llist_add_tail(&msg->list, queue);
-}
-
-struct msgb *msgb_dequeue(struct llist_head *queue)
-{
- struct llist_head *lh;
-
- if (llist_empty(queue))
- return NULL;
-
- lh = queue->next;
- llist_del(lh);
-
- return llist_entry(lh, struct msgb, list);
-}
-
-void msgb_reset(struct msgb *msg)
-{
- msg->len = 0;
- msg->len = 0;
- msg->data = msg->_data;
-
- msg->head = msg->data;
- msg->data = msg->data;
- /* reset tail pointer */
- msg->tail = msg->data;
-
- /* reset pointers */
- msg->bts_link = NULL;
- msg->trx = NULL;
- msg->lchan = NULL;
- msg->l2h = NULL;
- msg->l3h = NULL;
- msg->smsh = NULL;
- msg->l4h = NULL;
-}
-
-static __attribute__((constructor)) void on_dso_load_trau_msgb(void)
-{
- tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 1, "msgb");
-}
diff --git a/openbsc/src/nat/bsc_filter.c b/openbsc/src/nat/bsc_filter.c
index ad2f6138f..051e53087 100644
--- a/openbsc/src/nat/bsc_filter.c
+++ b/openbsc/src/nat/bsc_filter.c
@@ -24,9 +24,10 @@
#include <openbsc/bsc_nat.h>
#include <openbsc/bssap.h>
#include <openbsc/ipaccess.h>
-#include <openbsc/talloc.h>
#include <openbsc/debug.h>
+#include <osmocore/talloc.h>
+
#include <sccp/sccp.h>
/*
diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c
index 6ce78be7f..09df4dcb6 100644
--- a/openbsc/src/nat/bsc_nat.c
+++ b/openbsc/src/nat/bsc_nat.c
@@ -36,19 +36,20 @@
#include <getopt.h>
#include <openbsc/debug.h>
-#include <openbsc/msgb.h>
#include <openbsc/bsc_msc.h>
#include <openbsc/bsc_nat.h>
#include <openbsc/bssap.h>
#include <openbsc/ipaccess.h>
#include <openbsc/abis_nm.h>
-#include <openbsc/talloc.h>
#include <openbsc/telnet_interface.h>
+#include <osmocore/talloc.h>
+
#include <vty/vty.h>
#include <sccp/sccp.h>
+struct debug_target *stderr_target;
static const char *config_file = "bsc-nat.cfg";
static char *msc_address = "127.0.0.1";
static struct in_addr local_addr;
@@ -309,7 +310,7 @@ static int forward_sccp_to_bts(struct msgb *msg)
if (!bsc)
return -1;
if (!bsc->authenticated) {
- LOGP(DNAT, LOGL_ERRO, "Selected BSC not authenticated.\n");
+ LOGP(DNAT, LOGL_ERROR, "Selected BSC not authenticated.\n");
return -1;
}
@@ -707,16 +708,16 @@ static void handle_options(int argc, char** argv)
print_help();
exit(0);
case 's':
- debug_use_color(0);
+ debug_set_use_color(stderr_target, 0);
break;
case 'd':
- debug_parse_category_mask(optarg);
+ debug_parse_category_mask(stderr_target, optarg);
break;
case 'c':
config_file = strdup(optarg);
break;
case 'T':
- debug_timestamp(1);
+ debug_set_print_timestamp(stderr_target, 1);
break;
case 'm':
msc_address = strdup(optarg);
@@ -749,6 +750,11 @@ int main(int argc, char** argv)
{
int rc;
+ debug_init();
+ stderr_target = debug_target_create_stderr();
+ debug_add_target(stderr_target);
+ debug_set_all_filter(stderr_target, 1);
+
/* parse options */
local_addr.s_addr = INADDR_ANY;
handle_options(argc, argv);
diff --git a/openbsc/src/nat/bsc_nat_vty.c b/openbsc/src/nat/bsc_nat_vty.c
index 24ef39835..5430670c9 100644
--- a/openbsc/src/nat/bsc_nat_vty.c
+++ b/openbsc/src/nat/bsc_nat_vty.c
@@ -25,7 +25,8 @@
#include <openbsc/bsc_nat.h>
#include <openbsc/gsm_04_08.h>
-#include <openbsc/talloc.h>
+
+#include <osmocore/talloc.h>
#include <sccp/sccp.h>
diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c
index c64bffdbd..9c978bee6 100644
--- a/openbsc/src/paging.c
+++ b/openbsc/src/paging.c
@@ -40,7 +40,7 @@
#include <assert.h>
#include <openbsc/paging.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/debug.h>
#include <openbsc/signal.h>
#include <openbsc/abis_rsl.h>
@@ -212,9 +212,9 @@ static void paging_T3113_expired(void *data)
cbfn = req->cbfn;
paging_remove_request(&req->bts->paging, req);
- req->bts->network->stats.paging.expired++;
+ counter_inc(req->bts->network->stats.paging.expired);
- dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
+ dispatch_signal(SS_PAGING, S_PAGING_EXPIRED, &sig_data);
if (cbfn)
cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED, NULL, NULL,
cbfn_param);
@@ -256,7 +256,7 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr,
struct gsm_bts *bts = NULL;
int num_pages = 0;
- network->stats.paging.attempted++;
+ counter_inc(network->stats.paging.attempted);
/* start paging subscriber on all BTS within Location Area */
do {
@@ -265,6 +265,11 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr,
bts = gsm_bts_by_lac(network, subscr->lac, bts);
if (!bts)
break;
+
+ /* skip all currently inactive TRX */
+ if (!trx_is_usable(bts->c0))
+ continue;
+
num_pages++;
/* Trigger paging, pass any error to caller */
@@ -274,7 +279,7 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr,
} while (1);
if (num_pages == 0)
- network->stats.paging.detached++;
+ counter_inc(network->stats.paging.detached);
return num_pages;
}
diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c
index 6c8c40314..a57e7dffe 100644
--- a/openbsc/src/rest_octets.c
+++ b/openbsc/src/rest_octets.c
@@ -27,7 +27,7 @@
#include <errno.h>
#include <openbsc/gsm_data.h>
-#include <openbsc/bitvec.h>
+#include <osmocore/bitvec.h>
#include <openbsc/rest_octets.h>
/* generate SI1 rest octets */
@@ -46,7 +46,7 @@ int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos)
bitvec_set_bit(&bv, L);
bitvec_spare_padding(&bv, 7);
- return 0;
+ return bv.data_len;
}
/* Append selection parameters to bitvec */
@@ -125,7 +125,8 @@ int rest_octets_si3(u_int8_t *data, const struct gsm48_si_ro_info *si3)
/* GPRS Indicator */
append_gprs_ind(&bv, &si3->gprs_ind);
- return bitvec_spare_padding(&bv, (bv.data_len*8)-1);
+ bitvec_spare_padding(&bv, (bv.data_len*8)-1);
+ return bv.data_len;
}
static int append_lsa_params(struct bitvec *bv,
@@ -178,7 +179,7 @@ int rest_octets_si4(u_int8_t *data, const struct gsm48_si_ro_info *si4)
bitvec_set_bit(&bv, si4->break_ind ? H : L);
}
- return 0;
+ return bv.data_len;
}
/* GPRS Mobile Allocation as per TS 04.60 Chapter 12.10a:
@@ -390,5 +391,6 @@ int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13)
}
}
}
- return bitvec_spare_padding(&bv, (bv.data_len*8)-1);
+ bitvec_spare_padding(&bv, (bv.data_len*8)-1);
+ return bv.data_len;
}
diff --git a/openbsc/src/rrlp.c b/openbsc/src/rrlp.c
index d4665d570..35044518c 100644
--- a/openbsc/src/rrlp.c
+++ b/openbsc/src/rrlp.c
@@ -89,14 +89,12 @@ static int paging_sig_cb(unsigned int subsys, unsigned int signal,
struct paging_signal_data *psig_data = signal_data;
switch (signal) {
- case S_PAGING_COMPLETED:
- /* paging might have "completed' unsucessfully,
- * in this case we don't have a lchan */
- if (!psig_data->lchan)
- break;
+ case S_PAGING_SUCCEEDED:
/* A subscriber has attached. */
send_rrlp_req(psig_data->lchan);
break;
+ case S_PAGING_EXPIRED:
+ break;
}
return 0;
}
diff --git a/openbsc/src/rs232.c b/openbsc/src/rs232.c
index a58472364..36af59cbf 100644
--- a/openbsc/src/rs232.c
+++ b/openbsc/src/rs232.c
@@ -28,8 +28,8 @@
#include <termios.h>
#include <fcntl.h>
-#include <openbsc/select.h>
-#include <openbsc/msgb.h>
+#include <osmocore/select.h>
+#include <osmocore/msgb.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/rs232.h>
diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c
index 0f4e32799..9f2e2fd76 100644
--- a/openbsc/src/rtp_proxy.c
+++ b/openbsc/src/rtp_proxy.c
@@ -19,6 +19,7 @@
*
*/
+#include <endian.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
@@ -29,10 +30,10 @@
#include <time.h> /* clock() */
#include <sys/utsname.h> /* uname() */
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/gsm_data.h>
-#include <openbsc/msgb.h>
-#include <openbsc/select.h>
+#include <osmocore/msgb.h>
+#include <osmocore/select.h>
#include <openbsc/debug.h>
#include <openbsc/rtp_proxy.h>
@@ -63,12 +64,21 @@ struct rtcp_hdr {
/* according to RFC 3550 */
struct rtp_hdr {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
u_int8_t csrc_count:4,
extension:1,
padding:1,
version:2;
u_int8_t payload_type:7,
marker:1;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u_int8_t version:2,
+ padding:1,
+ extension:1,
+ csrc_count:4;
+ u_int8_t marker:1,
+ payload_type:7;
+#endif
u_int16_t sequence;
u_int32_t timestamp;
u_int32_t ssrc;
@@ -240,7 +250,8 @@ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame)
if (abs(frame_diff) > 1) {
long int frame_diff_excess = frame_diff - 1;
- DEBUGP(DMUX, "Correcting frame difference of %ld frames\n", frame_diff_excess);
+ LOGP(DMUX, LOGL_NOTICE,
+ "Correcting frame difference of %ld frames\n", frame_diff_excess);
rs->transmit.sequence += frame_diff_excess;
rs->transmit.timestamp += frame_diff_excess * duration;
}
diff --git a/openbsc/src/sccp/sccp.c b/openbsc/src/sccp/sccp.c
index 8b3a487a0..b1da2c721 100644
--- a/openbsc/src/sccp/sccp.c
+++ b/openbsc/src/sccp/sccp.c
@@ -2,7 +2,7 @@
* SCCP management code
*
* (C) 2009, 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009, 2010 by on-waves.com
+ * (C) 2009, 2010 by On-Waves
*
* All Rights Reserved
*
@@ -24,11 +24,12 @@
#include <string.h>
+#include <osmocore/msgb.h>
+#include <openbsc/debug.h>
+#include <osmocore/talloc.h>
+
#include <sccp/sccp.h>
-#include <openbsc/debug.h>
-#include <openbsc/talloc.h>
-#include <openbsc/linuxlist.h>
static void *tall_sccp_ctx;
static LLIST_HEAD(sccp_connections);
@@ -208,7 +209,7 @@ int _sccp_parse_connection_request(struct msgb *msgb, struct sccp_parse_result *
static const u_int32_t called_offset =
offsetof(struct sccp_connection_request, variable_called);
- struct sccp_connection_request *req = (struct sccp_connection_request *)msgb->data;
+ struct sccp_connection_request *req = (struct sccp_connection_request *)msgb->l2h;
struct sccp_optional_data optional_data;
/* header check */
@@ -459,6 +460,7 @@ int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result)
msgb->l3h = &udt->data[udt->variable_data];
+ result->data_len = msgb_l3len(msgb);
if (msgb_l3len(msgb) != msgb->l3h[-1]) {
DEBUGP(DSCCP, "msgb is truncated is: %u should: %u\n",
@@ -469,6 +471,25 @@ int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result)
return 0;
}
+static int _sccp_parse_it(struct msgb *msgb, struct sccp_parse_result *result)
+{
+ static const u_int32_t header_size = sizeof(struct sccp_data_it);
+
+ struct sccp_data_it *it;
+
+ if (msgb_l2len(msgb) < header_size) {
+ DEBUGP(DSCCP, "msgb < header_size %u %u\n",
+ msgb_l2len(msgb), header_size);
+ return -1;
+ }
+
+ it = (struct sccp_data_it *) msgb->l2h;
+ result->data_len = 0;
+ result->source_local_reference = &it->source_local_reference;
+ result->destination_local_reference = &it->destination_local_reference;
+ return 0;
+}
+
/*
* Send UDT. Currently we have a fixed address...
@@ -1305,8 +1326,12 @@ int sccp_parse_header(struct msgb *msg, struct sccp_parse_result *result)
case SCCP_MSG_TYPE_UDT:
return _sccp_parse_udt(msg, result);
break;
+ case SCCP_MSG_TYPE_IT:
+ return _sccp_parse_it(msg, result);
+ break;
};
+ LOGP(DSCCP, LOGL_ERROR, "Unimplemented MSG Type: 0x%x\n", type);
return -1;
}
diff --git a/openbsc/src/select.c b/openbsc/src/select.c
deleted file mode 100644
index c11f3a511..000000000
--- a/openbsc/src/select.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/* select filedescriptor handling, taken from:
- * userspace logging daemon for the iptables ULOG target
- * of the linux 2.4 netfilter subsystem.
- *
- * (C) 2000-2009 by Harald Welte <laforge@gnumonks.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <fcntl.h>
-#include <openbsc/select.h>
-#include <openbsc/linuxlist.h>
-#include <openbsc/timer.h>
-
-static int maxfd = 0;
-static LLIST_HEAD(bsc_fds);
-static int unregistered_count;
-
-int bsc_register_fd(struct bsc_fd *fd)
-{
- int flags;
-
- /* make FD nonblocking */
- flags = fcntl(fd->fd, F_GETFL);
- if (flags < 0)
- return flags;
- flags |= O_NONBLOCK;
- flags = fcntl(fd->fd, F_SETFL, flags);
- if (flags < 0)
- return flags;
-
- /* Register FD */
- if (fd->fd > maxfd)
- maxfd = fd->fd;
-
- llist_add_tail(&fd->list, &bsc_fds);
-
- return 0;
-}
-
-void bsc_unregister_fd(struct bsc_fd *fd)
-{
- unregistered_count++;
- llist_del(&fd->list);
-}
-
-int bsc_select_main(int polling)
-{
- struct bsc_fd *ufd, *tmp;
- fd_set readset, writeset, exceptset;
- int work = 0, rc;
- struct timeval no_time = {0, 0};
-
- FD_ZERO(&readset);
- FD_ZERO(&writeset);
- FD_ZERO(&exceptset);
-
- /* prepare read and write fdsets */
- llist_for_each_entry(ufd, &bsc_fds, list) {
- if (ufd->when & BSC_FD_READ)
- FD_SET(ufd->fd, &readset);
-
- if (ufd->when & BSC_FD_WRITE)
- FD_SET(ufd->fd, &writeset);
-
- if (ufd->when & BSC_FD_EXCEPT)
- FD_SET(ufd->fd, &exceptset);
- }
-
- bsc_timer_check();
-
- if (!polling)
- bsc_prepare_timers();
- rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : bsc_nearest_timer());
- if (rc < 0)
- return 0;
-
- /* fire timers */
- bsc_update_timers();
-
- /* call registered callback functions */
-restart:
- unregistered_count = 0;
- llist_for_each_entry_safe(ufd, tmp, &bsc_fds, list) {
- int flags = 0;
-
- if (FD_ISSET(ufd->fd, &readset))
- flags |= BSC_FD_READ;
-
- if (FD_ISSET(ufd->fd, &writeset))
- flags |= BSC_FD_WRITE;
-
- if (FD_ISSET(ufd->fd, &exceptset))
- flags |= BSC_FD_EXCEPT;
-
- if (flags) {
- work = 1;
- ufd->cb(ufd, flags);
- }
- /* ugly, ugly hack. If more than one filedescriptors were
- * unregistered, they might have been consecutive and
- * llist_for_each_entry_safe() is no longer safe */
- if (unregistered_count > 1)
- goto restart;
- }
- return work;
-}
diff --git a/openbsc/src/signal.c b/openbsc/src/signal.c
deleted file mode 100644
index e04cadf73..000000000
--- a/openbsc/src/signal.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/* Generic signalling/notification infrastructure */
-/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.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 <openbsc/signal.h>
-#include <openbsc/talloc.h>
-#include <stdlib.h>
-#include <string.h>
-
-
-void *tall_sigh_ctx;
-static LLIST_HEAD(signal_handler_list);
-
-struct signal_handler {
- struct llist_head entry;
- unsigned int subsys;
- signal_cbfn *cbfn;
- void *data;
-};
-
-
-int register_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data)
-{
- struct signal_handler *sig_data;
-
- sig_data = talloc(tall_sigh_ctx, struct signal_handler);
- if (!sig_data)
- return -ENOMEM;
-
- memset(sig_data, 0, sizeof(*sig_data));
-
- sig_data->subsys = subsys;
- sig_data->data = data;
- sig_data->cbfn = cbfn;
-
- /* FIXME: check if we already have a handler for this subsys/cbfn/data */
-
- llist_add_tail(&sig_data->entry, &signal_handler_list);
-
- return 0;
-}
-
-void unregister_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data)
-{
- struct signal_handler *handler;
-
- llist_for_each_entry(handler, &signal_handler_list, entry) {
- if (handler->cbfn == cbfn && handler->data == data
- && subsys == handler->subsys) {
- llist_del(&handler->entry);
- talloc_free(handler);
- break;
- }
- }
-}
-
-
-void dispatch_signal(unsigned int subsys, unsigned int signal, void *signal_data)
-{
- struct signal_handler *handler;
-
- llist_for_each_entry(handler, &signal_handler_list, entry) {
- if (handler->subsys != subsys)
- continue;
- (*handler->cbfn)(subsys, signal, handler->data, signal_data);
- }
-}
diff --git a/openbsc/src/silent_call.c b/openbsc/src/silent_call.c
index 82b656327..cada24e66 100644
--- a/openbsc/src/silent_call.c
+++ b/openbsc/src/silent_call.c
@@ -25,7 +25,7 @@
#include <unistd.h>
#include <errno.h>
-#include <openbsc/msgb.h>
+#include <osmocore/msgb.h>
#include <openbsc/signal.h>
#include <openbsc/debug.h>
#include <openbsc/paging.h>
@@ -34,6 +34,7 @@
#include <openbsc/abis_rsl.h>
#include <openbsc/chan_alloc.h>
+/* paging of the requested subscriber has completed */
static int paging_cb_silent(unsigned int hooknum, unsigned int event,
struct msgb *msg, void *_lchan, void *_data)
{
@@ -53,6 +54,7 @@ static int paging_cb_silent(unsigned int hooknum, unsigned int event,
case GSM_PAGING_SUCCEEDED:
DEBUGPC(DSMS, "success, using Timeslot %u on ARFCN %u\n",
lchan->ts->nr, lchan->ts->trx->arfcn);
+ lchan->silent_call = 1;
/* increment lchan reference count */
dispatch_signal(SS_SCALL, S_SCALL_SUCCESS, &sigdata);
use_lchan(lchan);
@@ -69,15 +71,58 @@ static int paging_cb_silent(unsigned int hooknum, unsigned int event,
return rc;
}
-int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data)
+/* receive a layer 3 message from a silent call */
+int silent_call_rx(struct msgb *msg)
+{
+ /* FIXME: do something like sending it through a UDP port */
+ return 0;
+}
+
+struct msg_match {
+ u_int8_t pdisc;
+ u_int8_t msg_type;
+};
+
+/* list of messages that are handled inside OpenBSC, even in a silent call */
+static const struct msg_match silent_call_accept[] = {
+ { GSM48_PDISC_MM, GSM48_MT_MM_LOC_UPD_REQUEST },
+ { GSM48_PDISC_MM, GSM48_MT_MM_CM_SERV_REQ },
+};
+
+/* decide if we need to reroute a message as part of a silent call */
+int silent_call_reroute(struct msgb *msg)
+{
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ u_int8_t pdisc = gh->proto_discr & 0x0f;
+ int i;
+
+ /* if we're not part of a silent call, never reroute */
+ if (!msg->lchan->silent_call)
+ return 0;
+
+ /* check if we are a special message that is handled in openbsc */
+ for (i = 0; i < ARRAY_SIZE(silent_call_accept); i++) {
+ if (silent_call_accept[i].pdisc == pdisc &&
+ silent_call_accept[i].msg_type == gh->msg_type)
+ return 0;
+ }
+
+ /* otherwise, reroute */
+ return 1;
+}
+
+
+/* initiate a silent call with a given subscriber */
+int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data, int type)
{
int rc;
- rc = paging_request(subscr->net, subscr, RSL_CHANNEED_TCH_F,
+ rc = paging_request(subscr->net, subscr, type,
paging_cb_silent, data);
return rc;
}
+/* end a silent call with a given subscriber */
int gsm_silent_call_stop(struct gsm_subscriber *subscr)
{
struct gsm_lchan *lchan;
@@ -86,7 +131,10 @@ int gsm_silent_call_stop(struct gsm_subscriber *subscr)
if (!lchan)
return -EINVAL;
- /* FIXME: did we actually establish a silent call for this guy? */
+ /* did we actually establish a silent call for this guy? */
+ if (!lchan->silent_call)
+ return -EINVAL;
+
put_lchan(lchan);
return 0;
diff --git a/openbsc/src/subchan_demux.c b/openbsc/src/subchan_demux.c
index 63be533df..0d6c1febe 100644
--- a/openbsc/src/subchan_demux.c
+++ b/openbsc/src/subchan_demux.c
@@ -28,7 +28,7 @@
#include <openbsc/subchan_demux.h>
#include <openbsc/trau_frame.h>
#include <openbsc/debug.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/gsm_data.h>
void *tall_tqe_ctx;
diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c
index 7625da637..a9df0ba26 100644
--- a/openbsc/src/system_information.c
+++ b/openbsc/src/system_information.c
@@ -31,13 +31,29 @@
#include <openbsc/gsm_data.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/rest_octets.h>
-#include <openbsc/bitvec.h>
+#include <osmocore/bitvec.h>
#include <openbsc/debug.h>
#define GSM48_CELL_CHAN_DESC_SIZE 16
#define GSM_MACBLOCK_LEN 23
#define GSM_MACBLOCK_PADDING 0x2b
+/* verify the sizes of the system information type structs */
+
+/* rest octets are not part of the struct */
+static_assert(sizeof(struct gsm48_system_information_type_header) == 3, _si_header_size);
+static_assert(sizeof(struct gsm48_rach_control) == 3, _si_rach_control);
+static_assert(sizeof(struct gsm48_system_information_type_1) == 22, _si1_size);
+static_assert(sizeof(struct gsm48_system_information_type_2) == 23, _si2_size);
+static_assert(sizeof(struct gsm48_system_information_type_3) == 19, _si3_size);
+static_assert(sizeof(struct gsm48_system_information_type_4) == 13, _si4_size);
+
+/* bs11 forgot the l2 len, 0-6 rest octets */
+static_assert(sizeof(struct gsm48_system_information_type_5) == 18, _si5_size);
+static_assert(sizeof(struct gsm48_system_information_type_6) == 11, _si6_size);
+
+static_assert(sizeof(struct gsm48_system_information_type_13) == 3, _si13_size);
+
/* Frequency Lists as per TS 04.08 10.5.2.13 */
/* 10.5.2.13.2: Bit map 0 format */
@@ -98,7 +114,7 @@ static int freq_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn)
static int bitvec2freq_list(u_int8_t *chan_list, struct bitvec *bv,
const struct gsm_bts *bts)
{
- int i, rc, min = 1024, max = 0;
+ int i, rc, min = 1024, max = -1;
memset(chan_list, 0, 16);
@@ -128,6 +144,12 @@ static int bitvec2freq_list(u_int8_t *chan_list, struct bitvec *bv,
}
}
+ if (max == -1) {
+ /* Empty set, use 'bit map 0 format' */
+ chan_list[0] = 0;
+ return 0;
+ }
+
if ((max - min) > 111) {
LOGP(DRR, LOGL_ERROR, "min_arfcn=%u, max_arfcn=%u, "
"distance > 111\n", min, max);
@@ -200,9 +222,8 @@ static int generate_si1(u_int8_t *output, struct gsm_bts *bts)
si1->rach_control = bts->si_common.rach_control;
/* SI1 Rest Octets (10.5.2.32), contains NCH position */
- rest_octets_si1(si1->rest_octets, NULL);
-
- return GSM_MACBLOCK_LEN;
+ rc = rest_octets_si1(si1->rest_octets, NULL);
+ return sizeof(*si1) + rc;
}
static int generate_si2(u_int8_t *output, struct gsm_bts *bts)
@@ -225,7 +246,7 @@ static int generate_si2(u_int8_t *output, struct gsm_bts *bts)
si2->ncc_permitted = bts->si_common.ncc_permitted;
si2->rach_control = bts->si_common.rach_control;
- return GSM_MACBLOCK_LEN;
+ return sizeof(*si2);
}
struct gsm48_si_ro_info si_info = {
@@ -254,6 +275,7 @@ struct gsm48_si_ro_info si_info = {
static int generate_si3(u_int8_t *output, struct gsm_bts *bts)
{
+ int rc;
struct gsm48_system_information_type_3 *si3 =
(struct gsm48_system_information_type_3 *) output;
@@ -265,9 +287,9 @@ static int generate_si3(u_int8_t *output, struct gsm_bts *bts)
si3->header.system_information = GSM48_MT_RR_SYSINFO_3;
si3->cell_identity = htons(bts->cell_identity);
- gsm0408_generate_lai(&si3->lai, bts->network->country_code,
- bts->network->network_code,
- bts->location_area_code);
+ gsm48_generate_lai(&si3->lai, bts->network->country_code,
+ bts->network->network_code,
+ bts->location_area_code);
si3->control_channel_desc = bts->si_common.chan_desc;
si3->cell_options = bts->si_common.cell_options;
si3->cell_sel_par = bts->si_common.cell_sel_par;
@@ -277,13 +299,14 @@ static int generate_si3(u_int8_t *output, struct gsm_bts *bts)
CBQ, CELL_RESELECT_OFFSET, TEMPORARY_OFFSET, PENALTY_TIME
Power Offset, 2ter Indicator, Early Classmark Sending,
Scheduling if and WHERE, GPRS Indicator, SI13 position */
- rest_octets_si3(si3->rest_octets, &si_info);
+ rc = rest_octets_si3(si3->rest_octets, &si_info);
- return GSM_MACBLOCK_LEN;
+ return sizeof(*si3) + rc;
}
static int generate_si4(u_int8_t *output, struct gsm_bts *bts)
{
+ int rc;
struct gsm48_system_information_type_4 *si4 =
(struct gsm48_system_information_type_4 *) output;
@@ -296,9 +319,9 @@ static int generate_si4(u_int8_t *output, struct gsm_bts *bts)
si4->header.skip_indicator = 0;
si4->header.system_information = GSM48_MT_RR_SYSINFO_4;
- gsm0408_generate_lai(&si4->lai, bts->network->country_code,
- bts->network->network_code,
- bts->location_area_code);
+ gsm48_generate_lai(&si4->lai, bts->network->country_code,
+ bts->network->network_code,
+ bts->location_area_code);
si4->cell_sel_par = bts->si_common.cell_sel_par;
si4->rach_control = bts->si_common.rach_control;
@@ -309,9 +332,9 @@ static int generate_si4(u_int8_t *output, struct gsm_bts *bts)
/* SI4 Rest Octets (10.5.2.35), containing
Optional Power offset, GPRS Indicator,
Cell Identity, LSA ID, Selection Parameter */
- rest_octets_si4(si4->data, &si_info);
+ rc = rest_octets_si4(si4->data, &si_info);
- return GSM_MACBLOCK_LEN;
+ return sizeof(*si4) + rc;
}
static int generate_si5(u_int8_t *output, struct gsm_bts *bts)
@@ -361,9 +384,9 @@ static int generate_si6(u_int8_t *output, struct gsm_bts *bts)
si6->skip_indicator = 0;
si6->system_information = GSM48_MT_RR_SYSINFO_6;
si6->cell_identity = htons(bts->cell_identity);
- gsm0408_generate_lai(&si6->lai, bts->network->country_code,
- bts->network->network_code,
- bts->location_area_code);
+ gsm48_generate_lai(&si6->lai, bts->network->country_code,
+ bts->network->network_code,
+ bts->location_area_code);
si6->cell_options = bts->si_common.cell_options;
si6->ncc_permitted = bts->si_common.ncc_permitted;
@@ -418,7 +441,7 @@ static int generate_si13(u_int8_t *output, struct gsm_bts *bts)
si13->header.l2_plen = ret & 0xff;
- return GSM_MACBLOCK_LEN;
+ return sizeof (*si13) + ret;
}
int gsm_generate_si(u_int8_t *output, struct gsm_bts *bts, int type)
diff --git a/openbsc/src/talloc.c b/openbsc/src/talloc.c
deleted file mode 100644
index d8213238e..000000000
--- a/openbsc/src/talloc.c
+++ /dev/null
@@ -1,1805 +0,0 @@
-/*
- Samba Unix SMB/CIFS implementation.
-
- Samba trivial allocation library - new interface
-
- NOTE: Please read talloc_guide.txt for full documentation
-
- Copyright (C) Andrew Tridgell 2004
- Copyright (C) Stefan Metzmacher 2006
-
- ** NOTE! The following LGPL license applies to the talloc
- ** library. This does NOT imply that all of Samba is released
- ** under the LGPL
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- This library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*
- inspired by http://swapped.cc/halloc/
-*/
-
-#ifdef _SAMBA_BUILD_
-#include "version.h"
-#if (SAMBA_VERSION_MAJOR<4)
-#include "includes.h"
-/* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file
- * we trust ourselves... */
-#ifdef malloc
-#undef malloc
-#endif
-#ifdef realloc
-#undef realloc
-#endif
-#define _TALLOC_SAMBA3
-#endif /* (SAMBA_VERSION_MAJOR<4) */
-#endif /* _SAMBA_BUILD_ */
-
-#ifndef _TALLOC_SAMBA3
-//#include "replace.h"
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdbool.h>
-#define __USE_GNU
-#include <string.h>
-#undef __USE_GNU
-#include <openbsc/talloc.h>
-#define MIN(x,y) ((x) < (y) ? (x) : (y))
-#endif /* not _TALLOC_SAMBA3 */
-
-/* use this to force every realloc to change the pointer, to stress test
- code that might not cope */
-#define ALWAYS_REALLOC 0
-
-
-#define MAX_TALLOC_SIZE 0x10000000
-#define TALLOC_MAGIC 0xe814ec70
-#define TALLOC_FLAG_FREE 0x01
-#define TALLOC_FLAG_LOOP 0x02
-#define TALLOC_FLAG_POOL 0x04 /* This is a talloc pool */
-#define TALLOC_FLAG_POOLMEM 0x08 /* This is allocated in a pool */
-#define TALLOC_MAGIC_REFERENCE ((const char *)1)
-
-/* by default we abort when given a bad pointer (such as when talloc_free() is called
- on a pointer that came from malloc() */
-#ifndef TALLOC_ABORT
-#define TALLOC_ABORT(reason) abort()
-#endif
-
-#ifndef discard_const_p
-#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
-# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
-#else
-# define discard_const_p(type, ptr) ((type *)(ptr))
-#endif
-#endif
-
-/* these macros gain us a few percent of speed on gcc */
-#if (__GNUC__ >= 3)
-/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
- as its first argument */
-#ifndef likely
-#define likely(x) __builtin_expect(!!(x), 1)
-#endif
-#ifndef unlikely
-#define unlikely(x) __builtin_expect(!!(x), 0)
-#endif
-#else
-#ifndef likely
-#define likely(x) (x)
-#endif
-#ifndef unlikely
-#define unlikely(x) (x)
-#endif
-#endif
-
-#ifdef __APPLE__
-/* taken from http://insanecoding.blogspot.com/2007/03/methods-for-safe-string-handling.html */
-size_t strnlen(const char *s, size_t n)
-{
- const char *p = (const char *)memchr(s, 0, n);
- return(p ? p-s : n);
-}
-#endif
-
-/* this null_context is only used if talloc_enable_leak_report() or
- talloc_enable_leak_report_full() is called, otherwise it remains
- NULL
-*/
-static void *null_context;
-static void *autofree_context;
-
-struct talloc_reference_handle {
- struct talloc_reference_handle *next, *prev;
- void *ptr;
-};
-
-typedef int (*talloc_destructor_t)(void *);
-
-struct talloc_chunk {
- struct talloc_chunk *next, *prev;
- struct talloc_chunk *parent, *child;
- struct talloc_reference_handle *refs;
- talloc_destructor_t destructor;
- const char *name;
- size_t size;
- unsigned flags;
-
- /*
- * "pool" has dual use:
- *
- * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool"
- * marks the end of the currently allocated area.
- *
- * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool"
- * is a pointer to the struct talloc_chunk of the pool that it was
- * allocated from. This way children can quickly find the pool to chew
- * from.
- */
- void *pool;
-};
-
-/* 16 byte alignment seems to keep everyone happy */
-#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
-#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
-
-static void (*talloc_abort_fn)(const char *reason);
-
-void talloc_set_abort_fn(void (*abort_fn)(const char *reason))
-{
- talloc_abort_fn = abort_fn;
-}
-
-static void talloc_abort(const char *reason)
-{
- if (!talloc_abort_fn) {
- TALLOC_ABORT(reason);
- }
-
- talloc_abort_fn(reason);
-}
-
-static void talloc_abort_double_free(void)
-{
- talloc_abort("Bad talloc magic value - double free");
-}
-
-static void talloc_abort_unknown_value(void)
-{
- talloc_abort("Bad talloc magic value - unknown value");
-}
-
-/* panic if we get a bad magic value */
-static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
-{
- const char *pp = (const char *)ptr;
- struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
- if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) {
- if (tc->flags & TALLOC_FLAG_FREE) {
- talloc_abort_double_free();
- } else {
- talloc_abort_unknown_value();
- }
- }
- return tc;
-}
-
-/* hook into the front of the list */
-#define _TLIST_ADD(list, p) \
-do { \
- if (!(list)) { \
- (list) = (p); \
- (p)->next = (p)->prev = NULL; \
- } else { \
- (list)->prev = (p); \
- (p)->next = (list); \
- (p)->prev = NULL; \
- (list) = (p); \
- }\
-} while (0)
-
-/* remove an element from a list - element doesn't have to be in list. */
-#define _TLIST_REMOVE(list, p) \
-do { \
- if ((p) == (list)) { \
- (list) = (p)->next; \
- if (list) (list)->prev = NULL; \
- } else { \
- if ((p)->prev) (p)->prev->next = (p)->next; \
- if ((p)->next) (p)->next->prev = (p)->prev; \
- } \
- if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
-} while (0)
-
-
-/*
- return the parent chunk of a pointer
-*/
-static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr)
-{
- struct talloc_chunk *tc;
-
- if (unlikely(ptr == NULL)) {
- return NULL;
- }
-
- tc = talloc_chunk_from_ptr(ptr);
- while (tc->prev) tc=tc->prev;
-
- return tc->parent;
-}
-
-void *talloc_parent(const void *ptr)
-{
- struct talloc_chunk *tc = talloc_parent_chunk(ptr);
- return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
-}
-
-/*
- find parents name
-*/
-const char *talloc_parent_name(const void *ptr)
-{
- struct talloc_chunk *tc = talloc_parent_chunk(ptr);
- return tc? tc->name : NULL;
-}
-
-/*
- A pool carries an in-pool object count count in the first 16 bytes.
- bytes. This is done to support talloc_steal() to a parent outside of the
- pool. The count includes the pool itself, so a talloc_free() on a pool will
- only destroy the pool if the count has dropped to zero. A talloc_free() of a
- pool member will reduce the count, and eventually also call free(3) on the
- pool memory.
-
- The object count is not put into "struct talloc_chunk" because it is only
- relevant for talloc pools and the alignment to 16 bytes would increase the
- memory footprint of each talloc chunk by those 16 bytes.
-*/
-
-#define TALLOC_POOL_HDR_SIZE 16
-
-static unsigned int *talloc_pool_objectcount(struct talloc_chunk *tc)
-{
- return (unsigned int *)((char *)tc + sizeof(struct talloc_chunk));
-}
-
-/*
- Allocate from a pool
-*/
-
-static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
- size_t size)
-{
- struct talloc_chunk *pool_ctx = NULL;
- size_t space_left;
- struct talloc_chunk *result;
- size_t chunk_size;
-
- if (parent == NULL) {
- return NULL;
- }
-
- if (parent->flags & TALLOC_FLAG_POOL) {
- pool_ctx = parent;
- }
- else if (parent->flags & TALLOC_FLAG_POOLMEM) {
- pool_ctx = (struct talloc_chunk *)parent->pool;
- }
-
- if (pool_ctx == NULL) {
- return NULL;
- }
-
- space_left = ((char *)pool_ctx + TC_HDR_SIZE + pool_ctx->size)
- - ((char *)pool_ctx->pool);
-
- /*
- * Align size to 16 bytes
- */
- chunk_size = ((size + 15) & ~15);
-
- if (space_left < chunk_size) {
- return NULL;
- }
-
- result = (struct talloc_chunk *)pool_ctx->pool;
-
-#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
- VALGRIND_MAKE_MEM_UNDEFINED(result, size);
-#endif
-
- pool_ctx->pool = (void *)((char *)result + chunk_size);
-
- result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM;
- result->pool = pool_ctx;
-
- *talloc_pool_objectcount(pool_ctx) += 1;
-
- return result;
-}
-
-/*
- Allocate a bit of memory as a child of an existing pointer
-*/
-static inline void *__talloc(const void *context, size_t size)
-{
- struct talloc_chunk *tc = NULL;
-
- if (unlikely(context == NULL)) {
- context = null_context;
- }
-
- if (unlikely(size >= MAX_TALLOC_SIZE)) {
- return NULL;
- }
-
- if (context != NULL) {
- tc = talloc_alloc_pool(talloc_chunk_from_ptr(context),
- TC_HDR_SIZE+size);
- }
-
- if (tc == NULL) {
- tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
- if (unlikely(tc == NULL)) return NULL;
- tc->flags = TALLOC_MAGIC;
- tc->pool = NULL;
- }
-
- tc->size = size;
- tc->destructor = NULL;
- tc->child = NULL;
- tc->name = NULL;
- tc->refs = NULL;
-
- if (likely(context)) {
- struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
-
- if (parent->child) {
- parent->child->parent = NULL;
- tc->next = parent->child;
- tc->next->prev = tc;
- } else {
- tc->next = NULL;
- }
- tc->parent = parent;
- tc->prev = NULL;
- parent->child = tc;
- } else {
- tc->next = tc->prev = tc->parent = NULL;
- }
-
- return TC_PTR_FROM_CHUNK(tc);
-}
-
-/*
- * Create a talloc pool
- */
-
-void *talloc_pool(const void *context, size_t size)
-{
- void *result = __talloc(context, size + TALLOC_POOL_HDR_SIZE);
- struct talloc_chunk *tc;
-
- if (unlikely(result == NULL)) {
- return NULL;
- }
-
- tc = talloc_chunk_from_ptr(result);
-
- tc->flags |= TALLOC_FLAG_POOL;
- tc->pool = (char *)result + TALLOC_POOL_HDR_SIZE;
-
- *talloc_pool_objectcount(tc) = 1;
-
-#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
- VALGRIND_MAKE_MEM_NOACCESS(tc->pool, size);
-#endif
-
- return result;
-}
-
-/*
- setup a destructor to be called on free of a pointer
- the destructor should return 0 on success, or -1 on failure.
- if the destructor fails then the free is failed, and the memory can
- be continued to be used
-*/
-void _talloc_set_destructor(const void *ptr, int (*destructor)(void *))
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- tc->destructor = destructor;
-}
-
-/*
- increase the reference count on a piece of memory.
-*/
-int talloc_increase_ref_count(const void *ptr)
-{
- if (unlikely(!talloc_reference(null_context, ptr))) {
- return -1;
- }
- return 0;
-}
-
-/*
- helper for talloc_reference()
-
- this is referenced by a function pointer and should not be inline
-*/
-static int talloc_reference_destructor(struct talloc_reference_handle *handle)
-{
- struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr);
- _TLIST_REMOVE(ptr_tc->refs, handle);
- return 0;
-}
-
-/*
- more efficient way to add a name to a pointer - the name must point to a
- true string constant
-*/
-static inline void _talloc_set_name_const(const void *ptr, const char *name)
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- tc->name = name;
-}
-
-/*
- internal talloc_named_const()
-*/
-static inline void *_talloc_named_const(const void *context, size_t size, const char *name)
-{
- void *ptr;
-
- ptr = __talloc(context, size);
- if (unlikely(ptr == NULL)) {
- return NULL;
- }
-
- _talloc_set_name_const(ptr, name);
-
- return ptr;
-}
-
-/*
- make a secondary reference to a pointer, hanging off the given context.
- the pointer remains valid until both the original caller and this given
- context are freed.
-
- the major use for this is when two different structures need to reference the
- same underlying data, and you want to be able to free the two instances separately,
- and in either order
-*/
-void *_talloc_reference(const void *context, const void *ptr)
-{
- struct talloc_chunk *tc;
- struct talloc_reference_handle *handle;
- if (unlikely(ptr == NULL)) return NULL;
-
- tc = talloc_chunk_from_ptr(ptr);
- handle = (struct talloc_reference_handle *)_talloc_named_const(context,
- sizeof(struct talloc_reference_handle),
- TALLOC_MAGIC_REFERENCE);
- if (unlikely(handle == NULL)) return NULL;
-
- /* note that we hang the destructor off the handle, not the
- main context as that allows the caller to still setup their
- own destructor on the context if they want to */
- talloc_set_destructor(handle, talloc_reference_destructor);
- handle->ptr = discard_const_p(void, ptr);
- _TLIST_ADD(tc->refs, handle);
- return handle->ptr;
-}
-
-
-/*
- internal talloc_free call
-*/
-static inline int _talloc_free(void *ptr)
-{
- struct talloc_chunk *tc;
-
- if (unlikely(ptr == NULL)) {
- return -1;
- }
-
- tc = talloc_chunk_from_ptr(ptr);
-
- if (unlikely(tc->refs)) {
- int is_child;
- /* check this is a reference from a child or grantchild
- * back to it's parent or grantparent
- *
- * in that case we need to remove the reference and
- * call another instance of talloc_free() on the current
- * pointer.
- */
- is_child = talloc_is_parent(tc->refs, ptr);
- _talloc_free(tc->refs);
- if (is_child) {
- return _talloc_free(ptr);
- }
- return -1;
- }
-
- if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) {
- /* we have a free loop - stop looping */
- return 0;
- }
-
- if (unlikely(tc->destructor)) {
- talloc_destructor_t d = tc->destructor;
- if (d == (talloc_destructor_t)-1) {
- return -1;
- }
- tc->destructor = (talloc_destructor_t)-1;
- if (d(ptr) == -1) {
- tc->destructor = d;
- return -1;
- }
- tc->destructor = NULL;
- }
-
- if (tc->parent) {
- _TLIST_REMOVE(tc->parent->child, tc);
- if (tc->parent->child) {
- tc->parent->child->parent = tc->parent;
- }
- } else {
- if (tc->prev) tc->prev->next = tc->next;
- if (tc->next) tc->next->prev = tc->prev;
- }
-
- tc->flags |= TALLOC_FLAG_LOOP;
-
- while (tc->child) {
- /* we need to work out who will own an abandoned child
- if it cannot be freed. In priority order, the first
- choice is owner of any remaining reference to this
- pointer, the second choice is our parent, and the
- final choice is the null context. */
- void *child = TC_PTR_FROM_CHUNK(tc->child);
- const void *new_parent = null_context;
- if (unlikely(tc->child->refs)) {
- struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
- if (p) new_parent = TC_PTR_FROM_CHUNK(p);
- }
- if (unlikely(_talloc_free(child) == -1)) {
- if (new_parent == null_context) {
- struct talloc_chunk *p = talloc_parent_chunk(ptr);
- if (p) new_parent = TC_PTR_FROM_CHUNK(p);
- }
- talloc_steal(new_parent, child);
- }
- }
-
- tc->flags |= TALLOC_FLAG_FREE;
-
- if (tc->flags & (TALLOC_FLAG_POOL|TALLOC_FLAG_POOLMEM)) {
- struct talloc_chunk *pool;
- unsigned int *pool_object_count;
-
- pool = (tc->flags & TALLOC_FLAG_POOL)
- ? tc : (struct talloc_chunk *)tc->pool;
-
- pool_object_count = talloc_pool_objectcount(pool);
-
- if (*pool_object_count == 0) {
- talloc_abort("Pool object count zero!");
- }
-
- *pool_object_count -= 1;
-
- if (*pool_object_count == 0) {
- free(pool);
- }
- }
- else {
- free(tc);
- }
- return 0;
-}
-
-/*
- move a lump of memory from one talloc context to another return the
- ptr on success, or NULL if it could not be transferred.
- passing NULL as ptr will always return NULL with no side effects.
-*/
-void *_talloc_steal(const void *new_ctx, const void *ptr)
-{
- struct talloc_chunk *tc, *new_tc;
-
- if (unlikely(!ptr)) {
- return NULL;
- }
-
- if (unlikely(new_ctx == NULL)) {
- new_ctx = null_context;
- }
-
- tc = talloc_chunk_from_ptr(ptr);
-
- if (unlikely(new_ctx == NULL)) {
- if (tc->parent) {
- _TLIST_REMOVE(tc->parent->child, tc);
- if (tc->parent->child) {
- tc->parent->child->parent = tc->parent;
- }
- } else {
- if (tc->prev) tc->prev->next = tc->next;
- if (tc->next) tc->next->prev = tc->prev;
- }
-
- tc->parent = tc->next = tc->prev = NULL;
- return discard_const_p(void, ptr);
- }
-
- new_tc = talloc_chunk_from_ptr(new_ctx);
-
- if (unlikely(tc == new_tc || tc->parent == new_tc)) {
- return discard_const_p(void, ptr);
- }
-
- if (tc->parent) {
- _TLIST_REMOVE(tc->parent->child, tc);
- if (tc->parent->child) {
- tc->parent->child->parent = tc->parent;
- }
- } else {
- if (tc->prev) tc->prev->next = tc->next;
- if (tc->next) tc->next->prev = tc->prev;
- }
-
- tc->parent = new_tc;
- if (new_tc->child) new_tc->child->parent = NULL;
- _TLIST_ADD(new_tc->child, tc);
-
- return discard_const_p(void, ptr);
-}
-
-
-
-/*
- remove a secondary reference to a pointer. This undo's what
- talloc_reference() has done. The context and pointer arguments
- must match those given to a talloc_reference()
-*/
-static inline int talloc_unreference(const void *context, const void *ptr)
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- struct talloc_reference_handle *h;
-
- if (unlikely(context == NULL)) {
- context = null_context;
- }
-
- for (h=tc->refs;h;h=h->next) {
- struct talloc_chunk *p = talloc_parent_chunk(h);
- if (p == NULL) {
- if (context == NULL) break;
- } else if (TC_PTR_FROM_CHUNK(p) == context) {
- break;
- }
- }
- if (h == NULL) {
- return -1;
- }
-
- return _talloc_free(h);
-}
-
-/*
- remove a specific parent context from a pointer. This is a more
- controlled varient of talloc_free()
-*/
-int talloc_unlink(const void *context, void *ptr)
-{
- struct talloc_chunk *tc_p, *new_p;
- void *new_parent;
-
- if (ptr == NULL) {
- return -1;
- }
-
- if (context == NULL) {
- context = null_context;
- }
-
- if (talloc_unreference(context, ptr) == 0) {
- return 0;
- }
-
- if (context == NULL) {
- if (talloc_parent_chunk(ptr) != NULL) {
- return -1;
- }
- } else {
- if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
- return -1;
- }
- }
-
- tc_p = talloc_chunk_from_ptr(ptr);
-
- if (tc_p->refs == NULL) {
- return _talloc_free(ptr);
- }
-
- new_p = talloc_parent_chunk(tc_p->refs);
- if (new_p) {
- new_parent = TC_PTR_FROM_CHUNK(new_p);
- } else {
- new_parent = NULL;
- }
-
- if (talloc_unreference(new_parent, ptr) != 0) {
- return -1;
- }
-
- talloc_steal(new_parent, ptr);
-
- return 0;
-}
-
-/*
- add a name to an existing pointer - va_list version
-*/
-static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
-
-static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- tc->name = talloc_vasprintf(ptr, fmt, ap);
- if (likely(tc->name)) {
- _talloc_set_name_const(tc->name, ".name");
- }
- return tc->name;
-}
-
-/*
- add a name to an existing pointer
-*/
-const char *talloc_set_name(const void *ptr, const char *fmt, ...)
-{
- const char *name;
- va_list ap;
- va_start(ap, fmt);
- name = talloc_set_name_v(ptr, fmt, ap);
- va_end(ap);
- return name;
-}
-
-
-/*
- create a named talloc pointer. Any talloc pointer can be named, and
- talloc_named() operates just like talloc() except that it allows you
- to name the pointer.
-*/
-void *talloc_named(const void *context, size_t size, const char *fmt, ...)
-{
- va_list ap;
- void *ptr;
- const char *name;
-
- ptr = __talloc(context, size);
- if (unlikely(ptr == NULL)) return NULL;
-
- va_start(ap, fmt);
- name = talloc_set_name_v(ptr, fmt, ap);
- va_end(ap);
-
- if (unlikely(name == NULL)) {
- _talloc_free(ptr);
- return NULL;
- }
-
- return ptr;
-}
-
-/*
- return the name of a talloc ptr, or "UNNAMED"
-*/
-const char *talloc_get_name(const void *ptr)
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) {
- return ".reference";
- }
- if (likely(tc->name)) {
- return tc->name;
- }
- return "UNNAMED";
-}
-
-
-/*
- check if a pointer has the given name. If it does, return the pointer,
- otherwise return NULL
-*/
-void *talloc_check_name(const void *ptr, const char *name)
-{
- const char *pname;
- if (unlikely(ptr == NULL)) return NULL;
- pname = talloc_get_name(ptr);
- if (likely(pname == name || strcmp(pname, name) == 0)) {
- return discard_const_p(void, ptr);
- }
- return NULL;
-}
-
-static void talloc_abort_type_missmatch(const char *location,
- const char *name,
- const char *expected)
-{
- const char *reason;
-
- reason = talloc_asprintf(NULL,
- "%s: Type mismatch: name[%s] expected[%s]",
- location,
- name?name:"NULL",
- expected);
- if (!reason) {
- reason = "Type mismatch";
- }
-
- talloc_abort(reason);
-}
-
-void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location)
-{
- const char *pname;
-
- if (unlikely(ptr == NULL)) {
- talloc_abort_type_missmatch(location, NULL, name);
- return NULL;
- }
-
- pname = talloc_get_name(ptr);
- if (likely(pname == name || strcmp(pname, name) == 0)) {
- return discard_const_p(void, ptr);
- }
-
- talloc_abort_type_missmatch(location, pname, name);
- return NULL;
-}
-
-/*
- this is for compatibility with older versions of talloc
-*/
-void *talloc_init(const char *fmt, ...)
-{
- va_list ap;
- void *ptr;
- const char *name;
-
- /*
- * samba3 expects talloc_report_depth_cb(NULL, ...)
- * reports all talloc'ed memory, so we need to enable
- * null_tracking
- */
- talloc_enable_null_tracking();
-
- ptr = __talloc(NULL, 0);
- if (unlikely(ptr == NULL)) return NULL;
-
- va_start(ap, fmt);
- name = talloc_set_name_v(ptr, fmt, ap);
- va_end(ap);
-
- if (unlikely(name == NULL)) {
- _talloc_free(ptr);
- return NULL;
- }
-
- return ptr;
-}
-
-/*
- this is a replacement for the Samba3 talloc_destroy_pool functionality. It
- should probably not be used in new code. It's in here to keep the talloc
- code consistent across Samba 3 and 4.
-*/
-void talloc_free_children(void *ptr)
-{
- struct talloc_chunk *tc;
-
- if (unlikely(ptr == NULL)) {
- return;
- }
-
- tc = talloc_chunk_from_ptr(ptr);
-
- while (tc->child) {
- /* we need to work out who will own an abandoned child
- if it cannot be freed. In priority order, the first
- choice is owner of any remaining reference to this
- pointer, the second choice is our parent, and the
- final choice is the null context. */
- void *child = TC_PTR_FROM_CHUNK(tc->child);
- const void *new_parent = null_context;
- if (unlikely(tc->child->refs)) {
- struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
- if (p) new_parent = TC_PTR_FROM_CHUNK(p);
- }
- if (unlikely(_talloc_free(child) == -1)) {
- if (new_parent == null_context) {
- struct talloc_chunk *p = talloc_parent_chunk(ptr);
- if (p) new_parent = TC_PTR_FROM_CHUNK(p);
- }
- talloc_steal(new_parent, child);
- }
- }
-
- if ((tc->flags & TALLOC_FLAG_POOL)
- && (*talloc_pool_objectcount(tc) == 1)) {
- tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE);
-#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
- VALGRIND_MAKE_MEM_NOACCESS(
- tc->pool, tc->size - TALLOC_POOL_HDR_SIZE);
-#endif
- }
-}
-
-/*
- Allocate a bit of memory as a child of an existing pointer
-*/
-void *_talloc(const void *context, size_t size)
-{
- return __talloc(context, size);
-}
-
-/*
- externally callable talloc_set_name_const()
-*/
-void talloc_set_name_const(const void *ptr, const char *name)
-{
- _talloc_set_name_const(ptr, name);
-}
-
-/*
- create a named talloc pointer. Any talloc pointer can be named, and
- talloc_named() operates just like talloc() except that it allows you
- to name the pointer.
-*/
-void *talloc_named_const(const void *context, size_t size, const char *name)
-{
- return _talloc_named_const(context, size, name);
-}
-
-/*
- free a talloc pointer. This also frees all child pointers of this
- pointer recursively
-
- return 0 if the memory is actually freed, otherwise -1. The memory
- will not be freed if the ref_count is > 1 or the destructor (if
- any) returns non-zero
-*/
-int talloc_free(void *ptr)
-{
- return _talloc_free(ptr);
-}
-
-
-
-/*
- A talloc version of realloc. The context argument is only used if
- ptr is NULL
-*/
-void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
-{
- struct talloc_chunk *tc;
- void *new_ptr;
- bool malloced = false;
-
- /* size zero is equivalent to free() */
- if (unlikely(size == 0)) {
- _talloc_free(ptr);
- return NULL;
- }
-
- if (unlikely(size >= MAX_TALLOC_SIZE)) {
- return NULL;
- }
-
- /* realloc(NULL) is equivalent to malloc() */
- if (ptr == NULL) {
- return _talloc_named_const(context, size, name);
- }
-
- tc = talloc_chunk_from_ptr(ptr);
-
- /* don't allow realloc on referenced pointers */
- if (unlikely(tc->refs)) {
- return NULL;
- }
-
- /* don't let anybody try to realloc a talloc_pool */
- if (unlikely(tc->flags & TALLOC_FLAG_POOL)) {
- return NULL;
- }
-
- /* don't shrink if we have less than 1k to gain */
- if ((size < tc->size) && ((tc->size - size) < 1024)) {
- tc->size = size;
- return ptr;
- }
-
- /* by resetting magic we catch users of the old memory */
- tc->flags |= TALLOC_FLAG_FREE;
-
-#if ALWAYS_REALLOC
- new_ptr = malloc(size + TC_HDR_SIZE);
- if (new_ptr) {
- memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
- free(tc);
- }
-#else
- if (tc->flags & TALLOC_FLAG_POOLMEM) {
-
- new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE);
- *talloc_pool_objectcount((struct talloc_chunk *)
- (tc->pool)) -= 1;
-
- if (new_ptr == NULL) {
- new_ptr = malloc(TC_HDR_SIZE+size);
- malloced = true;
- }
-
- if (new_ptr) {
- memcpy(new_ptr, tc, MIN(tc->size,size) + TC_HDR_SIZE);
- }
- }
- else {
- new_ptr = realloc(tc, size + TC_HDR_SIZE);
- }
-#endif
- if (unlikely(!new_ptr)) {
- tc->flags &= ~TALLOC_FLAG_FREE;
- return NULL;
- }
-
- tc = (struct talloc_chunk *)new_ptr;
- tc->flags &= ~TALLOC_FLAG_FREE;
- if (malloced) {
- tc->flags &= ~TALLOC_FLAG_POOLMEM;
- }
- if (tc->parent) {
- tc->parent->child = tc;
- }
- if (tc->child) {
- tc->child->parent = tc;
- }
-
- if (tc->prev) {
- tc->prev->next = tc;
- }
- if (tc->next) {
- tc->next->prev = tc;
- }
-
- tc->size = size;
- _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
-
- return TC_PTR_FROM_CHUNK(tc);
-}
-
-/*
- a wrapper around talloc_steal() for situations where you are moving a pointer
- between two structures, and want the old pointer to be set to NULL
-*/
-void *_talloc_move(const void *new_ctx, const void *_pptr)
-{
- const void **pptr = discard_const_p(const void *,_pptr);
- void *ret = _talloc_steal(new_ctx, *pptr);
- (*pptr) = NULL;
- return ret;
-}
-
-/*
- return the total size of a talloc pool (subtree)
-*/
-size_t talloc_total_size(const void *ptr)
-{
- size_t total = 0;
- struct talloc_chunk *c, *tc;
-
- if (ptr == NULL) {
- ptr = null_context;
- }
- if (ptr == NULL) {
- return 0;
- }
-
- tc = talloc_chunk_from_ptr(ptr);
-
- if (tc->flags & TALLOC_FLAG_LOOP) {
- return 0;
- }
-
- tc->flags |= TALLOC_FLAG_LOOP;
-
- total = tc->size;
- for (c=tc->child;c;c=c->next) {
- total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
- }
-
- tc->flags &= ~TALLOC_FLAG_LOOP;
-
- return total;
-}
-
-/*
- return the total number of blocks in a talloc pool (subtree)
-*/
-size_t talloc_total_blocks(const void *ptr)
-{
- size_t total = 0;
- struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
-
- if (tc->flags & TALLOC_FLAG_LOOP) {
- return 0;
- }
-
- tc->flags |= TALLOC_FLAG_LOOP;
-
- total++;
- for (c=tc->child;c;c=c->next) {
- total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
- }
-
- tc->flags &= ~TALLOC_FLAG_LOOP;
-
- return total;
-}
-
-/*
- return the number of external references to a pointer
-*/
-size_t talloc_reference_count(const void *ptr)
-{
- struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
- struct talloc_reference_handle *h;
- size_t ret = 0;
-
- for (h=tc->refs;h;h=h->next) {
- ret++;
- }
- return ret;
-}
-
-/*
- report on memory usage by all children of a pointer, giving a full tree view
-*/
-void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
- void (*callback)(const void *ptr,
- int depth, int max_depth,
- int is_ref,
- void *private_data),
- void *private_data)
-{
- struct talloc_chunk *c, *tc;
-
- if (ptr == NULL) {
- ptr = null_context;
- }
- if (ptr == NULL) return;
-
- tc = talloc_chunk_from_ptr(ptr);
-
- if (tc->flags & TALLOC_FLAG_LOOP) {
- return;
- }
-
- callback(ptr, depth, max_depth, 0, private_data);
-
- if (max_depth >= 0 && depth >= max_depth) {
- return;
- }
-
- tc->flags |= TALLOC_FLAG_LOOP;
- for (c=tc->child;c;c=c->next) {
- if (c->name == TALLOC_MAGIC_REFERENCE) {
- struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c);
- callback(h->ptr, depth + 1, max_depth, 1, private_data);
- } else {
- talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data);
- }
- }
- tc->flags &= ~TALLOC_FLAG_LOOP;
-}
-
-static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f)
-{
- const char *name = talloc_get_name(ptr);
- FILE *f = (FILE *)_f;
-
- if (is_ref) {
- fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
- return;
- }
-
- if (depth == 0) {
- fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n",
- (max_depth < 0 ? "full " :""), name,
- (unsigned long)talloc_total_size(ptr),
- (unsigned long)talloc_total_blocks(ptr));
- return;
- }
-
- fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n",
- depth*4, "",
- name,
- (unsigned long)talloc_total_size(ptr),
- (unsigned long)talloc_total_blocks(ptr),
- (int)talloc_reference_count(ptr), ptr);
-
-#if 0
- fprintf(f, "content: ");
- if (talloc_total_size(ptr)) {
- int tot = talloc_total_size(ptr);
- int i;
-
- for (i = 0; i < tot; i++) {
- if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) {
- fprintf(f, "%c", ((char *)ptr)[i]);
- } else {
- fprintf(f, "~%02x", ((char *)ptr)[i]);
- }
- }
- }
- fprintf(f, "\n");
-#endif
-}
-
-/*
- report on memory usage by all children of a pointer, giving a full tree view
-*/
-void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f)
-{
- talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f);
- fflush(f);
-}
-
-/*
- report on memory usage by all children of a pointer, giving a full tree view
-*/
-void talloc_report_full(const void *ptr, FILE *f)
-{
- talloc_report_depth_file(ptr, 0, -1, f);
-}
-
-/*
- report on memory usage by all children of a pointer
-*/
-void talloc_report(const void *ptr, FILE *f)
-{
- talloc_report_depth_file(ptr, 0, 1, f);
-}
-
-/*
- report on any memory hanging off the null context
-*/
-static void talloc_report_null(void)
-{
- if (talloc_total_size(null_context) != 0) {
- talloc_report(null_context, stderr);
- }
-}
-
-/*
- report on any memory hanging off the null context
-*/
-static void talloc_report_null_full(void)
-{
- if (talloc_total_size(null_context) != 0) {
- talloc_report_full(null_context, stderr);
- }
-}
-
-/*
- enable tracking of the NULL context
-*/
-void talloc_enable_null_tracking(void)
-{
- if (null_context == NULL) {
- null_context = _talloc_named_const(NULL, 0, "null_context");
- }
-}
-
-/*
- disable tracking of the NULL context
-*/
-void talloc_disable_null_tracking(void)
-{
- _talloc_free(null_context);
- null_context = NULL;
-}
-
-/*
- enable leak reporting on exit
-*/
-void talloc_enable_leak_report(void)
-{
- talloc_enable_null_tracking();
- atexit(talloc_report_null);
-}
-
-/*
- enable full leak reporting on exit
-*/
-void talloc_enable_leak_report_full(void)
-{
- talloc_enable_null_tracking();
- atexit(talloc_report_null_full);
-}
-
-/*
- talloc and zero memory.
-*/
-void *_talloc_zero(const void *ctx, size_t size, const char *name)
-{
- void *p = _talloc_named_const(ctx, size, name);
-
- if (p) {
- memset(p, '\0', size);
- }
-
- return p;
-}
-
-/*
- memdup with a talloc.
-*/
-void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
-{
- void *newp = _talloc_named_const(t, size, name);
-
- if (likely(newp)) {
- memcpy(newp, p, size);
- }
-
- return newp;
-}
-
-static inline char *__talloc_strlendup(const void *t, const char *p, size_t len)
-{
- char *ret;
-
- ret = (char *)__talloc(t, len + 1);
- if (unlikely(!ret)) return NULL;
-
- memcpy(ret, p, len);
- ret[len] = 0;
-
- _talloc_set_name_const(ret, ret);
- return ret;
-}
-
-/*
- strdup with a talloc
-*/
-char *talloc_strdup(const void *t, const char *p)
-{
- if (unlikely(!p)) return NULL;
- return __talloc_strlendup(t, p, strlen(p));
-}
-
-/*
- strndup with a talloc
-*/
-char *talloc_strndup(const void *t, const char *p, size_t n)
-{
- if (unlikely(!p)) return NULL;
- return __talloc_strlendup(t, p, strnlen(p, n));
-}
-
-static inline char *__talloc_strlendup_append(char *s, size_t slen,
- const char *a, size_t alen)
-{
- char *ret;
-
- ret = talloc_realloc(NULL, s, char, slen + alen + 1);
- if (unlikely(!ret)) return NULL;
-
- /* append the string and the trailing \0 */
- memcpy(&ret[slen], a, alen);
- ret[slen+alen] = 0;
-
- _talloc_set_name_const(ret, ret);
- return ret;
-}
-
-/*
- * Appends at the end of the string.
- */
-char *talloc_strdup_append(char *s, const char *a)
-{
- if (unlikely(!s)) {
- return talloc_strdup(NULL, a);
- }
-
- if (unlikely(!a)) {
- return s;
- }
-
- return __talloc_strlendup_append(s, strlen(s), a, strlen(a));
-}
-
-/*
- * Appends at the end of the talloc'ed buffer,
- * not the end of the string.
- */
-char *talloc_strdup_append_buffer(char *s, const char *a)
-{
- size_t slen;
-
- if (unlikely(!s)) {
- return talloc_strdup(NULL, a);
- }
-
- if (unlikely(!a)) {
- return s;
- }
-
- slen = talloc_get_size(s);
- if (likely(slen > 0)) {
- slen--;
- }
-
- return __talloc_strlendup_append(s, slen, a, strlen(a));
-}
-
-/*
- * Appends at the end of the string.
- */
-char *talloc_strndup_append(char *s, const char *a, size_t n)
-{
- if (unlikely(!s)) {
- return talloc_strdup(NULL, a);
- }
-
- if (unlikely(!a)) {
- return s;
- }
-
- return __talloc_strlendup_append(s, strlen(s), a, strnlen(a, n));
-}
-
-/*
- * Appends at the end of the talloc'ed buffer,
- * not the end of the string.
- */
-char *talloc_strndup_append_buffer(char *s, const char *a, size_t n)
-{
- size_t slen;
-
- if (unlikely(!s)) {
- return talloc_strdup(NULL, a);
- }
-
- if (unlikely(!a)) {
- return s;
- }
-
- slen = talloc_get_size(s);
- if (likely(slen > 0)) {
- slen--;
- }
-
- return __talloc_strlendup_append(s, slen, a, strnlen(a, n));
-}
-
-#ifndef HAVE_VA_COPY
-#ifdef HAVE___VA_COPY
-#define va_copy(dest, src) __va_copy(dest, src)
-#else
-#define va_copy(dest, src) (dest) = (src)
-#endif
-#endif
-
-char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
-{
- int len;
- char *ret;
- va_list ap2;
- char c;
-
- /* this call looks strange, but it makes it work on older solaris boxes */
- va_copy(ap2, ap);
- len = vsnprintf(&c, 1, fmt, ap2);
- va_end(ap2);
- if (unlikely(len < 0)) {
- return NULL;
- }
-
- ret = (char *)__talloc(t, len+1);
- if (unlikely(!ret)) return NULL;
-
- va_copy(ap2, ap);
- vsnprintf(ret, len+1, fmt, ap2);
- va_end(ap2);
-
- _talloc_set_name_const(ret, ret);
- return ret;
-}
-
-
-/*
- Perform string formatting, and return a pointer to newly allocated
- memory holding the result, inside a memory pool.
- */
-char *talloc_asprintf(const void *t, const char *fmt, ...)
-{
- va_list ap;
- char *ret;
-
- va_start(ap, fmt);
- ret = talloc_vasprintf(t, fmt, ap);
- va_end(ap);
- return ret;
-}
-
-static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
- const char *fmt, va_list ap)
- PRINTF_ATTRIBUTE(3,0);
-
-static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
- const char *fmt, va_list ap)
-{
- ssize_t alen;
- va_list ap2;
- char c;
-
- va_copy(ap2, ap);
- alen = vsnprintf(&c, 1, fmt, ap2);
- va_end(ap2);
-
- if (alen <= 0) {
- /* Either the vsnprintf failed or the format resulted in
- * no characters being formatted. In the former case, we
- * ought to return NULL, in the latter we ought to return
- * the original string. Most current callers of this
- * function expect it to never return NULL.
- */
- return s;
- }
-
- s = talloc_realloc(NULL, s, char, slen + alen + 1);
- if (!s) return NULL;
-
- va_copy(ap2, ap);
- vsnprintf(s + slen, alen + 1, fmt, ap2);
- va_end(ap2);
-
- _talloc_set_name_const(s, s);
- return s;
-}
-
-/**
- * Realloc @p s to append the formatted result of @p fmt and @p ap,
- * and return @p s, which may have moved. Good for gradually
- * accumulating output into a string buffer. Appends at the end
- * of the string.
- **/
-char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
-{
- if (unlikely(!s)) {
- return talloc_vasprintf(NULL, fmt, ap);
- }
-
- return __talloc_vaslenprintf_append(s, strlen(s), fmt, ap);
-}
-
-/**
- * Realloc @p s to append the formatted result of @p fmt and @p ap,
- * and return @p s, which may have moved. Always appends at the
- * end of the talloc'ed buffer, not the end of the string.
- **/
-char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap)
-{
- size_t slen;
-
- if (unlikely(!s)) {
- return talloc_vasprintf(NULL, fmt, ap);
- }
-
- slen = talloc_get_size(s);
- if (likely(slen > 0)) {
- slen--;
- }
-
- return __talloc_vaslenprintf_append(s, slen, fmt, ap);
-}
-
-/*
- Realloc @p s to append the formatted result of @p fmt and return @p
- s, which may have moved. Good for gradually accumulating output
- into a string buffer.
- */
-char *talloc_asprintf_append(char *s, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- s = talloc_vasprintf_append(s, fmt, ap);
- va_end(ap);
- return s;
-}
-
-/*
- Realloc @p s to append the formatted result of @p fmt and return @p
- s, which may have moved. Good for gradually accumulating output
- into a buffer.
- */
-char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- s = talloc_vasprintf_append_buffer(s, fmt, ap);
- va_end(ap);
- return s;
-}
-
-/*
- alloc an array, checking for integer overflow in the array size
-*/
-void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
-{
- if (count >= MAX_TALLOC_SIZE/el_size) {
- return NULL;
- }
- return _talloc_named_const(ctx, el_size * count, name);
-}
-
-/*
- alloc an zero array, checking for integer overflow in the array size
-*/
-void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
-{
- if (count >= MAX_TALLOC_SIZE/el_size) {
- return NULL;
- }
- return _talloc_zero(ctx, el_size * count, name);
-}
-
-/*
- realloc an array, checking for integer overflow in the array size
-*/
-void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
-{
- if (count >= MAX_TALLOC_SIZE/el_size) {
- return NULL;
- }
- return _talloc_realloc(ctx, ptr, el_size * count, name);
-}
-
-/*
- a function version of talloc_realloc(), so it can be passed as a function pointer
- to libraries that want a realloc function (a realloc function encapsulates
- all the basic capabilities of an allocation library, which is why this is useful)
-*/
-void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
-{
- return _talloc_realloc(context, ptr, size, NULL);
-}
-
-
-static int talloc_autofree_destructor(void *ptr)
-{
- autofree_context = NULL;
- return 0;
-}
-
-static void talloc_autofree(void)
-{
- _talloc_free(autofree_context);
-}
-
-/*
- return a context which will be auto-freed on exit
- this is useful for reducing the noise in leak reports
-*/
-void *talloc_autofree_context(void)
-{
- if (autofree_context == NULL) {
- autofree_context = _talloc_named_const(NULL, 0, "autofree_context");
- talloc_set_destructor(autofree_context, talloc_autofree_destructor);
- atexit(talloc_autofree);
- }
- return autofree_context;
-}
-
-size_t talloc_get_size(const void *context)
-{
- struct talloc_chunk *tc;
-
- if (context == NULL)
- return 0;
-
- tc = talloc_chunk_from_ptr(context);
-
- return tc->size;
-}
-
-/*
- find a parent of this context that has the given name, if any
-*/
-void *talloc_find_parent_byname(const void *context, const char *name)
-{
- struct talloc_chunk *tc;
-
- if (context == NULL) {
- return NULL;
- }
-
- tc = talloc_chunk_from_ptr(context);
- while (tc) {
- if (tc->name && strcmp(tc->name, name) == 0) {
- return TC_PTR_FROM_CHUNK(tc);
- }
- while (tc && tc->prev) tc = tc->prev;
- if (tc) {
- tc = tc->parent;
- }
- }
- return NULL;
-}
-
-/*
- show the parentage of a context
-*/
-void talloc_show_parents(const void *context, FILE *file)
-{
- struct talloc_chunk *tc;
-
- if (context == NULL) {
- fprintf(file, "talloc no parents for NULL\n");
- return;
- }
-
- tc = talloc_chunk_from_ptr(context);
- fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
- while (tc) {
- fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
- while (tc && tc->prev) tc = tc->prev;
- if (tc) {
- tc = tc->parent;
- }
- }
- fflush(file);
-}
-
-/*
- return 1 if ptr is a parent of context
-*/
-int talloc_is_parent(const void *context, const void *ptr)
-{
- struct talloc_chunk *tc;
-
- if (context == NULL) {
- return 0;
- }
-
- tc = talloc_chunk_from_ptr(context);
- while (tc) {
- if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1;
- while (tc && tc->prev) tc = tc->prev;
- if (tc) {
- tc = tc->parent;
- }
- }
- return 0;
-}
diff --git a/openbsc/src/talloc_ctx.c b/openbsc/src/talloc_ctx.c
index aa9f0b4d7..6379e13db 100644
--- a/openbsc/src/talloc_ctx.c
+++ b/openbsc/src/talloc_ctx.c
@@ -1,6 +1,7 @@
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/gsm_data.h>
+extern void *tall_msgb_ctx;
extern void *tall_fle_ctx;
extern void *tall_locop_ctx;
extern void *tall_gsms_ctx;
@@ -13,9 +14,11 @@ extern void *tall_tqe_ctx;
extern void *tall_trans_ctx;
extern void *tall_map_ctx;
extern void *tall_upq_ctx;
+extern void *tall_ctr_ctx;
void talloc_ctx_init(void)
{
+ tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb");
tall_fle_ctx = talloc_named_const(tall_bsc_ctx, 0,
"bs11_file_list_entry");
tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 0, "loc_updating_oper");
@@ -29,4 +32,5 @@ void talloc_ctx_init(void)
tall_trans_ctx = talloc_named_const(tall_bsc_ctx, 0, "transaction");
tall_map_ctx = talloc_named_const(tall_bsc_ctx, 0, "trau_map_entry");
tall_upq_ctx = talloc_named_const(tall_bsc_ctx, 0, "trau_upq_entry");
+ tall_ctr_ctx = talloc_named_const(tall_bsc_ctx, 0, "counter");
}
diff --git a/openbsc/src/telnet_interface.c b/openbsc/src/telnet_interface.c
index bc91ca333..805dd127d 100644
--- a/openbsc/src/telnet_interface.c
+++ b/openbsc/src/telnet_interface.c
@@ -30,11 +30,11 @@
#include <openbsc/chan_alloc.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/gsm_04_11.h>
-#include <openbsc/msgb.h>
+#include <osmocore/msgb.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/paging.h>
#include <openbsc/signal.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/debug.h>
#include <vty/buffer.h>
@@ -102,9 +102,9 @@ static void print_welcome(int fd) {
int ret;
static char *msg =
"Welcome to the OpenBSC Control interface\n"
- "Copyright (C) 2008, 2009 Harald Welte\n"
+ "Copyright (C) 2008-2010 Harald Welte\n"
"Contributions by Daniel Willmann, Jan Lübbe, "
- "Stefan Schmidt, Holger Freyther\n\n"
+ "Stefan Schmidt, Holger Freyther, Andreas Eversberg\n\n"
"License GPLv2+: GNU GPL version 2 or later "
"<http://gnu.org/licenses/gpl.html>\n"
"This is free software: you are free to change "
@@ -120,6 +120,12 @@ int telnet_close_client(struct bsc_fd *fd) {
close(fd->fd);
bsc_unregister_fd(fd);
+
+ if (conn->dbg) {
+ debug_del_target(conn->dbg);
+ talloc_free(conn->dbg);
+ }
+
llist_del(&conn->entry);
talloc_free(conn);
return 0;
diff --git a/openbsc/src/timer.c b/openbsc/src/timer.c
deleted file mode 100644
index ffeb4aba3..000000000
--- a/openbsc/src/timer.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * (C) 2008,2009 by Holger Hans Peter Freyther <zecke@selfish.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 <assert.h>
-#include <string.h>
-#include <openbsc/timer.h>
-
-static LLIST_HEAD(timer_list);
-static struct timeval s_nearest_time;
-static struct timeval s_select_time;
-
-#define MICRO_SECONDS 1000000LL
-
-#define TIME_SMALLER(left, right) \
- (left.tv_sec*MICRO_SECONDS+left.tv_usec) <= (right.tv_sec*MICRO_SECONDS+right.tv_usec)
-
-void bsc_add_timer(struct timer_list *timer)
-{
- struct timer_list *list_timer;
-
- /* TODO: Optimize and remember the closest item... */
- timer->active = 1;
-
- /* this might be called from within update_timers */
- llist_for_each_entry(list_timer, &timer_list, entry)
- if (timer == list_timer)
- return;
-
- timer->in_list = 1;
- llist_add(&timer->entry, &timer_list);
-}
-
-void bsc_schedule_timer(struct timer_list *timer, int seconds, int microseconds)
-{
- struct timeval current_time;
-
- gettimeofday(&current_time, NULL);
- unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
- currentTime += seconds * MICRO_SECONDS + microseconds;
- timer->timeout.tv_sec = currentTime / MICRO_SECONDS;
- timer->timeout.tv_usec = currentTime % MICRO_SECONDS;
- bsc_add_timer(timer);
-}
-
-void bsc_del_timer(struct timer_list *timer)
-{
- if (timer->in_list) {
- timer->active = 0;
- timer->in_list = 0;
- llist_del(&timer->entry);
- }
-}
-
-int bsc_timer_pending(struct timer_list *timer)
-{
- return timer->active;
-}
-
-/*
- * if we have a nearest time return the delta between the current
- * time and the time of the nearest timer.
- * If the nearest timer timed out return NULL and then we will
- * dispatch everything after the select
- */
-struct timeval *bsc_nearest_timer()
-{
- struct timeval current_time;
-
- if (s_nearest_time.tv_sec == 0 && s_nearest_time.tv_usec == 0)
- return NULL;
-
- if (gettimeofday(&current_time, NULL) == -1)
- return NULL;
-
- unsigned long long nearestTime = s_nearest_time.tv_sec * MICRO_SECONDS + s_nearest_time.tv_usec;
- unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
-
- if (nearestTime < currentTime) {
- s_select_time.tv_sec = 0;
- s_select_time.tv_usec = 0;
- } else {
- s_select_time.tv_sec = (nearestTime - currentTime) / MICRO_SECONDS;
- s_select_time.tv_usec = (nearestTime - currentTime) % MICRO_SECONDS;
- }
-
- return &s_select_time;
-}
-
-/*
- * Find the nearest time and update s_nearest_time
- */
-void bsc_prepare_timers()
-{
- struct timer_list *timer, *nearest_timer = NULL;
- llist_for_each_entry(timer, &timer_list, entry) {
- if (!nearest_timer || TIME_SMALLER(timer->timeout, nearest_timer->timeout)) {
- nearest_timer = timer;
- }
- }
-
- if (nearest_timer) {
- s_nearest_time = nearest_timer->timeout;
- } else {
- memset(&s_nearest_time, 0, sizeof(struct timeval));
- }
-}
-
-/*
- * fire all timers... and remove them
- */
-int bsc_update_timers()
-{
- struct timeval current_time;
- struct timer_list *timer, *tmp;
- int work = 0;
-
- gettimeofday(&current_time, NULL);
-
- /*
- * The callbacks might mess with our list and in this case
- * even llist_for_each_entry_safe is not safe to use. To allow
- * del_timer, add_timer, schedule_timer to be called from within
- * the callback we jump through some loops.
- *
- * First we set the handled flag of each active timer to zero,
- * then we iterate over the list and execute the callbacks. As the
- * list might have been changed (specially the next) from within
- * the callback we have to start over again. Once every callback
- * is dispatched we will remove the non-active from the list.
- *
- * TODO: If this is a performance issue we can poison a global
- * variable in add_timer and del_timer and only then restart.
- */
- llist_for_each_entry(timer, &timer_list, entry) {
- timer->handled = 0;
- }
-
-restart:
- llist_for_each_entry(timer, &timer_list, entry) {
- if (!timer->handled && TIME_SMALLER(timer->timeout, current_time)) {
- timer->handled = 1;
- timer->active = 0;
- (*timer->cb)(timer->data);
- work = 1;
- goto restart;
- }
- }
-
- llist_for_each_entry_safe(timer, tmp, &timer_list, entry) {
- timer->handled = 0;
- if (!timer->active) {
- bsc_del_timer(timer);
- }
- }
-
- return work;
-}
-
-int bsc_timer_check(void)
-{
- struct timer_list *timer;
- int i = 0;
-
- llist_for_each_entry(timer, &timer_list, entry) {
- i++;
- }
- return i;
-}
diff --git a/openbsc/src/tlv_parser.c b/openbsc/src/tlv_parser.c
deleted file mode 100644
index fd0045f97..000000000
--- a/openbsc/src/tlv_parser.c
+++ /dev/null
@@ -1,157 +0,0 @@
-#include <stdio.h>
-#include <openbsc/tlv.h>
-#include <openbsc/gsm_data.h>
-
-struct tlv_definition tvlv_att_def;
-
-int tlv_dump(struct tlv_parsed *dec)
-{
- int i;
-
- for (i = 0; i <= 0xff; i++) {
- if (!dec->lv[i].val)
- continue;
- printf("T=%02x L=%d\n", i, dec->lv[i].len);
- }
- return 0;
-}
-
-/* o_tag: output: tag found
- * o_len: output: length of the data
- * o_val: output: pointer to the data
- * def: input: a structure defining the valid TLV tags / configurations
- * buf: input: the input data buffer to be parsed
- * buf_len: input: the length of the input data buffer
- *
- * Also, returns the number of bytes consumed by the TLV entry
- */
-int tlv_parse_one(u_int8_t *o_tag, u_int16_t *o_len, const u_int8_t **o_val,
- const struct tlv_definition *def,
- const u_int8_t *buf, int buf_len)
-{
- u_int8_t tag;
- int len;
-
- tag = *buf;
- *o_tag = tag;
-
- /* FIXME: use tables for knwon IEI */
- switch (def->def[tag].type) {
- case TLV_TYPE_T:
- /* GSM TS 04.07 11.2.4: Type 1 TV or Type 2 T */
- *o_val = buf;
- *o_len = 0;
- len = 1;
- break;
- case TLV_TYPE_TV:
- *o_val = buf+1;
- *o_len = 1;
- len = 2;
- break;
- case TLV_TYPE_FIXED:
- *o_val = buf+1;
- *o_len = def->def[tag].fixed_len;
- len = def->def[tag].fixed_len + 1;
- break;
- case TLV_TYPE_TLV:
- /* GSM TS 04.07 11.2.4: Type 4 TLV */
- if (buf + 1 > buf + buf_len)
- return -1;
- *o_val = buf+2;
- *o_len = *(buf+1);
- len = *o_len + 2;
- if (len > buf_len)
- return -2;
- break;
- case TLV_TYPE_TvLV:
- if (*(buf+1) & 0x80) {
- /* like TLV, but without highest bit of len */
- if (buf + 1 > buf + buf_len)
- return -1;
- *o_val = buf+2;
- *o_len = *(buf+1) & 0x7f;
- len = *o_len + 2;
- if (len > buf_len)
- return -2;
- break;
- }
- /* like TL16V, fallthrough */
- case TLV_TYPE_TL16V:
- if (2 > buf_len)
- return -1;
- *o_val = buf+3;
- *o_len = *(buf+1) << 8 | *(buf+2);
- len = *o_len + 3;
- if (len > buf_len)
- return -2;
- break;
- default:
- return -3;
- }
-
- return len;
-}
-
-/* dec: output: a caller-allocated pointer to a struct tlv_parsed,
- * def: input: a structure defining the valid TLV tags / configurations
- * buf: input: the input data buffer to be parsed
- * buf_len: input: the length of the input data buffer
- * lv_tag: input: an initial LV tag at the start of the buffer
- * lv_tag2: input: a second initial LV tag following lv_tag
- */
-int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
- const u_int8_t *buf, int buf_len, u_int8_t lv_tag,
- u_int8_t lv_tag2)
-{
- int ofs = 0, num_parsed = 0;
- u_int16_t len;
-
- memset(dec, 0, sizeof(*dec));
-
- if (lv_tag) {
- if (ofs > buf_len)
- return -1;
- dec->lv[lv_tag].val = &buf[ofs+1];
- dec->lv[lv_tag].len = buf[ofs];
- len = dec->lv[lv_tag].len + 1;
- if (ofs + len > buf_len)
- return -2;
- num_parsed++;
- ofs += len;
- }
- if (lv_tag2) {
- if (ofs > buf_len)
- return -1;
- dec->lv[lv_tag2].val = &buf[ofs+1];
- dec->lv[lv_tag2].len = buf[ofs];
- len = dec->lv[lv_tag2].len + 1;
- if (ofs + len > buf_len)
- return -2;
- num_parsed++;
- ofs += len;
- }
-
- while (ofs < buf_len) {
- int rv;
- u_int8_t tag;
- const u_int8_t *val;
-
- rv = tlv_parse_one(&tag, &len, &val, def,
- &buf[ofs], buf_len-ofs);
- if (rv < 0)
- return rv;
- dec->lv[tag].val = val;
- dec->lv[tag].len = len;
- ofs += rv;
- num_parsed++;
- }
- //tlv_dump(dec);
- return num_parsed;
-}
-
-static __attribute__((constructor)) void on_dso_load_tlv(void)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(tvlv_att_def.def); i++)
- tvlv_att_def.def[i].type = TLV_TYPE_TvLV;
-}
diff --git a/openbsc/src/token_auth.c b/openbsc/src/token_auth.c
index f6be0bc98..7fefea5a4 100644
--- a/openbsc/src/token_auth.c
+++ b/openbsc/src/token_auth.c
@@ -21,7 +21,7 @@
*/
#include <stdio.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/signal.h>
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_04_11.h>
@@ -103,7 +103,7 @@ unauth:
if (lchan) {
u_int8_t auth_rand[16];
/* kick the subscriber off the network */
- gsm48_tx_mm_auth_req(lchan, auth_rand);
+ gsm48_tx_mm_auth_req(lchan, auth_rand, 0);
gsm48_tx_mm_auth_rej(lchan);
/* FIXME: close the channel early ?*/
//gsm48_send_rr_Release(lchan);
@@ -139,7 +139,7 @@ static int token_sms_cb(unsigned int subsys, unsigned int signal,
lchan = lchan_for_subscr(sms->receiver);
if (lchan) {
/* kick the subscriber off the network */
- gsm48_tx_mm_auth_req(lchan, auth_rand);
+ gsm48_tx_mm_auth_req(lchan, auth_rand, 0);
gsm48_tx_mm_auth_rej(lchan);
/* FIXME: close the channel early ?*/
//gsm48_send_rr_Release(lchan);
diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c
index 2f5681433..23dfe073d 100644
--- a/openbsc/src/transaction.c
+++ b/openbsc/src/transaction.c
@@ -23,7 +23,7 @@
#include <openbsc/gsm_data.h>
#include <openbsc/mncc.h>
#include <openbsc/debug.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/mncc.h>
@@ -120,7 +120,7 @@ int trans_assign_trans_id(struct gsm_subscriber *subscr,
struct gsm_network *net = subscr->net;
struct gsm_trans *trans;
unsigned int used_tid_bitmask = 0;
- int i;
+ int i, j, h;
if (ti_flag)
ti_flag = 0x8;
@@ -134,9 +134,14 @@ int trans_assign_trans_id(struct gsm_subscriber *subscr,
used_tid_bitmask |= (1 << trans->transaction_id);
}
+ /* find a new one, trying to go in a 'circular' pattern */
+ for (h = 6; h > 0; h--)
+ if (used_tid_bitmask & (1 << (h | ti_flag)))
+ break;
for (i = 0; i < 7; i++) {
- if ((used_tid_bitmask & (1 << (i | ti_flag))) == 0)
- return i | ti_flag;
+ j = ((h + i) % 7) | ti_flag;
+ if ((used_tid_bitmask & (1 << j)) == 0)
+ return j;
}
return -1;
diff --git a/openbsc/src/trau_mux.c b/openbsc/src/trau_mux.c
index 9930751a5..f2fa5c023 100644
--- a/openbsc/src/trau_mux.c
+++ b/openbsc/src/trau_mux.c
@@ -30,7 +30,7 @@
#include <openbsc/subchan_demux.h>
#include <openbsc/e1_input.h>
#include <openbsc/debug.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
u_int8_t gsm_fr_map[] = {
6, 6, 5, 5, 4, 4, 3, 3,
diff --git a/openbsc/src/vty/buffer.c b/openbsc/src/vty/buffer.c
index 8ab73114b..195d06209 100644
--- a/openbsc/src/vty/buffer.c
+++ b/openbsc/src/vty/buffer.c
@@ -28,7 +28,7 @@
#include <stddef.h>
#include <sys/uio.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <vty/buffer.h>
#include <vty/vty.h>
diff --git a/openbsc/src/vty/command.c b/openbsc/src/vty/command.c
index a0d36a913..30c26ac9b 100644
--- a/openbsc/src/vty/command.c
+++ b/openbsc/src/vty/command.c
@@ -47,8 +47,10 @@ Boston, MA 02111-1307, USA. */
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_subscriber.h>
-#include <openbsc/talloc.h>
#include <openbsc/bsc_nat.h>
+#include <osmocore/talloc.h>
+
+void *tall_vty_cmd_ctx;
/* Command vector which includes some level of command lists. Normally
each daemon maintains each own cmdvec. */
@@ -174,7 +176,7 @@ char *argv_concat(const char **argv, int argc, int shift)
len += strlen(argv[i]) + 1;
if (!len)
return NULL;
- p = str = _talloc_zero(tall_vty_ctx, len, "arvg_concat");
+ p = str = _talloc_zero(tall_vty_cmd_ctx, len, "arvg_concat");
for (i = shift; i < argc; i++) {
size_t arglen;
memcpy(p, argv[i], (arglen = strlen(argv[i])));
@@ -276,7 +278,7 @@ vector cmd_make_strvec(const char *string)
*cp != '\0')
cp++;
strlen = cp - start;
- token = _talloc_zero(tall_vty_ctx, strlen + 1, "make_strvec");
+ token = _talloc_zero(tall_vty_cmd_ctx, strlen + 1, "make_strvec");
memcpy(token, start, strlen);
*(token + strlen) = '\0';
vector_set(strvec, token);
@@ -332,7 +334,7 @@ static char *cmd_desc_str(const char **string)
cp++;
strlen = cp - start;
- token = _talloc_zero(tall_vty_ctx, strlen + 1, "cmd_desc_str");
+ token = _talloc_zero(tall_vty_cmd_ctx, strlen + 1, "cmd_desc_str");
memcpy(token, start, strlen);
*(token + strlen) = '\0';
@@ -403,11 +405,11 @@ static vector cmd_make_descvec(const char *string, const char *descstr)
len = cp - sp;
- token = _talloc_zero(tall_vty_ctx, len + 1, "cmd_make_descvec");
+ token = _talloc_zero(tall_vty_cmd_ctx, len + 1, "cmd_make_descvec");
memcpy(token, sp, len);
*(token + len) = '\0';
- desc = talloc_zero(tall_vty_ctx, struct desc);
+ desc = talloc_zero(tall_vty_cmd_ctx, struct desc);
desc->cmd = token;
desc->str = cmd_desc_str(&dp);
@@ -1805,7 +1807,7 @@ static char **cmd_complete_command_real(vector vline, struct vty *vty,
if ((desc = vector_slot(descvec, j))) {
if ((string = cmd_entry_function(vector_slot(vline, index), desc->cmd)))
if (cmd_unique_string (matchvec, string))
- vector_set (matchvec, talloc_strdup(tall_vty_ctx, string));
+ vector_set (matchvec, talloc_strdup(tall_vty_cmd_ctx, string));
}
}
}
@@ -1846,7 +1848,7 @@ static char **cmd_complete_command_real(vector vline, struct vty *vty,
if (len < lcd) {
char *lcdstr;
- lcdstr = _talloc_zero(tall_vty_ctx, lcd + 1,
+ lcdstr = _talloc_zero(tall_vty_cmd_ctx, lcd + 1,
"complete-lcdstr");
memcpy(lcdstr, matchvec->index[0], lcd);
lcdstr[lcd] = '\0';
@@ -2471,13 +2473,13 @@ DEFUN(config_write_file,
config_file = host.config;
config_file_sav =
- _talloc_zero(tall_vty_ctx,
+ _talloc_zero(tall_vty_cmd_ctx,
strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1,
"config_file_sav");
strcpy(config_file_sav, config_file);
strcat(config_file_sav, CONF_BACKUP_EXT);
- config_file_tmp = _talloc_zero(tall_vty_ctx, strlen(config_file) + 8,
+ config_file_tmp = _talloc_zero(tall_vty_cmd_ctx, strlen(config_file) + 8,
"config_file_tmp");
sprintf(config_file_tmp, "%s.XXXXXX", config_file);
@@ -2658,7 +2660,7 @@ DEFUN(config_hostname,
if (host.name)
talloc_free(host.name);
- host.name = talloc_strdup(tall_vty_ctx, argv[0]);
+ host.name = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
return CMD_SUCCESS;
}
@@ -2693,7 +2695,7 @@ DEFUN(config_password, password_cmd,
host.password = NULL;
if (host.password_encrypt)
talloc_free(host.password_encrypt);
- host.password_encrypt = talloc_strdup(tall_vty_ctx, argv[1]);
+ host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, argv[1]);
return CMD_SUCCESS;
} else {
vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE);
@@ -2716,10 +2718,10 @@ DEFUN(config_password, password_cmd,
if (host.encrypt) {
if (host.password_encrypt)
talloc_free(host.password_encrypt);
- host.password_encrypt = talloc_strdup(tall_vty_ctx, zencrypt(argv[0]));
+ host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(argv[0]));
} else
#endif
- host.password = talloc_strdup(tall_vty_ctx, argv[0]);
+ host.password = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
return CMD_SUCCESS;
}
@@ -2752,7 +2754,7 @@ ALIAS(config_password, password_text_cmd,
if (host.enable_encrypt)
talloc_free(host.enable_encrypt);
- host.enable_encrypt = talloc_strdup(tall_vty_ctx, argv[1]);
+ host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, argv[1]);
return CMD_SUCCESS;
} else {
@@ -2777,10 +2779,10 @@ ALIAS(config_password, password_text_cmd,
if (host.encrypt) {
if (host.enable_encrypt)
talloc_free(host.enable_encrypt);
- host.enable_encrypt = talloc_strdup(tall_vty_ctx, zencrypt(argv[0]));
+ host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(argv[0]));
} else
#endif
- host.enable = talloc_strdup(tall_vty_ctx, argv[0]);
+ host.enable = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
return CMD_SUCCESS;
}
@@ -2824,12 +2826,12 @@ DEFUN(service_password_encrypt,
if (host.password) {
if (host.password_encrypt)
talloc_free(host.password_encrypt);
- host.password_encrypt = talloc_strdup(tall_vty_ctx, zencrypt(host.password));
+ host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(host.password));
}
if (host.enable) {
if (host.enable_encrypt)
talloc_free(host.enable_encrypt);
- host.enable_encrypt = talloc_strdup(tall_vty_ctx, zencrypt(host.enable));
+ host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(host.enable));
}
return CMD_SUCCESS;
@@ -3103,7 +3105,7 @@ static int set_log_file(struct vty *vty, const char *fname, int loglevel)
if (host.logfile)
talloc_free(host.logfile);
- host.logfile = talloc_strdup(tall_vty_ctx, fname);
+ host.logfile = talloc_strdup(tall_vty_cmd_ctx, fname);
return CMD_SUCCESS;
}
@@ -3293,7 +3295,7 @@ DEFUN(banner_motd_file,
{
if (host.motdfile)
talloc_free(host.motdfile);
- host.motdfile = talloc_strdup(tall_vty_ctx, argv[0]);
+ host.motdfile = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
return CMD_SUCCESS;
}
@@ -3321,7 +3323,7 @@ DEFUN(no_banner_motd,
/* Set config filename. Called from vty.c */
void host_config_set(const char *filename)
{
- host.config = talloc_strdup(tall_vty_ctx, filename);
+ host.config = talloc_strdup(tall_vty_cmd_ctx, filename);
}
void install_default(enum node_type node)
diff --git a/openbsc/src/vty/vector.c b/openbsc/src/vty/vector.c
index 371f71d95..db47ae59a 100644
--- a/openbsc/src/vty/vector.c
+++ b/openbsc/src/vty/vector.c
@@ -24,13 +24,15 @@
#include <vty/vector.h>
#include <vty/vty.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <memory.h>
+void *tall_vty_vec_ctx;
+
/* Initialize vector : allocate memory and return vector. */
vector vector_init(unsigned int size)
{
- vector v = talloc_zero(tall_vty_ctx, struct _vector);
+ vector v = talloc_zero(tall_vty_vec_ctx, struct _vector);
if (!v)
return NULL;
@@ -40,7 +42,7 @@ vector vector_init(unsigned int size)
v->alloced = size;
v->active = 0;
- v->index = _talloc_zero(tall_vty_ctx, sizeof(void *) * size,
+ v->index = _talloc_zero(tall_vty_vec_ctx, sizeof(void *) * size,
"vector_init:index");
if (!v->index) {
talloc_free(v);
@@ -68,7 +70,7 @@ void vector_free(vector v)
vector vector_copy(vector v)
{
unsigned int size;
- vector new = talloc_zero(tall_vty_ctx, struct _vector);
+ vector new = talloc_zero(tall_vty_vec_ctx, struct _vector);
if (!new)
return NULL;
@@ -76,7 +78,7 @@ vector vector_copy(vector v)
new->alloced = v->alloced;
size = sizeof(void *) * (v->alloced);
- new->index = _talloc_zero(tall_vty_ctx, size, "vector_copy:index");
+ new->index = _talloc_zero(tall_vty_vec_ctx, size, "vector_copy:index");
if (!new->index) {
talloc_free(new);
return NULL;
@@ -92,7 +94,7 @@ void vector_ensure(vector v, unsigned int num)
if (v->alloced > num)
return;
- v->index = talloc_realloc_size(tall_vty_ctx, v->index,
+ v->index = talloc_realloc_size(tall_vty_vec_ctx, v->index,
sizeof(void *) * (v->alloced * 2));
memset(&v->index[v->alloced], 0, sizeof(void *) * v->alloced);
v->alloced *= 2;
diff --git a/openbsc/src/vty/vty.c b/openbsc/src/vty/vty.c
index 788c7fd6f..1260f38c5 100644
--- a/openbsc/src/vty/vty.c
+++ b/openbsc/src/vty/vty.c
@@ -17,7 +17,7 @@
#include <vty/vty.h>
#include <vty/command.h>
#include <vty/buffer.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
/* our callback, located in telnet_interface.c */
void vty_event(enum event event, int sock, struct vty *vty);
@@ -1633,6 +1633,8 @@ extern void *tall_bsc_ctx;
void vty_init()
{
tall_vty_ctx = talloc_named_const(NULL, 0, "vty");
+ tall_vty_vec_ctx = talloc_named_const(tall_vty_ctx, 0, "vty_vector");
+ tall_vty_cmd_ctx = talloc_named_const(tall_vty_ctx, 0, "vty_command");
/* For further configuration read, preserve current directory. */
vty_save_cwd();
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index 5197ec36b..c2488c3c4 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -28,13 +28,16 @@
#include <arpa/inet.h>
-#include <openbsc/linuxlist.h>
+#include <osmocore/linuxlist.h>
#include <openbsc/gsm_data.h>
#include <openbsc/e1_input.h>
#include <openbsc/abis_nm.h>
-#include <openbsc/gsm_utils.h>
+#include <osmocore/gsm_utils.h>
+#include <openbsc/chan_alloc.h>
+#include <openbsc/meas_rep.h>
#include <openbsc/db.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
+#include <openbsc/telnet_interface.h>
static struct gsm_network *gsmnet;
@@ -74,9 +77,30 @@ static void net_dump_nmstate(struct vty *vty, struct gsm_nm_state *nms)
nm_avail_name(nms->availability), VTY_NEWLINE);
}
+static void dump_pchan_load_vty(struct vty *vty, char *prefix,
+ const struct pchan_load *pl)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pl->pchan); i++) {
+ const struct load_counter *lc = &pl->pchan[i];
+ unsigned int percent;
+
+ if (lc->total == 0)
+ continue;
+
+ percent = (lc->used * 100) / lc->total;
+
+ vty_out(vty, "%s%20s: %3u%% (%u/%u)%s", prefix,
+ gsm_pchan_name(i), percent, lc->used, lc->total,
+ VTY_NEWLINE);
+ }
+}
+
static void net_dump_vty(struct vty *vty, struct gsm_network *net)
{
int i;
+ struct pchan_load pl;
vty_out(vty, "BSC is on Country Code %u, Network Code %u "
"and has %u BTS%s", net->country_code, net->network_code,
@@ -99,6 +123,10 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net)
VTY_NEWLINE);
vty_out(vty, " Handover: %s%s", net->handover.active ? "On" : "Off",
VTY_NEWLINE);
+ network_chan_load(&pl, net);
+ vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE);
+ dump_pchan_load_vty(vty, " ", &pl);
+
vty_out(vty, " Allowed Audio Codecs: ");
for (i = 0; i < net->audio_length; ++i)
vty_out(vty, "hr: %d ver: %d, ",
@@ -135,6 +163,8 @@ static void e1isl_dump_vty(struct vty *vty, struct e1inp_sign_link *e1l)
static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
{
+ struct pchan_load pl;
+
vty_out(vty, "BTS %u is of %s type in band %s, has CI %u LAC %u, "
"BSIC %u, TSC %u and %u TRX%s",
bts->nr, btstype2str(bts->type), gsm_band_name(bts->band),
@@ -147,6 +177,11 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
VTY_NEWLINE);
vty_out(vty, "Cell Reselection Hysteresis: %u dBm%s",
bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE);
+ vty_out(vty, "RACH TX-Integer: %u%s", bts->si_common.rach_control.tx_integer,
+ VTY_NEWLINE);
+ vty_out(vty, "RACH Max transmissions: %u%s",
+ rach_max_trans_raw2val(bts->si_common.rach_control.max_trans),
+ VTY_NEWLINE);
if (bts->si_common.rach_control.cell_bar)
vty_out(vty, " CELL IS BARRED%s", VTY_NEWLINE);
if (is_ipaccess_bts(bts))
@@ -164,6 +199,10 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
e1isl_dump_vty(vty, bts->oml_link);
}
/* FIXME: oml_link, chan_desc */
+ memset(&pl, 0, sizeof(pl));
+ bts_chan_load(&pl, bts);
+ vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE);
+ dump_pchan_load_vty(vty, " ", &pl);
}
DEFUN(show_bts, show_bts_cmd, "show bts [number]",
@@ -234,6 +273,7 @@ static void config_write_trx_single(struct vty *vty, struct gsm_bts_trx *trx)
vty_out(vty, " trx %u%s", trx->nr, VTY_NEWLINE);
vty_out(vty, " arfcn %u%s", trx->arfcn, VTY_NEWLINE);
+ vty_out(vty, " nominal power %u%s", trx->nominal_power, VTY_NEWLINE);
vty_out(vty, " max_power_red %u%s", trx->max_power_red, VTY_NEWLINE);
config_write_e1_link(vty, &trx->rsl_e1_link, " rsl ");
vty_out(vty, " rsl e1 tei %u%s", trx->rsl_tei, VTY_NEWLINE);
@@ -265,6 +305,11 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
vty_out(vty, " channel allocator %s%s",
bts->chan_alloc_reverse ? "descending" : "ascending",
VTY_NEWLINE);
+ vty_out(vty, " rach tx integer %u%s",
+ bts->si_common.rach_control.tx_integer, VTY_NEWLINE);
+ vty_out(vty, " rach max transmission %u%s",
+ rach_max_trans_raw2val(bts->si_common.rach_control.max_trans),
+ VTY_NEWLINE);
if (bts->si_common.rach_control.cell_bar)
vty_out(vty, " cell barred 1%s", VTY_NEWLINE);
if (is_ipaccess_bts(bts)) {
@@ -500,8 +545,12 @@ DEFUN(show_ts,
return CMD_SUCCESS;
}
-void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr)
+static void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr)
{
+ int rc;
+ struct gsm_auth_info ainfo;
+ struct gsm_auth_tuple atuple;
+
vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
subscr->authorized, VTY_NEWLINE);
if (subscr->name)
@@ -514,16 +563,54 @@ void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr)
if (subscr->tmsi != GSM_RESERVED_TMSI)
vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
VTY_NEWLINE);
+
vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
}
+static void meas_rep_dump_uni_vty(struct vty *vty,
+ struct gsm_meas_rep_unidir *mru,
+ const char *prefix,
+ const char *dir)
+{
+ vty_out(vty, "%s RXL-FULL-%s: %4d dBm, RXL-SUB-%s: %4d dBm ",
+ prefix, dir, rxlev2dbm(mru->full.rx_lev),
+ dir, rxlev2dbm(mru->sub.rx_lev));
+ vty_out(vty, "RXQ-FULL-%s: %d, RXQ-SUB-%s: %d%s",
+ dir, mru->full.rx_qual, dir, mru->sub.rx_qual,
+ VTY_NEWLINE);
+}
+
+static void meas_rep_dump_vty(struct vty *vty, struct gsm_meas_rep *mr,
+ const char *prefix)
+{
+ vty_out(vty, "%sMeasurement Report:%s", prefix, VTY_NEWLINE);
+ vty_out(vty, "%s Flags: %s%s%s%s%s", prefix,
+ mr->flags & MEAS_REP_F_UL_DTX ? "DTXu " : "",
+ mr->flags & MEAS_REP_F_DL_DTX ? "DTXd " : "",
+ mr->flags & MEAS_REP_F_FPC ? "FPC " : "",
+ mr->flags & MEAS_REP_F_DL_VALID ? " " : "DLinval ",
+ VTY_NEWLINE);
+ if (mr->flags & MEAS_REP_F_MS_TO)
+ vty_out(vty, "%s MS Timing Offset: %u%s", prefix,
+ mr->ms_timing_offset, VTY_NEWLINE);
+ if (mr->flags & MEAS_REP_F_MS_L1)
+ vty_out(vty, "%s L1 MS Power: %u dBm, Timing Advance: %u%s",
+ prefix, mr->ms_l1.pwr, mr->ms_l1.ta, VTY_NEWLINE);
+ if (mr->flags & MEAS_REP_F_DL_VALID)
+ meas_rep_dump_uni_vty(vty, &mr->dl, prefix, "dl");
+ meas_rep_dump_uni_vty(vty, &mr->ul, prefix, "ul");
+}
+
static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan)
{
+ int idx;
+
vty_out(vty, "Lchan %u in Timeslot %u of TRX %u in BTS %u, Type %s%s",
lchan->nr, lchan->ts->nr, lchan->ts->trx->nr,
- lchan->ts->trx->bts->nr, gsm_lchan_name(lchan->type),
+ lchan->ts->trx->bts->nr, gsm_lchant_name(lchan->type),
VTY_NEWLINE);
- vty_out(vty, " Use Count: %u%s", lchan->use_count, VTY_NEWLINE);
+ vty_out(vty, " Use Count: %u, State: %s%s", lchan->use_count,
+ gsm_lchans_name(lchan->state), VTY_NEWLINE);
vty_out(vty, " BS Power: %u dBm, MS Power: %u dBm%s",
lchan->ts->trx->nominal_power - lchan->ts->trx->max_power_red
- lchan->bs_power*2,
@@ -542,6 +629,11 @@ static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan)
lchan->abis_ip.rtp_payload2, lchan->abis_ip.conn_id,
VTY_NEWLINE);
}
+
+ /* we want to report the last measurement report */
+ idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
+ lchan->meas_rep_idx, 1);
+ meas_rep_dump_vty(vty, &lchan->meas_rep[idx], " ");
}
#if 0
@@ -794,6 +886,204 @@ DEFUN(show_paging,
return CMD_SUCCESS;
}
+static void _vty_output(struct debug_target *tgt, const char *line)
+{
+ struct vty *vty = tgt->tgt_vty.vty;
+ vty_out(vty, "%s", line);
+ /* This is an ugly hack, but there is no easy way... */
+ if (strchr(line, '\n'))
+ vty_out(vty, "\r");
+}
+
+struct debug_target *debug_target_create_vty(struct vty *vty)
+{
+ struct debug_target *target;
+
+ target = debug_target_create();
+ if (!target)
+ return NULL;
+
+ target->tgt_vty.vty = vty;
+ target->output = _vty_output;
+ return target;
+}
+
+DEFUN(enable_logging,
+ enable_logging_cmd,
+ "logging enable",
+ "Enables logging to this vty\n")
+{
+ struct telnet_connection *conn;
+
+ conn = (struct telnet_connection *) vty->priv;
+ if (conn->dbg) {
+ vty_out(vty, "Logging already enabled.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ conn->dbg = debug_target_create_vty(vty);
+ if (!conn->dbg)
+ return CMD_WARNING;
+
+ debug_add_target(conn->dbg);
+ return CMD_SUCCESS;
+}
+
+DEFUN(logging_fltr_imsi,
+ logging_fltr_imsi_cmd,
+ "logging filter imsi IMSI",
+ "Print all messages related to a IMSI\n")
+{
+ struct telnet_connection *conn;
+
+ conn = (struct telnet_connection *) vty->priv;
+ if (!conn->dbg) {
+ vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ debug_set_imsi_filter(conn->dbg, argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(logging_fltr_all,
+ logging_fltr_all_cmd,
+ "logging filter all <0-1>",
+ "Print all messages to the console\n")
+{
+ struct telnet_connection *conn;
+
+ conn = (struct telnet_connection *) vty->priv;
+ if (!conn->dbg) {
+ vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ debug_set_all_filter(conn->dbg, atoi(argv[0]));
+ return CMD_SUCCESS;
+}
+
+DEFUN(logging_use_clr,
+ logging_use_clr_cmd,
+ "logging color <0-1>",
+ "Use color for printing messages\n")
+{
+ struct telnet_connection *conn;
+
+ conn = (struct telnet_connection *) vty->priv;
+ if (!conn->dbg) {
+ vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ debug_set_use_color(conn->dbg, atoi(argv[0]));
+ return CMD_SUCCESS;
+}
+
+DEFUN(logging_prnt_timestamp,
+ logging_prnt_timestamp_cmd,
+ "logging timestamp <0-1>",
+ "Print the timestamp of each message\n")
+{
+ struct telnet_connection *conn;
+
+ conn = (struct telnet_connection *) vty->priv;
+ if (!conn->dbg) {
+ vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ debug_set_print_timestamp(conn->dbg, atoi(argv[0]));
+ return CMD_SUCCESS;
+}
+
+/* FIXME: those have to be kept in sync with the log levels and categories */
+#define VTY_DEBUG_CATEGORIES "(rll|cc|mm|rr|rsl|nm|sms|pag|mncc|inp|mi|mib|mux|meas|sccp|msc|mgcp|ho|db|ref)"
+#define VTY_DEBUG_LEVELS "(everything|debug|info|notice|error|fatal)"
+DEFUN(logging_level,
+ logging_level_cmd,
+ "logging level " VTY_DEBUG_CATEGORIES " " VTY_DEBUG_LEVELS,
+ "Set the log level for a specified category\n")
+{
+ struct telnet_connection *conn;
+ int category = debug_parse_category(argv[0]);
+ int level = debug_parse_level(argv[1]);
+
+ conn = (struct telnet_connection *) vty->priv;
+ if (!conn->dbg) {
+ vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (category < 0) {
+ vty_out(vty, "Invalid category `%s'%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (level < 0) {
+ vty_out(vty, "Invalid level `%s'%s", argv[1], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ conn->dbg->categories[category].enabled = 1;
+ conn->dbg->categories[category].loglevel = level;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(logging_set_category_mask,
+ logging_set_category_mask_cmd,
+ "logging set debug mask MASK",
+ "Decide which categories to output.\n")
+{
+ struct telnet_connection *conn;
+
+ conn = (struct telnet_connection *) vty->priv;
+ if (!conn->dbg) {
+ vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ debug_parse_category_mask(conn->dbg, argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(logging_set_log_level,
+ logging_set_log_level_cmd,
+ "logging set log level <0-8>",
+ "Set the global log level. The value 0 implies no filtering.\n")
+{
+ struct telnet_connection *conn;
+
+ conn = (struct telnet_connection *) vty->priv;
+ if (!conn->dbg) {
+ vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ debug_set_log_level(conn->dbg, atoi(argv[0]));
+ return CMD_SUCCESS;
+}
+
+DEFUN(diable_logging,
+ disable_logging_cmd,
+ "logging disable",
+ "Disables logging to this vty\n")
+{
+ struct telnet_connection *conn;
+
+ conn = (struct telnet_connection *) vty->priv;
+ if (!conn->dbg) {
+ vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ debug_del_target(conn->dbg);
+ talloc_free(conn->dbg);
+ conn->dbg = NULL;
+ return CMD_SUCCESS;
+}
+
DEFUN(show_stats,
show_stats_cmd,
"show statistics",
@@ -801,31 +1091,36 @@ DEFUN(show_stats,
{
struct gsm_network *net = gsmnet;
- vty_out(vty, "Channel Requests: %lu total, %lu no channel%s",
- net->stats.chreq.total, net->stats.chreq.no_channel,
- VTY_NEWLINE);
- vty_out(vty, "Location Update: %lu attach, %lu normal, %lu periodic%s",
- net->stats.loc_upd_type.attach, net->stats.loc_upd_type.normal,
- net->stats.loc_upd_type.periodic, VTY_NEWLINE);
- vty_out(vty, "IMSI Detach Indications: %lu%s\n",
- net->stats.loc_upd_type.detach, VTY_NEWLINE);
+ vty_out(vty, "Channel Requests : %lu total, %lu no channel%s",
+ counter_get(net->stats.chreq.total),
+ counter_get(net->stats.chreq.no_channel), VTY_NEWLINE);
+ vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s",
+ counter_get(net->stats.loc_upd_type.attach),
+ counter_get(net->stats.loc_upd_type.normal),
+ counter_get(net->stats.loc_upd_type.periodic), VTY_NEWLINE);
+ vty_out(vty, "IMSI Detach Indications : %lu%s",
+ counter_get(net->stats.loc_upd_type.detach), VTY_NEWLINE);
vty_out(vty, "Location Update Response: %lu accept, %lu reject%s",
- net->stats.loc_upd_resp.accept,
- net->stats.loc_upd_resp.reject, VTY_NEWLINE);
- vty_out(vty, "Paging: %lu attempted, %lu complete, %lu expired%s",
- net->stats.paging.attempted, net->stats.paging.completed,
- net->stats.paging.expired, VTY_NEWLINE);
- vty_out(vty, "Handover: %lu attempted, %lu no_channel, %lu timeout, "
- "%lu completed, %lu failed%s", net->stats.handover.attempted,
- net->stats.handover.no_channel, net->stats.handover.timeout,
- net->stats.handover.completed, net->stats.handover.failed,
- VTY_NEWLINE);
- vty_out(vty, "SMS MO: %lu submitted, %lu no receiver%s",
- net->stats.sms.submitted, net->stats.sms.no_receiver,
- VTY_NEWLINE);
- vty_out(vty, "SMS MT: %lu delivered, %lu no memory, %lu other error%s",
- net->stats.sms.delivered, net->stats.sms.rp_err_mem,
- net->stats.sms.rp_err_other, VTY_NEWLINE);
+ counter_get(net->stats.loc_upd_resp.accept),
+ counter_get(net->stats.loc_upd_resp.reject), VTY_NEWLINE);
+ vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s",
+ counter_get(net->stats.paging.attempted),
+ counter_get(net->stats.paging.completed),
+ counter_get(net->stats.paging.expired), VTY_NEWLINE);
+ vty_out(vty, "Handover : %lu attempted, %lu no_channel, %lu timeout, "
+ "%lu completed, %lu failed%s",
+ counter_get(net->stats.handover.attempted),
+ counter_get(net->stats.handover.no_channel),
+ counter_get(net->stats.handover.timeout),
+ counter_get(net->stats.handover.completed),
+ counter_get(net->stats.handover.failed), VTY_NEWLINE);
+ vty_out(vty, "SMS MO : %lu submitted, %lu no receiver%s",
+ counter_get(net->stats.sms.submitted),
+ counter_get(net->stats.sms.no_receiver), VTY_NEWLINE);
+ vty_out(vty, "SMS MT : %lu delivered, %lu no memory, %lu other error%s",
+ counter_get(net->stats.sms.delivered),
+ counter_get(net->stats.sms.rp_err_mem),
+ counter_get(net->stats.sms.rp_err_other), VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -970,13 +1265,15 @@ DEFUN(cfg_net_handover, cfg_net_handover_cmd,
"handover (0|1)",
"Whether or not to use in-call handover")
{
- if (ipacc_rtp_direct) {
+ int enable = atoi(argv[0]);
+
+ if (enable && ipacc_rtp_direct) {
vty_out(vty, "%% Cannot enable handover unless RTP Proxy mode "
"is enabled by using the -P command line option%s",
VTY_NEWLINE);
return CMD_WARNING;
}
- gsmnet->handover.active = atoi(argv[0]);
+ gsmnet->handover.active = enable;
return CMD_SUCCESS;
}
@@ -1125,11 +1422,11 @@ DEFUN(cfg_net_bsc_token,
return CMD_SUCCESS;
}
-#define DECLARE_TIMER(number) \
+#define DECLARE_TIMER(number, doc) \
DEFUN(cfg_net_T##number, \
cfg_net_T##number##_cmd, \
"timer t" #number " <0-65535>", \
- "Set the T" #number " value.") \
+ doc) \
{ \
int value = atoi(argv[0]); \
\
@@ -1143,17 +1440,17 @@ DEFUN(cfg_net_bsc_token,
return CMD_SUCCESS; \
}
-DECLARE_TIMER(3101)
-DECLARE_TIMER(3103)
-DECLARE_TIMER(3105)
-DECLARE_TIMER(3107)
-DECLARE_TIMER(3109)
-DECLARE_TIMER(3111)
-DECLARE_TIMER(3113)
-DECLARE_TIMER(3115)
-DECLARE_TIMER(3117)
-DECLARE_TIMER(3119)
-DECLARE_TIMER(3141)
+DECLARE_TIMER(3101, "Set the timeout value for IMMEDIATE ASSIGNMENT.")
+DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.")
+DECLARE_TIMER(3105, "Currently not used.")
+DECLARE_TIMER(3107, "Currently not used.")
+DECLARE_TIMER(3109, "Currently not used.")
+DECLARE_TIMER(3111, "Currently not used.")
+DECLARE_TIMER(3113, "Set the time to try paging a subscriber.")
+DECLARE_TIMER(3115, "Currently not used.")
+DECLARE_TIMER(3117, "Currently not used.")
+DECLARE_TIMER(3119, "Currently not used.")
+DECLARE_TIMER(3141, "Currently not used.")
/* per-BTS configuration */
DEFUN(cfg_bts,
@@ -1175,8 +1472,11 @@ DEFUN(cfg_bts,
} else
bts = gsm_bts_num(gsmnet, bts_nr);
- if (!bts)
+ if (!bts) {
+ vty_out(vty, "%% Unable to allocate BTS %u%s",
+ gsmnet->num_bts, VTY_NEWLINE);
return CMD_WARNING;
+ }
vty->index = bts;
vty->node = BTS_NODE;
@@ -1190,13 +1490,11 @@ DEFUN(cfg_bts_type,
"Set the BTS type\n")
{
struct gsm_bts *bts = vty->index;
+ int rc;
- bts->type = parse_btstype(argv[0]);
-
- if (is_ipaccess_bts(bts)) {
- /* Set the default OML Stream ID to 0xff */
- bts->oml_tei = 0xff;
- }
+ rc = gsm_set_bts_type(bts, parse_btstype(argv[0]));
+ if (rc < 0)
+ return CMD_WARNING;
return CMD_SUCCESS;
}
@@ -1379,6 +1677,26 @@ DEFUN(cfg_bts_challoc, cfg_bts_challoc_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_bts_rach_tx_integer,
+ cfg_bts_rach_tx_integer_cmd,
+ "rach tx integer <0-15>",
+ "Set the raw tx integer value in RACH Control parameters IE")
+{
+ struct gsm_bts *bts = vty->index;
+ bts->si_common.rach_control.tx_integer = atoi(argv[0]) & 0xf;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_rach_max_trans,
+ cfg_bts_rach_max_trans_cmd,
+ "rach max transmission (1|2|4|7)",
+ "Set the maximum number of RACH burst transmissions")
+{
+ struct gsm_bts *bts = vty->index;
+ bts->si_common.rach_control.max_trans = rach_max_trans_val2raw(atoi(argv[0]));
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_bts_cell_barred, cfg_bts_cell_barred_cmd,
"cell barred (0|1)",
"Should this cell be barred from access?")
@@ -1483,6 +1801,18 @@ DEFUN(cfg_trx_arfcn,
return CMD_SUCCESS;
}
+DEFUN(cfg_trx_nominal_power,
+ cfg_trx_nominal_power_cmd,
+ "nominal power <0-100>",
+ "Nominal TRX RF Power in dB\n")
+{
+ struct gsm_bts_trx *trx = vty->index;
+
+ trx->nominal_power = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_trx_max_power_red,
cfg_trx_max_power_red_cmd,
"max_power_red <0-100>",
@@ -1620,6 +1950,16 @@ int bsc_vty_init(struct gsm_network *net)
install_element(VIEW_NODE, &show_paging_cmd);
install_element(VIEW_NODE, &show_stats_cmd);
+ install_element(VIEW_NODE, &enable_logging_cmd);
+ install_element(VIEW_NODE, &disable_logging_cmd);
+ install_element(VIEW_NODE, &logging_fltr_imsi_cmd);
+ install_element(VIEW_NODE, &logging_fltr_all_cmd);
+ install_element(VIEW_NODE, &logging_use_clr_cmd);
+ install_element(VIEW_NODE, &logging_prnt_timestamp_cmd);
+ install_element(VIEW_NODE, &logging_set_category_mask_cmd);
+ install_element(VIEW_NODE, &logging_level_cmd);
+ install_element(VIEW_NODE, &logging_set_log_level_cmd);
+
install_element(CONFIG_NODE, &cfg_net_cmd);
install_node(&net_node, config_write_net);
install_default(GSMNET_NODE);
@@ -1672,6 +2012,8 @@ int bsc_vty_init(struct gsm_network *net)
install_element(BTS_NODE, &cfg_bts_oml_e1_cmd);
install_element(BTS_NODE, &cfg_bts_oml_e1_tei_cmd);
install_element(BTS_NODE, &cfg_bts_challoc_cmd);
+ install_element(BTS_NODE, &cfg_bts_rach_tx_integer_cmd);
+ install_element(BTS_NODE, &cfg_bts_rach_max_trans_cmd);
install_element(BTS_NODE, &cfg_bts_cell_barred_cmd);
install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd);
install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd);
@@ -1683,6 +2025,7 @@ int bsc_vty_init(struct gsm_network *net)
install_node(&trx_node, dummy_config_write);
install_default(TRX_NODE);
install_element(TRX_NODE, &cfg_trx_arfcn_cmd);
+ install_element(TRX_NODE, &cfg_trx_nominal_power_cmd);
install_element(TRX_NODE, &cfg_trx_max_power_red_cmd);
install_element(TRX_NODE, &cfg_trx_rsl_e1_cmd);
install_element(TRX_NODE, &cfg_trx_rsl_e1_tei_cmd);
diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c
index 4cc08c2da..b824c3db6 100644
--- a/openbsc/src/vty_interface_layer3.c
+++ b/openbsc/src/vty_interface_layer3.c
@@ -29,20 +29,18 @@
#include <arpa/inet.h>
-#include <openbsc/linuxlist.h>
+#include <osmocore/linuxlist.h>
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/silent_call.h>
#include <openbsc/gsm_04_11.h>
#include <openbsc/e1_input.h>
#include <openbsc/abis_nm.h>
-#include <openbsc/gsm_utils.h>
+#include <osmocore/gsm_utils.h>
#include <openbsc/db.h>
-#include <openbsc/talloc.h>
+#include <osmocore/talloc.h>
#include <openbsc/signal.h>
-
-/* forward declarations */
-void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr);
+#include <openbsc/debug.h>
static struct gsm_network *gsmnet;
@@ -74,6 +72,33 @@ static struct buffer *argv_to_buffer(int argc, const char *argv[], int base)
return b;
}
+static int hexparse(const char *str, u_int8_t *b, int max_len)
+
+{
+ int i, l, v;
+
+ l = strlen(str);
+ if ((l&1) || ((l>>1) > max_len))
+ return -1;
+
+ memset(b, 0x00, max_len);
+
+ for (i=0; i<l; i++) {
+ char c = str[i];
+ if (c >= '0' && c <= '9')
+ v = c - '0';
+ else if (c >= 'a' && c <= 'f')
+ v = 10 + (c - 'a');
+ else if (c >= 'A' && c <= 'F')
+ v = 10 + (c - 'a');
+ else
+ return -1;
+ b[i>>1] |= v << (i&1 ? 0 : 4);
+ }
+
+ return i>>1;
+}
+
/* per-subscriber configuration */
DEFUN(cfg_subscr,
cfg_subscr_cmd,
@@ -97,6 +122,55 @@ DEFUN(cfg_subscr,
return CMD_SUCCESS;
}
+static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr)
+{
+ int rc;
+ struct gsm_auth_info ainfo;
+ struct gsm_auth_tuple atuple;
+
+ vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
+ subscr->authorized, VTY_NEWLINE);
+ if (subscr->name)
+ vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
+ if (subscr->extension)
+ vty_out(vty, " Extension: %s%s", subscr->extension,
+ VTY_NEWLINE);
+ if (subscr->imsi)
+ vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
+ if (subscr->tmsi != GSM_RESERVED_TMSI)
+ vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
+ VTY_NEWLINE);
+
+ rc = get_authinfo_by_subscr(&ainfo, subscr);
+ if (!rc) {
+ vty_out(vty, " A3A8 algorithm id: %d%s",
+ ainfo.auth_algo, VTY_NEWLINE);
+ vty_out(vty, " A3A8 Ki: %s%s",
+ hexdump(ainfo.a3a8_ki, ainfo.a3a8_ki_len),
+ VTY_NEWLINE);
+ }
+
+ rc = get_authtuple_by_subscr(&atuple, subscr);
+ if (!rc) {
+ vty_out(vty, " A3A8 last tuple (used %d times):%s",
+ atuple.use_count, VTY_NEWLINE);
+ vty_out(vty, " seq # : %d%s",
+ atuple.key_seq, VTY_NEWLINE);
+ vty_out(vty, " RAND : %s%s",
+ hexdump(atuple.rand, sizeof(atuple.rand)),
+ VTY_NEWLINE);
+ vty_out(vty, " SRES : %s%s",
+ hexdump(atuple.sres, sizeof(atuple.sres)),
+ VTY_NEWLINE);
+ vty_out(vty, " Kc : %s%s",
+ hexdump(atuple.kc, sizeof(atuple.kc)),
+ VTY_NEWLINE);
+ }
+
+ vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
+}
+
+
/* Subscriber */
DEFUN(show_subscr,
show_subscr_cmd,
@@ -114,7 +188,7 @@ DEFUN(show_subscr,
VTY_NEWLINE);
return CMD_WARNING;
}
- subscr_dump_vty(vty, subscr);
+ subscr_dump_full_vty(vty, subscr);
subscr_put(subscr);
return CMD_SUCCESS;
@@ -135,7 +209,7 @@ DEFUN(show_subscr_cache,
llist_for_each_entry(subscr, &active_subscribers, entry) {
vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
- subscr_dump_vty(vty, subscr);
+ subscr_dump_full_vty(vty, subscr);
}
return CMD_SUCCESS;
@@ -143,23 +217,20 @@ DEFUN(show_subscr_cache,
DEFUN(sms_send_pend,
sms_send_pend_cmd,
- "sms send pending MIN_ID",
- "Send all pending SMS starting from MIN_ID")
+ "sms send pending",
+ "Send all pending SMS")
{
struct gsm_sms *sms;
- int id = atoi(argv[0]);
+ int id = 0;
while (1) {
- sms = db_sms_get_unsent(gsmnet, id++);
+ sms = db_sms_get_unsent_by_subscr(gsmnet, id);
if (!sms)
- return CMD_WARNING;
-
- if (!sms->receiver) {
- sms_free(sms);
- continue;
- }
+ break;
gsm411_send_sms_subscr(sms->receiver, sms);
+
+ id = sms->receiver->id + 1;
}
return CMD_SUCCESS;
@@ -269,10 +340,46 @@ DEFUN(subscriber_silent_sms,
return rc;
}
-DEFUN(subscriber_silent_call,
- subscriber_silent_call_cmd,
- "subscriber " SUBSCR_TYPES " EXTEN silent call (start|stop)",
- "Send a silent call to a subscriber")
+DEFUN(subscriber_silent_call_start,
+ subscriber_silent_call_start_cmd,
+ "subscriber " SUBSCR_TYPES " EXTEN silent call start (any|tch/f|tch/any|sdcch)",
+ "Start a silent call to a subscriber")
+{
+ struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
+ int rc, type;
+
+ if (!subscr) {
+ vty_out(vty, "%% No subscriber found for %s %s%s",
+ argv[0], argv[1], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!strcmp(argv[2], "tch/f"))
+ type = RSL_CHANNEED_TCH_F;
+ else if (!strcmp(argv[2], "tch/any"))
+ type = RSL_CHANNEED_TCH_ForH;
+ else if (!strcmp(argv[2], "sdcch"))
+ type = RSL_CHANNEED_SDCCH;
+ else
+ type = RSL_CHANNEED_ANY; /* Defaults to ANY */
+
+ rc = gsm_silent_call_start(subscr, vty, type);
+ if (rc <= 0) {
+ vty_out(vty, "%% Subscriber not attached%s",
+ VTY_NEWLINE);
+ subscr_put(subscr);
+ return CMD_WARNING;
+ }
+
+ subscr_put(subscr);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(subscriber_silent_call_stop,
+ subscriber_silent_call_stop_cmd,
+ "subscriber " SUBSCR_TYPES " EXTEN silent call stop",
+ "Stop a silent call to a subscriber")
{
struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
int rc;
@@ -283,17 +390,10 @@ DEFUN(subscriber_silent_call,
return CMD_WARNING;
}
- if (!strcmp(argv[2], "start")) {
- rc = gsm_silent_call_start(subscr, vty);
- if (rc <= 0) {
- vty_out(vty, "%% Subscriber not attached%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- } else {
- rc = gsm_silent_call_stop(subscr);
- if (rc < 0)
- return CMD_WARNING;
+ rc = gsm_silent_call_stop(subscr);
+ if (rc < 0) {
+ subscr_put(subscr);
+ return CMD_WARNING;
}
subscr_put(subscr);
@@ -349,6 +449,40 @@ DEFUN(cfg_subscr_authorized,
return CMD_SUCCESS;
}
+#define A3A8_ALG_TYPES "(none|comp128v1)"
+
+DEFUN(cfg_subscr_a3a8,
+ cfg_subscr_a3a8_cmd,
+ "a3a8 " A3A8_ALG_TYPES " [KI]",
+ "Set a3a8 parameters for the subscriber")
+{
+ struct gsm_subscriber *subscr = vty->index;
+ const char *alg_str = argv[0];
+ const char *ki_str = argv[1];
+ struct gsm_auth_info ainfo;
+ int rc;
+
+ if (!strcasecmp(alg_str, "none")) {
+ /* Just erase */
+ rc = set_authinfo_for_subscr(NULL, subscr);
+ } else if (!strcasecmp(alg_str, "comp128v1")) {
+ /* Parse hex string Ki */
+ rc = hexparse(ki_str, ainfo.a3a8_ki, sizeof(ainfo.a3a8_ki));
+ if (rc != 16)
+ return CMD_WARNING;
+
+ /* Set the infos */
+ ainfo.auth_algo = AUTH_ALGO_COMP128v1;
+ ainfo.a3a8_ki_len = rc;
+ rc = set_authinfo_for_subscr(&ainfo, subscr);
+ } else {
+ /* Unknown method */
+ return CMD_WARNING;
+ }
+
+ return rc ? CMD_WARNING : CMD_SUCCESS;
+}
+
static int scall_cbfn(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
@@ -381,7 +515,8 @@ int bsc_vty_init_extra(struct gsm_network *net)
install_element(VIEW_NODE, &subscriber_send_sms_cmd);
install_element(VIEW_NODE, &subscriber_silent_sms_cmd);
- install_element(VIEW_NODE, &subscriber_silent_call_cmd);
+ install_element(VIEW_NODE, &subscriber_silent_call_start_cmd);
+ install_element(VIEW_NODE, &subscriber_silent_call_stop_cmd);
install_element(CONFIG_NODE, &cfg_subscr_cmd);
install_node(&subscr_node, dummy_config_write);
@@ -390,6 +525,7 @@ int bsc_vty_init_extra(struct gsm_network *net)
install_element(SUBSCR_NODE, &cfg_subscr_name_cmd);
install_element(SUBSCR_NODE, &cfg_subscr_extension_cmd);
install_element(SUBSCR_NODE, &cfg_subscr_authorized_cmd);
+ install_element(SUBSCR_NODE, &cfg_subscr_a3a8_cmd);
return 0;
}
diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am
index d867ec6bb..b469832fc 100644
--- a/openbsc/tests/Makefile.am
+++ b/openbsc/tests/Makefile.am
@@ -1 +1 @@
-SUBDIRS = debug timer sms gsm0408 db channel sccp bsc-nat
+SUBDIRS = debug gsm0408 db channel sccp bsc-nat
diff --git a/openbsc/tests/bsc-nat/Makefile.am b/openbsc/tests/bsc-nat/Makefile.am
index cc9fb3bae..550f0a820 100644
--- a/openbsc/tests/bsc-nat/Makefile.am
+++ b/openbsc/tests/bsc-nat/Makefile.am
@@ -1,8 +1,8 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS=-Wall -ggdb3
+AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS)
noinst_PROGRAMS = bsc_nat_test
bsc_nat_test_SOURCES = bsc_nat_test.c $(top_srcdir)/src/nat/bsc_filter.c
-bsc_nat_test_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libsccp.a
+bsc_nat_test_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libsccp.a $(LIBOSMOCORE_LIBS)
diff --git a/openbsc/tests/channel/Makefile.am b/openbsc/tests/channel/Makefile.am
index 50fadc582..772965953 100644
--- a/openbsc/tests/channel/Makefile.am
+++ b/openbsc/tests/channel/Makefile.am
@@ -1,5 +1,5 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS=-Wall -ggdb3
+AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS)
noinst_PROGRAMS = channel_test
@@ -8,10 +8,8 @@ channel_test_SOURCES = channel_test.c \
$(top_srcdir)/src/gsm_subscriber_base.c \
$(top_srcdir)/src/gsm_subscriber.c \
$(top_srcdir)/src/debug.c \
- $(top_srcdir)/src/timer.c \
- $(top_srcdir)/src/select.c \
- $(top_srcdir)/src/talloc.c \
$(top_srcdir)/src/gsm_data.c \
- $(top_srcdir)/src/signal.c
-channel_test_LDADD = -ldl -ldbi
+ $(top_srcdir)/src/bts_ipaccess_nanobts.c \
+ $(top_srcdir)/src/bts_siemens_bs11.c
+channel_test_LDADD = -ldl -ldbi $(LIBOSMOCORE_LIBS)
diff --git a/openbsc/tests/channel/channel_test.c b/openbsc/tests/channel/channel_test.c
index ed0f3ad57..4c57a75c6 100644
--- a/openbsc/tests/channel/channel_test.c
+++ b/openbsc/tests/channel/channel_test.c
@@ -23,7 +23,7 @@
#include <assert.h>
-#include <openbsc/select.h>
+#include <osmocore/select.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/abis_rsl.h>
@@ -78,3 +78,5 @@ void input_event() {}
void sms_alloc() {}
void _lchan_release() {}
+struct tlv_definition nm_att_tlvdef;
+
diff --git a/openbsc/tests/db/Makefile.am b/openbsc/tests/db/Makefile.am
index 8ce7e3c49..6eb9180ce 100644
--- a/openbsc/tests/db/Makefile.am
+++ b/openbsc/tests/db/Makefile.am
@@ -1,8 +1,8 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS=-Wall -ggdb3
+AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS)
noinst_PROGRAMS = db_test
db_test_SOURCES = db_test.c
-db_test_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libmsc.a $(top_builddir)/src/libbsc.a -ldl -ldbi
+db_test_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libmsc.a $(top_builddir)/src/libbsc.a $(LIBOSMOCORE_LIBS) -ldl -ldbi
diff --git a/openbsc/tests/debug/Makefile.am b/openbsc/tests/debug/Makefile.am
index 0cdf46ad5..8423fd178 100644
--- a/openbsc/tests/debug/Makefile.am
+++ b/openbsc/tests/debug/Makefile.am
@@ -1,4 +1,6 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include
+AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS)
noinst_PROGRAMS = debug_test
-debug_test_SOURCES = debug_test.c $(top_srcdir)/src/debug.c
+debug_test_SOURCES = debug_test.c $(top_srcdir)/src/debug.c
+debug_test_LDADD = $(LIBOSMOCORE_LIBS)
diff --git a/openbsc/tests/debug/debug_test.c b/openbsc/tests/debug/debug_test.c
index 77ac01532..0f0c284ab 100644
--- a/openbsc/tests/debug/debug_test.c
+++ b/openbsc/tests/debug/debug_test.c
@@ -1,6 +1,6 @@
/* simple test for the debug interface */
/*
- * (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -24,11 +24,18 @@
int main(int argc, char** argv)
{
- debug_parse_category_mask("DRLL");
- DEBUGP(DCC, "You should not see this\n");
+ struct debug_target *stderr_target;
- debug_parse_category_mask("DRLL:DCC");
- DEBUGP(DRLL, "You should see this\n");
- DEBUGP(DCC, "You should see this\n");
- DEBUGP(DMM, "You should not see this\n");
+ debug_init();
+ stderr_target = debug_target_create_stderr();
+ debug_add_target(stderr_target);
+ debug_set_all_filter(stderr_target, 1);
+
+ debug_parse_category_mask(stderr_target, "DRLL");
+ DEBUGP(DCC, "You should not see this\n");
+
+ debug_parse_category_mask(stderr_target, "DRLL:DCC");
+ DEBUGP(DRLL, "You should see this\n");
+ DEBUGP(DCC, "You should see this\n");
+ DEBUGP(DMM, "You should not see this\n");
}
diff --git a/openbsc/tests/gsm0408/Makefile.am b/openbsc/tests/gsm0408/Makefile.am
index ff8caf999..f98c673ea 100644
--- a/openbsc/tests/gsm0408/Makefile.am
+++ b/openbsc/tests/gsm0408/Makefile.am
@@ -1,5 +1,6 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include
+AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS)
noinst_PROGRAMS = gsm0408_test
gsm0408_test_SOURCES = gsm0408_test.c
-gsm0408_test_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libmsc.a $(top_builddir)/src/libbsc.a -ldbi
+gsm0408_test_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libmsc.a $(top_builddir)/src/libbsc.a $(LIBOSMOCORE_LIBS) -ldbi
diff --git a/openbsc/tests/gsm0408/gsm0408_test.c b/openbsc/tests/gsm0408/gsm0408_test.c
index bbf812965..287d4ee99 100644
--- a/openbsc/tests/gsm0408/gsm0408_test.c
+++ b/openbsc/tests/gsm0408/gsm0408_test.c
@@ -23,6 +23,8 @@
#include <stdio.h>
#include <stdlib.h>
+#include <arpa/inet.h>
+
#include <openbsc/gsm_04_08.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/debug.h>
@@ -52,13 +54,13 @@ static void test_location_area_identifier(void)
* Test the default/test setup. Coming from
* bsc_hack.c dumps
*/
- gsm0408_generate_lai(&lai48, 1, 1, 1);
+ gsm48_generate_lai(&lai48, 1, 1, 1);
COMPARE(lai48.digits[0], ==, 0x00);
COMPARE(lai48.digits[1], ==, 0xF1);
COMPARE(lai48.digits[2], ==, 0x10);
COMPARE(lai48.lac, ==, htons(0x0001));
- gsm0408_generate_lai(&lai48, 602, 1, 15);
+ gsm48_generate_lai(&lai48, 602, 1, 15);
COMPARE(lai48.digits[0], ==, 0x06);
COMPARE(lai48.digits[1], ==, 0xF2);
COMPARE(lai48.digits[2], ==, 0x10);
@@ -97,6 +99,8 @@ int main(int argc, char** argv)
{
test_location_area_identifier();
test_mi_functionality();
+
+ exit(0);
}
diff --git a/openbsc/tests/sccp/Makefile.am b/openbsc/tests/sccp/Makefile.am
index 5a275fc2b..b35693e82 100644
--- a/openbsc/tests/sccp/Makefile.am
+++ b/openbsc/tests/sccp/Makefile.am
@@ -1,8 +1,8 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS=-Wall -ggdb3
+AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS)
noinst_PROGRAMS = sccp_test
sccp_test_SOURCES = sccp_test.c
-sccp_test_LDADD = $(top_builddir)/src/libsccp.a $(top_builddir)/src/libbsc.a
+sccp_test_LDADD = $(top_builddir)/src/libsccp.a $(top_builddir)/src/libbsc.a $(LIBOSMOCORE_LIBS)
diff --git a/openbsc/tests/sccp/sccp_test.c b/openbsc/tests/sccp/sccp_test.c
index bd28ed179..eb41d3eaf 100644
--- a/openbsc/tests/sccp/sccp_test.c
+++ b/openbsc/tests/sccp/sccp_test.c
@@ -2,7 +2,7 @@
* SCCP testing code
*
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009 by on-waves.com
+ * (C) 2009 by On-Waves
*
* All Rights Reserved
*
@@ -26,9 +26,11 @@
#include <arpa/inet.h>
-#include <sccp/sccp.h>
#include <openbsc/gsm_data.h>
#include <openbsc/debug.h>
+#include <osmocore/msgb.h>
+
+#include <sccp/sccp.h>
#define MIN(x, y) ((x) < (y) ? (x) : (y))
@@ -242,6 +244,52 @@ static const struct connection_test connection_tests[] = {
},
};
+struct sccp_parse_header_result {
+ /* results */
+ int msg_type;
+ int wanted_len;
+ int src_ssn;
+ int dst_ssn;
+
+ int has_src_ref, has_dst_ref;
+ struct sccp_source_reference src_ref;
+ struct sccp_source_reference dst_ref;
+
+ /* the input */
+ const u_int8_t *input;
+ int input_len;
+};
+
+static const u_int8_t it_test[] = {
+0x10, 0x01, 0x07,
+0x94, 0x01, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00 };
+
+static const struct sccp_parse_header_result parse_result[] = {
+ {
+ .msg_type = SCCP_MSG_TYPE_IT,
+ .wanted_len = 0,
+ .src_ssn = -1,
+ .dst_ssn = -1,
+ .has_src_ref = 1,
+ .has_dst_ref = 1,
+
+ .src_ref = {
+ .octet1 = 0x01,
+ .octet2 = 0x04,
+ .octet3 = 0x00
+ },
+ .dst_ref = {
+ .octet1 = 0x01,
+ .octet2 = 0x07,
+ .octet3 = 0x94,
+ },
+
+ .input = it_test,
+ .input_len = sizeof(it_test),
+ },
+};
+
+
/* testing procedure:
* - we will use sccp_write and see what will be set in the
* outgoing callback
@@ -712,6 +760,59 @@ static void test_sccp_system_crash(void)
printf("survived\n");
}
+static void test_sccp_parsing(void)
+{
+ for (current_test = 0; current_test < ARRAY_SIZE(parse_result); ++current_test) {
+ struct msgb *msg;
+ struct sccp_parse_result result;
+
+ msg = msgb_alloc_headroom(1024, 128, "parse-test");
+ msgb_put(msg, 1);
+ msg->l2h = msgb_put(msg, parse_result[current_test].input_len);
+ memcpy(msg->l2h, parse_result[current_test].input, msgb_l2len(msg));
+
+ memset(&result, 0, sizeof(result));
+ if (sccp_parse_header(msg, &result) != 0) {
+ fprintf(stderr, "Failed to parse test: %d\n", current_test);
+ } else {
+ if (parse_result[current_test].wanted_len != result.data_len) {
+ fprintf(stderr, "Unexpected data length.\n");
+ abort();
+ }
+
+ if (parse_result[current_test].has_src_ref) {
+ if (memcmp(result.source_local_reference,
+ &parse_result[current_test].src_ref,
+ sizeof(struct sccp_source_reference)) != 0) {
+ fprintf(stderr, "SRC REF did not match\n");
+ abort();
+ }
+ }
+
+ if (parse_result[current_test].has_dst_ref) {
+ if (memcmp(result.destination_local_reference,
+ &parse_result[current_test].dst_ref,
+ sizeof(struct sccp_source_reference)) != 0) {
+ fprintf(stderr, "DST REF did not match\n");
+ abort();
+ }
+ }
+
+ if (parse_result[current_test].src_ssn != -1) {
+ fprintf(stderr, "Not implemented.\n");
+ abort();
+ }
+
+ if (parse_result[current_test].dst_ssn != -1) {
+ fprintf(stderr, "Not implemented.\n");
+ abort();
+ }
+ }
+
+ msgb_free(msg);
+ }
+}
+
int main(int argc, char **argv)
{
@@ -720,5 +821,8 @@ int main(int argc, char **argv)
test_sccp_udt_communication();
test_sccp_connection();
test_sccp_system_crash();
+ test_sccp_parsing();
return 0;
}
+
+void db_store_counter() {}
diff --git a/openbsc/tests/sms/Makefile.am b/openbsc/tests/sms/Makefile.am
deleted file mode 100644
index 807c674e5..000000000
--- a/openbsc/tests/sms/Makefile.am
+++ /dev/null
@@ -1,5 +0,0 @@
-INCLUDES = $(all_includes) -I$(top_srcdir)/include
-noinst_PROGRAMS = sms_test
-
-sms_test_SOURCES = sms_test.c
-sms_test_LDADD = $(top_builddir)/src/libmsc.a $(top_builddir)/src/libbsc.a -ldl -ldbi
diff --git a/openbsc/tests/sms/sms_test.c b/openbsc/tests/sms/sms_test.c
deleted file mode 100644
index 2ce2cc6c4..000000000
--- a/openbsc/tests/sms/sms_test.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <openbsc/debug.h>
-#include <openbsc/msgb.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_utils.h>
-
-int main(int argc, char** argv)
-{
- DEBUGP(DSMS, "SMS testing\n");
- struct msgb *msg;
- u_int8_t *sms;
- u_int8_t i;
-
- /* test 7-bit coding/decoding */
- const char *input = "test text";
- u_int8_t length;
- u_int8_t coded[256];
- char result[256];
-
- length = gsm_7bit_encode(coded, input);
- gsm_7bit_decode(result, coded, length);
- if (strcmp(result, input) != 0) {
- printf("7 Bit coding failed... life sucks\n");
- printf("Wanted: '%s' got '%s'\n", input, result);
- }
-}
-
-/* stubs */
-void input_event(void) {}
-void nm_state_event(void) {}
diff --git a/openbsc/tests/timer/Makefile.am b/openbsc/tests/timer/Makefile.am
deleted file mode 100644
index 9f12d23ac..000000000
--- a/openbsc/tests/timer/Makefile.am
+++ /dev/null
@@ -1,5 +0,0 @@
-INCLUDES = $(all_includes) -I$(top_srcdir)/include
-noinst_PROGRAMS = timer_test
-
-timer_test_SOURCES = timer_test.c $(top_srcdir)/src/timer.c $(top_srcdir)/src/select.c
-
diff --git a/openbsc/tests/timer/timer_test.c b/openbsc/tests/timer/timer_test.c
deleted file mode 100644
index 26fcbc938..000000000
--- a/openbsc/tests/timer/timer_test.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.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 <stdio.h>
-
-#include <openbsc/timer.h>
-#include <openbsc/select.h>
-
-static void timer_fired(unsigned long data);
-
-static struct timer_list timer_one = {
- .cb = timer_fired,
- .data = (void*)1,
-};
-
-static struct timer_list timer_two = {
- .cb = timer_fired,
- .data = (void*)2,
-};
-
-static struct timer_list timer_three = {
- .cb = timer_fired,
- .data = (void*)3,
-};
-
-static void timer_fired(unsigned long data)
-{
- printf("Fired timer: %lu\n", data);
-
- if (data == 1) {
- bsc_schedule_timer(&timer_one, 3, 0);
- bsc_del_timer(&timer_two);
- } else if (data == 2) {
- printf("Should not be fired... bug in del_timer\n");
- } else if (data == 3) {
- printf("Timer fired not registering again\n");
- } else {
- printf("wtf... wrong data\n");
- }
-}
-
-int main(int argc, char** argv)
-{
- printf("Starting... timer\n");
-
- bsc_schedule_timer(&timer_one, 3, 0);
- bsc_schedule_timer(&timer_two, 5, 0);
- bsc_schedule_timer(&timer_three, 4, 0);
-
- while (1) {
- bsc_select_main(0);
- }
-}
diff --git a/openbsc/tools/hlrstat.pl b/openbsc/tools/hlrstat.pl
index a3fd2b81e..668fc9a4a 100755
--- a/openbsc/tools/hlrstat.pl
+++ b/openbsc/tools/hlrstat.pl
@@ -8,6 +8,18 @@ my $dbh = DBI->connect("dbi:SQLite:dbname=hlr.sqlite3","","");
my %mcc_names;
my %mcc_mnc_names;
+sub get_mcc_mnc_name($)
+{
+ my $mcc_mnc = shift;
+ my $ret = $mcc_mnc;
+
+ if ($mcc_mnc_names{$mcc_mnc} ne '') {
+ $ret = $mcc_mnc_names{$mcc_mnc};
+ }
+
+ return $ret;
+}
+
sub read_networks($)
{
my $filename = shift;
@@ -37,6 +49,7 @@ read_networks("networks.tab");
my %oper_count;
my %country_count;
+#my $sth = $dbh->prepare("SELECT imsi FROM subscriber where authorized=1");
my $sth = $dbh->prepare("SELECT imsi FROM subscriber");
$sth->execute();
@@ -49,10 +62,12 @@ while (my $href = $sth->fetchrow_hashref) {
}
-foreach my $c (keys %country_count) {
+foreach my $c (sort{$country_count{$b} <=> $country_count{$a}} keys %country_count) {
printf("%s: %d\n", $mcc_names{$c}, $country_count{$c});
-}
- foreach my $k (keys %oper_count) {
- printf("\t%s: %d\n", $mcc_mnc_names{$k}, $oper_count{$k});
+
+ foreach my $k (sort{$oper_count{$b} <=> $oper_count{$a}} keys %oper_count) {
+ if ($k =~ /^$c-/) {
+ printf("\t%s: %d\n", get_mcc_mnc_name($k), $oper_count{$k});
+ }
}
-#//}
+}